From 16f504a9dca3fe3b70568f67b7d41241ae485288 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 18:49:04 +0200 Subject: Adding upstream version 7.0.6-dfsg. Signed-off-by: Daniel Baumann --- src/libs/xpcom18a4/xpcom/.cvsignore | 3 + src/libs/xpcom18a4/xpcom/Makefile.in | 84 + src/libs/xpcom18a4/xpcom/Makefile.kup | 0 src/libs/xpcom18a4/xpcom/MoreFiles/.cvsignore | 1 + src/libs/xpcom18a4/xpcom/MoreFiles/Makefile.in | 70 + src/libs/xpcom18a4/xpcom/MoreFiles/MoreFilesX.c | 2765 +++++++++++ src/libs/xpcom18a4/xpcom/MoreFiles/MoreFilesX.h | 1800 +++++++ src/libs/xpcom18a4/xpcom/base/.cvsignore | 2 + src/libs/xpcom18a4/xpcom/base/Makefile.in | 133 + src/libs/xpcom18a4/xpcom/base/nsAgg.h | 155 + src/libs/xpcom18a4/xpcom/base/nsAllocator.cpp | 41 + src/libs/xpcom18a4/xpcom/base/nsAllocator.h | 50 + src/libs/xpcom18a4/xpcom/base/nsAutoPtr.h | 1353 ++++++ src/libs/xpcom18a4/xpcom/base/nsCom.h | 43 + src/libs/xpcom18a4/xpcom/base/nsConsoleMessage.cpp | 69 + src/libs/xpcom18a4/xpcom/base/nsConsoleMessage.h | 58 + src/libs/xpcom18a4/xpcom/base/nsConsoleService.cpp | 321 ++ src/libs/xpcom18a4/xpcom/base/nsConsoleService.h | 89 + src/libs/xpcom18a4/xpcom/base/nsDebugImpl.cpp | 477 ++ src/libs/xpcom18a4/xpcom/base/nsDebugImpl.h | 61 + src/libs/xpcom18a4/xpcom/base/nsError.h | 317 ++ src/libs/xpcom18a4/xpcom/base/nsErrorService.cpp | 153 + src/libs/xpcom18a4/xpcom/base/nsErrorService.h | 76 + .../xpcom18a4/xpcom/base/nsExceptionService.cpp | 383 ++ src/libs/xpcom18a4/xpcom/base/nsExceptionService.h | 94 + src/libs/xpcom18a4/xpcom/base/nsGarbageCollector.c | 127 + src/libs/xpcom18a4/xpcom/base/nsIAllocator.h | 56 + .../xpcom18a4/xpcom/base/nsIConsoleListener.idl | 49 + .../xpcom18a4/xpcom/base/nsIConsoleMessage.idl | 56 + .../xpcom18a4/xpcom/base/nsIConsoleService.idl | 85 + src/libs/xpcom18a4/xpcom/base/nsID.cpp | 152 + src/libs/xpcom18a4/xpcom/base/nsID.h | 166 + src/libs/xpcom18a4/xpcom/base/nsIDebug.idl | 67 + src/libs/xpcom18a4/xpcom/base/nsIErrorService.idl | 100 + src/libs/xpcom18a4/xpcom/base/nsIException.idl | 101 + .../xpcom18a4/xpcom/base/nsIExceptionService.idl | 97 + src/libs/xpcom18a4/xpcom/base/nsIID.h | 41 + .../xpcom18a4/xpcom/base/nsIInterfaceRequestor.idl | 72 + src/libs/xpcom18a4/xpcom/base/nsILeakDetector.idl | 54 + src/libs/xpcom18a4/xpcom/base/nsIMemory.idl | 126 + .../xpcom/base/nsIProgrammingLanguage.idl | 70 + src/libs/xpcom18a4/xpcom/base/nsISupports.idl | 80 + src/libs/xpcom18a4/xpcom/base/nsISupportsBase.h | 119 + .../xpcom18a4/xpcom/base/nsISupportsObsolete.h | 243 + src/libs/xpcom18a4/xpcom/base/nsISystemInfo.idl | 62 + src/libs/xpcom18a4/xpcom/base/nsITraceRefcnt.idl | 72 + src/libs/xpcom18a4/xpcom/base/nsIWeakReference.idl | 102 + src/libs/xpcom18a4/xpcom/base/nsLeakDetector.cpp | 248 + src/libs/xpcom18a4/xpcom/base/nsLeakDetector.h | 60 + src/libs/xpcom18a4/xpcom/base/nsMemoryImpl.cpp | 548 +++ src/libs/xpcom18a4/xpcom/base/nsMemoryImpl.h | 91 + src/libs/xpcom18a4/xpcom/base/nsStackFrameUnix.cpp | 375 ++ src/libs/xpcom18a4/xpcom/base/nsStackFrameUnix.h | 46 + src/libs/xpcom18a4/xpcom/base/nsStackFrameWin.cpp | 351 ++ src/libs/xpcom18a4/xpcom/base/nsStackFrameWin.h | 126 + .../xpcom18a4/xpcom/base/nsTraceRefcntImpl.cpp | 1444 ++++++ src/libs/xpcom18a4/xpcom/base/nsTraceRefcntImpl.h | 109 + src/libs/xpcom18a4/xpcom/base/nsWeakPtr.h | 48 + src/libs/xpcom18a4/xpcom/base/nscore.h | 468 ++ src/libs/xpcom18a4/xpcom/base/nsrootidl.idl | 128 + src/libs/xpcom18a4/xpcom/base/pure.h | 135 + src/libs/xpcom18a4/xpcom/base/pure_api.c | 126 + src/libs/xpcom18a4/xpcom/build/.cvsignore | 1 + src/libs/xpcom18a4/xpcom/build/Makefile.in | 165 + src/libs/xpcom18a4/xpcom/build/dlldeps.cpp | 202 + src/libs/xpcom18a4/xpcom/build/malloc.c | 5126 ++++++++++++++++++++ src/libs/xpcom18a4/xpcom/build/nsOS2VACLegacy.cpp | 753 +++ src/libs/xpcom18a4/xpcom/build/nsStringAPI.cpp | 261 + src/libs/xpcom18a4/xpcom/build/nsXPCOM.h | 217 + src/libs/xpcom18a4/xpcom/build/nsXPCOMCID.h | 174 + src/libs/xpcom18a4/xpcom/build/nsXPCOMPrivate.h | 228 + src/libs/xpcom18a4/xpcom/build/nsXPComInit.cpp | 1079 ++++ src/libs/xpcom18a4/xpcom/build/win32.order | 1514 ++++++ src/libs/xpcom18a4/xpcom/build/xpcom-tests.pkg | 47 + src/libs/xpcom18a4/xpcom/build/xpcom.pkg | 106 + src/libs/xpcom18a4/xpcom/build/xpcom_alpha.def | 252 + src/libs/xpcom18a4/xpcom/components/.cvsignore | 1 + src/libs/xpcom18a4/xpcom/components/Makefile.in | 107 + .../xpcom/components/nsCategoryManager.cpp | 799 +++ .../xpcom18a4/xpcom/components/nsCategoryManager.h | 159 + .../xpcom/components/nsCategoryManagerUtils.h | 88 + .../xpcom/components/nsComponentManager.cpp | 3794 +++++++++++++++ .../xpcom/components/nsComponentManager.h | 339 ++ .../components/nsComponentManagerObsolete.cpp | 271 ++ .../xpcom/components/nsComponentManagerObsolete.h | 185 + .../xpcom/components/nsComponentManagerUtils.h | 196 + .../xpcom/components/nsICategoryManager.idl | 101 + .../xpcom18a4/xpcom/components/nsIClassInfo.idl | 132 + .../xpcom/components/nsIComponentLoader.idl | 109 + .../xpcom/components/nsIComponentLoaderManager.idl | 72 + .../xpcom/components/nsIComponentManager.idl | 111 + .../components/nsIComponentManagerObsolete.idl | 351 ++ .../xpcom/components/nsIComponentManagerUtils.h | 43 + .../xpcom/components/nsIComponentRegistrar.idl | 243 + src/libs/xpcom18a4/xpcom/components/nsIFactory.idl | 79 + src/libs/xpcom18a4/xpcom/components/nsIModule.idl | 115 + .../xpcom/components/nsINativeComponentLoader.idl | 70 + .../xpcom/components/nsIServiceManager.idl | 119 + .../xpcom/components/nsIServiceManagerObsolete.h | 250 + .../xpcom/components/nsIServiceManagerUtils.h | 185 + src/libs/xpcom18a4/xpcom/components/nsModule.h | 58 + .../xpcom/components/nsNativeComponentLoader.cpp | 1150 +++++ .../xpcom/components/nsNativeComponentLoader.h | 84 + .../xpcom/components/nsObsoleteModuleLoading.h | 27 + .../xpcom/components/nsServiceManagerObsolete.cpp | 155 + .../xpcom18a4/xpcom/components/nsStaticComponent.h | 52 + .../xpcom/components/nsStaticComponentLoader.cpp | 317 ++ src/libs/xpcom18a4/xpcom/components/xcDll.cpp | 457 ++ src/libs/xpcom18a4/xpcom/components/xcDll.h | 121 + src/libs/xpcom18a4/xpcom/doc/README | 8 + src/libs/xpcom18a4/xpcom/ds/.cvsignore | 1 + src/libs/xpcom18a4/xpcom/ds/Makefile.in | 171 + src/libs/xpcom18a4/xpcom/ds/nsArray.cpp | 226 + src/libs/xpcom18a4/xpcom/ds/nsArray.h | 118 + src/libs/xpcom18a4/xpcom/ds/nsArrayEnumerator.cpp | 210 + src/libs/xpcom18a4/xpcom/ds/nsArrayEnumerator.h | 87 + src/libs/xpcom18a4/xpcom/ds/nsAtomService.cpp | 67 + src/libs/xpcom18a4/xpcom/ds/nsAtomService.h | 56 + src/libs/xpcom18a4/xpcom/ds/nsAtomTable.cpp | 616 +++ src/libs/xpcom18a4/xpcom/ds/nsAtomTable.h | 101 + src/libs/xpcom18a4/xpcom/ds/nsAutoBuffer.h | 127 + src/libs/xpcom18a4/xpcom/ds/nsBaseHashtable.h | 458 ++ src/libs/xpcom18a4/xpcom/ds/nsByteBuffer.cpp | 170 + src/libs/xpcom18a4/xpcom/ds/nsByteBuffer.h | 67 + src/libs/xpcom18a4/xpcom/ds/nsCOMArray.cpp | 162 + src/libs/xpcom18a4/xpcom/ds/nsCOMArray.h | 267 + src/libs/xpcom18a4/xpcom/ds/nsCRT.cpp | 534 ++ src/libs/xpcom18a4/xpcom/ds/nsCRT.h | 301 ++ src/libs/xpcom18a4/xpcom/ds/nsCheapSets.cpp | 180 + src/libs/xpcom18a4/xpcom/ds/nsCheapSets.h | 194 + src/libs/xpcom18a4/xpcom/ds/nsClassHashtable.h | 149 + src/libs/xpcom18a4/xpcom/ds/nsCppSharedAllocator.h | 127 + src/libs/xpcom18a4/xpcom/ds/nsDataHashtable.h | 62 + src/libs/xpcom18a4/xpcom/ds/nsDeque.cpp | 627 +++ src/libs/xpcom18a4/xpcom/ds/nsDeque.h | 405 ++ src/libs/xpcom18a4/xpcom/ds/nsDoubleHashtable.h | 505 ++ src/libs/xpcom18a4/xpcom/ds/nsEmptyEnumerator.cpp | 108 + src/libs/xpcom18a4/xpcom/ds/nsEmptyEnumerator.h | 64 + src/libs/xpcom18a4/xpcom/ds/nsEnumeratorUtils.cpp | 253 + src/libs/xpcom18a4/xpcom/ds/nsEnumeratorUtils.h | 129 + .../xpcom18a4/xpcom/ds/nsFixedSizeAllocator.cpp | 153 + src/libs/xpcom18a4/xpcom/ds/nsFixedSizeAllocator.h | 201 + src/libs/xpcom18a4/xpcom/ds/nsHashKeys.h | 315 ++ src/libs/xpcom18a4/xpcom/ds/nsHashSets.cpp | 46 + src/libs/xpcom18a4/xpcom/ds/nsHashSets.h | 107 + src/libs/xpcom18a4/xpcom/ds/nsHashtable.cpp | 896 ++++ src/libs/xpcom18a4/xpcom/ds/nsHashtable.h | 454 ++ src/libs/xpcom18a4/xpcom/ds/nsIArray.idl | 202 + src/libs/xpcom18a4/xpcom/ds/nsIAtom.idl | 161 + src/libs/xpcom18a4/xpcom/ds/nsIAtomService.idl | 73 + src/libs/xpcom18a4/xpcom/ds/nsIByteBuffer.h | 95 + src/libs/xpcom18a4/xpcom/ds/nsICollection.idl | 92 + src/libs/xpcom18a4/xpcom/ds/nsIEnumerator.idl | 89 + src/libs/xpcom18a4/xpcom/ds/nsIHashable.idl | 58 + src/libs/xpcom18a4/xpcom/ds/nsIObserver.idl | 72 + src/libs/xpcom18a4/xpcom/ds/nsIObserverService.idl | 111 + .../xpcom18a4/xpcom/ds/nsIPersistentProperties.h | 8 + .../xpcom/ds/nsIPersistentProperties2.idl | 107 + src/libs/xpcom18a4/xpcom/ds/nsIProperties.idl | 79 + src/libs/xpcom18a4/xpcom/ds/nsIPropertyBag.idl | 77 + .../xpcom18a4/xpcom/ds/nsIRecyclingAllocator.idl | 68 + src/libs/xpcom18a4/xpcom/ds/nsISerializable.idl | 65 + .../xpcom18a4/xpcom/ds/nsISimpleEnumerator.idl | 81 + .../xpcom18a4/xpcom/ds/nsIStringEnumerator.idl | 58 + src/libs/xpcom18a4/xpcom/ds/nsISupportsArray.idl | 139 + .../xpcom18a4/xpcom/ds/nsISupportsIterators.idl | 325 ++ .../xpcom18a4/xpcom/ds/nsISupportsPrimitives.idl | 304 ++ src/libs/xpcom18a4/xpcom/ds/nsITimelineService.idl | 242 + src/libs/xpcom18a4/xpcom/ds/nsIUnicharBuffer.h | 73 + src/libs/xpcom18a4/xpcom/ds/nsIVariant.idl | 188 + src/libs/xpcom18a4/xpcom/ds/nsInt64.h | 399 ++ src/libs/xpcom18a4/xpcom/ds/nsInterfaceHashtable.h | 196 + src/libs/xpcom18a4/xpcom/ds/nsManifestLineReader.h | 121 + src/libs/xpcom18a4/xpcom/ds/nsObserverList.cpp | 211 + src/libs/xpcom18a4/xpcom/ds/nsObserverList.h | 79 + src/libs/xpcom18a4/xpcom/ds/nsObserverService.cpp | 227 + src/libs/xpcom18a4/xpcom/ds/nsObserverService.h | 75 + .../xpcom18a4/xpcom/ds/nsPersistentProperties.cpp | 492 ++ .../xpcom18a4/xpcom/ds/nsPersistentProperties.h | 106 + src/libs/xpcom18a4/xpcom/ds/nsProperties.cpp | 150 + src/libs/xpcom18a4/xpcom/ds/nsProperties.h | 72 + src/libs/xpcom18a4/xpcom/ds/nsQuickSort.cpp | 182 + src/libs/xpcom18a4/xpcom/ds/nsQuickSort.h | 72 + .../xpcom18a4/xpcom/ds/nsRecyclingAllocator.cpp | 443 ++ src/libs/xpcom18a4/xpcom/ds/nsRecyclingAllocator.h | 208 + src/libs/xpcom18a4/xpcom/ds/nsRefPtrHashtable.h | 197 + src/libs/xpcom18a4/xpcom/ds/nsStaticAtom.h | 65 + src/libs/xpcom18a4/xpcom/ds/nsStaticNameTable.cpp | 217 + src/libs/xpcom18a4/xpcom/ds/nsStaticNameTable.h | 81 + src/libs/xpcom18a4/xpcom/ds/nsStringEnumerator.cpp | 261 + src/libs/xpcom18a4/xpcom/ds/nsStringEnumerator.h | 122 + src/libs/xpcom18a4/xpcom/ds/nsSupportsArray.cpp | 684 +++ src/libs/xpcom18a4/xpcom/ds/nsSupportsArray.h | 172 + .../xpcom/ds/nsSupportsArrayEnumerator.cpp | 148 + .../xpcom18a4/xpcom/ds/nsSupportsArrayEnumerator.h | 67 + .../xpcom18a4/xpcom/ds/nsSupportsPrimitives.cpp | 880 ++++ src/libs/xpcom18a4/xpcom/ds/nsSupportsPrimitives.h | 358 ++ src/libs/xpcom18a4/xpcom/ds/nsTHashtable.cpp | 62 + src/libs/xpcom18a4/xpcom/ds/nsTHashtable.h | 429 ++ src/libs/xpcom18a4/xpcom/ds/nsTextFormatter.cpp | 1557 ++++++ src/libs/xpcom18a4/xpcom/ds/nsTextFormatter.h | 115 + src/libs/xpcom18a4/xpcom/ds/nsTime.h | 143 + src/libs/xpcom18a4/xpcom/ds/nsTimelineService.cpp | 613 +++ src/libs/xpcom18a4/xpcom/ds/nsTimelineService.h | 64 + src/libs/xpcom18a4/xpcom/ds/nsUnicharBuffer.cpp | 141 + src/libs/xpcom18a4/xpcom/ds/nsUnicharBuffer.h | 65 + src/libs/xpcom18a4/xpcom/ds/nsUnitConversion.h | 207 + src/libs/xpcom18a4/xpcom/ds/nsValueArray.cpp | 304 ++ src/libs/xpcom18a4/xpcom/ds/nsValueArray.h | 125 + src/libs/xpcom18a4/xpcom/ds/nsVariant.cpp | 2092 ++++++++ src/libs/xpcom18a4/xpcom/ds/nsVariant.h | 203 + src/libs/xpcom18a4/xpcom/ds/nsVoidArray.cpp | 1560 ++++++ src/libs/xpcom18a4/xpcom/ds/nsVoidArray.h | 410 ++ src/libs/xpcom18a4/xpcom/ds/pldhash.c | 826 ++++ src/libs/xpcom18a4/xpcom/ds/pldhash.h | 603 +++ src/libs/xpcom18a4/xpcom/glue/.cvsignore | 1 + src/libs/xpcom18a4/xpcom/glue/Makefile.in | 86 + src/libs/xpcom18a4/xpcom/glue/nsCOMPtr.cpp | 124 + src/libs/xpcom18a4/xpcom/glue/nsCOMPtr.h | 1405 ++++++ .../xpcom/glue/nsComponentManagerUtils.cpp | 133 + src/libs/xpcom18a4/xpcom/glue/nsDebug.cpp | 119 + src/libs/xpcom18a4/xpcom/glue/nsDebug.h | 276 ++ src/libs/xpcom18a4/xpcom/glue/nsGenericFactory.cpp | 547 +++ src/libs/xpcom18a4/xpcom/glue/nsGenericFactory.h | 129 + src/libs/xpcom18a4/xpcom/glue/nsIGenericFactory.h | 480 ++ .../xpcom/glue/nsIInterfaceRequestorUtils.cpp | 64 + .../xpcom/glue/nsIInterfaceRequestorUtils.h | 83 + src/libs/xpcom18a4/xpcom/glue/nsISupportsImpl.h | 1246 +++++ src/libs/xpcom18a4/xpcom/glue/nsISupportsUtils.h | 230 + .../xpcom18a4/xpcom/glue/nsIWeakReferenceUtils.h | 162 + src/libs/xpcom18a4/xpcom/glue/nsMemory.cpp | 151 + src/libs/xpcom18a4/xpcom/glue/nsMemory.h | 154 + .../xpcom18a4/xpcom/glue/nsServiceManagerUtils.h | 183 + src/libs/xpcom18a4/xpcom/glue/nsTraceRefcnt.cpp | 125 + src/libs/xpcom18a4/xpcom/glue/nsTraceRefcnt.h | 135 + src/libs/xpcom18a4/xpcom/glue/nsWeakReference.cpp | 169 + src/libs/xpcom18a4/xpcom/glue/nsWeakReference.h | 150 + src/libs/xpcom18a4/xpcom/glue/objs.mk | 60 + .../xpcom18a4/xpcom/glue/standalone/.cvsignore | 8 + .../xpcom18a4/xpcom/glue/standalone/Makefile.in | 88 + .../glue/standalone/nsGREDirServiceProvider.cpp | 596 +++ .../glue/standalone/nsGREDirServiceProvider.h | 68 + .../xpcom/glue/standalone/nsXPCOMGlue.cpp | 524 ++ .../xpcom18a4/xpcom/glue/standalone/nsXPCOMGlue.h | 109 + src/libs/xpcom18a4/xpcom/io/.cvsignore | 1 + src/libs/xpcom18a4/xpcom/io/Makefile.in | 175 + .../xpcom18a4/xpcom/io/SpecialSystemDirectory.cpp | 770 +++ .../xpcom18a4/xpcom/io/SpecialSystemDirectory.h | 136 + src/libs/xpcom18a4/xpcom/io/macDirectoryCopy.c | 784 +++ src/libs/xpcom18a4/xpcom/io/macDirectoryCopy.h | 158 + .../xpcom18a4/xpcom/io/nsAppDirectoryServiceDefs.h | 120 + .../xpcom/io/nsAppFileLocationProvider.cpp | 608 +++ .../xpcom18a4/xpcom/io/nsAppFileLocationProvider.h | 67 + src/libs/xpcom18a4/xpcom/io/nsBinaryStream.cpp | 663 +++ src/libs/xpcom18a4/xpcom/io/nsBinaryStream.h | 125 + .../xpcom18a4/xpcom/io/nsByteArrayInputStream.cpp | 164 + .../xpcom18a4/xpcom/io/nsByteArrayInputStream.h | 59 + src/libs/xpcom18a4/xpcom/io/nsDirectoryService.cpp | 1241 +++++ src/libs/xpcom18a4/xpcom/io/nsDirectoryService.h | 177 + .../xpcom18a4/xpcom/io/nsDirectoryServiceDefs.h | 197 + .../xpcom18a4/xpcom/io/nsDirectoryServiceUtils.h | 61 + src/libs/xpcom18a4/xpcom/io/nsEscape.cpp | 491 ++ src/libs/xpcom18a4/xpcom/io/nsEscape.h | 196 + src/libs/xpcom18a4/xpcom/io/nsFastLoadFile.cpp | 2581 ++++++++++ src/libs/xpcom18a4/xpcom/io/nsFastLoadFile.h | 566 +++ src/libs/xpcom18a4/xpcom/io/nsFastLoadPtr.h | 112 + src/libs/xpcom18a4/xpcom/io/nsFastLoadService.cpp | 571 +++ src/libs/xpcom18a4/xpcom/io/nsFastLoadService.h | 71 + .../xpcom18a4/xpcom/io/nsIAsyncInputStream.idl | 136 + .../xpcom18a4/xpcom/io/nsIAsyncOutputStream.idl | 136 + src/libs/xpcom18a4/xpcom/io/nsIBaseStream.idl | 45 + .../xpcom18a4/xpcom/io/nsIBinaryInputStream.idl | 121 + .../xpcom18a4/xpcom/io/nsIBinaryOutputStream.idl | 119 + .../xpcom18a4/xpcom/io/nsIByteArrayInputStream.idl | 48 + .../xpcom18a4/xpcom/io/nsIDirectoryEnumerator.idl | 68 + .../xpcom18a4/xpcom/io/nsIDirectoryService.idl | 138 + .../xpcom18a4/xpcom/io/nsIFastLoadFileControl.idl | 123 + src/libs/xpcom18a4/xpcom/io/nsIFastLoadService.idl | 155 + src/libs/xpcom18a4/xpcom/io/nsIFile.idl | 343 ++ src/libs/xpcom18a4/xpcom/io/nsIInputStream.idl | 139 + src/libs/xpcom18a4/xpcom/io/nsIInputStreamTee.idl | 61 + src/libs/xpcom18a4/xpcom/io/nsILineInputStream.idl | 54 + src/libs/xpcom18a4/xpcom/io/nsILocalFile.idl | 180 + src/libs/xpcom18a4/xpcom/io/nsILocalFileMac.idl | 262 + src/libs/xpcom18a4/xpcom/io/nsILocalFileOS2.idl | 90 + .../xpcom18a4/xpcom/io/nsIMultiplexInputStream.idl | 88 + .../xpcom18a4/xpcom/io/nsIObjectInputStream.idl | 87 + .../xpcom18a4/xpcom/io/nsIObjectOutputStream.idl | 131 + .../xpcom/io/nsIObservableInputStream.idl | 67 + .../xpcom/io/nsIObservableOutputStream.idl | 67 + src/libs/xpcom18a4/xpcom/io/nsIOutputStream.idl | 167 + src/libs/xpcom18a4/xpcom/io/nsIPipe.idl | 211 + .../xpcom/io/nsIScriptableInputStream.idl | 73 + src/libs/xpcom18a4/xpcom/io/nsISeekableStream.idl | 102 + src/libs/xpcom18a4/xpcom/io/nsIStorageStream.idl | 107 + .../xpcom18a4/xpcom/io/nsIStreamBufferAccess.idl | 191 + src/libs/xpcom18a4/xpcom/io/nsIStringStream.idl | 138 + .../xpcom18a4/xpcom/io/nsIUnicharInputStream.h | 94 + src/libs/xpcom18a4/xpcom/io/nsInputStreamTee.cpp | 224 + .../xpcom18a4/xpcom/io/nsLinebreakConverter.cpp | 495 ++ src/libs/xpcom18a4/xpcom/io/nsLinebreakConverter.h | 156 + src/libs/xpcom18a4/xpcom/io/nsLocalFile.h | 118 + src/libs/xpcom18a4/xpcom/io/nsLocalFileCommon.cpp | 278 ++ src/libs/xpcom18a4/xpcom/io/nsLocalFileMac.cpp | 3554 ++++++++++++++ src/libs/xpcom18a4/xpcom/io/nsLocalFileMac.h | 137 + src/libs/xpcom18a4/xpcom/io/nsLocalFileOS2.cpp | 1742 +++++++ src/libs/xpcom18a4/xpcom/io/nsLocalFileOS2.h | 113 + src/libs/xpcom18a4/xpcom/io/nsLocalFileOSX.cpp | 2542 ++++++++++ src/libs/xpcom18a4/xpcom/io/nsLocalFileOSX.h | 119 + src/libs/xpcom18a4/xpcom/io/nsLocalFileUnicode.h | 47 + src/libs/xpcom18a4/xpcom/io/nsLocalFileUnix.cpp | 1724 +++++++ src/libs/xpcom18a4/xpcom/io/nsLocalFileUnix.h | 132 + src/libs/xpcom18a4/xpcom/io/nsLocalFileWin.cpp | 2440 ++++++++++ src/libs/xpcom18a4/xpcom/io/nsLocalFileWin.h | 113 + .../xpcom18a4/xpcom/io/nsMultiplexInputStream.cpp | 389 ++ .../xpcom18a4/xpcom/io/nsMultiplexInputStream.h | 63 + .../xpcom18a4/xpcom/io/nsNativeCharsetUtils.cpp | 1280 +++++ src/libs/xpcom18a4/xpcom/io/nsNativeCharsetUtils.h | 66 + src/libs/xpcom18a4/xpcom/io/nsPipe3.cpp | 1276 +++++ .../xpcom18a4/xpcom/io/nsScriptableInputStream.cpp | 102 + .../xpcom18a4/xpcom/io/nsScriptableInputStream.h | 71 + src/libs/xpcom18a4/xpcom/io/nsSegmentedBuffer.cpp | 207 + src/libs/xpcom18a4/xpcom/io/nsSegmentedBuffer.h | 125 + src/libs/xpcom18a4/xpcom/io/nsStorageStream.cpp | 563 +++ src/libs/xpcom18a4/xpcom/io/nsStorageStream.h | 98 + src/libs/xpcom18a4/xpcom/io/nsStreamUtils.cpp | 583 +++ src/libs/xpcom18a4/xpcom/io/nsStreamUtils.h | 111 + src/libs/xpcom18a4/xpcom/io/nsStringIO.h | 86 + src/libs/xpcom18a4/xpcom/io/nsStringStream.cpp | 457 ++ src/libs/xpcom18a4/xpcom/io/nsStringStream.h | 84 + .../xpcom18a4/xpcom/io/nsUnicharInputStream.cpp | 415 ++ .../xpcom18a4/xpcom/libxpt/xptcall/porting.html | 13 + .../xpcom18a4/xpcom/libxpt/xptcall/status.html | 13 + src/libs/xpcom18a4/xpcom/obsolete/Makefile.in | 130 + .../xpcom18a4/xpcom/obsolete/component/Makefile.in | 81 + .../xpcom/obsolete/component/nsFileSpecImpl.cpp | 857 ++++ .../xpcom/obsolete/component/nsFileSpecImpl.h | 116 + .../xpcom/obsolete/component/nsIRegistry.idl | 186 + .../xpcom/obsolete/component/nsIRegistryUtils.h | 63 + .../xpcom/obsolete/component/nsRegistry.cpp | 2019 ++++++++ .../xpcom/obsolete/component/nsRegistry.h | 77 + .../xpcom/obsolete/component/nsXPCOMObsolete.cpp | 57 + .../xpcom/obsolete/component/regExport.cpp | 357 ++ .../xpcom/obsolete/component/xpcomobsoletec.pkg | 6 + src/libs/xpcom18a4/xpcom/obsolete/dlldeps.cpp | 50 + src/libs/xpcom18a4/xpcom/obsolete/nsFileSpec.cpp | 1367 ++++++ src/libs/xpcom18a4/xpcom/obsolete/nsFileSpec.h | 782 +++ .../xpcom18a4/xpcom/obsolete/nsFileSpecBeOS.cpp | 547 +++ .../xpcom18a4/xpcom/obsolete/nsFileSpecImpl.cpp | 879 ++++ src/libs/xpcom18a4/xpcom/obsolete/nsFileSpecImpl.h | 116 + .../xpcom18a4/xpcom/obsolete/nsFileSpecMac.cpp | 1471 ++++++ .../xpcom18a4/xpcom/obsolete/nsFileSpecOS2.cpp | 840 ++++ .../xpcom18a4/xpcom/obsolete/nsFileSpecUnix.cpp | 703 +++ .../xpcom18a4/xpcom/obsolete/nsFileSpecWin.cpp | 766 +++ src/libs/xpcom18a4/xpcom/obsolete/nsFileStream.cpp | 392 ++ src/libs/xpcom18a4/xpcom/obsolete/nsFileStream.h | 772 +++ src/libs/xpcom18a4/xpcom/obsolete/nsIFileSpec.idl | 204 + .../xpcom18a4/xpcom/obsolete/nsIFileStream.cpp | 727 +++ src/libs/xpcom18a4/xpcom/obsolete/nsIFileStream.h | 157 + src/libs/xpcom18a4/xpcom/obsolete/nsIRegistry.idl | 186 + .../xpcom18a4/xpcom/obsolete/nsIRegistryUtils.h | 63 + .../xpcom/obsolete/nsSpecialSystemDirectory.cpp | 1189 +++++ .../xpcom/obsolete/nsSpecialSystemDirectory.h | 167 + .../xpcom18a4/xpcom/obsolete/nsXPCOMObsolete.cpp | 54 + src/libs/xpcom18a4/xpcom/obsolete/xpcomobsolete.h | 50 + .../xpcom18a4/xpcom/obsolete/xpcomobsolete.pkg | 7 + src/libs/xpcom18a4/xpcom/proxy/.cvsignore | 1 + src/libs/xpcom18a4/xpcom/proxy/Makefile.in | 49 + src/libs/xpcom18a4/xpcom/proxy/public/.cvsignore | 1 + src/libs/xpcom18a4/xpcom/proxy/public/Makefile.in | 63 + .../xpcom/proxy/public/nsIProxyCreateInstance.idl | 53 + .../xpcom/proxy/public/nsIProxyObjectManager.idl | 87 + .../xpcom/proxy/public/nsProxiedService.h | 164 + .../xpcom18a4/xpcom/proxy/public/nsProxyEvent.h | 183 + .../xpcom18a4/xpcom/proxy/public/nsProxyRelease.h | 112 + src/libs/xpcom18a4/xpcom/proxy/src/.cvsignore | 1 + src/libs/xpcom18a4/xpcom/proxy/src/Makefile.in | 67 + .../xpcom/proxy/src/nsIProxyCreateInstance.h | 39 + .../xpcom18a4/xpcom/proxy/src/nsProxyEvent.cpp | 613 +++ .../xpcom/proxy/src/nsProxyEventClass.cpp | 367 ++ .../xpcom/proxy/src/nsProxyEventObject.cpp | 555 +++ .../xpcom/proxy/src/nsProxyEventPrivate.h | 201 + .../xpcom/proxy/src/nsProxyObjectManager.cpp | 322 ++ .../xpcom18a4/xpcom/proxy/src/nsProxyRelease.cpp | 55 + src/libs/xpcom18a4/xpcom/proxy/tests/.cvsignore | 2 + src/libs/xpcom18a4/xpcom/proxy/tests/Makefile.in | 60 + .../xpcom18a4/xpcom/proxy/tests/nsITestProxy.idl | 9 + .../xpcom18a4/xpcom/proxy/tests/proxytests.cpp | 553 +++ src/libs/xpcom18a4/xpcom/reflect/.cvsignore | 1 + src/libs/xpcom18a4/xpcom/reflect/Makefile.in | 49 + src/libs/xpcom18a4/xpcom/reflect/Makefile.kup | 0 .../xpcom18a4/xpcom/reflect/xptcall/.cvsignore | 4 + .../xpcom18a4/xpcom/reflect/xptcall/Makefile.in | 49 + .../xpcom18a4/xpcom/reflect/xptcall/Makefile.kup | 0 src/libs/xpcom18a4/xpcom/reflect/xptcall/README | 6 + .../xpcom18a4/xpcom/reflect/xptcall/porting.html | 212 + .../xpcom/reflect/xptcall/public/.cvsignore | 1 + .../xpcom/reflect/xptcall/public/Makefile.in | 54 + .../xpcom/reflect/xptcall/public/genstubs.pl | 78 + .../xpcom/reflect/xptcall/public/xptcall.h | 271 ++ .../xpcom/reflect/xptcall/public/xptcstubsdecl.inc | 761 +++ .../xpcom/reflect/xptcall/public/xptcstubsdef.inc | 256 + .../xpcom18a4/xpcom/reflect/xptcall/src/.cvsignore | 1 + .../xpcom/reflect/xptcall/src/Makefile.in | 62 + .../xpcom/reflect/xptcall/src/Makefile.kup | 0 .../xpcom/reflect/xptcall/src/md/.cvsignore | 1 + .../xpcom/reflect/xptcall/src/md/Makefile.in | 56 + .../xpcom/reflect/xptcall/src/md/Makefile.kup | 0 .../reflect/xptcall/src/md/mac/xptcinvoke_mac.cpp | 148 + .../reflect/xptcall/src/md/mac/xptcinvoke_mac.s | 128 + .../reflect/xptcall/src/md/mac/xptcstubs_mac.cpp | 265 + .../reflect/xptcall/src/md/mac/xptcstubs_mac.s | 78 + .../xpcom/reflect/xptcall/src/md/os2/.cvsignore | 1 + .../xpcom/reflect/xptcall/src/md/os2/Makefile.in | 72 + .../reflect/xptcall/src/md/os2/xptcinvoke_emx.cpp | 185 + .../xptcall/src/md/os2/xptcinvoke_gcc_x86_os2.cpp | 159 + .../xptcall/src/md/os2/xptcinvoke_vacpp.asm | 268 + .../reflect/xptcall/src/md/os2/xptcstubs_emx.cpp | 153 + .../xptcall/src/md/os2/xptcstubs_gcc_x86_os2.cpp | 180 + .../reflect/xptcall/src/md/os2/xptcstubs_os2.cpp | 195 + .../reflect/xptcall/src/md/os2/xptcstubs_vacpp.asm | 1563 ++++++ .../xpcom/reflect/xptcall/src/md/test/.cvsignore | 2 + .../xpcom/reflect/xptcall/src/md/test/Makefile.in | 50 + .../xpcom/reflect/xptcall/src/md/test/README | 6 + .../xpcom/reflect/xptcall/src/md/test/clean.bat | 5 + .../reflect/xptcall/src/md/test/invoke_test.cpp | 239 + .../reflect/xptcall/src/md/test/mk_invoke.bat | 9 + .../xpcom/reflect/xptcall/src/md/test/mk_stub.bat | 9 + .../reflect/xptcall/src/md/test/stub_test.cpp | 210 + .../xpcom/reflect/xptcall/src/md/unix/.cvsignore | 2 + .../xpcom/reflect/xptcall/src/md/unix/Makefile.in | 416 ++ .../xpcom/reflect/xptcall/src/md/unix/Makefile.kup | 0 .../xptcall/src/md/unix/vtable_layout_x86.cpp | 62 + .../xptcall/src/md/unix/xptc_gcc_x86_unix.h | 92 + .../src/md/unix/xptc_platforms_unixish_x86.h | 161 + .../src/md/unix/xptcinvoke_amd64_darwin.cpp | 218 + .../xptcall/src/md/unix/xptcinvoke_amd64_vbox.asm | 403 ++ .../reflect/xptcall/src/md/unix/xptcinvoke_arm.cpp | 220 + .../xptcall/src/md/unix/xptcinvoke_arm64_vbox.cpp | 296 ++ .../xptcall/src/md/unix/xptcinvoke_arm_netbsd.cpp | 213 + .../xptcall/src/md/unix/xptcinvoke_asm_ipf32.s | 145 + .../xptcall/src/md/unix/xptcinvoke_asm_ipf64.s | 145 + .../xptcall/src/md/unix/xptcinvoke_asm_irix.s | 149 + .../xptcall/src/md/unix/xptcinvoke_asm_mips.s | 166 + .../src/md/unix/xptcinvoke_asm_openvms_alpha.s | 99 + .../src/md/unix/xptcinvoke_asm_osf1_alpha.s | 83 + .../xptcall/src/md/unix/xptcinvoke_asm_pa32.s | 131 + .../xptcall/src/md/unix/xptcinvoke_asm_ppc_aix.s | 146 + .../xptcall/src/md/unix/xptcinvoke_asm_ppc_aix64.s | 161 + .../src/md/unix/xptcinvoke_asm_ppc_ibmobj_aix.s | 140 + .../xptcall/src/md/unix/xptcinvoke_asm_ppc_linux.s | 113 + .../src/md/unix/xptcinvoke_asm_ppc_netbsd.s | 114 + .../src/md/unix/xptcinvoke_asm_ppc_rhapsody.s | 162 + .../src/md/unix/xptcinvoke_asm_sparc_bsdos.s | 121 + .../src/md/unix/xptcinvoke_asm_sparc_linux.s | 67 + .../src/md/unix/xptcinvoke_asm_sparc_linux_GCC3.s | 84 + .../src/md/unix/xptcinvoke_asm_sparc_netbsd.s | 71 + .../src/md/unix/xptcinvoke_asm_sparc_solaris.s | 71 + .../src/md/unix/xptcinvoke_asm_sparc_solaris_GCC.s | 71 + .../md/unix/xptcinvoke_asm_sparc_solaris_GCC3.s | 70 + .../md/unix/xptcinvoke_asm_sparc_solaris_SUNW.s | 72 + .../md/unix/xptcinvoke_asm_sparcv9_solaris_SUNW.s | 103 + .../src/md/unix/xptcinvoke_gcc_x86_unix.cpp | 215 + .../xptcall/src/md/unix/xptcinvoke_ipf32.cpp | 164 + .../xptcall/src/md/unix/xptcinvoke_ipf64.cpp | 133 + .../xptcall/src/md/unix/xptcinvoke_irix.cpp | 173 + .../xptcall/src/md/unix/xptcinvoke_linux_alpha.cpp | 181 + .../xptcall/src/md/unix/xptcinvoke_linux_m68k.cpp | 170 + .../xptcall/src/md/unix/xptcinvoke_linux_s390.cpp | 254 + .../xptcall/src/md/unix/xptcinvoke_linux_s390x.cpp | 250 + .../xptcall/src/md/unix/xptcinvoke_mips.cpp | 122 + .../xptcall/src/md/unix/xptcinvoke_netbsd_m68k.cpp | 175 + .../src/md/unix/xptcinvoke_openvms_alpha.cpp | 107 + .../xptcall/src/md/unix/xptcinvoke_osf1_alpha.cpp | 93 + .../xptcall/src/md/unix/xptcinvoke_pa32.cpp | 181 + .../xptcall/src/md/unix/xptcinvoke_ppc_aix.cpp | 106 + .../xptcall/src/md/unix/xptcinvoke_ppc_aix64.cpp | 95 + .../xptcall/src/md/unix/xptcinvoke_ppc_linux.cpp | 141 + .../xptcall/src/md/unix/xptcinvoke_ppc_netbsd.cpp | 147 + .../src/md/unix/xptcinvoke_ppc_rhapsody.cpp | 145 + .../src/md/unix/xptcinvoke_sparc_netbsd.cpp | 156 + .../src/md/unix/xptcinvoke_sparc_solaris.cpp | 156 + .../src/md/unix/xptcinvoke_sparcv9_solaris.cpp | 107 + .../xptcall/src/md/unix/xptcinvoke_unixish_x86.cpp | 187 + .../xptcall/src/md/unix/xptcinvoke_unsupported.cpp | 48 + .../src/md/unix/xptcinvoke_x86_64_linux.cpp | 227 + .../xptcall/src/md/unix/xptcinvoke_x86_solaris.cpp | 285 ++ .../xptcall/src/md/unix/xptcstubs_amd64_darwin.cpp | 243 + .../reflect/xptcall/src/md/unix/xptcstubs_arm.cpp | 244 + .../xptcall/src/md/unix/xptcstubs_arm64_vbox.cpp | 272 ++ .../xptcall/src/md/unix/xptcstubs_arm_netbsd.cpp | 145 + .../xptcall/src/md/unix/xptcstubs_asm_ipf32.s | 124 + .../xptcall/src/md/unix/xptcstubs_asm_ipf64.s | 124 + .../xptcall/src/md/unix/xptcstubs_asm_irix.s | 97 + .../xptcall/src/md/unix/xptcstubs_asm_mips.s.m4 | 109 + .../src/md/unix/xptcstubs_asm_openvms_alpha.s | 115 + .../xptcall/src/md/unix/xptcstubs_asm_osf1_alpha.s | 75 + .../xptcall/src/md/unix/xptcstubs_asm_pa32.s | 68 + .../xptcall/src/md/unix/xptcstubs_asm_ppc_aix.s | 117 + .../xptcall/src/md/unix/xptcstubs_asm_ppc_aix64.s | 137 + .../src/md/unix/xptcstubs_asm_ppc_darwin.s.m4 | 126 + .../xptcall/src/md/unix/xptcstubs_asm_ppc_linux.s | 89 + .../xptcall/src/md/unix/xptcstubs_asm_ppc_netbsd.s | 89 + .../src/md/unix/xptcstubs_asm_sparc_netbsd.s | 65 + .../src/md/unix/xptcstubs_asm_sparc_solaris.s | 65 + .../src/md/unix/xptcstubs_asm_sparcv9_solaris.s | 67 + .../xptcall/src/md/unix/xptcstubs_gcc_x86_unix.cpp | 202 + .../xptcall/src/md/unix/xptcstubs_ipf32.cpp | 185 + .../xptcall/src/md/unix/xptcstubs_ipf64.cpp | 186 + .../reflect/xptcall/src/md/unix/xptcstubs_irix.cpp | 226 + .../xptcall/src/md/unix/xptcstubs_linux_alpha.cpp | 236 + .../xptcall/src/md/unix/xptcstubs_linux_m68k.cpp | 146 + .../xptcall/src/md/unix/xptcstubs_linux_s390.cpp | 220 + .../xptcall/src/md/unix/xptcstubs_linux_s390x.cpp | 224 + .../reflect/xptcall/src/md/unix/xptcstubs_mips.cpp | 131 + .../xptcall/src/md/unix/xptcstubs_netbsd_m68k.cpp | 147 + .../src/md/unix/xptcstubs_openvms_alpha.cpp | 147 + .../xptcall/src/md/unix/xptcstubs_osf1_alpha.cpp | 149 + .../reflect/xptcall/src/md/unix/xptcstubs_pa32.cpp | 176 + .../xptcall/src/md/unix/xptcstubs_ppc_aix.cpp | 228 + .../xptcall/src/md/unix/xptcstubs_ppc_aix64.cpp | 215 + .../xptcall/src/md/unix/xptcstubs_ppc_linux.cpp | 253 + .../xptcall/src/md/unix/xptcstubs_ppc_netbsd.cpp | 217 + .../xptcall/src/md/unix/xptcstubs_ppc_rhapsody.cpp | 254 + .../xptcall/src/md/unix/xptcstubs_sparc_netbsd.cpp | 146 + .../src/md/unix/xptcstubs_sparc_solaris.cpp | 146 + .../src/md/unix/xptcstubs_sparcv9_solaris.cpp | 139 + .../xptcall/src/md/unix/xptcstubs_unixish_x86.cpp | 188 + .../xptcall/src/md/unix/xptcstubs_unsupported.cpp | 56 + .../xptcall/src/md/unix/xptcstubs_x86_64_linux.cpp | 242 + .../src/md/unix/xptcstubs_x86_64_solaris.cpp | 271 ++ .../xptcall/src/md/unix/xptcstubs_x86_solaris.cpp | 165 + .../xpcom/reflect/xptcall/src/md/win32/.cvsignore | 1 + .../xpcom/reflect/xptcall/src/md/win32/Makefile.in | 82 + .../reflect/xptcall/src/md/win32/xptcinvoke.cpp | 107 + .../xptcall/src/md/win32/xptcinvoke_alpha.cpp | 171 + .../xptcall/src/md/win32/xptcinvoke_asm_alpha.s | 128 + .../reflect/xptcall/src/md/win32/xptcstubs.cpp | 202 + .../xptcall/src/md/win32/xptcstubs_alpha.cpp | 228 + .../xptcall/src/md/win32/xptcstubs_asm_alpha.s | 120 + .../xpcom/reflect/xptcall/src/xptcall.cpp | 62 + .../xpcom/reflect/xptcall/src/xptcprivate.h | 45 + .../xpcom18a4/xpcom/reflect/xptcall/status.html | 404 ++ .../xpcom/reflect/xptcall/tests/.cvsignore | 2 + .../xpcom/reflect/xptcall/tests/Makefile.in | 64 + .../xpcom/reflect/xptcall/tests/TestXPTCInvoke.cpp | 1464 ++++++ .../xpcom18a4/xpcom/reflect/xptinfo/.cvsignore | 1 + .../xpcom18a4/xpcom/reflect/xptinfo/Makefile.in | 49 + .../xpcom/reflect/xptinfo/public/.cvsignore | 1 + .../xpcom/reflect/xptinfo/public/Makefile.in | 66 + .../reflect/xptinfo/public/nsIInterfaceInfo.idl | 137 + .../xptinfo/public/nsIInterfaceInfoManager.idl | 85 + .../xpcom/reflect/xptinfo/public/nsIXPTLoader.idl | 100 + .../xpcom/reflect/xptinfo/public/xptinfo.h | 281 ++ .../xpcom18a4/xpcom/reflect/xptinfo/src/.cvsignore | 1 + .../xpcom/reflect/xptinfo/src/Makefile.in | 75 + src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/TODO | 20 + .../xpcom/reflect/xptinfo/src/xptiFile.cpp | 113 + .../reflect/xptinfo/src/xptiInterfaceInfo.cpp | 819 ++++ .../xptinfo/src/xptiInterfaceInfoManager.cpp | 2126 ++++++++ .../xpcom/reflect/xptinfo/src/xptiManifest.cpp | 710 +++ .../xpcom/reflect/xptinfo/src/xptiMisc.cpp | 164 + .../xpcom/reflect/xptinfo/src/xptiTypelibGuts.cpp | 63 + .../xpcom/reflect/xptinfo/src/xptiWorkingSet.cpp | 432 ++ .../xpcom/reflect/xptinfo/src/xptiZipItem.cpp | 102 + .../xpcom/reflect/xptinfo/src/xptiZipLoader.cpp | 113 + .../xpcom/reflect/xptinfo/src/xptiprivate.h | 981 ++++ .../xpcom/reflect/xptinfo/tests/.cvsignore | 2 + .../xpcom/reflect/xptinfo/tests/Makefile.in | 58 + .../reflect/xptinfo/tests/TestInterfaceInfo.cpp | 146 + src/libs/xpcom18a4/xpcom/sample/.cvsignore | 2 + src/libs/xpcom18a4/xpcom/sample/Makefile.in | 113 + src/libs/xpcom18a4/xpcom/sample/nsISample.idl | 66 + src/libs/xpcom18a4/xpcom/sample/nsSample.cpp | 181 + src/libs/xpcom18a4/xpcom/sample/nsSample.h | 129 + src/libs/xpcom18a4/xpcom/sample/nsSample.js | 130 + src/libs/xpcom18a4/xpcom/sample/nsSampleModule.cpp | 131 + src/libs/xpcom18a4/xpcom/sample/nsTestSample.cpp | 158 + src/libs/xpcom18a4/xpcom/sample/win32.order | 1 + .../xpcom18a4/xpcom/sample/xpconnect-sample.html | 220 + src/libs/xpcom18a4/xpcom/string/.cvsignore | 1 + src/libs/xpcom18a4/xpcom/string/Makefile.in | 54 + src/libs/xpcom18a4/xpcom/string/README.html | 44 + src/libs/xpcom18a4/xpcom/string/doc/README.html | 44 + .../xpcom18a4/xpcom/string/doc/string-guide.html | 2508 ++++++++++ src/libs/xpcom18a4/xpcom/string/public/.cvsignore | 1 + src/libs/xpcom18a4/xpcom/string/public/Makefile.in | 86 + src/libs/xpcom18a4/xpcom/string/public/nsAString.h | 96 + .../xpcom18a4/xpcom/string/public/nsAlgorithm.h | 131 + .../xpcom18a4/xpcom/string/public/nsCharTraits.h | 784 +++ .../xpcom/string/public/nsDependentString.h | 60 + .../xpcom/string/public/nsDependentSubstring.h | 56 + .../xpcom18a4/xpcom/string/public/nsEmbedString.h | 158 + .../xpcom/string/public/nsLiteralString.h | 116 + .../xpcom/string/public/nsObsoleteAString.h | 102 + .../xpcom/string/public/nsPrintfCString.h | 87 + .../xpcom/string/public/nsPromiseFlatString.h | 56 + .../xpcom/string/public/nsReadableUtils.h | 370 ++ src/libs/xpcom18a4/xpcom/string/public/nsString.h | 237 + .../xpcom18a4/xpcom/string/public/nsStringAPI.h | 853 ++++ .../xpcom18a4/xpcom/string/public/nsStringFwd.h | 96 + .../xpcom/string/public/nsStringIterator.h | 373 ++ .../xpcom18a4/xpcom/string/public/nsSubstring.h | 74 + .../xpcom/string/public/nsSubstringTuple.h | 56 + .../xpcom18a4/xpcom/string/public/nsTAString.h | 618 +++ .../xpcom/string/public/nsTDependentString.h | 137 + .../xpcom/string/public/nsTDependentSubstring.h | 143 + .../xpcom/string/public/nsTObsoleteAString.h | 165 + .../xpcom/string/public/nsTPromiseFlatString.h | 158 + src/libs/xpcom18a4/xpcom/string/public/nsTString.h | 721 +++ .../xpcom18a4/xpcom/string/public/nsTSubstring.h | 575 +++ .../xpcom/string/public/nsTSubstringTuple.h | 113 + .../xpcom18a4/xpcom/string/public/nsUTF8Utils.h | 462 ++ .../xpcom18a4/xpcom/string/public/nsXPIDLString.h | 46 + .../xpcom/string/public/string-template-def-char.h | 58 + .../string/public/string-template-def-unichar.h | 58 + .../xpcom/string/public/string-template-undef.h | 59 + src/libs/xpcom18a4/xpcom/string/src/.cvsignore | 1 + src/libs/xpcom18a4/xpcom/string/src/Makefile.in | 77 + src/libs/xpcom18a4/xpcom/string/src/nsAString.cpp | 51 + .../xpcom/string/src/nsDependentSubstring.cpp | 50 + .../xpcom/string/src/nsObsoleteAStringThunk.cpp | 52 + .../xpcom18a4/xpcom/string/src/nsPrintfCString.cpp | 83 + .../xpcom/string/src/nsPromiseFlatString.cpp | 49 + .../xpcom18a4/xpcom/string/src/nsReadableUtils.cpp | 1122 +++++ src/libs/xpcom18a4/xpcom/string/src/nsString.cpp | 49 + .../xpcom/string/src/nsStringComparator.cpp | 75 + .../xpcom/string/src/nsStringObsolete.cpp | 1327 +++++ .../xpcom18a4/xpcom/string/src/nsSubstring.cpp | 250 + .../xpcom/string/src/nsSubstringTuple.cpp | 64 + src/libs/xpcom18a4/xpcom/string/src/nsTAString.cpp | 509 ++ .../xpcom/string/src/nsTDependentSubstring.cpp | 65 + .../xpcom/string/src/nsTObsoleteAStringThunk.cpp | 235 + .../xpcom/string/src/nsTPromiseFlatString.cpp | 66 + src/libs/xpcom18a4/xpcom/string/src/nsTString.cpp | 63 + .../xpcom/string/src/nsTStringComparator.cpp | 79 + .../xpcom/string/src/nsTStringObsolete.cpp | 518 ++ .../xpcom18a4/xpcom/string/src/nsTSubstring.cpp | 656 +++ .../xpcom/string/src/nsTSubstringTuple.cpp | 127 + src/libs/xpcom18a4/xpcom/stub/nsStringAPI.cpp | 261 + src/libs/xpcom18a4/xpcom/tests/.cvsignore | 31 + src/libs/xpcom18a4/xpcom/tests/CvtURL.cpp | 126 + src/libs/xpcom18a4/xpcom/tests/Makefile.in | 116 + src/libs/xpcom18a4/xpcom/tests/RegFactory.cpp | 162 + src/libs/xpcom18a4/xpcom/tests/SizeTest01.cpp | 107 + src/libs/xpcom18a4/xpcom/tests/SizeTest02.cpp | 93 + src/libs/xpcom18a4/xpcom/tests/SizeTest03.cpp | 101 + src/libs/xpcom18a4/xpcom/tests/SizeTest04.cpp | 72 + src/libs/xpcom18a4/xpcom/tests/SizeTest05.cpp | 78 + src/libs/xpcom18a4/xpcom/tests/SizeTest06.cpp | 231 + .../xpcom/tests/StringFactoringTests/Makefile.in | 76 + .../tests/StringFactoringTests/StringTest.Prefix | 4 + .../tests/StringFactoringTests/StringTest.mcp | Bin 0 -> 245184 bytes .../StringFactoringTests/StringTestDebug.Prefix | 4 + .../StringTestNo_wchar_t.Prefix | 5 + .../StringTestProfileNew.Prefix | 3 + .../StringTestProfileOld.Prefix | 6 + .../StringTestProfileStd.Prefix | 7 + .../xpcom/tests/StringFactoringTests/ToDo.doc | 41 + .../StringFactoringTests/nsStdStringWrapper.h | 234 + .../tests/StringFactoringTests/profile_main.cpp | 497 ++ .../xpcom/tests/StringFactoringTests/test_main.cpp | 651 +++ src/libs/xpcom18a4/xpcom/tests/TestArray.cpp | 230 + src/libs/xpcom18a4/xpcom/tests/TestAtoms.cpp | 132 + src/libs/xpcom18a4/xpcom/tests/TestAutoLock.cpp | 91 + src/libs/xpcom18a4/xpcom/tests/TestAutoPtr.cpp | 566 +++ src/libs/xpcom18a4/xpcom/tests/TestCOMPtr.cpp | 651 +++ src/libs/xpcom18a4/xpcom/tests/TestCOMPtrEq.cpp | 200 + src/libs/xpcom18a4/xpcom/tests/TestCRT.cpp | 112 + .../xpcom18a4/xpcom/tests/TestCallTemplates.cpp | 129 + src/libs/xpcom18a4/xpcom/tests/TestDeque.cpp | 155 + src/libs/xpcom18a4/xpcom/tests/TestFactory.cpp | 160 + src/libs/xpcom18a4/xpcom/tests/TestFactory.h | 69 + src/libs/xpcom18a4/xpcom/tests/TestHashtables.cpp | 939 ++++ src/libs/xpcom18a4/xpcom/tests/TestID.cpp | 77 + .../xpcom18a4/xpcom/tests/TestMinStringAPI.cpp | 333 ++ .../xpcom18a4/xpcom/tests/TestObserverService.cpp | 250 + .../xpcom18a4/xpcom/tests/TestPermanentAtoms.cpp | 88 + src/libs/xpcom18a4/xpcom/tests/TestPipes.cpp | 655 +++ src/libs/xpcom18a4/xpcom/tests/TestServMgr.cpp | 173 + src/libs/xpcom18a4/xpcom/tests/TestShutdown.cpp | 78 + src/libs/xpcom18a4/xpcom/tests/TestStackCrawl.cpp | 11 + src/libs/xpcom18a4/xpcom/tests/TestStrings.cpp | 643 +++ src/libs/xpcom18a4/xpcom/tests/TestThreads.cpp | 280 ++ src/libs/xpcom18a4/xpcom/tests/TestVoidBTree.cpp | 302 ++ src/libs/xpcom18a4/xpcom/tests/TestXPIDLString.cpp | 18 + src/libs/xpcom18a4/xpcom/tests/dynamic/.cvsignore | 1 + src/libs/xpcom18a4/xpcom/tests/dynamic/Makefile.in | 61 + .../xpcom18a4/xpcom/tests/dynamic/TestDynamic.cpp | 76 + src/libs/xpcom18a4/xpcom/tests/dynamic/win32.order | 1 + .../xpcom18a4/xpcom/tests/nsIFileEnumerator.cpp | 95 + src/libs/xpcom18a4/xpcom/tests/nsIFileTest.cpp | 475 ++ src/libs/xpcom18a4/xpcom/tests/resources.h | 52 + src/libs/xpcom18a4/xpcom/tests/services/.cvsignore | 1 + .../xpcom18a4/xpcom/tests/services/Makefile.in | 58 + .../xpcom18a4/xpcom/tests/services/MyService.cpp | 93 + .../xpcom18a4/xpcom/tests/services/MyService.h | 69 + .../xpcom18a4/xpcom/tests/services/win32.order | 1 + src/libs/xpcom18a4/xpcom/tests/test.properties | 46 + src/libs/xpcom18a4/xpcom/tests/utils/WhatError.cpp | 61 + src/libs/xpcom18a4/xpcom/tests/utils/cp.js | 111 + src/libs/xpcom18a4/xpcom/tests/utils/dirs.js | 155 + src/libs/xpcom18a4/xpcom/tests/utils/ls.js | 64 + src/libs/xpcom18a4/xpcom/tests/windows/.cvsignore | 1 + src/libs/xpcom18a4/xpcom/tests/windows/Makefile.in | 60 + src/libs/xpcom18a4/xpcom/tests/windows/TestCOM.cpp | 181 + .../xpcom/tests/windows/TestHelloXPLoop.cpp | 177 + .../xpcom18a4/xpcom/tests/windows/nsStringTest.cpp | 33 + .../xpcom18a4/xpcom/tests/windows/nsStringTest.h | 2277 +++++++++ .../xpcom18a4/xpcom/tests/windows/nsStringTest2.h | 444 ++ src/libs/xpcom18a4/xpcom/threads/.cvsignore | 1 + src/libs/xpcom18a4/xpcom/threads/Makefile.in | 105 + src/libs/xpcom18a4/xpcom/threads/TimerThread.cpp | 462 ++ src/libs/xpcom18a4/xpcom/threads/TimerThread.h | 122 + src/libs/xpcom18a4/xpcom/threads/nsAutoLock.cpp | 435 ++ src/libs/xpcom18a4/xpcom/threads/nsAutoLock.h | 383 ++ src/libs/xpcom18a4/xpcom/threads/nsEnvironment.cpp | 202 + src/libs/xpcom18a4/xpcom/threads/nsEnvironment.h | 67 + src/libs/xpcom18a4/xpcom/threads/nsEventQueue.cpp | 632 +++ src/libs/xpcom18a4/xpcom/threads/nsEventQueue.h | 89 + .../xpcom/threads/nsEventQueueService.cpp | 450 ++ .../xpcom18a4/xpcom/threads/nsEventQueueService.h | 77 + .../xpcom18a4/xpcom/threads/nsEventQueueUtils.h | 78 + .../xpcom18a4/xpcom/threads/nsIEnvironment.idl | 89 + src/libs/xpcom18a4/xpcom/threads/nsIEventQueue.idl | 107 + .../xpcom/threads/nsIEventQueueService.idl | 151 + .../xpcom18a4/xpcom/threads/nsIEventTarget.idl | 67 + src/libs/xpcom18a4/xpcom/threads/nsIProcess.idl | 32 + src/libs/xpcom18a4/xpcom/threads/nsIRunnable.idl | 44 + src/libs/xpcom18a4/xpcom/threads/nsIThread.idl | 144 + src/libs/xpcom18a4/xpcom/threads/nsITimer.idl | 191 + .../xpcom18a4/xpcom/threads/nsITimerInternal.idl | 48 + .../xpcom18a4/xpcom/threads/nsITimerManager.idl | 61 + .../xpcom18a4/xpcom/threads/nsPIEventQueueChain.h | 93 + src/libs/xpcom18a4/xpcom/threads/nsProcess.h | 71 + .../xpcom18a4/xpcom/threads/nsProcessCommon.cpp | 363 ++ src/libs/xpcom18a4/xpcom/threads/nsProcessMac.cpp | 188 + src/libs/xpcom18a4/xpcom/threads/nsThread.cpp | 457 ++ src/libs/xpcom18a4/xpcom/threads/nsThread.h | 92 + src/libs/xpcom18a4/xpcom/threads/nsTimerImpl.cpp | 642 +++ src/libs/xpcom18a4/xpcom/threads/nsTimerImpl.h | 195 + src/libs/xpcom18a4/xpcom/threads/plevent.c | 1774 +++++++ src/libs/xpcom18a4/xpcom/threads/plevent.h | 690 +++ src/libs/xpcom18a4/xpcom/tools/.cvsignore | 1 + src/libs/xpcom18a4/xpcom/tools/Makefile.in | 53 + .../xpcom18a4/xpcom/tools/analyze-xpcom-log.pl | 177 + src/libs/xpcom18a4/xpcom/tools/registry/.cvsignore | 3 + .../xpcom18a4/xpcom/tools/registry/Makefile.in | 77 + .../xpcom18a4/xpcom/tools/registry/regxpcom.cpp | 404 ++ src/libs/xpcom18a4/xpcom/tools/windows/.cvsignore | 1 + src/libs/xpcom18a4/xpcom/tools/windows/Makefile.in | 52 + .../xpcom18a4/xpcom/tools/windows/rebasedlls.cpp | 104 + src/libs/xpcom18a4/xpcom/typelib/.cvsignore | 1 + src/libs/xpcom18a4/xpcom/typelib/Makefile.in | 49 + src/libs/xpcom18a4/xpcom/typelib/xpidl/.cvsignore | 2 + src/libs/xpcom18a4/xpcom/typelib/xpidl/Makefile.in | 88 + src/libs/xpcom18a4/xpcom/typelib/xpidl/README | 16 + .../xpcom/typelib/xpidl/macplugin/compiler.rsrc | Bin 0 -> 915 bytes .../xpcom/typelib/xpidl/macplugin/linker.rsrc | Bin 0 -> 984 bytes .../xpcom/typelib/xpidl/macplugin/mac_console.c | 139 + .../xpcom/typelib/xpidl/macplugin/mac_console.h | 49 + .../xpcom/typelib/xpidl/macplugin/mac_memory.cpp | 146 + .../xpcom/typelib/xpidl/macplugin/mac_stdlib.cpp | 58 + .../xpcom/typelib/xpidl/macplugin/mac_strings.cpp | 38 + .../xpcom/typelib/xpidl/macplugin/mac_strings.h | 47 + .../xpcom/typelib/xpidl/macplugin/mac_xpidl.cpp | 417 ++ .../xpcom/typelib/xpidl/macplugin/mac_xpidl.h | 25 + .../typelib/xpidl/macplugin/mac_xpidl_panel.cpp | 695 +++ .../typelib/xpidl/macplugin/mac_xpidl_panel.h | 106 + .../typelib/xpidl/macplugin/mac_xpt_linker.cpp | 546 +++ .../xpcom/typelib/xpidl/macplugin/panel.rsrc | Bin 0 -> 16238 bytes .../xpcom/typelib/xpidl/macplugin/version.rsrc | Bin 0 -> 755 bytes src/libs/xpcom18a4/xpcom/typelib/xpidl/xpidl.c | 275 ++ src/libs/xpcom18a4/xpcom/typelib/xpidl/xpidl.h | 278 ++ src/libs/xpcom18a4/xpcom/typelib/xpidl/xpidl_doc.c | 312 ++ .../xpcom18a4/xpcom/typelib/xpidl/xpidl_header.c | 1196 +++++ src/libs/xpcom18a4/xpcom/typelib/xpidl/xpidl_idl.c | 836 ++++ .../xpcom18a4/xpcom/typelib/xpidl/xpidl_java.c | 1053 ++++ .../xpcom18a4/xpcom/typelib/xpidl/xpidl_typelib.c | 1237 +++++ .../xpcom18a4/xpcom/typelib/xpidl/xpidl_util.c | 851 ++++ src/libs/xpcom18a4/xpcom/typelib/xpt/.cvsignore | 1 + src/libs/xpcom18a4/xpcom/typelib/xpt/Makefile.in | 50 + .../xpcom18a4/xpcom/typelib/xpt/public/.cvsignore | 1 + .../xpcom18a4/xpcom/typelib/xpt/public/Makefile.in | 51 + .../xpcom18a4/xpcom/typelib/xpt/public/xpt_arena.h | 145 + .../xpcom/typelib/xpt/public/xpt_struct.h | 562 +++ .../xpcom18a4/xpcom/typelib/xpt/public/xpt_xdr.h | 240 + .../xpcom18a4/xpcom/typelib/xpt/src/.cvsignore | 1 + .../xpcom18a4/xpcom/typelib/xpt/src/Makefile.in | 76 + .../xpcom18a4/xpcom/typelib/xpt/src/xpt_arena.c | 358 ++ .../xpcom18a4/xpcom/typelib/xpt/src/xpt_struct.c | 956 ++++ src/libs/xpcom18a4/xpcom/typelib/xpt/src/xpt_xdr.c | 665 +++ .../xpcom18a4/xpcom/typelib/xpt/tests/.cvsignore | 3 + .../xpcom18a4/xpcom/typelib/xpt/tests/Makefile.in | 59 + .../xpcom/typelib/xpt/tests/PrimitiveTest.c | 157 + .../xpcom/typelib/xpt/tests/SimpleTypeLib.c | 192 + .../xpcom18a4/xpcom/typelib/xpt/tools/.cvsignore | 3 + .../xpcom18a4/xpcom/typelib/xpt/tools/Makefile.in | 90 + .../xpcom18a4/xpcom/typelib/xpt/tools/xpt_dump.c | 941 ++++ .../xpcom18a4/xpcom/typelib/xpt/tools/xpt_link.c | 883 ++++ src/libs/xpcom18a4/xpcom/windbgdlg/.cvsignore | 1 + src/libs/xpcom18a4/xpcom/windbgdlg/Makefile.in | 50 + src/libs/xpcom18a4/xpcom/windbgdlg/windbgdlg.cpp | 60 + src/libs/xpcom18a4/xpcom/xpcom-config.h.in | 65 + src/libs/xpcom18a4/xpcom/xpcom-private.h.in | 31 + 805 files changed, 208361 insertions(+) create mode 100644 src/libs/xpcom18a4/xpcom/.cvsignore create mode 100644 src/libs/xpcom18a4/xpcom/Makefile.in create mode 100644 src/libs/xpcom18a4/xpcom/Makefile.kup create mode 100644 src/libs/xpcom18a4/xpcom/MoreFiles/.cvsignore create mode 100644 src/libs/xpcom18a4/xpcom/MoreFiles/Makefile.in create mode 100644 src/libs/xpcom18a4/xpcom/MoreFiles/MoreFilesX.c create mode 100644 src/libs/xpcom18a4/xpcom/MoreFiles/MoreFilesX.h create mode 100644 src/libs/xpcom18a4/xpcom/base/.cvsignore create mode 100644 src/libs/xpcom18a4/xpcom/base/Makefile.in create mode 100644 src/libs/xpcom18a4/xpcom/base/nsAgg.h create mode 100644 src/libs/xpcom18a4/xpcom/base/nsAllocator.cpp create mode 100644 src/libs/xpcom18a4/xpcom/base/nsAllocator.h create mode 100644 src/libs/xpcom18a4/xpcom/base/nsAutoPtr.h create mode 100644 src/libs/xpcom18a4/xpcom/base/nsCom.h create mode 100644 src/libs/xpcom18a4/xpcom/base/nsConsoleMessage.cpp create mode 100644 src/libs/xpcom18a4/xpcom/base/nsConsoleMessage.h create mode 100644 src/libs/xpcom18a4/xpcom/base/nsConsoleService.cpp create mode 100644 src/libs/xpcom18a4/xpcom/base/nsConsoleService.h create mode 100644 src/libs/xpcom18a4/xpcom/base/nsDebugImpl.cpp create mode 100644 src/libs/xpcom18a4/xpcom/base/nsDebugImpl.h create mode 100644 src/libs/xpcom18a4/xpcom/base/nsError.h create mode 100644 src/libs/xpcom18a4/xpcom/base/nsErrorService.cpp create mode 100644 src/libs/xpcom18a4/xpcom/base/nsErrorService.h create mode 100644 src/libs/xpcom18a4/xpcom/base/nsExceptionService.cpp create mode 100644 src/libs/xpcom18a4/xpcom/base/nsExceptionService.h create mode 100644 src/libs/xpcom18a4/xpcom/base/nsGarbageCollector.c create mode 100644 src/libs/xpcom18a4/xpcom/base/nsIAllocator.h create mode 100644 src/libs/xpcom18a4/xpcom/base/nsIConsoleListener.idl create mode 100644 src/libs/xpcom18a4/xpcom/base/nsIConsoleMessage.idl create mode 100644 src/libs/xpcom18a4/xpcom/base/nsIConsoleService.idl create mode 100644 src/libs/xpcom18a4/xpcom/base/nsID.cpp create mode 100644 src/libs/xpcom18a4/xpcom/base/nsID.h create mode 100644 src/libs/xpcom18a4/xpcom/base/nsIDebug.idl create mode 100644 src/libs/xpcom18a4/xpcom/base/nsIErrorService.idl create mode 100644 src/libs/xpcom18a4/xpcom/base/nsIException.idl create mode 100644 src/libs/xpcom18a4/xpcom/base/nsIExceptionService.idl create mode 100644 src/libs/xpcom18a4/xpcom/base/nsIID.h create mode 100644 src/libs/xpcom18a4/xpcom/base/nsIInterfaceRequestor.idl create mode 100644 src/libs/xpcom18a4/xpcom/base/nsILeakDetector.idl create mode 100644 src/libs/xpcom18a4/xpcom/base/nsIMemory.idl create mode 100644 src/libs/xpcom18a4/xpcom/base/nsIProgrammingLanguage.idl create mode 100644 src/libs/xpcom18a4/xpcom/base/nsISupports.idl create mode 100644 src/libs/xpcom18a4/xpcom/base/nsISupportsBase.h create mode 100644 src/libs/xpcom18a4/xpcom/base/nsISupportsObsolete.h create mode 100644 src/libs/xpcom18a4/xpcom/base/nsISystemInfo.idl create mode 100644 src/libs/xpcom18a4/xpcom/base/nsITraceRefcnt.idl create mode 100644 src/libs/xpcom18a4/xpcom/base/nsIWeakReference.idl create mode 100644 src/libs/xpcom18a4/xpcom/base/nsLeakDetector.cpp create mode 100644 src/libs/xpcom18a4/xpcom/base/nsLeakDetector.h create mode 100644 src/libs/xpcom18a4/xpcom/base/nsMemoryImpl.cpp create mode 100644 src/libs/xpcom18a4/xpcom/base/nsMemoryImpl.h create mode 100644 src/libs/xpcom18a4/xpcom/base/nsStackFrameUnix.cpp create mode 100644 src/libs/xpcom18a4/xpcom/base/nsStackFrameUnix.h create mode 100644 src/libs/xpcom18a4/xpcom/base/nsStackFrameWin.cpp create mode 100644 src/libs/xpcom18a4/xpcom/base/nsStackFrameWin.h create mode 100644 src/libs/xpcom18a4/xpcom/base/nsTraceRefcntImpl.cpp create mode 100644 src/libs/xpcom18a4/xpcom/base/nsTraceRefcntImpl.h create mode 100644 src/libs/xpcom18a4/xpcom/base/nsWeakPtr.h create mode 100644 src/libs/xpcom18a4/xpcom/base/nscore.h create mode 100644 src/libs/xpcom18a4/xpcom/base/nsrootidl.idl create mode 100644 src/libs/xpcom18a4/xpcom/base/pure.h create mode 100644 src/libs/xpcom18a4/xpcom/base/pure_api.c create mode 100644 src/libs/xpcom18a4/xpcom/build/.cvsignore create mode 100644 src/libs/xpcom18a4/xpcom/build/Makefile.in create mode 100644 src/libs/xpcom18a4/xpcom/build/dlldeps.cpp create mode 100644 src/libs/xpcom18a4/xpcom/build/malloc.c create mode 100644 src/libs/xpcom18a4/xpcom/build/nsOS2VACLegacy.cpp create mode 100644 src/libs/xpcom18a4/xpcom/build/nsStringAPI.cpp create mode 100644 src/libs/xpcom18a4/xpcom/build/nsXPCOM.h create mode 100644 src/libs/xpcom18a4/xpcom/build/nsXPCOMCID.h create mode 100644 src/libs/xpcom18a4/xpcom/build/nsXPCOMPrivate.h create mode 100644 src/libs/xpcom18a4/xpcom/build/nsXPComInit.cpp create mode 100644 src/libs/xpcom18a4/xpcom/build/win32.order create mode 100644 src/libs/xpcom18a4/xpcom/build/xpcom-tests.pkg create mode 100644 src/libs/xpcom18a4/xpcom/build/xpcom.pkg create mode 100644 src/libs/xpcom18a4/xpcom/build/xpcom_alpha.def create mode 100644 src/libs/xpcom18a4/xpcom/components/.cvsignore create mode 100644 src/libs/xpcom18a4/xpcom/components/Makefile.in create mode 100644 src/libs/xpcom18a4/xpcom/components/nsCategoryManager.cpp create mode 100644 src/libs/xpcom18a4/xpcom/components/nsCategoryManager.h create mode 100644 src/libs/xpcom18a4/xpcom/components/nsCategoryManagerUtils.h create mode 100644 src/libs/xpcom18a4/xpcom/components/nsComponentManager.cpp create mode 100644 src/libs/xpcom18a4/xpcom/components/nsComponentManager.h create mode 100644 src/libs/xpcom18a4/xpcom/components/nsComponentManagerObsolete.cpp create mode 100644 src/libs/xpcom18a4/xpcom/components/nsComponentManagerObsolete.h create mode 100644 src/libs/xpcom18a4/xpcom/components/nsComponentManagerUtils.h create mode 100644 src/libs/xpcom18a4/xpcom/components/nsICategoryManager.idl create mode 100644 src/libs/xpcom18a4/xpcom/components/nsIClassInfo.idl create mode 100644 src/libs/xpcom18a4/xpcom/components/nsIComponentLoader.idl create mode 100644 src/libs/xpcom18a4/xpcom/components/nsIComponentLoaderManager.idl create mode 100644 src/libs/xpcom18a4/xpcom/components/nsIComponentManager.idl create mode 100644 src/libs/xpcom18a4/xpcom/components/nsIComponentManagerObsolete.idl create mode 100644 src/libs/xpcom18a4/xpcom/components/nsIComponentManagerUtils.h create mode 100644 src/libs/xpcom18a4/xpcom/components/nsIComponentRegistrar.idl create mode 100644 src/libs/xpcom18a4/xpcom/components/nsIFactory.idl create mode 100644 src/libs/xpcom18a4/xpcom/components/nsIModule.idl create mode 100644 src/libs/xpcom18a4/xpcom/components/nsINativeComponentLoader.idl create mode 100644 src/libs/xpcom18a4/xpcom/components/nsIServiceManager.idl create mode 100644 src/libs/xpcom18a4/xpcom/components/nsIServiceManagerObsolete.h create mode 100644 src/libs/xpcom18a4/xpcom/components/nsIServiceManagerUtils.h create mode 100644 src/libs/xpcom18a4/xpcom/components/nsModule.h create mode 100644 src/libs/xpcom18a4/xpcom/components/nsNativeComponentLoader.cpp create mode 100644 src/libs/xpcom18a4/xpcom/components/nsNativeComponentLoader.h create mode 100644 src/libs/xpcom18a4/xpcom/components/nsObsoleteModuleLoading.h create mode 100644 src/libs/xpcom18a4/xpcom/components/nsServiceManagerObsolete.cpp create mode 100644 src/libs/xpcom18a4/xpcom/components/nsStaticComponent.h create mode 100644 src/libs/xpcom18a4/xpcom/components/nsStaticComponentLoader.cpp create mode 100644 src/libs/xpcom18a4/xpcom/components/xcDll.cpp create mode 100644 src/libs/xpcom18a4/xpcom/components/xcDll.h create mode 100644 src/libs/xpcom18a4/xpcom/doc/README create mode 100644 src/libs/xpcom18a4/xpcom/ds/.cvsignore create mode 100644 src/libs/xpcom18a4/xpcom/ds/Makefile.in create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsArray.cpp create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsArray.h create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsArrayEnumerator.cpp create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsArrayEnumerator.h create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsAtomService.cpp create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsAtomService.h create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsAtomTable.cpp create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsAtomTable.h create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsAutoBuffer.h create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsBaseHashtable.h create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsByteBuffer.cpp create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsByteBuffer.h create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsCOMArray.cpp create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsCOMArray.h create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsCRT.cpp create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsCRT.h create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsCheapSets.cpp create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsCheapSets.h create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsClassHashtable.h create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsCppSharedAllocator.h create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsDataHashtable.h create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsDeque.cpp create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsDeque.h create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsDoubleHashtable.h create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsEmptyEnumerator.cpp create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsEmptyEnumerator.h create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsEnumeratorUtils.cpp create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsEnumeratorUtils.h create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsFixedSizeAllocator.cpp create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsFixedSizeAllocator.h create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsHashKeys.h create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsHashSets.cpp create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsHashSets.h create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsHashtable.cpp create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsHashtable.h create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsIArray.idl create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsIAtom.idl create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsIAtomService.idl create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsIByteBuffer.h create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsICollection.idl create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsIEnumerator.idl create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsIHashable.idl create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsIObserver.idl create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsIObserverService.idl create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsIPersistentProperties.h create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsIPersistentProperties2.idl create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsIProperties.idl create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsIPropertyBag.idl create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsIRecyclingAllocator.idl create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsISerializable.idl create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsISimpleEnumerator.idl create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsIStringEnumerator.idl create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsISupportsArray.idl create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsISupportsIterators.idl create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsISupportsPrimitives.idl create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsITimelineService.idl create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsIUnicharBuffer.h create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsIVariant.idl create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsInt64.h create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsInterfaceHashtable.h create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsManifestLineReader.h create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsObserverList.cpp create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsObserverList.h create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsObserverService.cpp create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsObserverService.h create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsPersistentProperties.cpp create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsPersistentProperties.h create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsProperties.cpp create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsProperties.h create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsQuickSort.cpp create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsQuickSort.h create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsRecyclingAllocator.cpp create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsRecyclingAllocator.h create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsRefPtrHashtable.h create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsStaticAtom.h create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsStaticNameTable.cpp create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsStaticNameTable.h create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsStringEnumerator.cpp create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsStringEnumerator.h create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsSupportsArray.cpp create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsSupportsArray.h create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsSupportsArrayEnumerator.cpp create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsSupportsArrayEnumerator.h create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsSupportsPrimitives.cpp create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsSupportsPrimitives.h create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsTHashtable.cpp create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsTHashtable.h create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsTextFormatter.cpp create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsTextFormatter.h create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsTime.h create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsTimelineService.cpp create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsTimelineService.h create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsUnicharBuffer.cpp create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsUnicharBuffer.h create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsUnitConversion.h create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsValueArray.cpp create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsValueArray.h create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsVariant.cpp create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsVariant.h create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsVoidArray.cpp create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsVoidArray.h create mode 100644 src/libs/xpcom18a4/xpcom/ds/pldhash.c create mode 100644 src/libs/xpcom18a4/xpcom/ds/pldhash.h create mode 100644 src/libs/xpcom18a4/xpcom/glue/.cvsignore create mode 100644 src/libs/xpcom18a4/xpcom/glue/Makefile.in create mode 100644 src/libs/xpcom18a4/xpcom/glue/nsCOMPtr.cpp create mode 100644 src/libs/xpcom18a4/xpcom/glue/nsCOMPtr.h create mode 100644 src/libs/xpcom18a4/xpcom/glue/nsComponentManagerUtils.cpp create mode 100644 src/libs/xpcom18a4/xpcom/glue/nsDebug.cpp create mode 100644 src/libs/xpcom18a4/xpcom/glue/nsDebug.h create mode 100644 src/libs/xpcom18a4/xpcom/glue/nsGenericFactory.cpp create mode 100644 src/libs/xpcom18a4/xpcom/glue/nsGenericFactory.h create mode 100644 src/libs/xpcom18a4/xpcom/glue/nsIGenericFactory.h create mode 100644 src/libs/xpcom18a4/xpcom/glue/nsIInterfaceRequestorUtils.cpp create mode 100644 src/libs/xpcom18a4/xpcom/glue/nsIInterfaceRequestorUtils.h create mode 100644 src/libs/xpcom18a4/xpcom/glue/nsISupportsImpl.h create mode 100644 src/libs/xpcom18a4/xpcom/glue/nsISupportsUtils.h create mode 100644 src/libs/xpcom18a4/xpcom/glue/nsIWeakReferenceUtils.h create mode 100644 src/libs/xpcom18a4/xpcom/glue/nsMemory.cpp create mode 100644 src/libs/xpcom18a4/xpcom/glue/nsMemory.h create mode 100644 src/libs/xpcom18a4/xpcom/glue/nsServiceManagerUtils.h create mode 100644 src/libs/xpcom18a4/xpcom/glue/nsTraceRefcnt.cpp create mode 100644 src/libs/xpcom18a4/xpcom/glue/nsTraceRefcnt.h create mode 100644 src/libs/xpcom18a4/xpcom/glue/nsWeakReference.cpp create mode 100644 src/libs/xpcom18a4/xpcom/glue/nsWeakReference.h create mode 100644 src/libs/xpcom18a4/xpcom/glue/objs.mk create mode 100644 src/libs/xpcom18a4/xpcom/glue/standalone/.cvsignore create mode 100644 src/libs/xpcom18a4/xpcom/glue/standalone/Makefile.in create mode 100644 src/libs/xpcom18a4/xpcom/glue/standalone/nsGREDirServiceProvider.cpp create mode 100644 src/libs/xpcom18a4/xpcom/glue/standalone/nsGREDirServiceProvider.h create mode 100644 src/libs/xpcom18a4/xpcom/glue/standalone/nsXPCOMGlue.cpp create mode 100644 src/libs/xpcom18a4/xpcom/glue/standalone/nsXPCOMGlue.h create mode 100644 src/libs/xpcom18a4/xpcom/io/.cvsignore create mode 100644 src/libs/xpcom18a4/xpcom/io/Makefile.in create mode 100644 src/libs/xpcom18a4/xpcom/io/SpecialSystemDirectory.cpp create mode 100644 src/libs/xpcom18a4/xpcom/io/SpecialSystemDirectory.h create mode 100644 src/libs/xpcom18a4/xpcom/io/macDirectoryCopy.c create mode 100644 src/libs/xpcom18a4/xpcom/io/macDirectoryCopy.h create mode 100644 src/libs/xpcom18a4/xpcom/io/nsAppDirectoryServiceDefs.h create mode 100644 src/libs/xpcom18a4/xpcom/io/nsAppFileLocationProvider.cpp create mode 100644 src/libs/xpcom18a4/xpcom/io/nsAppFileLocationProvider.h create mode 100644 src/libs/xpcom18a4/xpcom/io/nsBinaryStream.cpp create mode 100644 src/libs/xpcom18a4/xpcom/io/nsBinaryStream.h create mode 100644 src/libs/xpcom18a4/xpcom/io/nsByteArrayInputStream.cpp create mode 100644 src/libs/xpcom18a4/xpcom/io/nsByteArrayInputStream.h create mode 100644 src/libs/xpcom18a4/xpcom/io/nsDirectoryService.cpp create mode 100644 src/libs/xpcom18a4/xpcom/io/nsDirectoryService.h create mode 100644 src/libs/xpcom18a4/xpcom/io/nsDirectoryServiceDefs.h create mode 100644 src/libs/xpcom18a4/xpcom/io/nsDirectoryServiceUtils.h create mode 100644 src/libs/xpcom18a4/xpcom/io/nsEscape.cpp create mode 100644 src/libs/xpcom18a4/xpcom/io/nsEscape.h create mode 100644 src/libs/xpcom18a4/xpcom/io/nsFastLoadFile.cpp create mode 100644 src/libs/xpcom18a4/xpcom/io/nsFastLoadFile.h create mode 100644 src/libs/xpcom18a4/xpcom/io/nsFastLoadPtr.h create mode 100644 src/libs/xpcom18a4/xpcom/io/nsFastLoadService.cpp create mode 100644 src/libs/xpcom18a4/xpcom/io/nsFastLoadService.h create mode 100644 src/libs/xpcom18a4/xpcom/io/nsIAsyncInputStream.idl create mode 100644 src/libs/xpcom18a4/xpcom/io/nsIAsyncOutputStream.idl create mode 100644 src/libs/xpcom18a4/xpcom/io/nsIBaseStream.idl create mode 100644 src/libs/xpcom18a4/xpcom/io/nsIBinaryInputStream.idl create mode 100644 src/libs/xpcom18a4/xpcom/io/nsIBinaryOutputStream.idl create mode 100644 src/libs/xpcom18a4/xpcom/io/nsIByteArrayInputStream.idl create mode 100644 src/libs/xpcom18a4/xpcom/io/nsIDirectoryEnumerator.idl create mode 100644 src/libs/xpcom18a4/xpcom/io/nsIDirectoryService.idl create mode 100644 src/libs/xpcom18a4/xpcom/io/nsIFastLoadFileControl.idl create mode 100644 src/libs/xpcom18a4/xpcom/io/nsIFastLoadService.idl create mode 100644 src/libs/xpcom18a4/xpcom/io/nsIFile.idl create mode 100644 src/libs/xpcom18a4/xpcom/io/nsIInputStream.idl create mode 100644 src/libs/xpcom18a4/xpcom/io/nsIInputStreamTee.idl create mode 100644 src/libs/xpcom18a4/xpcom/io/nsILineInputStream.idl create mode 100644 src/libs/xpcom18a4/xpcom/io/nsILocalFile.idl create mode 100644 src/libs/xpcom18a4/xpcom/io/nsILocalFileMac.idl create mode 100644 src/libs/xpcom18a4/xpcom/io/nsILocalFileOS2.idl create mode 100644 src/libs/xpcom18a4/xpcom/io/nsIMultiplexInputStream.idl create mode 100644 src/libs/xpcom18a4/xpcom/io/nsIObjectInputStream.idl create mode 100644 src/libs/xpcom18a4/xpcom/io/nsIObjectOutputStream.idl create mode 100644 src/libs/xpcom18a4/xpcom/io/nsIObservableInputStream.idl create mode 100644 src/libs/xpcom18a4/xpcom/io/nsIObservableOutputStream.idl create mode 100644 src/libs/xpcom18a4/xpcom/io/nsIOutputStream.idl create mode 100644 src/libs/xpcom18a4/xpcom/io/nsIPipe.idl create mode 100644 src/libs/xpcom18a4/xpcom/io/nsIScriptableInputStream.idl create mode 100644 src/libs/xpcom18a4/xpcom/io/nsISeekableStream.idl create mode 100644 src/libs/xpcom18a4/xpcom/io/nsIStorageStream.idl create mode 100644 src/libs/xpcom18a4/xpcom/io/nsIStreamBufferAccess.idl create mode 100644 src/libs/xpcom18a4/xpcom/io/nsIStringStream.idl create mode 100644 src/libs/xpcom18a4/xpcom/io/nsIUnicharInputStream.h create mode 100644 src/libs/xpcom18a4/xpcom/io/nsInputStreamTee.cpp create mode 100644 src/libs/xpcom18a4/xpcom/io/nsLinebreakConverter.cpp create mode 100644 src/libs/xpcom18a4/xpcom/io/nsLinebreakConverter.h create mode 100644 src/libs/xpcom18a4/xpcom/io/nsLocalFile.h create mode 100644 src/libs/xpcom18a4/xpcom/io/nsLocalFileCommon.cpp create mode 100644 src/libs/xpcom18a4/xpcom/io/nsLocalFileMac.cpp create mode 100644 src/libs/xpcom18a4/xpcom/io/nsLocalFileMac.h create mode 100644 src/libs/xpcom18a4/xpcom/io/nsLocalFileOS2.cpp create mode 100644 src/libs/xpcom18a4/xpcom/io/nsLocalFileOS2.h create mode 100644 src/libs/xpcom18a4/xpcom/io/nsLocalFileOSX.cpp create mode 100644 src/libs/xpcom18a4/xpcom/io/nsLocalFileOSX.h create mode 100644 src/libs/xpcom18a4/xpcom/io/nsLocalFileUnicode.h create mode 100644 src/libs/xpcom18a4/xpcom/io/nsLocalFileUnix.cpp create mode 100644 src/libs/xpcom18a4/xpcom/io/nsLocalFileUnix.h create mode 100644 src/libs/xpcom18a4/xpcom/io/nsLocalFileWin.cpp create mode 100644 src/libs/xpcom18a4/xpcom/io/nsLocalFileWin.h create mode 100644 src/libs/xpcom18a4/xpcom/io/nsMultiplexInputStream.cpp create mode 100644 src/libs/xpcom18a4/xpcom/io/nsMultiplexInputStream.h create mode 100644 src/libs/xpcom18a4/xpcom/io/nsNativeCharsetUtils.cpp create mode 100644 src/libs/xpcom18a4/xpcom/io/nsNativeCharsetUtils.h create mode 100644 src/libs/xpcom18a4/xpcom/io/nsPipe3.cpp create mode 100644 src/libs/xpcom18a4/xpcom/io/nsScriptableInputStream.cpp create mode 100644 src/libs/xpcom18a4/xpcom/io/nsScriptableInputStream.h create mode 100644 src/libs/xpcom18a4/xpcom/io/nsSegmentedBuffer.cpp create mode 100644 src/libs/xpcom18a4/xpcom/io/nsSegmentedBuffer.h create mode 100644 src/libs/xpcom18a4/xpcom/io/nsStorageStream.cpp create mode 100644 src/libs/xpcom18a4/xpcom/io/nsStorageStream.h create mode 100644 src/libs/xpcom18a4/xpcom/io/nsStreamUtils.cpp create mode 100644 src/libs/xpcom18a4/xpcom/io/nsStreamUtils.h create mode 100644 src/libs/xpcom18a4/xpcom/io/nsStringIO.h create mode 100644 src/libs/xpcom18a4/xpcom/io/nsStringStream.cpp create mode 100644 src/libs/xpcom18a4/xpcom/io/nsStringStream.h create mode 100644 src/libs/xpcom18a4/xpcom/io/nsUnicharInputStream.cpp create mode 100644 src/libs/xpcom18a4/xpcom/libxpt/xptcall/porting.html create mode 100644 src/libs/xpcom18a4/xpcom/libxpt/xptcall/status.html create mode 100644 src/libs/xpcom18a4/xpcom/obsolete/Makefile.in create mode 100644 src/libs/xpcom18a4/xpcom/obsolete/component/Makefile.in create mode 100644 src/libs/xpcom18a4/xpcom/obsolete/component/nsFileSpecImpl.cpp create mode 100644 src/libs/xpcom18a4/xpcom/obsolete/component/nsFileSpecImpl.h create mode 100644 src/libs/xpcom18a4/xpcom/obsolete/component/nsIRegistry.idl create mode 100644 src/libs/xpcom18a4/xpcom/obsolete/component/nsIRegistryUtils.h create mode 100644 src/libs/xpcom18a4/xpcom/obsolete/component/nsRegistry.cpp create mode 100644 src/libs/xpcom18a4/xpcom/obsolete/component/nsRegistry.h create mode 100644 src/libs/xpcom18a4/xpcom/obsolete/component/nsXPCOMObsolete.cpp create mode 100644 src/libs/xpcom18a4/xpcom/obsolete/component/regExport.cpp create mode 100644 src/libs/xpcom18a4/xpcom/obsolete/component/xpcomobsoletec.pkg create mode 100644 src/libs/xpcom18a4/xpcom/obsolete/dlldeps.cpp create mode 100644 src/libs/xpcom18a4/xpcom/obsolete/nsFileSpec.cpp create mode 100644 src/libs/xpcom18a4/xpcom/obsolete/nsFileSpec.h create mode 100644 src/libs/xpcom18a4/xpcom/obsolete/nsFileSpecBeOS.cpp create mode 100644 src/libs/xpcom18a4/xpcom/obsolete/nsFileSpecImpl.cpp create mode 100644 src/libs/xpcom18a4/xpcom/obsolete/nsFileSpecImpl.h create mode 100644 src/libs/xpcom18a4/xpcom/obsolete/nsFileSpecMac.cpp create mode 100644 src/libs/xpcom18a4/xpcom/obsolete/nsFileSpecOS2.cpp create mode 100644 src/libs/xpcom18a4/xpcom/obsolete/nsFileSpecUnix.cpp create mode 100644 src/libs/xpcom18a4/xpcom/obsolete/nsFileSpecWin.cpp create mode 100644 src/libs/xpcom18a4/xpcom/obsolete/nsFileStream.cpp create mode 100644 src/libs/xpcom18a4/xpcom/obsolete/nsFileStream.h create mode 100644 src/libs/xpcom18a4/xpcom/obsolete/nsIFileSpec.idl create mode 100644 src/libs/xpcom18a4/xpcom/obsolete/nsIFileStream.cpp create mode 100644 src/libs/xpcom18a4/xpcom/obsolete/nsIFileStream.h create mode 100644 src/libs/xpcom18a4/xpcom/obsolete/nsIRegistry.idl create mode 100644 src/libs/xpcom18a4/xpcom/obsolete/nsIRegistryUtils.h create mode 100644 src/libs/xpcom18a4/xpcom/obsolete/nsSpecialSystemDirectory.cpp create mode 100644 src/libs/xpcom18a4/xpcom/obsolete/nsSpecialSystemDirectory.h create mode 100644 src/libs/xpcom18a4/xpcom/obsolete/nsXPCOMObsolete.cpp create mode 100644 src/libs/xpcom18a4/xpcom/obsolete/xpcomobsolete.h create mode 100644 src/libs/xpcom18a4/xpcom/obsolete/xpcomobsolete.pkg create mode 100644 src/libs/xpcom18a4/xpcom/proxy/.cvsignore create mode 100644 src/libs/xpcom18a4/xpcom/proxy/Makefile.in create mode 100644 src/libs/xpcom18a4/xpcom/proxy/public/.cvsignore create mode 100644 src/libs/xpcom18a4/xpcom/proxy/public/Makefile.in create mode 100644 src/libs/xpcom18a4/xpcom/proxy/public/nsIProxyCreateInstance.idl create mode 100644 src/libs/xpcom18a4/xpcom/proxy/public/nsIProxyObjectManager.idl create mode 100644 src/libs/xpcom18a4/xpcom/proxy/public/nsProxiedService.h create mode 100644 src/libs/xpcom18a4/xpcom/proxy/public/nsProxyEvent.h create mode 100644 src/libs/xpcom18a4/xpcom/proxy/public/nsProxyRelease.h create mode 100644 src/libs/xpcom18a4/xpcom/proxy/src/.cvsignore create mode 100644 src/libs/xpcom18a4/xpcom/proxy/src/Makefile.in create mode 100644 src/libs/xpcom18a4/xpcom/proxy/src/nsIProxyCreateInstance.h create mode 100644 src/libs/xpcom18a4/xpcom/proxy/src/nsProxyEvent.cpp create mode 100644 src/libs/xpcom18a4/xpcom/proxy/src/nsProxyEventClass.cpp create mode 100644 src/libs/xpcom18a4/xpcom/proxy/src/nsProxyEventObject.cpp create mode 100644 src/libs/xpcom18a4/xpcom/proxy/src/nsProxyEventPrivate.h create mode 100644 src/libs/xpcom18a4/xpcom/proxy/src/nsProxyObjectManager.cpp create mode 100644 src/libs/xpcom18a4/xpcom/proxy/src/nsProxyRelease.cpp create mode 100644 src/libs/xpcom18a4/xpcom/proxy/tests/.cvsignore create mode 100644 src/libs/xpcom18a4/xpcom/proxy/tests/Makefile.in create mode 100644 src/libs/xpcom18a4/xpcom/proxy/tests/nsITestProxy.idl create mode 100644 src/libs/xpcom18a4/xpcom/proxy/tests/proxytests.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/.cvsignore create mode 100644 src/libs/xpcom18a4/xpcom/reflect/Makefile.in create mode 100644 src/libs/xpcom18a4/xpcom/reflect/Makefile.kup create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/.cvsignore create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/Makefile.in create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/Makefile.kup create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/README create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/porting.html create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/public/.cvsignore create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/public/Makefile.in create mode 100755 src/libs/xpcom18a4/xpcom/reflect/xptcall/public/genstubs.pl create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/public/xptcall.h create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/public/xptcstubsdecl.inc create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/public/xptcstubsdef.inc create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/.cvsignore create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/Makefile.in create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/Makefile.kup create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/.cvsignore create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/Makefile.in create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/Makefile.kup create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/mac/xptcinvoke_mac.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/mac/xptcinvoke_mac.s create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/mac/xptcstubs_mac.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/mac/xptcstubs_mac.s create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/os2/.cvsignore create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/os2/Makefile.in create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/os2/xptcinvoke_emx.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/os2/xptcinvoke_gcc_x86_os2.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/os2/xptcinvoke_vacpp.asm create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/os2/xptcstubs_emx.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/os2/xptcstubs_gcc_x86_os2.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/os2/xptcstubs_os2.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/os2/xptcstubs_vacpp.asm create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/test/.cvsignore create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/test/Makefile.in create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/test/README create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/test/clean.bat create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/test/invoke_test.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/test/mk_invoke.bat create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/test/mk_stub.bat create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/test/stub_test.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/.cvsignore create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/Makefile.in create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/Makefile.kup create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/vtable_layout_x86.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptc_gcc_x86_unix.h create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptc_platforms_unixish_x86.h create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_amd64_darwin.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_amd64_vbox.asm create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_arm.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_arm64_vbox.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_arm_netbsd.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_ipf32.s create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_ipf64.s create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_irix.s create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_mips.s create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_openvms_alpha.s create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_osf1_alpha.s create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_pa32.s create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_ppc_aix.s create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_ppc_aix64.s create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_ppc_ibmobj_aix.s create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_ppc_linux.s create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_ppc_netbsd.s create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_ppc_rhapsody.s create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_sparc_bsdos.s create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_sparc_linux.s create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_sparc_linux_GCC3.s create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_sparc_netbsd.s create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_sparc_solaris.s create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_sparc_solaris_GCC.s create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_sparc_solaris_GCC3.s create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_sparc_solaris_SUNW.s create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_sparcv9_solaris_SUNW.s create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_gcc_x86_unix.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_ipf32.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_ipf64.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_irix.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_linux_alpha.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_linux_m68k.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_linux_s390.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_linux_s390x.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_mips.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_netbsd_m68k.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_openvms_alpha.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_osf1_alpha.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_pa32.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_ppc_aix.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_ppc_aix64.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_ppc_linux.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_ppc_netbsd.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_ppc_rhapsody.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_sparc_netbsd.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_sparc_solaris.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_sparcv9_solaris.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_unixish_x86.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_unsupported.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_x86_64_linux.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_x86_solaris.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_amd64_darwin.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_arm.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_arm64_vbox.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_arm_netbsd.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_ipf32.s create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_ipf64.s create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_irix.s create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_mips.s.m4 create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_openvms_alpha.s create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_osf1_alpha.s create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_pa32.s create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_ppc_aix.s create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_ppc_aix64.s create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_ppc_darwin.s.m4 create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_ppc_linux.s create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_ppc_netbsd.s create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_sparc_netbsd.s create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_sparc_solaris.s create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_sparcv9_solaris.s create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_gcc_x86_unix.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_ipf32.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_ipf64.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_irix.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_linux_alpha.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_linux_m68k.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_linux_s390.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_linux_s390x.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_mips.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_netbsd_m68k.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_openvms_alpha.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_osf1_alpha.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_pa32.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_ppc_aix.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_ppc_aix64.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_ppc_linux.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_ppc_netbsd.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_ppc_rhapsody.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_sparc_netbsd.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_sparc_solaris.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_sparcv9_solaris.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_unixish_x86.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_unsupported.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_x86_64_linux.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_x86_64_solaris.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_x86_solaris.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/win32/.cvsignore create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/win32/Makefile.in create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/win32/xptcinvoke.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/win32/xptcinvoke_alpha.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/win32/xptcinvoke_asm_alpha.s create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/win32/xptcstubs.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/win32/xptcstubs_alpha.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/win32/xptcstubs_asm_alpha.s create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/xptcall.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/xptcprivate.h create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/status.html create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/tests/.cvsignore create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/tests/Makefile.in create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/tests/TestXPTCInvoke.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptinfo/.cvsignore create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptinfo/Makefile.in create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptinfo/public/.cvsignore create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptinfo/public/Makefile.in create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptinfo/public/nsIInterfaceInfo.idl create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptinfo/public/nsIInterfaceInfoManager.idl create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptinfo/public/nsIXPTLoader.idl create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptinfo/public/xptinfo.h create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/.cvsignore create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/Makefile.in create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/TODO create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiFile.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiInterfaceInfo.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiInterfaceInfoManager.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiManifest.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiMisc.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiTypelibGuts.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiWorkingSet.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiZipItem.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiZipLoader.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiprivate.h create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptinfo/tests/.cvsignore create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptinfo/tests/Makefile.in create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptinfo/tests/TestInterfaceInfo.cpp create mode 100644 src/libs/xpcom18a4/xpcom/sample/.cvsignore create mode 100644 src/libs/xpcom18a4/xpcom/sample/Makefile.in create mode 100644 src/libs/xpcom18a4/xpcom/sample/nsISample.idl create mode 100644 src/libs/xpcom18a4/xpcom/sample/nsSample.cpp create mode 100644 src/libs/xpcom18a4/xpcom/sample/nsSample.h create mode 100644 src/libs/xpcom18a4/xpcom/sample/nsSample.js create mode 100644 src/libs/xpcom18a4/xpcom/sample/nsSampleModule.cpp create mode 100644 src/libs/xpcom18a4/xpcom/sample/nsTestSample.cpp create mode 100644 src/libs/xpcom18a4/xpcom/sample/win32.order create mode 100644 src/libs/xpcom18a4/xpcom/sample/xpconnect-sample.html create mode 100644 src/libs/xpcom18a4/xpcom/string/.cvsignore create mode 100644 src/libs/xpcom18a4/xpcom/string/Makefile.in create mode 100644 src/libs/xpcom18a4/xpcom/string/README.html create mode 100644 src/libs/xpcom18a4/xpcom/string/doc/README.html create mode 100644 src/libs/xpcom18a4/xpcom/string/doc/string-guide.html create mode 100644 src/libs/xpcom18a4/xpcom/string/public/.cvsignore create mode 100644 src/libs/xpcom18a4/xpcom/string/public/Makefile.in create mode 100644 src/libs/xpcom18a4/xpcom/string/public/nsAString.h create mode 100644 src/libs/xpcom18a4/xpcom/string/public/nsAlgorithm.h create mode 100644 src/libs/xpcom18a4/xpcom/string/public/nsCharTraits.h create mode 100644 src/libs/xpcom18a4/xpcom/string/public/nsDependentString.h create mode 100644 src/libs/xpcom18a4/xpcom/string/public/nsDependentSubstring.h create mode 100644 src/libs/xpcom18a4/xpcom/string/public/nsEmbedString.h create mode 100644 src/libs/xpcom18a4/xpcom/string/public/nsLiteralString.h create mode 100644 src/libs/xpcom18a4/xpcom/string/public/nsObsoleteAString.h create mode 100644 src/libs/xpcom18a4/xpcom/string/public/nsPrintfCString.h create mode 100644 src/libs/xpcom18a4/xpcom/string/public/nsPromiseFlatString.h create mode 100644 src/libs/xpcom18a4/xpcom/string/public/nsReadableUtils.h create mode 100644 src/libs/xpcom18a4/xpcom/string/public/nsString.h create mode 100644 src/libs/xpcom18a4/xpcom/string/public/nsStringAPI.h create mode 100644 src/libs/xpcom18a4/xpcom/string/public/nsStringFwd.h create mode 100644 src/libs/xpcom18a4/xpcom/string/public/nsStringIterator.h create mode 100644 src/libs/xpcom18a4/xpcom/string/public/nsSubstring.h create mode 100644 src/libs/xpcom18a4/xpcom/string/public/nsSubstringTuple.h create mode 100644 src/libs/xpcom18a4/xpcom/string/public/nsTAString.h create mode 100644 src/libs/xpcom18a4/xpcom/string/public/nsTDependentString.h create mode 100644 src/libs/xpcom18a4/xpcom/string/public/nsTDependentSubstring.h create mode 100644 src/libs/xpcom18a4/xpcom/string/public/nsTObsoleteAString.h create mode 100644 src/libs/xpcom18a4/xpcom/string/public/nsTPromiseFlatString.h create mode 100644 src/libs/xpcom18a4/xpcom/string/public/nsTString.h create mode 100644 src/libs/xpcom18a4/xpcom/string/public/nsTSubstring.h create mode 100644 src/libs/xpcom18a4/xpcom/string/public/nsTSubstringTuple.h create mode 100644 src/libs/xpcom18a4/xpcom/string/public/nsUTF8Utils.h create mode 100644 src/libs/xpcom18a4/xpcom/string/public/nsXPIDLString.h create mode 100644 src/libs/xpcom18a4/xpcom/string/public/string-template-def-char.h create mode 100644 src/libs/xpcom18a4/xpcom/string/public/string-template-def-unichar.h create mode 100644 src/libs/xpcom18a4/xpcom/string/public/string-template-undef.h create mode 100644 src/libs/xpcom18a4/xpcom/string/src/.cvsignore create mode 100644 src/libs/xpcom18a4/xpcom/string/src/Makefile.in create mode 100644 src/libs/xpcom18a4/xpcom/string/src/nsAString.cpp create mode 100644 src/libs/xpcom18a4/xpcom/string/src/nsDependentSubstring.cpp create mode 100644 src/libs/xpcom18a4/xpcom/string/src/nsObsoleteAStringThunk.cpp create mode 100644 src/libs/xpcom18a4/xpcom/string/src/nsPrintfCString.cpp create mode 100644 src/libs/xpcom18a4/xpcom/string/src/nsPromiseFlatString.cpp create mode 100644 src/libs/xpcom18a4/xpcom/string/src/nsReadableUtils.cpp create mode 100644 src/libs/xpcom18a4/xpcom/string/src/nsString.cpp create mode 100644 src/libs/xpcom18a4/xpcom/string/src/nsStringComparator.cpp create mode 100644 src/libs/xpcom18a4/xpcom/string/src/nsStringObsolete.cpp create mode 100644 src/libs/xpcom18a4/xpcom/string/src/nsSubstring.cpp create mode 100644 src/libs/xpcom18a4/xpcom/string/src/nsSubstringTuple.cpp create mode 100644 src/libs/xpcom18a4/xpcom/string/src/nsTAString.cpp create mode 100644 src/libs/xpcom18a4/xpcom/string/src/nsTDependentSubstring.cpp create mode 100644 src/libs/xpcom18a4/xpcom/string/src/nsTObsoleteAStringThunk.cpp create mode 100644 src/libs/xpcom18a4/xpcom/string/src/nsTPromiseFlatString.cpp create mode 100644 src/libs/xpcom18a4/xpcom/string/src/nsTString.cpp create mode 100644 src/libs/xpcom18a4/xpcom/string/src/nsTStringComparator.cpp create mode 100644 src/libs/xpcom18a4/xpcom/string/src/nsTStringObsolete.cpp create mode 100644 src/libs/xpcom18a4/xpcom/string/src/nsTSubstring.cpp create mode 100644 src/libs/xpcom18a4/xpcom/string/src/nsTSubstringTuple.cpp create mode 100644 src/libs/xpcom18a4/xpcom/stub/nsStringAPI.cpp create mode 100644 src/libs/xpcom18a4/xpcom/tests/.cvsignore create mode 100644 src/libs/xpcom18a4/xpcom/tests/CvtURL.cpp create mode 100644 src/libs/xpcom18a4/xpcom/tests/Makefile.in create mode 100644 src/libs/xpcom18a4/xpcom/tests/RegFactory.cpp create mode 100644 src/libs/xpcom18a4/xpcom/tests/SizeTest01.cpp create mode 100644 src/libs/xpcom18a4/xpcom/tests/SizeTest02.cpp create mode 100644 src/libs/xpcom18a4/xpcom/tests/SizeTest03.cpp create mode 100644 src/libs/xpcom18a4/xpcom/tests/SizeTest04.cpp create mode 100644 src/libs/xpcom18a4/xpcom/tests/SizeTest05.cpp create mode 100644 src/libs/xpcom18a4/xpcom/tests/SizeTest06.cpp create mode 100644 src/libs/xpcom18a4/xpcom/tests/StringFactoringTests/Makefile.in create mode 100644 src/libs/xpcom18a4/xpcom/tests/StringFactoringTests/StringTest.Prefix create mode 100644 src/libs/xpcom18a4/xpcom/tests/StringFactoringTests/StringTest.mcp create mode 100644 src/libs/xpcom18a4/xpcom/tests/StringFactoringTests/StringTestDebug.Prefix create mode 100644 src/libs/xpcom18a4/xpcom/tests/StringFactoringTests/StringTestNo_wchar_t.Prefix create mode 100644 src/libs/xpcom18a4/xpcom/tests/StringFactoringTests/StringTestProfileNew.Prefix create mode 100644 src/libs/xpcom18a4/xpcom/tests/StringFactoringTests/StringTestProfileOld.Prefix create mode 100644 src/libs/xpcom18a4/xpcom/tests/StringFactoringTests/StringTestProfileStd.Prefix create mode 100644 src/libs/xpcom18a4/xpcom/tests/StringFactoringTests/ToDo.doc create mode 100644 src/libs/xpcom18a4/xpcom/tests/StringFactoringTests/nsStdStringWrapper.h create mode 100644 src/libs/xpcom18a4/xpcom/tests/StringFactoringTests/profile_main.cpp create mode 100644 src/libs/xpcom18a4/xpcom/tests/StringFactoringTests/test_main.cpp create mode 100644 src/libs/xpcom18a4/xpcom/tests/TestArray.cpp create mode 100644 src/libs/xpcom18a4/xpcom/tests/TestAtoms.cpp create mode 100644 src/libs/xpcom18a4/xpcom/tests/TestAutoLock.cpp create mode 100644 src/libs/xpcom18a4/xpcom/tests/TestAutoPtr.cpp create mode 100644 src/libs/xpcom18a4/xpcom/tests/TestCOMPtr.cpp create mode 100644 src/libs/xpcom18a4/xpcom/tests/TestCOMPtrEq.cpp create mode 100644 src/libs/xpcom18a4/xpcom/tests/TestCRT.cpp create mode 100644 src/libs/xpcom18a4/xpcom/tests/TestCallTemplates.cpp create mode 100644 src/libs/xpcom18a4/xpcom/tests/TestDeque.cpp create mode 100644 src/libs/xpcom18a4/xpcom/tests/TestFactory.cpp create mode 100644 src/libs/xpcom18a4/xpcom/tests/TestFactory.h create mode 100644 src/libs/xpcom18a4/xpcom/tests/TestHashtables.cpp create mode 100644 src/libs/xpcom18a4/xpcom/tests/TestID.cpp create mode 100644 src/libs/xpcom18a4/xpcom/tests/TestMinStringAPI.cpp create mode 100644 src/libs/xpcom18a4/xpcom/tests/TestObserverService.cpp create mode 100644 src/libs/xpcom18a4/xpcom/tests/TestPermanentAtoms.cpp create mode 100644 src/libs/xpcom18a4/xpcom/tests/TestPipes.cpp create mode 100644 src/libs/xpcom18a4/xpcom/tests/TestServMgr.cpp create mode 100644 src/libs/xpcom18a4/xpcom/tests/TestShutdown.cpp create mode 100644 src/libs/xpcom18a4/xpcom/tests/TestStackCrawl.cpp create mode 100644 src/libs/xpcom18a4/xpcom/tests/TestStrings.cpp create mode 100644 src/libs/xpcom18a4/xpcom/tests/TestThreads.cpp create mode 100644 src/libs/xpcom18a4/xpcom/tests/TestVoidBTree.cpp create mode 100644 src/libs/xpcom18a4/xpcom/tests/TestXPIDLString.cpp create mode 100644 src/libs/xpcom18a4/xpcom/tests/dynamic/.cvsignore create mode 100644 src/libs/xpcom18a4/xpcom/tests/dynamic/Makefile.in create mode 100644 src/libs/xpcom18a4/xpcom/tests/dynamic/TestDynamic.cpp create mode 100644 src/libs/xpcom18a4/xpcom/tests/dynamic/win32.order create mode 100644 src/libs/xpcom18a4/xpcom/tests/nsIFileEnumerator.cpp create mode 100644 src/libs/xpcom18a4/xpcom/tests/nsIFileTest.cpp create mode 100644 src/libs/xpcom18a4/xpcom/tests/resources.h create mode 100644 src/libs/xpcom18a4/xpcom/tests/services/.cvsignore create mode 100644 src/libs/xpcom18a4/xpcom/tests/services/Makefile.in create mode 100644 src/libs/xpcom18a4/xpcom/tests/services/MyService.cpp create mode 100644 src/libs/xpcom18a4/xpcom/tests/services/MyService.h create mode 100644 src/libs/xpcom18a4/xpcom/tests/services/win32.order create mode 100644 src/libs/xpcom18a4/xpcom/tests/test.properties create mode 100644 src/libs/xpcom18a4/xpcom/tests/utils/WhatError.cpp create mode 100644 src/libs/xpcom18a4/xpcom/tests/utils/cp.js create mode 100644 src/libs/xpcom18a4/xpcom/tests/utils/dirs.js create mode 100644 src/libs/xpcom18a4/xpcom/tests/utils/ls.js create mode 100644 src/libs/xpcom18a4/xpcom/tests/windows/.cvsignore create mode 100644 src/libs/xpcom18a4/xpcom/tests/windows/Makefile.in create mode 100644 src/libs/xpcom18a4/xpcom/tests/windows/TestCOM.cpp create mode 100644 src/libs/xpcom18a4/xpcom/tests/windows/TestHelloXPLoop.cpp create mode 100644 src/libs/xpcom18a4/xpcom/tests/windows/nsStringTest.cpp create mode 100644 src/libs/xpcom18a4/xpcom/tests/windows/nsStringTest.h create mode 100644 src/libs/xpcom18a4/xpcom/tests/windows/nsStringTest2.h create mode 100644 src/libs/xpcom18a4/xpcom/threads/.cvsignore create mode 100644 src/libs/xpcom18a4/xpcom/threads/Makefile.in create mode 100644 src/libs/xpcom18a4/xpcom/threads/TimerThread.cpp create mode 100644 src/libs/xpcom18a4/xpcom/threads/TimerThread.h create mode 100644 src/libs/xpcom18a4/xpcom/threads/nsAutoLock.cpp create mode 100644 src/libs/xpcom18a4/xpcom/threads/nsAutoLock.h create mode 100644 src/libs/xpcom18a4/xpcom/threads/nsEnvironment.cpp create mode 100644 src/libs/xpcom18a4/xpcom/threads/nsEnvironment.h create mode 100644 src/libs/xpcom18a4/xpcom/threads/nsEventQueue.cpp create mode 100644 src/libs/xpcom18a4/xpcom/threads/nsEventQueue.h create mode 100644 src/libs/xpcom18a4/xpcom/threads/nsEventQueueService.cpp create mode 100644 src/libs/xpcom18a4/xpcom/threads/nsEventQueueService.h create mode 100644 src/libs/xpcom18a4/xpcom/threads/nsEventQueueUtils.h create mode 100644 src/libs/xpcom18a4/xpcom/threads/nsIEnvironment.idl create mode 100644 src/libs/xpcom18a4/xpcom/threads/nsIEventQueue.idl create mode 100644 src/libs/xpcom18a4/xpcom/threads/nsIEventQueueService.idl create mode 100644 src/libs/xpcom18a4/xpcom/threads/nsIEventTarget.idl create mode 100644 src/libs/xpcom18a4/xpcom/threads/nsIProcess.idl create mode 100644 src/libs/xpcom18a4/xpcom/threads/nsIRunnable.idl create mode 100644 src/libs/xpcom18a4/xpcom/threads/nsIThread.idl create mode 100644 src/libs/xpcom18a4/xpcom/threads/nsITimer.idl create mode 100644 src/libs/xpcom18a4/xpcom/threads/nsITimerInternal.idl create mode 100644 src/libs/xpcom18a4/xpcom/threads/nsITimerManager.idl create mode 100644 src/libs/xpcom18a4/xpcom/threads/nsPIEventQueueChain.h create mode 100644 src/libs/xpcom18a4/xpcom/threads/nsProcess.h create mode 100644 src/libs/xpcom18a4/xpcom/threads/nsProcessCommon.cpp create mode 100644 src/libs/xpcom18a4/xpcom/threads/nsProcessMac.cpp create mode 100644 src/libs/xpcom18a4/xpcom/threads/nsThread.cpp create mode 100644 src/libs/xpcom18a4/xpcom/threads/nsThread.h create mode 100644 src/libs/xpcom18a4/xpcom/threads/nsTimerImpl.cpp create mode 100644 src/libs/xpcom18a4/xpcom/threads/nsTimerImpl.h create mode 100644 src/libs/xpcom18a4/xpcom/threads/plevent.c create mode 100644 src/libs/xpcom18a4/xpcom/threads/plevent.h create mode 100644 src/libs/xpcom18a4/xpcom/tools/.cvsignore create mode 100644 src/libs/xpcom18a4/xpcom/tools/Makefile.in create mode 100755 src/libs/xpcom18a4/xpcom/tools/analyze-xpcom-log.pl create mode 100644 src/libs/xpcom18a4/xpcom/tools/registry/.cvsignore create mode 100644 src/libs/xpcom18a4/xpcom/tools/registry/Makefile.in create mode 100644 src/libs/xpcom18a4/xpcom/tools/registry/regxpcom.cpp create mode 100644 src/libs/xpcom18a4/xpcom/tools/windows/.cvsignore create mode 100644 src/libs/xpcom18a4/xpcom/tools/windows/Makefile.in create mode 100644 src/libs/xpcom18a4/xpcom/tools/windows/rebasedlls.cpp create mode 100644 src/libs/xpcom18a4/xpcom/typelib/.cvsignore create mode 100644 src/libs/xpcom18a4/xpcom/typelib/Makefile.in create mode 100644 src/libs/xpcom18a4/xpcom/typelib/xpidl/.cvsignore create mode 100644 src/libs/xpcom18a4/xpcom/typelib/xpidl/Makefile.in create mode 100644 src/libs/xpcom18a4/xpcom/typelib/xpidl/README create mode 100644 src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/compiler.rsrc create mode 100644 src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/linker.rsrc create mode 100644 src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/mac_console.c create mode 100644 src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/mac_console.h create mode 100644 src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/mac_memory.cpp create mode 100644 src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/mac_stdlib.cpp create mode 100644 src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/mac_strings.cpp create mode 100644 src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/mac_strings.h create mode 100644 src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/mac_xpidl.cpp create mode 100644 src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/mac_xpidl.h create mode 100644 src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/mac_xpidl_panel.cpp create mode 100644 src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/mac_xpidl_panel.h create mode 100644 src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/mac_xpt_linker.cpp create mode 100644 src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/panel.rsrc create mode 100644 src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/version.rsrc create mode 100644 src/libs/xpcom18a4/xpcom/typelib/xpidl/xpidl.c create mode 100644 src/libs/xpcom18a4/xpcom/typelib/xpidl/xpidl.h create mode 100644 src/libs/xpcom18a4/xpcom/typelib/xpidl/xpidl_doc.c create mode 100644 src/libs/xpcom18a4/xpcom/typelib/xpidl/xpidl_header.c create mode 100644 src/libs/xpcom18a4/xpcom/typelib/xpidl/xpidl_idl.c create mode 100644 src/libs/xpcom18a4/xpcom/typelib/xpidl/xpidl_java.c create mode 100644 src/libs/xpcom18a4/xpcom/typelib/xpidl/xpidl_typelib.c create mode 100644 src/libs/xpcom18a4/xpcom/typelib/xpidl/xpidl_util.c create mode 100644 src/libs/xpcom18a4/xpcom/typelib/xpt/.cvsignore create mode 100644 src/libs/xpcom18a4/xpcom/typelib/xpt/Makefile.in create mode 100644 src/libs/xpcom18a4/xpcom/typelib/xpt/public/.cvsignore create mode 100644 src/libs/xpcom18a4/xpcom/typelib/xpt/public/Makefile.in create mode 100644 src/libs/xpcom18a4/xpcom/typelib/xpt/public/xpt_arena.h create mode 100644 src/libs/xpcom18a4/xpcom/typelib/xpt/public/xpt_struct.h create mode 100644 src/libs/xpcom18a4/xpcom/typelib/xpt/public/xpt_xdr.h create mode 100644 src/libs/xpcom18a4/xpcom/typelib/xpt/src/.cvsignore create mode 100644 src/libs/xpcom18a4/xpcom/typelib/xpt/src/Makefile.in create mode 100644 src/libs/xpcom18a4/xpcom/typelib/xpt/src/xpt_arena.c create mode 100644 src/libs/xpcom18a4/xpcom/typelib/xpt/src/xpt_struct.c create mode 100644 src/libs/xpcom18a4/xpcom/typelib/xpt/src/xpt_xdr.c create mode 100644 src/libs/xpcom18a4/xpcom/typelib/xpt/tests/.cvsignore create mode 100644 src/libs/xpcom18a4/xpcom/typelib/xpt/tests/Makefile.in create mode 100644 src/libs/xpcom18a4/xpcom/typelib/xpt/tests/PrimitiveTest.c create mode 100644 src/libs/xpcom18a4/xpcom/typelib/xpt/tests/SimpleTypeLib.c create mode 100644 src/libs/xpcom18a4/xpcom/typelib/xpt/tools/.cvsignore create mode 100644 src/libs/xpcom18a4/xpcom/typelib/xpt/tools/Makefile.in create mode 100644 src/libs/xpcom18a4/xpcom/typelib/xpt/tools/xpt_dump.c create mode 100644 src/libs/xpcom18a4/xpcom/typelib/xpt/tools/xpt_link.c create mode 100644 src/libs/xpcom18a4/xpcom/windbgdlg/.cvsignore create mode 100644 src/libs/xpcom18a4/xpcom/windbgdlg/Makefile.in create mode 100644 src/libs/xpcom18a4/xpcom/windbgdlg/windbgdlg.cpp create mode 100644 src/libs/xpcom18a4/xpcom/xpcom-config.h.in create mode 100644 src/libs/xpcom18a4/xpcom/xpcom-private.h.in (limited to 'src/libs/xpcom18a4/xpcom') diff --git a/src/libs/xpcom18a4/xpcom/.cvsignore b/src/libs/xpcom18a4/xpcom/.cvsignore new file mode 100644 index 00000000..34b091a9 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/.cvsignore @@ -0,0 +1,3 @@ +Makefile +xpcom-config.h +xpcom-private.h diff --git a/src/libs/xpcom18a4/xpcom/Makefile.in b/src/libs/xpcom18a4/xpcom/Makefile.in new file mode 100644 index 00000000..8bfe9abe --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/Makefile.in @@ -0,0 +1,84 @@ +# +# ***** 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.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of 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 ***** + +DEPTH = .. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = xpcom +GRE_MODULE = 1 + +DIRS = \ + MoreFiles \ + typelib \ + string \ + glue \ + base \ + ds \ + io \ + components \ + threads \ + reflect \ + proxy \ + build \ + tools \ + $(NULL) + +ifeq ($(OS_ARCH),WINNT) +ifdef MOZ_DEBUG +DIRS += windbgdlg +endif +endif + +ifdef ENABLE_TESTS +DIRS += \ + tests \ + sample \ + typelib/xpt/tests \ + reflect/xptinfo/tests \ + reflect/xptcall/tests \ + proxy/tests +endif + +# xpcom-config.h is generated by configure +SDK_HEADERS = xpcom-config.h + +include $(topsrcdir)/config/rules.mk + diff --git a/src/libs/xpcom18a4/xpcom/Makefile.kup b/src/libs/xpcom18a4/xpcom/Makefile.kup new file mode 100644 index 00000000..e69de29b diff --git a/src/libs/xpcom18a4/xpcom/MoreFiles/.cvsignore b/src/libs/xpcom18a4/xpcom/MoreFiles/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/MoreFiles/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/xpcom/MoreFiles/Makefile.in b/src/libs/xpcom18a4/xpcom/MoreFiles/Makefile.in new file mode 100644 index 00000000..56d89456 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/MoreFiles/Makefile.in @@ -0,0 +1,70 @@ +# +# ***** 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. +# Portions created by the Initial Developer are Copyright (C) 2001 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of 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 ***** + +DEPTH = ../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = macmorefiles +REQUIRES = + +# ifeq for standalone builds +ifneq (,$(filter mac cocoa,$(MOZ_WIDGET_TOOLKIT))) + +LIBRARY_NAME = macmorefiles_s + +CSRCS = \ + MoreFilesX.c \ + FSCopyObject.c \ + $(NULL) + +EXPORTS += \ + MoreFilesX.h \ + FSCopyObject.h \ + $(NULL) + +# we don't want the shared lib, but we want to force the creation of a +# static lib. +FORCE_STATIC_LIB=1 +FORCE_USE_PIC=1 + +endif + +include $(topsrcdir)/config/rules.mk diff --git a/src/libs/xpcom18a4/xpcom/MoreFiles/MoreFilesX.c b/src/libs/xpcom18a4/xpcom/MoreFiles/MoreFilesX.c new file mode 100644 index 00000000..d1b7af9e --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/MoreFiles/MoreFilesX.c @@ -0,0 +1,2765 @@ +/* + File: MoreFilesX.c + + Contains: A collection of useful high-level File Manager routines + which use the HFS Plus APIs wherever possible. + + Version: MoreFilesX 1.0.1 + + +*/ + +/* ***** 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 Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + + +// Modified 2006-01-23 - added this comment. + +#if defined(__MACH__) + #include + #include +#else + #include + #include +#endif + +#include "MoreFilesX.h" + +/* Set BuildingMoreFilesXForMacOS9 to 1 if building for Mac OS 9 */ +#ifndef BuildingMoreFilesXForMacOS9 + #define BuildingMoreFilesXForMacOS9 0 +#endif + +/*****************************************************************************/ + +#pragma mark ----- Local type definitions ----- + +struct FSIterateContainerGlobals +{ + IterateContainerFilterProcPtr iterateFilter; /* pointer to IterateFilterProc */ + FSCatalogInfoBitmap whichInfo; /* fields of the CatalogInfo to get */ + FSCatalogInfo catalogInfo; /* FSCatalogInfo */ + FSRef ref; /* FSRef */ + FSSpec spec; /* FSSpec */ + FSSpec *specPtr; /* pointer to spec field, or NULL */ + HFSUniStr255 name; /* HFSUniStr255 */ + HFSUniStr255 *namePtr; /* pointer to name field, or NULL */ + void *yourDataPtr; /* a pointer to caller supplied data the filter may need to access */ + ItemCount maxLevels; /* maximum levels to iterate through */ + ItemCount currentLevel; /* the current level FSIterateContainerLevel is on */ + Boolean quitFlag; /* set to true if filter wants to kill interation */ + Boolean containerChanged; /* temporary - set to true if the current container changed during iteration */ + OSErr result; /* result */ + ItemCount actualObjects; /* number of objects returned */ +}; +typedef struct FSIterateContainerGlobals FSIterateContainerGlobals; + +struct FSDeleteContainerGlobals +{ + OSErr result; /* result */ + ItemCount actualObjects; /* number of objects returned */ + FSCatalogInfo catalogInfo; /* FSCatalogInfo */ +}; +typedef struct FSDeleteContainerGlobals FSDeleteContainerGlobals; + +/*****************************************************************************/ + +#pragma mark ----- Local prototypes ----- + +static +void +FSDeleteContainerLevel( + const FSRef *container, + FSDeleteContainerGlobals *theGlobals); + +static +void +FSIterateContainerLevel( + FSIterateContainerGlobals *theGlobals); + +static +OSErr +GenerateUniqueHFSUniStr( + long *startSeed, + const FSRef *dir1, + const FSRef *dir2, + HFSUniStr255 *uniqueName); + +/*****************************************************************************/ + +#pragma mark ----- File Access Routines ----- + +/*****************************************************************************/ + +OSErr +FSCopyFork( + SInt16 srcRefNum, + SInt16 dstRefNum, + void *copyBufferPtr, + ByteCount copyBufferSize) +{ + OSErr srcResult; + OSErr dstResult; + OSErr result; + SInt64 forkSize; + ByteCount readActualCount; + + /* check input parameters */ + require_action((NULL != copyBufferPtr) && (0 != copyBufferSize), BadParameter, result = paramErr); + + /* get source fork size */ + result = FSGetForkSize(srcRefNum, &forkSize); + require_noerr(result, SourceFSGetForkSizeFailed); + + /* allocate disk space for destination fork */ + result = FSSetForkSize(dstRefNum, fsFromStart, forkSize); + require_noerr(result, DestinationFSSetForkSizeFailed); + + /* reset source fork's position to 0 */ + result = FSSetForkPosition(srcRefNum, fsFromStart, 0); + require_noerr(result, SourceFSSetForkPositionFailed); + + /* reset destination fork's position to 0 */ + result = FSSetForkPosition(dstRefNum, fsFromStart, 0); + require_noerr(result, DestinationFSSetForkPositionFailed); + + /* If copyBufferSize is greater than 4K bytes, make it a multiple of 4k bytes */ + /* This will make writes on local volumes faster */ + if ( (copyBufferSize >= 0x00001000) && ((copyBufferSize & 0x00000fff) != 0) ) + { + copyBufferSize &= ~(0x00001000 - 1); + } + + /* copy source to destination */ + srcResult = dstResult = noErr; + while ( (noErr == srcResult) && (noErr == dstResult) ) + { + srcResult = FSReadFork(srcRefNum, fsAtMark + noCacheMask, 0, copyBufferSize, copyBufferPtr, &readActualCount); + dstResult = FSWriteFork(dstRefNum, fsAtMark + noCacheMask, 0, readActualCount, copyBufferPtr, NULL); + } + + /* make sure there were no errors at the destination */ + require_noerr_action(dstResult, DestinationFSWriteForkFailed, result = dstResult); + + /* make sure the error at the source was eofErr */ + require_action(eofErr == srcResult, SourceResultNotEofErr, result = srcResult); + + /* everything went as expected */ + result = noErr; + +SourceResultNotEofErr: +DestinationFSWriteForkFailed: +DestinationFSSetForkPositionFailed: +SourceFSSetForkPositionFailed: +DestinationFSSetForkSizeFailed: +SourceFSGetForkSizeFailed: +BadParameter: + + return ( result ); +} + +/*****************************************************************************/ + +#pragma mark ----- Volume Access Routines ----- + +/*****************************************************************************/ + +OSErr +FSGetVolParms( + FSVolumeRefNum volRefNum, + UInt32 bufferSize, + GetVolParmsInfoBuffer *volParmsInfo, + UInt32 *actualInfoSize) +{ + OSErr result; + HParamBlockRec pb; + + /* check parameters */ + require_action((NULL != volParmsInfo) && (NULL != actualInfoSize), + BadParameter, result = paramErr); + + pb.ioParam.ioNamePtr = NULL; + pb.ioParam.ioVRefNum = volRefNum; + pb.ioParam.ioBuffer = (Ptr)volParmsInfo; + pb.ioParam.ioReqCount = (SInt32)bufferSize; + result = PBHGetVolParmsSync(&pb); + require_noerr(result, PBHGetVolParmsSync); + + /* return number of bytes the file system returned in volParmsInfo buffer */ + *actualInfoSize = (UInt32)pb.ioParam.ioActCount; + +PBHGetVolParmsSync: +BadParameter: + + return ( result ); +} + +/*****************************************************************************/ + +OSErr +FSGetVRefNum( + const FSRef *ref, + FSVolumeRefNum *vRefNum) +{ + OSErr result; + FSCatalogInfo catalogInfo; + + /* check parameters */ + require_action(NULL != vRefNum, BadParameter, result = paramErr); + + /* get the volume refNum from the FSRef */ + result = FSGetCatalogInfo(ref, kFSCatInfoVolume, &catalogInfo, NULL, NULL, NULL); + require_noerr(result, FSGetCatalogInfo); + + /* return volume refNum from catalogInfo */ + *vRefNum = catalogInfo.volume; + +FSGetCatalogInfo: +BadParameter: + + return ( result ); +} + +/*****************************************************************************/ + +OSErr +FSGetVInfo( + FSVolumeRefNum volume, + HFSUniStr255 *volumeName, /* can be NULL */ + UInt64 *freeBytes, /* can be NULL */ + UInt64 *totalBytes) /* can be NULL */ +{ + OSErr result; + FSVolumeInfo info; + + /* ask for the volume's sizes only if needed */ + result = FSGetVolumeInfo(volume, 0, NULL, + (((NULL != freeBytes) || (NULL != totalBytes)) ? kFSVolInfoSizes : kFSVolInfoNone), + &info, volumeName, NULL); + require_noerr(result, FSGetVolumeInfo); + + if ( NULL != freeBytes ) + { + *freeBytes = info.freeBytes; + } + if ( NULL != totalBytes ) + { + *totalBytes = info.totalBytes; + } + +FSGetVolumeInfo: + + return ( result ); +} + +/*****************************************************************************/ + +OSErr +FSGetVolFileSystemID( + FSVolumeRefNum volume, + UInt16 *fileSystemID, /* can be NULL */ + UInt16 *signature) /* can be NULL */ +{ + OSErr result; + FSVolumeInfo info; + + result = FSGetVolumeInfo(volume, 0, NULL, kFSVolInfoFSInfo, &info, NULL, NULL); + require_noerr(result, FSGetVolumeInfo); + + if ( NULL != fileSystemID ) + { + *fileSystemID = info.filesystemID; + } + if ( NULL != signature ) + { + *signature = info.signature; + } + +FSGetVolumeInfo: + + return ( result ); +} + +/*****************************************************************************/ + +OSErr +FSGetMountedVolumes( + FSRef ***volumeRefsHandle, /* pointer to handle of FSRefs */ + ItemCount *numVolumes) +{ + OSErr result; + OSErr memResult; + ItemCount volumeIndex; + FSRef ref; + + /* check parameters */ + require_action((NULL != volumeRefsHandle) && (NULL != numVolumes), + BadParameter, result = paramErr); + + /* No volumes yet */ + *numVolumes = 0; + + /* Allocate a handle for the results */ + *volumeRefsHandle = (FSRef **)NewHandle(0); + require_action(NULL != *volumeRefsHandle, NewHandle, result = memFullErr); + + /* Call FSGetVolumeInfo in loop to get all volumes starting with the first */ + volumeIndex = 1; + do + { + result = FSGetVolumeInfo(0, volumeIndex, NULL, kFSVolInfoNone, NULL, NULL, &ref); + if ( noErr == result ) + { + /* concatenate the FSRef to the end of the handle */ + PtrAndHand(&ref, (Handle)*volumeRefsHandle, sizeof(FSRef)); + memResult = MemError(); + require_noerr_action(memResult, MemoryAllocationFailed, result = memResult); + + ++(*numVolumes); /* increment the volume count */ + ++volumeIndex; /* and the volumeIndex to get the next volume*/ + } + } while ( noErr == result ); + + /* nsvErr is OK -- it just means there are no more volumes */ + require(nsvErr == result, FSGetVolumeInfo); + + return ( noErr ); + + /**********************/ + +MemoryAllocationFailed: +FSGetVolumeInfo: + + /* dispose of handle if already allocated and clear the outputs */ + if ( NULL != *volumeRefsHandle ) + { + DisposeHandle((Handle)*volumeRefsHandle); + *volumeRefsHandle = NULL; + } + *numVolumes = 0; + +NewHandle: +BadParameter: + + return ( result ); +} + +/*****************************************************************************/ + +#pragma mark ----- FSRef/FSpec/Path/Name Conversion Routines ----- + +/*****************************************************************************/ + +OSErr +FSRefMakeFSSpec( + const FSRef *ref, + FSSpec *spec) +{ + OSErr result; + + /* check parameters */ + require_action(NULL != spec, BadParameter, result = paramErr); + + result = FSGetCatalogInfo(ref, kFSCatInfoNone, NULL, NULL, spec, NULL); + require_noerr(result, FSGetCatalogInfo); + +FSGetCatalogInfo: +BadParameter: + + return ( result ); +} + +/*****************************************************************************/ + +OSErr +FSMakeFSRef( + FSVolumeRefNum volRefNum, + SInt32 dirID, + ConstStr255Param name, + FSRef *ref) +{ + OSErr result; + FSRefParam pb; + + /* check parameters */ + require_action(NULL != ref, BadParameter, result = paramErr); + + pb.ioVRefNum = volRefNum; + pb.ioDirID = dirID; + pb.ioNamePtr = (StringPtr)name; + pb.newRef = ref; + result = PBMakeFSRefSync(&pb); + require_noerr(result, PBMakeFSRefSync); + +PBMakeFSRefSync: +BadParameter: + + return ( result ); +} + +/*****************************************************************************/ + +OSStatus +FSMakePath( + SInt16 volRefNum, + SInt32 dirID, + ConstStr255Param name, + UInt8 *path, + UInt32 maxPathSize) +{ + OSStatus result; + FSRef ref; + + /* check parameters */ + require_action(NULL != path, BadParameter, result = paramErr); + + /* convert the inputs to an FSRef */ + result = FSMakeFSRef(volRefNum, dirID, name, &ref); + require_noerr(result, FSMakeFSRef); + + /* and then convert the FSRef to a path */ + result = FSRefMakePath(&ref, path, maxPathSize); + require_noerr(result, FSRefMakePath); + +FSRefMakePath: +FSMakeFSRef: +BadParameter: + + return ( result ); +} + +/*****************************************************************************/ + +OSStatus +FSPathMakeFSSpec( + const UInt8 *path, + FSSpec *spec, + Boolean *isDirectory) /* can be NULL */ +{ + OSStatus result; + FSRef ref; + + /* check parameters */ + require_action(NULL != spec, BadParameter, result = paramErr); + + /* convert the POSIX path to an FSRef */ + result = FSPathMakeRef(path, &ref, isDirectory); + require_noerr(result, FSPathMakeRef); + + /* and then convert the FSRef to an FSSpec */ + result = FSGetCatalogInfo(&ref, kFSCatInfoNone, NULL, NULL, spec, NULL); + require_noerr(result, FSGetCatalogInfo); + +FSGetCatalogInfo: +FSPathMakeRef: +BadParameter: + + return ( result ); +} + +/*****************************************************************************/ + +OSErr +UnicodeNameGetHFSName( + UniCharCount nameLength, + const UniChar *name, + TextEncoding textEncodingHint, + Boolean isVolumeName, + Str31 hfsName) +{ + OSStatus result; + ByteCount unicodeByteLength; + ByteCount unicodeBytesConverted; + ByteCount actualPascalBytes; + UnicodeMapping uMapping; + UnicodeToTextInfo utInfo; + + /* check parameters */ + require_action(NULL != hfsName, BadParameter, result = paramErr); + + /* make sure output is valid in case we get errors or there's nothing to convert */ + hfsName[0] = 0; + + unicodeByteLength = nameLength * sizeof(UniChar); + if ( 0 == unicodeByteLength ) + { + /* do nothing */ + result = noErr; + } + else + { + /* if textEncodingHint is kTextEncodingUnknown, get a "default" textEncodingHint */ + if ( kTextEncodingUnknown == textEncodingHint ) + { + ScriptCode script; + RegionCode region; + + script = (ScriptCode)GetScriptManagerVariable(smSysScript); + region = (RegionCode)GetScriptManagerVariable(smRegionCode); + result = UpgradeScriptInfoToTextEncoding(script, kTextLanguageDontCare, region, + NULL, &textEncodingHint ); + if ( paramErr == result ) + { + /* ok, ignore the region and try again */ + result = UpgradeScriptInfoToTextEncoding(script, kTextLanguageDontCare, + kTextRegionDontCare, NULL, &textEncodingHint ); + } + if ( noErr != result ) + { + /* ok... try something */ + textEncodingHint = kTextEncodingMacRoman; + } + } + + uMapping.unicodeEncoding = CreateTextEncoding(kTextEncodingUnicodeV2_0, + kUnicodeCanonicalDecompVariant, kUnicode16BitFormat); + uMapping.otherEncoding = GetTextEncodingBase(textEncodingHint); + uMapping.mappingVersion = kUnicodeUseHFSPlusMapping; + + result = CreateUnicodeToTextInfo(&uMapping, &utInfo); + require_noerr(result, CreateUnicodeToTextInfo); + + result = ConvertFromUnicodeToText(utInfo, unicodeByteLength, name, kUnicodeLooseMappingsMask, + 0, NULL, 0, NULL, /* offsetCounts & offsetArrays */ + isVolumeName ? kHFSMaxVolumeNameChars : kHFSMaxFileNameChars, + &unicodeBytesConverted, &actualPascalBytes, &hfsName[1]); + require_noerr(result, ConvertFromUnicodeToText); + + hfsName[0] = (unsigned char)actualPascalBytes; /* fill in length byte */ + +ConvertFromUnicodeToText: + + /* verify the result in debug builds -- there's really not anything you can do if it fails */ + verify_noerr(DisposeUnicodeToTextInfo(&utInfo)); + } + +CreateUnicodeToTextInfo: +BadParameter: + + return ( result ); +} + +/*****************************************************************************/ + +OSErr +HFSNameGetUnicodeName( + ConstStr31Param hfsName, + TextEncoding textEncodingHint, + HFSUniStr255 *unicodeName) +{ + ByteCount unicodeByteLength; + OSStatus result; + UnicodeMapping uMapping; + TextToUnicodeInfo tuInfo; + ByteCount pascalCharsRead; + + /* check parameters */ + require_action(NULL != unicodeName, BadParameter, result = paramErr); + + /* make sure output is valid in case we get errors or there's nothing to convert */ + unicodeName->length = 0; + + if ( 0 == StrLength(hfsName) ) + { + result = noErr; + } + else + { + /* if textEncodingHint is kTextEncodingUnknown, get a "default" textEncodingHint */ + if ( kTextEncodingUnknown == textEncodingHint ) + { + ScriptCode script; + RegionCode region; + + script = GetScriptManagerVariable(smSysScript); + region = GetScriptManagerVariable(smRegionCode); + result = UpgradeScriptInfoToTextEncoding(script, kTextLanguageDontCare, region, + NULL, &textEncodingHint); + if ( paramErr == result ) + { + /* ok, ignore the region and try again */ + result = UpgradeScriptInfoToTextEncoding(script, kTextLanguageDontCare, + kTextRegionDontCare, NULL, &textEncodingHint); + } + if ( noErr != result ) + { + /* ok... try something */ + textEncodingHint = kTextEncodingMacRoman; + } + } + + uMapping.unicodeEncoding = CreateTextEncoding(kTextEncodingUnicodeV2_0, + kUnicodeCanonicalDecompVariant, kUnicode16BitFormat); + uMapping.otherEncoding = GetTextEncodingBase(textEncodingHint); + uMapping.mappingVersion = kUnicodeUseHFSPlusMapping; + + result = CreateTextToUnicodeInfo(&uMapping, &tuInfo); + require_noerr(result, CreateTextToUnicodeInfo); + + result = ConvertFromTextToUnicode(tuInfo, hfsName[0], &hfsName[1], + 0, /* no control flag bits */ + 0, NULL, 0, NULL, /* offsetCounts & offsetArrays */ + sizeof(unicodeName->unicode), /* output buffer size in bytes */ + &pascalCharsRead, &unicodeByteLength, unicodeName->unicode); + require_noerr(result, ConvertFromTextToUnicode); + + /* convert from byte count to char count */ + unicodeName->length = unicodeByteLength / sizeof(UniChar); + +ConvertFromTextToUnicode: + + /* verify the result in debug builds -- there's really not anything you can do if it fails */ + verify_noerr(DisposeTextToUnicodeInfo(&tuInfo)); + } + +CreateTextToUnicodeInfo: +BadParameter: + + return ( result ); +} + +/*****************************************************************************/ + +#pragma mark ----- File/Directory Manipulation Routines ----- + +/*****************************************************************************/ + +Boolean FSRefValid(const FSRef *ref) +{ + return ( noErr == FSGetCatalogInfo(ref, kFSCatInfoNone, NULL, NULL, NULL, NULL) ); +} + +/*****************************************************************************/ + +OSErr +FSGetParentRef( + const FSRef *ref, + FSRef *parentRef) +{ + OSErr result; + FSCatalogInfo catalogInfo; + + /* check parameters */ + require_action(NULL != parentRef, BadParameter, result = paramErr); + + result = FSGetCatalogInfo(ref, kFSCatInfoNodeID, &catalogInfo, NULL, NULL, parentRef); + require_noerr(result, FSGetCatalogInfo); + + /* + * Note: FSRefs always point to real file system objects. So, there cannot + * be a FSRef to the parent of volume root directories. Early versions of + * Mac OS X do not handle this case correctly and incorrectly return a + * FSRef for the parent of volume root directories instead of returning an + * invalid FSRef (a cleared FSRef is invalid). The next three lines of code + * ensure that you won't run into this bug. WW9D! + */ + if ( fsRtDirID == catalogInfo.nodeID ) + { + /* clear parentRef and return noErr which is the proper behavior */ + memset(parentRef, 0, sizeof(FSRef)); + } + +FSGetCatalogInfo: +BadParameter: + + return ( result ); +} + +/*****************************************************************************/ + +OSErr +FSGetFileDirName( + const FSRef *ref, + HFSUniStr255 *outName) +{ + OSErr result; + + /* check parameters */ + require_action(NULL != outName, BadParameter, result = paramErr); + + result = FSGetCatalogInfo(ref, kFSCatInfoNone, NULL, outName, NULL, NULL); + require_noerr(result, FSGetCatalogInfo); + +FSGetCatalogInfo: +BadParameter: + + return ( result ); +} + +/*****************************************************************************/ + +OSErr +FSGetNodeID( + const FSRef *ref, + long *nodeID, /* can be NULL */ + Boolean *isDirectory) /* can be NULL */ +{ + OSErr result; + FSCatalogInfo catalogInfo; + FSCatalogInfoBitmap whichInfo; + + /* determine what catalog information to get */ + whichInfo = kFSCatInfoNone; /* start with none */ + if ( NULL != nodeID ) + { + whichInfo |= kFSCatInfoNodeID; + } + if ( NULL != isDirectory ) + { + whichInfo |= kFSCatInfoNodeFlags; + } + + result = FSGetCatalogInfo(ref, whichInfo, &catalogInfo, NULL, NULL, NULL); + require_noerr(result, FSGetCatalogInfo); + + if ( NULL != nodeID ) + { + *nodeID = catalogInfo.nodeID; + } + if ( NULL != isDirectory ) + { + *isDirectory = (0 != (kFSNodeIsDirectoryMask & catalogInfo.nodeFlags)); + } + +FSGetCatalogInfo: + + return ( result ); +} + +/*****************************************************************************/ + +OSErr +FSGetUserPrivilegesPermissions( + const FSRef *ref, + UInt8 *userPrivileges, /* can be NULL */ + UInt32 permissions[4]) /* can be NULL */ +{ + OSErr result; + FSCatalogInfo catalogInfo; + FSCatalogInfoBitmap whichInfo; + + /* determine what catalog information to get */ + whichInfo = kFSCatInfoNone; /* start with none */ + if ( NULL != userPrivileges ) + { + whichInfo |= kFSCatInfoUserPrivs; + } + if ( NULL != permissions ) + { + whichInfo |= kFSCatInfoPermissions; + } + + result = FSGetCatalogInfo(ref, whichInfo, &catalogInfo, NULL, NULL, NULL); + require_noerr(result, FSGetCatalogInfo); + + if ( NULL != userPrivileges ) + { + *userPrivileges = catalogInfo.userPrivileges; + } + if ( NULL != permissions ) + { + BlockMoveData(&catalogInfo.permissions, permissions, sizeof(UInt32) * 4); + } + +FSGetCatalogInfo: + + return ( result ); +} + +/*****************************************************************************/ + +OSErr +FSCheckLock( + const FSRef *ref) +{ + OSErr result; + FSCatalogInfo catalogInfo; + FSVolumeInfo volumeInfo; + + /* get nodeFlags and vRefNum for container */ + result = FSGetCatalogInfo(ref, kFSCatInfoNodeFlags + kFSCatInfoVolume, &catalogInfo, NULL, NULL,NULL); + require_noerr(result, FSGetCatalogInfo); + + /* is file locked? */ + if ( 0 != (catalogInfo.nodeFlags & kFSNodeLockedMask) ) + { + result = fLckdErr; /* file is locked */ + } + else + { + /* file isn't locked, but is volume locked? */ + + /* get volume flags */ + result = FSGetVolumeInfo(catalogInfo.volume, 0, NULL, kFSVolInfoFlags, &volumeInfo, NULL, NULL); + require_noerr(result, FSGetVolumeInfo); + + if ( 0 != (volumeInfo.flags & kFSVolFlagHardwareLockedMask) ) + { + result = wPrErr; /* volume locked by hardware */ + } + else if ( 0 != (volumeInfo.flags & kFSVolFlagSoftwareLockedMask) ) + { + result = vLckdErr; /* volume locked by software */ + } + } + +FSGetVolumeInfo: +FSGetCatalogInfo: + + return ( result ); +} + +/*****************************************************************************/ + +OSErr +FSGetForkSizes( + const FSRef *ref, + UInt64 *dataLogicalSize, /* can be NULL */ + UInt64 *rsrcLogicalSize) /* can be NULL */ +{ + OSErr result; + FSCatalogInfoBitmap whichInfo; + FSCatalogInfo catalogInfo; + + whichInfo = kFSCatInfoNodeFlags; + if ( NULL != dataLogicalSize ) + { + /* get data fork size */ + whichInfo |= kFSCatInfoDataSizes; + } + if ( NULL != rsrcLogicalSize ) + { + /* get resource fork size */ + whichInfo |= kFSCatInfoRsrcSizes; + } + + /* get nodeFlags and catalog info */ + result = FSGetCatalogInfo(ref, whichInfo, &catalogInfo, NULL, NULL,NULL); + require_noerr(result, FSGetCatalogInfo); + + /* make sure FSRef was to a file */ + require_action(0 == (catalogInfo.nodeFlags & kFSNodeIsDirectoryMask), FSRefNotFile, result = notAFileErr); + + if ( NULL != dataLogicalSize ) + { + /* return data fork size */ + *dataLogicalSize = catalogInfo.dataLogicalSize; + } + if ( NULL != rsrcLogicalSize ) + { + /* return resource fork size */ + *rsrcLogicalSize = catalogInfo.rsrcLogicalSize; + } + +FSRefNotFile: +FSGetCatalogInfo: + + return ( result ); +} + +/*****************************************************************************/ + +OSErr +FSGetTotalForkSizes( + const FSRef *ref, + UInt64 *totalLogicalSize, /* can be NULL */ + UInt64 *totalPhysicalSize, /* can be NULL */ + ItemCount *forkCount) /* can be NULL */ +{ + OSErr result; + CatPositionRec forkIterator; + SInt64 forkSize; + SInt64 *forkSizePtr; + UInt64 forkPhysicalSize; + UInt64 *forkPhysicalSizePtr; + + /* Determine if forkSize needed */ + if ( NULL != totalLogicalSize) + { + *totalLogicalSize = 0; + forkSizePtr = &forkSize; + } + else + { + forkSizePtr = NULL; + } + + /* Determine if forkPhysicalSize is needed */ + if ( NULL != totalPhysicalSize ) + { + *totalPhysicalSize = 0; + forkPhysicalSizePtr = &forkPhysicalSize; + } + else + { + forkPhysicalSizePtr = NULL; + } + + /* zero fork count if returning it */ + if ( NULL != forkCount ) + { + *forkCount = 0; + } + + /* Iterate through the forks to get the sizes */ + forkIterator.initialize = 0; + do + { + result = FSIterateForks(ref, &forkIterator, NULL, forkSizePtr, forkPhysicalSizePtr); + if ( noErr == result ) + { + if ( NULL != totalLogicalSize ) + { + *totalLogicalSize += forkSize; + } + + if ( NULL != totalPhysicalSize ) + { + *totalPhysicalSize += forkPhysicalSize; + } + + if ( NULL != forkCount ) + { + ++*forkCount; + } + } + } while ( noErr == result ); + + /* any error result other than errFSNoMoreItems is serious */ + require(errFSNoMoreItems == result, FSIterateForks); + + /* Normal exit */ + result = noErr; + +FSIterateForks: + + return ( result ); +} + +/*****************************************************************************/ + +OSErr +FSBumpDate( + const FSRef *ref) +{ + OSStatus result; + FSCatalogInfo catalogInfo; + UTCDateTime oldDateTime; +#if !BuildingMoreFilesXForMacOS9 + FSRef parentRef; + Boolean notifyParent; +#endif + +#if !BuildingMoreFilesXForMacOS9 + /* Get the node flags, the content modification date and time, and the parent ref */ + result = FSGetCatalogInfo(ref, kFSCatInfoNodeFlags + kFSCatInfoContentMod, &catalogInfo, NULL, NULL, &parentRef); + require_noerr(result, FSGetCatalogInfo); + + /* Notify the parent if this is a file */ + notifyParent = (0 == (catalogInfo.nodeFlags & kFSNodeIsDirectoryMask)); +#else + /* Get the content modification date and time */ + result = FSGetCatalogInfo(ref, kFSCatInfoContentMod, &catalogInfo, NULL, NULL, NULL); + require_noerr(result, FSGetCatalogInfo); +#endif + + oldDateTime = catalogInfo.contentModDate; + + /* Get the current date and time */ + result = GetUTCDateTime(&catalogInfo.contentModDate, kUTCDefaultOptions); + require_noerr(result, GetUTCDateTime); + + /* if the old date and time is the the same as the current, bump the seconds by one */ + if ( (catalogInfo.contentModDate.fraction == oldDateTime.fraction) && + (catalogInfo.contentModDate.lowSeconds == oldDateTime.lowSeconds) && + (catalogInfo.contentModDate.highSeconds == oldDateTime.highSeconds) ) + { + ++catalogInfo.contentModDate.lowSeconds; + if ( 0 == catalogInfo.contentModDate.lowSeconds ) + { + ++catalogInfo.contentModDate.highSeconds; + } + } + + /* Bump the content modification date and time */ + result = FSSetCatalogInfo(ref, kFSCatInfoContentMod, &catalogInfo); + require_noerr(result, FSSetCatalogInfo); + +#if !BuildingMoreFilesXForMacOS9 + /* + * The problem with FNNotify is that it is not available under Mac OS 9 + * and there's no way to test for that except for looking for the symbol + * or something. So, I'll just conditionalize this for those who care + * to send a notification. + */ + + /* Send a notification for the parent of the file, or for the directory */ + result = FNNotify(notifyParent ? &parentRef : ref, kFNDirectoryModifiedMessage, kNilOptions); + require_noerr(result, FNNotify); +#endif + + /* ignore errors from FSSetCatalogInfo (volume might be write protected) and FNNotify */ +FNNotify: +FSSetCatalogInfo: + + return ( noErr ); + + /**********************/ + +GetUTCDateTime: +FSGetCatalogInfo: + + return ( result ); +} + +/*****************************************************************************/ + +OSErr +FSGetFinderInfo( + const FSRef *ref, + FinderInfo *info, /* can be NULL */ + ExtendedFinderInfo *extendedInfo, /* can be NULL */ + Boolean *isDirectory) /* can be NULL */ +{ + OSErr result; + FSCatalogInfo catalogInfo; + FSCatalogInfoBitmap whichInfo; + + /* determine what catalog information is really needed */ + whichInfo = kFSCatInfoNone; + + if ( NULL != info ) + { + /* get FinderInfo */ + whichInfo |= kFSCatInfoFinderInfo; + } + + if ( NULL != extendedInfo ) + { + /* get ExtendedFinderInfo */ + whichInfo |= kFSCatInfoFinderXInfo; + } + + if ( NULL != isDirectory ) + { + whichInfo |= kFSCatInfoNodeFlags; + } + + result = FSGetCatalogInfo(ref, whichInfo, &catalogInfo, NULL, NULL, NULL); + require_noerr(result, FSGetCatalogInfo); + + /* return FinderInfo if requested */ + if ( NULL != info ) + { + BlockMoveData(catalogInfo.finderInfo, info, sizeof(FinderInfo)); + } + + /* return ExtendedFinderInfo if requested */ + if ( NULL != extendedInfo) + { + BlockMoveData(catalogInfo.extFinderInfo, extendedInfo, sizeof(ExtendedFinderInfo)); + } + + /* set isDirectory Boolean if requested */ + if ( NULL != isDirectory) + { + *isDirectory = (0 != (kFSNodeIsDirectoryMask & catalogInfo.nodeFlags)); + } + +FSGetCatalogInfo: + + return ( result ); +} + +/*****************************************************************************/ + +OSErr +FSSetFinderInfo( + const FSRef *ref, + const FinderInfo *info, + const ExtendedFinderInfo *extendedInfo) +{ + OSErr result; + FSCatalogInfo catalogInfo; + FSCatalogInfoBitmap whichInfo; + + /* determine what catalog information will be set */ + whichInfo = kFSCatInfoNone; /* start with none */ + if ( NULL != info ) + { + /* set FinderInfo */ + whichInfo |= kFSCatInfoFinderInfo; + BlockMoveData(info, catalogInfo.finderInfo, sizeof(FinderInfo)); + } + if ( NULL != extendedInfo ) + { + /* set ExtendedFinderInfo */ + whichInfo |= kFSCatInfoFinderXInfo; + BlockMoveData(extendedInfo, catalogInfo.extFinderInfo, sizeof(ExtendedFinderInfo)); + } + + result = FSSetCatalogInfo(ref, whichInfo, &catalogInfo); + require_noerr(result, FSGetCatalogInfo); + +FSGetCatalogInfo: + + return ( result ); +} + +/*****************************************************************************/ + +OSErr +FSChangeCreatorType( + const FSRef *ref, + OSType fileCreator, + OSType fileType) +{ + OSErr result; + FSCatalogInfo catalogInfo; + FSRef parentRef; + + /* get nodeFlags, finder info, and parent FSRef */ + result = FSGetCatalogInfo(ref, kFSCatInfoNodeFlags + kFSCatInfoFinderInfo, &catalogInfo , NULL, NULL, &parentRef); + require_noerr(result, FSGetCatalogInfo); + + /* make sure FSRef was to a file */ + require_action(0 == (catalogInfo.nodeFlags & kFSNodeIsDirectoryMask), FSRefNotFile, result = notAFileErr); + + /* If fileType not 0x00000000, change fileType */ + if ( fileType != (OSType)0x00000000 ) + { + ((FileInfo *)&catalogInfo.finderInfo)->fileType = fileType; + } + + /* If creator not 0x00000000, change creator */ + if ( fileCreator != (OSType)0x00000000 ) + { + ((FileInfo *)&catalogInfo.finderInfo)->fileCreator = fileCreator; + } + + /* now, save the new information back to disk */ + result = FSSetCatalogInfo(ref, kFSCatInfoFinderInfo, &catalogInfo); + require_noerr(result, FSSetCatalogInfo); + + /* and attempt to bump the parent directory's mod date to wake up */ + /* the Finder to the change we just made (ignore errors from this) */ + verify_noerr(FSBumpDate(&parentRef)); + +FSSetCatalogInfo: +FSRefNotFile: +FSGetCatalogInfo: + + return ( result ); +} + +/*****************************************************************************/ + +OSErr +FSChangeFinderFlags( + const FSRef *ref, + Boolean setBits, + UInt16 flagBits) +{ + OSErr result; + FSCatalogInfo catalogInfo; + FSRef parentRef; + + /* get the current finderInfo */ + result = FSGetCatalogInfo(ref, kFSCatInfoFinderInfo, &catalogInfo, NULL, NULL, &parentRef); + require_noerr(result, FSGetCatalogInfo); + + /* set or clear the appropriate bits in the finderInfo.finderFlags */ + if ( setBits ) + { + /* OR in the bits */ + ((FileInfo *)&catalogInfo.finderInfo)->finderFlags |= flagBits; + } + else + { + /* AND out the bits */ + ((FileInfo *)&catalogInfo.finderInfo)->finderFlags &= ~flagBits; + } + + /* save the modified finderInfo */ + result = FSSetCatalogInfo(ref, kFSCatInfoFinderInfo, &catalogInfo); + require_noerr(result, FSSetCatalogInfo); + + /* and attempt to bump the parent directory's mod date to wake up the Finder */ + /* to the change we just made (ignore errors from this) */ + verify_noerr(FSBumpDate(&parentRef)); + +FSSetCatalogInfo: +FSGetCatalogInfo: + + return ( result ); +} + +/*****************************************************************************/ + +OSErr +FSSetInvisible( + const FSRef *ref) +{ + return ( FSChangeFinderFlags(ref, true, kIsInvisible) ); +} + +OSErr +FSClearInvisible( + const FSRef *ref) +{ + return ( FSChangeFinderFlags(ref, false, kIsInvisible) ); +} + +/*****************************************************************************/ + +OSErr +FSSetNameLocked( + const FSRef *ref) +{ + return ( FSChangeFinderFlags(ref, true, kNameLocked) ); +} + +OSErr +FSClearNameLocked( + const FSRef *ref) +{ + return ( FSChangeFinderFlags(ref, false, kNameLocked) ); +} + +/*****************************************************************************/ + +OSErr +FSSetIsStationery( + const FSRef *ref) +{ + return ( FSChangeFinderFlags(ref, true, kIsStationery) ); +} + +OSErr +FSClearIsStationery( + const FSRef *ref) +{ + return ( FSChangeFinderFlags(ref, false, kIsStationery) ); +} + +/*****************************************************************************/ + +OSErr +FSSetHasCustomIcon( + const FSRef *ref) +{ + return ( FSChangeFinderFlags(ref, true, kHasCustomIcon) ); +} + +OSErr +FSClearHasCustomIcon( + const FSRef *ref) +{ + return ( FSChangeFinderFlags(ref, false, kHasCustomIcon) ); +} + +/*****************************************************************************/ + +OSErr +FSClearHasBeenInited( + const FSRef *ref) +{ + return ( FSChangeFinderFlags(ref, false, kHasBeenInited) ); +} + +/*****************************************************************************/ + +OSErr +FSCopyFileMgrAttributes( + const FSRef *sourceRef, + const FSRef *destinationRef, + Boolean copyLockBit) +{ + OSErr result; + FSCatalogInfo catalogInfo; + + /* get the source information */ + result = FSGetCatalogInfo(sourceRef, kFSCatInfoSettableInfo, &catalogInfo, NULL, NULL, NULL); + require_noerr(result, FSGetCatalogInfo); + + /* don't copy the hasBeenInited bit; clear it */ + ((FileInfo *)&catalogInfo.finderInfo)->finderFlags &= ~kHasBeenInited; + + /* should the locked bit be copied? */ + if ( !copyLockBit ) + { + /* no, make sure the locked bit is clear */ + catalogInfo.nodeFlags &= ~kFSNodeLockedMask; + } + + /* set the destination information */ + result = FSSetCatalogInfo(destinationRef, kFSCatInfoSettableInfo, &catalogInfo); + require_noerr(result, FSSetCatalogInfo); + +FSSetCatalogInfo: +FSGetCatalogInfo: + + return ( result ); +} + +/*****************************************************************************/ + +OSErr +FSMoveRenameObjectUnicode( + const FSRef *ref, + const FSRef *destDirectory, + UniCharCount nameLength, + const UniChar *name, /* can be NULL (no rename during move) */ + TextEncoding textEncodingHint, + FSRef *newRef) /* if function fails along the way, newRef is final location of file */ +{ + OSErr result; + FSVolumeRefNum vRefNum; + FSCatalogInfo catalogInfo; + FSRef originalDirectory; + TextEncoding originalTextEncodingHint; + HFSUniStr255 originalName; + HFSUniStr255 uniqueName; /* unique name given to object while moving it to destination */ + long theSeed; /* the seed for generating unique names */ + + /* check parameters */ + require_action(NULL != newRef, BadParameter, result = paramErr); + + /* newRef = input to start with */ + BlockMoveData(ref, newRef, sizeof(FSRef)); + + /* get destDirectory's vRefNum */ + result = FSGetCatalogInfo(destDirectory, kFSCatInfoVolume, &catalogInfo, NULL, NULL, NULL); + require_noerr(result, DestinationBad); + + /* save vRefNum */ + vRefNum = catalogInfo.volume; + + /* get ref's vRefNum, TextEncoding, name and parent directory*/ + result = FSGetCatalogInfo(ref, kFSCatInfoTextEncoding + kFSCatInfoVolume, &catalogInfo, &originalName, NULL, &originalDirectory); + require_noerr(result, SourceBad); + + /* save TextEncoding */ + originalTextEncodingHint = catalogInfo.textEncodingHint; + + /* make sure ref and destDirectory are on same volume */ + require_action(vRefNum == catalogInfo.volume, NotSameVolume, result = diffVolErr); + + /* Skip a few steps if we're not renaming */ + if ( NULL != name ) + { + /* generate a name that is unique in both directories */ + theSeed = 0x4a696d4c; /* a fine unlikely filename */ + + result = GenerateUniqueHFSUniStr(&theSeed, &originalDirectory, destDirectory, &uniqueName); + require_noerr(result, GenerateUniqueHFSUniStrFailed); + + /* Rename the object to uniqueName */ + result = FSRenameUnicode(ref, uniqueName.length, uniqueName.unicode, kTextEncodingUnknown, newRef); + require_noerr(result, FSRenameUnicodeBeforeMoveFailed); + + if ( FSCompareFSRefs(destDirectory, &originalDirectory) != noErr ) + { + /* Move object to its new home */ + result = FSMoveObject(newRef, destDirectory, newRef); + require_noerr(result, FSMoveObjectAfterRenameFailed); + } + + /* Rename the object to new name */ + result = FSRenameUnicode(ref, nameLength, name, textEncodingHint, newRef); + require_noerr(result, FSRenameUnicodeAfterMoveFailed); + } + else + { + /* Move object to its new home */ + result = FSMoveObject(newRef, destDirectory, newRef); + require_noerr(result, FSMoveObjectNoRenameFailed); + } + + return ( result ); + + /*************/ + +/* + * failure handling code when renaming + */ + +FSRenameUnicodeAfterMoveFailed: + + /* Error handling: move object back to original location - ignore errors */ + verify_noerr(FSMoveObject(newRef, &originalDirectory, newRef)); + +FSMoveObjectAfterRenameFailed: + + /* Error handling: rename object back to original name - ignore errors */ + verify_noerr(FSRenameUnicode(newRef, originalName.length, originalName.unicode, originalTextEncodingHint, newRef)); + +FSRenameUnicodeBeforeMoveFailed: +GenerateUniqueHFSUniStrFailed: + +/* + * failure handling code for renaming or not + */ +FSMoveObjectNoRenameFailed: +NotSameVolume: +SourceBad: +DestinationBad: +BadParameter: + + return ( result ); +} + +/*****************************************************************************/ + +/* + The FSDeleteContainerLevel function deletes the contents of a container + directory. All files and subdirectories in the specified container are + deleted. If a locked file or directory is encountered, it is unlocked + and then deleted. If any unexpected errors are encountered, + FSDeleteContainerLevel quits and returns to the caller. + + container --> FSRef to a directory. + theGlobals --> A pointer to a FSDeleteContainerGlobals struct + which contains the variables that do not need to + be allocated each time FSDeleteContainerLevel + recurses. That lets FSDeleteContainerLevel use + less stack space per recursion level. +*/ + +static +void +FSDeleteContainerLevel( + const FSRef *container, + FSDeleteContainerGlobals *theGlobals) +{ + /* level locals */ + FSIterator iterator; + FSRef itemToDelete; + UInt16 nodeFlags; + + /* Open FSIterator for flat access and give delete optimization hint */ + theGlobals->result = FSOpenIterator(container, kFSIterateFlat + kFSIterateDelete, &iterator); + require_noerr(theGlobals->result, FSOpenIterator); + + /* delete the contents of the directory */ + do + { + /* get 1 item to delete */ + theGlobals->result = FSGetCatalogInfoBulk(iterator, 1, &theGlobals->actualObjects, + NULL, kFSCatInfoNodeFlags, &theGlobals->catalogInfo, + &itemToDelete, NULL, NULL); + if ( (noErr == theGlobals->result) && (1 == theGlobals->actualObjects) ) + { + /* save node flags in local in case we have to recurse */ + nodeFlags = theGlobals->catalogInfo.nodeFlags; + + /* is it a file or directory? */ + if ( 0 != (nodeFlags & kFSNodeIsDirectoryMask) ) + { + /* it's a directory -- delete its contents before attempting to delete it */ + FSDeleteContainerLevel(&itemToDelete, theGlobals); + } + /* are we still OK to delete? */ + if ( noErr == theGlobals->result ) + { + /* is item locked? */ + if ( 0 != (nodeFlags & kFSNodeLockedMask) ) + { + /* then attempt to unlock it (ignore result since FSDeleteObject will set it correctly) */ + theGlobals->catalogInfo.nodeFlags = nodeFlags & ~kFSNodeLockedMask; + (void) FSSetCatalogInfo(&itemToDelete, kFSCatInfoNodeFlags, &theGlobals->catalogInfo); + } + /* delete the item */ + theGlobals->result = FSDeleteObject(&itemToDelete); + } + } + } while ( noErr == theGlobals->result ); + + /* we found the end of the items normally, so return noErr */ + if ( errFSNoMoreItems == theGlobals->result ) + { + theGlobals->result = noErr; + } + + /* close the FSIterator (closing an open iterator should never fail) */ + verify_noerr(FSCloseIterator(iterator)); + +FSOpenIterator: + + return; +} + +/*****************************************************************************/ + +OSErr +FSDeleteContainerContents( + const FSRef *container) +{ + FSDeleteContainerGlobals theGlobals; + + /* delete container's contents */ + FSDeleteContainerLevel(container, &theGlobals); + + return ( theGlobals.result ); +} + +/*****************************************************************************/ + +OSErr +FSDeleteContainer( + const FSRef *container) +{ + OSErr result; + FSCatalogInfo catalogInfo; + + /* get nodeFlags for container */ + result = FSGetCatalogInfo(container, kFSCatInfoNodeFlags, &catalogInfo, NULL, NULL,NULL); + require_noerr(result, FSGetCatalogInfo); + + /* make sure container is a directory */ + require_action(0 != (catalogInfo.nodeFlags & kFSNodeIsDirectoryMask), ContainerNotDirectory, result = dirNFErr); + + /* delete container's contents */ + result = FSDeleteContainerContents(container); + require_noerr(result, FSDeleteContainerContents); + + /* is container locked? */ + if ( 0 != (catalogInfo.nodeFlags & kFSNodeLockedMask) ) + { + /* then attempt to unlock container (ignore result since FSDeleteObject will set it correctly) */ + catalogInfo.nodeFlags &= ~kFSNodeLockedMask; + (void) FSSetCatalogInfo(container, kFSCatInfoNodeFlags, &catalogInfo); + } + + /* delete the container */ + result = FSDeleteObject(container); + +FSDeleteContainerContents: +ContainerNotDirectory: +FSGetCatalogInfo: + + return ( result ); +} + +/*****************************************************************************/ + +/* + The FSIterateContainerLevel function iterates the contents of a container + directory and calls a IterateContainerFilterProc function once for each + file and directory found. + + theGlobals --> A pointer to a FSIterateContainerGlobals struct + which contains the variables needed globally by + all recusion levels of FSIterateContainerLevel. + That makes FSIterateContainer thread safe since + each call to it uses its own global world. + It also contains the variables that do not need + to be allocated each time FSIterateContainerLevel + recurses. That lets FSIterateContainerLevel use + less stack space per recursion level. +*/ + +static +void +FSIterateContainerLevel( + FSIterateContainerGlobals *theGlobals) +{ + FSIterator iterator; + + /* If maxLevels is zero, we aren't checking levels */ + /* If currentLevel < maxLevels, look at this level */ + if ( (theGlobals->maxLevels == 0) || + (theGlobals->currentLevel < theGlobals->maxLevels) ) + { + /* Open FSIterator for flat access to theGlobals->ref */ + theGlobals->result = FSOpenIterator(&theGlobals->ref, kFSIterateFlat, &iterator); + require_noerr(theGlobals->result, FSOpenIterator); + + ++theGlobals->currentLevel; /* Go to next level */ + + /* Call FSGetCatalogInfoBulk in loop to get all items in the container */ + do + { + theGlobals->result = FSGetCatalogInfoBulk(iterator, 1, &theGlobals->actualObjects, + &theGlobals->containerChanged, theGlobals->whichInfo, &theGlobals->catalogInfo, + &theGlobals->ref, theGlobals->specPtr, theGlobals->namePtr); + if ( (noErr == theGlobals->result || errFSNoMoreItems == theGlobals->result) && + (0 != theGlobals->actualObjects) ) + { + /* Call the IterateFilterProc */ + theGlobals->quitFlag = CallIterateContainerFilterProc(theGlobals->iterateFilter, + theGlobals->containerChanged, theGlobals->currentLevel, + &theGlobals->catalogInfo, &theGlobals->ref, + theGlobals->specPtr, theGlobals->namePtr, theGlobals->yourDataPtr); + /* Is it a directory? */ + if ( 0 != (theGlobals->catalogInfo.nodeFlags & kFSNodeIsDirectoryMask) ) + { + /* Keep going? */ + if ( !theGlobals->quitFlag ) + { + /* Dive again if the IterateFilterProc didn't say "quit" */ + FSIterateContainerLevel(theGlobals); + } + } + } + /* time to fall back a level? */ + } while ( (noErr == theGlobals->result) && (!theGlobals->quitFlag) ); + + /* errFSNoMoreItems is OK - it only means we hit the end of this level */ + /* afpAccessDenied is OK, too - it only means we cannot see inside a directory */ + if ( (errFSNoMoreItems == theGlobals->result) || + (afpAccessDenied == theGlobals->result) ) + { + theGlobals->result = noErr; + } + + --theGlobals->currentLevel; /* Return to previous level as we leave */ + + /* Close the FSIterator (closing an open iterator should never fail) */ + verify_noerr(FSCloseIterator(iterator)); + } + +FSOpenIterator: + + return; +} + +/*****************************************************************************/ + +OSErr +FSIterateContainer( + const FSRef *container, + ItemCount maxLevels, + FSCatalogInfoBitmap whichInfo, + Boolean wantFSSpec, + Boolean wantName, + IterateContainerFilterProcPtr iterateFilter, + void *yourDataPtr) +{ + OSErr result; + FSIterateContainerGlobals theGlobals; + + /* make sure there is an iterateFilter */ + require_action(iterateFilter != NULL, NoIterateFilter, result = paramErr); + + /* + * set up the globals we need to access from the recursive routine + */ + theGlobals.iterateFilter = iterateFilter; + /* we need the node flags no matter what was requested so we can detect files vs. directories */ + theGlobals.whichInfo = whichInfo | kFSCatInfoNodeFlags; + /* start with input container -- the first OpenIterator will ensure it is a directory */ + theGlobals.ref = *container; + if ( wantFSSpec ) + { + theGlobals.specPtr = &theGlobals.spec; + } + else + { + theGlobals.specPtr = NULL; + } + if ( wantName ) + { + theGlobals.namePtr = &theGlobals.name; + } + else + { + theGlobals.namePtr = NULL; + } + theGlobals.yourDataPtr = yourDataPtr; + theGlobals.maxLevels = maxLevels; + theGlobals.currentLevel = 0; + theGlobals.quitFlag = false; + theGlobals.containerChanged = false; + theGlobals.result = noErr; + theGlobals.actualObjects = 0; + + /* here we go into recursion land... */ + FSIterateContainerLevel(&theGlobals); + result = theGlobals.result; + require_noerr(result, FSIterateContainerLevel); + +FSIterateContainerLevel: +NoIterateFilter: + + return ( result ); +} + +/*****************************************************************************/ + +OSErr +FSGetDirectoryItems( + const FSRef *container, + FSRef ***refsHandle, /* pointer to handle of FSRefs */ + ItemCount *numRefs, + Boolean *containerChanged) +{ + /* Grab items 10 at a time. */ + enum { kMaxItemsPerBulkCall = 10 }; + + OSErr result; + OSErr memResult; + FSIterator iterator; + FSRef refs[kMaxItemsPerBulkCall]; + ItemCount actualObjects; + Boolean changed; + + /* check parameters */ + require_action((NULL != refsHandle) && (NULL != numRefs) && (NULL != containerChanged), + BadParameter, result = paramErr); + + *numRefs = 0; + *containerChanged = false; + *refsHandle = (FSRef **)NewHandle(0); + require_action(NULL != *refsHandle, NewHandle, result = memFullErr); + + /* open an FSIterator */ + result = FSOpenIterator(container, kFSIterateFlat, &iterator); + require_noerr(result, FSOpenIterator); + + /* Call FSGetCatalogInfoBulk in loop to get all items in the container */ + do + { + result = FSGetCatalogInfoBulk(iterator, kMaxItemsPerBulkCall, &actualObjects, + &changed, kFSCatInfoNone, NULL, refs, NULL, NULL); + + /* if the container changed, set containerChanged for output, but keep going */ + if ( changed ) + { + *containerChanged = changed; + } + + /* any result other than noErr and errFSNoMoreItems is serious */ + require((noErr == result) || (errFSNoMoreItems == result), FSGetCatalogInfoBulk); + + /* add objects to output array and count */ + if ( 0 != actualObjects ) + { + /* concatenate the FSRefs to the end of the handle */ + PtrAndHand(refs, (Handle)*refsHandle, actualObjects * sizeof(FSRef)); + memResult = MemError(); + require_noerr_action(memResult, MemoryAllocationFailed, result = memResult); + + *numRefs += actualObjects; + } + } while ( noErr == result ); + + verify_noerr(FSCloseIterator(iterator)); /* closing an open iterator should never fail, but... */ + + return ( noErr ); + + /**********************/ + +MemoryAllocationFailed: +FSGetCatalogInfoBulk: + + /* close the iterator */ + verify_noerr(FSCloseIterator(iterator)); + +FSOpenIterator: + /* dispose of handle if already allocated and clear the outputs */ + if ( NULL != *refsHandle ) + { + DisposeHandle((Handle)*refsHandle); + *refsHandle = NULL; + } + *numRefs = 0; + +NewHandle: +BadParameter: + + return ( result ); +} + +/*****************************************************************************/ + +/* + The GenerateUniqueName function generates a HFSUniStr255 name that is + unique in both dir1 and dir2. + + startSeed --> A pointer to a long which is used to generate the + unique name. + <-- It is modified on output to a value which should + be used to generate the next unique name. + dir1 --> The first directory. + dir2 --> The second directory. + uniqueName <-- A pointer to a HFSUniStr255 where the unique name + is to be returned. +*/ + +static +OSErr +GenerateUniqueHFSUniStr( + long *startSeed, + const FSRef *dir1, + const FSRef *dir2, + HFSUniStr255 *uniqueName) +{ + OSErr result; + long i; + FSRefParam pb; + FSRef newRef; + unsigned char hexStr[17] = "0123456789ABCDEF"; + + /* set up the parameter block */ + pb.name = uniqueName->unicode; + pb.nameLength = 8; /* always 8 characters */ + pb.textEncodingHint = kTextEncodingUnknown; + pb.newRef = &newRef; + + /* loop until we get fnfErr with a filename in both directories */ + result = noErr; + while ( fnfErr != result ) + { + /* convert startSeed to 8 character Unicode string */ + uniqueName->length = 8; + for ( i = 0; i < 8; ++i ) + { + uniqueName->unicode[i] = hexStr[((*startSeed >> ((7-i)*4)) & 0xf)]; + } + + /* try in dir1 */ + pb.ref = dir1; + result = PBMakeFSRefUnicodeSync(&pb); + if ( fnfErr == result ) + { + /* try in dir2 */ + pb.ref = dir2; + result = PBMakeFSRefUnicodeSync(&pb); + if ( fnfErr != result ) + { + /* exit if anything other than noErr or fnfErr */ + require_noerr(result, Dir2PBMakeFSRefUnicodeSyncFailed); + } + } + else + { + /* exit if anything other than noErr or fnfErr */ + require_noerr(result, Dir1PBMakeFSRefUnicodeSyncFailed); + } + + /* increment seed for next pass through loop, */ + /* or for next call to GenerateUniqueHFSUniStr */ + ++(*startSeed); + } + + /* we have a unique file name which doesn't exist in dir1 or dir2 */ + result = noErr; + +Dir2PBMakeFSRefUnicodeSyncFailed: +Dir1PBMakeFSRefUnicodeSyncFailed: + + return ( result ); +} + +/*****************************************************************************/ + +OSErr +FSExchangeObjectsCompat( + const FSRef *sourceRef, + const FSRef *destRef, + FSRef *newSourceRef, + FSRef *newDestRef) +{ + enum + { + /* get all settable info except for mod dates, plus the volume refNum and parent directory ID */ + kGetCatInformationMask = (kFSCatInfoSettableInfo | + kFSCatInfoVolume | + kFSCatInfoParentDirID) & + ~(kFSCatInfoContentMod | kFSCatInfoAttrMod), + /* set everything possible except for mod dates */ + kSetCatinformationMask = kFSCatInfoSettableInfo & + ~(kFSCatInfoContentMod | kFSCatInfoAttrMod) + }; + + OSErr result; + GetVolParmsInfoBuffer volParmsInfo; + UInt32 infoSize; + FSCatalogInfo sourceCatalogInfo; /* source file's catalog information */ + FSCatalogInfo destCatalogInfo; /* destination file's catalog information */ + HFSUniStr255 sourceName; /* source file's Unicode name */ + HFSUniStr255 destName; /* destination file's Unicode name */ + FSRef sourceCurrentRef; /* FSRef to current location of source file throughout this function */ + FSRef destCurrentRef; /* FSRef to current location of destination file throughout this function */ + FSRef sourceParentRef; /* FSRef to parent directory of source file */ + FSRef destParentRef; /* FSRef to parent directory of destination file */ + HFSUniStr255 sourceUniqueName; /* unique name given to source file while exchanging it with destination */ + HFSUniStr255 destUniqueName; /* unique name given to destination file while exchanging it with source */ + long theSeed; /* the seed for generating unique names */ + Boolean sameParentDirs; /* true if source and destinatin parent directory is the same */ + + /* check parameters */ + require_action((NULL != newSourceRef) && (NULL != newDestRef), BadParameter, result = paramErr); + + /* output refs and current refs = input refs to start with */ + BlockMoveData(sourceRef, newSourceRef, sizeof(FSRef)); + BlockMoveData(sourceRef, &sourceCurrentRef, sizeof(FSRef)); + + BlockMoveData(destRef, newDestRef, sizeof(FSRef)); + BlockMoveData(destRef, &destCurrentRef, sizeof(FSRef)); + + /* get source volume's vRefNum */ + result = FSGetCatalogInfo(&sourceCurrentRef, kFSCatInfoVolume, &sourceCatalogInfo, NULL, NULL, NULL); + require_noerr(result, DetermineSourceVRefNumFailed); + + /* see if that volume supports FSExchangeObjects */ + result = FSGetVolParms(sourceCatalogInfo.volume, sizeof(GetVolParmsInfoBuffer), + &volParmsInfo, &infoSize); + if ( (noErr == result) && VolSupportsFSExchangeObjects(&volParmsInfo) ) + { + /* yes - use FSExchangeObjects */ + result = FSExchangeObjects(sourceRef, destRef); + } + else + { + /* no - emulate FSExchangeObjects */ + + /* Note: The compatibility case won't work for files with *Btree control blocks. */ + /* Right now the only *Btree files are created by the system. */ + + /* get all catalog information and Unicode names for each file */ + result = FSGetCatalogInfo(&sourceCurrentRef, kGetCatInformationMask, &sourceCatalogInfo, &sourceName, NULL, &sourceParentRef); + require_noerr(result, SourceFSGetCatalogInfoFailed); + + result = FSGetCatalogInfo(&destCurrentRef, kGetCatInformationMask, &destCatalogInfo, &destName, NULL, &destParentRef); + require_noerr(result, DestFSGetCatalogInfoFailed); + + /* make sure source and destination are on same volume */ + require_action(sourceCatalogInfo.volume == destCatalogInfo.volume, NotSameVolume, result = diffVolErr); + + /* make sure both files are *really* files */ + require_action((0 == (sourceCatalogInfo.nodeFlags & kFSNodeIsDirectoryMask)) && + (0 == (destCatalogInfo.nodeFlags & kFSNodeIsDirectoryMask)), NotAFile, result = notAFileErr); + + /* generate 2 names that are unique in both directories */ + theSeed = 0x4a696d4c; /* a fine unlikely filename */ + + result = GenerateUniqueHFSUniStr(&theSeed, &sourceParentRef, &destParentRef, &sourceUniqueName); + require_noerr(result, GenerateUniqueHFSUniStr1Failed); + + result = GenerateUniqueHFSUniStr(&theSeed, &sourceParentRef, &destParentRef, &destUniqueName); + require_noerr(result, GenerateUniqueHFSUniStr2Failed); + + /* rename sourceCurrentRef to sourceUniqueName */ + result = FSRenameUnicode(&sourceCurrentRef, sourceUniqueName.length, sourceUniqueName.unicode, kTextEncodingUnknown, newSourceRef); + require_noerr(result, FSRenameUnicode1Failed); + BlockMoveData(newSourceRef, &sourceCurrentRef, sizeof(FSRef)); + + /* rename destCurrentRef to destUniqueName */ + result = FSRenameUnicode(&destCurrentRef, destUniqueName.length, destUniqueName.unicode, kTextEncodingUnknown, newDestRef); + require_noerr(result, FSRenameUnicode2Failed); + BlockMoveData(newDestRef, &destCurrentRef, sizeof(FSRef)); + + /* are the source and destination parent directories the same? */ + sameParentDirs = ( sourceCatalogInfo.parentDirID == destCatalogInfo.parentDirID ); + if ( !sameParentDirs ) + { + /* move source file to dest parent directory */ + result = FSMoveObject(&sourceCurrentRef, &destParentRef, newSourceRef); + require_noerr(result, FSMoveObject1Failed); + BlockMoveData(newSourceRef, &sourceCurrentRef, sizeof(FSRef)); + + /* move dest file to source parent directory */ + result = FSMoveObject(&destCurrentRef, &sourceParentRef, newDestRef); + require_noerr(result, FSMoveObject2Failed); + BlockMoveData(newDestRef, &destCurrentRef, sizeof(FSRef)); + } + + /* At this point, the files are in their new locations (if they were moved). */ + /* The source file is named sourceUniqueName and is in the directory referred to */ + /* by destParentRef. The destination file is named destUniqueName and is in the */ + /* directory referred to by sourceParentRef. */ + + /* give source file the dest file's catalog information except for mod dates */ + result = FSSetCatalogInfo(&sourceCurrentRef, kSetCatinformationMask, &destCatalogInfo); + require_noerr(result, FSSetCatalogInfo1Failed); + + /* give dest file the source file's catalog information except for mod dates */ + result = FSSetCatalogInfo(&destCurrentRef, kSetCatinformationMask, &sourceCatalogInfo); + require_noerr(result, FSSetCatalogInfo2Failed); + + /* rename source file with dest file's name */ + result = FSRenameUnicode(&sourceCurrentRef, destName.length, destName.unicode, destCatalogInfo.textEncodingHint, newSourceRef); + require_noerr(result, FSRenameUnicode3Failed); + BlockMoveData(newSourceRef, &sourceCurrentRef, sizeof(FSRef)); + + /* rename dest file with source file's name */ + result = FSRenameUnicode(&destCurrentRef, sourceName.length, sourceName.unicode, sourceCatalogInfo.textEncodingHint, newDestRef); + require_noerr(result, FSRenameUnicode4Failed); + + /* we're done with no errors, so swap newSourceRef and newDestRef */ + BlockMoveData(newDestRef, newSourceRef, sizeof(FSRef)); + BlockMoveData(&sourceCurrentRef, newDestRef, sizeof(FSRef)); + } + + return ( result ); + + /**********************/ + +/* If there are any failures while emulating FSExchangeObjects, attempt to reverse any steps */ +/* already taken. In any case, newSourceRef and newDestRef will refer to the files in whatever */ +/* state and location they ended up in so that both files can be found by the calling code. */ + +FSRenameUnicode4Failed: + + /* attempt to rename source file to sourceUniqueName */ + if ( noErr == FSRenameUnicode(&sourceCurrentRef, sourceUniqueName.length, sourceUniqueName.unicode, kTextEncodingUnknown, newSourceRef) ) + { + BlockMoveData(newSourceRef, &sourceCurrentRef, sizeof(FSRef)); + } + +FSRenameUnicode3Failed: + + /* attempt to restore dest file's catalog information */ + verify_noerr(FSSetCatalogInfo(&destCurrentRef, kFSCatInfoSettableInfo, &destCatalogInfo)); + +FSSetCatalogInfo2Failed: + + /* attempt to restore source file's catalog information */ + verify_noerr(FSSetCatalogInfo(&sourceCurrentRef, kFSCatInfoSettableInfo, &sourceCatalogInfo)); + +FSSetCatalogInfo1Failed: + + if ( !sameParentDirs ) + { + /* attempt to move dest file back to dest directory */ + if ( noErr == FSMoveObject(&destCurrentRef, &destParentRef, newDestRef) ) + { + BlockMoveData(newDestRef, &destCurrentRef, sizeof(FSRef)); + } + } + +FSMoveObject2Failed: + + if ( !sameParentDirs ) + { + /* attempt to move source file back to source directory */ + if ( noErr == FSMoveObject(&sourceCurrentRef, &sourceParentRef, newSourceRef) ) + { + BlockMoveData(newSourceRef, &sourceCurrentRef, sizeof(FSRef)); + } + } + +FSMoveObject1Failed: + + /* attempt to rename dest file to original name */ + verify_noerr(FSRenameUnicode(&destCurrentRef, destName.length, destName.unicode, destCatalogInfo.textEncodingHint, newDestRef)); + +FSRenameUnicode2Failed: + + /* attempt to rename source file to original name */ + verify_noerr(FSRenameUnicode(&sourceCurrentRef, sourceName.length, sourceName.unicode, sourceCatalogInfo.textEncodingHint, newSourceRef)); + +FSRenameUnicode1Failed: +GenerateUniqueHFSUniStr2Failed: +GenerateUniqueHFSUniStr1Failed: +NotAFile: +NotSameVolume: +DestFSGetCatalogInfoFailed: +SourceFSGetCatalogInfoFailed: +DetermineSourceVRefNumFailed: +BadParameter: + + return ( result ); +} + +/*****************************************************************************/ + +#pragma mark ----- Shared Environment Routines ----- + +/*****************************************************************************/ + +/* Renamed from FSLockRange to MFX_FSLockRange to avoid a conflict with + * the FSLockRange function present in the system library since Mac OS X + * 10.4. */ + +OSErr +MFX_FSLockRange( + SInt16 refNum, + SInt32 rangeLength, + SInt32 rangeStart) +{ + OSErr result; + ParamBlockRec pb; + + pb.ioParam.ioRefNum = refNum; + pb.ioParam.ioReqCount = rangeLength; + pb.ioParam.ioPosMode = fsFromStart; + pb.ioParam.ioPosOffset = rangeStart; + result = PBLockRangeSync(&pb); + require_noerr(result, PBLockRangeSync); + +PBLockRangeSync: + + return ( result ); +} + +/*****************************************************************************/ + +/* Renamed from FSUnlockRange to MFX_FSUnlockRange to avoid a conflict with + * the FSUnlockRange function present in the system library since Mac OS X + * 10.4. */ + +OSErr +MFX_FSUnlockRange( + SInt16 refNum, + SInt32 rangeLength, + SInt32 rangeStart) +{ + OSErr result; + ParamBlockRec pb; + + pb.ioParam.ioRefNum = refNum; + pb.ioParam.ioReqCount = rangeLength; + pb.ioParam.ioPosMode = fsFromStart; + pb.ioParam.ioPosOffset = rangeStart; + result = PBUnlockRangeSync(&pb); + require_noerr(result, PBUnlockRangeSync); + +PBUnlockRangeSync: + + return ( result ); +} + +/*****************************************************************************/ + +OSErr +FSGetDirAccess( + const FSRef *ref, + SInt32 *ownerID, /* can be NULL */ + SInt32 *groupID, /* can be NULL */ + SInt32 *accessRights) /* can be NULL */ +{ + OSErr result; + FSSpec spec; + HParamBlockRec pb; + + /* get FSSpec from FSRef */ + result = FSGetCatalogInfo(ref, kFSCatInfoNone, NULL, NULL, &spec, NULL); + require_noerr(result, FSGetCatalogInfo); + + /* get directory access info for FSSpec */ + pb.accessParam.ioNamePtr = (StringPtr)spec.name; + pb.accessParam.ioVRefNum = spec.vRefNum; + pb.fileParam.ioDirID = spec.parID; + result = PBHGetDirAccessSync(&pb); + require_noerr(result, PBHGetDirAccessSync); + + /* return the IDs and access rights */ + if ( NULL != ownerID ) + { + *ownerID = pb.accessParam.ioACOwnerID; + } + if ( NULL != groupID ) + { + *groupID = pb.accessParam.ioACGroupID; + } + if ( NULL != accessRights ) + { + *accessRights = pb.accessParam.ioACAccess; + } + +PBHGetDirAccessSync: +FSGetCatalogInfo: + + return ( result ); +} + +/*****************************************************************************/ + +OSErr +FSSetDirAccess( + const FSRef *ref, + SInt32 ownerID, + SInt32 groupID, + SInt32 accessRights) +{ + OSErr result; + FSSpec spec; + HParamBlockRec pb; + + enum + { + /* Just the bits that can be set */ + kSetDirAccessSettableMask = (kioACAccessBlankAccessMask + + kioACAccessEveryoneWriteMask + kioACAccessEveryoneReadMask + kioACAccessEveryoneSearchMask + + kioACAccessGroupWriteMask + kioACAccessGroupReadMask + kioACAccessGroupSearchMask + + kioACAccessOwnerWriteMask + kioACAccessOwnerReadMask + kioACAccessOwnerSearchMask) + }; + + /* get FSSpec from FSRef */ + result = FSGetCatalogInfo(ref, kFSCatInfoNone, NULL, NULL, &spec, NULL); + require_noerr(result, FSGetCatalogInfo); + + /* set directory access info for FSSpec */ + pb.accessParam.ioNamePtr = (StringPtr)spec.name; + pb.accessParam.ioVRefNum = spec.vRefNum; + pb.fileParam.ioDirID = spec.parID; + pb.accessParam.ioACOwnerID = ownerID; + pb.accessParam.ioACGroupID = groupID; + pb.accessParam.ioACAccess = accessRights & kSetDirAccessSettableMask; + result = PBHSetDirAccessSync(&pb); + require_noerr(result, PBHSetDirAccessSync); + +PBHSetDirAccessSync: +FSGetCatalogInfo: + + return ( result ); +} + +/*****************************************************************************/ + +OSErr +FSGetVolMountInfoSize( + FSVolumeRefNum volRefNum, + SInt16 *size) +{ + OSErr result; + ParamBlockRec pb; + + /* check parameters */ + require_action(NULL != size, BadParameter, result = paramErr); + + pb.ioParam.ioNamePtr = NULL; + pb.ioParam.ioVRefNum = volRefNum; + pb.ioParam.ioBuffer = (Ptr)size; + result = PBGetVolMountInfoSize(&pb); + require_noerr(result, PBGetVolMountInfoSize); + +PBGetVolMountInfoSize: +BadParameter: + + return ( result ); +} + +/*****************************************************************************/ + +OSErr +FSGetVolMountInfo( + FSVolumeRefNum volRefNum, + void *volMountInfo) +{ + OSErr result; + ParamBlockRec pb; + + /* check parameters */ + require_action(NULL != volMountInfo, BadParameter, result = paramErr); + + pb.ioParam.ioNamePtr = NULL; + pb.ioParam.ioVRefNum = volRefNum; + pb.ioParam.ioBuffer = (Ptr)volMountInfo; + result = PBGetVolMountInfo(&pb); + require_noerr(result, PBGetVolMountInfo); + +PBGetVolMountInfo: +BadParameter: + + return ( result ); +} + +/*****************************************************************************/ + +// This function exists in Mac OS X 10.5, we cannot re-define it here. +// We don't use this function, so just don't compile it. +#if 0 +OSErr +FSVolumeMount( + const void *volMountInfo, + FSVolumeRefNum *volRefNum) +{ + OSErr result; + ParamBlockRec pb; + + /* check parameters */ + require_action(NULL != volRefNum, BadParameter, result = paramErr); + + pb.ioParam.ioBuffer = (Ptr)volMountInfo; + result = PBVolumeMount(&pb); + require_noerr(result, PBVolumeMount); + + /* return the volume reference number */ + *volRefNum = pb.ioParam.ioVRefNum; + +PBVolumeMount: +BadParameter: + + return ( result ); +} +#endif + +/*****************************************************************************/ + +OSErr +FSMapID( + FSVolumeRefNum volRefNum, + SInt32 ugID, + SInt16 objType, + Str31 name) +{ + OSErr result; + HParamBlockRec pb; + + /* check parameters */ + require_action(NULL != name, BadParameter, result = paramErr); + + pb.objParam.ioNamePtr = NULL; + pb.objParam.ioVRefNum = volRefNum; + pb.objParam.ioObjType = objType; + pb.objParam.ioObjNamePtr = name; + pb.objParam.ioObjID = ugID; + result = PBHMapIDSync(&pb); + require_noerr(result, PBHMapIDSync); + +PBHMapIDSync: +BadParameter: + + return ( result ); +} + +/*****************************************************************************/ + +OSErr +FSMapName( + FSVolumeRefNum volRefNum, + ConstStr255Param name, + SInt16 objType, + SInt32 *ugID) +{ + OSErr result; + HParamBlockRec pb; + + /* check parameters */ + require_action(NULL != ugID, BadParameter, result = paramErr); + + pb.objParam.ioNamePtr = NULL; + pb.objParam.ioVRefNum = volRefNum; + pb.objParam.ioObjType = objType; + pb.objParam.ioObjNamePtr = (StringPtr)name; + result = PBHMapNameSync(&pb); + require_noerr(result, PBHMapNameSync); + + /* return the user or group ID */ + *ugID = pb.objParam.ioObjID; + +PBHMapNameSync: +BadParameter: + + return ( result ); +} + +/*****************************************************************************/ + +OSErr +FSCopyFile( + const FSRef *srcFileRef, + const FSRef *dstDirectoryRef, + UniCharCount nameLength, + const UniChar *copyName, /* can be NULL (no rename during copy) */ + TextEncoding textEncodingHint, + FSRef *newRef) /* can be NULL */ +{ + OSErr result; + FSSpec srcFileSpec; + FSCatalogInfo catalogInfo; + HParamBlockRec pb; + Str31 hfsName; + GetVolParmsInfoBuffer volParmsInfo; + UInt32 infoSize; + + /* get source FSSpec from source FSRef */ + result = FSGetCatalogInfo(srcFileRef, kFSCatInfoNone, NULL, NULL, &srcFileSpec, NULL); + require_noerr(result, FSGetCatalogInfo_srcFileRef); + + /* Make sure the volume supports CopyFile */ + result = FSGetVolParms(srcFileSpec.vRefNum, sizeof(GetVolParmsInfoBuffer), + &volParmsInfo, &infoSize); + require_action((noErr == result) && VolHasCopyFile(&volParmsInfo), + NoCopyFileSupport, result = paramErr); + + /* get destination volume reference number and destination directory ID from destination FSRef */ + result = FSGetCatalogInfo(dstDirectoryRef, kFSCatInfoVolume + kFSCatInfoNodeID, + &catalogInfo, NULL, NULL, NULL); + require_noerr(result, FSGetCatalogInfo_dstDirectoryRef); + + /* tell the server to copy the object */ + pb.copyParam.ioVRefNum = srcFileSpec.vRefNum; + pb.copyParam.ioDirID = srcFileSpec.parID; + pb.copyParam.ioNamePtr = (StringPtr)srcFileSpec.name; + pb.copyParam.ioDstVRefNum = catalogInfo.volume; + pb.copyParam.ioNewDirID = (long)catalogInfo.nodeID; + pb.copyParam.ioNewName = NULL; + if ( NULL != copyName ) + { + result = UnicodeNameGetHFSName(nameLength, copyName, textEncodingHint, false, hfsName); + require_noerr(result, UnicodeNameGetHFSName); + + pb.copyParam.ioCopyName = hfsName; + } + else + { + pb.copyParam.ioCopyName = NULL; + } + result = PBHCopyFileSync(&pb); + require_noerr(result, PBHCopyFileSync); + + if ( NULL != newRef ) + { + verify_noerr(FSMakeFSRef(pb.copyParam.ioDstVRefNum, pb.copyParam.ioNewDirID, + pb.copyParam.ioCopyName, newRef)); + } + +PBHCopyFileSync: +UnicodeNameGetHFSName: +FSGetCatalogInfo_dstDirectoryRef: +NoCopyFileSupport: +FSGetCatalogInfo_srcFileRef: + + return ( result ); +} + +/*****************************************************************************/ + +OSErr +FSMoveRename( + const FSRef *srcFileRef, + const FSRef *dstDirectoryRef, + UniCharCount nameLength, + const UniChar *moveName, /* can be NULL (no rename during move) */ + TextEncoding textEncodingHint, + FSRef *newRef) /* can be NULL */ +{ + OSErr result; + FSSpec srcFileSpec; + FSCatalogInfo catalogInfo; + HParamBlockRec pb; + Str31 hfsName; + GetVolParmsInfoBuffer volParmsInfo; + UInt32 infoSize; + + /* get source FSSpec from source FSRef */ + result = FSGetCatalogInfo(srcFileRef, kFSCatInfoNone, NULL, NULL, &srcFileSpec, NULL); + require_noerr(result, FSGetCatalogInfo_srcFileRef); + + /* Make sure the volume supports MoveRename */ + result = FSGetVolParms(srcFileSpec.vRefNum, sizeof(GetVolParmsInfoBuffer), + &volParmsInfo, &infoSize); + require_action((noErr == result) && VolHasMoveRename(&volParmsInfo), + NoMoveRenameSupport, result = paramErr); + + /* get destination volume reference number and destination directory ID from destination FSRef */ + result = FSGetCatalogInfo(dstDirectoryRef, kFSCatInfoVolume + kFSCatInfoNodeID, + &catalogInfo, NULL, NULL, NULL); + require_noerr(result, FSGetCatalogInfo_dstDirectoryRef); + + /* make sure the source and destination are on the same volume */ + require_action(srcFileSpec.vRefNum == catalogInfo.volume, NotSameVolume, result = diffVolErr); + + /* tell the server to move and rename the object */ + pb.copyParam.ioVRefNum = srcFileSpec.vRefNum; + pb.copyParam.ioDirID = srcFileSpec.parID; + pb.copyParam.ioNamePtr = (StringPtr)srcFileSpec.name; + pb.copyParam.ioNewDirID = (long)catalogInfo.nodeID; + pb.copyParam.ioNewName = NULL; + if ( NULL != moveName ) + { + result = UnicodeNameGetHFSName(nameLength, moveName, textEncodingHint, false, hfsName); + require_noerr(result, UnicodeNameGetHFSName); + + pb.copyParam.ioCopyName = hfsName; + } + else + { + pb.copyParam.ioCopyName = NULL; + } + result = PBHMoveRenameSync(&pb); + require_noerr(result, PBHMoveRenameSync); + + if ( NULL != newRef ) + { + verify_noerr(FSMakeFSRef(pb.copyParam.ioVRefNum, pb.copyParam.ioNewDirID, + pb.copyParam.ioCopyName, newRef)); + } + +PBHMoveRenameSync: +UnicodeNameGetHFSName: +NotSameVolume: +FSGetCatalogInfo_dstDirectoryRef: +NoMoveRenameSupport: +FSGetCatalogInfo_srcFileRef: + + return ( result ); +} + +/*****************************************************************************/ + +#pragma mark ----- File ID Routines ----- + +/*****************************************************************************/ + +OSErr +FSResolveFileIDRef( + FSVolumeRefNum volRefNum, + SInt32 fileID, + FSRef *ref) +{ + OSErr result; + FIDParam pb; + Str255 tempStr; + + /* check parameters */ + require_action(NULL != ref, BadParameter, result = paramErr); + + /* resolve the file ID reference */ + tempStr[0] = 0; + pb.ioNamePtr = tempStr; + pb.ioVRefNum = volRefNum; + pb.ioFileID = fileID; + result = PBResolveFileIDRefSync((HParmBlkPtr)&pb); + require_noerr(result, PBResolveFileIDRefSync); + + /* and then make an FSRef to the file */ + result = FSMakeFSRef(volRefNum, pb.ioSrcDirID, tempStr, ref); + require_noerr(result, FSMakeFSRef); + +FSMakeFSRef: +PBResolveFileIDRefSync: +BadParameter: + + return ( result ); +} + +/*****************************************************************************/ + +OSErr +FSCreateFileIDRef( + const FSRef *ref, + SInt32 *fileID) +{ + OSErr result; + FSSpec spec; + FIDParam pb; + + /* check parameters */ + require_action(NULL != fileID, BadParameter, result = paramErr); + + /* Get an FSSpec from the FSRef */ + result = FSGetCatalogInfo(ref, kFSCatInfoNone, NULL, NULL, &spec, NULL); + require_noerr(result, FSGetCatalogInfo); + + /* Create (or get) the file ID reference using the FSSpec */ + pb.ioNamePtr = (StringPtr)spec.name; + pb.ioVRefNum = spec.vRefNum; + pb.ioSrcDirID = spec.parID; + result = PBCreateFileIDRefSync((HParmBlkPtr)&pb); + require((noErr == result) || (fidExists == result) || (afpIDExists == result), + PBCreateFileIDRefSync); + + /* return the file ID reference */ + *fileID = pb.ioFileID; + +PBCreateFileIDRefSync: +FSGetCatalogInfo: +BadParameter: + + return ( result ); +} + +/*****************************************************************************/ + +#pragma mark ----- Utility Routines ----- + +/*****************************************************************************/ + +Ptr +GetTempBuffer( + ByteCount buffReqSize, + ByteCount *buffActSize) +{ + enum + { + kSlopMemory = 0x00008000 /* 32K - Amount of free memory to leave when allocating buffers */ + }; + + Ptr tempPtr; + + /* check parameters */ + require_action(NULL != buffActSize, BadParameter, tempPtr = NULL); + + /* Make request a multiple of 4K bytes */ + buffReqSize = buffReqSize & 0xfffff000; + + if ( buffReqSize < 0x00001000 ) + { + /* Request was smaller than 4K bytes - make it 4K */ + buffReqSize = 0x00001000; + } + + /* Attempt to allocate the memory */ + tempPtr = NewPtr(buffReqSize); + + /* If request failed, go to backup plan */ + if ( (tempPtr == NULL) && (buffReqSize > 0x00001000) ) + { + /* + ** Try to get largest 4K byte block available + ** leaving some slop for the toolbox if possible + */ + long freeMemory = (FreeMem() - kSlopMemory) & 0xfffff000; + + buffReqSize = MaxBlock() & 0xfffff000; + + if ( buffReqSize > freeMemory ) + { + buffReqSize = freeMemory; + } + + if ( buffReqSize == 0 ) + { + buffReqSize = 0x00001000; + } + + tempPtr = NewPtr(buffReqSize); + } + + /* Return bytes allocated */ + if ( tempPtr != NULL ) + { + *buffActSize = buffReqSize; + } + else + { + *buffActSize = 0; + } + +BadParameter: + + return ( tempPtr ); +} + +/*****************************************************************************/ + +OSErr +FileRefNumGetFSRef( + short refNum, + FSRef *ref) +{ + return ( FSGetForkCBInfo(refNum, 0, NULL, NULL, NULL, ref, NULL) ); +} + +/*****************************************************************************/ + +OSErr +FSSetDefault( + const FSRef *newDefault, + FSRef *oldDefault) +{ + OSErr result; + FSVolumeRefNum vRefNum; + long dirID; + FSCatalogInfo catalogInfo; + + /* check parameters */ + require_action((NULL != newDefault) && (NULL != oldDefault), BadParameter, result = paramErr); + + /* Get nodeFlags, vRefNum and dirID (nodeID) of newDefault */ + result = FSGetCatalogInfo(newDefault, + kFSCatInfoNodeFlags + kFSCatInfoVolume + kFSCatInfoNodeID, + &catalogInfo, NULL, NULL, NULL); + require_noerr(result, FSGetCatalogInfo); + + /* Make sure newDefault is a directory */ + require_action(0 != (kFSNodeIsDirectoryMask & catalogInfo.nodeFlags), NewDefaultNotDirectory, + result = dirNFErr); + + /* Get the current working directory. */ + result = HGetVol(NULL, &vRefNum, &dirID); + require_noerr(result, HGetVol); + + /* Return the oldDefault FSRef */ + result = FSMakeFSRef(vRefNum, dirID, NULL, oldDefault); + require_noerr(result, FSMakeFSRef); + + /* Set the new current working directory */ + result = HSetVol(NULL, catalogInfo.volume, catalogInfo.nodeID); + require_noerr(result, HSetVol); + +HSetVol: +FSMakeFSRef: +HGetVol: +NewDefaultNotDirectory: +FSGetCatalogInfo: +BadParameter: + + return ( result ); +} + +/*****************************************************************************/ + +OSErr +FSRestoreDefault( + const FSRef *oldDefault) +{ + OSErr result; + FSCatalogInfo catalogInfo; + + /* check parameters */ + require_action(NULL != oldDefault, BadParameter, result = paramErr); + + /* Get nodeFlags, vRefNum and dirID (nodeID) of oldDefault */ + result = FSGetCatalogInfo(oldDefault, + kFSCatInfoNodeFlags + kFSCatInfoVolume + kFSCatInfoNodeID, + &catalogInfo, NULL, NULL, NULL); + require_noerr(result, FSGetCatalogInfo); + + /* Make sure oldDefault is a directory */ + require_action(0 != (kFSNodeIsDirectoryMask & catalogInfo.nodeFlags), OldDefaultNotDirectory, + result = dirNFErr); + + /* Set the current working directory to oldDefault */ + result = HSetVol(NULL, catalogInfo.volume, catalogInfo.nodeID); + require_noerr(result, HSetVol); + +HSetVol: +OldDefaultNotDirectory: +FSGetCatalogInfo: +BadParameter: + + return ( result ); +} + +/*****************************************************************************/ diff --git a/src/libs/xpcom18a4/xpcom/MoreFiles/MoreFilesX.h b/src/libs/xpcom18a4/xpcom/MoreFiles/MoreFilesX.h new file mode 100644 index 00000000..378e4552 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/MoreFiles/MoreFilesX.h @@ -0,0 +1,1800 @@ +/* + File: MoreFilesX.h + + Contains: A collection of useful high-level File Manager routines + which use the HFS Plus APIs wherever possible. + + Version: MoreFilesX 1.0.1 + + +*/ + +/* ***** 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 Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + + +// Modified 2006-01-23 - added this comment. + +#ifndef __MOREFILESX__ +#define __MOREFILESX__ + +#ifndef __CARBON__ + #if defined(__MACH__) + #include + #else + #include + #endif +#endif + +#if PRAGMA_ONCE +#pragma once +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#if PRAGMA_IMPORT +#pragma import on +#endif + +#if PRAGMA_STRUCT_ALIGN + #pragma options align=mac68k +#elif PRAGMA_STRUCT_PACKPUSH + #pragma pack(push, 2) +#elif PRAGMA_STRUCT_PACK + #pragma pack(2) +#endif + +/*****************************************************************************/ + +#pragma mark ----- FinderInfo and ExtendedFinderInfo ----- + +/* + * FSGetFinderInfo and FSSetFinderInfo use these unions for Finder information. + */ + +union FinderInfo +{ + FileInfo file; + FolderInfo folder; +}; +typedef union FinderInfo FinderInfo; + +union ExtendedFinderInfo +{ + ExtendedFileInfo file; + ExtendedFolderInfo folder; +}; +typedef union ExtendedFinderInfo ExtendedFinderInfo; + +/*****************************************************************************/ + +#pragma mark ----- GetVolParmsInfoBuffer Macros ----- + +/* + * Macros to get information out of GetVolParmsInfoBuffer. + */ + +/* version 1 field getters */ +#define GetVolParmsInfoVersion(volParms) \ + ((volParms)->vMVersion) +#define GetVolParmsInfoAttrib(volParms) \ + ((volParms)->vMAttrib) +#define GetVolParmsInfoLocalHand(volParms) \ + ((volParms)->vMLocalHand) +#define GetVolParmsInfoServerAdr(volParms) \ + ((volParms)->vMServerAdr) + +/* version 2 field getters (assume zero result if version < 2) */ +#define GetVolParmsInfoVolumeGrade(volParms) \ + (((volParms)->vMVersion >= 2) ? (volParms)->vMVolumeGrade : 0) +#define GetVolParmsInfoForeignPrivID(volParms) \ + (((volParms)->vMVersion >= 2) ? (volParms)->vMForeignPrivID : 0) + +/* version 3 field getters (assume zero result if version < 3) */ +#define GetVolParmsInfoExtendedAttributes(volParms) \ + (((volParms)->vMVersion >= 3) ? (volParms)->vMExtendedAttributes : 0) + +/* attribute bits supported by all versions of GetVolParmsInfoBuffer */ +#define VolIsNetworkVolume(volParms) \ + ((volParms)->vMServerAdr != 0) +#define VolHasLimitFCBs(volParms) \ + (((volParms)->vMAttrib & (1L << bLimitFCBs)) != 0) +#define VolHasLocalWList(volParms) \ + (((volParms)->vMAttrib & (1L << bLocalWList)) != 0) +#define VolHasNoMiniFndr(volParms) \ + (((volParms)->vMAttrib & (1L << bNoMiniFndr)) != 0) +#define VolHasNoVNEdit(volParms) \ + (((volParms)->vMAttrib & (1L << bNoVNEdit)) != 0) +#define VolHasNoLclSync(volParms) \ + (((volParms)->vMAttrib & (1L << bNoLclSync)) != 0) +#define VolHasTrshOffLine(volParms) \ + (((volParms)->vMAttrib & (1L << bTrshOffLine)) != 0) +#define VolHasNoSwitchTo(volParms) \ + (((volParms)->vMAttrib & (1L << bNoSwitchTo)) != 0) +#define VolHasNoDeskItems(volParms) \ + (((volParms)->vMAttrib & (1L << bNoDeskItems)) != 0) +#define VolHasNoBootBlks(volParms) \ + (((volParms)->vMAttrib & (1L << bNoBootBlks)) != 0) +#define VolHasAccessCntl(volParms) \ + (((volParms)->vMAttrib & (1L << bAccessCntl)) != 0) +#define VolHasNoSysDir(volParms) \ + (((volParms)->vMAttrib & (1L << bNoSysDir)) != 0) +#define VolHasExtFSVol(volParms) \ + (((volParms)->vMAttrib & (1L << bHasExtFSVol)) != 0) +#define VolHasOpenDeny(volParms) \ + (((volParms)->vMAttrib & (1L << bHasOpenDeny)) != 0) +#define VolHasCopyFile(volParms) \ + (((volParms)->vMAttrib & (1L << bHasCopyFile)) != 0) +#define VolHasMoveRename(volParms) \ + (((volParms)->vMAttrib & (1L << bHasMoveRename)) != 0) +#define VolHasDesktopMgr(volParms) \ + (((volParms)->vMAttrib & (1L << bHasDesktopMgr)) != 0) +#define VolHasShortName(volParms) \ + (((volParms)->vMAttrib & (1L << bHasShortName)) != 0) +#define VolHasFolderLock(volParms) \ + (((volParms)->vMAttrib & (1L << bHasFolderLock)) != 0) +#define VolHasPersonalAccessPrivileges(volParms) \ + (((volParms)->vMAttrib & (1L << bHasPersonalAccessPrivileges)) != 0) +#define VolHasUserGroupList(volParms) \ + (((volParms)->vMAttrib & (1L << bHasUserGroupList)) != 0) +#define VolHasCatSearch(volParms) \ + (((volParms)->vMAttrib & (1L << bHasCatSearch)) != 0) +#define VolHasFileIDs(volParms) \ + (((volParms)->vMAttrib & (1L << bHasFileIDs)) != 0) +#define VolHasBTreeMgr(volParms) \ + (((volParms)->vMAttrib & (1L << bHasBTreeMgr)) != 0) +#define VolHasBlankAccessPrivileges(volParms) \ + (((volParms)->vMAttrib & (1L << bHasBlankAccessPrivileges)) != 0) +#define VolSupportsAsyncRequests(volParms) \ + (((volParms)->vMAttrib & (1L << bSupportsAsyncRequests)) != 0) +#define VolSupportsTrashVolumeCache(volParms) \ + (((volParms)->vMAttrib & (1L << bSupportsTrashVolumeCache)) != 0) + +/* attribute bits supported by version 3 and greater versions of GetVolParmsInfoBuffer */ +#define VolIsEjectable(volParms) \ + ((GetVolParmsInfoExtendedAttributes(volParms) & (1L << bIsEjectable)) != 0) +#define VolSupportsHFSPlusAPIs(volParms) \ + ((GetVolParmsInfoExtendedAttributes(volParms) & (1L << bSupportsHFSPlusAPIs)) != 0) +#define VolSupportsFSCatalogSearch(volParms) \ + ((GetVolParmsInfoExtendedAttributes(volParms) & (1L << bSupportsFSCatalogSearch)) != 0) +#define VolSupportsFSExchangeObjects(volParms) \ + ((GetVolParmsInfoExtendedAttributes(volParms) & (1L << bSupportsFSExchangeObjects)) != 0) +#define VolSupports2TBFiles(volParms) \ + ((GetVolParmsInfoExtendedAttributes(volParms) & (1L << bSupports2TBFiles)) != 0) +#define VolSupportsLongNames(volParms) \ + ((GetVolParmsInfoExtendedAttributes(volParms) & (1L << bSupportsLongNames)) != 0) +#define VolSupportsMultiScriptNames(volParms) \ + ((GetVolParmsInfoExtendedAttributes(volParms) & (1L << bSupportsMultiScriptNames)) != 0) +#define VolSupportsNamedForks(volParms) \ + ((GetVolParmsInfoExtendedAttributes(volParms) & (1L << bSupportsNamedForks)) != 0) +#define VolSupportsSubtreeIterators(volParms) \ + ((GetVolParmsInfoExtendedAttributes(volParms) & (1L << bSupportsSubtreeIterators)) != 0) +#define VolL2PCanMapFileBlocks(volParms) \ + ((GetVolParmsInfoExtendedAttributes(volParms) & (1L << bL2PCanMapFileBlocks)) != 0) +#define VolParentModDateChanges(volParms) \ + ((GetVolParmsInfoExtendedAttributes(volParms) & (1L << bParentModDateChanges)) != 0) +#define VolAncestorModDateChanges(volParms) \ + ((GetVolParmsInfoExtendedAttributes(volParms) & (1L << bAncestorModDateChanges)) != 0) +#define VolSupportsSymbolicLinks(volParms) \ + ((GetVolParmsInfoExtendedAttributes(volParms) & (1L << bSupportsSymbolicLinks)) != 0) +#define VolIsAutoMounted(volParms) \ + ((GetVolParmsInfoExtendedAttributes(volParms) & (1L << bIsAutoMounted)) != 0) + +/*****************************************************************************/ + +#pragma mark ----- userPrivileges Bit Masks and Macros ----- + +/* + * Bit masks and macros to get common information out of userPrivileges byte + * returned by FSGetCatalogInfo. + * + * Note: The userPrivileges byte is the same as the ioACUser byte returned + * by PBGetCatInfo, and is the 1's complement of the user's privileges + * byte returned in ioACAccess by PBHGetDirAccess. That's where the + * ioACUser names came from. + * + * The userPrivileges are user's effective privileges based on the + * user ID and the groups that user belongs to, and the owner, group, + * and everyone privileges for the given directory. + */ + +enum +{ + /* mask for just the access restriction bits */ + kioACUserAccessMask = (kioACUserNoSeeFolderMask + + kioACUserNoSeeFilesMask + + kioACUserNoMakeChangesMask), + /* common access privilege settings */ + kioACUserFull = 0x00, /* no access restiction bits on */ + kioACUserNone = kioACUserAccessMask, /* all access restiction bits on */ + kioACUserDropBox = (kioACUserNoSeeFolderMask + + kioACUserNoSeeFilesMask), /* make changes, but not see files or folders */ + kioACUserBulletinBoard = kioACUserNoMakeChangesMask /* see files and folders, but not make changes */ +}; + + +/* Macros for testing ioACUser bits. */ + +#define UserIsOwner(userPrivileges) \ + (((userPrivileges) & kioACUserNotOwnerMask) == 0) +#define UserHasFullAccess(userPrivileges) \ + (((userPrivileges) & (kioACUserAccessMask)) == kioACUserFull) +#define UserHasDropBoxAccess(userPrivileges) \ + (((userPrivileges) & kioACUserAccessMask) == kioACUserDropBox) +#define UserHasBulletinBoard(userPrivileges) \ + (((userPrivileges) & kioACUserAccessMask) == kioACUserBulletinBoard) +#define UserHasNoAccess(userPrivileges) \ + (((userPrivileges) & kioACUserAccessMask) == kioACUserNone) + +/*****************************************************************************/ + +#pragma mark ----- File Access Routines ----- + +/*****************************************************************************/ + +#pragma mark FSCopyFork + +OSErr +FSCopyFork( + SInt16 srcRefNum, + SInt16 dstRefNum, + void *copyBufferPtr, + ByteCount copyBufferSize); + +/* + The FSCopyFork function copies all data from the source fork to the + destination fork of open file forks and makes sure the destination EOF + is equal to the source EOF. + + srcRefNum --> The source file reference number. + dstRefNum --> The destination file reference number. + copyBufferPtr --> Pointer to buffer to use during copy. The + buffer should be at least 4K-bytes minimum. + The larger the buffer, the faster the copy + (up to a point). + copyBufferSize --> The size of the copy buffer. +*/ + +/*****************************************************************************/ + +#pragma mark ----- Volume Access Routines ----- + +/*****************************************************************************/ + +#pragma mark FSGetVolParms + +OSErr +FSGetVolParms( + FSVolumeRefNum volRefNum, + UInt32 bufferSize, + GetVolParmsInfoBuffer *volParmsInfo, + UInt32 *actualInfoSize); + +/* + The FSGetVolParms function returns information about the characteristics + of a volume. A result of paramErr usually just means the volume doesn't + support GetVolParms and the feature you were going to check + for isn't available. + + volRefNum --> Volume specification. + bufferSize --> Size of buffer pointed to by volParmsInfo. + volParmsInfo <-- A GetVolParmsInfoBuffer record where the volume + attributes information is returned. + actualInfoSize <-- The number of bytes actually returned + in volParmsInfo. + + __________ + + Also see: The GetVolParmsInfoBuffer Macros for checking attribute bits + in this file +*/ + +/*****************************************************************************/ + +#pragma mark FSGetVRefNum + +OSErr +FSGetVRefNum( + const FSRef *ref, + FSVolumeRefNum *vRefNum); + +/* + The FSGetVRefNum function determines the volume reference + number of a volume from a FSRef. + + ref --> The FSRef. + vRefNum <-- The volume reference number. +*/ + +/*****************************************************************************/ + +#pragma mark FSGetVInfo + +OSErr +FSGetVInfo( + FSVolumeRefNum volume, + HFSUniStr255 *volumeName, /* can be NULL */ + UInt64 *freeBytes, /* can be NULL */ + UInt64 *totalBytes); /* can be NULL */ + +/* + The FSGetVInfo function returns the name, available space (in bytes), + and total space (in bytes) for the specified volume. + + volume --> The volume reference number. + volumeName <** An optional pointer to a HFSUniStr255. + If not NULL, the volume name will be returned in + the HFSUniStr255. + freeBytes <** An optional pointer to a UInt64. + If not NULL, the number of free bytes on the + volume will be returned in the UInt64. + totalBytes <** An optional pointer to a UInt64. + If not NULL, the total number of bytes on the + volume will be returned in the UInt64. +*/ + +/*****************************************************************************/ + +#pragma mark FSGetVolFileSystemID + +OSErr +FSGetVolFileSystemID( + FSVolumeRefNum volume, + UInt16 *fileSystemID, /* can be NULL */ + UInt16 *signature); /* can be NULL */ + +/* + The FSGetVolFileSystemID function returns the file system ID and signature + of a mounted volume. The file system ID identifies the file system + that handles requests to a particular volume. The signature identifies the + volume type of the volume (for example, FSID 0 is Macintosh HFS Plus, HFS + or MFS, where a signature of 0x4244 identifies the volume as HFS). + Here's a partial list of file system ID numbers (only Apple's file systems + are listed): + FSID File System + ----- ----------------------------------------------------- + $0000 Macintosh HFS Plus, HFS or MFS + $0100 ProDOS File System + $0101 PowerTalk Mail Enclosures + $4147 ISO 9660 File Access (through Foreign File Access) + $4242 High Sierra File Access (through Foreign File Access) + $464D QuickTake File System (through Foreign File Access) + $4953 Macintosh PC Exchange (MS-DOS) + $4A48 Audio CD Access (through Foreign File Access) + $4D4B Apple Photo Access (through Foreign File Access) + $6173 AppleShare (later versions of AppleShare only) + + See the Technical Note "FL 35 - Determining Which File System + Is Active" and the "Guide to the File System Manager" for more + information. + + volume --> The volume reference number. + fileSystemID <** An optional pointer to a UInt16. + If not NULL, the volume's file system ID will + be returned in the UInt16. + signature <** An optional pointer to a UInt16. + If not NULL, the volume's signature will + be returned in the UInt16. +*/ + +/*****************************************************************************/ + +#pragma mark FSGetMountedVolumes + +OSErr +FSGetMountedVolumes( + FSRef ***volumeRefsHandle, /* pointer to handle of FSRefs */ + ItemCount *numVolumes); + +/* + The FSGetMountedVolumes function returns the list of volumes currently + mounted in an array of FSRef records. The array of FSRef records is + returned in a Handle, volumeRefsHandle, which is allocated by + FSGetMountedVolumes. The caller is responsible for disposing of + volumeRefsHandle if the FSGetMountedVolumes returns noErr. + + volumeRefsHandle <-- Pointer to an FSRef Handle where the array of + FSRefs is to be returned. + numVolumes <-- The number of volumes returned in the array. +*/ + +/*****************************************************************************/ + +#pragma mark ----- FSRef/FSpec/Path/Name Conversion Routines ----- + +/*****************************************************************************/ + +#pragma mark FSRefMakeFSSpec + +OSErr +FSRefMakeFSSpec( + const FSRef *ref, + FSSpec *spec); + +/* + The FSRefMakeFSSpec function returns an FSSpec for the file or + directory specified by the ref parameter. + + ref --> An FSRef specifying the file or directory. + spec <-- The FSSpec. +*/ + +/*****************************************************************************/ + +#pragma mark FSMakeFSRef + +OSErr +FSMakeFSRef( + FSVolumeRefNum volRefNum, + SInt32 dirID, + ConstStr255Param name, + FSRef *ref); + +/* + The FSMakeFSRef function creates an FSRef from the traditional + volume reference number, directory ID and pathname inputs. It is + functionally equivalent to FSMakeFSSpec followed by FSpMakeFSRef. + + volRefNum --> Volume specification. + dirID --> Directory specification. + name --> The file or directory name, or NULL. + ref <-- The FSRef. +*/ + +/*****************************************************************************/ + +#pragma mark FSMakePath + +OSStatus +FSMakePath( + SInt16 vRefNum, + SInt32 dirID, + ConstStr255Param name, + UInt8 *path, + UInt32 maxPathSize); + +/* + The FSMakePath function creates a pathname from the traditional volume reference + number, directory ID, and pathname inputs. It is functionally equivalent to + FSMakeFSSpec, FSpMakeFSRef, FSRefMakePath. + + volRefNum --> Volume specification. + dirID --> Directory specification. + name --> The file or directory name, or NULL. + path <-- A pointer to a buffer which FSMakePath will + fill with a C string representing the pathname + to the file or directory specified. The format of + the pathname returned can be determined with the + Gestalt selector gestaltFSAttr's + gestaltFSUsesPOSIXPathsForConversion bit. + If the gestaltFSUsesPOSIXPathsForConversion bit is + clear, the pathname is a Mac OS File Manager full + pathname in a C string, and file or directory names + in the pathname may be mangled as returned by + the File Manager. If the + gestaltFSUsesPOSIXPathsForConversion bit is set, + the pathname is a UTF8 encoded POSIX absolute + pathname in a C string. In either case, the + pathname returned can be passed back to + FSPathMakeRef to create an FSRef to the file or + directory, or FSPathMakeFSSpec to craete an FSSpec + to the file or directory. + maxPathSize --> The size of the path buffer in bytes. If the path + buffer is too small for the pathname string, + FSMakePath returns pathTooLongErr or + buffersTooSmall. +*/ + +/*****************************************************************************/ + +#pragma mark FSPathMakeFSSpec + +OSStatus +FSPathMakeFSSpec( + const UInt8 *path, + FSSpec *spec, + Boolean *isDirectory); /* can be NULL */ + +/* + The FSPathMakeFSSpec function converts a pathname to an FSSpec. + + path --> A pointer to a C String that is the pathname. The + format of the pathname you must supply can be + determined with the Gestalt selector gestaltFSAttr's + gestaltFSUsesPOSIXPathsForConversion bit. + If the gestaltFSUsesPOSIXPathsForConversion bit is + clear, the pathname must be a Mac OS File Manager + full pathname in a C string. If the + gestaltFSUsesPOSIXPathsForConversion bit is set, + the pathname must be a UTF8 encoded POSIX absolute + pathname in a C string. + spec <-- The FSSpec. + isDirectory <** An optional pointer to a Boolean. + If not NULL, true will be returned in the Boolean + if the specified path is a directory, or false will + be returned in the Boolean if the specified path is + a file. +*/ + +/*****************************************************************************/ + +#pragma mark UnicodeNameGetHFSName + +OSErr +UnicodeNameGetHFSName( + UniCharCount nameLength, + const UniChar *name, + TextEncoding textEncodingHint, + Boolean isVolumeName, + Str31 hfsName); + +/* + The UnicodeNameGetHFSName function converts a Unicode string + to a Pascal Str31 (or Str27) string using an algorithm similar to that used + by the File Manager. Note that if the name is too long or cannot be converted + using the given text encoding hint, you will get an error instead of the + mangled name that the File Manager would return. + + nameLength --> Number of UniChar in name parameter. + name --> The Unicode string to convert. + textEncodingHint --> The text encoding hint used for the conversion. + You can pass kTextEncodingUnknown to use the + "default" textEncodingHint. + isVolumeName --> If true, the output name will be limited to + 27 characters (kHFSMaxVolumeNameChars). If false, + the output name will be limited to 31 characters + (kHFSMaxFileNameChars). + hfsName <-- The hfsName as a Pascal string. + + __________ + + Also see: HFSNameGetUnicodeName +*/ + +/*****************************************************************************/ + +#pragma mark HFSNameGetUnicodeName + +OSErr +HFSNameGetUnicodeName( + ConstStr31Param hfsName, + TextEncoding textEncodingHint, + HFSUniStr255 *unicodeName); + +/* + The HFSNameGetUnicodeName function converts a Pascal Str31 string to an + Unicode HFSUniStr255 string using the same routines as the File Manager. + + hfsName --> The Pascal string to convert. + textEncodingHint --> The text encoding hint used for the conversion. + You can pass kTextEncodingUnknown to use the + "default" textEncodingHint. + unicodeName <-- The Unicode string. + + __________ + + Also see: UnicodeNameGetHFSName +*/ + +/*****************************************************************************/ + +#pragma mark ----- File/Directory Manipulation Routines ----- + +/*****************************************************************************/ + +#pragma mark FSRefValid + +Boolean FSRefValid(const FSRef *ref); + +/* + The FSRefValid function determines if an FSRef is valid. If the result is + true, then the FSRef refers to an existing file or directory. + + ref --> FSRef to a file or directory. +*/ + +/*****************************************************************************/ + +#pragma mark FSGetParentRef + +OSErr +FSGetParentRef( + const FSRef *ref, + FSRef *parentRef); + +/* + The FSGetParentRef function gets the parent directory FSRef of the + specified object. + + Note: FSRefs always point to real file system objects. So, there cannot + be a FSRef to the parent of volume root directories. If you call + FSGetParentRef with a ref to the root directory of a volume, the + function result will be noErr and the parentRef will be invalid (using it + for other file system requests will fail). + + ref --> FSRef to a file or directory. + parentRef <-- The parent directory's FSRef. +*/ + +/*****************************************************************************/ + +#pragma mark FSGetFileDirName + +OSErr +FSGetFileDirName( + const FSRef *ref, + HFSUniStr255 *outName); + +/* + The FSGetFileDirName function gets the name of the file or directory + specified. + + ref --> FSRef to a file or directory. + outName <-- The file or directory name. +*/ + +/*****************************************************************************/ + +#pragma mark FSGetNodeID + +OSErr +FSGetNodeID( + const FSRef *ref, + long *nodeID, /* can be NULL */ + Boolean *isDirectory); /* can be NULL */ + +/* + The GetNodeIDFromFSRef function gets the node ID number of the + file or directory specified (note: the node ID is the directory ID + for directories). + + ref --> FSRef to a file or directory. + nodeID <** An optional pointer to a long. + If not NULL, the node ID will be returned in + the long. + isDirectory <** An optional pointer to a Boolean. + If not NULL, true will be returned in the Boolean + if the object is a directory, or false will be + returned in the Boolean if object is a file. +*/ + +/*****************************************************************************/ + +#pragma mark FSGetUserPrivilegesPermissions + +OSErr +FSGetUserPrivilegesPermissions( + const FSRef *ref, + UInt8 *userPrivileges, /* can be NULL */ + UInt32 permissions[4]); /* can be NULL */ + +/* + The FSGetUserPrivilegesPermissions function gets the userPrivileges and/or + permissions of the file or directory specified. + + ref --> FSRef to a file or directory. + userPrivileges <** An optional pointer to a UInt8. + If not NULL, the userPrivileges will be returned + in the UInt8. + permissions <** An optional pointer to an UInt32[4] array. + If not NULL, the permissions will be returned + in the UInt32[4] array. +*/ + +/*****************************************************************************/ + +#pragma mark FSCheckLock + +OSErr +FSCheckLock( + const FSRef *ref); + +/* + The FSCheckLock function determines if a file or directory is locked. + If FSCheckLock returns noErr, then the file or directory is not locked + and the volume it is on is not locked either. If FSCheckLock returns + fLckdErr, then the file or directory is locked. If FSCheckLock returns + wPrErr, then the volume is locked by hardware (i.e., locked tab on + removable media). If FSCheckLock returns vLckdErr, then the volume is + locked by software. + + ref --> FSRef to a file or directory. +*/ + +/*****************************************************************************/ + +#pragma mark FSGetForkSizes + +OSErr +FSGetForkSizes( + const FSRef *ref, + UInt64 *dataLogicalSize, /* can be NULL */ + UInt64 *rsrcLogicalSize); /* can be NULL */ + +/* + The FSGetForkSizes returns the size of the data and/or resource fork for + the specified file. + + ref --> FSRef to a file or directory. + dataLogicalSize <** An optional pointer to a UInt64. + If not NULL, the data fork's size will be + returned in the UInt64. + rsrcLogicalSize <** An optional pointer to a UInt64. + If not NULL, the resource fork's size will be + returned in the UInt64. + + __________ + + Also see: FSGetTotalForkSizes +*/ + +/*****************************************************************************/ + +#pragma mark FSGetTotalForkSizes + +OSErr +FSGetTotalForkSizes( + const FSRef *ref, + UInt64 *totalLogicalSize, /* can be NULL */ + UInt64 *totalPhysicalSize, /* can be NULL */ + ItemCount *forkCount); /* can be NULL */ + +/* + The FSGetTotalForkSizes returns the total logical size and/or the total + physical size of the specified file (i.e., it adds the sizes of all file + forks). It optionally returns the number of file forks. + + ref --> FSRef to a file or directory. + totalLogicalSize <** An optional pointer to a UInt64. + If not NULL, the sum of all fork logical sizes + will be returned in the UInt64. + totalPhysicalSize <** An optional pointer to a UInt64. + If not NULL, the sum of all fork physical sizes + will be returned in the UInt64. + forkCount <** An optional pointer to a ItemCount. + If not NULL, the number of file forks + will be returned in the ItemCount. + + __________ + + Also see: FSGetForkSizes +*/ + +/*****************************************************************************/ + +#pragma mark FSBumpDate + +OSErr +FSBumpDate( + const FSRef *ref); + +/* + The FSBumpDate function changes the content modification date of a file + or directory to the current date/time. If the content modification date + is already equal to the current date/time, then add one second to the + content modification date. + + ref --> FSRef to a file or directory. +*/ + +/*****************************************************************************/ + +#pragma mark FSGetFinderInfo + +OSErr +FSGetFinderInfo( + const FSRef *ref, + FinderInfo *info, /* can be NULL */ + ExtendedFinderInfo *extendedInfo, /* can be NULL */ + Boolean *isDirectory); /* can be NULL */ + +/* + The FSGetFinderInfo function gets the finder information for a file or + directory. + + ref --> FSRef to a file or directory. + info <** An optional pointer to a FinderInfo. + If not NULL, the FileInfo (if ref is a file) or + the FolderInfo (if ref is a folder) will be + returned in the FinderInfo. + extendedInfo <** An optional pointer to a ExtendedFinderInfo. + If not NULL, the ExtendedFileInfo (if ref is a file) + or the ExtendedFolderInfo (if ref is a folder) will + be returned in the ExtendedFinderInfo. + isDirectory <** An optional pointer to a Boolean. + If not NULL, true will be returned in the Boolean + if the object is a directory, or false will be + returned in the Boolean if object is a file. + + __________ + + Also see: FSSetFinderInfo +*/ + +/*****************************************************************************/ + +#pragma mark FSSetFinderInfo + +OSErr +FSSetFinderInfo( + const FSRef *ref, + const FinderInfo *info, /* can be NULL */ + const ExtendedFinderInfo *extendedInfo); /* can be NULL */ + +/* + The FSSetFinderInfo function sets the finder information for a file or + directory. + + ref --> FSRef to a file or directory. + info **> A pointer to a FinderInfo record with the new + FileInfo (if ref is a file) or new FolderInfo + (if ref is a folder), or NULL if the FinderInfo + is not to be changed. + extendedInfo **> A pointer to a FinderInfo record with the new + ExtendedFileInfo (if ref is a file) or new + ExtendedFolderInfo (if ref is a folder), or NULL + if the ExtendedFinderInfo is not to be changed. + + __________ + + Also see: FSGetFinderInfo +*/ + +/*****************************************************************************/ + +#pragma mark FSChangeCreatorType + +OSErr +FSChangeCreatorType( + const FSRef *ref, + OSType fileCreator, + OSType fileType); + +/* + The FSChangeCreatorType function changes the creator and/or file type of a file. + + ref --> FSRef to a file. + creator --> The new creator type or 0x00000000 to leave + the creator type alone. + fileType --> The new file type or 0x00000000 to leave the + file type alone. +*/ + +/*****************************************************************************/ + +#pragma mark FSChangeFinderFlags + +OSErr +FSChangeFinderFlags( + const FSRef *ref, + Boolean setBits, + UInt16 flagBits); + +/* + The FSChangeFinderFlags function sets or clears flag bits in + the finderFlags field of a file's FileInfo record or a + directory's FolderInfo record. + + ref --> FSRef to a file or directory. + setBits --> If true, then set the bits specified in flagBits. + If false, then clear the bits specified in flagBits. + flagBits --> The flagBits parameter specifies which Finder Flag + bits to set or clear. If a bit in flagBits is set, + then the same bit in fdFlags is either set or + cleared depending on the state of the setBits + parameter. +*/ + +/*****************************************************************************/ + +#pragma mark FSSetInvisible + +OSErr +FSSetInvisible( + const FSRef *ref); + +#pragma mark FSClearInvisible + +OSErr +FSClearInvisible( + const FSRef *ref); + +/* + The FSSetInvisible and FSClearInvisible functions set or clear the + kIsInvisible bit in the finderFlags field of the specified file or + directory's finder information. + + ref --> FSRef to a file or directory. +*/ + +/*****************************************************************************/ + +#pragma mark FSSetNameLocked + +OSErr +FSSetNameLocked( + const FSRef *ref); + +#pragma mark FSClearNameLocked + +OSErr +FSClearNameLocked( + const FSRef *ref); + +/* + The FSSetNameLocked and FSClearNameLocked functions set or clear the + kNameLocked bit bit in the finderFlags field of the specified file or + directory's finder information. + + ref --> FSRef to a file or directory. +*/ + +/*****************************************************************************/ + +#pragma mark FSSetIsStationery + +OSErr +FSSetIsStationery( + const FSRef *ref); + +#pragma mark FSClearIsStationery + +OSErr +FSClearIsStationery( + const FSRef *ref); + +/* + The FSSetIsStationery and FSClearIsStationery functions set or clear the + kIsStationery bit bit in the finderFlags field of the specified file or + directory's finder information. + + ref --> FSRef to a file or directory. +*/ + +/*****************************************************************************/ + +#pragma mark FSSetHasCustomIcon + +OSErr +FSSetHasCustomIcon( + const FSRef *ref); + +#pragma mark FSClearHasCustomIcon + +OSErr +FSClearHasCustomIcon( + const FSRef *ref); + +/* + The FSSetHasCustomIcon and FSClearHasCustomIcon functions set or clear the + kHasCustomIcon bit bit in the finderFlags field of the specified file or + directory's finder information. + + ref --> FSRef to a file or directory. +*/ + +/*****************************************************************************/ + +#pragma mark FSClearHasBeenInited + +OSErr +FSClearHasBeenInited( + const FSRef *ref); + +/* + The FSClearHasBeenInited function clears the kHasBeenInited bit in the + finderFlags field of the specified file or directory's finder information. + + Note: There is no FSSetHasBeenInited function because ONLY the Finder + should set the kHasBeenInited bit. + + ref --> FSRef to a file or directory. +*/ + +/*****************************************************************************/ + +#pragma mark FSCopyFileMgrAttributes + +OSErr +FSCopyFileMgrAttributes( + const FSRef *sourceRef, + const FSRef *destinationRef, + Boolean copyLockBit); + +/* + The CopyFileMgrAttributes function copies all File Manager attributes + from the source file or directory to the destination file or directory. + If copyLockBit is true, then set the locked state of the destination + to match the source. + + sourceRef --> FSRef to a file or directory. + destinationRef --> FSRef to a file or directory. + copyLockBit --> If true, set the locked state of the destination + to match the source. +*/ + +/*****************************************************************************/ + +#pragma mark FSMoveRenameObjectUnicode + +OSErr +FSMoveRenameObjectUnicode( + const FSRef *ref, + const FSRef *destDirectory, + UniCharCount nameLength, + const UniChar *name, /* can be NULL (no rename during move) */ + TextEncoding textEncodingHint, + FSRef *newRef); /* if function fails along the way, newRef is final location of file */ + +/* + The FSMoveRenameObjectUnicode function moves a file or directory and + optionally renames it. The source and destination locations must be on + the same volume. + + Note: If the input ref parameter is invalid, this call will fail and + newRef, like ref, will be invalid. + + ref --> FSRef to a file or directory. + destDirectory --> FSRef to the destination directory. + nameLength --> Number of UniChar in name parameter. + name --> An Unicode string with the new name for the + moved object, or NULL if no rename is wanted. + textEncodingHint --> The text encoding hint used for the rename. + You can pass kTextEncodingUnknown to use the + "default" textEncodingHint. + newRef <-- The new FSRef of the object moved. Note that if + this function fails at any step along the way, + newRef is still then final location of the object. +*/ + +/*****************************************************************************/ + +#pragma mark FSDeleteContainerContents + +OSErr +FSDeleteContainerContents( + const FSRef *container); + +/* + The FSDeleteContainerContents function deletes the contents of a container + directory. All files and subdirectories in the specified container are + deleted. If a locked file or directory is encountered, it is unlocked and + then deleted. If any unexpected errors are encountered, + FSDeleteContainerContents quits and returns to the caller. + + container --> FSRef to a directory. + + __________ + + Also see: FSDeleteContainer +*/ + +/*****************************************************************************/ + +#pragma mark FSDeleteContainer + +OSErr +FSDeleteContainer( + const FSRef *container); + +/* + The FSDeleteContainer function deletes a container directory and its contents. + All files and subdirectories in the specified container are deleted. + If a locked file or directory is encountered, it is unlocked and then + deleted. After deleting the container's contents, the container is + deleted. If any unexpected errors are encountered, FSDeleteContainer + quits and returns to the caller. + + container --> FSRef to a directory. + + __________ + + Also see: FSDeleteContainerContents +*/ + +/*****************************************************************************/ + +#pragma mark IterateContainerFilterProcPtr + +typedef CALLBACK_API( Boolean , IterateContainerFilterProcPtr ) ( + Boolean containerChanged, + ItemCount currentLevel, + const FSCatalogInfo *catalogInfo, + const FSRef *ref, + const FSSpec *spec, + const HFSUniStr255 *name, + void *yourDataPtr); + +/* + This is the prototype for the IterateContainerFilterProc function which + is called once for each file and directory found by FSIterateContainer. + The IterateContainerFilterProc can use the read-only data it receives for + whatever it wants. + + The result of the IterateContainerFilterProc function indicates if + iteration should be stopped. To stop iteration, return true; to continue + iteration, return false. + + The yourDataPtr parameter can point to whatever data structure you might + want to access from within the IterateContainerFilterProc. + + containerChanged --> Set to true if the container's contents changed + during iteration. + currentLevel --> The current recursion level into the container. + 1 = the container, 2 = the container's immediate + subdirectories, etc. + catalogInfo --> The catalog information for the current object. + Only the fields requested by the whichInfo + parameter passed to FSIterateContainer are valid. + ref --> The FSRef to the current object. + spec --> The FSSpec to the current object if the wantFSSpec + parameter passed to FSIterateContainer is true. + name --> The name of the current object if the wantName + parameter passed to FSIterateContainer is true. + yourDataPtr --> An optional pointer to whatever data structure you + might want to access from within the + IterateFilterProc. + result <-- To stop iteration, return true; to continue + iteration, return false. + + __________ + + Also see: FSIterateContainer +*/ + +/*****************************************************************************/ + +#pragma mark CallIterateContainerFilterProc + +#define CallIterateContainerFilterProc(userRoutine, containerChanged, currentLevel, catalogInfo, ref, spec, name, yourDataPtr) \ + (*(userRoutine))((containerChanged), (currentLevel), (catalogInfo), (ref), (spec), (name), (yourDataPtr)) + +/*****************************************************************************/ + +#pragma mark FSIterateContainer + +OSErr +FSIterateContainer( + const FSRef *container, + ItemCount maxLevels, + FSCatalogInfoBitmap whichInfo, + Boolean wantFSSpec, + Boolean wantName, + IterateContainerFilterProcPtr iterateFilter, + void *yourDataPtr); + +/* + The FSIterateContainer function performs a recursive iteration (scan) of the + specified container directory and calls your IterateContainerFilterProc + function once for each file and directory found. + + The maxLevels parameter lets you control how deep the recursion goes. + If maxLevels is 1, FSIterateContainer only scans the specified directory; + if maxLevels is 2, FSIterateContainer scans the specified directory and + one subdirectory below the specified directory; etc. Set maxLevels to + zero to scan all levels. + + The yourDataPtr parameter can point to whatever data structure you might + want to access from within your IterateContainerFilterProc. + + container --> The FSRef to the container directory to iterate. + maxLevels --> Maximum number of directory levels to scan or + zero to scan all directory levels. + whichInfo --> The fields of the FSCatalogInfo you wish to get. + wantFSSpec --> Set to true if you want the FSSpec to each + object passed to your IterateContainerFilterProc. + wantName --> Set to true if you want the name of each + object passed to your IterateContainerFilterProc. + iterateFilter --> A pointer to the IterateContainerFilterProc you + want called once for each file and directory found + by FSIterateContainer. + yourDataPtr --> An optional pointer to whatever data structure you + might want to access from within the + IterateFilterProc. +*/ + +/*****************************************************************************/ + +#pragma mark FSGetDirectoryItems + +OSErr +FSGetDirectoryItems( + const FSRef *container, + FSRef ***refsHandle, /* pointer to handle of FSRefs */ + ItemCount *numRefs, + Boolean *containerChanged); + +/* + The FSGetDirectoryItems function returns the list of items in the specified + container. The array of FSRef records is returned in a Handle, refsHandle, + which is allocated by FSGetDirectoryItems. The caller is responsible for + disposing of refsHandle if the FSGetDirectoryItems returns noErr. + + container --> FSRef to a directory. + refsHandle <-- Pointer to an FSRef Handle where the array of + FSRefs is to be returned. + numRefs <-- The number of FSRefs returned in the array. + containerChanged <-- Set to true if the container changes while the + list of items is being obtained. +*/ + +/*****************************************************************************/ + +#pragma mark FSExchangeObjectsCompat + +OSErr +FSExchangeObjectsCompat( + const FSRef *sourceRef, + const FSRef *destRef, + FSRef *newSourceRef, + FSRef *newDestRef); + +/* + The FSExchangeObjectsCompat function exchanges the data between two files. + + The FSExchangeObjectsCompat function is an enhanced version of + FSExchangeObjects function. The two enhancements FSExchangeObjectsCompat + provides are: + + 1, FSExchangeObjectsCompat will work on volumes which do not support + FSExchangeObjects. FSExchangeObjectsCompat does this by emulating + FSExchangeObjects through a series of File Manager operations. If + there is a failure at any step along the way, FSExchangeObjectsCompat + attempts to undo any steps already taken to leave the files in their + original state in their original locations. + + 2. FSExchangeObjectsCompat returns new FSRefs to the source and + destination files. Note that if this function fails at any step along + the way, newSourceRef and newDestRef still give you access to the final + locations of the files being exchanged -- even if they are renamed or + not in their original locations. + + sourceRef --> FSRef to the source file. + destRef --> FSRef to the destination file. + newSourceRef <-- The new FSRef to the source file. + newDestRef <-- The new FSRef to the destination file. +*/ + +/*****************************************************************************/ + +#pragma mark ----- Shared Environment Routines ----- + +/*****************************************************************************/ + +#pragma mark MFX_FSLockRange +/* Renamed from FSLockRange to MFX_FSLockRange to avoid a conflict with + * the FSLockRange function present in the system library since Mac OS X + * 10.4. */ + +OSErr +MFX_FSLockRange( + SInt16 refNum, + SInt32 rangeLength, + SInt32 rangeStart); + +/* + The LockRange function locks (denies access to) a portion of a file + that was opened with shared read/write permission. + + refNum --> The file reference number of an open file. + rangeLength --> The number of bytes in the range. + rangeStart --> The starting byte in the range to lock. + + __________ + + Also see: UnlockRange +*/ + +/*****************************************************************************/ + +#pragma mark MFX_FSUnlockRange +/* Renamed from FSUnlockRange to MFX_FSUnlockRange to avoid a conflict with + * the FSUnlockRange function present in the system library since Mac OS X + * 10.4. */ + +OSErr +MFX_FSUnlockRange( + SInt16 refNum, + SInt32 rangeLength, + SInt32 rangeStart); + +/* + The UnlockRange function unlocks (allows access to) a previously locked + portion of a file that was opened with shared read/write permission. + + refNum --> The file reference number of an open file. + rangeLength --> The number of bytes in the range. + rangeStart --> The starting byte in the range to unlock. + + __________ + + Also see: LockRange +*/ + +/*****************************************************************************/ + +#pragma mark FSGetDirAccess + +OSErr +FSGetDirAccess( + const FSRef *ref, + SInt32 *ownerID, /* can be NULL */ + SInt32 *groupID, /* can be NULL */ + SInt32 *accessRights); /* can be NULL */ + +/* + The FSGetDirAccess function retrieves the directory access control + information for a directory on a shared volume. + + ref --> An FSRef specifying the directory. + ownerID <** An optional pointer to a SInt32. + If not NULL, the directory's owner ID + will be returned in the SInt32. + groupID <** An optional pointer to a SInt32. + If not NULL, the directory's group ID, or 0 + if no group affiliation, will be returned in + the SInt32. + accessRights <** An optional pointer to a SInt32. + If not NULL, the directory's access rights + will be returned in the SInt32. + + __________ + + Also see: FSSetDirAccess, FSMapID, FSMapName +*/ + +/*****************************************************************************/ + +#pragma mark FSSetDirAccess + +OSErr +FSSetDirAccess( + const FSRef *ref, + SInt32 ownerID, + SInt32 groupID, + SInt32 accessRights); + +/* + The FSpSetDirAccess function changes the directory access control + information for a directory on a shared volume. You must be the owner of + a directory to change its access control information. + + ref --> An FSRef specifying the directory. + ownerID --> The directory's owner ID. + groupID --> The directory's group ID or 0 if no group affiliation. + accessRights --> The directory's access rights. + + __________ + + Also see: FSGetDirAccess, FSMapID, FSMapName +*/ + +/*****************************************************************************/ + +#pragma mark FSGetVolMountInfoSize + +OSErr +FSGetVolMountInfoSize( + FSVolumeRefNum volRefNum, + SInt16 *size); + +/* + The FSGetVolMountInfoSize function determines the how much space the + program needs to allocate for a volume mounting information record. + + volRefNum --> Volume specification. + size <-- The space needed (in bytes) of the volume + mounting information record. + + __________ + + Also see: FSGetVolMountInfo, VolumeMount +*/ + +/*****************************************************************************/ + +#pragma mark FSGetVolMountInfo + +OSErr +FSGetVolMountInfo( + FSVolumeRefNum volRefNum, + void *volMountInfo); + +/* + The FSGetVolMountInfo function retrieves a volume mounting information + record containing all the information needed to mount the volume, + except for passwords. + + volRefNum --> Volume specification. + volMountInfo <-- The volume mounting information. + + __________ + + Also see: FSGetVolMountInfoSize, VolumeMount +*/ + +/*****************************************************************************/ + +#pragma mark FSVolumeMount + +// This function exists in Mac OS X 10.5, we cannot re-define it here. +// We don't use this function, so just don't compile it. +#if 0 +OSErr +FSVolumeMount( + const void *volMountInfo, + FSVolumeRefNum *volRefNum); +#endif + +/* + The VolumeMount function mounts a volume using a volume mounting + information record. + + volMountInfo --> A volume mounting information record. + volRefNum <-- The volume reference number. + + __________ + + Also see: FSGetVolMountInfoSize, FSGetVolMountInfo +*/ + +/*****************************************************************************/ + +#pragma mark FSMapID + +OSErr +FSMapID( + FSVolumeRefNum volRefNum, + SInt32 ugID, + SInt16 objType, + Str31 name); + +/* + The FSMapID function determines the name of a user or group if you know + the user or group ID. + + volRefNum --> Volume specification. + objType --> The mapping function code: + kOwnerID2Name to map a user ID to a user name + kGroupID2Name to map a group ID to a group name + name <** An optional pointer to a buffer (minimum Str31). + If not NULL, the user or group name + will be returned in the buffer. + + __________ + + Also see: FSGetDirAccess, FSSetDirAccess, FSMapName +*/ + +/*****************************************************************************/ + +#pragma mark FSMapName + +OSErr +FSMapName( + FSVolumeRefNum volRefNum, + ConstStr255Param name, + SInt16 objType, + SInt32 *ugID); + +/* + The FSMapName function determines the user or group ID if you know the + user or group name. + + volRefNum --> Volume specification. + name --> The user or group name. + objType --> The mapping function code: + kOwnerName2ID to map a user name to a user ID + kGroupName2ID to map a user name to a group ID + ugID <-- The user or group ID. + + __________ + + Also see: FSGetDirAccess, FSSetDirAccess, FSMapID +*/ + +/*****************************************************************************/ + +#pragma mark FSCopyFile + +OSErr +FSCopyFile( + const FSRef *srcFileRef, + const FSRef *dstDirectoryRef, + UniCharCount nameLength, + const UniChar *copyName, /* can be NULL (no rename during copy) */ + TextEncoding textEncodingHint, + FSRef *newRef); /* can be NULL */ + +/* + The FSCopyFile function duplicates a file and optionally renames it. + The source and destination volumes must be on the same file server. + This function instructs the server to copy the file. + + srcFileRef --> An FSRef specifying the source file. + dstDirectoryRef --> An FSRef specifying the destination directory. + nameLength --> Number of UniChar in copyName parameter (ignored + if copyName is NULL). + copyName --> Points to the new file name if the file is to be + renamed, or NULL if the file isn't to be renamed. + textEncodingHint --> The text encoding hint used for the rename. + You can pass kTextEncodingUnknown to use the + "default" textEncodingHint. + newRef <** An optional pointer to a FSRef. + If not NULL, the FSRef of the duplicated file + will be returned in the FSRef. +*/ + +/*****************************************************************************/ + +#pragma mark FSMoveRename + +OSErr +FSMoveRename( + const FSRef *srcFileRef, + const FSRef *dstDirectoryRef, + UniCharCount nameLength, + const UniChar *moveName, /* can be NULL (no rename during move) */ + TextEncoding textEncodingHint, + FSRef *newRef); /* can be NULL */ + +/* + The FSMoveRename function moves a file or directory (object), and + optionally renames it. The source and destination locations must be on + the same shared volume. + + srcFileRef --> An FSRef specifying the source file. + dstDirectoryRef --> An FSRef specifying the destination directory. + nameLength --> Number of UniChar in moveName parameter (ignored + if copyName is NULL) + moveName --> Points to the new object name if the object is to be + renamed, or NULL if the object isn't to be renamed. + textEncodingHint --> The text encoding hint used for the rename. + You can pass kTextEncodingUnknown to use the + "default" textEncodingHint. + newRef <** An optional pointer to a FSRef. + If not NULL, the FSRef of the moved object + will be returned in the FSRef. +*/ + +/*****************************************************************************/ + +#pragma mark ----- File ID Routines ----- + +/*****************************************************************************/ + +#pragma mark FSResolveFileIDRef + +OSErr +FSResolveFileIDRef( + FSVolumeRefNum volRefNum, + SInt32 fileID, + FSRef *ref); + +/* + The FSResolveFileIDRef function returns an FSRef for the file with the + specified file ID reference. + + volRefNum --> Volume specification. + fileID --> The file ID reference. + ref <-- The FSRef for the file ID reference. + + __________ + + Also see: FSCreateFileIDRef, FSDeleteFileIDRef +*/ + +/*****************************************************************************/ + +#pragma mark FSCreateFileIDRef + +OSErr +FSCreateFileIDRef( + const FSRef *ref, + SInt32 *fileID); + +/* + The FSCreateFileIDRef function creates a file ID reference for the + specified file, or if a file ID reference already exists, supplies + the file ID reference and returns the result code fidExists or afpIDExists. + + ref --> The FSRef for the file. + fileID <-- The file ID reference (if result is noErr, + fidExists, or afpIDExists). + + __________ + + Also see: GetFSRefFromFileIDRef, FSDeleteFileIDRef +*/ + +/*****************************************************************************/ + +#pragma mark FSDeleteFileIDRef + +/* + Why is there no FSDeleteFileIDRef routine? There are two reasons: + + 1. Since Mac OS 8.1, PBDeleteFileIDRef hasn't deleted file ID references. + On HFS volumes, deleting a file ID reference breaks aliases (which + use file ID references to track files as they are moved around on a + volume) and file ID references are automatically deleted when the file + they refer to is deleted. On HFS Plus volumes, file ID references are + always created when a file is created, deleted when the file is deleted, + and cannot be deleted at any other time. + + 2. PBDeleteFileIDRef causes a memory access fault under Mac OS X 10.0 + through 10.1.x. While this will be fixed in a future release, the + implementation, like the Mac OS 8/9 implementation, does not delete + file ID references. + + __________ + + Also see: GetFSRefFromFileIDRef, FSCreateFileIDRef +*/ + +/*****************************************************************************/ + +#pragma mark ----- Utility Routines ----- + +/*****************************************************************************/ + +#pragma mark GetTempBuffer + +Ptr +GetTempBuffer( + ByteCount buffReqSize, + ByteCount *buffActSize); + +/* + The GetTempBuffer function allocates a temporary buffer for file system + operations which is at least 4K bytes and a multiple of 4K bytes. + + buffReqSize --> Size you'd like the buffer to be. + buffActSize <-- The size of the buffer allocated. + function result <-- Pointer to memory allocated, or NULL if no memory + was available. The caller is responsible for + disposing of this buffer with DisposePtr. +*/ + +/*****************************************************************************/ + +#pragma mark FileRefNumGetFSRef + +OSErr +FileRefNumGetFSRef( + short refNum, + FSRef *ref); + +/* + The FileRefNumGetFSRef function gets the FSRef of an open file. + + refNum --> The file reference number of an open file. + ref <-- The FSRef to the open file. +*/ + +/*****************************************************************************/ + +#pragma mark FSSetDefault + +OSErr +FSSetDefault( + const FSRef *newDefault, + FSRef *oldDefault); + +/* + The FSSetDefault function sets the current working directory to the + directory specified by newDefault. The previous current working directory + is returned in oldDefault and must be used to restore the current working + directory to its previous state with the FSRestoreDefault function. + These two functions are designed to be used as a wrapper around + Standard I/O routines where the location of the file is implied to be the + current working directory. This is how you should use these functions: + + result = FSSetDefault(&newDefault, &oldDefault); + if ( noErr == result ) + { + // call the Stdio functions like remove, rename, + // fopen, freopen, etc here! + + result = FSRestoreDefault(&oldDefault); + } + + newDefault --> An FSRef that specifies the new current working + directory. + oldDefault <-- The previous current working directory's FSRef. + + __________ + + Also see: FSRestoreDefault +*/ + +/*****************************************************************************/ + +#pragma mark FSRestoreDefault + +OSErr +FSRestoreDefault( + const FSRef *oldDefault); + +/* + The FSRestoreDefault function restores the current working directory + to the directory specified by oldDefault. The oldDefault parameter was + previously obtained from the FSSetDefault function. + These two functions are designed to be used as a wrapper around + Standard I/O routines where the location of the file is implied to be the + current working directory. This is how you should use these functions: + + result = FSSetDefault(&newDefault, &oldDefault); + if ( noErr == result ) + { + // call the Stdio functions like remove, rename, + // fopen, freopen, etc here! + + result = FSRestoreDefault(&oldDefault); + } + + oldDefault --> The FSRef of the location to restore. + + __________ + + Also see: FSSetDefault +*/ + +/*****************************************************************************/ + +#if PRAGMA_STRUCT_ALIGN + #pragma options align=reset +#elif PRAGMA_STRUCT_PACKPUSH + #pragma pack(pop) +#elif PRAGMA_STRUCT_PACK + #pragma pack() +#endif + +#ifdef PRAGMA_IMPORT_OFF +#pragma import off +#elif PRAGMA_IMPORT +#pragma import reset +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* __MOREFILESX__ */ + diff --git a/src/libs/xpcom18a4/xpcom/base/.cvsignore b/src/libs/xpcom18a4/xpcom/base/.cvsignore new file mode 100644 index 00000000..235f7398 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/base/.cvsignore @@ -0,0 +1,2 @@ +Makefile +bloatblame diff --git a/src/libs/xpcom18a4/xpcom/base/Makefile.in b/src/libs/xpcom18a4/xpcom/base/Makefile.in new file mode 100644 index 00000000..a897bca8 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/base/Makefile.in @@ -0,0 +1,133 @@ +# +# ***** 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.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of 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 ***** + +DEPTH = ../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = xpcom +XPIDL_MODULE = xpcom_base +LIBRARY_NAME = xpcombase_s +GRE_MODULE = 1 + +REQUIRES = string \ + $(NULL) + +CPPSRCS = \ + nsAllocator.cpp \ + nsConsoleMessage.cpp \ + nsConsoleService.cpp \ + nsDebugImpl.cpp \ + nsErrorService.cpp \ + nsExceptionService.cpp \ + nsID.cpp \ + nsMemoryImpl.cpp \ + nsTraceRefcntImpl.cpp \ + $(NULL) + +ifdef GC_LEAK_DETECTOR +CSRCS += nsGarbageCollector.c +CPPSRCS += nsLeakDetector.cpp +REQUIRES += boehm +endif + +EXPORTS = \ + nsAgg.h \ + nsAutoPtr.h \ + nsCom.h \ + nsDebugImpl.h \ + nsIAllocator.h \ + nsIID.h \ + nsISupportsObsolete.h \ + nsTraceRefcntImpl.h \ + nsWeakPtr.h \ + $(NULL) + +ifeq ($(OS_ARCH),WINNT) +ifdef MOZ_DEBUG +CSRCS += pure_api.c +EXPORTS += pure.h +endif +CPPSRCS += nsStackFrameWin.cpp +endif + +ifneq ($(OS_ARCH),WINNT) +CPPSRCS += nsStackFrameUnix.cpp +endif + +SDK_XPIDLSRCS = \ + nsIDebug.idl \ + nsIInterfaceRequestor.idl \ + nsIMemory.idl \ + nsIProgrammingLanguage.idl \ + nsISupports.idl \ + nsITraceRefcnt.idl \ + nsIWeakReference.idl \ + nsrootidl.idl \ + +SDK_HEADERS = \ + nsError.h \ + nsID.h \ + nsISupportsBase.h \ + nscore.h \ + +XPIDLSRCS = \ + nsIConsoleListener.idl \ + nsIConsoleMessage.idl \ + nsIConsoleService.idl \ + nsIErrorService.idl \ + nsIException.idl \ + nsIExceptionService.idl \ + $(NULL) + +ifdef GC_LEAK_DETECTOR +XPIDLSRCS += nsILeakDetector.idl +endif + +# we don't want the shared lib, but we want to force the creation of a static lib. +FORCE_STATIC_LIB = 1 + +# Force use of PIC +FORCE_USE_PIC = 1 + +include $(topsrcdir)/config/rules.mk + +DEFINES += -D_IMPL_NS_COM + diff --git a/src/libs/xpcom18a4/xpcom/base/nsAgg.h b/src/libs/xpcom18a4/xpcom/base/nsAgg.h new file mode 100644 index 00000000..c818639e --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/base/nsAgg.h @@ -0,0 +1,155 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +#ifndef nsAgg_h___ +#define nsAgg_h___ + +#include "nsISupports.h" + + +//////////////////////////////////////////////////////////////////////////////// + +// Put this in your class's declaration: +#define NS_DECL_AGGREGATED \ + NS_DECL_ISUPPORTS \ + \ +public: \ + \ + /* You must implement this operation instead of the nsISupports */ \ + /* methods if you inherit from nsAggregated. */ \ + NS_IMETHOD \ + AggregatedQueryInterface(const nsIID& aIID, void** aInstancePtr); \ + \ +protected: \ + \ + class Internal : public nsISupports { \ + public: \ + \ + Internal() {} \ + \ + NS_IMETHOD QueryInterface(const nsIID& aIID, \ + void** aInstancePtr); \ + NS_IMETHOD_(nsrefcnt) AddRef(void); \ + NS_IMETHOD_(nsrefcnt) Release(void); \ + \ + }; \ + \ + friend class Internal; \ + \ + nsISupports* fOuter; \ + Internal fAggregated; \ + \ + nsISupports* GetInner(void) { return &fAggregated; } \ + \ +public: \ + + +// Put this in your class's constructor: +#define NS_INIT_AGGREGATED(outer) \ + PR_BEGIN_MACRO \ + fOuter = outer ? outer : &fAggregated; \ + PR_END_MACRO + + +// Put this in your class's implementation file: +#define NS_IMPL_AGGREGATED(_class) \ +NS_IMETHODIMP \ +_class::QueryInterface(const nsIID& aIID, void** aInstancePtr) \ +{ \ + return fOuter->QueryInterface(aIID, aInstancePtr); \ +} \ + \ +NS_IMETHODIMP_(nsrefcnt) \ +_class::AddRef(void) \ +{ \ + return fOuter->AddRef(); \ +} \ + \ +NS_IMETHODIMP_(nsrefcnt) \ +_class::Release(void) \ +{ \ + return fOuter->Release(); \ +} \ + \ +NS_IMETHODIMP \ +_class::Internal::QueryInterface(const nsIID& aIID, void** aInstancePtr) \ +{ \ + _class* agg = (_class*)((char*)(this) - offsetof(_class, fAggregated)); \ + return agg->AggregatedQueryInterface(aIID, aInstancePtr); \ +} \ + \ +NS_IMETHODIMP_(nsrefcnt) \ +_class::Internal::AddRef(void) \ +{ \ + _class* agg = (_class*)((char*)(this) - offsetof(_class, fAggregated)); \ + NS_PRECONDITION(PRInt32(agg->mRefCnt) >= 0, "illegal refcnt"); \ + ++agg->mRefCnt; \ + NS_LOG_ADDREF(this, agg->mRefCnt, #_class, sizeof(*this)); \ + return agg->mRefCnt; \ +} \ + \ +NS_IMETHODIMP_(nsrefcnt) \ +_class::Internal::Release(void) \ +{ \ + _class* agg = (_class*)((char*)(this) - offsetof(_class, fAggregated)); \ + NS_PRECONDITION(0 != agg->mRefCnt, "dup release"); \ + --agg->mRefCnt; \ + NS_LOG_RELEASE(this, agg->mRefCnt, #_class); \ + if (agg->mRefCnt == 0) { \ + agg->mRefCnt = 1; /* stabilize */ \ + NS_DELETEXPCOM(agg); \ + return 0; \ + } \ + return agg->mRefCnt; \ +} \ + +// for use with QI macros in nsISupportsUtils.h: + +#define NS_INTERFACE_MAP_BEGIN_AGGREGATED(_class) \ + NS_IMPL_AGGREGATED_QUERY_HEAD(_class) + +#define NS_IMPL_AGGREGATED_QUERY_HEAD(_class) \ +NS_IMETHODIMP \ +_class::AggregatedQueryInterface(REFNSIID aIID, void** aInstancePtr) \ +{ \ + NS_ASSERTION(aInstancePtr, \ + "AggregatedQueryInterface requires a non-NULL result ptr!"); \ + if ( !aInstancePtr ) \ + return NS_ERROR_NULL_POINTER; \ + nsISupports* foundInterface; + +#endif /* nsAgg_h___ */ diff --git a/src/libs/xpcom18a4/xpcom/base/nsAllocator.cpp b/src/libs/xpcom18a4/xpcom/base/nsAllocator.cpp new file mode 100644 index 00000000..d565329d --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/base/nsAllocator.cpp @@ -0,0 +1,41 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Pierre Phaneuf + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +//////////////////////////////////////////////////////////////////////////////// +// obsolete +//////////////////////////////////////////////////////////////////////////////// diff --git a/src/libs/xpcom18a4/xpcom/base/nsAllocator.h b/src/libs/xpcom18a4/xpcom/base/nsAllocator.h new file mode 100644 index 00000000..5320469c --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/base/nsAllocator.h @@ -0,0 +1,50 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +//////////////////////////////////////////////////////////////////////////////// +// obsolete +//////////////////////////////////////////////////////////////////////////////// + +#ifndef nsAllocator_h__ +#define nsAllocator_h__ + +#include "nsIAllocator.h" +#include "prmem.h" +#include "nsAgg.h" +#include "nsIFactory.h" + +#endif // nsAllocator_h__ diff --git a/src/libs/xpcom18a4/xpcom/base/nsAutoPtr.h b/src/libs/xpcom18a4/xpcom/base/nsAutoPtr.h new file mode 100644 index 00000000..874b1e31 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/base/nsAutoPtr.h @@ -0,0 +1,1353 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Scott Collins (original author of nsCOMPtr) + * L. David Baron + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +#ifndef nsAutoPtr_h___ +#define nsAutoPtr_h___ + + // Wrapping includes can speed up compiles (see "Large Scale C++ Software Design") +#ifndef nsCOMPtr_h___ + // For |already_AddRefed|, |nsDerivedSafe|, |NSCAP_Zero|, + // |NSCAP_DONT_PROVIDE_NONCONST_OPEQ|, + // |NSCAP_FEATURE_INLINE_STARTASSIGNMENT| +#include "nsCOMPtr.h" +#endif + +/*****************************************************************************/ + +// template class nsAutoPtrGetterTransfers; + +template +class nsAutoPtr + { + private: + void** + begin_assignment() + { + assign(0); + return NS_REINTERPRET_CAST(void**, &mRawPtr); + } + + void + assign( T* newPtr ) + { + T* oldPtr = mRawPtr; + mRawPtr = newPtr; + delete oldPtr; + } + + private: + T* mRawPtr; + + public: + typedef T element_type; + + ~nsAutoPtr() + { + delete mRawPtr; + } + + // Constructors + + nsAutoPtr() + : mRawPtr(0) + // default constructor + { + } + + nsAutoPtr( T* aRawPtr ) + : mRawPtr(aRawPtr) + // construct from a raw pointer (of the right type) + { + } + + nsAutoPtr( nsAutoPtr& aSmartPtr ) + : mRawPtr( aSmartPtr.forget() ) + // Construct by transferring ownership from another smart pointer. + { + } + + + // Assignment operators + + nsAutoPtr& + operator=( T* rhs ) + // assign from a raw pointer (of the right type) + { + assign(rhs); + return *this; + } + + nsAutoPtr& operator=( nsAutoPtr& rhs ) + // assign by transferring ownership from another smart pointer. + { + assign(rhs.forget()); + return *this; + } + + // Other pointer operators + + T* + get() const + /* + Prefer the implicit conversion provided automatically by + |operator T*() const|. Use |get()| _only_ to resolve + ambiguity. + */ + { + return mRawPtr; + } + + operator T*() const + /* + ...makes an |nsAutoPtr| act like its underlying raw pointer + type whenever it is used in a context where a raw pointer + is expected. It is this operator that makes an |nsAutoPtr| + substitutable for a raw pointer. + + Prefer the implicit use of this operator to calling |get()|, + except where necessary to resolve ambiguity. + */ + { + return get(); + } + + T* + forget() + { + T* temp = mRawPtr; + mRawPtr = 0; + return temp; + } + + T* + operator->() const + { + NS_PRECONDITION(mRawPtr != 0, "You can't dereference a NULL nsAutoPtr with operator->()."); + return get(); + } + +#ifdef CANT_RESOLVE_CPP_CONST_AMBIGUITY + // broken version for IRIX + + nsAutoPtr* + get_address() const + // This is not intended to be used by clients. See |address_of| + // below. + { + return NS_CONST_CAST(nsAutoPtr*, this); + } + +#else // CANT_RESOLVE_CPP_CONST_AMBIGUITY + + nsAutoPtr* + get_address() + // This is not intended to be used by clients. See |address_of| + // below. + { + return this; + } + + const nsAutoPtr* + get_address() const + // This is not intended to be used by clients. See |address_of| + // below. + { + return this; + } + +#endif // CANT_RESOLVE_CPP_CONST_AMBIGUITY + + public: + T& + operator*() const + { + NS_PRECONDITION(mRawPtr != 0, "You can't dereference a NULL nsAutoPtr with operator*()."); + return *get(); + } + + T** + StartAssignment() + { +#ifndef NSCAP_FEATURE_INLINE_STARTASSIGNMENT + return NS_REINTERPRET_CAST(T**, begin_assignment()); +#else + assign(0); + return NS_REINTERPRET_CAST(T**, &mRawPtr); +#endif + } + }; + +#ifdef CANT_RESOLVE_CPP_CONST_AMBIGUITY + +// This is the broken version for IRIX, which can't handle the version below. + +template +inline +nsAutoPtr* +address_of( const nsAutoPtr& aPtr ) + { + return aPtr.get_address(); + } + +#else // CANT_RESOLVE_CPP_CONST_AMBIGUITY + +template +inline +nsAutoPtr* +address_of( nsAutoPtr& aPtr ) + { + return aPtr.get_address(); + } + +template +inline +const nsAutoPtr* +address_of( const nsAutoPtr& aPtr ) + { + return aPtr.get_address(); + } + +#endif // CANT_RESOLVE_CPP_CONST_AMBIGUITY + +template +class nsAutoPtrGetterTransfers + /* + ... + + This class is designed to be used for anonymous temporary objects in the + argument list of calls that return COM interface pointers, e.g., + + nsAutoPtr fooP; + ...->GetTransferedPointer(getter_Transfers(fooP)) + + DO NOT USE THIS TYPE DIRECTLY IN YOUR CODE. Use |getter_Transfers()| instead. + + When initialized with a |nsAutoPtr|, as in the example above, it returns + a |void**|, a |T**|, or an |nsISupports**| as needed, that the + outer call (|GetTransferedPointer| in this case) can fill in. + + This type should be a nested class inside |nsAutoPtr|. + */ + { + public: + explicit + nsAutoPtrGetterTransfers( nsAutoPtr& aSmartPtr ) + : mTargetSmartPtr(aSmartPtr) + { + // nothing else to do + } + + operator void**() + { + return NS_REINTERPRET_CAST(void**, mTargetSmartPtr.StartAssignment()); + } + + operator T**() + { + return mTargetSmartPtr.StartAssignment(); + } + + T*& + operator*() + { + return *(mTargetSmartPtr.StartAssignment()); + } + + private: + nsAutoPtr& mTargetSmartPtr; + }; + +template +inline +nsAutoPtrGetterTransfers +getter_Transfers( nsAutoPtr& aSmartPtr ) + /* + Used around a |nsAutoPtr| when + ...makes the class |nsAutoPtrGetterTransfers| invisible. + */ + { + return nsAutoPtrGetterTransfers(aSmartPtr); + } + + + + // Comparing two |nsAutoPtr|s + +template +inline +NSCAP_BOOL +operator==( const nsAutoPtr& lhs, const nsAutoPtr& rhs ) + { + return NS_STATIC_CAST(const T*, lhs.get()) == NS_STATIC_CAST(const U*, rhs.get()); + } + + +template +inline +NSCAP_BOOL +operator!=( const nsAutoPtr& lhs, const nsAutoPtr& rhs ) + { + return NS_STATIC_CAST(const T*, lhs.get()) != NS_STATIC_CAST(const U*, rhs.get()); + } + + + // Comparing an |nsAutoPtr| to a raw pointer + +template +inline +NSCAP_BOOL +operator==( const nsAutoPtr& lhs, const U* rhs ) + { + return NS_STATIC_CAST(const T*, lhs.get()) == NS_STATIC_CAST(const U*, rhs); + } + +template +inline +NSCAP_BOOL +operator==( const U* lhs, const nsAutoPtr& rhs ) + { + return NS_STATIC_CAST(const U*, lhs) == NS_STATIC_CAST(const T*, rhs.get()); + } + +template +inline +NSCAP_BOOL +operator!=( const nsAutoPtr& lhs, const U* rhs ) + { + return NS_STATIC_CAST(const T*, lhs.get()) != NS_STATIC_CAST(const U*, rhs); + } + +template +inline +NSCAP_BOOL +operator!=( const U* lhs, const nsAutoPtr& rhs ) + { + return NS_STATIC_CAST(const U*, lhs) != NS_STATIC_CAST(const T*, rhs.get()); + } + + // To avoid ambiguities caused by the presence of builtin |operator==|s + // creating a situation where one of the |operator==| defined above + // has a better conversion for one argument and the builtin has a + // better conversion for the other argument, define additional + // |operator==| without the |const| on the raw pointer. + // See bug 65664 for details. + +#ifndef NSCAP_DONT_PROVIDE_NONCONST_OPEQ +template +inline +NSCAP_BOOL +operator==( const nsAutoPtr& lhs, U* rhs ) + { + return NS_STATIC_CAST(const T*, lhs.get()) == NS_CONST_CAST(const U*, rhs); + } + +template +inline +NSCAP_BOOL +operator==( U* lhs, const nsAutoPtr& rhs ) + { + return NS_CONST_CAST(const U*, lhs) == NS_STATIC_CAST(const T*, rhs.get()); + } + +template +inline +NSCAP_BOOL +operator!=( const nsAutoPtr& lhs, U* rhs ) + { + return NS_STATIC_CAST(const T*, lhs.get()) != NS_CONST_CAST(const U*, rhs); + } + +template +inline +NSCAP_BOOL +operator!=( U* lhs, const nsAutoPtr& rhs ) + { + return NS_CONST_CAST(const U*, lhs) != NS_STATIC_CAST(const T*, rhs.get()); + } +#endif + + + + // Comparing an |nsAutoPtr| to |0| + +template +inline +NSCAP_BOOL +operator==( const nsAutoPtr& lhs, NSCAP_Zero* rhs ) + // specifically to allow |smartPtr == 0| + { + return NS_STATIC_CAST(const void*, lhs.get()) == NS_REINTERPRET_CAST(const void*, rhs); + } + +template +inline +NSCAP_BOOL +operator==( NSCAP_Zero* lhs, const nsAutoPtr& rhs ) + // specifically to allow |0 == smartPtr| + { + return NS_REINTERPRET_CAST(const void*, lhs) == NS_STATIC_CAST(const void*, rhs.get()); + } + +template +inline +NSCAP_BOOL +operator!=( const nsAutoPtr& lhs, NSCAP_Zero* rhs ) + // specifically to allow |smartPtr != 0| + { + return NS_STATIC_CAST(const void*, lhs.get()) != NS_REINTERPRET_CAST(const void*, rhs); + } + +template +inline +NSCAP_BOOL +operator!=( NSCAP_Zero* lhs, const nsAutoPtr& rhs ) + // specifically to allow |0 != smartPtr| + { + return NS_REINTERPRET_CAST(const void*, lhs) != NS_STATIC_CAST(const void*, rhs.get()); + } + + +#ifdef HAVE_CPP_TROUBLE_COMPARING_TO_ZERO + + // We need to explicitly define comparison operators for `int' + // because the compiler is lame. + +template +inline +NSCAP_BOOL +operator==( const nsAutoPtr& lhs, int rhs ) + // specifically to allow |smartPtr == 0| + { + return NS_STATIC_CAST(const void*, lhs.get()) == NS_REINTERPRET_CAST(const void*, rhs); + } + +template +inline +NSCAP_BOOL +operator==( int lhs, const nsAutoPtr& rhs ) + // specifically to allow |0 == smartPtr| + { + return NS_REINTERPRET_CAST(const void*, lhs) == NS_STATIC_CAST(const void*, rhs.get()); + } + +#endif // !defined(HAVE_CPP_TROUBLE_COMPARING_TO_ZERO) + +/*****************************************************************************/ + +// template class nsAutoArrayPtrGetterTransfers; + +template +class nsAutoArrayPtr + { + private: + void** + begin_assignment() + { + assign(0); + return NS_REINTERPRET_CAST(void**, &mRawPtr); + } + + void + assign( T* newPtr ) + { + T* oldPtr = mRawPtr; + mRawPtr = newPtr; + delete [] oldPtr; + } + + private: + T* mRawPtr; + + public: + typedef T element_type; + + ~nsAutoArrayPtr() + { + delete [] mRawPtr; + } + + // Constructors + + nsAutoArrayPtr() + : mRawPtr(0) + // default constructor + { + } + + nsAutoArrayPtr( T* aRawPtr ) + : mRawPtr(aRawPtr) + // construct from a raw pointer (of the right type) + { + } + + nsAutoArrayPtr( nsAutoArrayPtr& aSmartPtr ) + : mRawPtr( aSmartPtr.forget() ) + // Construct by transferring ownership from another smart pointer. + { + } + + + // Assignment operators + + nsAutoArrayPtr& + operator=( T* rhs ) + // assign from a raw pointer (of the right type) + { + assign(rhs); + return *this; + } + + nsAutoArrayPtr& operator=( nsAutoArrayPtr& rhs ) + // assign by transferring ownership from another smart pointer. + { + assign(rhs.forget()); + return *this; + } + + // Other pointer operators + + T* + get() const + /* + Prefer the implicit conversion provided automatically by + |operator T*() const|. Use |get()| _only_ to resolve + ambiguity. + */ + { + return mRawPtr; + } + + operator T*() const + /* + ...makes an |nsAutoArrayPtr| act like its underlying raw pointer + type whenever it is used in a context where a raw pointer + is expected. It is this operator that makes an |nsAutoArrayPtr| + substitutable for a raw pointer. + + Prefer the implicit use of this operator to calling |get()|, + except where necessary to resolve ambiguity. + */ + { + return get(); + } + + T* + forget() + { + T* temp = mRawPtr; + mRawPtr = 0; + return temp; + } + + T* + operator->() const + { + NS_PRECONDITION(mRawPtr != 0, "You can't dereference a NULL nsAutoArrayPtr with operator->()."); + return get(); + } + +#ifdef CANT_RESOLVE_CPP_CONST_AMBIGUITY + // broken version for IRIX + + nsAutoArrayPtr* + get_address() const + // This is not intended to be used by clients. See |address_of| + // below. + { + return NS_CONST_CAST(nsAutoArrayPtr*, this); + } + +#else // CANT_RESOLVE_CPP_CONST_AMBIGUITY + + nsAutoArrayPtr* + get_address() + // This is not intended to be used by clients. See |address_of| + // below. + { + return this; + } + + const nsAutoArrayPtr* + get_address() const + // This is not intended to be used by clients. See |address_of| + // below. + { + return this; + } + +#endif // CANT_RESOLVE_CPP_CONST_AMBIGUITY + + public: + T& + operator*() const + { + NS_PRECONDITION(mRawPtr != 0, "You can't dereference a NULL nsAutoArrayPtr with operator*()."); + return *get(); + } + + T** + StartAssignment() + { +#ifndef NSCAP_FEATURE_INLINE_STARTASSIGNMENT + return NS_REINTERPRET_CAST(T**, begin_assignment()); +#else + assign(0); + return NS_REINTERPRET_CAST(T**, &mRawPtr); +#endif + } + }; + +#ifdef CANT_RESOLVE_CPP_CONST_AMBIGUITY + +// This is the broken version for IRIX, which can't handle the version below. + +template +inline +nsAutoArrayPtr* +address_of( const nsAutoArrayPtr& aPtr ) + { + return aPtr.get_address(); + } + +#else // CANT_RESOLVE_CPP_CONST_AMBIGUITY + +template +inline +nsAutoArrayPtr* +address_of( nsAutoArrayPtr& aPtr ) + { + return aPtr.get_address(); + } + +template +inline +const nsAutoArrayPtr* +address_of( const nsAutoArrayPtr& aPtr ) + { + return aPtr.get_address(); + } + +#endif // CANT_RESOLVE_CPP_CONST_AMBIGUITY + +template +class nsAutoArrayPtrGetterTransfers + /* + ... + + This class is designed to be used for anonymous temporary objects in the + argument list of calls that return COM interface pointers, e.g., + + nsAutoArrayPtr fooP; + ...->GetTransferedPointer(getter_Transfers(fooP)) + + DO NOT USE THIS TYPE DIRECTLY IN YOUR CODE. Use |getter_Transfers()| instead. + + When initialized with a |nsAutoArrayPtr|, as in the example above, it returns + a |void**|, a |T**|, or an |nsISupports**| as needed, that the + outer call (|GetTransferedPointer| in this case) can fill in. + + This type should be a nested class inside |nsAutoArrayPtr|. + */ + { + public: + explicit + nsAutoArrayPtrGetterTransfers( nsAutoArrayPtr& aSmartPtr ) + : mTargetSmartPtr(aSmartPtr) + { + // nothing else to do + } + + operator void**() + { + return NS_REINTERPRET_CAST(void**, mTargetSmartPtr.StartAssignment()); + } + + operator T**() + { + return mTargetSmartPtr.StartAssignment(); + } + + T*& + operator*() + { + return *(mTargetSmartPtr.StartAssignment()); + } + + private: + nsAutoArrayPtr& mTargetSmartPtr; + }; + +template +inline +nsAutoArrayPtrGetterTransfers +getter_Transfers( nsAutoArrayPtr& aSmartPtr ) + /* + Used around a |nsAutoArrayPtr| when + ...makes the class |nsAutoArrayPtrGetterTransfers| invisible. + */ + { + return nsAutoArrayPtrGetterTransfers(aSmartPtr); + } + + + + // Comparing two |nsAutoArrayPtr|s + +template +inline +NSCAP_BOOL +operator==( const nsAutoArrayPtr& lhs, const nsAutoArrayPtr& rhs ) + { + return NS_STATIC_CAST(const T*, lhs.get()) == NS_STATIC_CAST(const U*, rhs.get()); + } + + +template +inline +NSCAP_BOOL +operator!=( const nsAutoArrayPtr& lhs, const nsAutoArrayPtr& rhs ) + { + return NS_STATIC_CAST(const T*, lhs.get()) != NS_STATIC_CAST(const U*, rhs.get()); + } + + + // Comparing an |nsAutoArrayPtr| to a raw pointer + +template +inline +NSCAP_BOOL +operator==( const nsAutoArrayPtr& lhs, const U* rhs ) + { + return NS_STATIC_CAST(const T*, lhs.get()) == NS_STATIC_CAST(const U*, rhs); + } + +template +inline +NSCAP_BOOL +operator==( const U* lhs, const nsAutoArrayPtr& rhs ) + { + return NS_STATIC_CAST(const U*, lhs) == NS_STATIC_CAST(const T*, rhs.get()); + } + +template +inline +NSCAP_BOOL +operator!=( const nsAutoArrayPtr& lhs, const U* rhs ) + { + return NS_STATIC_CAST(const T*, lhs.get()) != NS_STATIC_CAST(const U*, rhs); + } + +template +inline +NSCAP_BOOL +operator!=( const U* lhs, const nsAutoArrayPtr& rhs ) + { + return NS_STATIC_CAST(const U*, lhs) != NS_STATIC_CAST(const T*, rhs.get()); + } + + // To avoid ambiguities caused by the presence of builtin |operator==|s + // creating a situation where one of the |operator==| defined above + // has a better conversion for one argument and the builtin has a + // better conversion for the other argument, define additional + // |operator==| without the |const| on the raw pointer. + // See bug 65664 for details. + +#ifndef NSCAP_DONT_PROVIDE_NONCONST_OPEQ +template +inline +NSCAP_BOOL +operator==( const nsAutoArrayPtr& lhs, U* rhs ) + { + return NS_STATIC_CAST(const T*, lhs.get()) == NS_CONST_CAST(const U*, rhs); + } + +template +inline +NSCAP_BOOL +operator==( U* lhs, const nsAutoArrayPtr& rhs ) + { + return NS_CONST_CAST(const U*, lhs) == NS_STATIC_CAST(const T*, rhs.get()); + } + +template +inline +NSCAP_BOOL +operator!=( const nsAutoArrayPtr& lhs, U* rhs ) + { + return NS_STATIC_CAST(const T*, lhs.get()) != NS_CONST_CAST(const U*, rhs); + } + +template +inline +NSCAP_BOOL +operator!=( U* lhs, const nsAutoArrayPtr& rhs ) + { + return NS_CONST_CAST(const U*, lhs) != NS_STATIC_CAST(const T*, rhs.get()); + } +#endif + + + + // Comparing an |nsAutoArrayPtr| to |0| + +template +inline +NSCAP_BOOL +operator==( const nsAutoArrayPtr& lhs, NSCAP_Zero* rhs ) + // specifically to allow |smartPtr == 0| + { + return NS_STATIC_CAST(const void*, lhs.get()) == NS_REINTERPRET_CAST(const void*, rhs); + } + +template +inline +NSCAP_BOOL +operator==( NSCAP_Zero* lhs, const nsAutoArrayPtr& rhs ) + // specifically to allow |0 == smartPtr| + { + return NS_REINTERPRET_CAST(const void*, lhs) == NS_STATIC_CAST(const void*, rhs.get()); + } + +template +inline +NSCAP_BOOL +operator!=( const nsAutoArrayPtr& lhs, NSCAP_Zero* rhs ) + // specifically to allow |smartPtr != 0| + { + return NS_STATIC_CAST(const void*, lhs.get()) != NS_REINTERPRET_CAST(const void*, rhs); + } + +template +inline +NSCAP_BOOL +operator!=( NSCAP_Zero* lhs, const nsAutoArrayPtr& rhs ) + // specifically to allow |0 != smartPtr| + { + return NS_REINTERPRET_CAST(const void*, lhs) != NS_STATIC_CAST(const void*, rhs.get()); + } + + +#ifdef HAVE_CPP_TROUBLE_COMPARING_TO_ZERO + + // We need to explicitly define comparison operators for `int' + // because the compiler is lame. + +template +inline +NSCAP_BOOL +operator==( const nsAutoArrayPtr& lhs, int rhs ) + // specifically to allow |smartPtr == 0| + { + return NS_STATIC_CAST(const void*, lhs.get()) == NS_REINTERPRET_CAST(const void*, rhs); + } + +template +inline +NSCAP_BOOL +operator==( int lhs, const nsAutoArrayPtr& rhs ) + // specifically to allow |0 == smartPtr| + { + return NS_REINTERPRET_CAST(const void*, lhs) == NS_STATIC_CAST(const void*, rhs.get()); + } + +#endif // !defined(HAVE_CPP_TROUBLE_COMPARING_TO_ZERO) + + +/*****************************************************************************/ + +// template class nsRefPtrGetterAddRefs; + +template +class nsRefPtr + { + private: + + void + assign_with_AddRef( T* rawPtr ) + { + if ( rawPtr ) + rawPtr->AddRef(); + assign_assuming_AddRef(rawPtr); + } + + void** + begin_assignment() + { + assign_assuming_AddRef(0); + return NS_REINTERPRET_CAST(void**, &mRawPtr); + } + + void + assign_assuming_AddRef( T* newPtr ) + { + T* oldPtr = mRawPtr; + mRawPtr = newPtr; + if ( oldPtr ) + oldPtr->Release(); + } + + private: + T* mRawPtr; + + public: + typedef T element_type; + + ~nsRefPtr() + { + if ( mRawPtr ) + mRawPtr->Release(); + } + + // Constructors + + nsRefPtr() + : mRawPtr(0) + // default constructor + { + } + + nsRefPtr( const nsRefPtr& aSmartPtr ) + : mRawPtr(aSmartPtr.mRawPtr) + // copy-constructor + { + if ( mRawPtr ) + mRawPtr->AddRef(); + } + + nsRefPtr( T* aRawPtr ) + : mRawPtr(aRawPtr) + // construct from a raw pointer (of the right type) + { + if ( mRawPtr ) + mRawPtr->AddRef(); + } + + nsRefPtr( const already_AddRefed& aSmartPtr ) + : mRawPtr(aSmartPtr.mRawPtr) + // construct from |dont_AddRef(expr)| + { + } + + // Assignment operators + + nsRefPtr& + operator=( const nsRefPtr& rhs ) + // copy assignment operator + { + assign_with_AddRef(rhs.mRawPtr); + return *this; + } + + nsRefPtr& + operator=( T* rhs ) + // assign from a raw pointer (of the right type) + { + assign_with_AddRef(rhs); + return *this; + } + + nsRefPtr& + operator=( const already_AddRefed& rhs ) + // assign from |dont_AddRef(expr)| + { + assign_assuming_AddRef(rhs.mRawPtr); + return *this; + } + + // Other pointer operators + + void + swap( nsRefPtr& rhs ) + // ...exchange ownership with |rhs|; can save a pair of refcount operations + { + T* temp = rhs.mRawPtr; + rhs.mRawPtr = mRawPtr; + mRawPtr = temp; + } + + void + swap( T*& rhs ) + // ...exchange ownership with |rhs|; can save a pair of refcount operations + { + T* temp = rhs; + rhs = mRawPtr; + mRawPtr = temp; + } + + nsDerivedSafe* + get() const + /* + Prefer the implicit conversion provided automatically by |operator nsDerivedSafe*() const|. + Use |get()| _only_ to resolve ambiguity. + + Returns a |nsDerivedSafe*| to deny clients the use of |AddRef| and |Release|. + */ + { + return NS_CONST_CAST(nsDerivedSafe*, + NS_REINTERPRET_CAST(const nsDerivedSafe*, mRawPtr)); + } + + operator nsDerivedSafe*() const + /* + ...makes an |nsRefPtr| act like its underlying raw pointer type (except against |AddRef()|, |Release()|, + and |delete|) whenever it is used in a context where a raw pointer is expected. It is this operator + that makes an |nsRefPtr| substitutable for a raw pointer. + + Prefer the implicit use of this operator to calling |get()|, except where necessary to resolve ambiguity. + */ + { + return get(); + } + + nsDerivedSafe* + operator->() const + { + NS_PRECONDITION(mRawPtr != 0, "You can't dereference a NULL nsRefPtr with operator->()."); + return get(); + } + +#ifdef CANT_RESOLVE_CPP_CONST_AMBIGUITY + // broken version for IRIX + + nsRefPtr* + get_address() const + // This is not intended to be used by clients. See |address_of| + // below. + { + return NS_CONST_CAST(nsRefPtr*, this); + } + +#else // CANT_RESOLVE_CPP_CONST_AMBIGUITY + + nsRefPtr* + get_address() + // This is not intended to be used by clients. See |address_of| + // below. + { + return this; + } + + const nsRefPtr* + get_address() const + // This is not intended to be used by clients. See |address_of| + // below. + { + return this; + } + +#endif // CANT_RESOLVE_CPP_CONST_AMBIGUITY + + public: + nsDerivedSafe& + operator*() const + { + NS_PRECONDITION(mRawPtr != 0, "You can't dereference a NULL nsRefPtr with operator*()."); + return *get(); + } + + T** + StartAssignment() + { +#ifndef NSCAP_FEATURE_INLINE_STARTASSIGNMENT + return NS_REINTERPRET_CAST(T**, begin_assignment()); +#else + assign_assuming_AddRef(0); + return NS_REINTERPRET_CAST(T**, &mRawPtr); +#endif + } + }; + +#ifdef CANT_RESOLVE_CPP_CONST_AMBIGUITY + +// This is the broken version for IRIX, which can't handle the version below. + +template +inline +nsRefPtr* +address_of( const nsRefPtr& aPtr ) + { + return aPtr.get_address(); + } + +#else // CANT_RESOLVE_CPP_CONST_AMBIGUITY + +template +inline +nsRefPtr* +address_of( nsRefPtr& aPtr ) + { + return aPtr.get_address(); + } + +template +inline +const nsRefPtr* +address_of( const nsRefPtr& aPtr ) + { + return aPtr.get_address(); + } + +#endif // CANT_RESOLVE_CPP_CONST_AMBIGUITY + +template +class nsRefPtrGetterAddRefs + /* + ... + + This class is designed to be used for anonymous temporary objects in the + argument list of calls that return COM interface pointers, e.g., + + nsRefPtr fooP; + ...->GetAddRefedPointer(getter_AddRefs(fooP)) + + DO NOT USE THIS TYPE DIRECTLY IN YOUR CODE. Use |getter_AddRefs()| instead. + + When initialized with a |nsRefPtr|, as in the example above, it returns + a |void**|, a |T**|, or an |nsISupports**| as needed, that the + outer call (|GetAddRefedPointer| in this case) can fill in. + + This type should be a nested class inside |nsRefPtr|. + */ + { + public: + explicit + nsRefPtrGetterAddRefs( nsRefPtr& aSmartPtr ) + : mTargetSmartPtr(aSmartPtr) + { + // nothing else to do + } + + operator void**() + { + return NS_REINTERPRET_CAST(void**, mTargetSmartPtr.StartAssignment()); + } + + operator T**() + { + return mTargetSmartPtr.StartAssignment(); + } + + T*& + operator*() + { + return *(mTargetSmartPtr.StartAssignment()); + } + + private: + nsRefPtr& mTargetSmartPtr; + }; + +template +inline +nsRefPtrGetterAddRefs +getter_AddRefs( nsRefPtr& aSmartPtr ) + /* + Used around a |nsRefPtr| when + ...makes the class |nsRefPtrGetterAddRefs| invisible. + */ + { + return nsRefPtrGetterAddRefs(aSmartPtr); + } + + + + // Comparing two |nsRefPtr|s + +template +inline +NSCAP_BOOL +operator==( const nsRefPtr& lhs, const nsRefPtr& rhs ) + { + return NS_STATIC_CAST(const T*, lhs.get()) == NS_STATIC_CAST(const U*, rhs.get()); + } + + +template +inline +NSCAP_BOOL +operator!=( const nsRefPtr& lhs, const nsRefPtr& rhs ) + { + return NS_STATIC_CAST(const T*, lhs.get()) != NS_STATIC_CAST(const U*, rhs.get()); + } + + + // Comparing an |nsRefPtr| to a raw pointer + +template +inline +NSCAP_BOOL +operator==( const nsRefPtr& lhs, const U* rhs ) + { + return NS_STATIC_CAST(const T*, lhs.get()) == NS_STATIC_CAST(const U*, rhs); + } + +template +inline +NSCAP_BOOL +operator==( const U* lhs, const nsRefPtr& rhs ) + { + return NS_STATIC_CAST(const U*, lhs) == NS_STATIC_CAST(const T*, rhs.get()); + } + +template +inline +NSCAP_BOOL +operator!=( const nsRefPtr& lhs, const U* rhs ) + { + return NS_STATIC_CAST(const T*, lhs.get()) != NS_STATIC_CAST(const U*, rhs); + } + +template +inline +NSCAP_BOOL +operator!=( const U* lhs, const nsRefPtr& rhs ) + { + return NS_STATIC_CAST(const U*, lhs) != NS_STATIC_CAST(const T*, rhs.get()); + } + + // To avoid ambiguities caused by the presence of builtin |operator==|s + // creating a situation where one of the |operator==| defined above + // has a better conversion for one argument and the builtin has a + // better conversion for the other argument, define additional + // |operator==| without the |const| on the raw pointer. + // See bug 65664 for details. + +#ifndef NSCAP_DONT_PROVIDE_NONCONST_OPEQ +template +inline +NSCAP_BOOL +operator==( const nsRefPtr& lhs, U* rhs ) + { + return NS_STATIC_CAST(const T*, lhs.get()) == NS_CONST_CAST(const U*, rhs); + } + +template +inline +NSCAP_BOOL +operator==( U* lhs, const nsRefPtr& rhs ) + { + return NS_CONST_CAST(const U*, lhs) == NS_STATIC_CAST(const T*, rhs.get()); + } + +template +inline +NSCAP_BOOL +operator!=( const nsRefPtr& lhs, U* rhs ) + { + return NS_STATIC_CAST(const T*, lhs.get()) != NS_CONST_CAST(const U*, rhs); + } + +template +inline +NSCAP_BOOL +operator!=( U* lhs, const nsRefPtr& rhs ) + { + return NS_CONST_CAST(const U*, lhs) != NS_STATIC_CAST(const T*, rhs.get()); + } +#endif + + + + // Comparing an |nsRefPtr| to |0| + +template +inline +NSCAP_BOOL +operator==( const nsRefPtr& lhs, NSCAP_Zero* rhs ) + // specifically to allow |smartPtr == 0| + { + return NS_STATIC_CAST(const void*, lhs.get()) == NS_REINTERPRET_CAST(const void*, rhs); + } + +template +inline +NSCAP_BOOL +operator==( NSCAP_Zero* lhs, const nsRefPtr& rhs ) + // specifically to allow |0 == smartPtr| + { + return NS_REINTERPRET_CAST(const void*, lhs) == NS_STATIC_CAST(const void*, rhs.get()); + } + +template +inline +NSCAP_BOOL +operator!=( const nsRefPtr& lhs, NSCAP_Zero* rhs ) + // specifically to allow |smartPtr != 0| + { + return NS_STATIC_CAST(const void*, lhs.get()) != NS_REINTERPRET_CAST(const void*, rhs); + } + +template +inline +NSCAP_BOOL +operator!=( NSCAP_Zero* lhs, const nsRefPtr& rhs ) + // specifically to allow |0 != smartPtr| + { + return NS_REINTERPRET_CAST(const void*, lhs) != NS_STATIC_CAST(const void*, rhs.get()); + } + + +#ifdef HAVE_CPP_TROUBLE_COMPARING_TO_ZERO + + // We need to explicitly define comparison operators for `int' + // because the compiler is lame. + +template +inline +NSCAP_BOOL +operator==( const nsRefPtr& lhs, int rhs ) + // specifically to allow |smartPtr == 0| + { + return NS_STATIC_CAST(const void*, lhs.get()) == NS_REINTERPRET_CAST(const void*, rhs); + } + +template +inline +NSCAP_BOOL +operator==( int lhs, const nsRefPtr& rhs ) + // specifically to allow |0 == smartPtr| + { + return NS_REINTERPRET_CAST(const void*, lhs) == NS_STATIC_CAST(const void*, rhs.get()); + } + +#endif // !defined(HAVE_CPP_TROUBLE_COMPARING_TO_ZERO) + +/*****************************************************************************/ + +#endif // !defined(nsAutoPtr_h___) diff --git a/src/libs/xpcom18a4/xpcom/base/nsCom.h b/src/libs/xpcom18a4/xpcom/base/nsCom.h new file mode 100644 index 00000000..54b0b8bf --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/base/nsCom.h @@ -0,0 +1,43 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +#ifndef nsCom_h__ +#define nsCom_h__ +#include "nscore.h" +#endif + + diff --git a/src/libs/xpcom18a4/xpcom/base/nsConsoleMessage.cpp b/src/libs/xpcom18a4/xpcom/base/nsConsoleMessage.cpp new file mode 100644 index 00000000..02dc589b --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/base/nsConsoleMessage.cpp @@ -0,0 +1,69 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* + * Base implementation for console messages. + */ + +#include "nsConsoleMessage.h" +#include "nsReadableUtils.h" + +NS_IMPL_THREADSAFE_ISUPPORTS1(nsConsoleMessage, nsIConsoleMessage) + +nsConsoleMessage::nsConsoleMessage() +{ +} + +nsConsoleMessage::nsConsoleMessage(const PRUnichar *message) +{ + mMessage.Assign(message); +} + +NS_IMETHODIMP +nsConsoleMessage::GetMessage(PRUnichar **result) { + *result = ToNewUnicode(mMessage); + + return NS_OK; +} + +// NS_IMETHODIMP +// nsConsoleMessage::Init(const PRUnichar *message) { +// nsAutoString newMessage(message); +// mMessage = ToNewUnicode(newMessage); +// return NS_OK; +// } + diff --git a/src/libs/xpcom18a4/xpcom/base/nsConsoleMessage.h b/src/libs/xpcom18a4/xpcom/base/nsConsoleMessage.h new file mode 100644 index 00000000..3d4a7e6c --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/base/nsConsoleMessage.h @@ -0,0 +1,58 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +#ifndef __nsconsolemessage_h__ +#define __nsconsolemessage_h__ + +#include "nsIConsoleMessage.h" +#include "nsString.h" + +class nsConsoleMessage : public nsIConsoleMessage { +public: + nsConsoleMessage(); + nsConsoleMessage(const PRUnichar *message); + + NS_DECL_ISUPPORTS + NS_DECL_NSICONSOLEMESSAGE + +private: + ~nsConsoleMessage() {} + + nsString mMessage; +}; + +#endif /* __nsconsolemessage_h__ */ diff --git a/src/libs/xpcom18a4/xpcom/base/nsConsoleService.cpp b/src/libs/xpcom18a4/xpcom/base/nsConsoleService.cpp new file mode 100644 index 00000000..1b369071 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/base/nsConsoleService.cpp @@ -0,0 +1,321 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* + * Maintains a circular buffer of recent messages, and notifies + * listeners when new messages are logged. + */ + +/* Threadsafe. */ + +#include "nsMemory.h" +#include "nsIServiceManager.h" +#include "nsIProxyObjectManager.h" +#include "nsSupportsArray.h" + +#include "nsConsoleService.h" +#include "nsConsoleMessage.h" + +NS_IMPL_THREADSAFE_ISUPPORTS1(nsConsoleService, nsIConsoleService) + +nsConsoleService::nsConsoleService() + : mCurrent(0), mFull(PR_FALSE), mListening(PR_FALSE), mLock(nsnull) +{ + // XXX grab this from a pref! + // hm, but worry about circularity, bc we want to be able to report + // prefs errs... + mBufferSize = 250; + + // XXX deal with these two allocations by detecting null mLock in factory? + mMessages = (nsIConsoleMessage **) + nsMemory::Alloc(mBufferSize * sizeof(nsIConsoleMessage *)); + + mLock = PR_NewLock(); + + // Array elements should be 0 initially for circular buffer algorithm. + for (PRUint32 i = 0; i < mBufferSize; i++) { + mMessages[i] = nsnull; + } + +} + +nsConsoleService::~nsConsoleService() +{ + PRUint32 i = 0; + while (i < mBufferSize && mMessages[i] != nsnull) { + NS_RELEASE(mMessages[i]); + i++; + } + +#ifdef DEBUG_mccabe + if (mListeners.Count() != 0) { + fprintf(stderr, + "WARNING - %d console error listeners still registered!\n" + "More calls to nsIConsoleService::UnregisterListener needed.\n", + mListeners.Count()); + } + +#endif + + nsMemory::Free(mMessages); + if (mLock) + PR_DestroyLock(mLock); +} + +static PRBool PR_CALLBACK snapshot_enum_func(nsHashKey *key, void *data, void* closure) +{ + nsISupportsArray *array = (nsISupportsArray *)closure; + + // Copy each element into the temporary nsSupportsArray... + array->AppendElement((nsISupports*)data); + return PR_TRUE; +} + +// nsIConsoleService methods +NS_IMETHODIMP +nsConsoleService::LogMessage(nsIConsoleMessage *message) +{ + if (message == nsnull) + return NS_ERROR_INVALID_ARG; + + nsSupportsArray listenersSnapshot; + nsIConsoleMessage *retiredMessage; + + NS_ADDREF(message); // early, in case it's same as replaced below. + + /* + * Lock while updating buffer, and while taking snapshot of + * listeners array. + */ + { + nsAutoLock lock(mLock); + + /* + * If there's already a message in the slot we're about to replace, + * we've wrapped around, and we need to release the old message. We + * save a pointer to it, so we can release below outside the lock. + */ + retiredMessage = mMessages[mCurrent]; + + mMessages[mCurrent++] = message; + if (mCurrent == mBufferSize) { + mCurrent = 0; // wrap around. + mFull = PR_TRUE; + } + + /* + * Copy the listeners into the snapshot array - in case a listener + * is removed during an Observe(...) notification... + */ + mListeners.Enumerate(snapshot_enum_func, &listenersSnapshot); + } + if (retiredMessage != nsnull) + NS_RELEASE(retiredMessage); + + /* + * Iterate through any registered listeners and tell them about + * the message. We use the mListening flag to guard against + * recursive message logs. This could sometimes result in + * listeners being skipped because of activity on other threads, + * when we only care about the recursive case. + */ + nsCOMPtr listener; + nsresult rv; + nsresult returned_rv; + PRUint32 snapshotCount; + rv = listenersSnapshot.Count(&snapshotCount); + if (NS_FAILED(rv)) + return rv; + + { + nsAutoLock lock(mLock); + if (mListening) + return NS_OK; + mListening = PR_TRUE; + } + + returned_rv = NS_OK; + for (PRUint32 i = 0; i < snapshotCount; i++) { + rv = listenersSnapshot.GetElementAt(i, getter_AddRefs(listener)); + if (NS_FAILED(rv)) { + returned_rv = rv; + break; // fall thru to mListening restore code below. + } + listener->Observe(message); + } + + { + nsAutoLock lock(mLock); + mListening = PR_FALSE; + } + + return returned_rv; +} + +NS_IMETHODIMP +nsConsoleService::LogStringMessage(const PRUnichar *message) +{ + nsConsoleMessage *msg = new nsConsoleMessage(message); + return this->LogMessage(msg); +} + +NS_IMETHODIMP +nsConsoleService::GetMessageArray(nsIConsoleMessage ***messages, PRUint32 *count) +{ + nsIConsoleMessage **messageArray; + + /* + * Lock the whole method, as we don't want anyone mucking with mCurrent or + * mFull while we're copying out the buffer. + */ + nsAutoLock lock(mLock); + + if (mCurrent == 0 && !mFull) { + /* + * Make a 1-length output array so that nobody gets confused, + * and return a count of 0. This should result in a 0-length + * array object when called from script. + */ + messageArray = (nsIConsoleMessage **) + nsMemory::Alloc(sizeof (nsIConsoleMessage *)); + *messageArray = nsnull; + *messages = messageArray; + *count = 0; + + return NS_OK; + } + + PRUint32 resultSize = mFull ? mBufferSize : mCurrent; + messageArray = + (nsIConsoleMessage **)nsMemory::Alloc((sizeof (nsIConsoleMessage *)) + * resultSize); + + if (messageArray == nsnull) { + *messages = nsnull; + *count = 0; + return NS_ERROR_FAILURE; + } + + PRUint32 i; + if (mFull) { + for (i = 0; i < mBufferSize; i++) { + // if full, fill the buffer starting from mCurrent (which'll be + // oldest) wrapping around the buffer to the most recent. + messageArray[i] = mMessages[(mCurrent + i) % mBufferSize]; + NS_ADDREF(messageArray[i]); + } + } else { + for (i = 0; i < mCurrent; i++) { + messageArray[i] = mMessages[i]; + NS_ADDREF(messageArray[i]); + } + } + *count = resultSize; + *messages = messageArray; + + return NS_OK; +} + +NS_IMETHODIMP +nsConsoleService::RegisterListener(nsIConsoleListener *listener) { + nsresult rv; + + /* + * Store a threadsafe proxy to the listener rather than the + * listener itself; we want the console service to be callable + * from any thread, but listeners can be implemented in + * thread-specific ways, and we always want to call them on their + * originating thread. JavaScript is the motivating example. + */ + nsCOMPtr proxiedListener; + + rv = GetProxyForListener(listener, getter_AddRefs(proxiedListener)); + if (NS_FAILED(rv)) + return rv; + + { + nsAutoLock lock(mLock); + nsISupportsKey key(listener); + + /* + * Put the proxy event listener into a hashtable using the *real* + * listener as the key. + * + * This is necessary because proxy objects do *not* maintain + * nsISupports identity. Therefore, since GetProxyForListener(...) + * can return different proxies for the same object (see bug #85831) + * we need to use the real object as the unique key... + */ + mListeners.Put(&key, proxiedListener); + } + return NS_OK; +} + +NS_IMETHODIMP +nsConsoleService::UnregisterListener(nsIConsoleListener *listener) { + nsAutoLock lock(mLock); + + nsISupportsKey key(listener); + mListeners.Remove(&key); + return NS_OK; +} + +nsresult +nsConsoleService::GetProxyForListener(nsIConsoleListener* aListener, + nsIConsoleListener** aProxy) +{ + nsresult rv; + *aProxy = nsnull; + + nsCOMPtr proxyManager = + (do_GetService(NS_XPCOMPROXY_CONTRACTID)); + + if (proxyManager == nsnull) + return NS_ERROR_NOT_AVAILABLE; + + /* + * NOTE this will fail if the calling thread doesn't have an eventQ. + * + * Would it be better to catch that case and leave the listener unproxied? + */ + rv = proxyManager->GetProxyForObject(NS_CURRENT_EVENTQ, + NS_GET_IID(nsIConsoleListener), + aListener, + PROXY_ASYNC | PROXY_ALWAYS, + (void**) aProxy); + return rv; +} diff --git a/src/libs/xpcom18a4/xpcom/base/nsConsoleService.h b/src/libs/xpcom18a4/xpcom/base/nsConsoleService.h new file mode 100644 index 00000000..59758f84 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/base/nsConsoleService.h @@ -0,0 +1,89 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* + * nsConsoleService class declaration. + */ + +#ifndef __nsconsoleservice_h__ +#define __nsconsoleservice_h__ + +#include "nsCOMPtr.h" +#include "nsHashtable.h" +#include "nsAutoLock.h" + +#include "nsIConsoleService.h" + +class nsConsoleService : public nsIConsoleService +{ +public: + nsConsoleService(); + + NS_DECL_ISUPPORTS + NS_DECL_NSICONSOLESERVICE + +private: + ~nsConsoleService(); + + // build (or find) a proxy for the listener + nsresult GetProxyForListener(nsIConsoleListener* aListener, + nsIConsoleListener** aProxy); + + // Circular buffer of saved messages + nsIConsoleMessage **mMessages; + + // How big? + PRUint32 mBufferSize; + + // Index of slot in mMessages that'll be filled by *next* log message + PRUint32 mCurrent; + + // Is the buffer full? (Has mCurrent wrapped around at least once?) + PRBool mFull; + + // Listeners to notify whenever a new message is logged. + nsSupportsHashtable mListeners; + + // Current listener being notified of a logged error - to prevent + // stack overflows. + PRBool mListening; + + // To serialize interesting methods. + PRLock *mLock; +}; + +#endif /* __nsconsoleservice_h__ */ diff --git a/src/libs/xpcom18a4/xpcom/base/nsDebugImpl.cpp b/src/libs/xpcom18a4/xpcom/base/nsDebugImpl.cpp new file mode 100644 index 00000000..f8806092 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/base/nsDebugImpl.cpp @@ -0,0 +1,477 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * IBM Corp. + * Henry Sobotka + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsXPCOMPrivate.h" +#include "nsDebugImpl.h" +#include "nsDebug.h" +#include "prprf.h" +#include "prlog.h" +#include "prinit.h" +#include "plstr.h" +#include "nsError.h" +#include "prerror.h" +#include "prerr.h" + +#if defined(XP_BEOS) +/* For DEBUGGER macros */ +#include +#endif + +#if defined(XP_UNIX) || defined(_WIN32) || defined(XP_OS2) || defined(XP_BEOS) +/* for abort() and getenv() */ +#include +#endif + +#if defined(XP_UNIX) && !defined(UNIX_CRASH_ON_ASSERT) +#include +/* for nsTraceRefcnt::WalkTheStack() */ +#include "nsISupportsUtils.h" +#include "nsTraceRefcntImpl.h" + +#if defined(__GNUC__) && defined(__i386) +# define DebugBreak() { asm("int $3"); } +#elif defined(__APPLE__) && defined(TARGET_CARBON) +# include "MacTypes.h" +# define DebugBreak() { Debugger(); } +#else +# define DebugBreak() +#endif +#endif + +#if defined(XP_OS2) + /* Added definitions for DebugBreak() for 2 different OS/2 compilers. Doing + * the int3 on purpose so that a developer can step over the + * instruction if so desired. Not always possible if trapping due to exception + * handling IBM-AKR + */ + #define INCL_WINDIALOGS // need for WinMessageBox + #include + #include + + #if defined(DEBUG) + #define DebugBreak() { asm("int $3"); } + #else + #define DebugBreak() + #endif /* DEBUG */ +#endif /* XP_OS2 */ + +#if defined(_WIN32) +#include +#include +#elif defined(XP_MAC) + #define TEMP_MAC_HACK + + //------------------------ + #ifdef TEMP_MAC_HACK + #include + #include + #include + + // TEMPORARY UNTIL WE HAVE MACINTOSH ENVIRONMENT VARIABLES THAT CAN TURN ON + // LOGGING ON MACINTOSH + // At this moment, NSPR's logging is a no-op on Macintosh. + + #include + #include + + #undef PR_LOG + #undef PR_LogFlush + #define PR_LOG(module,level,args) dprintf args + #define PR_LogFlush() + static void dprintf(const char *format, ...) + { + va_list ap; + Str255 buffer; + + va_start(ap, format); + buffer[0] = std::vsnprintf((char *)buffer + 1, sizeof(buffer) - 1, format, ap); + va_end(ap); + if (PL_strcasestr((char *)&buffer[1], "warning")) + printf("¥¥¥%s\n", (char*)buffer + 1); + else + DebugStr(buffer); + } + #endif // TEMP_MAC_HACK + //------------------------ +#elif defined(XP_UNIX) +#include +#endif + +/* + * Determine if debugger is present in windows. + */ +#if defined (_WIN32) + +typedef WINBASEAPI BOOL (WINAPI* LPFNISDEBUGGERPRESENT)(); +PRBool InDebugger() +{ + PRBool fReturn = PR_FALSE; + LPFNISDEBUGGERPRESENT lpfnIsDebuggerPresent = NULL; + HINSTANCE hKernel = LoadLibrary("Kernel32.dll"); + + if(hKernel) + { + lpfnIsDebuggerPresent = + (LPFNISDEBUGGERPRESENT)GetProcAddress(hKernel, "IsDebuggerPresent"); + if(lpfnIsDebuggerPresent) + { + fReturn = (*lpfnIsDebuggerPresent)(); + } + FreeLibrary(hKernel); + } + + return fReturn; +} + +#endif /* WIN32*/ + +NS_IMPL_THREADSAFE_ISUPPORTS1(nsDebugImpl, nsIDebug) + +nsDebugImpl::nsDebugImpl() +{ +} + +/** + * Implementation of the nsDebug methods. Note that this code is + * always compiled in, in case some other module that uses it is + * compiled with debugging even if this library is not. + */ +static PRLogModuleInfo* gDebugLog; + +static void InitLog(void) +{ + if (0 == gDebugLog) { + gDebugLog = PR_NewLogModule("nsDebug"); + gDebugLog->level = PR_LOG_DEBUG; + } +} + + + +NS_IMETHODIMP +nsDebugImpl::Assertion(const char *aStr, const char *aExpr, const char *aFile, PRInt32 aLine) +{ + InitLog(); + + char buf[1000]; + PR_snprintf(buf, sizeof(buf), + "###!!! ASSERTION: %s: '%s', file %s, line %d", + aStr, aExpr, aFile, aLine); + + // Write out the assertion message to the debug log + PR_LOG(gDebugLog, PR_LOG_ERROR, ("%s", buf)); + PR_LogFlush(); + + // And write it out to the stderr + fprintf(stderr, "%s\n", buf); + fflush(stderr); + +#if defined(_WIN32) + char* assertBehavior = getenv("XPCOM_DEBUG_BREAK"); + if (assertBehavior && strcmp(assertBehavior, "warn") == 0) + return NS_OK; + + if(!InDebugger()) + { + DWORD code = IDRETRY; + + /* Create the debug dialog out of process to avoid the crashes caused by + * Windows events leaking into our event loop from an in process dialog. + * We do this by launching windbgdlg.exe (built in xpcom/windbgdlg). + * See http://bugzilla.mozilla.org/show_bug.cgi?id=54792 + */ + PROCESS_INFORMATION pi; + STARTUPINFO si; + char executable[MAX_PATH]; + char* pName; + + memset(&pi, 0, sizeof(pi)); + + memset(&si, 0, sizeof(si)); + si.cb = sizeof(si); + si.wShowWindow = SW_SHOW; + + if(GetModuleFileName(GetModuleHandle(XPCOM_DLL), executable, MAX_PATH) && + NULL != (pName = strrchr(executable, '\\')) && + NULL != strcpy(pName+1, "windbgdlg.exe") && +#ifdef DEBUG_jband + (printf("Launching %s\n", executable), PR_TRUE) && +#endif + CreateProcess(executable, buf, NULL, NULL, PR_FALSE, + DETACHED_PROCESS | NORMAL_PRIORITY_CLASS, + NULL, NULL, &si, &pi) && + WAIT_OBJECT_0 == WaitForSingleObject(pi.hProcess, INFINITE) && + GetExitCodeProcess(pi.hProcess, &code)) + { + CloseHandle(pi.hProcess); + } + + switch(code) + { + case IDABORT: + //This should exit us + raise(SIGABRT); + //If we are ignored exit this way.. + _exit(3); + break; + + case IDIGNORE: + return NS_OK; + // Fall Through + } + } +#endif + +#if defined(XP_OS2) + char* assertBehavior = getenv("XPCOM_DEBUG_BREAK"); + if (assertBehavior && strcmp(assertBehavior, "warn") == 0) + return NS_OK; + + char msg[1200]; + PR_snprintf(msg, sizeof(msg), + "%s\n\nClick Cancel to Debug Application.\n" + "Click Enter to continue running the Application.", buf); + ULONG code = MBID_ERROR; + code = WinMessageBox(HWND_DESKTOP, HWND_DESKTOP, msg, + "nsDebug::Assertion", 0, + MB_ERROR | MB_ENTERCANCEL); + + /* It is possible that we are executing on a thread that doesn't have a + * message queue. In that case, the message won't appear, and code will + * be 0xFFFF. We'll give the user a chance to debug it by calling + * Break() + * Actually, that's a really bad idea since this happens a lot with threadsafe + * assertions and since it means that you can't actually run the debug build + * outside a debugger without it crashing constantly. + */ + if(( code == MBID_ENTER ) || (code == MBID_ERROR)) + { + return NS_OK; + // If Retry, Fall Through + } +#endif + + Break(aFile, aLine); + return NS_OK; +} + +NS_IMETHODIMP +nsDebugImpl::Break(const char *aFile, PRInt32 aLine) +{ +#ifndef TEMP_MAC_HACK + // Write out the assertion message to the debug log + InitLog(); + + PR_LOG(gDebugLog, PR_LOG_ERROR, + ("###!!! Break: at file %s, line %d", aFile, aLine)); + PR_LogFlush(); + + fprintf(stderr, "Break: at file %s, line %d\n",aFile, aLine); fflush(stderr); + fflush(stderr); + +#if defined(_WIN32) +#ifdef _M_IX86 + ::DebugBreak(); +#endif +#elif defined(XP_UNIX) && !defined(UNIX_CRASH_ON_ASSERT) + fprintf(stderr, "\07"); + + char *assertBehavior = getenv("XPCOM_DEBUG_BREAK"); + + if (!assertBehavior) { + + // the default; nothing else to do + ; + + } else if ( strcmp(assertBehavior, "suspend")== 0 ) { + + // the suspend case is first because we wanna send the signal before + // other threads have had a chance to get too far from the state that + // caused this assertion (in case they happen to have been involved). + // + fprintf(stderr, "Suspending process; attach with the debugger.\n"); + kill(0, SIGSTOP); + + } else if ( strcmp(assertBehavior, "warn")==0 ) { + + // same as default; nothing else to do (see "suspend" case comment for + // why this compare isn't done as part of the default case) + // + ; + + } + else if ( strcmp(assertBehavior,"stack")==0 ) { + + // walk the stack + // + nsTraceRefcntImpl::WalkTheStack(stderr); + } + else if ( strcmp(assertBehavior,"abort")==0 ) { + + // same as UNIX_CRASH_ON_ASSERT + // + Abort(aFile, aLine); + + } else if ( strcmp(assertBehavior,"trap")==0 ) { + + DebugBreak(); + + } else { + + fprintf(stderr, "unrecognized value of XPCOM_DEBUG_BREAK env var!\n"); + + } + fflush(stderr); // this shouldn't really be necessary, i don't think, + // but maybe there's some lame stdio that buffers stderr + +#elif defined(XP_BEOS) + { +#ifdef UNIX_CRASH_ON_ASSERT + char buf[2000]; + sprintf(buf, "Break: at file %s, line %d", aFile, aLine); + DEBUGGER(buf); +#endif + } +#else + Abort(aFile, aLine); +#endif +#endif // TEMP_MAC_HACK + return NS_OK; +} + +NS_IMETHODIMP +nsDebugImpl::Abort(const char *aFile, PRInt32 aLine) +{ + InitLog(); + + PR_LOG(gDebugLog, PR_LOG_ERROR, + ("###!!! Abort: at file %s, line %d", aFile, aLine)); + PR_LogFlush(); + fprintf(stderr, "\07 Abort\n"); fflush(stderr); + fflush(stderr); + +#if defined(_WIN32) +#ifdef _M_IX86 + long* __p = (long*) 0x7; + *__p = 0x7; +#else /* _M_ALPHA */ + PR_Abort(); +#endif +#elif defined(XP_MAC) + ExitToShell(); +#elif defined(XP_UNIX) + PR_Abort(); +#elif defined(XP_OS2) + DebugBreak(); + return NS_OK; +#elif defined(XP_BEOS) + { +#ifndef DEBUG_cls + char buf[2000]; + sprintf(buf, "Abort: at file %s, line %d", aFile, aLine); + DEBUGGER(buf); +#endif + } +#endif + return NS_OK; +} + +NS_IMETHODIMP +nsDebugImpl::Warning(const char* aMessage, + const char* aFile, PRIntn aLine) +{ + InitLog(); + + char buf[1000]; + PR_snprintf(buf, sizeof(buf), + "WARNING: %s, file %s, line %d", + aMessage, aFile, aLine); + + // Write out the warning message to the debug log + PR_LOG(gDebugLog, PR_LOG_ERROR, ("%s", buf)); + + // And write it out to the stdout + fprintf(stderr, "%s\n", buf); + fflush(stderr); + return NS_OK; +} + +NS_METHOD +nsDebugImpl::Create(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr) +{ + *aInstancePtr = nsnull; + nsIDebug* debug = new nsDebugImpl(); + if (!debug) + return NS_ERROR_OUT_OF_MEMORY; + + nsresult rv = debug->QueryInterface(aIID, aInstancePtr); + if (NS_FAILED(rv)) { + delete debug; + } + + return rv; +} + +//////////////////////////////////////////////////////////////////////////////// + +NS_COM nsresult +NS_ErrorAccordingToNSPR() +{ + PRErrorCode err = PR_GetError(); + switch (err) { + case PR_OUT_OF_MEMORY_ERROR: return NS_ERROR_OUT_OF_MEMORY; + case PR_WOULD_BLOCK_ERROR: return NS_BASE_STREAM_WOULD_BLOCK; + case PR_FILE_NOT_FOUND_ERROR: return NS_ERROR_FILE_NOT_FOUND; + case PR_READ_ONLY_FILESYSTEM_ERROR: return NS_ERROR_FILE_READ_ONLY; + case PR_NOT_DIRECTORY_ERROR: return NS_ERROR_FILE_NOT_DIRECTORY; + case PR_IS_DIRECTORY_ERROR: return NS_ERROR_FILE_IS_DIRECTORY; + case PR_LOOP_ERROR: return NS_ERROR_FILE_UNRESOLVABLE_SYMLINK; + case PR_FILE_EXISTS_ERROR: return NS_ERROR_FILE_ALREADY_EXISTS; + case PR_FILE_IS_LOCKED_ERROR: return NS_ERROR_FILE_IS_LOCKED; + case PR_FILE_TOO_BIG_ERROR: return NS_ERROR_FILE_TOO_BIG; + case PR_NO_DEVICE_SPACE_ERROR: return NS_ERROR_FILE_NO_DEVICE_SPACE; + case PR_NAME_TOO_LONG_ERROR: return NS_ERROR_FILE_NAME_TOO_LONG; + case PR_DIRECTORY_NOT_EMPTY_ERROR: return NS_ERROR_FILE_DIR_NOT_EMPTY; + case PR_NO_ACCESS_RIGHTS_ERROR: return NS_ERROR_FILE_ACCESS_DENIED; + default: return NS_ERROR_FAILURE; + } +} + +//////////////////////////////////////////////////////////////////////////////// + diff --git a/src/libs/xpcom18a4/xpcom/base/nsDebugImpl.h b/src/libs/xpcom18a4/xpcom/base/nsDebugImpl.h new file mode 100644 index 00000000..b6ca9770 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/base/nsDebugImpl.h @@ -0,0 +1,61 @@ +/* ***** 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 XPCOM + * + * The Initial Developer of the Original Code is Doug Turner + * + * Portions created by the Initial Developer are Copyright (C) 2003 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * 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 "nsIDebug.h" + +class nsDebugImpl : public nsIDebug +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIDEBUG + + nsDebugImpl(); + static NS_METHOD Create(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr); + +private: + ~nsDebugImpl() {} +}; + + +#define NS_DEBUG_CONTRACTID "@mozilla.org/xpcom/debug;1" +#define NS_DEBUG_CLASSNAME "nsDebug Interface" +#define NS_DEBUG_CID \ +{ /* a80b1fb3-aaf6-4852-b678-c27eb7a518af */ \ + 0xa80b1fb3, \ + 0xaaf6, \ + 0x4852, \ + {0xb6, 0x78, 0xc2, 0x7e, 0xb7, 0xa5, 0x18, 0xaf} \ +} diff --git a/src/libs/xpcom18a4/xpcom/base/nsError.h b/src/libs/xpcom18a4/xpcom/base/nsError.h new file mode 100644 index 00000000..e0f3fe54 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/base/nsError.h @@ -0,0 +1,317 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +#ifndef nsError_h__ +#define nsError_h__ + +#ifndef nscore_h___ +#include "nscore.h" /* needed for nsresult */ +#endif + +/* + * To add error code to your module, you need to do the following: + * + * 1) Add a module offset code. Add yours to the bottom of the list + * right below this comment, adding 1. + * + * 2) In your module, define a header file which uses one of the + * NE_ERROR_GENERATExxxxxx macros. Some examples below: + * + * #define NS_ERROR_MYMODULE_MYERROR1 NS_ERROR_GENERATE(NS_ERROR_SEVERITY_ERROR,NS_ERROR_MODULE_MYMODULE,1) + * #define NS_ERROR_MYMODULE_MYERROR2 NS_ERROR_GENERATE_SUCCESS(NS_ERROR_MODULE_MYMODULE,2) + * #define NS_ERROR_MYMODULE_MYERROR3 NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_MYMODULE,3) + * + */ + + +/** + * @name Standard Module Offset Code. Each Module should identify a unique number + * and then all errors associated with that module become offsets from the + * base associated with that module id. There are 16 bits of code bits for + * each module. + */ + +#define NS_ERROR_MODULE_XPCOM 1 +#define NS_ERROR_MODULE_BASE 2 +#define NS_ERROR_MODULE_GFX 3 +#define NS_ERROR_MODULE_WIDGET 4 +#define NS_ERROR_MODULE_CALENDAR 5 +#define NS_ERROR_MODULE_NETWORK 6 +#define NS_ERROR_MODULE_PLUGINS 7 +#define NS_ERROR_MODULE_LAYOUT 8 +#define NS_ERROR_MODULE_HTMLPARSER 9 +#define NS_ERROR_MODULE_RDF 10 +#define NS_ERROR_MODULE_UCONV 11 +#define NS_ERROR_MODULE_REG 12 +#define NS_ERROR_MODULE_FILES 13 +#define NS_ERROR_MODULE_DOM 14 +#define NS_ERROR_MODULE_IMGLIB 15 +#define NS_ERROR_MODULE_MAILNEWS 16 +#define NS_ERROR_MODULE_EDITOR 17 +#define NS_ERROR_MODULE_XPCONNECT 18 +#define NS_ERROR_MODULE_PROFILE 19 +#define NS_ERROR_MODULE_LDAP 20 +#define NS_ERROR_MODULE_SECURITY 21 +#define NS_ERROR_MODULE_DOM_XPATH 22 +#define NS_ERROR_MODULE_DOM_RANGE 23 +#define NS_ERROR_MODULE_URILOADER 24 +#define NS_ERROR_MODULE_CONTENT 25 +#define NS_ERROR_MODULE_PYXPCOM 26 +#define NS_ERROR_MODULE_XSLT 27 +#define NS_ERROR_MODULE_IPC 28 +#define NS_ERROR_MODULE_SVG 29 + +/* NS_ERROR_MODULE_GENERAL should be used by modules that do not + * care if return code values overlap. Callers of methods that + * return such codes should be aware that they are not + * globally unique. Implementors should be careful about blindly + * returning codes from other modules that might also use + * the generic base. + */ +#define NS_ERROR_MODULE_GENERAL 51 + +/** + * @name Standard Error Handling Macros + */ + +#define NS_FAILED(_nsresult) (NS_UNLIKELY((_nsresult) & 0x80000000)) +#define NS_SUCCEEDED(_nsresult) (NS_LIKELY(!((_nsresult) & 0x80000000))) + +/** + * @name Severity Code. This flag identifies the level of warning + */ + +#define NS_ERROR_SEVERITY_SUCCESS 0 +#define NS_ERROR_SEVERITY_ERROR 1 + +/** + * @name Mozilla Code. This flag separates consumers of mozilla code + * from the native platform + */ + +#define NS_ERROR_MODULE_BASE_OFFSET 0x45 + +/** + * @name Standard Error Generating Macros + */ + +#define NS_ERROR_GENERATE(sev,module,code) \ + ((nsresult) (((PRUint32)(sev)<<31) | ((PRUint32)(module+NS_ERROR_MODULE_BASE_OFFSET)<<16) | ((PRUint32)(code))) ) + +#define NS_ERROR_GENERATE_SUCCESS(module,code) \ + ((nsresult) (((PRUint32)(NS_ERROR_SEVERITY_SUCCESS)<<31) | ((PRUint32)(module+NS_ERROR_MODULE_BASE_OFFSET)<<16) | ((PRUint32)(code))) ) + +#define NS_ERROR_GENERATE_FAILURE(module,code) \ + ((nsresult) (((PRUint32)(NS_ERROR_SEVERITY_ERROR)<<31) | ((PRUint32)(module+NS_ERROR_MODULE_BASE_OFFSET)<<16) | ((PRUint32)(code))) ) + +/** + * @name Standard Macros for retrieving error bits + */ + +#define NS_ERROR_GET_CODE(err) ((err) & 0xffff) +#define NS_ERROR_GET_MODULE(err) (((((err) >> 16) - NS_ERROR_MODULE_BASE_OFFSET) & 0x1fff)) +#define NS_ERROR_GET_SEVERITY(err) (((err) >> 31) & 0x1) + +/** + * @name Standard return values + */ + +/*@{*/ + +/* Standard "it worked" return value */ +#define NS_OK 0 + +#define NS_ERROR_BASE ((nsresult) 0xC1F30000) + +/* Returned when an instance is not initialized */ +#define NS_ERROR_NOT_INITIALIZED (NS_ERROR_BASE + 1) + +/* Returned when an instance is already initialized */ +#define NS_ERROR_ALREADY_INITIALIZED (NS_ERROR_BASE + 2) + +/* Returned by a not implemented function */ +#define NS_ERROR_NOT_IMPLEMENTED ((nsresult) 0x80004001L) + +/* Returned when a given interface is not supported. */ +#define NS_NOINTERFACE ((nsresult) 0x80004002L) +#define NS_ERROR_NO_INTERFACE NS_NOINTERFACE + +#define NS_ERROR_INVALID_POINTER ((nsresult) 0x80004003L) +#define NS_ERROR_NULL_POINTER NS_ERROR_INVALID_POINTER + +/* Returned when a function aborts */ +#define NS_ERROR_ABORT ((nsresult) 0x80004004L) + +/* Returned when a function fails */ +#define NS_ERROR_FAILURE ((nsresult) 0x80004005L) + +/* Returned when an IPC fails */ +#define NS_ERROR_CALL_FAILED ((nsresult) 0x800706beL) + +/* Returned when an unexpected error occurs */ +#define NS_ERROR_UNEXPECTED ((nsresult) 0x8000ffffL) + +/* Returned when a memory allocation fails */ +#define NS_ERROR_OUT_OF_MEMORY ((nsresult) 0x8007000eL) + +/* Returned when an illegal value is passed */ +#define NS_ERROR_ILLEGAL_VALUE ((nsresult) 0x80070057L) +#define NS_ERROR_INVALID_ARG NS_ERROR_ILLEGAL_VALUE + +/* Returned when a class doesn't allow aggregation */ +#define NS_ERROR_NO_AGGREGATION ((nsresult) 0x80040110L) + +/* Returned when an operation can't complete due to an unavailable resource */ +#define NS_ERROR_NOT_AVAILABLE ((nsresult) 0x80040111L) + +/* Returned when a class is not registered */ +#define NS_ERROR_FACTORY_NOT_REGISTERED ((nsresult) 0x80040154L) + +/* Returned when a class cannot be registered, but may be tried again later */ +#define NS_ERROR_FACTORY_REGISTER_AGAIN ((nsresult) 0x80040155L) + +/* Returned when a dynamically loaded factory couldn't be found */ +#define NS_ERROR_FACTORY_NOT_LOADED ((nsresult) 0x800401f8L) + +/* Returned when a factory doesn't support signatures */ +#define NS_ERROR_FACTORY_NO_SIGNATURE_SUPPORT \ + (NS_ERROR_BASE + 0x101) + +/* Returned when a factory already is registered */ +#define NS_ERROR_FACTORY_EXISTS (NS_ERROR_BASE + 0x100) + +/* Socket failures */ +#define NS_ERROR_SOCKET_FAIL (NS_ERROR_BASE + 0x200) + + +/* For COM compatibility reasons, we want to use exact error code numbers + for NS_ERROR_PROXY_INVALID_IN_PARAMETER and NS_ERROR_PROXY_INVALID_OUT_PARAMETER. + The first matches: + + #define RPC_E_INVALID_PARAMETER _HRESULT_TYPEDEF_(0x80010010L) + + Errors returning this mean that the xpcom proxy code could not create a proxy for + one of the in paramaters. + + Because of this, we are ignoring the convention if using a base and offset for + error numbers. + +*/ + +/* Returned when a proxy could not be create a proxy for one of the IN parameters + This is returned only when the "real" meathod has NOT been invoked. +*/ + +#define NS_ERROR_PROXY_INVALID_IN_PARAMETER ((nsresult) 0x80010010L) + +/* Returned when a proxy could not be create a proxy for one of the OUT parameters + This is returned only when the "real" meathod has ALREADY been invoked. +*/ + +#define NS_ERROR_PROXY_INVALID_OUT_PARAMETER ((nsresult) 0x80010011L) + + +/*@}*/ + + /* I/O Errors */ + + /* Stream closed */ +#define NS_BASE_STREAM_CLOSED NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_BASE, 2) + /* Error from the operating system */ +#define NS_BASE_STREAM_OSERROR NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_BASE, 3) + /* Illegal arguments */ +#define NS_BASE_STREAM_ILLEGAL_ARGS NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_BASE, 4) + /* For unichar streams */ +#define NS_BASE_STREAM_NO_CONVERTER NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_BASE, 5) + /* For unichar streams */ +#define NS_BASE_STREAM_BAD_CONVERSION NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_BASE, 6) + +#define NS_BASE_STREAM_WOULD_BLOCK NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_BASE, 7) + + +#define NS_ERROR_FILE_UNRECOGNIZED_PATH NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_FILES, 1) +#define NS_ERROR_FILE_UNRESOLVABLE_SYMLINK NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_FILES, 2) +#define NS_ERROR_FILE_EXECUTION_FAILED NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_FILES, 3) +#define NS_ERROR_FILE_UNKNOWN_TYPE NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_FILES, 4) +#define NS_ERROR_FILE_DESTINATION_NOT_DIR NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_FILES, 5) +#define NS_ERROR_FILE_TARGET_DOES_NOT_EXIST NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_FILES, 6) +#define NS_ERROR_FILE_COPY_OR_MOVE_FAILED NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_FILES, 7) +#define NS_ERROR_FILE_ALREADY_EXISTS NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_FILES, 8) +#define NS_ERROR_FILE_INVALID_PATH NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_FILES, 9) +#define NS_ERROR_FILE_DISK_FULL NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_FILES, 10) +#define NS_ERROR_FILE_CORRUPTED NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_FILES, 11) +#define NS_ERROR_FILE_NOT_DIRECTORY NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_FILES, 12) +#define NS_ERROR_FILE_IS_DIRECTORY NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_FILES, 13) +#define NS_ERROR_FILE_IS_LOCKED NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_FILES, 14) +#define NS_ERROR_FILE_TOO_BIG NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_FILES, 15) +#define NS_ERROR_FILE_NO_DEVICE_SPACE NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_FILES, 16) +#define NS_ERROR_FILE_NAME_TOO_LONG NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_FILES, 17) +#define NS_ERROR_FILE_NOT_FOUND NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_FILES, 18) +#define NS_ERROR_FILE_READ_ONLY NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_FILES, 19) +#define NS_ERROR_FILE_DIR_NOT_EMPTY NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_FILES, 20) +#define NS_ERROR_FILE_ACCESS_DENIED NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_FILES, 21) + +#define NS_SUCCESS_FILE_DIRECTORY_EMPTY NS_ERROR_GENERATE_SUCCESS(NS_ERROR_MODULE_FILES, 1) + + /* Result codes used by nsIVariant */ + +#define NS_ERROR_CANNOT_CONVERT_DATA NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_XPCOM, 1) +#define NS_ERROR_OBJECT_IS_IMMUTABLE NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_XPCOM, 2) +#define NS_ERROR_LOSS_OF_SIGNIFICANT_DATA NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_XPCOM, 3) + +#define NS_SUCCESS_LOSS_OF_INSIGNIFICANT_DATA NS_ERROR_GENERATE_SUCCESS(NS_ERROR_MODULE_XPCOM, 1) + + + /* + * This will return the nsresult corresponding to the most recent NSPR failure + * returned by PR_GetError. + * + *********************************************************************** + * Do not depend on this function. It will be going away! + *********************************************************************** + */ +extern NS_COM nsresult +NS_ErrorAccordingToNSPR(); + + +#ifdef _MSC_VER +#pragma warning(disable: 4251) /* 'nsCOMPtr' needs to have dll-interface to be used by clients of class 'nsInputStream' */ +#pragma warning(disable: 4275) /* non dll-interface class 'nsISupports' used as base for dll-interface class 'nsIRDFNode' */ +#endif + +#endif + diff --git a/src/libs/xpcom18a4/xpcom/base/nsErrorService.cpp b/src/libs/xpcom18a4/xpcom/base/nsErrorService.cpp new file mode 100644 index 00000000..f38495ed --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/base/nsErrorService.cpp @@ -0,0 +1,153 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsErrorService.h" +#include "nsCRT.h" + +static void* PR_CALLBACK +CloneCString(nsHashKey *aKey, void *aData, void* closure) +{ + return nsCRT::strdup((const char*)aData); +} + +static PRBool PR_CALLBACK +DeleteCString(nsHashKey *aKey, void *aData, void* closure) +{ + nsCRT::free((char*)aData); + return PR_TRUE; +} + +nsInt2StrHashtable::nsInt2StrHashtable() + : mHashtable(CloneCString, nsnull, DeleteCString, nsnull, 16) +{ +} + +nsresult +nsInt2StrHashtable::Put(PRUint32 key, const char* aData) +{ + char* value = nsCRT::strdup(aData); + if (value == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + nsPRUint32Key k(key); + char* oldValue = (char*)mHashtable.Put(&k, value); + if (oldValue) + nsCRT::free(oldValue); + return NS_OK; +} + +char* +nsInt2StrHashtable::Get(PRUint32 key) +{ + nsPRUint32Key k(key); + const char* value = (const char*)mHashtable.Get(&k); + if (value == nsnull) + return nsnull; + return nsCRT::strdup(value); +} + +nsresult +nsInt2StrHashtable::Remove(PRUint32 key) +{ + nsPRUint32Key k(key); + char* oldValue = (char*)mHashtable.Remove(&k); + if (oldValue) + nsCRT::free(oldValue); + return NS_OK; +} + +//////////////////////////////////////////////////////////////////////////////// + +NS_IMPL_ISUPPORTS1(nsErrorService, nsIErrorService) + +NS_METHOD +nsErrorService::Create(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr) +{ + NS_ENSURE_NO_AGGREGATION(outer); + nsErrorService* serv = new nsErrorService(); + if (serv == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + NS_ADDREF(serv); + nsresult rv = serv->QueryInterface(aIID, aInstancePtr); + NS_RELEASE(serv); + return rv; +} + +NS_IMETHODIMP +nsErrorService::RegisterErrorStringBundle(PRInt16 errorModule, const char *stringBundleURL) +{ + return mErrorStringBundleURLMap.Put(errorModule, stringBundleURL); +} + +NS_IMETHODIMP +nsErrorService::UnregisterErrorStringBundle(PRInt16 errorModule) +{ + return mErrorStringBundleURLMap.Remove(errorModule); +} + +NS_IMETHODIMP +nsErrorService::GetErrorStringBundle(PRInt16 errorModule, char **result) +{ + char* value = mErrorStringBundleURLMap.Get(errorModule); + if (value == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + *result = value; + return NS_OK; +} + +NS_IMETHODIMP +nsErrorService::RegisterErrorStringBundleKey(nsresult error, const char *stringBundleKey) +{ + return mErrorStringBundleKeyMap.Put(error, stringBundleKey); +} + +NS_IMETHODIMP +nsErrorService::UnregisterErrorStringBundleKey(nsresult error) +{ + return mErrorStringBundleKeyMap.Remove(error); +} + +NS_IMETHODIMP +nsErrorService::GetErrorStringBundleKey(nsresult error, char **result) +{ + char* value = mErrorStringBundleKeyMap.Get(error); + if (value == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + *result = value; + return NS_OK; +} + +//////////////////////////////////////////////////////////////////////////////// diff --git a/src/libs/xpcom18a4/xpcom/base/nsErrorService.h b/src/libs/xpcom18a4/xpcom/base/nsErrorService.h new file mode 100644 index 00000000..70a30c0e --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/base/nsErrorService.h @@ -0,0 +1,76 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +#ifndef nsErrorService_h__ +#define nsErrorService_h__ + +#include "nsIErrorService.h" +#include "nsHashtable.h" + +class nsInt2StrHashtable +{ +public: + nsInt2StrHashtable(); + + nsresult Put(PRUint32 key, const char* aData); + char* Get(PRUint32 key); + nsresult Remove(PRUint32 key); + +protected: + nsObjectHashtable mHashtable; +}; + +class nsErrorService : public nsIErrorService +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIERRORSERVICE + + nsErrorService() {} + + static NS_METHOD + Create(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr); + +private: + ~nsErrorService() {} + +protected: + nsInt2StrHashtable mErrorStringBundleURLMap; + nsInt2StrHashtable mErrorStringBundleKeyMap; +}; + +#endif // nsErrorService_h__ diff --git a/src/libs/xpcom18a4/xpcom/base/nsExceptionService.cpp b/src/libs/xpcom18a4/xpcom/base/nsExceptionService.cpp new file mode 100644 index 00000000..f68f2d5f --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/base/nsExceptionService.cpp @@ -0,0 +1,383 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * ActiveState Tool Corp.. + * Portions created by the Initial Developer are Copyright (C) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mark Hammond + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsISupports.h" +#include "nsExceptionService.h" +#include "nsIServiceManager.h" +#include "nsCOMPtr.h" +#include "prthread.h" +#include "prlock.h" +static const PRUintn BAD_TLS_INDEX = (PRUintn) -1; + +#define CHECK_SERVICE_USE_OK() if (tlsIndex == BAD_TLS_INDEX) return NS_ERROR_NOT_INITIALIZED +#define CHECK_MANAGER_USE_OK() if (!mService || nsExceptionService::tlsIndex == BAD_TLS_INDEX) return NS_ERROR_NOT_INITIALIZED + +// A key for our registered module providers hashtable +class nsProviderKey : public nsHashKey { +protected: + PRUint32 mKey; +public: + nsProviderKey(PRUint32 key) : mKey(key) {} + PRUint32 HashCode(void) const { + return mKey; + } + PRBool Equals(const nsHashKey *aKey) const { + return mKey == ((const nsProviderKey *) aKey)->mKey; + } + nsHashKey *Clone() const { + return new nsProviderKey(mKey); + } + PRUint32 GetValue() { return mKey; } +}; + +/** Exception Manager definition **/ +class nsExceptionManager : public nsIExceptionManager +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIEXCEPTIONMANAGER + + nsExceptionManager(nsExceptionService *svc); + /* additional members */ + nsCOMPtr mCurrentException; + nsExceptionManager *mNextThread; // not ref-counted. + nsExceptionService *mService; // not ref-counted +#ifdef NS_DEBUG + static PRInt32 totalInstances; +#endif + +#ifdef NS_DEBUG + inline nsrefcnt ReleaseQuiet() { + // shut up NS_ASSERT_OWNINGTHREAD (see explanation below) + nsAutoOwningThread old = _mOwningThread; + _mOwningThread = nsAutoOwningThread(); + nsrefcnt ref = Release(); + NS_ASSERTION(ref == 0, "the object is still referenced by other threads while it shouldn't"); + if (ref != 0) + _mOwningThread = old; + return ref; + } +#else + inline nsrefcnt ReleaseQuiet(void) { return Release(); } +#endif + +private: + ~nsExceptionManager(); +}; + + +#ifdef NS_DEBUG +PRInt32 nsExceptionManager::totalInstances = 0; +#endif + +// Note: the nsExceptionManager object is single threaded - the exception +// service itself ensures one per thread. However, there are two methods that +// may be called on foreign threads: DropAllThreads (called on the thread +// shutting down xpcom) and ThreadDestruct (called after xpcom destroyed the +// internal thread struct, so that PR_GetCurrentThread() will create a new one +// from scratch which will obviously not match the old one stored in the +// instance on creation). In both cases, there should be no other threads +// holding objects (i.e. it's thread-safe to call them), but +// NS_CheckThreadSafe() assertions will still happen and yell in the debug +// build. Since it is quite annoying, we use a special ReleaseQuiet() method +// in DoDropThread() to shut them up. +NS_IMPL_THREADSAFE_ISUPPORTS1(nsExceptionManager, nsIExceptionManager) + +nsExceptionManager::nsExceptionManager(nsExceptionService *svc) : + mNextThread(nsnull), + mService(svc) +{ + /* member initializers and constructor code */ +#ifdef NS_DEBUG + PR_AtomicIncrement(&totalInstances); +#endif +} + +nsExceptionManager::~nsExceptionManager() +{ + /* destructor code */ +#ifdef NS_DEBUG + PR_AtomicDecrement(&totalInstances); +#endif // NS_DEBUG +} + +/* void setCurrentException (in nsIException error); */ +NS_IMETHODIMP nsExceptionManager::SetCurrentException(nsIException *error) +{ + CHECK_MANAGER_USE_OK(); + mCurrentException = error; + return NS_OK; +} + +/* nsIException getCurrentException (); */ +NS_IMETHODIMP nsExceptionManager::GetCurrentException(nsIException **_retval) +{ + CHECK_MANAGER_USE_OK(); + *_retval = mCurrentException; + NS_IF_ADDREF(*_retval); + return NS_OK; +} + +/* nsIException getExceptionFromProvider( in nsresult rc, in nsIException defaultException); */ +NS_IMETHODIMP nsExceptionManager::GetExceptionFromProvider(nsresult rc, nsIException * defaultException, nsIException **_retval) +{ + CHECK_MANAGER_USE_OK(); + // Just delegate back to the service with the provider map. + return mService->GetExceptionFromProvider(rc, defaultException, _retval); +} + +/* The Exception Service */ + +PRUintn nsExceptionService::tlsIndex = BAD_TLS_INDEX; +PRLock *nsExceptionService::lock = nsnull; +nsExceptionManager *nsExceptionService::firstThread = nsnull; + +#ifdef NS_DEBUG +PRInt32 nsExceptionService::totalInstances = 0; +#endif + +NS_IMPL_THREADSAFE_ISUPPORTS2(nsExceptionService, nsIExceptionService, nsIObserver) + +nsExceptionService::nsExceptionService() + : mProviders(4, PR_TRUE) /* small, thread-safe hashtable */ +{ +#ifdef NS_DEBUG + if (PR_AtomicIncrement(&totalInstances)!=1) { + NS_ERROR("The nsExceptionService is a singleton!"); + } +#endif + /* member initializers and constructor code */ + if (tlsIndex == BAD_TLS_INDEX) { + PRStatus status; + status = PR_NewThreadPrivateIndex( &tlsIndex, ThreadDestruct ); + NS_WARN_IF_FALSE(status==0, "ScriptErrorService could not allocate TLS storage."); + } + lock = PR_NewLock(); + NS_WARN_IF_FALSE(lock, "Error allocating ExceptionService lock"); + + // observe XPCOM shutdown. + nsCOMPtr observerService = do_GetService("@mozilla.org/observer-service;1"); + NS_WARN_IF_FALSE(observerService, "Could not get observer service!"); + if (observerService) + observerService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, PR_FALSE); +} + +nsExceptionService::~nsExceptionService() +{ + Shutdown(); + if (lock) { + PRLock *tmp = lock; + lock = nsnull; + PR_DestroyLock(tmp); + } + /* destructor code */ +#ifdef NS_DEBUG + PR_AtomicDecrement(&totalInstances); +#endif +} + +/*static*/ +void nsExceptionService::ThreadDestruct( void *data ) +{ + if (!lock) { + NS_WARNING("nsExceptionService ignoring thread destruction after shutdown"); + return; + } + DropThread( (nsExceptionManager *)data ); +} + + +void nsExceptionService::Shutdown() +{ + PRUintn tmp = tlsIndex; + tlsIndex = BAD_TLS_INDEX; + PR_SetThreadPrivate(tmp, nsnull); + mProviders.Reset(); + if (lock) { + DropAllThreads(); + } +} + +/* void setCurrentException (in nsIException error); */ +NS_IMETHODIMP nsExceptionService::SetCurrentException(nsIException *error) +{ + CHECK_SERVICE_USE_OK(); + nsCOMPtr sm; + nsresult nr = GetCurrentExceptionManager(getter_AddRefs(sm)); + if (NS_FAILED(nr)) + return nr; + return sm->SetCurrentException(error); +} + +/* nsIException getCurrentException (); */ +NS_IMETHODIMP nsExceptionService::GetCurrentException(nsIException **_retval) +{ + CHECK_SERVICE_USE_OK(); + nsCOMPtr sm; + nsresult nr = GetCurrentExceptionManager(getter_AddRefs(sm)); + if (NS_FAILED(nr)) + return nr; + return sm->GetCurrentException(_retval); +} + +/* nsIException getExceptionFromProvider( in nsresult rc, in nsIException defaultException); */ +NS_IMETHODIMP nsExceptionService::GetExceptionFromProvider(nsresult rc, + nsIException * defaultException, nsIException **_retval) +{ + CHECK_SERVICE_USE_OK(); + return DoGetExceptionFromProvider(rc, defaultException, _retval); +} + +/* readonly attribute nsIExceptionManager currentExceptionManager; */ +NS_IMETHODIMP nsExceptionService::GetCurrentExceptionManager(nsIExceptionManager * *aCurrentScriptManager) +{ + CHECK_SERVICE_USE_OK(); + nsExceptionManager *mgr = (nsExceptionManager *)PR_GetThreadPrivate(tlsIndex); + if (mgr == nsnull) { + // Stick the new exception object in with no reference count. + mgr = new nsExceptionManager(this); + if (mgr == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + PR_SetThreadPrivate(tlsIndex, mgr); + // The reference count is held in the thread-list + AddThread(mgr); + } + *aCurrentScriptManager = mgr; + NS_ADDREF(*aCurrentScriptManager); + return NS_OK; +} + +/* void registerErrorProvider (in nsIExceptionProvider provider, in PRUint32 moduleCode); */ +NS_IMETHODIMP nsExceptionService::RegisterExceptionProvider(nsIExceptionProvider *provider, PRUint32 errorModule) +{ + CHECK_SERVICE_USE_OK(); + + nsProviderKey key(errorModule); + if (mProviders.Put(&key, provider)) { + NS_WARNING("Registration of exception provider overwrote another provider with the same module code!"); + } + return NS_OK; +} + +/* void unregisterErrorProvider (in nsIExceptionProvider provider, in PRUint32 errorModule); */ +NS_IMETHODIMP nsExceptionService::UnregisterExceptionProvider(nsIExceptionProvider *provider, PRUint32 errorModule) +{ + CHECK_SERVICE_USE_OK(); + nsProviderKey key(errorModule); + if (!mProviders.Remove(&key)) { + NS_WARNING("Attempt to unregister an unregistered exception provider!"); + return NS_ERROR_UNEXPECTED; + } + return NS_OK; +} + +// nsIObserver +NS_IMETHODIMP nsExceptionService::Observe(nsISupports *aSubject, const char *aTopic, const PRUnichar *someData) +{ + Shutdown(); + return NS_OK; +} + +nsresult +nsExceptionService::DoGetExceptionFromProvider(nsresult errCode, + nsIException * defaultException, + nsIException **_exc) +{ + // Check for an existing exception + nsresult nr = GetCurrentException(_exc); + if (NS_SUCCEEDED(nr) && *_exc) { + (*_exc)->GetResult(&nr); + // If it matches our result then use it + if (nr == errCode) + return NS_OK; + NS_RELEASE(*_exc); + } + nsProviderKey key(NS_ERROR_GET_MODULE(errCode)); + nsCOMPtr provider = + dont_AddRef((nsIExceptionProvider *)mProviders.Get(&key)); + + // No provider so we'll return the default exception + if (!provider) { + *_exc = defaultException; + NS_IF_ADDREF(*_exc); + return NS_OK; + } + + return provider->GetException(errCode, defaultException, _exc); +} + +// thread management +/*static*/ void nsExceptionService::AddThread(nsExceptionManager *thread) +{ + PR_Lock(lock); + thread->mNextThread = firstThread; + firstThread = thread; + NS_ADDREF(thread); + PR_Unlock(lock); +} + +/*static*/ void nsExceptionService::DoDropThread(nsExceptionManager *thread) +{ + nsExceptionManager **emp = &firstThread; + while (*emp != thread) { + if (!*emp) + { + NS_WARNING("Could not find the thread to drop!"); + return; + } + emp = &(*emp)->mNextThread; + } + *emp = thread->mNextThread; + thread->ReleaseQuiet(); + thread = nsnull; +} + +/*static*/ void nsExceptionService::DropThread(nsExceptionManager *thread) +{ + PR_Lock(lock); + DoDropThread(thread); + PR_Unlock(lock); +} + +/*static*/ void nsExceptionService::DropAllThreads() +{ + PR_Lock(lock); + while (firstThread) + DoDropThread(firstThread); + PR_Unlock(lock); +} diff --git a/src/libs/xpcom18a4/xpcom/base/nsExceptionService.h b/src/libs/xpcom18a4/xpcom/base/nsExceptionService.h new file mode 100644 index 00000000..441a4c5b --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/base/nsExceptionService.h @@ -0,0 +1,94 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * ActiveState Tool Corp.. + * Portions created by the Initial Developer are Copyright (C) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mark Hammond + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +#ifndef nsExceptionService_h__ +#define nsExceptionService_h__ + +#include "nsVoidArray.h" +#include "nsIException.h" +#include "nsIExceptionService.h" +#include "nsIObserverService.h" +#include "nsHashtable.h" +#include "nsIObserver.h" + +class nsExceptionManager; + +/** Exception Service definition **/ +class nsExceptionService : public nsIExceptionService, public nsIObserver +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIEXCEPTIONSERVICE + NS_DECL_NSIEXCEPTIONMANAGER + NS_DECL_NSIOBSERVER + + nsExceptionService(); + + /* additional members */ + nsresult DoGetExceptionFromProvider(nsresult errCode, + nsIException *defaultException, + nsIException **_richError); + void Shutdown(); + + + /* thread management and cleanup */ + static void AddThread(nsExceptionManager *); + static void DropThread(nsExceptionManager *); + static void DoDropThread(nsExceptionManager *thread); + + static void DropAllThreads(); + static nsExceptionManager *firstThread; + + nsSupportsHashtable mProviders; + + /* single lock protects both providers hashtable + and thread list */ + static PRLock* lock; + + static PRUintn tlsIndex; + static void PR_CALLBACK ThreadDestruct( void *data ); +#ifdef NS_DEBUG + static PRInt32 totalInstances; +#endif + +private: + ~nsExceptionService(); +}; + + +#endif // nsExceptionService_h__ diff --git a/src/libs/xpcom18a4/xpcom/base/nsGarbageCollector.c b/src/libs/xpcom18a4/xpcom/base/nsGarbageCollector.c new file mode 100644 index 00000000..b0447598 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/base/nsGarbageCollector.c @@ -0,0 +1,127 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * ***** 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 the Mozilla browser. + * + * The Initial Developer of the Original Code is + * Netscape Communications, Inc. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Patrick Beard + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* + nsGarbageCollector.c + */ + +#ifdef GC_LEAK_DETECTOR + +/* for FILE */ +#include + +/* NSPR stuff */ +#include "generic_threads.h" +#include "prthread.h" +#include "prlock.h" + +/* Linux/Win32 export private NSPR files to include/private */ +#ifdef XP_MAC +#include "pprthred.h" +#else +#include "private/pprthred.h" +#endif + +#include "nsLeakDetector.h" + +extern FILE *GC_stdout, *GC_stderr; + +extern void GC_gcollect(void); +extern void GC_clear_roots(void); + +static PRStatus PR_CALLBACK scanner(PRThread* t, void** baseAddr, PRUword count, void* closure) +{ + char* begin = (char*)baseAddr; + char* end = (char*)(baseAddr + count); + GC_mark_range_proc marker = (GC_mark_range_proc) closure; + marker(begin, end); + return PR_SUCCESS; +} + +static void mark_all_stacks(GC_mark_range_proc marker) +{ + /* PR_ThreadScanStackPointers(PR_GetCurrentThread(), &scanner, marker); */ + PR_ScanStackPointers(&scanner, (void *)marker); +} + +static void locker(void* mutex) +{ + PR_Lock(mutex); +} + +static void unlocker(void* mutex) +{ + PR_Unlock(mutex); +} + +static void stopper(void* unused) +{ + PR_SuspendAll(); +} + +static void starter(void* unused) +{ + PR_ResumeAll(); +} + +nsresult NS_InitGarbageCollector() +{ + PRLock* mutex; + + /* redirect GC's stderr to catch startup leaks. */ + GC_stderr = fopen("StartupLeaks", "w"); + + mutex = PR_NewLock(); + if (mutex == NULL) + return NS_ERROR_FAILURE; + + GC_generic_init_threads(&mark_all_stacks, mutex, + &locker, &unlocker, + &stopper, &starter); + + return NS_OK; +} + +nsresult NS_ShutdownGarbageCollector() +{ + /* do anything you need to shut down the collector. */ + return NS_OK; +} + +#endif /* GC_LEAK_DETECTOR */ diff --git a/src/libs/xpcom18a4/xpcom/base/nsIAllocator.h b/src/libs/xpcom18a4/xpcom/base/nsIAllocator.h new file mode 100644 index 00000000..2195f42d --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/base/nsIAllocator.h @@ -0,0 +1,56 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/** + * XXX This file is obsolete. Use nsIMemory.idl or nsMemory.h instead. + */ + +#ifndef nsIAllocator_h___ +#define nsIAllocator_h___ + +#include "nsMemory.h" + +#define nsIAllocator nsIMemory +#define nsAllocator nsMemory +#define GetGlobalAllocator GetGlobalMemoryService + +#define NS_IALLOCATOR_IID NS_GET_IID(nsIMemory) +#define NS_ALLOCATOR_CONTRACTID NS_MEMORY_CONTRACTID +#define NS_ALLOCATOR_CLASSNAME NS_MEMORY_CLASSNAME +#define NS_ALLOCATOR_CID NS_MEMORY_CID + +#endif /* nsIAllocator_h___ */ diff --git a/src/libs/xpcom18a4/xpcom/base/nsIConsoleListener.idl b/src/libs/xpcom18a4/xpcom/base/nsIConsoleListener.idl new file mode 100644 index 00000000..f983132d --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/base/nsIConsoleListener.idl @@ -0,0 +1,49 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* + * Used by the console service to notify listeners of new console messages. + */ + +#include "nsISupports.idl" +#include "nsIConsoleMessage.idl" + +[scriptable, uuid(eaaf61d6-1dd1-11b2-bc6e-8fc96480f20d)] +interface nsIConsoleListener : nsISupports +{ + void observe(in nsIConsoleMessage aMessage); +}; diff --git a/src/libs/xpcom18a4/xpcom/base/nsIConsoleMessage.idl b/src/libs/xpcom18a4/xpcom/base/nsIConsoleMessage.idl new file mode 100644 index 00000000..0662a2d2 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/base/nsIConsoleMessage.idl @@ -0,0 +1,56 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsISupports.idl" + +/** + * This is intended as a base interface; implementations may want to + * provide an object that can be qi'ed to provide more specific + * message information. + */ +[scriptable, uuid(41bd8784-1dd2-11b2-9553-8606958fffe1)] +interface nsIConsoleMessage : nsISupports +{ + readonly attribute wstring message; +}; + +%{ C++ +#define NS_CONSOLEMESSAGE_CID \ +{ 0x56c9d666, 0x1dd2, 0x11b2, { 0xb4, 0x3c, 0xa8, 0x4b, 0xf3, 0xb3, 0xec, 0xbb }} + +#define NS_CONSOLEMESSAGE_CONTRACTID "@mozilla.org/consolemessage;1" +%} diff --git a/src/libs/xpcom18a4/xpcom/base/nsIConsoleService.idl b/src/libs/xpcom18a4/xpcom/base/nsIConsoleService.idl new file mode 100644 index 00000000..283c7acc --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/base/nsIConsoleService.idl @@ -0,0 +1,85 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsISupports.idl" +#include "nsIConsoleListener.idl" +#include "nsIConsoleMessage.idl" + +[scriptable, uuid(a647f184-1dd1-11b2-a9d1-8537b201161b)] +interface nsIConsoleService : nsISupports +{ + void logMessage(in nsIConsoleMessage message); + + /** + * Convenience method for logging simple messages. + */ + void logStringMessage(in wstring message); + + /** + * Get an array of all the messages logged so far. If no messages + * are logged, this function will return a count of 0, but still + * will allocate one word for messages, so as to show up as a + * 0-length array when called from script. + */ + void getMessageArray([array, size_is(count)] out nsIConsoleMessage messages, + out PRUint32 count); + + /** + * To guard against stack overflows from listeners that could log + * messages (it's easy to do this inadvertently from listeners + * implemented in JavaScript), we don't call any listeners when + * another error is already being logged. + */ + void registerListener(in nsIConsoleListener listener); + + /** + * Each registered listener should also be unregistered. + */ + void unregisterListener(in nsIConsoleListener listener); + +}; + + +%{ C++ +#define NS_CONSOLESERVICE_CLASSNAME "Console Service" + +#define NS_CONSOLESERVICE_CID \ +{ 0x7e3ff85c, 0x1dd2, 0x11b2, { 0x8d, 0x4b, 0xeb, 0x45, 0x2c, 0xb0, 0xff, 0x40 }} + +#define NS_CONSOLESERVICE_CONTRACTID "@mozilla.org/consoleservice;1" +%} + diff --git a/src/libs/xpcom18a4/xpcom/base/nsID.cpp b/src/libs/xpcom18a4/xpcom/base/nsID.cpp new file mode 100644 index 00000000..adb0d41c --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/base/nsID.cpp @@ -0,0 +1,152 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Daniel Bratell + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsID.h" +#include "prprf.h" +#include "prmem.h" + +static const char gIDFormat[] = + "{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}"; + +static const char gIDFormat2[] = + "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x"; + + +/** + * Multiplies the_int_var with 16 (0x10) and adds the value of the + * hexadecimal digit the_char. If it fails it returns PR_FALSE from + * the function it's used in. + */ + +#define ADD_HEX_CHAR_TO_INT_OR_RETURN_FALSE(the_char, the_int_var) \ + the_int_var = (the_int_var << 4) + the_char; \ + if(the_char >= '0' && the_char <= '9') the_int_var -= '0'; \ + else if(the_char >= 'a' && the_char <= 'f') the_int_var -= 'a'-10; \ + else if(the_char >= 'A' && the_char <= 'F') the_int_var -= 'A'-10; \ + else return PR_FALSE + + +/** + * Parses number_of_chars characters from the char_pointer pointer and + * puts the number in the dest_variable. The pointer is moved to point + * at the first character after the parsed ones. If it fails it returns + * PR_FALSE from the function the macro is used in. + */ + +#define PARSE_CHARS_TO_NUM(char_pointer, dest_variable, number_of_chars) \ + do { PRInt32 _i=number_of_chars; \ + dest_variable = 0; \ + while(_i) { \ + ADD_HEX_CHAR_TO_INT_OR_RETURN_FALSE(*char_pointer, dest_variable); \ + char_pointer++; \ + _i--; \ + } } while(0) + + +/** + * Parses a hyphen from the char_pointer string. If there is no hyphen there + * the function returns PR_FALSE from the function it's used in. The + * char_pointer is advanced one step. + */ + + #define PARSE_HYPHEN(char_pointer) if(*(char_pointer++) != '-') return PR_FALSE + +/* + * Turns a {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} string into + * an nsID. It can also handle the old format without the { and }. + */ + +NS_COM PRBool nsID::Parse(const char *aIDStr) +{ + /* Optimized for speed */ + if(!aIDStr) { + return PR_FALSE; + } + + PRBool expectFormat1 = (aIDStr[0] == '{'); + if(expectFormat1) aIDStr++; + + PARSE_CHARS_TO_NUM(aIDStr, m0, 8); + PARSE_HYPHEN(aIDStr); + PARSE_CHARS_TO_NUM(aIDStr, m1, 4); + PARSE_HYPHEN(aIDStr); + PARSE_CHARS_TO_NUM(aIDStr, m2, 4); + PARSE_HYPHEN(aIDStr); + int i; + for(i=0; i<2; i++) + PARSE_CHARS_TO_NUM(aIDStr, m3[i], 2); + PARSE_HYPHEN(aIDStr); + while(i < 8) { + PARSE_CHARS_TO_NUM(aIDStr, m3[i], 2); + i++; + } + + return expectFormat1 ? *aIDStr == '}' : PR_TRUE; +} + +/* + * Returns an allocated string in {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} + * format. The string is allocated with PR_Malloc and should be freed by + * the caller. + */ + +NS_COM char *nsID::ToString() const +{ + char *res = (char*)PR_Malloc(39); // use PR_Malloc if this is to be freed with nsCRT::free + + if (res != NULL) { + PR_snprintf(res, 39, gIDFormat, + m0, (PRUint32) m1, (PRUint32) m2, + (PRUint32) m3[0], (PRUint32) m3[1], (PRUint32) m3[2], + (PRUint32) m3[3], (PRUint32) m3[4], (PRUint32) m3[5], + (PRUint32) m3[6], (PRUint32) m3[7]); + } + return res; +} + +#ifdef VBOX +void nsID::ToProvidedString(char (&dest)[NSID_LENGTH]) const +{ + PR_snprintf(dest, NSID_LENGTH, gIDFormat, + m0, (PRUint32) m1, (PRUint32) m2, + (PRUint32) m3[0], (PRUint32) m3[1], (PRUint32) m3[2], + (PRUint32) m3[3], (PRUint32) m3[4], (PRUint32) m3[5], + (PRUint32) m3[6], (PRUint32) m3[7]); +} +#endif + + diff --git a/src/libs/xpcom18a4/xpcom/base/nsID.h b/src/libs/xpcom18a4/xpcom/base/nsID.h new file mode 100644 index 00000000..257ba927 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/base/nsID.h @@ -0,0 +1,166 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +#ifndef nsID_h__ +#define nsID_h__ + +#include + +#ifndef nscore_h___ +#include "nscore.h" +#endif + +#ifdef VBOX +#define NSID_LENGTH 39 +#endif + +/** + * A "unique identifier". This is modeled after OSF DCE UUIDs. + * @status FROZEN + */ + +struct nsID { + /** + * @name Indentifier values + */ + + //@{ + PRUint32 m0; + PRUint16 m1; + PRUint16 m2; + PRUint8 m3[8]; + //@} + + /** + * @name Methods + */ + + //@{ + /** + * Equivalency method. Compares this nsID with another. + * @return PR_TRUE if they are the same, PR_FALSE if not. + */ + + inline PRBool Equals(const nsID& other) const { + // One would think that this could be done faster with a really + // efficient implementation of memcmp(), but evidently no + // memcmp()'s out there are better than this code. + // + // See bug http://bugzilla.mozilla.org/show_bug.cgi?id=164580 for + // details. + + return (PRBool) + ((((PRUint32*) &m0)[0] == ((PRUint32*) &other.m0)[0]) && + (((PRUint32*) &m0)[1] == ((PRUint32*) &other.m0)[1]) && + (((PRUint32*) &m0)[2] == ((PRUint32*) &other.m0)[2]) && + (((PRUint32*) &m0)[3] == ((PRUint32*) &other.m0)[3])); + } + + /** + * nsID Parsing method. Turns a {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} + * string into an nsID + */ + NS_COM PRBool Parse(const char *aIDStr); + + /** + * nsID string encoder. Returns an allocated string in + * {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} format. Caller should free string. + */ + NS_COM char* ToString() const; + +#ifdef VBOX + /** + * nsID string encoder. Builds a string in + * {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} format, into a char[NSID_LENGTH] + * buffer provided by the caller (for instance, on the stack). + */ + NS_COM void ToProvidedString(char (&dest)[NSID_LENGTH]) const; +#endif + + //@} +}; + +/* + * Class IDs + */ + +typedef nsID nsCID; + +// Define an CID +#define NS_DEFINE_CID(_name, _cidspec) \ + const nsCID _name = _cidspec + +#define REFNSCID const nsCID& + +/** + * An "interface id" which can be used to uniquely identify a given + * interface. + */ + +typedef nsID nsIID; + +/** + * A macro shorthand for const nsIID& + */ + +#define REFNSIID const nsIID& + +/** + * Define an IID + * obsolete - do not use this macro + */ + +#define NS_DEFINE_IID(_name, _iidspec) \ + const nsIID _name = _iidspec + +/** + * A macro to build the static const IID accessor method + */ + +#define NS_DEFINE_STATIC_IID_ACCESSOR(the_iid) \ + static const nsIID& GetIID() {static const nsIID iid = the_iid; return iid;} + +/** + * A macro to build the static const CID accessor method + */ + +#define NS_DEFINE_STATIC_CID_ACCESSOR(the_cid) \ + static const nsID& GetCID() {static const nsID cid = the_cid; return cid;} + +#endif + + diff --git a/src/libs/xpcom18a4/xpcom/base/nsIDebug.idl b/src/libs/xpcom18a4/xpcom/base/nsIDebug.idl new file mode 100644 index 00000000..73b3912a --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/base/nsIDebug.idl @@ -0,0 +1,67 @@ +/* ***** 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 XPCOM + * + * The Initial Developer of the Original Code is Doug Turner + * + * Portions created by the Initial Developer are Copyright (C) 2003 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * 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 "nsISupports.idl" + +/** + * nsIDebug is an interface between XPCOM Glue and XPCOM. Users should access + * the nsIDebug interface through the static class nsDebug. + * @see nsDebug.h + * + * @status UNDER_REVIEW + * + */ + +[scriptable, uuid(3bf0c3d7-3bd9-4cf2-a971-33572c503e1e)] +interface nsIDebug : nsISupports +{ + void assertion(in string aStr, + in string aExpr, + in string aFile, + in long aLine); + + void warning(in string aStr, + in string aFile, + in long aLine); + + void break(in string aFile, + in long aLine); + + void abort(in string aFile, + in long aLine); +}; + diff --git a/src/libs/xpcom18a4/xpcom/base/nsIErrorService.idl b/src/libs/xpcom18a4/xpcom/base/nsIErrorService.idl new file mode 100644 index 00000000..c4ed3964 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/base/nsIErrorService.idl @@ -0,0 +1,100 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsISupports.idl" + +/** + * nsIErrorService: This is an interim service that allows nsresult codes to be mapped to + * string bundles that can be used to look up error messages. String bundle keys can also + * be mapped. + * + * This service will eventually get replaced by extending xpidl to allow errors to be defined. + * (http://bugzilla.mozilla.org/show_bug.cgi?id=13423). + */ +[scriptable, uuid(e72f94b2-5f85-11d4-9877-00c04fa0cf4a)] +interface nsIErrorService : nsISupports +{ + /** + * Registers a string bundle URL for an error module. Error modules are obtained from + * nsresult code with NS_ERROR_GET_MODULE. + */ + void registerErrorStringBundle(in short errorModule, in string stringBundleURL); + + /** + * Registers a string bundle URL for an error module. + */ + void unregisterErrorStringBundle(in short errorModule); + + /** + * Retrieves a string bundle URL for an error module. + */ + string getErrorStringBundle(in short errorModule); + + /** + * Registers a key in a string bundle for an nsresult error code. Only the code portion + * of the nsresult is used (obtained with NS_ERROR_GET_CODE) in this registration. The + * string bundle key is used to look up internationalized messages in the string bundle. + */ + void registerErrorStringBundleKey(in nsresult error, in string stringBundleKey); + + /** + * Unregisters a key in a string bundle for an nsresult error code. + */ + void unregisterErrorStringBundleKey(in nsresult error); + + /** + * Retrieves a key in a string bundle for an nsresult error code. If no key is registered + * for the specified nsresult's code (obtained with NS_ERROR_GET_CODE), then the stringified + * version of the nsresult code is returned. + */ + string getErrorStringBundleKey(in nsresult error); +}; + +%{C++ + +// The global nsIErrorService: +#define NS_ERRORSERVICE_NAME "Error Service" +#define NS_ERRORSERVICE_CONTRACTID "@mozilla.org/xpcom/error-service;1" +#define NS_ERRORSERVICE_CID \ +{ /* 744afd5e-5f8c-11d4-9877-00c04fa0cf4a */ \ + 0x744afd5e, \ + 0x5f8c, \ + 0x11d4, \ + {0x98, 0x77, 0x00, 0xc0, 0x4f, 0xa0, 0xcf, 0x4a} \ +} + +%} diff --git a/src/libs/xpcom18a4/xpcom/base/nsIException.idl b/src/libs/xpcom18a4/xpcom/base/nsIException.idl new file mode 100644 index 00000000..affbb36e --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/base/nsIException.idl @@ -0,0 +1,101 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* + * Interfaces for representing cross-language exceptions and stack traces. + */ + + +#include "nsISupports.idl" +#include "nsIProgrammingLanguage.idl" + +// XXX - most "string"s in this file should probably move to Unicode +// so may as well use AStrings... + + +[scriptable, uuid(91d82105-7c62-4f8b-9779-154277c0ee90)] +interface nsIStackFrame : nsISupports +{ + // see nsIProgrammingLanguage for list of language consts + readonly attribute PRUint32 language; + readonly attribute string languageName; + readonly attribute string filename; + readonly attribute string name; + // Valid line numbers begin at '1'. '0' indicates unknown. + readonly attribute PRInt32 lineNumber; + readonly attribute string sourceLine; + readonly attribute nsIStackFrame caller; + + string toString(); +}; + +[scriptable, uuid(F3A8D3B4-C424-4edc-8BF6-8974C983BA78)] +interface nsIException : nsISupports +{ + // A custom message set by the thrower. + readonly attribute string message; + // The nsresult associated with this exception. + readonly attribute nsresult result; + // The name of the error code (ie, a string repr of |result|) + readonly attribute string name; + + // Filename location. This is the location that caused the + // error, which may or may not be a source file location. + // For example, standard language errors would generally have + // the same location as their top stack entry. File + // parsers may put the location of the file they were parsing, + // etc. + + // null indicates "no data" + readonly attribute string filename; + // Valid line numbers begin at '1'. '0' indicates unknown. + readonly attribute PRUint32 lineNumber; + // Valid column numbers begin at 0. + // We don't have an unambiguous indicator for unknown. + readonly attribute PRUint32 columnNumber; + + // A stack trace, if available. + readonly attribute nsIStackFrame location; + // An inner exception that triggered this, if available. + readonly attribute nsIException inner; + + // Arbitary data for the implementation. + readonly attribute nsISupports data; + + // A generic formatter - make it suitable to print, etc. + string toString(); +}; diff --git a/src/libs/xpcom18a4/xpcom/base/nsIExceptionService.idl b/src/libs/xpcom18a4/xpcom/base/nsIExceptionService.idl new file mode 100644 index 00000000..22ebe751 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/base/nsIExceptionService.idl @@ -0,0 +1,97 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * ActiveState Tool Corp.. + * Portions created by the Initial Developer are Copyright (C) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mark Hammond + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsISupports.idl" +#include "nsIException.idl" + +// An exception provider. These can turn special nsresult codes +// into nsIExceptions + +[scriptable, uuid(0577744c-c1d2-47f2-8bcc-ce7a9e5a88fc)] +interface nsIExceptionProvider : nsISupports +{ + /** Gets an nsIException or returns NULL if not possible. **/ + nsIException getException(in nsresult result, in nsIException defaultException); +}; + +// A ScriptErrorManager for a single thread. These objects +// are _not_ thread-safe. Use the ScriptErrorService +// to get a script error manager for your current thread. +[scriptable, uuid(efc9d00b-231c-4feb-852c-ac017266a415)] +interface nsIExceptionManager : nsISupports +{ + /** Sets (or clears with nsnull) the current error on the this thread. */ + void setCurrentException( in nsIException error); + + /** Gets the current error for the current thread, or NULL if no error */ + nsIException getCurrentException(); + + /** Gets an exception from a registered exception provider.. + This has no effect on the "current exception" */ + nsIException getExceptionFromProvider( in nsresult rc, in nsIException defaultException); +}; + + +// The Exception Service. Allows you to get an set exceptions in a thread +// safe manner, or to get an ExceptionManager for your specific thread. +[scriptable, uuid(35A88F54-F267-4414-92A7-191F6454AB52)] +interface nsIExceptionService : nsIExceptionManager +{ + /** Obtains an exception manager for the current thread. */ + readonly attribute nsIExceptionManager currentExceptionManager; + + /** Installs an "exception provider" which is capable of + translating an nsresult into an exception. This enables + error providers to return simple nsresults and only provide + rich errors when specifically requested. It also has the + advantage of allowing code like the DOM to handle all errors + in a single function rather than at each XPCOM entry point. + NOTE: This interface must be thread-safe - it will be called + on whatever thread needs the error translation performed.*/ + void registerExceptionProvider( in nsIExceptionProvider provider, in PRUint32 moduleCode ); + void unregisterExceptionProvider( in nsIExceptionProvider provider, in PRUint32 moduleCode ); +}; + + +%{ C++ +#define NS_EXCEPTIONSERVICE_CLASSNAME "Exception Service" +// {35A88F54-F267-4414-92A7-191F6454AB52} +#define NS_EXCEPTIONSERVICE_CID \ +{ 0x35a88f54, 0xf267, 0x4414, { 0x92, 0xa7, 0x19, 0x1f, 0x64, 0x54, 0xab, 0x52 } } +#define NS_EXCEPTIONSERVICE_CONTRACTID "@mozilla.org/exceptionservice;1" +%} diff --git a/src/libs/xpcom18a4/xpcom/base/nsIID.h b/src/libs/xpcom18a4/xpcom/base/nsIID.h new file mode 100644 index 00000000..f00d6b23 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/base/nsIID.h @@ -0,0 +1,41 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +#ifndef __nsIID_h +#define __nsIID_h +#include "nsID.h" +#endif /* __nsIID_h */ diff --git a/src/libs/xpcom18a4/xpcom/base/nsIInterfaceRequestor.idl b/src/libs/xpcom18a4/xpcom/base/nsIInterfaceRequestor.idl new file mode 100644 index 00000000..31388643 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/base/nsIInterfaceRequestor.idl @@ -0,0 +1,72 @@ +/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * ***** 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 the Mozilla browser. + * + * The Initial Developer of the Original Code is + * Netscape Communications, Inc. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Travis Bogard + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsISupports.idl" + +/** + * The nsIInterfaceRequestor interface defines a generic interface for + * requesting interfaces that a given object might provide access to. + * This is very similar to QueryInterface found in nsISupports. + * The main difference is that interfaces returned from GetInterface() + * are not required to provide a way back to the object implementing this + * interface. The semantics of QI() dictate that given an interface A that + * you QI() on to get to interface B, you must be able to QI on B to get back + * to A. This interface however allows you to obtain an interface C from A + * that may or most likely will not have the ability to get back to A. + * + * @status FROZEN + */ + +[scriptable, uuid(033A1470-8B2A-11d3-AF88-00A024FFC08C)] +interface nsIInterfaceRequestor : nsISupports +{ + /** + * Retrieves the specified interface pointer. + * + * @param uuid The IID of the interface being requested. + * @param result [out] The interface pointer to be filled in if + * the interface is accessible. + * @return NS_OK - interface was successfully returned. + * NS_NOINTERFACE - interface not accessible. + * NS_ERROR* - method failure. + */ + void getInterface(in nsIIDRef uuid, + [iid_is(uuid),retval] out nsQIResult result); +}; + diff --git a/src/libs/xpcom18a4/xpcom/base/nsILeakDetector.idl b/src/libs/xpcom18a4/xpcom/base/nsILeakDetector.idl new file mode 100644 index 00000000..6d27fa70 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/base/nsILeakDetector.idl @@ -0,0 +1,54 @@ +/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * ***** 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 the Mozilla browser. + * + * The Initial Developer of the Original Code is + * Netscape Communications, Inc. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Patrick C. Beard + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsISupports.idl" + +interface nsICollection; + +/** + * Controls the leak detector. + */ +[scriptable, uuid(a2ec052c-1dd1-11b2-9c92-84be252fe47e)] +interface nsILeakDetector : nsISupports { + void dumpLeaks(); + void traceObject(in nsISupports object, in PRBool verbose); + void traceCollection(in nsICollection objects, in PRBool verbose); + void markObject(in nsISupports object, in PRBool marked); + readonly attribute nsISupports services; +}; diff --git a/src/libs/xpcom18a4/xpcom/base/nsIMemory.idl b/src/libs/xpcom18a4/xpcom/base/nsIMemory.idl new file mode 100644 index 00000000..071aed06 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/base/nsIMemory.idl @@ -0,0 +1,126 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsISupports.idl" + +/** + * + * nsIMemory: interface to allocate and deallocate memory. Also provides + * for notifications in low-memory situations. + * + * A client that wishes to be notified of low memory situations (for + * example, because the client maintains a large memory cache that + * could be released when memory is tight) should register with the + * observer service (see nsIObserverService) using the topic + * "memory-pressure". There are three specific types of notications + * that can occur. These types will be passed as the |aData| + * parameter of the of the "memory-pressure" notification: + * + * "low-memory" + * This will be passed as the extra data when the pressure + * observer is being asked to flush for low-memory conditions. + * + * "heap-minimize" + * This will be passed as the extra data when the pressure + * observer is being asked to flush because of a heap minimize + * call. + * + * "alloc-failure" + * This will be passed as the extra data when the pressure + * observer has been asked to flush because a malloc() or + * realloc() has failed. + * + * @status FROZEN + */ + +[scriptable, uuid(59e7e77a-38e4-11d4-8cf5-0060b0fc14a3)] +interface nsIMemory : nsISupports +{ + /** + * Allocates a block of memory of a particular size. If the memory + * cannot be allocated (because of an out-of-memory condition), null + * is returned. + * + * @param size - the size of the block to allocate + * @result the block of memory + */ + [noscript, notxpcom] voidPtr alloc(in size_t size); + + /** + * Reallocates a block of memory to a new size. + * + * @param ptr - the block of memory to reallocate + * @param size - the new size + * @result the reallocated block of memory + * + * If ptr is null, this function behaves like malloc. + * If s is the size of the block to which ptr points, the first + * min(s, size) bytes of ptr's block are copied to the new block. + * If the allocation succeeds, ptr is freed and a pointer to the + * new block returned. If the allocation fails, ptr is not freed + * and null is returned. The returned value may be the same as ptr. + */ + [noscript, notxpcom] voidPtr realloc(in voidPtr ptr, + in size_t newSize); + + /** + * Frees a block of memory. Null is a permissible value, in which case + * nothing happens. + * + * @param ptr - the block of memory to free + */ + [noscript, notxpcom] void free(in voidPtr ptr); + + /** + * Attempts to shrink the heap. + * @param immediate - if true, heap minimization will occur + * immediately if the call was made on the main thread. If + * false, the flush will be scheduled to happen when the app is + * idle. + * @return NS_ERROR_FAILURE if 'immediate' is set an the call + * was not on the application's main thread. + */ + void heapMinimize(in boolean immediate); + + /** + * This predicate can be used to determine if we're in a low-memory + * situation (what constitutes low-memory is platform dependent). This + * can be used to trigger the memory pressure observers. + */ + boolean isLowMemory(); +}; + diff --git a/src/libs/xpcom18a4/xpcom/base/nsIProgrammingLanguage.idl b/src/libs/xpcom18a4/xpcom/base/nsIProgrammingLanguage.idl new file mode 100644 index 00000000..2fe6fb58 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/base/nsIProgrammingLanguage.idl @@ -0,0 +1,70 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** 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 Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * John Bandhauer + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsISupports.idl" + +%{C++ +#ifdef XP_OS2 // OS2 has UNKNOWN problems :) +#undef UNKNOWN +#endif +%} + +/** + * Enumeration of Programming Languages + * @status FROZEN + */ + +[scriptable, uuid(ea604e90-40ba-11d5-90bb-0010a4e73d9a)] +interface nsIProgrammingLanguage : nsISupports +{ + /** + * Identifiers for programming languages. + */ + const PRUint32 UNKNOWN = 0; + const PRUint32 CPLUSPLUS = 1; + const PRUint32 JAVASCRIPT = 2; + const PRUint32 PYTHON = 3; + const PRUint32 PERL = 4; + const PRUint32 JAVA = 5; + const PRUint32 ZX81_BASIC = 6; // it could happen :) + const PRUint32 JAVASCRIPT2 = 7; + // This list can grow indefinitely. Just don't ever change an existing item. + +}; diff --git a/src/libs/xpcom18a4/xpcom/base/nsISupports.idl b/src/libs/xpcom18a4/xpcom/base/nsISupports.idl new file mode 100644 index 00000000..6bf08ac4 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/base/nsISupports.idl @@ -0,0 +1,80 @@ +/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/** + * The mother of all xpcom interfaces. + * @status FROZEN + */ + +/* In order to get both the right typelib and the right header we force +* the 'real' output from xpidl to be commented out in the generated header +* and includes a copy of the original nsISupports.h. This is all just to deal +* with the Mac specific ": public __comobject" thing. +*/ + +#include "nsrootidl.idl" + +%{C++ +/* + * Start commenting out the C++ versions of the below in the output header + */ +#if 0 +%} + +[scriptable, uuid(00000000-0000-0000-c000-000000000046)] +interface nsISupports { + void QueryInterface(in nsIIDRef uuid, + [iid_is(uuid),retval] out nsQIResult result); + [noscript, notxpcom] nsrefcnt AddRef(); + [noscript, notxpcom] nsrefcnt Release(); +}; + +%{C++ +/* + * End commenting out the C++ versions of the above in the output header + */ +#endif +%} + + +%{C++ +#include "nsISupportsBase.h" + +#ifndef MOZILLA_STRICT_API +#include "nsISupportsUtils.h" +#endif +%} diff --git a/src/libs/xpcom18a4/xpcom/base/nsISupportsBase.h b/src/libs/xpcom18a4/xpcom/base/nsISupportsBase.h new file mode 100644 index 00000000..bea876f5 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/base/nsISupportsBase.h @@ -0,0 +1,119 @@ +/* ***** 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 XPCOM. + * + * The Initial Developer of the Original Code is Netscape Communications Corp. + * Portions created by the Initial Developer are Copyright (C) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * 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 ***** */ + +#ifndef nsISupportsBase_h__ +#define nsISupportsBase_h__ + +#ifndef nscore_h___ +#include "nscore.h" +#endif + +#ifndef nsID_h__ +#include "nsID.h" +#endif + + +/*@{*/ +/** + * IID for the nsISupports interface + * {00000000-0000-0000-c000-000000000046} + * + * To maintain binary compatibility with COM's IUnknown, we define the IID + * of nsISupports to be the same as that of COM's IUnknown. + */ +#define NS_ISUPPORTS_IID \ + { 0x00000000, 0x0000, 0x0000, \ + {0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46} } + +/** + * Reference count values + * + * This is the return type for AddRef() and Release() in nsISupports. + * IUnknown of COM returns an unsigned long from equivalent functions. + * The following ifdef exists to maintain binary compatibility with + * IUnknown. + */ +#if defined(XP_WIN) && PR_BYTES_PER_LONG == 4 +typedef unsigned long nsrefcnt; +#else +typedef PRUint32 nsrefcnt; +#endif + +/** + * Basic component object model interface. Objects which implement + * this interface support runtime interface discovery (QueryInterface) + * and a reference counted memory model (AddRef/Release). This is + * modelled after the win32 IUnknown API. + */ +class NS_NO_VTABLE nsISupports { +public: + + /** + * @name Methods + */ + + //@{ + /** + * A run time mechanism for interface discovery. + * @param aIID [in] A requested interface IID + * @param aInstancePtr [out] A pointer to an interface pointer to + * receive the result. + * @return NS_OK if the interface is supported by the associated + * instance, NS_NOINTERFACE if it is not. + * NS_ERROR_INVALID_POINTER if aInstancePtr is NULL. + */ + NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr) = 0; + /** + * Increases the reference count for this interface. + * The associated instance will not be deleted unless + * the reference count is returned to zero. + * + * @return The resulting reference count. + */ + NS_IMETHOD_(nsrefcnt) AddRef(void) = 0; + + /** + * Decreases the reference count for this interface. + * Generally, if the reference count returns to zero, + * the associated instance is deleted. + * + * @return The resulting reference count. + */ + NS_IMETHOD_(nsrefcnt) Release(void) = 0; + + //@} +}; +/*@}*/ +#endif diff --git a/src/libs/xpcom18a4/xpcom/base/nsISupportsObsolete.h b/src/libs/xpcom18a4/xpcom/base/nsISupportsObsolete.h new file mode 100644 index 00000000..874d859f --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/base/nsISupportsObsolete.h @@ -0,0 +1,243 @@ +/* ***** 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 XPCOM. + * + * The Initial Developer of the Original Code is Netscape Communications Corp. + * Portions created by the Initial Developer are Copyright (C) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * 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 ***** */ + + +#ifndef nsISupportsObsolete_h__ +#define nsISupportsObsolete_h__ + +#include "prcmon.h" + +/////////////////////////////////////////////////////////////////////////////// + + +#define NS_INIT_REFCNT() NS_INIT_ISUPPORTS() + +/** + * Macro to free an array of pointers to nsISupports (or classes + * derived from it). A convenience wrapper around + * NS_FREE_XPCOM_POINTER_ARRAY. + * + * Note that if you know that none of your nsISupports pointers are + * going to be 0, you can gain a bit of speed by calling + * NS_FREE_XPCOM_POINTER_ARRAY directly and using NS_RELEASE as your + * free function. + * + * @param size Number of elements in the array. If not a constant, this + * should be a PRInt32. Note that this means this macro + * will not work if size >= 2^31. + * @param array The array to be freed. + */ +#define NS_FREE_XPCOM_ISUPPORTS_POINTER_ARRAY(size, array) \ + NS_FREE_XPCOM_POINTER_ARRAY((size), (array), NS_IF_RELEASE) + + +/////////////////////////////////////////////////////////////////////////////// + +/* use these functions to associate get/set methods with a + C++ member variable +*/ + +#define NS_METHOD_GETTER(_method, _type, _member) \ +_method(_type* aResult) \ +{\ + if (!aResult) return NS_ERROR_NULL_POINTER; \ + *aResult = _member; \ + return NS_OK; \ +} + +#define NS_METHOD_SETTER(_method, _type, _member) \ +_method(_type aResult) \ +{ \ + _member = aResult; \ + return NS_OK; \ +} + +/* + * special for strings to get/set char* strings + * using PL_strdup and PR_FREEIF + */ +#define NS_METHOD_GETTER_STR(_method,_member) \ +_method(char* *aString) \ +{ \ + if (!aString) return NS_ERROR_NULL_POINTER; \ + if (!(*aString = PL_strdup(_member))) \ + return NS_ERROR_OUT_OF_MEMORY; \ + return NS_OK; \ +} + +#define NS_METHOD_SETTER_STR(_method, _member) \ +_method(const char *aString) \ +{ \ + if (_member) PR_Free(_member); \ + if (!aString) \ + _member = nsnull; \ + else if (!(_member = PL_strdup(aString))) \ + return NS_ERROR_OUT_OF_MEMORY; \ + return NS_OK; \ +} + +/* Getter/Setter macros. + Usage: + NS_IMPL_[CLASS_]GETTER[_](method, [type,] member); + NS_IMPL_[CLASS_]SETTER[_](method, [type,] member); + NS_IMPL_[CLASS_]GETSET[_]([class, ]postfix, [type,] member); + + where: + CLASS_ - implementation is inside a class definition + (otherwise the class name is needed) + Do NOT use in publicly exported header files, because + the implementation may be included many times over. + Instead, use the non-CLASS_ version. + _ - For more complex (STR, IFACE) data types + (otherwise the simple data type is needed) + method - name of the method, such as GetWidth or SetColor + type - simple data type if required + member - class member variable such as m_width or mColor + class - the class name, such as Window or MyObject + postfix - Method part after Get/Set such as "Width" for "GetWidth" + + Example: + class Window { + public: + NS_IMPL_CLASS_GETSET(Width, int, m_width); + NS_IMPL_CLASS_GETTER_STR(GetColor, m_color); + NS_IMETHOD SetColor(char *color); + + private: + int m_width; // read/write + char *m_color; // readonly + }; + + // defined outside of class + NS_IMPL_SETTER_STR(Window::GetColor, m_color); + + Questions/Comments to alecf@netscape.com +*/ + + +/* + * Getter/Setter implementation within a class definition + */ + +/* simple data types */ +#define NS_IMPL_CLASS_GETTER(_method, _type, _member) \ +NS_IMETHOD NS_METHOD_GETTER(_method, _type, _member) + +#define NS_IMPL_CLASS_SETTER(_method, _type, _member) \ +NS_IMETHOD NS_METHOD_SETTER(_method, _type, _member) + +#define NS_IMPL_CLASS_GETSET(_postfix, _type, _member) \ +NS_IMPL_CLASS_GETTER(Get##_postfix, _type, _member) \ +NS_IMPL_CLASS_SETTER(Set##_postfix, _type, _member) + +/* strings */ +#define NS_IMPL_CLASS_GETTER_STR(_method, _member) \ +NS_IMETHOD NS_METHOD_GETTER_STR(_method, _member) + +#define NS_IMPL_CLASS_SETTER_STR(_method, _member) \ +NS_IMETHOD NS_METHOD_SETTER_STR(_method, _member) + +#define NS_IMPL_CLASS_GETSET_STR(_postfix, _member) \ +NS_IMPL_CLASS_GETTER_STR(Get##_postfix, _member) \ +NS_IMPL_CLASS_SETTER_STR(Set##_postfix, _member) + +/* Getter/Setter implementation outside of a class definition */ + +/* simple data types */ +#define NS_IMPL_GETTER(_method, _type, _member) \ +NS_IMETHODIMP NS_METHOD_GETTER(_method, _type, _member) + +#define NS_IMPL_SETTER(_method, _type, _member) \ +NS_IMETHODIMP NS_METHOD_SETTER(_method, _type, _member) + +#define NS_IMPL_GETSET(_class, _postfix, _type, _member) \ +NS_IMPL_GETTER(_class::Get##_postfix, _type, _member) \ +NS_IMPL_SETTER(_class::Set##_postfix, _type, _member) + +/* strings */ +#define NS_IMPL_GETTER_STR(_method, _member) \ +NS_IMETHODIMP NS_METHOD_GETTER_STR(_method, _member) + +#define NS_IMPL_SETTER_STR(_method, _member) \ +NS_IMETHODIMP NS_METHOD_SETTER_STR(_method, _member) + +#define NS_IMPL_GETSET_STR(_class, _postfix, _member) \ +NS_IMPL_GETTER_STR(_class::Get##_postfix, _member) \ +NS_IMPL_SETTER_STR(_class::Set##_postfix, _member) + +/** + * IID for the nsIsThreadsafe interface + * {88210890-47a6-11d2-bec3-00805f8a66dc} + * + * This interface is *only* used for debugging purposes to determine if + * a given component is threadsafe. + */ +#define NS_ISTHREADSAFE_IID \ + { 0x88210890, 0x47a6, 0x11d2, \ + {0xbe, 0xc3, 0x00, 0x80, 0x5f, 0x8a, 0x66, 0xdc} } + +#define NS_LOCK_INSTANCE() \ + PR_CEnterMonitor((void*)this) +#define NS_UNLOCK_INSTANCE() \ + PR_CExitMonitor((void*)this) + +/** + * This implements query interface with two assumptions: First, the + * class in question implements nsISupports and its own interface and + * nothing else. Second, the implementation of the class's primary + * inheritance chain leads to its own interface. + * + * @param _class The name of the class implementing the method + * @param _classiiddef The name of the #define symbol that defines the IID + * for the class (e.g. NS_ISUPPORTS_IID) + */ +#if defined(NS_DEBUG) +#define NS_VERIFY_THREADSAFE_INTERFACE(_iface) \ + if (NULL != (_iface)) { \ + nsISupports* tmp; \ + static NS_DEFINE_IID(kIsThreadsafeIID, NS_ISTHREADSAFE_IID); \ + NS_PRECONDITION((NS_OK == _iface->QueryInterface(kIsThreadsafeIID, \ + (void**)&tmp)), \ + "Interface is not threadsafe"); \ + } +#else +#define NS_VERIFY_THREADSAFE_INTERFACE(_iface) +#endif + +//////////////////////////////////////////////////////////////////////////////// + + + +#endif diff --git a/src/libs/xpcom18a4/xpcom/base/nsISystemInfo.idl b/src/libs/xpcom18a4/xpcom/base/nsISystemInfo.idl new file mode 100644 index 00000000..0351196a --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/base/nsISystemInfo.idl @@ -0,0 +1,62 @@ +/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mike Shaver + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsISupports.idl" + +/** + * System information service. + * + * At present, a thin wrapper around PR_GetSystemInfo. + */ + +[scriptable,uuid(4189b420-1dd2-11b2-bff7-daaf5c1f7b10)] +interface nsISystemInfo : nsISupports +{ + /** The system hostname. */ + readonly attribute string hostname; + + /** The operating system name. */ + readonly attribute string OSName; + + /** The operating system version. */ + readonly attribute string OSVersion; + + /** The processor architecture of the machine. */ + readonly attribute string architecture; +}; + diff --git a/src/libs/xpcom18a4/xpcom/base/nsITraceRefcnt.idl b/src/libs/xpcom18a4/xpcom/base/nsITraceRefcnt.idl new file mode 100644 index 00000000..536861a0 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/base/nsITraceRefcnt.idl @@ -0,0 +1,72 @@ +/* ***** 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 XPCOM + * + * The Initial Developer of the Original Code is Doug Turner + * + * Portions created by the Initial Developer are Copyright (C) 2003 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * 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 "nsISupports.idl" + +/** + * nsITraceRefcnt is an interface between XPCOM Glue and XPCOM. Users should + * access the nsITraceRefcnt interface through the static class nsTraceRefcnt. + * @see nsTraceRefcnt.h + * + * @status UNDER_REVIEW + */ + +[uuid(273dc92f-0fe6-4545-96a9-21be77828039)] +interface nsITraceRefcnt : nsISupports +{ + void logAddRef(in voidPtr aPtr, + in nsrefcnt aNewRefcnt, + in string aTypeName, + in unsigned long aInstanceSize); + + void logRelease(in voidPtr aPtr, + in nsrefcnt aNewRefcnt, + in string aTypeName); + + void logCtor(in voidPtr aPtr, + in string aTypeName, + in unsigned long aInstanceSize); + + void logDtor(in voidPtr aPtr, + in string aTypeName, + in unsigned long aInstanceSize); + + + void logAddCOMPtr(in voidPtr aPtr, in nsISupports aObject); + + void logReleaseCOMPtr(in voidPtr aPtr, in nsISupports aObject); +}; diff --git a/src/libs/xpcom18a4/xpcom/base/nsIWeakReference.idl b/src/libs/xpcom18a4/xpcom/base/nsIWeakReference.idl new file mode 100644 index 00000000..2806fc8a --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/base/nsIWeakReference.idl @@ -0,0 +1,102 @@ +/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * ***** 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 the Mozilla browser. + * + * The Initial Developer of the Original Code is + * Netscape Communications, Inc. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Pierre Phaneuf + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsISupports.idl" + + +/** + * An instance of |nsIWeakReference| is a proxy object that cooperates with + * its referent to give clients a non-owning, non-dangling reference. Clients + * own the proxy, and should generally manage it with an |nsCOMPtr| (see the + * type |nsWeakPtr| for a |typedef| name that stands out) as they would any + * other XPCOM object. The |QueryReferent| member function provides a + * (hopefully short-lived) owning reference on demand, through which clients + * can get useful access to the referent, while it still exists. + * + * @status FROZEN + * @version 1.0 + * @see nsISupportsWeakReference + * @see nsWeakReference + * @see nsWeakPtr + */ +[scriptable, uuid(9188bc85-f92e-11d2-81ef-0060083a0bcf)] +interface nsIWeakReference : nsISupports + { + /** + * |QueryReferent| queries the referent, if it exists, and like |QueryInterface|, produces + * an owning reference to the desired interface. It is designed to look and act exactly + * like (a proxied) |QueryInterface|. Don't hold on to the produced interface permanently; + * that would defeat the purpose of using a non-owning |nsIWeakReference| in the first place. + */ + void QueryReferent( in nsIIDRef uuid, [iid_is(uuid), retval] out nsQIResult result ); + }; + + +/** + * |nsISupportsWeakReference| is a factory interface which produces appropriate + * instances of |nsIWeakReference|. Weak references in this scheme can only be + * produced for objects that implement this interface. + * + * @status FROZEN + * @version 1.0 + * @see nsIWeakReference + * @see nsSupportsWeakReference + */ +[scriptable, uuid(9188bc86-f92e-11d2-81ef-0060083a0bcf)] +interface nsISupportsWeakReference : nsISupports + { + /** + * |GetWeakReference| produces an appropriate instance of |nsIWeakReference|. + * As with all good XPCOM `getters', you own the resulting interface and should + * manage it with an |nsCOMPtr|. + * + * @see nsIWeakReference + * @see nsWeakPtr + * @see nsCOMPtr + */ + nsIWeakReference GetWeakReference(); + }; + + +%{C++ +#ifndef MOZILLA_STRICT_API +#include "nsIWeakReferenceUtils.h" +#endif +%} + diff --git a/src/libs/xpcom18a4/xpcom/base/nsLeakDetector.cpp b/src/libs/xpcom18a4/xpcom/base/nsLeakDetector.cpp new file mode 100644 index 00000000..a42f77bf --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/base/nsLeakDetector.cpp @@ -0,0 +1,248 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + * + * ***** 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 the Mozilla browser. + * + * The Initial Developer of the Original Code is + * Netscape Communications, Inc. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Patrick C. Beard + * Scott Collins + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +#if defined(GC_LEAK_DETECTOR) + +#include "nsLeakDetector.h" +#include "nsCOMPtr.h" +#include "nsIComponentManager.h" +#include "nsIServiceManager.h" +#include "nsIGenericFactory.h" +#include "nsILeakDetector.h" +#include "nsICollection.h" + +#include +#include + +#include "gc.h" + +extern "C" { +extern FILE *GC_stdout, *GC_stderr; +extern void GC_trace_object(GC_PTR object, int verbose); +extern void GC_mark_object(GC_PTR object, GC_word mark); +} + +static nsresult nextLeakFile() +{ + if (GC_stderr != NULL) + fclose(GC_stderr); + + // generate a time stamped report name. + time_t timer; + time(&timer); + tm* now = localtime(&timer); + + char reportName[256]; + sprintf(reportName, "Leaks%02d%02d%02d", + now->tm_hour, now->tm_min, now->tm_sec); + GC_stderr = fopen(reportName, "w"); + + return NS_OK; +} + +static FILE* openTraceFile() +{ + // generate a time stamped report name. + time_t timer; + time(&timer); + tm* now = localtime(&timer); + + char reportName[256]; + sprintf(reportName, "Trace%02d%02d%02d", + now->tm_hour, now->tm_min, now->tm_sec); + return fopen(reportName, "w"); +} + +class nsLeakDetector : public nsILeakDetector { +public: + nsLeakDetector(); + + NS_DECL_ISUPPORTS + NS_DECL_NSILEAKDETECTOR +private: + ~nsLeakDetector() {} +}; + +NS_IMPL_ISUPPORTS1(nsLeakDetector, nsILeakDetector) + +nsLeakDetector::nsLeakDetector() { + } + +NS_METHOD nsLeakDetector::DumpLeaks() +{ + GC_gcollect(); + + return nextLeakFile(); +} + +NS_METHOD nsLeakDetector::TraceObject(nsISupports* object, PRBool verbose) +{ + FILE* trace = openTraceFile(); + if (trace != NULL) { + FILE* old_stderr = GC_stderr; + GC_stderr = trace; + GC_trace_object(object, (verbose ? 1 : 0)); + GC_stderr = old_stderr; + fclose(trace); + return NS_OK; + } + return NS_ERROR_FAILURE; +} + +NS_METHOD nsLeakDetector::TraceCollection(nsICollection* objects, PRBool verbose) +{ + PRUint32 count; + if (NS_FAILED(objects->Count(&count))) + return NS_ERROR_FAILURE; + + nsCOMPtr* elements = new nsCOMPtr[count]; + if (elements == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + + for (PRUint32 i = 0; i < count; ++i) + objects->GetElementAt(i, getter_AddRefs(elements[i])); + + nsresult rv = NS_ERROR_FAILURE; + FILE* trace = openTraceFile(); + if (trace != NULL) { + FILE* old_stderr = GC_stderr; + GC_stderr = trace; + GC_trace_object(elements, (verbose ? 1 : 0)); + GC_stderr = old_stderr; + fclose(trace); + rv = NS_OK; + } + + delete[] elements; + + return rv; +} + +NS_METHOD nsLeakDetector::MarkObject(nsISupports* object, PRBool marked) +{ + GC_mark_object(object, (marked ? 1 : 0)); + return NS_OK; +} + +NS_METHOD nsLeakDetector::GetServices(nsISupports* *result) +{ + return NS_GetServiceManager((nsIServiceManager**)result); +} + +#define NS_CLEAKDETECTOR_CID_STR "bb1ba360-1dd1-11b2-b30e-aa2314429f54" +#define NS_CLEAKDETECTOR_CID {0xbb1ba360, 0x1dd1, 0x11b2, {0xb3, 0x0e, 0xaa, 0x23, 0x14, 0x42, 0x9f, 0x54}} +#define NS_CLEAKDETECTOR_CONTRACTID "@mozilla.org/xpcom/leakdetector;1" + +NS_GENERIC_FACTORY_CONSTRUCTOR(nsLeakDetector) + +static NS_DEFINE_CID(kCLeakDetectorCID, NS_CLEAKDETECTOR_CID); + +nsresult NS_InitLeakDetector() +{ + nsresult rv; + + // open the first leak file. + rv = nextLeakFile(); + if (NS_FAILED(rv)) + return rv; + + static const nsModuleComponentInfo info = { + "Leak Detector", kCLeakDetectorCID, NS_CLEAKDETECTOR_CONTRACTID, nsLeakDetectorConstructor + }; + + // create a generic factory for the leak detector. + nsCOMPtr factory; + rv = NS_NewGenericFactory(getter_AddRefs(factory), &info); + if (NS_FAILED(rv)) + return rv; + + // register this factory with the component manager. + return nsComponentManager::RegisterFactory(info.mCID, info.mDescription, info.mContractID, factory, PR_TRUE); +} + +#ifdef XP_MAC +#define SHUTDOWN_LEAKS_EARLY +#undef SHUTDOWN_LEAKS_MEDIUM +#undef SHUTDOWN_LEAKS_LATE +#else +#undef SHUTDOWN_LEAKS_EARLY +#undef SHUTDOWN_LEAKS_MEDIUM +#define SHUTDOWN_LEAKS_LATE +#endif + +class LeakDetectorFinalizer +{ +public: + ~LeakDetectorFinalizer(); +}; + +#ifdef SHUTDOWN_LEAKS_LATE +// do shutdown leaks when XPCOM library is unloaded +LeakDetectorFinalizer gLeakDetectorFinalizer; +#endif + +LeakDetectorFinalizer::~LeakDetectorFinalizer() +{ + GC_gcollect(); + +#if 0 + nextLeakFile(); + if (GC_stdout != NULL) { + fprintf(GC_stdout, "ShutDown Leaks\n"); + GC_clear_roots(); + GC_gcollect(); + } +#endif +} + +nsresult NS_ShutdownLeakDetector() +{ +#if defined(SHUTDOWN_LEAKS_MEDIUM) + // Make this the first atexit() called so it's before the atexit() crashes + // see http://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=23552 + static LeakDetectorFinalizer trick; +#elif defined(SHUTDOWN_LEAKS_EARLY) + // do shutdown leaks now + LeakDetectorFinalizer trick; +#endif + return NS_OK; +} + +#endif /* defined(GC_LEAK_DETECTOR) */ diff --git a/src/libs/xpcom18a4/xpcom/base/nsLeakDetector.h b/src/libs/xpcom18a4/xpcom/base/nsLeakDetector.h new file mode 100644 index 00000000..5c560401 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/base/nsLeakDetector.h @@ -0,0 +1,60 @@ +/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * ***** 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 the Mozilla browser. + * + * The Initial Developer of the Original Code is + * Netscape Communications, Inc. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Patrick C. Beard + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +#ifndef nsLeakDetector_h +#define nsLeakDetector_h + +#ifndef nsError_h +#include "nsError.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +nsresult NS_InitGarbageCollector(void); +nsresult NS_InitLeakDetector(void); +nsresult NS_ShutdownLeakDetector(void); +nsresult NS_ShutdownGarbageCollector(void); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* nsLeakDetector_h */ diff --git a/src/libs/xpcom18a4/xpcom/base/nsMemoryImpl.cpp b/src/libs/xpcom18a4/xpcom/base/nsMemoryImpl.cpp new file mode 100644 index 00000000..8aa16e58 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/base/nsMemoryImpl.cpp @@ -0,0 +1,548 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsMemoryImpl.h" +#include "prmem.h" +#include "nsAlgorithm.h" +#include "nsIServiceManager.h" +#include "nsIObserverService.h" +#include "nsAutoLock.h" +#include "nsIThread.h" +#include "nsIEventQueueService.h" +#include "nsString.h" + +#if defined(XP_WIN) +#include +#define NS_MEMORY_FLUSHER_THREAD +#elif defined(XP_MAC) +#include +#define NS_MEMORY_FLUSHER_THREAD +#else +// Need to implement the nsIMemory::IsLowMemory() predicate +#undef NS_MEMORY_FLUSHER_THREAD +#endif + +//---------------------------------------------------------------------- + +#if defined(XDEBUG_waterson) +#define NS_TEST_MEMORY_FLUSHER +#endif + +/** + * A runnable that is used to periodically check the status + * of the system, determine if too much memory is in use, + * and if so, trigger a "memory flush". + */ +class MemoryFlusher : public nsIRunnable +{ +protected: + nsMemoryImpl* mMemoryImpl; // WEAK, it owns us. + PRBool mRunning; + PRIntervalTime mTimeout; + PRLock* mLock; + PRCondVar* mCVar; + + MemoryFlusher(nsMemoryImpl* aMemoryImpl); + + enum { + kInitialTimeout = 60 /*seconds*/ + }; + +private: + ~MemoryFlusher(); + +public: + /** + * Create a memory flusher. + * @param aResult the memory flusher + * @param aMemoryImpl the owning nsMemoryImpl object + * @return NS_OK if the memory flusher was created successfully + */ + static nsresult + Create(MemoryFlusher** aResult, nsMemoryImpl* aMemoryImpl); + + NS_DECL_ISUPPORTS + NS_DECL_NSIRUNNABLE + + /** + * Stop the memory flusher. + */ + nsresult Stop(); +}; + + +MemoryFlusher::MemoryFlusher(nsMemoryImpl* aMemoryImpl) + : mMemoryImpl(aMemoryImpl), + mRunning(PR_FALSE), + mTimeout(PR_SecondsToInterval(kInitialTimeout)), + mLock(nsnull), + mCVar(nsnull) +{ +} + +MemoryFlusher::~MemoryFlusher() +{ + if (mLock) + PR_DestroyLock(mLock); + + if (mCVar) + PR_DestroyCondVar(mCVar); +} + + +nsresult +MemoryFlusher::Create(MemoryFlusher** aResult, nsMemoryImpl* aMemoryImpl) +{ + MemoryFlusher* result = new MemoryFlusher(aMemoryImpl); + if (! result) + return NS_ERROR_OUT_OF_MEMORY; + + do { + if ((result->mLock = PR_NewLock()) == nsnull) + break; + + if ((result->mCVar = PR_NewCondVar(result->mLock)) == nsnull) + break; + + NS_ADDREF(*aResult = result); + return NS_OK; + } while (0); + + // Something bad happened if we get here... + delete result; + return NS_ERROR_OUT_OF_MEMORY; +} + +NS_IMPL_THREADSAFE_ISUPPORTS1(MemoryFlusher, nsIRunnable) + +NS_IMETHODIMP +MemoryFlusher::Run() +{ + nsresult rv; + + mRunning = PR_TRUE; + + while (1) { + PRStatus status; + + { + nsAutoLock l(mLock); + if (! mRunning) { + rv = NS_OK; + break; + } + + status = PR_WaitCondVar(mCVar, mTimeout); + } + + if (status != PR_SUCCESS) { + rv = NS_ERROR_FAILURE; + break; + } + + if (! mRunning) { + rv = NS_OK; + break; + } + + PRBool isLowMemory; + rv = mMemoryImpl->IsLowMemory(&isLowMemory); + if (NS_FAILED(rv)) + break; + +#ifdef NS_TEST_MEMORY_FLUSHER + // Fire the flusher *every* time + isLowMemory = PR_TRUE; +#endif + + if (isLowMemory) { + mMemoryImpl->FlushMemory(NS_LITERAL_STRING("low-memory").get(), PR_FALSE); + } + } + + mRunning = PR_FALSE; + + return rv; +} + + +nsresult +MemoryFlusher::Stop() +{ + if (mRunning) { + nsAutoLock l(mLock); + mRunning = PR_FALSE; + PR_NotifyCondVar(mCVar); + } + + return NS_OK; +} + +//---------------------------------------------------------------------- + +nsMemoryImpl* gMemory = nsnull; + +NS_IMPL_THREADSAFE_ISUPPORTS1(nsMemoryImpl, nsIMemory) + +NS_METHOD +nsMemoryImpl::Create(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr) +{ + NS_ENSURE_ARG_POINTER(aInstancePtr); + NS_ENSURE_PROPER_AGGREGATION(outer, aIID); + if (gMemory && NS_SUCCEEDED(gMemory->QueryInterface(aIID, aInstancePtr))) + return NS_OK; + + nsMemoryImpl* mm = new nsMemoryImpl(); + if (mm == NULL) + return NS_ERROR_OUT_OF_MEMORY; + + nsresult rv; + + do { + rv = mm->QueryInterface(aIID, aInstancePtr); + if (NS_FAILED(rv)) + break; + + rv = NS_ERROR_OUT_OF_MEMORY; + + mm->mFlushLock = PR_NewLock(); + if (! mm->mFlushLock) + break; + + rv = NS_OK; + } while (0); + + if (NS_FAILED(rv)) + delete mm; + + return rv; +} + + +nsMemoryImpl::nsMemoryImpl() + : mFlusher(nsnull), + mFlushLock(nsnull), + mIsFlushing(PR_FALSE) +{ +} + +nsMemoryImpl::~nsMemoryImpl() +{ + if (mFlushLock) + PR_DestroyLock(mFlushLock); +} + +//////////////////////////////////////////////////////////////////////////////// +// Define NS_OUT_OF_MEMORY_TESTER if you want to force memory failures + +#ifdef DEBUG_xwarren +#define NS_OUT_OF_MEMORY_TESTER +#endif + +#ifdef NS_OUT_OF_MEMORY_TESTER + +// flush memory one in this number of times: +#define NS_FLUSH_FREQUENCY 100000 + +// fail allocation one in this number of flushes: +#define NS_FAIL_FREQUENCY 10 + +PRUint32 gFlushFreq = 0; +PRUint32 gFailFreq = 0; + +static void* +mallocator(PRSize size, PRUint32& counter, PRUint32 max) +{ + if (counter++ >= max) { + counter = 0; + NS_ASSERTION(0, "about to fail allocation... watch out"); + return nsnull; + } + return PR_Malloc(size); +} + +static void* +reallocator(void* ptr, PRSize size, PRUint32& counter, PRUint32 max) +{ + if (counter++ >= max) { + counter = 0; + NS_ASSERTION(0, "about to fail reallocation... watch out"); + return nsnull; + } + return PR_Realloc(ptr, size); +} + +#define MALLOC1(s) mallocator(s, gFlushFreq, NS_FLUSH_FREQUENCY) +#define REALLOC1(p, s) reallocator(p, s, gFlushFreq, NS_FLUSH_FREQUENCY) + +#else + +#define MALLOC1(s) PR_Malloc(s) +#define REALLOC1(p, s) PR_Realloc(p, s) + +#endif // NS_OUT_OF_MEMORY_TESTER + +//////////////////////////////////////////////////////////////////////////////// + +NS_IMETHODIMP_(void *) +nsMemoryImpl::Alloc(PRSize size) +{ + NS_ASSERTION(size, "nsMemoryImpl::Alloc of 0"); + void* result = MALLOC1(size); + if (! result) { + // Request an asynchronous flush + FlushMemory(NS_LITERAL_STRING("alloc-failure").get(), PR_FALSE); + } + return result; +} + +NS_IMETHODIMP_(void *) +nsMemoryImpl::Realloc(void * ptr, PRSize size) +{ + void* result = REALLOC1(ptr, size); + if (! result) { + // Request an asynchronous flush + FlushMemory(NS_LITERAL_STRING("alloc-failure").get(), PR_FALSE); + } + return result; +} + +NS_IMETHODIMP_(void) +nsMemoryImpl::Free(void * ptr) +{ + PR_Free(ptr); +} + +NS_IMETHODIMP +nsMemoryImpl::HeapMinimize(PRBool aImmediate) +{ + return FlushMemory(NS_LITERAL_STRING("heap-minimize").get(), aImmediate); +} + +NS_IMETHODIMP +nsMemoryImpl::IsLowMemory(PRBool *result) +{ +#if defined(XP_WIN) + MEMORYSTATUS stat; + GlobalMemoryStatus(&stat); + *result = ((float)stat.dwAvailPageFile / stat.dwTotalPageFile) < 0.1; +#elif defined(XP_MAC) + + const long kReserveHeapFreeSpace = (256 * 1024); + const long kReserveHeapContigSpace = (128 * 1024); + + long totalSpace, contiguousSpace; + // this call measures how much memory would be available if the OS + // purged. Despite the name, it does not purge (that happens + // automatically when heap space is low). + ::PurgeSpace(&totalSpace, &contiguousSpace); + if (totalSpace < kReserveHeapFreeSpace || contiguousSpace < kReserveHeapContigSpace) + { + NS_WARNING("Found that heap mem is low"); + *result = PR_TRUE; + return NS_OK; + } + + // see how much temp mem is available (since our allocators allocate 1Mb chunks + // in temp mem. We don't use TempMaxMem() (to get contig space) here, because it + // compacts the application heap, so can be slow. + const long kReserveTempFreeSpace = (2 * 1024 * 1024); // 2Mb + long totalTempSpace = ::TempFreeMem(); + if (totalTempSpace < kReserveTempFreeSpace) + { + NS_WARNING("Found that temp mem is low"); + *result = PR_TRUE; + return NS_OK; + } + + *result = PR_FALSE; + +#else + *result = PR_FALSE; +#endif + return NS_OK; +} + +nsresult +nsMemoryImpl::FlushMemory(const PRUnichar* aReason, PRBool aImmediate) +{ + nsresult rv; + + if (aImmediate) { + // They've asked us to run the flusher *immediately*. We've + // got to be on the UI main thread for us to be able to do + // that...are we? + PRBool isOnUIThread = PR_FALSE; + + nsCOMPtr main; + rv = nsIThread::GetMainThread(getter_AddRefs(main)); + if (NS_SUCCEEDED(rv)) { + nsCOMPtr current; + rv = nsIThread::GetCurrent(getter_AddRefs(current)); + if (NS_SUCCEEDED(rv)) { + if (current == main) + isOnUIThread = PR_TRUE; + } + } + + if (! isOnUIThread) { + NS_ERROR("can't synchronously flush memory: not on UI thread"); + return NS_ERROR_FAILURE; + } + } + + { + // Are we already flushing? + nsAutoLock l(mFlushLock); + if (mIsFlushing) + return NS_OK; + + // Well, we are now! + mIsFlushing = PR_TRUE; + } + + // Run the flushers immediately if we can; otherwise, proxy to the + // UI thread an run 'em asynchronously. + if (aImmediate) { + rv = RunFlushers(this, aReason); + } + else { + nsCOMPtr eqs = do_GetService(NS_EVENTQUEUESERVICE_CONTRACTID, &rv); + if (eqs) { + nsCOMPtr eq; + rv = eqs->GetThreadEventQueue(NS_UI_THREAD, getter_AddRefs(eq)); + if (NS_SUCCEEDED(rv)) { + PL_InitEvent(&mFlushEvent.mEvent, this, HandleFlushEvent, DestroyFlushEvent); + mFlushEvent.mReason = aReason; + + rv = eq->PostEvent(NS_REINTERPRET_CAST(PLEvent*, &mFlushEvent)); + } + } + } + + return rv; +} + +nsresult +nsMemoryImpl::RunFlushers(nsMemoryImpl* aSelf, const PRUnichar* aReason) +{ + nsCOMPtr os = do_GetService("@mozilla.org/observer-service;1"); + if (os) { + os->NotifyObservers(aSelf, "memory-pressure", aReason); + } + + { + // Done flushing + nsAutoLock l(aSelf->mFlushLock); + aSelf->mIsFlushing = PR_FALSE; + } + + return NS_OK; +} + +void* +nsMemoryImpl::HandleFlushEvent(PLEvent* aEvent) +{ + nsMemoryImpl* self = NS_STATIC_CAST(nsMemoryImpl*, PL_GetEventOwner(aEvent)); + FlushEvent* event = NS_REINTERPRET_CAST(FlushEvent*, aEvent); + + RunFlushers(self, event->mReason); + return 0; +} + +void +nsMemoryImpl::DestroyFlushEvent(PLEvent* aEvent) +{ + // no-op, since mEvent is a member of nsMemoryImpl +} + +static void +EnsureGlobalMemoryService() +{ + if (gMemory) return; + nsresult rv = nsMemoryImpl::Create(nsnull, NS_GET_IID(nsIMemory), (void**)&gMemory); + NS_ASSERTION(NS_SUCCEEDED(rv), "nsMemoryImpl::Create failed"); + NS_ASSERTION(gMemory, "improper xpcom initialization"); +} + +nsresult +nsMemoryImpl::Startup() +{ + EnsureGlobalMemoryService(); + if (! gMemory) + return NS_ERROR_FAILURE; + +#ifdef NS_MEMORY_FLUSHER_THREAD + nsresult rv; + + // Create and start a memory flusher thread + rv = MemoryFlusher::Create(&gMemory->mFlusher, gMemory); + if (NS_FAILED(rv)) return rv; + + rv = NS_NewThread(getter_AddRefs(gMemory->mFlusherThread), + gMemory->mFlusher, + 0, /* XXX use default stack size? */ + PR_JOINABLE_THREAD); + + if (NS_FAILED(rv)) return rv; +#endif + + return NS_OK; +} + +nsresult +nsMemoryImpl::Shutdown() +{ + if (gMemory) { +#ifdef NS_MEMORY_FLUSHER_THREAD + if (gMemory->mFlusher) { + // Stop the runnable... + gMemory->mFlusher->Stop(); + NS_RELEASE(gMemory->mFlusher); + + // ...and wait for the thread to exit + if (gMemory->mFlusherThread) + gMemory->mFlusherThread->Join(); + } +#endif + + NS_RELEASE(gMemory); + gMemory = nsnull; + } + + return NS_OK; +} diff --git a/src/libs/xpcom18a4/xpcom/base/nsMemoryImpl.h b/src/libs/xpcom18a4/xpcom/base/nsMemoryImpl.h new file mode 100644 index 00000000..c9086d11 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/base/nsMemoryImpl.h @@ -0,0 +1,91 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +#ifndef nsMemoryImpl_h__ +#define nsMemoryImpl_h__ + +#include "nsMemory.h" +#include "nsISupportsArray.h" +#include "nsIRunnable.h" +#include "nsIThread.h" +#include "nsCOMPtr.h" +#include "plevent.h" + +struct PRLock; +class MemoryFlusher; + +class nsMemoryImpl : public nsIMemory +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIMEMORY + + nsMemoryImpl(); + + nsresult FlushMemory(const PRUnichar* aReason, PRBool aImmediate); + + // called from xpcom initialization/finalization: + static nsresult Startup(); + static nsresult Shutdown(); + + static NS_METHOD + Create(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr); + +private: + ~nsMemoryImpl(); + +protected: + MemoryFlusher* mFlusher; + nsCOMPtr mFlusherThread; + + PRLock* mFlushLock; + PRBool mIsFlushing; + + struct FlushEvent { + PLEvent mEvent; + const PRUnichar* mReason; + }; + + FlushEvent mFlushEvent; + + static nsresult RunFlushers(nsMemoryImpl* aSelf, const PRUnichar* aReason); + + static void* PR_CALLBACK HandleFlushEvent(PLEvent* aEvent); + static void PR_CALLBACK DestroyFlushEvent(PLEvent* aEvent); +}; + +#endif // nsMemoryImpl_h__ diff --git a/src/libs/xpcom18a4/xpcom/base/nsStackFrameUnix.cpp b/src/libs/xpcom18a4/xpcom/base/nsStackFrameUnix.cpp new file mode 100644 index 00000000..11fe0fca --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/base/nsStackFrameUnix.cpp @@ -0,0 +1,375 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** 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 nsStackFrameWin.h code, released + * December 20, 2000. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2003 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsStackFrameUnix.h" +#include +#include +#include +#include "nscore.h" + +// On glibc 2.1, the Dl_info api defined in is only exposed +// if __USE_GNU is defined. I suppose its some kind of standards +// adherence thing. +// +#if (__GLIBC_MINOR__ >= 1) && !defined(__USE_GNU) +#define __USE_GNU +#endif + +#ifdef HAVE_LIBDL +#include +#endif + + + +// This thing is exported by libstdc++ +// Yes, this is a gcc only hack +#if defined(MOZ_DEMANGLE_SYMBOLS) +#include +#include // for free() +#endif // MOZ_DEMANGLE_SYMBOLS + +void DemangleSymbol(const char * aSymbol, + char * aBuffer, + int aBufLen) +{ + aBuffer[0] = '\0'; + +#if defined(MOZ_DEMANGLE_SYMBOLS) + /* See demangle.h in the gcc source for the voodoo */ + char * demangled = abi::__cxa_demangle(aSymbol,0,0,0); + + if (demangled) + { + strncpy(aBuffer,demangled,aBufLen); + free(demangled); + } +#endif // MOZ_DEMANGLE_SYMBOLS +} + + +#if defined(linux) && !defined(VBOX) && defined(__GLIBC__) && (defined(__i386) || defined(PPC)) // i386 or PPC Linux stackwalking code + +#include +// + +void DumpStackToFile(FILE* aStream) +{ + jmp_buf jb; + setjmp(jb); + + // Stack walking code courtesy Kipp's "leaky". + + // Get the frame pointer out of the jmp_buf + void **bp = (void**) +#if defined(__i386) + (jb[0].__jmpbuf[JB_BP]); +#elif defined(PPC) + (jb[0].__jmpbuf[JB_GPR1]); +#endif + + int skip = 2; + for ( ; (void**)*bp > bp; bp = (void**)*bp) { + void *pc = *(bp+1); + if (--skip <= 0) { + Dl_info info; + int ok = dladdr(pc, &info); + if (!ok) { + fprintf(aStream, "UNKNOWN %p\n", pc); + continue; + } + + PRUint32 foff = (char*)pc - (char*)info.dli_fbase; + + const char * symbol = info.dli_sname; + int len; + if (!symbol || !(len = strlen(symbol))) { + fprintf(aStream, "UNKNOWN [%s +0x%08X]\n", + info.dli_fname, foff); + continue; + } + + char demangled[4096] = "\0"; + + DemangleSymbol(symbol, demangled, sizeof(demangled)); + + if (strlen(demangled)) { + symbol = demangled; + len = strlen(symbol); + } + + PRUint32 off = (char*)pc - (char*)info.dli_saddr; + fprintf(aStream, "%s+0x%08X [%s +0x%08X]\n", + symbol, off, info.dli_fname, foff); + } + } +} + +#elif defined(__sun) && (defined(__sparc) || defined(sparc) || defined(__i386) || defined(i386)) + +/* + * Stack walking code for Solaris courtesy of Bart Smaalder's "memtrak". + */ + +#include +#include +#include +#include +#include + +static int load_address ( void * pc, void * arg, FILE * aStream ); +static int write_address_file ( void * pc ); +static struct bucket * newbucket ( void * pc ); +static struct frame * cs_getmyframeptr ( void ); +static void cs_walk_stack ( void * (*read_func)(char * address), + struct frame * fp, + int (*operate_func)(void *, void *), + void * usrarg, FILE * aStream ); +static void cs_operate ( void (*operate_func)(void *, void *), + void * usrarg, FILE * aStream ); + +#ifndef STACK_BIAS +#define STACK_BIAS 0 +#endif /*STACK_BIAS*/ + +#define LOGSIZE 4096 + +/* type of demangling function */ +typedef int demf_t(const char *, char *, size_t); + +static demf_t *demf; + +static int initialized = 0; + +#if defined(sparc) || defined(__sparc) +#define FRAME_PTR_REGISTER REG_SP +#endif + +#if defined(i386) || defined(__i386) +#define FRAME_PTR_REGISTER EBP +#endif + +struct bucket { + void * pc; + int index; + struct bucket * next; +}; + +struct mybuf { + char * buffer; + int chars_left; +}; + + +static void myinit(); + +#pragma init (myinit) + +static void +myinit() +{ + + if (! initialized) { +#ifndef __GNUC__ + void *handle; + const char *libdem = "libdemangle.so.1"; + + /* load libdemangle if we can and need to (only try this once) */ + if ((handle = dlopen(libdem, RTLD_LAZY)) != NULL) { + demf = (demf_t *)dlsym(handle, + "cplus_demangle"); /*lint !e611 */ + /* + * lint override above is to prevent lint from + * complaining about "suspicious cast". + */ + } +#endif /*__GNUC__*/ + } + initialized = 1; +} + + +static int +write_address_file(void * pc, FILE* aStream) +{ + static struct bucket table[2048]; + static mutex_t lock; + struct bucket * ptr; + + unsigned int val = NS_PTR_TO_INT32(pc); + + ptr = table + ((val >> 2)&2047); + + mutex_lock(&lock); + while (ptr->next) { + if (ptr->next->pc == pc) + break; + ptr = ptr->next; + } + + if (ptr->next) { + mutex_unlock(&lock); + return (ptr->next->index); + } else { + char buffer[4096], dembuff[4096]; + Dl_info info; + const char *func = "??", *lib = "??"; + + ptr->next = newbucket(pc); + mutex_unlock(&lock); + + if (dladdr(pc, & info)) { + if (info.dli_fname) + lib = info.dli_fname; + if (info.dli_sname) + func = info.dli_sname; + } + +#ifdef __GNUC__ + DemangleSymbol(func, dembuff, sizeof(dembuff)); +#else + if (!demf || demf(func, dembuff, sizeof (dembuff))) + dembuff[0] = 0; +#endif /*__GNUC__*/ + if (strlen(dembuff)) { + func = dembuff; + } + fprintf(aStream, "%u %s:%s+0x%x\n", + ptr->next->index, + lib, + func, + (char *)pc - (char*)info.dli_saddr); + + return (ptr->next->index); + } +} + + +static int +load_address(void * pc, void * arg, FILE * aStream) +{ + struct mybuf * buf = (struct mybuf *) arg; + + char name[80]; + int len; + + sprintf(name, " %u", write_address_file(pc, aStream)); + + len = strlen(name); + + if (len >= buf->chars_left) + return (1); + + strcat(buf->buffer, name); + + buf->chars_left -= len; + + return (0); +} + + +static struct bucket * +newbucket(void * pc) +{ + struct bucket * ptr = (struct bucket *) malloc(sizeof (*ptr)); + static int index; /* protected by lock in caller */ + + ptr->index = index++; + ptr->next = NULL; + ptr->pc = pc; + return (ptr); +} + + +static struct frame * +csgetframeptr() +{ + ucontext_t u; + struct frame *fp; + + (void) getcontext(&u); + + fp = (struct frame *) + ((char *)u.uc_mcontext.gregs[FRAME_PTR_REGISTER] + + STACK_BIAS); + + /* make sure to return parents frame pointer.... */ + + return ((struct frame *)((ulong_t)fp->fr_savfp + STACK_BIAS)); +} + + +static void +cswalkstack(struct frame *fp, int (*operate_func)(void *, void *, FILE *), + void *usrarg, FILE * aStream) +{ + + while (fp != 0 && fp->fr_savpc != 0) { + + if (operate_func((void *)fp->fr_savpc, usrarg, aStream) != 0) + break; + /* + * watch out - libthread stacks look funny at the top + * so they may not have their STACK_BIAS set + */ + + fp = (struct frame *)((ulong_t)fp->fr_savfp + + (fp->fr_savfp?(ulong_t)STACK_BIAS:0)); + } +} + + +static void +cs_operate(int (*operate_func)(void *, void *, FILE *), void * usrarg, FILE *aStream) +{ + cswalkstack(csgetframeptr(), operate_func, usrarg, aStream); +} + +void DumpStackToFile(FILE* aStream) +{ + char buffer[LOGSIZE]; + struct mybuf mybuf; + + if (!initialized) + myinit(); + + mybuf.chars_left = LOGSIZE - strlen(buffer)-1; + mybuf.buffer = buffer; + cs_operate(load_address, &mybuf, aStream); +} +#endif diff --git a/src/libs/xpcom18a4/xpcom/base/nsStackFrameUnix.h b/src/libs/xpcom18a4/xpcom/base/nsStackFrameUnix.h new file mode 100644 index 00000000..1673ae76 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/base/nsStackFrameUnix.h @@ -0,0 +1,46 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** 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 nsStackFrameWin.h code, released + * December 20, 2000. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2003 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ +#ifndef nsStackFrameUnix_h___ +#define nsStackFrameUnix_h___ + +#include "stdio.h" + +void DumpStackToFile(FILE* out); + +#endif diff --git a/src/libs/xpcom18a4/xpcom/base/nsStackFrameWin.cpp b/src/libs/xpcom18a4/xpcom/base/nsStackFrameWin.cpp new file mode 100644 index 00000000..7228356b --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/base/nsStackFrameWin.cpp @@ -0,0 +1,351 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** 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 nsStackFrameWin.h code, released + * December 20, 2003. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2003 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Michael Judge, 20-December-2000 + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nscore.h" +#include "windows.h" +#include "imagehlp.h" +#include "stdio.h" +#include "nsStackFrameWin.h" + +// Define these as static pointers so that we can load the DLL on the +// fly (and not introduce a link-time dependency on it). Tip o' the +// hat to Matt Pietrick for this idea. See: +// +// http://msdn.microsoft.com/library/periodic/period97/F1/D3/S245C6.htm +// + + +PR_BEGIN_EXTERN_C + +SYMSETOPTIONSPROC _SymSetOptions; + +SYMINITIALIZEPROC _SymInitialize; + +SYMCLEANUPPROC _SymCleanup; + +STACKWALKPROC _StackWalk; + +SYMFUNCTIONTABLEACCESSPROC _SymFunctionTableAccess; + +SYMGETMODULEBASEPROC _SymGetModuleBase; + +SYMGETSYMFROMADDRPROC _SymGetSymFromAddr; + +SYMLOADMODULE _SymLoadModule; + +SYMUNDNAME _SymUnDName; + +SYMGETMODULEINFO _SymGetModuleInfo; + +ENUMLOADEDMODULES _EnumerateLoadedModules; + +SYMGETLINEFROMADDRPROC _SymGetLineFromAddr; + +PR_END_EXTERN_C + + + + +PRBool +EnsureImageHlpInitialized() +{ + static PRBool gInitialized = PR_FALSE; + + if (! gInitialized) { + HMODULE module = ::LoadLibrary("IMAGEHLP.DLL"); + if (!module) return PR_FALSE; + + _SymSetOptions = (SYMSETOPTIONSPROC) ::GetProcAddress(module, "SymSetOptions"); + if (!_SymSetOptions) return PR_FALSE; + + _SymInitialize = (SYMINITIALIZEPROC) ::GetProcAddress(module, "SymInitialize"); + if (!_SymInitialize) return PR_FALSE; + + _SymCleanup = (SYMCLEANUPPROC)GetProcAddress(module, "SymCleanup"); + if (!_SymCleanup) return PR_FALSE; + + _StackWalk = (STACKWALKPROC)GetProcAddress(module, "StackWalk"); + if (!_StackWalk) return PR_FALSE; + + _SymFunctionTableAccess = (SYMFUNCTIONTABLEACCESSPROC) GetProcAddress(module, "SymFunctionTableAccess"); + if (!_SymFunctionTableAccess) return PR_FALSE; + + _SymGetModuleBase = (SYMGETMODULEBASEPROC)GetProcAddress(module, "SymGetModuleBase"); + if (!_SymGetModuleBase) return PR_FALSE; + + _SymGetSymFromAddr = (SYMGETSYMFROMADDRPROC)GetProcAddress(module, "SymGetSymFromAddr"); + if (!_SymGetSymFromAddr) return PR_FALSE; + + _SymLoadModule = (SYMLOADMODULE)GetProcAddress(module, "SymLoadModule"); + if (!_SymLoadModule) return PR_FALSE; + + _SymUnDName = (SYMUNDNAME)GetProcAddress(module, "SymUnDName"); + if (!_SymUnDName) return PR_FALSE; + + _SymGetModuleInfo = (SYMGETMODULEINFO)GetProcAddress(module, "SymGetModuleInfo"); + if (!_SymGetModuleInfo) return PR_FALSE; + + _EnumerateLoadedModules = (ENUMLOADEDMODULES)GetProcAddress(module, "EnumerateLoadedModules"); + if (!_EnumerateLoadedModules) return PR_FALSE; + + _SymGetLineFromAddr = (SYMGETLINEFROMADDRPROC)GetProcAddress(module, "SymGetLineFromAddr"); + if (!_SymGetLineFromAddr) return PR_FALSE; + + gInitialized = PR_TRUE; + } + + return gInitialized; +} + +/* + * Callback used by SymGetModuleInfoEspecial + */ +static BOOL CALLBACK callbackEspecial(LPSTR aModuleName, ULONG aModuleBase, ULONG aModuleSize, PVOID aUserContext) +{ + BOOL retval = TRUE; + DWORD addr = (DWORD)aUserContext; + + /* + * You'll want to control this if we are running on an + * architecture where the addresses go the other direction. + * Not sure this is even a realistic consideration. + */ + const BOOL addressIncreases = TRUE; + + /* + * If it falls in side the known range, load the symbols. + */ + if(addressIncreases + ? (addr >= aModuleBase && addr <= (aModuleBase + aModuleSize)) + : (addr <= aModuleBase && addr >= (aModuleBase - aModuleSize)) + ) + { + BOOL loadRes = FALSE; + HANDLE process = GetCurrentProcess(); + + loadRes = _SymLoadModule(process, NULL, aModuleName, NULL, aModuleBase, aModuleSize); + PR_ASSERT(FALSE != loadRes); + } + + return retval; +} + +/* + * SymGetModuleInfoEspecial + * + * Attempt to determine the module information. + * Bug 112196 says this DLL may not have been loaded at the time + * SymInitialize was called, and thus the module information + * and symbol information is not available. + * This code rectifies that problem. + */ +BOOL SymGetModuleInfoEspecial(HANDLE aProcess, DWORD aAddr, PIMAGEHLP_MODULE aModuleInfo, PIMAGEHLP_LINE aLineInfo) +{ + BOOL retval = FALSE; + + /* + * Init the vars if we have em. + */ + aModuleInfo->SizeOfStruct = sizeof(IMAGEHLP_MODULE); + if (nsnull != aLineInfo) { + aLineInfo->SizeOfStruct = sizeof(IMAGEHLP_LINE); + } + + /* + * Give it a go. + * It may already be loaded. + */ + retval = _SymGetModuleInfo(aProcess, aAddr, aModuleInfo); + + if (FALSE == retval) { + BOOL enumRes = FALSE; + + /* + * Not loaded, here's the magic. + * Go through all the modules. + */ + enumRes = _EnumerateLoadedModules(aProcess, callbackEspecial, (PVOID)aAddr); + if(FALSE != enumRes) + { + /* + * One final go. + * If it fails, then well, we have other problems. + */ + retval = _SymGetModuleInfo(aProcess, aAddr, aModuleInfo); + } + } + + /* + * If we got module info, we may attempt line info as well. + * We will not report failure if this does not work. + */ + if (FALSE != retval && nsnull != aLineInfo && nsnull != _SymGetLineFromAddr) { + DWORD displacement = 0; + BOOL lineRes = FALSE; + + lineRes = _SymGetLineFromAddr(aProcess, aAddr, &displacement, aLineInfo); + } + + return retval; +} + +PRBool +EnsureSymInitialized() +{ + static PRBool gInitialized = PR_FALSE; + + if (! gInitialized) { + if (! EnsureImageHlpInitialized()) + return PR_FALSE; + _SymSetOptions(SYMOPT_LOAD_LINES | SYMOPT_UNDNAME); + gInitialized = _SymInitialize(GetCurrentProcess(), 0, TRUE); + } + return gInitialized; +} + + +/** + * Walk the stack, translating PC's found into strings and recording the + * chain in aBuffer. For this to work properly, the dll's must be rebased + * so that the address in the file agrees with the address in memory. + * Otherwise StackWalk will return FALSE when it hits a frame in a dll's + * whose in memory address doesn't match it's in-file address. + * + * Fortunately, there is a handy dandy routine in IMAGEHLP.DLL that does + * the rebasing and accordingly I've made a tool to use it to rebase the + * DLL's in one fell swoop (see xpcom/tools/windows/rebasedlls.cpp). + */ + + +void +DumpStackToFile(FILE* aStream) +{ + HANDLE myProcess = ::GetCurrentProcess(); + HANDLE myThread = ::GetCurrentThread(); + BOOL ok; + + ok = EnsureSymInitialized(); + if (! ok) + return; + + // Get the context information for this thread. That way we will + // know where our sp, fp, pc, etc. are and can fill in the + // STACKFRAME with the initial values. + CONTEXT context; + context.ContextFlags = CONTEXT_FULL; + ok = GetThreadContext(myThread, &context); + if (! ok) + return; + + // Setup initial stack frame to walk from + STACKFRAME frame; + memset(&frame, 0, sizeof(frame)); + frame.AddrPC.Offset = context.Eip; + frame.AddrPC.Mode = AddrModeFlat; + frame.AddrStack.Offset = context.Esp; + frame.AddrStack.Mode = AddrModeFlat; + frame.AddrFrame.Offset = context.Ebp; + frame.AddrFrame.Mode = AddrModeFlat; + + // Now walk the stack and map the pc's to symbol names + int skip = 2; + while (1) { + ok = _StackWalk(IMAGE_FILE_MACHINE_I386, + myProcess, + myThread, + &frame, + &context, + 0, // read process memory routine + _SymFunctionTableAccess, // function table access routine + _SymGetModuleBase, // module base routine + 0); // translate address routine + + if (!ok) { + LPVOID lpMsgBuf; + FormatMessage( + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + GetLastError(), + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language + (LPTSTR) &lpMsgBuf, + 0, + NULL + ); + fprintf(aStream, "### ERROR: WalkStack: %s", lpMsgBuf); + fflush(aStream); + LocalFree( lpMsgBuf ); + } + if (!ok || frame.AddrPC.Offset == 0) + break; + + if (skip-- > 0) + continue; + + // + // Attempt to load module info before we attempt to reolve the symbol. + // This just makes sure we get good info if available. + // + IMAGEHLP_MODULE modInfo; + modInfo.SizeOfStruct = sizeof(modInfo); + BOOL modInfoRes = TRUE; + modInfoRes = SymGetModuleInfoEspecial(myProcess, frame.AddrPC.Offset, &modInfo, nsnull); + + char buf[sizeof(IMAGEHLP_SYMBOL) + 512]; + PIMAGEHLP_SYMBOL symbol = (PIMAGEHLP_SYMBOL) buf; + symbol->SizeOfStruct = sizeof(buf); + symbol->MaxNameLength = 512; + + DWORD displacement; + ok = _SymGetSymFromAddr(myProcess, + frame.AddrPC.Offset, + &displacement, + symbol); + + if (ok) { + fprintf(aStream, "%s+0x%08X\n", symbol->Name, displacement); + } + else { + fprintf(aStream, "0x%08X\n", frame.AddrPC.Offset); + } + } +} + diff --git a/src/libs/xpcom18a4/xpcom/base/nsStackFrameWin.h b/src/libs/xpcom18a4/xpcom/base/nsStackFrameWin.h new file mode 100644 index 00000000..d9b6585c --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/base/nsStackFrameWin.h @@ -0,0 +1,126 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** 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 nsStackFrameWin.h code, released + * December 20, 2000. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Michael Judge, 20-December-2000 + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ +#ifndef nsStackFrameWin_h___ +#define nsStackFrameWin_h___ + + +#if defined(_WIN32) && defined(_M_IX86) // WIN32 x86 stack walking code +#include "nspr.h" +#include +#include + +// Define these as static pointers so that we can load the DLL on the +// fly (and not introduce a link-time dependency on it). Tip o' the +// hat to Matt Pietrick for this idea. See: +// +// http://msdn.microsoft.com/library/periodic/period97/F1/D3/S245C6.htm +// +PR_BEGIN_EXTERN_C + +typedef DWORD (__stdcall *SYMSETOPTIONSPROC)(DWORD); +extern SYMSETOPTIONSPROC _SymSetOptions; + +typedef BOOL (__stdcall *SYMINITIALIZEPROC)(HANDLE, LPSTR, BOOL); +extern SYMINITIALIZEPROC _SymInitialize; + +typedef BOOL (__stdcall *SYMCLEANUPPROC)(HANDLE); +extern SYMCLEANUPPROC _SymCleanup; + +typedef BOOL (__stdcall *STACKWALKPROC)(DWORD, + HANDLE, + HANDLE, + LPSTACKFRAME, + LPVOID, + PREAD_PROCESS_MEMORY_ROUTINE, + PFUNCTION_TABLE_ACCESS_ROUTINE, + PGET_MODULE_BASE_ROUTINE, + PTRANSLATE_ADDRESS_ROUTINE); +extern STACKWALKPROC _StackWalk; + +typedef LPVOID (__stdcall *SYMFUNCTIONTABLEACCESSPROC)(HANDLE, DWORD); +extern SYMFUNCTIONTABLEACCESSPROC _SymFunctionTableAccess; + +typedef DWORD (__stdcall *SYMGETMODULEBASEPROC)(HANDLE, DWORD); +extern SYMGETMODULEBASEPROC _SymGetModuleBase; + +typedef BOOL (__stdcall *SYMGETSYMFROMADDRPROC)(HANDLE, DWORD, PDWORD, PIMAGEHLP_SYMBOL); +extern SYMGETSYMFROMADDRPROC _SymGetSymFromAddr; + +typedef DWORD ( __stdcall *SYMLOADMODULE)(HANDLE, HANDLE, PSTR, PSTR, DWORD, DWORD); +extern SYMLOADMODULE _SymLoadModule; + +typedef DWORD ( __stdcall *SYMUNDNAME)(PIMAGEHLP_SYMBOL, PSTR, DWORD); +extern SYMUNDNAME _SymUnDName; + +typedef DWORD ( __stdcall *SYMGETMODULEINFO)( HANDLE, DWORD, PIMAGEHLP_MODULE); +extern SYMGETMODULEINFO _SymGetModuleInfo; + +typedef BOOL ( __stdcall *ENUMLOADEDMODULES)( HANDLE, PENUMLOADED_MODULES_CALLBACK, PVOID); +extern ENUMLOADEDMODULES _EnumerateLoadedModules; + +typedef BOOL (__stdcall *SYMGETLINEFROMADDRPROC)(HANDLE, DWORD, PDWORD, PIMAGEHLP_LINE); +extern SYMGETLINEFROMADDRPROC _SymGetLineFromAddr; + +PRBool EnsureSymInitialized(); + +PRBool EnsureImageHlpInitialized(); + +/* + * SymGetModuleInfoEspecial + * + * Attempt to determine the module information. + * Bug 112196 says this DLL may not have been loaded at the time + * SymInitialize was called, and thus the module information + * and symbol information is not available. + * This code rectifies that problem. + * Line information is optional. + */ +BOOL SymGetModuleInfoEspecial(HANDLE aProcess, DWORD aAddr, PIMAGEHLP_MODULE aModuleInfo, PIMAGEHLP_LINE aLineInfo); + + +void DumpStackToFile(FILE* out); + +PR_END_EXTERN_C + +#endif //WIN32 + +#endif //nsStackFrameWin_h___ + + diff --git a/src/libs/xpcom18a4/xpcom/base/nsTraceRefcntImpl.cpp b/src/libs/xpcom18a4/xpcom/base/nsTraceRefcntImpl.cpp new file mode 100644 index 00000000..f74e84df --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/base/nsTraceRefcntImpl.cpp @@ -0,0 +1,1444 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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 Communicator client code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * L. David Baron + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsTraceRefcntImpl.h" +#include "nscore.h" +#include "nsISupports.h" +#include "nsVoidArray.h" +#include "prprf.h" +#include "prlog.h" +#include "plstr.h" +#include +#include "nsCOMPtr.h" +#include "nsCRT.h" +#include + +#if defined(_WIN32) +#include +#elif defined(linux) && !defined(VBOX) && defined(__GLIBC__) && (defined(__i386) || defined(PPC)) +#include + +// +// On glibc 2.1, the Dl_info api defined in is only exposed +// if __USE_GNU is defined. I suppose its some kind of standards +// adherence thing. +// +#if (__GLIBC_MINOR__ >= 1) && !defined(__USE_GNU) +#define __USE_GNU +#endif + +#include +#endif + +#ifdef HAVE_LIBDL +#include +#endif + +#if defined(XP_MAC) && !TARGET_CARBON +#include "macstdlibextras.h" +#endif + +//////////////////////////////////////////////////////////////////////////////// + +NS_COM void +NS_MeanAndStdDev(double n, double sumOfValues, double sumOfSquaredValues, + double *meanResult, double *stdDevResult) +{ + double mean = 0.0, var = 0.0, stdDev = 0.0; + if (n > 0.0 && sumOfValues >= 0) { + mean = sumOfValues / n; + double temp = (n * sumOfSquaredValues) - (sumOfValues * sumOfValues); + if (temp < 0.0 || n <= 1) + var = 0.0; + else + var = temp / (n * (n - 1)); + // for some reason, Windows says sqrt(0.0) is "-1.#J" (?!) so do this: + stdDev = var != 0.0 ? sqrt(var) : 0.0; + } + *meanResult = mean; + *stdDevResult = stdDev; +} + +//////////////////////////////////////////////////////////////////////////////// + +#ifdef NS_BUILD_REFCNT_LOGGING +#include "plhash.h" +#include "prmem.h" + +#include "prlock.h" + +static PRLock* gTraceLock; + +#define LOCK_TRACELOG() PR_Lock(gTraceLock) +#define UNLOCK_TRACELOG() PR_Unlock(gTraceLock) + +static PLHashTable* gBloatView; +static PLHashTable* gTypesToLog; +static PLHashTable* gObjectsToLog; +static PLHashTable* gSerialNumbers; +static PRInt32 gNextSerialNumber; + +static PRBool gLogging; +static PRBool gLogToLeaky; +static PRBool gLogLeaksOnly; + +static void (*leakyLogAddRef)(void* p, int oldrc, int newrc); +static void (*leakyLogRelease)(void* p, int oldrc, int newrc); + +static PRBool gInitialized = PR_FALSE; +static FILE *gBloatLog = nsnull; +static FILE *gRefcntsLog = nsnull; +static FILE *gAllocLog = nsnull; +static FILE *gLeakyLog = nsnull; +static FILE *gCOMPtrLog = nsnull; +static PRBool gActivityIsLegal = PR_FALSE; + +struct serialNumberRecord { + PRInt32 serialNumber; + PRInt32 refCount; + PRInt32 COMPtrCount; +}; + +struct nsTraceRefcntStats { + nsrefcnt mAddRefs; + nsrefcnt mReleases; + nsrefcnt mCreates; + nsrefcnt mDestroys; + double mRefsOutstandingTotal; + double mRefsOutstandingSquared; + double mObjsOutstandingTotal; + double mObjsOutstandingSquared; +}; + +#ifdef DEBUG_dbaron_off + // I hope to turn this on for everybody once we hit it a little less. +#define ASSERT_ACTIVITY_IS_LEGAL \ + NS_WARN_IF_FALSE(gActivityIsLegal, \ + "XPCOM objects created/destroyed from static ctor/dtor") +#else +#define ASSERT_ACTIVITY_IS_LEGAL +#endif + + +// These functions are copied from nsprpub/lib/ds/plhash.c, with changes +// to the functions not called Default* to free the serialNumberRecord or +// the BloatEntry. + +static void * PR_CALLBACK +DefaultAllocTable(void *pool, PRSize size) +{ +#if defined(XP_MAC) +#pragma unused (pool) +#endif + + return PR_MALLOC(size); +} + +static void PR_CALLBACK +DefaultFreeTable(void *pool, void *item) +{ +#if defined(XP_MAC) +#pragma unused (pool) +#endif + + PR_Free(item); +} + +static PLHashEntry * PR_CALLBACK +DefaultAllocEntry(void *pool, const void *key) +{ +#if defined(XP_MAC) +#pragma unused (pool,key) +#endif + + return PR_NEW(PLHashEntry); +} + +static void PR_CALLBACK +SerialNumberFreeEntry(void *pool, PLHashEntry *he, PRUintn flag) +{ +#if defined(XP_MAC) +#pragma unused (pool) +#endif + + if (flag == HT_FREE_ENTRY) { + PR_Free(NS_REINTERPRET_CAST(serialNumberRecord*,he->value)); + PR_Free(he); + } +} + +static void PR_CALLBACK +TypesToLogFreeEntry(void *pool, PLHashEntry *he, PRUintn flag) +{ +#if defined(XP_MAC) +#pragma unused (pool) +#endif + + if (flag == HT_FREE_ENTRY) { + nsCRT::free(NS_CONST_CAST(char*, + NS_REINTERPRET_CAST(const char*, he->key))); + PR_Free(he); + } +} + +static const PLHashAllocOps serialNumberHashAllocOps = { + DefaultAllocTable, DefaultFreeTable, + DefaultAllocEntry, SerialNumberFreeEntry +}; + +static const PLHashAllocOps typesToLogHashAllocOps = { + DefaultAllocTable, DefaultFreeTable, + DefaultAllocEntry, TypesToLogFreeEntry +}; + +//////////////////////////////////////////////////////////////////////////////// + +class BloatEntry { +public: + BloatEntry(const char* className, PRUint32 classSize) + : mClassSize(classSize) { + mClassName = PL_strdup(className); + Clear(&mNewStats); + Clear(&mAllStats); + mTotalLeaked = 0; + } + + ~BloatEntry() { + PL_strfree(mClassName); + } + + PRUint32 GetClassSize() { return (PRUint32)mClassSize; } + const char* GetClassName() { return mClassName; } + + static void Clear(nsTraceRefcntStats* stats) { + stats->mAddRefs = 0; + stats->mReleases = 0; + stats->mCreates = 0; + stats->mDestroys = 0; + stats->mRefsOutstandingTotal = 0; + stats->mRefsOutstandingSquared = 0; + stats->mObjsOutstandingTotal = 0; + stats->mObjsOutstandingSquared = 0; + } + + void Accumulate() { + mAllStats.mAddRefs += mNewStats.mAddRefs; + mAllStats.mReleases += mNewStats.mReleases; + mAllStats.mCreates += mNewStats.mCreates; + mAllStats.mDestroys += mNewStats.mDestroys; + mAllStats.mRefsOutstandingTotal += mNewStats.mRefsOutstandingTotal; + mAllStats.mRefsOutstandingSquared += mNewStats.mRefsOutstandingSquared; + mAllStats.mObjsOutstandingTotal += mNewStats.mObjsOutstandingTotal; + mAllStats.mObjsOutstandingSquared += mNewStats.mObjsOutstandingSquared; + Clear(&mNewStats); + } + + void AddRef(nsrefcnt refcnt) { + mNewStats.mAddRefs++; + if (refcnt == 1) { + Ctor(); + } + AccountRefs(); + } + + void Release(nsrefcnt refcnt) { + mNewStats.mReleases++; + if (refcnt == 0) { + Dtor(); + } + AccountRefs(); + } + + void Ctor() { + mNewStats.mCreates++; + AccountObjs(); + } + + void Dtor() { + mNewStats.mDestroys++; + AccountObjs(); + } + + void AccountRefs() { + PRInt32 cnt = (mNewStats.mAddRefs - mNewStats.mReleases); + mNewStats.mRefsOutstandingTotal += cnt; + mNewStats.mRefsOutstandingSquared += cnt * cnt; + } + + void AccountObjs() { + PRInt32 cnt = (mNewStats.mCreates - mNewStats.mDestroys); + mNewStats.mObjsOutstandingTotal += cnt; + mNewStats.mObjsOutstandingSquared += cnt * cnt; + } + + static PRIntn PR_CALLBACK DumpEntry(PLHashEntry *he, PRIntn i, void *arg) { + BloatEntry* entry = (BloatEntry*)he->value; + if (entry) { + entry->Accumulate(); + NS_STATIC_CAST(nsVoidArray*, arg)->AppendElement(entry); + } + return HT_ENUMERATE_NEXT; + } + + static PRIntn PR_CALLBACK TotalEntries(PLHashEntry *he, PRIntn i, void *arg) { + BloatEntry* entry = (BloatEntry*)he->value; + if (entry && nsCRT::strcmp(entry->mClassName, "TOTAL") != 0) { + entry->Total((BloatEntry*)arg); + } + return HT_ENUMERATE_NEXT; + } + + void Total(BloatEntry* total) { + total->mAllStats.mAddRefs += mNewStats.mAddRefs + mAllStats.mAddRefs; + total->mAllStats.mReleases += mNewStats.mReleases + mAllStats.mReleases; + total->mAllStats.mCreates += mNewStats.mCreates + mAllStats.mCreates; + total->mAllStats.mDestroys += mNewStats.mDestroys + mAllStats.mDestroys; + total->mAllStats.mRefsOutstandingTotal += mNewStats.mRefsOutstandingTotal + mAllStats.mRefsOutstandingTotal; + total->mAllStats.mRefsOutstandingSquared += mNewStats.mRefsOutstandingSquared + mAllStats.mRefsOutstandingSquared; + total->mAllStats.mObjsOutstandingTotal += mNewStats.mObjsOutstandingTotal + mAllStats.mObjsOutstandingTotal; + total->mAllStats.mObjsOutstandingSquared += mNewStats.mObjsOutstandingSquared + mAllStats.mObjsOutstandingSquared; + PRInt32 count = (mNewStats.mCreates + mAllStats.mCreates); + total->mClassSize += mClassSize * count; // adjust for average in DumpTotal + total->mTotalLeaked += (PRInt32)(mClassSize * + ((mNewStats.mCreates + mAllStats.mCreates) + -(mNewStats.mDestroys + mAllStats.mDestroys))); + } + + nsresult DumpTotal(PRUint32 nClasses, FILE* out) { + mClassSize /= mAllStats.mCreates; + return Dump(-1, out, nsTraceRefcntImpl::ALL_STATS); + } + + static PRBool HaveLeaks(nsTraceRefcntStats* stats) { + return ((stats->mAddRefs != stats->mReleases) || + (stats->mCreates != stats->mDestroys)); + } + + static nsresult PrintDumpHeader(FILE* out, const char* msg) { + fprintf(out, "\n== BloatView: %s\n\n", msg); + fprintf(out, + " |<----------------Class--------------->|<-----Bytes------>|<----------------Objects---------------->|<--------------References-------------->|\n"); + fprintf(out, + " Per-Inst Leaked Total Rem Mean StdDev Total Rem Mean StdDev\n"); + return NS_OK; + } + + nsresult Dump(PRIntn i, FILE* out, nsTraceRefcntImpl::StatisticsType type) { + nsTraceRefcntStats* stats = (type == nsTraceRefcntImpl::NEW_STATS) ? &mNewStats : &mAllStats; + if (gLogLeaksOnly && !HaveLeaks(stats)) { + return NS_OK; + } + + double meanRefs, stddevRefs; + NS_MeanAndStdDev(stats->mAddRefs + stats->mReleases, + stats->mRefsOutstandingTotal, + stats->mRefsOutstandingSquared, + &meanRefs, &stddevRefs); + + double meanObjs, stddevObjs; + NS_MeanAndStdDev(stats->mCreates + stats->mDestroys, + stats->mObjsOutstandingTotal, + stats->mObjsOutstandingSquared, + &meanObjs, &stddevObjs); + + if ((stats->mAddRefs - stats->mReleases) != 0 || + stats->mAddRefs != 0 || + meanRefs != 0 || + stddevRefs != 0 || + (stats->mCreates - stats->mDestroys) != 0 || + stats->mCreates != 0 || + meanObjs != 0 || + stddevObjs != 0) { + fprintf(out, "%4d %-40.40s %8d %8d %8d %8d (%8.2f +/- %8.2f) %8d %8d (%8.2f +/- %8.2f)\n", + i+1, mClassName, + (PRInt32)mClassSize, + (nsCRT::strcmp(mClassName, "TOTAL")) + ?(PRInt32)((stats->mCreates - stats->mDestroys) * mClassSize) + :mTotalLeaked, + stats->mCreates, + (stats->mCreates - stats->mDestroys), + meanObjs, + stddevObjs, + stats->mAddRefs, + (stats->mAddRefs - stats->mReleases), + meanRefs, + stddevRefs); + } + return NS_OK; + } + +protected: + char* mClassName; + double mClassSize; // this is stored as a double because of the way we compute the avg class size for total bloat + PRInt32 mTotalLeaked; // used only for TOTAL entry + nsTraceRefcntStats mNewStats; + nsTraceRefcntStats mAllStats; +}; + +static void PR_CALLBACK +BloatViewFreeEntry(void *pool, PLHashEntry *he, PRUintn flag) +{ +#if defined(XP_MAC) +#pragma unused (pool) +#endif + + if (flag == HT_FREE_ENTRY) { + BloatEntry* entry = NS_REINTERPRET_CAST(BloatEntry*,he->value); + delete entry; + PR_Free(he); + } +} + +const static PLHashAllocOps bloatViewHashAllocOps = { + DefaultAllocTable, DefaultFreeTable, + DefaultAllocEntry, BloatViewFreeEntry +}; + +static void +RecreateBloatView() +{ + gBloatView = PL_NewHashTable(256, + PL_HashString, + PL_CompareStrings, + PL_CompareValues, + &bloatViewHashAllocOps, NULL); +} + +static BloatEntry* +GetBloatEntry(const char* aTypeName, PRUint32 aInstanceSize) +{ + if (!gBloatView) { + RecreateBloatView(); + } + BloatEntry* entry = NULL; + if (gBloatView) { + entry = (BloatEntry*)PL_HashTableLookup(gBloatView, aTypeName); + if (entry == NULL && aInstanceSize > 0) { + + entry = new BloatEntry(aTypeName, aInstanceSize); + PLHashEntry* e = PL_HashTableAdd(gBloatView, aTypeName, entry); + if (e == NULL) { + delete entry; + entry = NULL; + } + } else { + NS_ASSERTION(aInstanceSize == 0 || + entry->GetClassSize() == aInstanceSize, + "bad size recorded"); + } + } + return entry; +} + +static PRIntn PR_CALLBACK DumpSerialNumbers(PLHashEntry* aHashEntry, PRIntn aIndex, void* aClosure) +{ + serialNumberRecord* record = NS_REINTERPRET_CAST(serialNumberRecord *,aHashEntry->value); +#ifdef HAVE_CPP_DYNAMIC_CAST_TO_VOID_PTR + fprintf((FILE*) aClosure, "%d (%d references; %d from COMPtrs)\n", + record->serialNumber, + record->refCount, + record->COMPtrCount); +#else + fprintf((FILE*) aClosure, "%d (%d references)\n", + record->serialNumber, + record->refCount); +#endif + return HT_ENUMERATE_NEXT; +} + + +#endif /* NS_BUILD_REFCNT_LOGGING */ + +nsresult +nsTraceRefcntImpl::DumpStatistics(StatisticsType type, FILE* out) +{ + nsresult rv = NS_OK; +#ifdef NS_BUILD_REFCNT_LOGGING + if (gBloatLog == nsnull || gBloatView == nsnull) { + return NS_ERROR_FAILURE; + } + if (out == nsnull) { + out = gBloatLog; + } + + LOCK_TRACELOG(); + + PRBool wasLogging = gLogging; + gLogging = PR_FALSE; // turn off logging for this method + + const char* msg; + if (type == NEW_STATS) { + if (gLogLeaksOnly) + msg = "NEW (incremental) LEAK STATISTICS"; + else + msg = "NEW (incremental) LEAK AND BLOAT STATISTICS"; + } + else { + if (gLogLeaksOnly) + msg = "ALL (cumulative) LEAK STATISTICS"; + else + msg = "ALL (cumulative) LEAK AND BLOAT STATISTICS"; + } + rv = BloatEntry::PrintDumpHeader(out, msg); + if (NS_FAILED(rv)) goto done; + + { + BloatEntry total("TOTAL", 0); + PL_HashTableEnumerateEntries(gBloatView, BloatEntry::TotalEntries, &total); + total.DumpTotal(gBloatView->nentries, out); + + nsVoidArray entries; + PL_HashTableEnumerateEntries(gBloatView, BloatEntry::DumpEntry, &entries); + + fprintf(stdout, "nsTraceRefcntImpl::DumpStatistics: %d entries\n", + entries.Count()); + + // Sort the entries alphabetically by classname. + PRInt32 i, j; + for (i = entries.Count() - 1; i >= 1; --i) { + for (j = i - 1; j >= 0; --j) { + BloatEntry* left = NS_STATIC_CAST(BloatEntry*, entries[i]); + BloatEntry* right = NS_STATIC_CAST(BloatEntry*, entries[j]); + + if (PL_strcmp(left->GetClassName(), right->GetClassName()) < 0) { + entries.ReplaceElementAt(right, i); + entries.ReplaceElementAt(left, j); + } + } + } + + // Enumerate from back-to-front, so things come out in alpha order + for (i = 0; i < entries.Count(); ++i) { + BloatEntry* entry = NS_STATIC_CAST(BloatEntry*, entries[i]); + entry->Dump(i, out, type); + } + } + + if (gSerialNumbers) { + fprintf(out, "\n\nSerial Numbers of Leaked Objects:\n"); + PL_HashTableEnumerateEntries(gSerialNumbers, DumpSerialNumbers, out); + } + +done: + gLogging = wasLogging; + UNLOCK_TRACELOG(); +#endif + return rv; +} + +void +nsTraceRefcntImpl::ResetStatistics() +{ +#ifdef NS_BUILD_REFCNT_LOGGING + LOCK_TRACELOG(); + if (gBloatView) { + PL_HashTableDestroy(gBloatView); + gBloatView = nsnull; + } + UNLOCK_TRACELOG(); +#endif +} + +#ifdef NS_BUILD_REFCNT_LOGGING +static PRBool LogThisType(const char* aTypeName) +{ + void* he = PL_HashTableLookup(gTypesToLog, aTypeName); + return nsnull != he; +} + +static PRInt32 GetSerialNumber(void* aPtr, PRBool aCreate) +{ +#ifdef GC_LEAK_DETECTOR + // need to disguise this pointer, so the table won't keep the object alive. + aPtr = (void*) ~PLHashNumber(aPtr); +#endif + PLHashEntry** hep = PL_HashTableRawLookup(gSerialNumbers, PLHashNumber(NS_PTR_TO_INT32(aPtr)), aPtr); + if (hep && *hep) { + return PRInt32((NS_REINTERPRET_CAST(serialNumberRecord*,(*hep)->value))->serialNumber); + } + else if (aCreate) { + serialNumberRecord *record = PR_NEW(serialNumberRecord); + record->serialNumber = ++gNextSerialNumber; + record->refCount = 0; + record->COMPtrCount = 0; + PL_HashTableRawAdd(gSerialNumbers, hep, PLHashNumber(NS_PTR_TO_INT32(aPtr)), aPtr, NS_REINTERPRET_CAST(void*,record)); + return gNextSerialNumber; + } + else { + return 0; + } +} + +static PRInt32* GetRefCount(void* aPtr) +{ +#ifdef GC_LEAK_DETECTOR + // need to disguise this pointer, so the table won't keep the object alive. + aPtr = (void*) ~PLHashNumber(aPtr); +#endif + PLHashEntry** hep = PL_HashTableRawLookup(gSerialNumbers, PLHashNumber(NS_PTR_TO_INT32(aPtr)), aPtr); + if (hep && *hep) { + return &((NS_REINTERPRET_CAST(serialNumberRecord*,(*hep)->value))->refCount); + } else { + return nsnull; + } +} + +static PRInt32* GetCOMPtrCount(void* aPtr) +{ +#ifdef GC_LEAK_DETECTOR + // need to disguise this pointer, so the table won't keep the object alive. + aPtr = (void*) ~PLHashNumber(aPtr); +#endif + PLHashEntry** hep = PL_HashTableRawLookup(gSerialNumbers, PLHashNumber(NS_PTR_TO_INT32(aPtr)), aPtr); + if (hep && *hep) { + return &((NS_REINTERPRET_CAST(serialNumberRecord*,(*hep)->value))->COMPtrCount); + } else { + return nsnull; + } +} + +static void RecycleSerialNumberPtr(void* aPtr) +{ +#ifdef GC_LEAK_DETECTOR + // need to disguise this pointer, so the table won't keep the object alive. + aPtr = (void*) ~PLHashNumber(aPtr); +#endif + PL_HashTableRemove(gSerialNumbers, aPtr); +} + +static PRBool LogThisObj(PRInt32 aSerialNumber) +{ + return nsnull != PL_HashTableLookup(gObjectsToLog, (const void*)(uintptr_t)(aSerialNumber)); +} + +static PRBool InitLog(const char* envVar, const char* msg, FILE* *result) +{ + const char* value = getenv(envVar); + if (value) { + if (nsCRT::strcmp(value, "1") == 0) { + *result = stdout; + fprintf(stdout, "### %s defined -- logging %s to stdout\n", + envVar, msg); + return PR_TRUE; + } + else if (nsCRT::strcmp(value, "2") == 0) { + *result = stderr; + fprintf(stdout, "### %s defined -- logging %s to stderr\n", + envVar, msg); + return PR_TRUE; + } + else { + FILE *stream = ::fopen(value, "w"); + if (stream != NULL) { + *result = stream; + fprintf(stdout, "### %s defined -- logging %s to %s\n", + envVar, msg, value); + return PR_TRUE; + } + else { + fprintf(stdout, "### %s defined -- unable to log %s to %s\n", + envVar, msg, value); + return PR_FALSE; + } + } + } + return PR_FALSE; +} + + +static PLHashNumber PR_CALLBACK HashNumber(const void* aKey) +{ + return PLHashNumber(NS_PTR_TO_INT32(aKey)); +} + +static void InitTraceLog(void) +{ + if (gInitialized) return; + gInitialized = PR_TRUE; + +#if defined(XP_MAC) && !TARGET_CARBON + // this can get called before Toolbox has been initialized. + InitializeMacToolbox(); +#endif + + PRBool defined; + defined = InitLog("XPCOM_MEM_BLOAT_LOG", "bloat/leaks", &gBloatLog); + if (!defined) + gLogLeaksOnly = InitLog("XPCOM_MEM_LEAK_LOG", "leaks", &gBloatLog); + if (defined || gLogLeaksOnly) { + RecreateBloatView(); + if (!gBloatView) { + NS_WARNING("out of memory"); + gBloatLog = nsnull; + gLogLeaksOnly = PR_FALSE; + } + } + + (void)InitLog("XPCOM_MEM_REFCNT_LOG", "refcounts", &gRefcntsLog); + + (void)InitLog("XPCOM_MEM_ALLOC_LOG", "new/delete", &gAllocLog); + + defined = InitLog("XPCOM_MEM_LEAKY_LOG", "for leaky", &gLeakyLog); + if (defined) { + gLogToLeaky = PR_TRUE; + void* p = nsnull; + void* q = nsnull; +#ifdef HAVE_LIBDL + p = dlsym(0, "__log_addref"); + q = dlsym(0, "__log_release"); +#endif + if (p && q) { + leakyLogAddRef = (void (*)(void*,int,int)) p; + leakyLogRelease = (void (*)(void*,int,int)) q; + } + else { + gLogToLeaky = PR_FALSE; + fprintf(stdout, "### ERROR: XPCOM_MEM_LEAKY_LOG defined, but can't locate __log_addref and __log_release symbols\n"); + fflush(stdout); + } + } + + const char* classes = getenv("XPCOM_MEM_LOG_CLASSES"); + +#ifdef HAVE_CPP_DYNAMIC_CAST_TO_VOID_PTR + if (classes) { + (void)InitLog("XPCOM_MEM_COMPTR_LOG", "nsCOMPtr", &gCOMPtrLog); + } else { + if (getenv("XPCOM_MEM_COMPTR_LOG")) { + fprintf(stdout, "### XPCOM_MEM_COMPTR_LOG defined -- but XPCOM_MEM_LOG_CLASSES is not defined\n"); + } + } +#else + const char* comptr_log = getenv("XPCOM_MEM_COMPTR_LOG"); + if (comptr_log) { + fprintf(stdout, "### XPCOM_MEM_COMPTR_LOG defined -- but it will not work without dynamic_cast\n"); + } +#endif + + if (classes) { + // if XPCOM_MEM_LOG_CLASSES was set to some value, the value is interpreted + // as a list of class names to track + gTypesToLog = PL_NewHashTable(256, + PL_HashString, + PL_CompareStrings, + PL_CompareValues, + &typesToLogHashAllocOps, NULL); + if (!gTypesToLog) { + NS_WARNING("out of memory"); + fprintf(stdout, "### XPCOM_MEM_LOG_CLASSES defined -- unable to log specific classes\n"); + } + else { + fprintf(stdout, "### XPCOM_MEM_LOG_CLASSES defined -- only logging these classes: "); + const char* cp = classes; + for (;;) { + char* cm = (char*) strchr(cp, ','); + if (cm) { + *cm = '\0'; + } + PL_HashTableAdd(gTypesToLog, nsCRT::strdup(cp), (void*)1); + fprintf(stdout, "%s ", cp); + if (!cm) break; + *cm = ','; + cp = cm + 1; + } + fprintf(stdout, "\n"); + } + + gSerialNumbers = PL_NewHashTable(256, + HashNumber, + PL_CompareValues, + PL_CompareValues, + &serialNumberHashAllocOps, NULL); + + + } + + const char* objects = getenv("XPCOM_MEM_LOG_OBJECTS"); + if (objects) { + gObjectsToLog = PL_NewHashTable(256, + HashNumber, + PL_CompareValues, + PL_CompareValues, + NULL, NULL); + + if (!gObjectsToLog) { + NS_WARNING("out of memory"); + fprintf(stdout, "### XPCOM_MEM_LOG_OBJECTS defined -- unable to log specific objects\n"); + } + else if (! (gRefcntsLog || gAllocLog || gCOMPtrLog)) { + fprintf(stdout, "### XPCOM_MEM_LOG_OBJECTS defined -- but none of XPCOM_MEM_(REFCNT|ALLOC|COMPTR)_LOG is defined\n"); + } + else { + fprintf(stdout, "### XPCOM_MEM_LOG_OBJECTS defined -- only logging these objects: "); + const char* cp = objects; + for (;;) { + char* cm = (char*) strchr(cp, ','); + if (cm) { + *cm = '\0'; + } + PRInt32 top = 0; + PRInt32 bottom = 0; + while (*cp) { + if (*cp == '-') { + bottom = top; + top = 0; + ++cp; + } + top *= 10; + top += *cp - '0'; + ++cp; + } + if (!bottom) { + bottom = top; + } + for(PRInt32 serialno = bottom; serialno <= top; serialno++) { + PL_HashTableAdd(gObjectsToLog, (const void*)serialno, (void*)1); + fprintf(stdout, "%d ", serialno); + } + if (!cm) break; + *cm = ','; + cp = cm + 1; + } + fprintf(stdout, "\n"); + } + } + + + if (gBloatLog || gRefcntsLog || gAllocLog || gLeakyLog || gCOMPtrLog) { + gLogging = PR_TRUE; + } + + gTraceLock = PR_NewLock(); +} + +#endif + +#if defined(_WIN32) && defined(_M_IX86) // WIN32 x86 stack walking code +#include "nsStackFrameWin.h" +void +nsTraceRefcntImpl::WalkTheStack(FILE* aStream) +{ + DumpStackToFile(aStream); +} + +// WIN32 x86 stack walking code +// i386 or PPC Linux stackwalking code or Solaris +#elif (defined(linux) && !defined(VBOX) && defined(__GLIBC__) && (defined(__i386) || defined(PPC))) || (defined(__sun) && (defined(__sparc) || defined(sparc) || defined(__i386) || defined(i386))) +#include "nsStackFrameUnix.h" +void +nsTraceRefcntImpl::WalkTheStack(FILE* aStream) +{ + DumpStackToFile(aStream); +} + +#elif defined(XP_MAC) + +/** + * Stack walking code for the Mac OS. + */ + +#include "gc_fragments.h" + +#include + +extern "C" { +void MWUnmangle(const char *mangled_name, char *unmangled_name, size_t buffersize); +} + +struct traceback_table { + long zero; + long magic; + long reserved; + long codeSize; + short nameLength; + char name[2]; +}; + +static char* pc2name(long* pc, char name[], long size) +{ + name[0] = '\0'; + + // make sure pc is instruction aligned (at least). + if (UInt32(pc) == (UInt32(pc) & 0xFFFFFFFC)) { + long instructionsToLook = 4096; + long* instruction = (long*)pc; + + // look for the traceback table. + while (instructionsToLook--) { + if (instruction[0] == 0x4E800020 && instruction[1] == 0x00000000) { + traceback_table* tb = (traceback_table*)&instruction[1]; + memcpy(name, tb->name + 1, --nameLength); + name[nameLength] = '\0'; + break; + } + ++instruction; + } + } + + return name; +} + +struct stack_frame { + stack_frame* next; // savedSP + void* savedCR; + void* savedLR; + void* reserved0; + void* reserved1; + void* savedTOC; +}; + +static asm stack_frame* getStackFrame() +{ + mr r3, sp + blr +} + +NS_COM void +nsTraceRefcntImpl::WalkTheStack(FILE* aStream) +{ + stack_frame* currentFrame = getStackFrame(); // WalkTheStack's frame. + currentFrame = currentFrame->next; // WalkTheStack's caller's frame. + currentFrame = currentFrame->next; // WalkTheStack's caller's caller's frame. + + while (true) { + // LR saved at 8(SP) in each frame. subtract 4 to get address of calling instruction. + void* pc = currentFrame->savedLR; + + // convert PC to name, unmangle it, and generate source location, if possible. + static char symbol_name[1024], unmangled_name[1024], file_name[256]; UInt32 file_offset; + + if (GC_address_to_source((char*)pc, symbol_name, file_name, &file_offset)) { + MWUnmangle(symbol_name, unmangled_name, sizeof(unmangled_name)); + fprintf(aStream, "%s[%s,%ld]\n", unmangled_name, file_name, file_offset); + } else { + pc2name((long*)pc, symbol_name, sizeof(symbol_name)); + MWUnmangle(symbol_name, unmangled_name, sizeof(unmangled_name)); + fprintf(aStream, "%s(0x%08X)\n", unmangled_name, pc); + } + + currentFrame = currentFrame->next; + // the bottom-most frame is marked as pointing to NULL, or is ODD if a 68K transition frame. + if (currentFrame == NULL || UInt32(currentFrame) & 0x1) + break; + } +} + +#else // unsupported platform. + +void +nsTraceRefcntImpl::WalkTheStack(FILE* aStream) +{ + fprintf(aStream, "write me, dammit!\n"); +} + +#endif + +//---------------------------------------------------------------------- + +// This thing is exported by libstdc++ +// Yes, this is a gcc only hack +#if defined(MOZ_DEMANGLE_SYMBOLS) +#include +#include // for free() +#endif // MOZ_DEMANGLE_SYMBOLS + +NS_COM void +nsTraceRefcntImpl::DemangleSymbol(const char * aSymbol, + char * aBuffer, + int aBufLen) +{ + NS_ASSERTION(nsnull != aSymbol,"null symbol"); + NS_ASSERTION(nsnull != aBuffer,"null buffer"); + NS_ASSERTION(aBufLen >= 32 ,"pulled 32 out of you know where"); + + aBuffer[0] = '\0'; + +#if defined(MOZ_DEMANGLE_SYMBOLS) + /* See demangle.h in the gcc source for the voodoo */ + char * demangled = abi::__cxa_demangle(aSymbol,0,0,0); + + if (demangled) + { + strncpy(aBuffer,demangled,aBufLen); + free(demangled); + } +#endif // MOZ_DEMANGLE_SYMBOLS +} + + +//---------------------------------------------------------------------- + +NS_COM void +nsTraceRefcntImpl::LoadLibrarySymbols(const char* aLibraryName, + void* aLibrayHandle) +{ +#ifdef NS_BUILD_REFCNT_LOGGING +#if defined(_WIN32) && defined(_M_IX86) /* Win32 x86 only */ + if (!gInitialized) + InitTraceLog(); + + if (gAllocLog || gRefcntsLog) { + fprintf(stdout, "### Loading symbols for %s\n", aLibraryName); + fflush(stdout); + + HANDLE myProcess = ::GetCurrentProcess(); + BOOL ok = EnsureSymInitialized(); + if (ok) { + const char* baseName = aLibraryName; + // just get the base name of the library if a full path was given: + PRInt32 len = strlen(aLibraryName); + for (PRInt32 i = len - 1; i >= 0; i--) { + if (aLibraryName[i] == '\\') { + baseName = &aLibraryName[i + 1]; + break; + } + } + DWORD baseAddr = _SymLoadModule(myProcess, + NULL, + (char*)baseName, + (char*)baseName, + 0, + 0); + ok = (baseAddr != nsnull); + } + if (!ok) { + LPVOID lpMsgBuf; + FormatMessage( + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + GetLastError(), + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language + (LPTSTR) &lpMsgBuf, + 0, + NULL + ); + fprintf(stdout, "### ERROR: LoadLibrarySymbols for %s: %s\n", + aLibraryName, lpMsgBuf); + fflush(stdout); + LocalFree( lpMsgBuf ); + } + } +#endif +#endif +} + +//---------------------------------------------------------------------- + + + + + + +// don't use the logging ones. :-) +NS_IMETHODIMP_(nsrefcnt) nsTraceRefcntImpl::AddRef(void) +{ + NS_PRECONDITION(PRInt32(mRefCnt) >= 0, "illegal refcnt"); + ++mRefCnt; + return mRefCnt; +} + +NS_IMETHODIMP_(nsrefcnt) nsTraceRefcntImpl::Release(void) +{ + NS_PRECONDITION(0 != mRefCnt, "dup release"); + --mRefCnt; + if (mRefCnt == 0) { + mRefCnt = 1; /* stabilize */ + delete this; + return 0; + } + return mRefCnt; +} + +NS_IMPL_QUERY_INTERFACE1(nsTraceRefcntImpl, nsITraceRefcnt) + +nsTraceRefcntImpl::nsTraceRefcntImpl() +{ + /* member initializers and constructor code */ +} + +NS_IMETHODIMP +nsTraceRefcntImpl::LogAddRef(void* aPtr, + nsrefcnt aRefcnt, + const char* aClazz, + PRUint32 classSize) +{ +#ifdef NS_BUILD_REFCNT_LOGGING + ASSERT_ACTIVITY_IS_LEGAL; + if (!gInitialized) + InitTraceLog(); + if (gLogging) { + LOCK_TRACELOG(); + + if (gBloatLog) { + BloatEntry* entry = GetBloatEntry(aClazz, classSize); + if (entry) { + entry->AddRef(aRefcnt); + } + } + + // Here's the case where neither NS_NEWXPCOM nor MOZ_COUNT_CTOR were used, + // yet we still want to see creation information: + + PRBool loggingThisType = (!gTypesToLog || LogThisType(aClazz)); + PRInt32 serialno = 0; + if (gSerialNumbers && loggingThisType) { + serialno = GetSerialNumber(aPtr, aRefcnt == 1); + PRInt32* count = GetRefCount(aPtr); + if(count) + (*count)++; + + } + + PRBool loggingThisObject = (!gObjectsToLog || LogThisObj(serialno)); + if (aRefcnt == 1 && gAllocLog && loggingThisType && loggingThisObject) { + fprintf(gAllocLog, "\n<%s> 0x%08X %d Create\n", + aClazz, NS_PTR_TO_INT32(aPtr), serialno); + WalkTheStack(gAllocLog); + } + + if (gRefcntsLog && loggingThisType && loggingThisObject) { + if (gLogToLeaky) { + (*leakyLogAddRef)(aPtr, aRefcnt - 1, aRefcnt); + } + else { + // Can't use PR_LOG(), b/c it truncates the line + fprintf(gRefcntsLog, + "\n<%s> 0x%08X %d AddRef %d\n", aClazz, NS_PTR_TO_INT32(aPtr), serialno, aRefcnt); + WalkTheStack(gRefcntsLog); + fflush(gRefcntsLog); + } + } + UNLOCK_TRACELOG(); + } +#endif + return NS_OK; +} + +NS_IMETHODIMP +nsTraceRefcntImpl::LogRelease(void* aPtr, + nsrefcnt aRefcnt, + const char* aClazz) +{ +#ifdef NS_BUILD_REFCNT_LOGGING + ASSERT_ACTIVITY_IS_LEGAL; + if (!gInitialized) + InitTraceLog(); + if (gLogging) { + LOCK_TRACELOG(); + + if (gBloatLog) { + BloatEntry* entry = GetBloatEntry(aClazz, 0); + if (entry) { + entry->Release(aRefcnt); + } + } + + PRBool loggingThisType = (!gTypesToLog || LogThisType(aClazz)); + PRInt32 serialno = 0; + if (gSerialNumbers && loggingThisType) { + serialno = GetSerialNumber(aPtr, PR_FALSE); + PRInt32* count = GetRefCount(aPtr); + if(count) + (*count)--; + + } + + PRBool loggingThisObject = (!gObjectsToLog || LogThisObj(serialno)); + if (gRefcntsLog && loggingThisType && loggingThisObject) { + if (gLogToLeaky) { + (*leakyLogRelease)(aPtr, aRefcnt + 1, aRefcnt); + } + else { + // Can't use PR_LOG(), b/c it truncates the line + fprintf(gRefcntsLog, + "\n<%s> 0x%08X %d Release %d\n", aClazz, NS_PTR_TO_INT32(aPtr), serialno, aRefcnt); + WalkTheStack(gRefcntsLog); + fflush(gRefcntsLog); + } + } + + // Here's the case where neither NS_DELETEXPCOM nor MOZ_COUNT_DTOR were used, + // yet we still want to see deletion information: + + if (aRefcnt == 0 && gAllocLog && loggingThisType && loggingThisObject) { + fprintf(gAllocLog, + "\n<%s> 0x%08X %d Destroy\n", + aClazz, NS_PTR_TO_INT32(aPtr), serialno); + WalkTheStack(gAllocLog); + } + + if (aRefcnt == 0 && gSerialNumbers && loggingThisType) { + RecycleSerialNumberPtr(aPtr); + } + + UNLOCK_TRACELOG(); + } +#endif + return NS_OK; +} + +NS_IMETHODIMP +nsTraceRefcntImpl::LogCtor(void* aPtr, + const char* aType, + PRUint32 aInstanceSize) +{ +#ifdef NS_BUILD_REFCNT_LOGGING + ASSERT_ACTIVITY_IS_LEGAL; + if (!gInitialized) + InitTraceLog(); + + if (gLogging) { + LOCK_TRACELOG(); + + if (gBloatLog) { + BloatEntry* entry = GetBloatEntry(aType, aInstanceSize); + if (entry) { + entry->Ctor(); + } + } + + PRBool loggingThisType = (!gTypesToLog || LogThisType(aType)); + PRInt32 serialno = 0; + if (gSerialNumbers && loggingThisType) { + serialno = GetSerialNumber(aPtr, PR_TRUE); + } + + PRBool loggingThisObject = (!gObjectsToLog || LogThisObj(serialno)); + if (gAllocLog && loggingThisType && loggingThisObject) { + fprintf(gAllocLog, "\n<%s> 0x%08X %d Ctor (%d)\n", + aType, NS_PTR_TO_INT32(aPtr), serialno, aInstanceSize); + WalkTheStack(gAllocLog); + } + + UNLOCK_TRACELOG(); + } +#endif + return NS_OK; +} + + +NS_IMETHODIMP +nsTraceRefcntImpl::LogDtor(void* aPtr, + const char* aType, + PRUint32 aInstanceSize) +{ +#ifdef NS_BUILD_REFCNT_LOGGING + ASSERT_ACTIVITY_IS_LEGAL; + if (!gInitialized) + InitTraceLog(); + + if (gLogging) { + LOCK_TRACELOG(); + + if (gBloatLog) { + BloatEntry* entry = GetBloatEntry(aType, aInstanceSize); + if (entry) { + entry->Dtor(); + } + } + + PRBool loggingThisType = (!gTypesToLog || LogThisType(aType)); + PRInt32 serialno = 0; + if (gSerialNumbers && loggingThisType) { + serialno = GetSerialNumber(aPtr, PR_FALSE); + RecycleSerialNumberPtr(aPtr); + } + + PRBool loggingThisObject = (!gObjectsToLog || LogThisObj(serialno)); + + // (If we're on a losing architecture, don't do this because we'll be + // using LogDeleteXPCOM instead to get file and line numbers.) + if (gAllocLog && loggingThisType && loggingThisObject) { + fprintf(gAllocLog, "\n<%s> 0x%08X %d Dtor (%d)\n", + aType, NS_PTR_TO_INT32(aPtr), serialno, aInstanceSize); + WalkTheStack(gAllocLog); + } + + UNLOCK_TRACELOG(); + } +#endif + return NS_OK; +} + + +NS_IMETHODIMP +nsTraceRefcntImpl::LogAddCOMPtr(void* aCOMPtr, + nsISupports* aObject) +{ +#if defined(NS_BUILD_REFCNT_LOGGING) && defined(HAVE_CPP_DYNAMIC_CAST_TO_VOID_PTR) + // Get the most-derived object. + void *object = dynamic_cast(aObject); + + // This is a very indirect way of finding out what the class is + // of the object being logged. If we're logging a specific type, + // then + if (!gTypesToLog || !gSerialNumbers) { + return NS_OK; + } + PRInt32 serialno = GetSerialNumber(object, PR_FALSE); + if (serialno == 0) { + return NS_OK; + } + + if (!gInitialized) + InitTraceLog(); + if (gLogging) { + LOCK_TRACELOG(); + + PRInt32* count = GetCOMPtrCount(object); + if(count) + (*count)++; + + PRBool loggingThisObject = (!gObjectsToLog || LogThisObj(serialno)); + + if (gCOMPtrLog && loggingThisObject) { + fprintf(gCOMPtrLog, "\n 0x%08X %d nsCOMPtrAddRef %d 0x%08X\n", + NS_PTR_TO_INT32(object), serialno, count?(*count):-1, NS_PTR_TO_INT32(aCOMPtr)); + WalkTheStack(gCOMPtrLog); + } + + UNLOCK_TRACELOG(); + } +#endif + return NS_OK; +} + + +NS_IMETHODIMP +nsTraceRefcntImpl::LogReleaseCOMPtr(void* aCOMPtr, + nsISupports* aObject) +{ +#if defined(NS_BUILD_REFCNT_LOGGING) && defined(HAVE_CPP_DYNAMIC_CAST_TO_VOID_PTR) + // Get the most-derived object. + void *object = dynamic_cast(aObject); + + // This is a very indirect way of finding out what the class is + // of the object being logged. If we're logging a specific type, + // then + if (!gTypesToLog || !gSerialNumbers) { + return NS_OK; + } + PRInt32 serialno = GetSerialNumber(object, PR_FALSE); + if (serialno == 0) { + return NS_OK; + } + + if (!gInitialized) + InitTraceLog(); + if (gLogging) { + LOCK_TRACELOG(); + + PRInt32* count = GetCOMPtrCount(object); + if(count) + (*count)--; + + PRBool loggingThisObject = (!gObjectsToLog || LogThisObj(serialno)); + + if (gCOMPtrLog && loggingThisObject) { + fprintf(gCOMPtrLog, "\n 0x%08X %d nsCOMPtrRelease %d 0x%08X\n", + NS_PTR_TO_INT32(object), serialno, count?(*count):-1, NS_PTR_TO_INT32(aCOMPtr)); + WalkTheStack(gCOMPtrLog); + } + + UNLOCK_TRACELOG(); + } +#endif + return NS_OK; +} + +NS_COM void +nsTraceRefcntImpl::Startup() +{ +#ifdef NS_BUILD_REFCNT_LOGGING + SetActivityIsLegal(PR_TRUE); +#endif +} + +NS_COM void +nsTraceRefcntImpl::Shutdown() +{ +#ifdef NS_BUILD_REFCNT_LOGGING + + if (gBloatView) { + PL_HashTableDestroy(gBloatView); + gBloatView = nsnull; + } + if (gTypesToLog) { + PL_HashTableDestroy(gTypesToLog); + gTypesToLog = nsnull; + } + if (gObjectsToLog) { + PL_HashTableDestroy(gObjectsToLog); + gObjectsToLog = nsnull; + } + if (gSerialNumbers) { + PL_HashTableDestroy(gSerialNumbers); + gSerialNumbers = nsnull; + } + + SetActivityIsLegal(PR_FALSE); + +#endif +} + +NS_COM void +nsTraceRefcntImpl::SetActivityIsLegal(PRBool aLegal) +{ +#ifdef NS_BUILD_REFCNT_LOGGING + gActivityIsLegal = aLegal; +#endif +} + + +NS_METHOD +nsTraceRefcntImpl::Create(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr) +{ + *aInstancePtr = nsnull; + nsITraceRefcnt* tracer = new nsTraceRefcntImpl(); + if (!tracer) + return NS_ERROR_OUT_OF_MEMORY; + + nsresult rv = tracer->QueryInterface(aIID, aInstancePtr); + if (NS_FAILED(rv)) { + delete tracer; + } + + return rv; +} diff --git a/src/libs/xpcom18a4/xpcom/base/nsTraceRefcntImpl.h b/src/libs/xpcom18a4/xpcom/base/nsTraceRefcntImpl.h new file mode 100644 index 00000000..528b285d --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/base/nsTraceRefcntImpl.h @@ -0,0 +1,109 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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 Communicator client code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * L. David Baron + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ +#ifndef nsTraceRefcntImpl_h___ +#define nsTraceRefcntImpl_h___ + +#include // for FILE +#include "nsITraceRefcnt.h" + +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +#define NS_MeanAndStdDev VBoxNsxpNS_MeanAndStdDev +#endif /* VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + +class nsTraceRefcntImpl : public nsITraceRefcnt +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSITRACEREFCNT + + nsTraceRefcntImpl(); + + static NS_COM void Startup(); + static NS_COM void Shutdown(); + + enum StatisticsType { + ALL_STATS, + NEW_STATS + }; + + static NS_COM nsresult DumpStatistics(StatisticsType type = ALL_STATS, + FILE* out = 0); + + static NS_COM void ResetStatistics(void); + + static NS_COM void LoadLibrarySymbols(const char* aLibraryName, + void* aLibrayHandle); + + + static NS_COM void DemangleSymbol(const char * aSymbol, + char * aBuffer, + int aBufLen); + + static NS_COM void WalkTheStack(FILE* aStream); + /** + * Tell nsTraceRefcnt whether refcounting, allocation, and destruction + * activity is legal. This is used to trigger assertions for any such + * activity that occurs because of static constructors or destructors. + */ + static NS_COM void SetActivityIsLegal(PRBool aLegal); + + static NS_METHOD Create(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr); + +private: + ~nsTraceRefcntImpl() {} +}; + +#define NS_TRACE_REFCNT_CONTRACTID "@mozilla.org/xpcom/trace-refcnt;1" +#define NS_TRACE_REFCNT_CLASSNAME "nsTraceRefcnt Interface" +#define NS_TRACE_REFCNT_CID \ +{ /* e3e7511e-a395-4924-94b1-d527861cded4 */ \ + 0xe3e7511e, \ + 0xa395, \ + 0x4924, \ + {0x94, 0xb1, 0xd5, 0x27, 0x86, 0x1c, 0xde, 0xd4} \ +} \ + +//////////////////////////////////////////////////////////////////////////////// +// And now for that utility that you've all been asking for... + +extern "C" NS_COM void +NS_MeanAndStdDev(double n, double sumOfValues, double sumOfSquaredValues, + double *meanResult, double *stdDevResult); + +//////////////////////////////////////////////////////////////////////////////// +#endif diff --git a/src/libs/xpcom18a4/xpcom/base/nsWeakPtr.h b/src/libs/xpcom18a4/xpcom/base/nsWeakPtr.h new file mode 100644 index 00000000..c15e31f0 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/base/nsWeakPtr.h @@ -0,0 +1,48 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * ***** 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 the Mozilla browser. + * + * The Initial Developer of the Original Code is + * Netscape Communications, Inc. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Scott Collins + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +#ifndef nsWeakPtr_h__ +#define nsWeakPtr_h__ + +#include "nsIWeakReference.h" +#include "nsCOMPtr.h" + +// typedef nsCOMPtr nsWeakPtr; + +#endif diff --git a/src/libs/xpcom18a4/xpcom/base/nscore.h b/src/libs/xpcom18a4/xpcom/base/nscore.h new file mode 100644 index 00000000..b7bfa11f --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/base/nscore.h @@ -0,0 +1,468 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ +#ifndef nscore_h___ +#define nscore_h___ + +/** + * Make sure that we have the proper platform specific + * c++ definitions needed by nscore.h + */ +#ifndef _XPCOM_CONFIG_H_ +#include "xpcom-config.h" +#endif + +/** + * Incorporate the core NSPR data types which XPCOM uses. + */ +#include "prtypes.h" + +/* Core XPCOM declarations. */ + +/** + * Macros defining the target platform... + */ +#ifdef _WIN32 +#define NS_WIN32 1 + +#elif defined(__unix) +#define NS_UNIX 1 + +#elif defined(XP_OS2) +#define NS_OS2 1 +#endif +/*----------------------------------------------------------------------*/ +/* Import/export defines */ + +/** + * Using the visibility("hidden") attribute allows the compiler to use + * PC-relative addressing to call this function. If a function does not + * access any global data, and does not call any methods which are not either + * file-local or hidden, then on ELF systems we avoid loading the address of + * the PLT into a register at the start of the function, which reduces code + * size and frees up a register for general use. + * + * As a general rule, this should be used for any non-exported symbol + * (including virtual method implementations). NS_IMETHOD uses this by + * default; if you need to have your NS_IMETHOD functions exported, you can + * wrap your class as follows: + * + * #undef IMETHOD_VISIBILITY + * #define IMETHOD_VISIBILITY NS_VISIBILITY_DEFAULT + * + * class Foo { + * ... + * }; + * + * #undef IMETHOD_VISIBILITY + * #define IMETHOD_VISIBILITY NS_VISIBILITY_HIDDEN + * + * Don't forget to change the visibility back to hidden before the end + * of a header! + * + * Other examples: + * + * NS_HIDDEN_(int) someMethod(); + * SomeCtor() NS_HIDDEN; + */ + +#ifdef HAVE_VISIBILITY_ATTRIBUTE +#define NS_VISIBILITY_HIDDEN __attribute__ ((visibility ("hidden"))) +# ifdef VBOX_HAVE_VISIBILITY_HIDDEN +# define NS_VISIBILITY_DEFAULT __attribute__ ((visibility ("default"))) +# else +# define NS_VISIBILITY_DEFAULT +# endif + +#define NS_HIDDEN_(type) NS_VISIBILITY_HIDDEN type +#else +#define NS_VISIBILITY_HIDDEN +#define NS_VISIBILITY_DEFAULT + +#define NS_HIDDEN_(type) type +#endif + +#define NS_HIDDEN NS_VISIBILITY_HIDDEN + +#undef IMETHOD_VISIBILITY +#define IMETHOD_VISIBILITY NS_VISIBILITY_HIDDEN + +/** + * Mark a function as using a potentially non-standard function calling + * convention. This can be used on functions that are called very + * frequently, to reduce the overhead of the function call. It is still worth + * using the macro for C++ functions which take no parameters since it allows + * passing |this| in a register. + * + * - Do not use this on any scriptable interface method since xptcall won't be + * aware of the different calling convention. + * - This must appear on the declaration, not the definition. + * - Adding this to a public function _will_ break binary compatibility. + * - This may be used on virtual functions but you must ensure it is applied + * to all implementations - the compiler will _not_ warn but it will crash. + * - This has no effect for inline functions or functions which take a + * variable number of arguments. + * + * Examples: int NS_FASTCALL func1(char *foo); + * NS_HIDDEN_(int) NS_FASTCALL func2(char *foo); + */ + +#if defined(__i386__) && defined(__GNUC__) && (__GNUC__ >= 3) && !defined(XP_OS2) +#define NS_FASTCALL __attribute__ ((regparm (3), stdcall)) +#else +#define NS_FASTCALL +#endif + +/* XXX: nike, maybe fix */ +#define NS_EXPORT_STATIC_MEMBER_(type) type +#define NS_IMPORT_STATIC_MEMBER_(type) type + +#ifdef NS_WIN32 + +#define NS_IMPORT __declspec(dllimport) +#define NS_IMPORT_(type) type __declspec(dllimport) __stdcall +#define NS_EXPORT __declspec(dllexport) +#define NS_EXPORT_(type) type __declspec(dllexport) __stdcall +#define NS_IMETHOD_(type) virtual type __stdcall +#define NS_IMETHODIMP_(type) type __stdcall +#define NS_METHOD_(type) type __stdcall +#define NS_CALLBACK_(_type, _name) _type (__stdcall * _name) +#define NS_STDCALL __stdcall + +#elif defined(XP_MAC) + +#define NS_IMPORT +#define NS_IMPORT_(type) type +#define NS_EXPORT __declspec(export) +#define NS_EXPORT_(type) __declspec(export) type +#define NS_IMETHOD_(type) virtual type +#define NS_IMETHODIMP_(type) type +#define NS_METHOD_(type) type +#define NS_CALLBACK_(_type, _name) _type (* _name) +#define NS_STDCALL + +#elif defined(XP_OS2) && defined(__declspec) + +#define NS_IMPORT __declspec(dllimport) +#define NS_IMPORT_(type) type __declspec(dllimport) __stdcall +#define NS_EXPORT __declspec(dllexport) +#define NS_EXPORT_(type) type __declspec(dllexport) __stdcall +#define NS_IMETHOD_(type) virtual IMETHOD_VISIBILITY type +#define NS_IMETHODIMP_(type) type +#define NS_METHOD_(type) type +#define NS_CALLBACK_(_type, _name) _type (* _name) +#define NS_STDCALL + +#else + +# ifdef VBOX_HAVE_VISIBILITY_HIDDEN +# define NS_IMPORT +# define NS_IMPORT_(type) type +# define NS_EXPORT __attribute__((visibility("default"))) +# define NS_EXPORT_(type) __attribute__((visibility("default"))) type +# define NS_IMETHOD_(type) virtual IMETHOD_VISIBILITY type +# define NS_IMETHODIMP_(type) type +# define NS_METHOD_(type) type +# define NS_CALLBACK_(_type, _name) _type (* _name) +# define NS_STDCALL +# else +# define NS_IMPORT +# define NS_IMPORT_(type) type +# define NS_EXPORT +# define NS_EXPORT_(type) type +# define NS_IMETHOD_(type) virtual IMETHOD_VISIBILITY type +# define NS_IMETHODIMP_(type) type +# define NS_METHOD_(type) type +# define NS_CALLBACK_(_type, _name) _type (* _name) +# define NS_STDCALL +# endif +#endif + +/** + * Macro for creating typedefs for pointer-to-member types which are + * declared with stdcall. It is important to use this for any type which is + * declared as stdcall (i.e. NS_IMETHOD). For example, instead of writing: + * + * typedef nsresult (nsIFoo::*someType)(nsISupports* arg); + * + * you should write: + * + * typedef + * NS_STDCALL_FUNCPROTO(nsresult, someType, nsIFoo, typeFunc, (nsISupports*)); + * + * where nsIFoo::typeFunc is any method declared as + * NS_IMETHOD typeFunc(nsISupports*); + * + * XXX this can be simplified to always use the non-typeof implementation + * when http://gcc.gnu.org/bugzilla/show_bug.cgi?id=11893 is fixed. + */ + +#ifdef __GNUC__ +#define NS_STDCALL_FUNCPROTO(ret, name, class, func, args) \ + typeof(&class::func) name +#else +#define NS_STDCALL_FUNCPROTO(ret, name, class, func, args) \ + ret (NS_STDCALL class::*name) args +#endif + +/** + * Generic API modifiers which return the standard XPCOM nsresult type + */ +#define NS_IMETHOD NS_IMETHOD_(nsresult) +#define NS_IMETHODIMP NS_IMETHODIMP_(nsresult) +#define NS_METHOD NS_METHOD_(nsresult) +#define NS_CALLBACK(_name) NS_CALLBACK_(nsresult, _name) + +/** + * Import/Export macros for XPCOM APIs + */ + +#ifdef _IMPL_NS_COM +#define NS_COM NS_EXPORT +#elif _IMPL_NS_COM_OFF +#define NS_COM +#elif XPCOM_GLUE +#define NS_COM +#else +#define NS_COM NS_IMPORT +#endif + + +/** + * NS_NO_VTABLE is emitted by xpidl in interface declarations whenever + * xpidl can determine that the interface can't contain a constructor. + * This results in some space savings and possible runtime savings - + * see bug 49416. We undefine it first, as xpidl-generated headers + * define it for IDL uses that don't include this file. + */ +#ifdef NS_NO_VTABLE +#undef NS_NO_VTABLE +#endif +#if defined(_MSC_VER) && _MSC_VER >= 1100 +#define NS_NO_VTABLE __declspec(novtable) +#else +#define NS_NO_VTABLE +#endif + + +/** + * Generic XPCOM result data type + */ +typedef PRUint32 nsresult; + +/** + * The preferred symbol for null. + */ +#define nsnull 0 + +#include "nsError.h" + +/* ------------------------------------------------------------------------ */ +/* Casting macros for hiding C++ features from older compilers */ + + /* + All our compiler support template specialization, but not all support the + |template <>| notation. The compiler that don't understand this notation + just omit it for specialization. + + Need to add an autoconf test for this. + */ + + /* under Metrowerks (Mac), we don't have autoconf yet */ +#ifdef __MWERKS__ + #define HAVE_CPP_PARTIAL_SPECIALIZATION + #define HAVE_CPP_MODERN_SPECIALIZE_TEMPLATE_SYNTAX + + #define HAVE_CPP_ACCESS_CHANGING_USING + #define HAVE_CPP_AMBIGUITY_RESOLVING_USING + #define HAVE_CPP_EXPLICIT + #define HAVE_CPP_TYPENAME + #define HAVE_CPP_BOOL + #define HAVE_CPP_NAMESPACE_STD + #define HAVE_CPP_UNAMBIGUOUS_STD_NOTEQUAL + #define HAVE_CPP_2BYTE_WCHAR_T +#endif + + /* under VC++ (Windows), we don't have autoconf yet */ +#if defined(_MSC_VER) && (_MSC_VER>=1100) + /* VC++ 5.0 and greater implement template specialization, 4.2 is unknown */ + #define HAVE_CPP_MODERN_SPECIALIZE_TEMPLATE_SYNTAX + + #define HAVE_CPP_EXPLICIT + #define HAVE_CPP_TYPENAME + #define HAVE_CPP_ACCESS_CHANGING_USING + + #if (_MSC_VER==1100) + /* VC++5.0 has an internal compiler error (sometimes) without this */ + #undef HAVE_CPP_ACCESS_CHANGING_USING + #endif + + #define HAVE_CPP_NAMESPACE_STD + #define HAVE_CPP_UNAMBIGUOUS_STD_NOTEQUAL + #define HAVE_CPP_2BYTE_WCHAR_T +#endif + +#ifndef __PRUNICHAR__ +#define __PRUNICHAR__ + /* For now, don't use wchar_t on Unix because it breaks the Netscape + * commercial build. When this is fixed there will be no need for the + * |NS_REINTERPRET_CAST| in nsLiteralString.h either. + */ + #if defined(HAVE_CPP_2BYTE_WCHAR_T) && (defined(NS_WIN32) || defined(XP_MAC)) + typedef wchar_t PRUnichar; + #else + typedef PRUint16 PRUnichar; + #endif +#endif + + /* + If the compiler doesn't support |explicit|, we'll just make it go away, trusting + that the builds under compilers that do have it will keep us on the straight and narrow. + */ +#ifndef HAVE_CPP_EXPLICIT + #define explicit +#endif + +#ifndef HAVE_CPP_TYPENAME + #define typename +#endif + +#ifdef HAVE_CPP_MODERN_SPECIALIZE_TEMPLATE_SYNTAX + #define NS_SPECIALIZE_TEMPLATE template <> +#else + #define NS_SPECIALIZE_TEMPLATE +#endif + +/* unix and beos now determine this automatically */ +#if ! defined XP_UNIX && ! defined XP_BEOS && !defined(XP_OS2) +#ifndef HAVE_CPP_NEW_CASTS +#define HAVE_CPP_NEW_CASTS 1 /* we'll be optimistic. */ +#endif +#endif + +#if defined(HAVE_CPP_NEW_CASTS) +#define NS_STATIC_CAST(__type, __ptr) static_cast< __type >(__ptr) +#define NS_CONST_CAST(__type, __ptr) const_cast< __type >(__ptr) + +#define NS_REINTERPRET_POINTER_CAST(__type, __ptr) reinterpret_cast< __type >(__ptr) +#define NS_REINTERPRET_NONPOINTER_CAST(__type, __obj) reinterpret_cast< __type >(__obj) +#define NS_REINTERPRET_CAST(__type, __expr) reinterpret_cast< __type >(__expr) + +#else +#define NS_STATIC_CAST(__type, __ptr) ((__type)(__ptr)) +#define NS_CONST_CAST(__type, __ptr) ((__type)(__ptr)) + +#define NS_REINTERPRET_POINTER_CAST(__type, __ptr) ((__type)((void*)(__ptr))) +#define NS_REINTERPRET_NONPOINTER_CAST(__type, __obj) ((__type)(__obj)) + + /* Note: the following is only appropriate for pointers. */ +#define NS_REINTERPRET_CAST(__type, __expr) NS_REINTERPRET_POINTER_CAST(__type, __expr) + /* + Why cast to a |void*| first? Well, when old-style casting from + a pointer to a base to a pointer to a derived class, the cast will be + ambiguous if the source pointer type appears multiple times in the + destination, e.g., + + class Base {}; + class Derived : public Base, public Base {}; + + void foo( Base* b ) + { + ((Derived*)b)->some_derived_member ... // Error: Ambiguous, expand from which |Base|? + } + + an old-style cast (like |static_cast|) will change the pointer, but + here, doesn't know how. The cast to |void*| prevents it from thinking + it needs to expand the original pointer. + + The cost is, |NS_REINTERPRET_CAST| is no longer appropriate for non-pointer + conversions. Also, mis-applying |NS_REINTERPRET_CAST| to cast |this| to something + will still expand the pointer to the outer object in standards complying compilers. + */ + + /* + No sense in making an NS_DYNAMIC_CAST() macro: you can't duplicate + the semantics. So if you want to dynamic_cast, then just use it + "straight", no macro. + */ +#endif + +#if __cplusplus+0 > 201100L +#define NS_DEFAULT = default +#define NS_DELETE = delete +#else +#define NS_DEFAULT +#define NS_DELETE +#endif + + +#ifndef VBOX +/* + * Use these macros to do 64bit safe pointer conversions. + */ + +#define NS_PTR_TO_INT32(x) ((char *)(x) - (char *)0) +#define NS_INT32_TO_PTR(x) ((void *)((char *)0 + (x))) +#else /* VBOX */ +// This stuff is (contrary to the comment) totally 64bit unsafe, so strip +// it down to only do one direction, which is used by the hashing code. +#define NS_PTR_TO_INT32(x) ((PRInt32)((char *)(x) - (char *)0)) +#endif /* VBOX */ + +/* + * These macros allow you to give a hint to the compiler about branch + * probability so that it can better optimize. Use them like this: + * + * if (NS_LIKELY(v == 1)) { + * ... expected code path ... + * } + * + * if (NS_UNLIKELY(v == 0)) { + * ... non-expected code path ... + * } + * + */ + +#if defined(__GNUC__) && (__GNUC__ > 2) && !defined(FORTIFY_RUNNING) +#define NS_LIKELY(x) (__builtin_expect(!!(x), 1)) +#define NS_UNLIKELY(x) (__builtin_expect(!!(x), 0)) +#else +#define NS_LIKELY(x) (x) +#define NS_UNLIKELY(x) (x) +#endif + +#endif /* nscore_h___ */ + diff --git a/src/libs/xpcom18a4/xpcom/base/nsrootidl.idl b/src/libs/xpcom18a4/xpcom/base/nsrootidl.idl new file mode 100644 index 00000000..0538e4bc --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/base/nsrootidl.idl @@ -0,0 +1,128 @@ +/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Dan Rosen + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/** + * Root idl declarations to be used by all. + * @status FROZEN + */ + +%{C++ + +#include "nscore.h" +#include "prtime.h" + +/* + * Forward declarations for new string types + */ +class nsAString; +class nsACString; + +/* + * Start commenting out the C++ versions of the below in the output header + */ +#if 0 +%} + +typedef boolean PRBool ; +typedef octet PRUint8 ; +typedef unsigned short PRUint16 ; +typedef unsigned short PRUnichar; +typedef unsigned long PRUint32 ; +typedef unsigned long long PRUint64 ; +typedef unsigned long long PRTime ; +typedef short PRInt16 ; +typedef long PRInt32 ; +typedef long long PRInt64 ; + +typedef unsigned long nsrefcnt ; +typedef unsigned long nsresult ; + +// XXX need this built into xpidl compiler so that it's really size_t or PRSize +// and it's scriptable: +typedef unsigned long size_t; + +[ptr] native voidPtr(void); +[ptr] native charPtr(char); +[ptr] native unicharPtr(PRUnichar); + +[ref, nsid] native nsIDRef(nsID); +[ref, nsid] native nsIIDRef(nsIID); +[ref, nsid] native nsCIDRef(nsCID); + +[ptr, nsid] native nsIDPtr(nsID); +[ptr, nsid] native nsIIDPtr(nsIID); +[ptr, nsid] native nsCIDPtr(nsCID); + +// NOTE: Be careful in using the following 3 types. The *Ref and *Ptr variants +// are more commonly used (and better supported). Those variants require +// nsMemory alloc'd copies when used as 'out' params while these types do not. +// However, currently these types can not be used for 'in' params. And, methods +// that use them as 'out' params *must* be declared [notxpcom] (with an explicit +// return type of nsresult). This makes such methods implicitly not scriptable. +// Use of these types in methods without a [notxpcom] declaration will cause +// the xpidl compiler to raise an error. +// See: http://bugzilla.mozilla.org/show_bug.cgi?id=93792 + +[nsid] native nsIID(nsIID); +[nsid] native nsID(nsID); +[nsid] native nsCID(nsCID); + +[ptr] native nsQIResult(void); + +[ref, domstring] native DOMString(ignored); +[ref, domstring] native DOMStringRef(ignored); +[ptr, domstring] native DOMStringPtr(ignored); + +[ref, utf8string] native AUTF8String(ignored); +[ref, utf8string] native AUTF8StringRef(ignored); +[ptr, utf8string] native AUTF8StringPtr(ignored); + +[ref, cstring] native ACString(ignored); +[ref, cstring] native ACStringRef(ignored); +[ptr, cstring] native ACStringPtr(ignored); + +[ref, astring] native AString(ignored); +[ref, astring] native AStringRef(ignored); +[ptr, astring] native AStringPtr(ignored); + +%{C++ +/* + * End commenting out the C++ versions of the above in the output header + */ +#endif +%} diff --git a/src/libs/xpcom18a4/xpcom/base/pure.h b/src/libs/xpcom18a4/xpcom/base/pure.h new file mode 100644 index 00000000..ea11b99d --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/base/pure.h @@ -0,0 +1,135 @@ +/* + * Header file of Pure API function declarations. + * + * Explicitly no copyright. + * You may recompile and redistribute these definitions as required. + * + * Version 1.0 + */ + +#if defined(c_plusplus) || defined(__cplusplus) +extern "C" { +#endif + +#define PURE_H_VERSION 1 + +////////////////////////////// +// API's Specific to Purify // +////////////////////////////// + +// TRUE when Purify is running. +int __cdecl PurifyIsRunning(void) ; +// +// Print a string to the viewer. +// +int __cdecl PurePrintf(const char *fmt, ...) ; +int __cdecl PurifyPrintf(const char *fmt, ...) ; +// +// Purify functions for leak and memory-in-use functionalty. +// +int __cdecl PurifyNewInuse(void) ; +int __cdecl PurifyAllInuse(void) ; +int __cdecl PurifyClearInuse(void) ; +int __cdecl PurifyNewLeaks(void) ; +int __cdecl PurifyAllLeaks(void) ; +int __cdecl PurifyClearLeaks(void) ; +// +// Purify functions for handle leakage. +// +int __cdecl PurifyAllHandlesInuse(void) ; +int __cdecl PurifyNewHandlesInuse(void) ; +// +// Functions that tell you about the state of memory. +// +int __cdecl PurifyDescribe(void *addr) ; +int __cdecl PurifyWhatColors(void *addr, int size) ; +// +// Functions to test the state of memory. If the memory is not +// accessable, an error is signaled just as if there were a memory +// reference and the function returns false. +// +int __cdecl PurifyAssertIsReadable(const void *addr, int size) ; +int __cdecl PurifyAssertIsWritable(const void *addr, int size) ; +// +// Functions to test the state of memory. If the memory is not +// accessable, these functions return false. No error is signaled. +// +int __cdecl PurifyIsReadable(const void *addr, int size) ; +int __cdecl PurifyIsWritable(const void *addr, int size) ; +int __cdecl PurifyIsInitialized(const void *addr, int size) ; +// +// Functions to set the state of memory. +// +void __cdecl PurifyMarkAsInitialized(void *addr, int size) ; +void __cdecl PurifyMarkAsUninitialized(void *addr, int size) ; +// +// Functions to do late detection of ABWs, FMWs, IPWs. +// +#define PURIFY_HEAP_CRT 0xfffffffe +#define PURIFY_HEAP_ALL 0xfffffffd +#define PURIFY_HEAP_BLOCKS_LIVE 0x80000000 +#define PURIFY_HEAP_BLOCKS_DEFERRED_FREE 0x40000000 +#define PURIFY_HEAP_BLOCKS_ALL (PURIFY_HEAP_BLOCKS_LIVE|PURIFY_HEAP_BLOCKS_DEFERRED_FREE) +int __cdecl PurifyHeapValidate(unsigned int hHeap, unsigned int dwFlags, const void *addr) ; +int __cdecl PurifySetLateDetectScanCounter(int counter); +int __cdecl PurifySetLateDetectScanInterval(int seconds); + + +//////////////////////////////// +// API's Specific to Quantify // +//////////////////////////////// + +// TRUE when Quantify is running. +int __cdecl QuantifyIsRunning(void) ; + +// +// Functions for controlling collection +// +int __cdecl QuantifyDisableRecordingData(void) ; +int __cdecl QuantifyStartRecordingData(void) ; +int __cdecl QuantifyStopRecordingData(void) ; +int __cdecl QuantifyClearData(void) ; +int __cdecl QuantifyIsRecordingData(void) ; + +// Add a comment to the dataset +int __cdecl QuantifyAddAnnotation(char *) ; + +// Save the current data, creating a "checkpoint" dataset +int __cdecl QuantifySaveData(void) ; + +//////////////////////////////// +// API's Specific to Coverage // +//////////////////////////////// + +// TRUE when Coverage is running. +int __cdecl CoverageIsRunning(void) ; +// +// Functions for controlling collection +// +int __cdecl CoverageDisableRecordingData(void) ; +int __cdecl CoverageStartRecordingData(void) ; +int __cdecl CoverageStopRecordingData(void) ; +int __cdecl CoverageClearData(void) ; +int __cdecl CoverageIsRecordingData(void) ; +// Add a comment to the dataset +int __cdecl CoverageAddAnnotation(char *) ; + +// Save the current data, creating a "checkpoint" dataset +int __cdecl CoverageSaveData(void) ; + + + + +//////////////////////////////// +// API's Specific to Purelock // +//////////////////////////////// + +// TRUE when Purelock is running. +int __cdecl PurelockIsRunning(void) ; + + + + +#if defined(c_plusplus) || defined(__cplusplus) +} +#endif diff --git a/src/libs/xpcom18a4/xpcom/base/pure_api.c b/src/libs/xpcom18a4/xpcom/base/pure_api.c new file mode 100644 index 00000000..716460ed --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/base/pure_api.c @@ -0,0 +1,126 @@ +/* + * Header file of Pure API function declarations. + * + * Explicitly no copyright. + * You may recompile and redistribute these definitions as required. + * + * NOTE1: In some situations when compiling with MFC, you should + * enable the setting 'Not using precompiled headers' in Visual C++ + * to avoid a compiler diagnostic. + * + * NOTE2: This file works through the use of deep magic. Calls to functions + * in this file are replaced with calls into the OCI runtime system + * when an instrumented version of this program is run. + * + * NOTE3: The static vars avoidGy_n (where n is a unique number) are used + * to prevent optimizing the functions away when compiler option + * /Gy is set. This is needed so that NOTE2 works properly. + */ +static int avoidGy_1; +static int avoidGy_2; +static int avoidGy_3; +static int avoidGy_4; +static int avoidGy_5; +static int avoidGy_6; +static int avoidGy_7; +static int avoidGy_8; +static int avoidGy_9; +static int avoidGy_10; +static int avoidGy_11; +static int avoidGy_12; +static int avoidGy_13; +static int avoidGy_14; +static int avoidGy_15; +static int avoidGy_16; +static int avoidGy_17; +static int avoidGy_18; +static int avoidGy_19; +static int avoidGy_20; +static int avoidGy_21; +static int avoidGy_22; +static int avoidGy_23; +static int avoidGy_24; +static int avoidGy_25; +static int avoidGy_26; +static int avoidGy_27; +static int avoidGy_28; +static int avoidGy_29; +static int avoidGy_30; +static int avoidGy_31; +static int avoidGy_32; +static int avoidGy_33; +static int avoidGy_34; +static int avoidGy_35; +static int avoidGy_36; +static int avoidGy_37; +static int avoidGy_38; +static int avoidGy_39; +static int avoidGy_40; +static int avoidGy_41; +static int avoidGy_42; +static int avoidGy_43; +static int avoidGy_44; +static int avoidGy_45; +static int avoidGy_46; +static int avoidGy_47; +static int avoidGy_48; +static int avoidGy_49; +static int avoidGy_50; +static int avoidGy_51; +static int avoidGy_52; +static int avoidGy_53; +static int avoidGy_54; +static int avoidGy_55; +static int avoidGy_56; +static int avoidGy_57; +static int avoidGy_58; +static int avoidGy_59; +static int avoidGy_60; +static int avoidGy_PL_01; +__declspec(dllexport) int __cdecl PurePrintf(const char *fmt, ...) { avoidGy_1++; fmt; return 0; } +__declspec(dllexport) int __cdecl PurifyIsRunning(void) { avoidGy_2++; return 0; } +__declspec(dllexport) int __cdecl PurifyPrintf(const char *fmt, ...) { avoidGy_3++; fmt; return 0; } +__declspec(dllexport) int __cdecl PurifyNewInuse(void) { avoidGy_4++; return 0; } +__declspec(dllexport) int __cdecl PurifyAllInuse(void) { avoidGy_5++; return 0; } +__declspec(dllexport) int __cdecl PurifyClearInuse(void) { avoidGy_6++; return 0; } +__declspec(dllexport) int __cdecl PurifyNewLeaks(void) { avoidGy_7++; return 0; } +__declspec(dllexport) int __cdecl PurifyAllLeaks(void) { avoidGy_8++; return 0; } +__declspec(dllexport) int __cdecl PurifyClearLeaks(void) { avoidGy_9++; return 0; } +__declspec(dllexport) int __cdecl PurifyAllHandlesInuse(void) { avoidGy_10++; return 0; } +__declspec(dllexport) int __cdecl PurifyNewHandlesInuse(void) { avoidGy_11++; return 0; } +__declspec(dllexport) int __cdecl PurifyDescribe(void *addr) { avoidGy_12++; addr; return 0; } +__declspec(dllexport) int __cdecl PurifyWhatColors(void *addr, int size) { avoidGy_13++; addr; size; return 0; } +__declspec(dllexport) int __cdecl PurifyAssertIsReadable(const void *addr, int size) { avoidGy_14++; addr; size; return 1; } +__declspec(dllexport) int __cdecl PurifyAssertIsWritable(const void *addr, int size) { avoidGy_15++; addr; size; return 1; } +__declspec(dllexport) int __cdecl PurifyIsReadable(const void *addr, int size) { avoidGy_16++; addr; size; return 1; } +__declspec(dllexport) int __cdecl PurifyIsWritable(const void *addr, int size) { avoidGy_17++; addr; size; return 1; } +__declspec(dllexport) int __cdecl PurifyIsInitialized(const void *addr, int size) { avoidGy_18++; addr; size; return 1; } +__declspec(dllexport) int __cdecl PurifyRed(void *addr, int size) { avoidGy_19++; addr; size; return 0; } +__declspec(dllexport) int __cdecl PurifyGreen(void *addr, int size) { avoidGy_20++; addr; size; return 0; } +__declspec(dllexport) int __cdecl PurifyYellow(void *addr, int size) { avoidGy_21++; addr; size; return 0; } +__declspec(dllexport) int __cdecl PurifyBlue(void *addr, int size) { avoidGy_22++; addr; size; return 0; } +__declspec(dllexport) int __cdecl PurifyMarkAsInitialized(void *addr, int size) { avoidGy_23++; addr; size; return 0; } +__declspec(dllexport) int __cdecl PurifyMarkAsUninitialized(void *addr, int size) { avoidGy_24++; addr; size; return 0; } +__declspec(dllexport) int __cdecl PurifyMarkForTrap(void *addr, int size) { avoidGy_25++; addr; size; return 0; } +__declspec(dllexport) int __cdecl PurifyMarkForNoTrap(void *addr, int size) { avoidGy_26++; addr; size; return 0; } +__declspec(dllexport) int __cdecl PurifyHeapValidate(unsigned int hHeap, unsigned int dwFlags, const void *addr) + { avoidGy_27++; hHeap; dwFlags; addr; return 1; } +__declspec(dllexport) int __cdecl PurifySetLateDetectScanCounter(int counter) { avoidGy_28++; counter; return 0; }; +__declspec(dllexport) int __cdecl PurifySetLateDetectScanInterval(int seconds) { avoidGy_29++; seconds; return 0; }; +__declspec(dllexport) int __cdecl CoverageIsRunning(void) { avoidGy_30++; return 0; } +__declspec(dllexport) int __cdecl CoverageDisableRecordingData(void) { avoidGy_31++; return 0; } +__declspec(dllexport) int __cdecl CoverageStartRecordingData(void) { avoidGy_32++; return 0; } +__declspec(dllexport) int __cdecl CoverageStopRecordingData(void) { avoidGy_33++; return 0; } +__declspec(dllexport) int __cdecl CoverageClearData(void) { avoidGy_34++; return 0; } +__declspec(dllexport) int __cdecl CoverageIsRecordingData(void) { avoidGy_35++; return 0; } +__declspec(dllexport) int __cdecl CoverageAddAnnotation(char *str) { avoidGy_36++; str; return 0; } +__declspec(dllexport) int __cdecl CoverageSaveData(void) { avoidGy_37++; return 0; } +__declspec(dllexport) int __cdecl QuantifyIsRunning(void) { avoidGy_42++; return 0; } +__declspec(dllexport) int __cdecl QuantifyDisableRecordingData(void) { avoidGy_43++; return 0; } +__declspec(dllexport) int __cdecl QuantifyStartRecordingData(void) { avoidGy_44++; return 0; } +__declspec(dllexport) int __cdecl QuantifyStopRecordingData(void) { avoidGy_45++; return 0; } +__declspec(dllexport) int __cdecl QuantifyClearData(void) { avoidGy_46++; return 0; } +__declspec(dllexport) int __cdecl QuantifyIsRecordingData(void) { avoidGy_47++; return 0; } +__declspec(dllexport) int __cdecl QuantifyAddAnnotation(char *str) { avoidGy_48++; str; return 0; } +__declspec(dllexport) int __cdecl QuantifySaveData(void) { avoidGy_49++; return 0; } +__declspec(dllexport) int __cdecl PurelockIsRunning(void) { avoidGy_PL_01++; return 0; } diff --git a/src/libs/xpcom18a4/xpcom/build/.cvsignore b/src/libs/xpcom18a4/xpcom/build/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/build/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/xpcom/build/Makefile.in b/src/libs/xpcom18a4/xpcom/build/Makefile.in new file mode 100644 index 00000000..5c2386ce --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/build/Makefile.in @@ -0,0 +1,165 @@ +# +# ***** 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.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of 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 ***** + +DEPTH = ../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = xpcom +LIBRARY_NAME = xpcom + +PACKAGE_FILE = xpcom.pkg +PACKAGE_VARS += USE_SHORT_LIBNAME + +ifdef ENABLE_TESTS +PACKAGE_FILE += xpcom-tests.pkg +endif + +# Do not set EXPORT_LIBRARY as we do not want xpcom in the static libs list +#EXPORT_LIBRARY = 1 +GRE_MODULE = 1 + +REQUIRES = string \ + $(NULL) + +# pull in MoreFiles for MacOSX +ifneq (,$(filter mac cocoa,$(MOZ_WIDGET_TOOLKIT))) +REQUIRES += macmorefiles +endif + +CPPSRCS = nsXPComInit.cpp \ + nsStringAPI.cpp \ + $(NULL) + +ifeq ($(OS_ARCH),WINNT) +CPPSRCS += dlldeps.cpp +endif + +ifdef XPCOM_USE_LEA +CSRCS += malloc.c +endif + +ifeq ($(OS_TARGET),OS2) +CPPSRCS += nsOS2VACLegacy.cpp +endif + +ifdef GC_LEAK_DETECTOR +EXTRA_DSO_LIBS = boehm +endif + +SHARED_LIBRARY_LIBS = \ + $(DIST)/lib/$(LIB_PREFIX)xpcomds_s.$(LIB_SUFFIX) \ + $(DIST)/lib/$(LIB_PREFIX)xpcomio_s.$(LIB_SUFFIX) \ + $(DIST)/lib/$(LIB_PREFIX)xpcomcomponents_s.$(LIB_SUFFIX) \ + $(DIST)/lib/$(LIB_PREFIX)xpcomthreads_s.$(LIB_SUFFIX) \ + $(DIST)/lib/$(LIB_PREFIX)xpcomproxy_s.$(LIB_SUFFIX) \ + $(DIST)/lib/$(LIB_PREFIX)xpcombase_s.$(LIB_SUFFIX) \ + $(DIST)/lib/$(LIB_PREFIX)xptcall.$(LIB_SUFFIX) \ + $(DIST)/lib/$(LIB_PREFIX)xptinfo.$(LIB_SUFFIX) \ + $(DIST)/lib/$(LIB_PREFIX)xpt.$(LIB_SUFFIX) \ + $(DIST)/lib/$(LIB_PREFIX)xptcmd.$(LIB_SUFFIX) \ + $(DIST)/lib/$(LIB_PREFIX)string_s.$(LIB_SUFFIX) \ + $(DIST)/lib/$(LIB_PREFIX)xpcomglue_s.$(LIB_SUFFIX) \ + $(NULL) + +LOCAL_INCLUDES = \ + -I.. \ + -I$(srcdir)/../glue \ + -I$(srcdir)/../base \ + -I$(srcdir)/../ds \ + -I$(srcdir)/../io \ + -I$(srcdir)/../components \ + -I$(srcdir)/../threads \ + -I$(srcdir)/../threads/_xpidlgen \ + -I$(srcdir)/../proxy/src \ + $(NULL) + +SDK_HEADERS = \ + nsXPCOM.h \ + nsXPCOMCID.h \ + $(NULL) + +SDK_LIBRARY = $(IMPORT_LIBRARY) +SDK_BINARY = $(SHARED_LIBRARY) + +# pull in MoreFiles for MacOSX +ifneq (,$(filter mac cocoa,$(MOZ_WIDGET_TOOLKIT))) +EXTRA_DSO_LIBS = macmorefiles_s +EXTRA_DSO_LDOPTS += $(EXTRA_DSO_LIBS) +EXTRA_DEPS += $(DIST)/lib/$(LIB_PREFIX)macmorefiles_s.$(LIB_SUFFIX) +endif + +# Force use of PIC +FORCE_USE_PIC = 1 + +FORCE_SHARED_LIB = 1 + +# UNIX98 iconv support +OS_LIBS += $(LIBICONV) + +include $(topsrcdir)/config/rules.mk + +DEFINES += \ + -D_IMPL_NS_COM \ + -DEXPORT_XPT_API \ + -DEXPORT_XPTC_API \ + -DEXPORT_XPTI_API + +EXTRA_DSO_LDOPTS += $(NSPR_LIBS) + +ifdef GC_LEAK_DETECTOR +DEFINES += -DGC_LEAK_DETECTOR +endif + +ifneq (,$(filter mac cocoa,$(MOZ_WIDGET_TOOLKIT))) +CXXFLAGS += $(TK_CFLAGS) +EXTRA_DSO_LDOPTS += $(TK_LIBS) +endif + +ifeq ($(OS_ARCH),BeOS) +EXTRA_DSO_LDOPTS += -lbe +endif + +ifeq ($(OS_ARCH),WINNT) +EXTRA_DSO_LDOPTS += $(call EXPAND_LIBNAME,shell32 ole32 uuid) +ifneq (,$(MOZ_DEBUG)$(NS_TRACE_MALLOC)) +EXTRA_DSO_LDOPTS += $(call EXPAND_LIBNAME,imagehlp) +endif +endif # WINNT diff --git a/src/libs/xpcom18a4/xpcom/build/dlldeps.cpp b/src/libs/xpcom18a4/xpcom/build/dlldeps.cpp new file mode 100644 index 00000000..5fc31189 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/build/dlldeps.cpp @@ -0,0 +1,202 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +// Force references to all of the symbols that we want exported from +// the dll that are located in the .lib files we link with + +#include "nsVoidArray.h" +#include "nsValueArray.h" +#include "nsIAtom.h" +//#include "nsIBuffer.h" +#include "nsIByteArrayInputStream.h" +#include "nsFixedSizeAllocator.h" +#include "nsRecyclingAllocator.h" +#include "nsIThread.h" +#include "nsDeque.h" +#include "nsTraceRefcnt.h" +#include "nsTraceRefcntImpl.h" +#include "nsXPIDLString.h" +#include "nsIEnumerator.h" +#include "nsEnumeratorUtils.h" +#include "nsQuickSort.h" +#include "nsString.h" +#include "nsPrintfCString.h" +#include "nsSupportsArray.h" +#include "nsArray.h" +#include "nsArrayEnumerator.h" +#include "nsProxyEventPrivate.h" +#include "nsProxyRelease.h" +#include "xpt_xdr.h" +#include "xptcall.h" +#include "nsILocalFile.h" +#include "nsIGenericFactory.h" +#include "nsIPipe.h" +#include "nsStreamUtils.h" +#include "nsWeakReference.h" +#include "nsTextFormatter.h" +#include "nsIStorageStream.h" +#include "nsLinebreakConverter.h" +#include "nsIBinaryInputStream.h" +#include "nsIInterfaceRequestor.h" +#include "nsIInterfaceRequestorUtils.h" +#include "nsReadableUtils.h" +#include "nsStaticNameTable.h" +#include "nsProcess.h" +#include "nsStringEnumerator.h" +#include "nsIInputStreamTee.h" +#include "nsCheapSets.h" +#ifdef DEBUG +#include "pure.h" +#endif +#include "nsHashKeys.h" +#include "nsTHashtable.h" +#include "pldhash.h" +#include "nsVariant.h" +#include "nsEscape.h" +#include "nsStreamUtils.h" + +#define NS_STRINGAPI_IMPL +#include "nsStringAPI.h" + +void XXXNeverCalled() +{ + nsTextFormatter::snprintf(nsnull,0,nsnull); + nsTextFormatter::smprintf(nsnull, nsnull); + nsTextFormatter::smprintf_free(nsnull); + nsVoidArray(); + nsSmallVoidArray(); + nsStringHashSet(); + nsCStringHashSet(); + nsInt32HashSet(); + nsVoidHashSet(); + nsCheapStringSet(); + nsCheapInt32Set(); + nsValueArray(0); + nsSupportsArray(); + NS_GetNumberOfAtoms(); + NS_NewPipe2(nsnull, nsnull, PR_FALSE, PR_FALSE, 0, 0, nsnull); + NS_NewInputStreamReadyEvent(nsnull, nsnull, nsnull); + NS_NewOutputStreamReadyEvent(nsnull, nsnull, nsnull); + NS_AsyncCopy(nsnull, nsnull, nsnull, NS_ASYNCCOPY_VIA_READSEGMENTS, 0, nsnull, nsnull); + PL_DHashStubEnumRemove(nsnull, nsnull, nsnull, nsnull); + nsIDHashKey::HashKey(nsnull); + nsFixedSizeAllocator a; + nsRecyclingAllocator recyclingAllocator(2); + a.Init(0, 0, 0, 0, 0); + a.Alloc(0); + a.Free(0, 0); + nsIThread::GetCurrent(nsnull); + nsDeque(nsnull); + nsTraceRefcnt::LogAddCOMPtr(nsnull, nsnull); + nsTraceRefcntImpl::DumpStatistics(); + NS_NewEmptyEnumerator(nsnull); + new nsArrayEnumerator(nsnull); + NS_QuickSort(nsnull, 0, 0, nsnull, nsnull); + nsString(); + nsProxyObject(nsnull, 0, nsnull); + NS_ProxyRelease(nsnull, nsnull, PR_FALSE); + XPT_DoString(nsnull, nsnull, nsnull); + XPT_DoHeader(nsnull, nsnull, nsnull); +#ifdef DEBUG + PurePrintf(0); +#endif + XPTC_InvokeByIndex(nsnull, 0, 0, nsnull); + xptc_dummy(); + xptc_dummy2(); + XPTI_GetInterfaceInfoManager(); + NS_NewGenericFactory(nsnull, nsnull); + NS_NewGenericModule2(nsnull, nsnull); + NS_GetWeakReference(nsnull); + nsCOMPtr dummyFoo(do_GetInterface(nsnull)); + NS_NewByteArrayInputStream(nsnull, nsnull, 0); + NS_NewStorageStream(0,0, nsnull); + nsString foo; + nsPrintfCString bar(""); + nsLinebreakConverter::ConvertStringLineBreaks(foo, + nsLinebreakConverter::eLinebreakAny, nsLinebreakConverter::eLinebreakContent); + NS_NewLocalFile(nsString(), PR_FALSE, nsnull); + NS_NewNativeLocalFile(nsCString(), PR_FALSE, nsnull); + new nsProcess(); + nsStaticCaseInsensitiveNameTable(); + nsAutoString str1; + str1.AssignWithConversion(nsnull, 0); + nsCAutoString str2; + ToNewUnicode(str1); + ToNewUnicode(str2); + ToNewCString(str1); + ToNewCString(str2); + PL_DHashTableFinish(nsnull); + NS_NewInputStreamTee(nsnull, nsnull, nsnull); + NS_NewArray(nsnull); + nsCOMArray dummyArray; + NS_NewArray(nsnull, dummyArray); + NS_NewArrayEnumerator(nsnull, dummyArray); + new nsVariant(); + nsUnescape(nsnull); + nsEscape(nsnull, url_XAlphas); + nsStringArray array; + NS_NewStringEnumerator(nsnull, &array); + NS_NewAdoptingStringEnumerator(nsnull, &array); + nsCStringArray carray; + NS_NewUTF8StringEnumerator(nsnull, &carray); + NS_NewAdoptingUTF8StringEnumerator(nsnull, &carray); + nsVoidableString str3; + nsCStringContainer sc1; + NS_CStringContainerInit(sc1); + NS_CStringContainerFinish(sc1); + NS_CStringGetData(str2, nsnull, nsnull); + NS_CStringSetData(str2, nsnull, 0); + NS_CStringSetDataRange(str2, 0, 0, nsnull, 0); + NS_CStringCopy(str2, str2); + nsStringContainer sc2; + NS_StringContainerInit(sc2); + NS_StringContainerFinish(sc2); + NS_StringGetData(str1, nsnull, nsnull); + NS_StringSetData(str1, nsnull, 0); + NS_StringSetDataRange(str1, 0, 0, nsnull, 0); + NS_StringCopy(str1, str1); + { + nsAdoptingCString foo, bar; + foo = bar; + } + { + nsAdoptingString foo, bar; + foo = bar; + } + NS_UTF16ToCString(str1, NS_CSTRING_ENCODING_ASCII, str2); + NS_CStringToUTF16(str2, NS_CSTRING_ENCODING_ASCII, str1); +} diff --git a/src/libs/xpcom18a4/xpcom/build/malloc.c b/src/libs/xpcom18a4/xpcom/build/malloc.c new file mode 100644 index 00000000..96691829 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/build/malloc.c @@ -0,0 +1,5126 @@ +#define USE_MALLOC_LOCK +#define DEFAULT_TRIM_THRESHOLD (256 * 1024) + +/* ---------- To make a malloc.h, start cutting here ------------ */ + +/* + **************************************************************** + * THIS IS A PRERELEASE. It has not yet been tested adequately. * + * If you use it, please send back comments, suggestions, * + * performance reports, etc. * + **************************************************************** +*/ + +/* + A version (aka dlmalloc) of malloc/free/realloc written by Doug + Lea and released to the public domain. Use this code without + permission or acknowledgement in any way you wish. Send questions, + comments, complaints, performance data, etc to dl@cs.oswego.edu + +* VERSION 2.7.0pre7 Wed Jan 10 13:33:01 2001 Doug Lea (dl at gee) + + Note: There may be an updated version of this malloc obtainable at + ftp://gee.cs.oswego.edu/pub/misc/malloc.c + Check before installing! + +* Quickstart + + This library is all in one file to simplify the most common usage: + ftp it, compile it (-O), and link it into another program. All + of the compile-time options default to reasonable values for use on + most unix platforms. Compile -DWIN32 for reasonable defaults on windows. + You might later want to step through various compile options. + +* Why use this malloc? + + This is not the fastest, most space-conserving, most portable, or + most tunable malloc ever written. However it is among the fastest + while also being among the most space-conserving, portable and tunable. + Consistent balance across these factors results in a good general-purpose + allocator for malloc-intensive programs. + + The main properties of the algorithms are: + * For large (>= 512 bytes) requests, it is a pure best-fit allocator, + with ties normally decided via FIFO (i.e. least recently used). + * For small (<= 64 bytes by default) requests, it is a caching + allocator, that maintains pools of quickly recycled chunks. + * In between, and for combinations of large and small requests, it does + the best it can trying to meet both goals at once. + + Compared to 2.6.X versions, this version is generally faster, + especially for programs that allocate and free many small chunks. + + For a longer but slightly out of date high-level description, see + http://gee.cs.oswego.edu/dl/html/malloc.html + + You may already by default be using a c library containing a malloc + that is somehow based on some version of this malloc (for example in + linux). You might still want to use the one in this file in order to + customize settings or to avoid overheads associated with library + versions. + +* Synopsis of public routines + + (Much fuller descriptions are contained in the program documentation below.) + + malloc(size_t n); + Return a pointer to a newly allocated chunk of at least n bytes, or null + if no space is available. + free(Void_t* p); + Release the chunk of memory pointed to by p, or no effect if p is null. + realloc(Void_t* p, size_t n); + Return a pointer to a chunk of size n that contains the same data + as does chunk p up to the minimum of (n, p's size) bytes, or null + if no space is available. The returned pointer may or may not be + the same as p. If p is null, equivalent to malloc. Unless the + #define REALLOC_ZERO_BYTES_FREES below is set, realloc with a + size argument of zero (re)allocates a minimum-sized chunk. + memalign(size_t alignment, size_t n); + Return a pointer to a newly allocated chunk of n bytes, aligned + in accord with the alignment argument, which must be a power of + two. + valloc(size_t n); + Equivalent to memalign(pagesize, n), where pagesize is the page + size of the system (or as near to this as can be figured out from + all the includes/defines below.) + pvalloc(size_t n); + Equivalent to valloc(minimum-page-that-holds(n)), that is, + round up n to nearest pagesize. + calloc(size_t unit, size_t quantity); + Returns a pointer to quantity * unit bytes, with all locations + set to zero. + cfree(Void_t* p); + Equivalent to free(p). + malloc_trim(size_t pad); + Release all but pad bytes of freed top-most memory back + to the system. Return 1 if successful, else 0. + malloc_usable_size(Void_t* p); + Report the number usable allocated bytes associated with allocated + chunk p. This may or may not report more bytes than were requested, + due to alignment and minimum size constraints. + malloc_stats(); + Prints brief summary statistics on stderr. + mallinfo() + Returns (by copy) a struct containing various summary statistics. + mallopt(int parameter_number, int parameter_value) + Changes one of the tunable parameters described below. Returns + 1 if successful in changing the parameter, else 0. + +* Vital statistics: + + Assumed pointer representation: 4 or 8 bytes + (Thanks to Wolfram Gloger for contributing most of the + changes supporting dual 4/8.) + + Assumed size_t representation: 4 or 8 bytes + Note that size_t is allowed to be 4 bytes even if pointers are 8. + You can adjust this by defining INTERNAL_SIZE_T + + Alignment: 2 * sizeof(size_t) + (i.e., 8 byte alignment with 4byte size_t). This suffices for + nearly all current machines and C compilers. However, you can + define MALLOC_ALIGNMENT to be wider than this if necessary. + + Minimum overhead per allocated chunk: 4 or 8 bytes + Each malloced chunk has a hidden word of overhead holding size + and status information. + + Minimum allocated size: 4-byte ptrs: 16 bytes (including 4 overhead) + 8-byte ptrs: 24/32 bytes (including, 4/8 overhead) + + When a chunk is freed, 12 (for 4byte ptrs) or 20 (for 8 byte + ptrs but 4 byte size) or 24 (for 8/8) additional bytes are + needed; 4 (8) for a trailing size field and 8 (16) bytes for + free list pointers. Thus, the minimum allocatable size is + 16/24/32 bytes. + + Even a request for zero bytes (i.e., malloc(0)) returns a + pointer to something of the minimum allocatable size. + + The maximum overhead wastage (i.e., number of extra bytes + allocated than were requested in malloc) is less than or equal + to the minimum size, except for requests >= mmap_threshold that + are serviced via mmap(), where the worst case wastage is 2 * + sizeof(size_t) bytes plus the remainder from a system page (the + minimal mmap unit); typically 4096 bytes. + + Maximum allocated size: 4-byte size_t: 2^31 minus about two pages + 8-byte size_t: 2^63 minus about two pages + + It is assumed that (possibly signed) size_t values suffice + to represent chunk sizes. `Possibly signed' is due to the fact + that `size_t' may be defined on a system as either a signed or + an unsigned type. The ISO C standard says that it must be + unsigned, but a few systems are known not to adhere to this. + Additionally, even when size_t is unsigned, sbrk (which is by + default used to obtain memory from system) accepts signed + arguments, and may not be able to handle size_t-wide arguments + with negative sign bit. To be conservative, values that would + appear as negative after accounting for overhead and alignment + are rejected. + + Requests for sizes outside this range will perform an optional + failure action and then return null. (Requests may also + also fail because a system is out of memory.) + + Thread-safety: NOT thread-safe unless USE_MALLOC_LOCK defined + + When USE_MALLOC_LOCK is defined, wrappers are created to + surround every public call with either a pthread mutex or + a win32 critical section (depending on WIN32). This is not + especially fast, and can be a major bottleneck in programs with + many threads. It is designed only to provide minimal protection + in concurrent environments, and to provide a basis for + extensions. If you are using malloc in a concurrent program, + you would be far better off obtaining ptmalloc, which is + derived from a version of this malloc, and is well-tuned for + concurrent programs. (See http://www.malloc.de) + + Compliance: I believe it is compliant with the 1997 Single Unix Specification + + (See http://www.opennc.org). Probably other standards as well. + +* Limitations + + Here are some features that are NOT currently supported + + * No automated mechanism for fully checking that all accesses + to malloced memory stay within their bounds. However, there + are several add-ons and adaptations of this or other mallocs + available that do this. + * No support for compaction. + +* Synopsis of compile-time options: + + People have reported using previous versions of this malloc on all + versions of Unix, sometimes by tweaking some of the defines + below. It has been tested most extensively on Solaris and + Linux. It is also reported to work on WIN32 platforms. + People also report using it in stand-alone embedded systems. + + The implementation is in straight, hand-tuned ANSI C. It is not + at all modular. (Sorry!) It uses a lot of macros. To be at all + usable, this code should be compiled using an optimizing compiler + (for example gcc -O3) that can simplify expressions and control + paths. (FAQ: some macros import variables as arguments rather than + declare locals because people reported that some debuggers + otherwise get confused.) + + OPTION DEFAULT VALUE + + Compilation Environment options: + + __STD_C derived from C compiler defines + WIN32 NOT defined + HAVE_MEMCPY defined + USE_MEMCPY 1 if HAVE_MEMCPY is defined + HAVE_MMAP defined as 1 + MMAP_AS_MORECORE_SIZE (1024 * 1024) + HAVE_MREMAP defined as 0 unless linux defined + malloc_getpagesize derived from system #includes, or 4096 if not + HAVE_USR_INCLUDE_MALLOC_H NOT defined + LACKS_UNISTD_H NOT defined unless WIN32 + LACKS_SYS_PARAM_H NOT defined unless WIN32 + LACKS_SYS_MMAN_H NOT defined unless WIN32 + + Changing default word sizes: + + INTERNAL_SIZE_T size_t + MALLOC_ALIGNMENT 2 * sizeof(INTERNAL_SIZE_T) + + Configuration and functionality options: + + USE_DL_PREFIX NOT defined + USE_PUBLIC_MALLOC_WRAPPERS NOT defined + USE_MALLOC_LOCK NOT defined + DEBUG NOT defined + REALLOC_ZERO_BYTES_FREES NOT defined + MALLOC_FAILURE_ACTION errno = ENOMEM, if __STD_C defined, else no-op + TRIM_FASTBINS 0 + + Options for customizing MORECORE: + + MORECORE sbrk + MORECORE_CONTIGUOUS 1 + + Tuning options that are also dynamically changeable via mallopt: + + DEFAULT_MXFAST 64 + DEFAULT_TRIM_THRESHOLD 128 * 1024 + DEFAULT_TOP_PAD 0 + DEFAULT_MMAP_THRESHOLD 128 * 1024 + DEFAULT_MMAP_MAX 256 + + There are several other #defined constants and macros that you + probably don't want to touch unless you are extending or adapting malloc. + +*/ +#include "xpcom-private.h" + + + +/* + WIN32 sets up defaults for MS environment and compilers. + Otherwise defaults are for unix. +*/ + +/* #define WIN32 */ + +#ifdef WIN32 + +#include + +/* Win32 doesn't supply or need the following headers */ +#define LACKS_UNISTD_H +#define LACKS_SYS_PARAM_H +#define LACKS_SYS_MMAN_H + +/* Use the supplied emulation of sbrk */ +#define MORECORE sbrk +#define MORECORE_CONTIGUOUS 1 +#define MORECORE_FAILURE ((void*)(-1)) + +/* Use the supplied emulation mmap, munmap */ +#define HAVE_MMAP 1 +#define MUNMAP_FAILURE (-1) +/* These values don't really matter in windows mmap emulation */ +#define MAP_PRIVATE 1 +#define MAP_ANONYMOUS 2 +#define PROT_READ 1 +#define PROT_WRITE 2 + +/* Emulation functions defined at the end of this file */ + +/* If USE_MALLOC_LOCK, use supplied critical-section-based lock functions */ +#ifdef USE_MALLOC_LOCK +static int slwait(int *sl); +static int slrelease(int *sl); +#endif + +static long getpagesize(void); +static long getregionsize(void); +static void *sbrk(long size); +static void *mmap(void *ptr, long size, long prot, long type, long handle, long arg); +static long munmap(void *ptr, long size); + +static void vminfo (unsigned long *free, unsigned long *reserved, unsigned long *committed); +static int cpuinfo (int whole, unsigned long *kernel, unsigned long *user); + +#endif + + + +/* + __STD_C should be nonzero if using ANSI-standard C compiler, a C++ + compiler, or a C compiler sufficiently close to ANSI to get away + with it. +*/ + +#ifndef __STD_C +#ifdef __STDC__ +#define __STD_C 1 +#else +#if __cplusplus +#define __STD_C 1 +#else +#define __STD_C 0 +#endif /*__cplusplus*/ +#endif /*__STDC__*/ +#endif /*__STD_C*/ + + +/* + Void_t* is the pointer type that malloc should say it returns +*/ + +#ifndef Void_t +#if (__STD_C || defined(WIN32)) +#define Void_t void +#else +#define Void_t char +#endif +#endif /*Void_t*/ + +#if __STD_C +#include /* for size_t */ +#else +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* define LACKS_UNISTD_H if your system does not have a . */ + +/* #define LACKS_UNISTD_H */ + +#ifndef LACKS_UNISTD_H +#include +#endif + +/* define LACKS_SYS_PARAM_H if your system does not have a . */ + +/* #define LACKS_SYS_PARAM_H */ + + +#include /* needed for malloc_stats */ +#include /* needed for optional MALLOC_FAILURE_ACTION */ + + +/* + Debugging: + + Because freed chunks may be overwritten with bookkeeping fields, this + malloc will often die when freed memory is overwritten by user + programs. This can be very effective (albeit in an annoying way) + in helping track down dangling pointers. + + If you compile with -DDEBUG, a number of assertion checks are + enabled that will catch more memory errors. You probably won't be + able to make much sense of the actual assertion errors, but they + should help you locate incorrectly overwritten memory. The + checking is fairly extensive, and will slow down execution + noticeably. Calling malloc_stats or mallinfo with DEBUG set will + attempt to check every non-mmapped allocated and free chunk in the + course of computing the summmaries. (By nature, mmapped regions + cannot be checked very much automatically.) + + Setting DEBUG may also be helpful if you are trying to modify + this code. The assertions in the check routines spell out in more + detail the assumptions and invariants underlying the algorithms. + +*/ + +#if DEBUG +#include +#else +#define assert(x) ((void)0) +#endif + + +/* + INTERNAL_SIZE_T is the word-size used for internal bookkeeping + of chunk sizes. + + The default version is the same as size_t. + + While not strictly necessary, it is best to define this as an + unsigned type, even if size_t is a signed type. This may avoid some + artificial size limitations on some systems. + + On a 64-bit machine, you may be able to reduce malloc overhead by + defining INTERNAL_SIZE_T to be a 32 bit `unsigned int' at the + expense of not being able to handle more than 2^32 of malloced + space. If this limitation is acceptable, you are encouraged to set + this unless you are on a platform requiring 16byte alignments. In + this case the alignment requirements turn out to negate any + potential advantages of decreasing size_t word size. + + Note to implementors: To deal with all this, comparisons and + difference computations among INTERNAL_SIZE_Ts should normally cast + INTERNAL_SIZE_T's to long or unsigned long, as appropriate, being + aware of the fact that casting an unsigned int to a wider long does not + sign-extend. (This also makes checking for negative numbers awkward.) + +*/ + +#ifndef INTERNAL_SIZE_T +#define INTERNAL_SIZE_T size_t +#endif + +/* The corresponding word size */ +#define SIZE_SZ (sizeof(INTERNAL_SIZE_T)) + + +/* + MALLOC_ALIGNMENT is the minimum alignment for malloc'ed chunks. + It must be a power of two at least 2 * SIZE_SZ, even on machines + for which smaller alignments would suffice. It may be defined as + larger than this though. (Note however that code and data structures + are optimized for the case of 8-byte alignment.) + +*/ + + /* #define MALLOC_ALIGNMENT 16 */ + +#ifndef MALLOC_ALIGNMENT +#define MALLOC_ALIGNMENT (2 * SIZE_SZ) +#endif + +/* The corresponding bit mask value */ +#define MALLOC_ALIGN_MASK (MALLOC_ALIGNMENT - 1) + + +/* + REALLOC_ZERO_BYTES_FREES should be set if a call to + realloc with zero bytes should be the same as a call to free. + Some people think it should. Otherwise, since this malloc + returns a unique pointer for malloc(0), so does realloc(p, 0). +*/ + +/* #define REALLOC_ZERO_BYTES_FREES */ + + +/* + USE_DL_PREFIX will prefix all public routines with the string 'dl'. + This is necessary when you only want to use this malloc in one part + of a program, using your regular system malloc elsewhere. +*/ + +/* #define USE_DL_PREFIX */ + + +/* + USE_MALLOC_LOCK causes wrapper functions to surround each + callable routine with pthread mutex lock/unlock. + + USE_MALLOC_LOCK forces USE_PUBLIC_MALLOC_WRAPPERS to be defined +*/ + +/* #define USE_MALLOC_LOCK */ + + +/* + If USE_PUBLIC_MALLOC_WRAPPERS is defined, every public routine is + actually a wrapper function that first calls MALLOC_PREACTION, then + calls the internal routine, and follows it with + MALLOC_POSTACTION. This is needed for locking, but you can also use + this, without USE_MALLOC_LOCK, for purposes of interception, + instrumentation, etc. It is a sad fact that using wrappers often + noticeably degrades performance of malloc-intensive programs. +*/ + +#ifdef USE_MALLOC_LOCK +#define USE_PUBLIC_MALLOC_WRAPPERS +#else +/* #define USE_PUBLIC_MALLOC_WRAPPERS */ +#endif + + + + +/* + HAVE_MEMCPY should be defined if you are not otherwise using + ANSI STD C, but still have memcpy and memset in your C library + and want to use them in calloc and realloc. Otherwise simple + macro versions are defined below. + + USE_MEMCPY should be defined as 1 if you actually want to + have memset and memcpy called. People report that the macro + versions are faster than libc versions on some systems. + + Even if USE_MEMCPY is set to 1, loops to copy/clear small chunks + (of <= 36 bytes) are manually unrolled in realloc and calloc. +*/ + +#define HAVE_MEMCPY + +#ifndef USE_MEMCPY +#ifdef HAVE_MEMCPY +#define USE_MEMCPY 1 +#else +#define USE_MEMCPY 0 +#endif +#endif + + +#if (__STD_C || defined(HAVE_MEMCPY)) + +#ifdef WIN32 + /* + On Win32 platforms, 'memset()' and 'memcpy()' are already declared in + 'windows.h' + */ +#else +#if __STD_C +void* memset(void*, int, size_t); +void* memcpy(void*, const void*, size_t); +void* memmove(void*, const void*, size_t); +#else +Void_t* memset(); +Void_t* memcpy(); +Void_t* memmove(); +#endif +#endif +#endif + + +/* + MALLOC_FAILURE_ACTION is the action to take before "return 0" when + malloc fails to be able to return memory, either because memory is + exhausted or because of illegal arguments. + + By default, sets errno if running on STD_C platform, else does nothing. +*/ + +#ifndef MALLOC_FAILURE_ACTION +#if __STD_C +#define MALLOC_FAILURE_ACTION \ + errno = ENOMEM; + +#else + +#define MALLOC_FAILURE_ACTION +#endif +#endif + +/* + Define HAVE_MMAP as true to optionally make malloc() use mmap() to + allocate very large blocks. These will be returned to the + operating system immediately after a free(). Also, if mmap + is available, it is used as a backup strategy in cases where + MORECORE fails to provide space from system. + + This malloc is best tuned to work with mmap for large requests. + If you do not have mmap, allocation of very large chunks (1MB + or so) may be slower than you'd like. +*/ + +#ifndef HAVE_MMAP +#define HAVE_MMAP 1 +#endif + +/* + MMAP_AS_MORECORE_SIZE is the minimum mmap size argument to use if + sbrk fails, and mmap is used as a backup (which is done only if + HAVE_MMAP). The value must be a multiple of page size. This + backup strategy generally applies only when systems have "holes" in + address space, so sbrk cannot perform contiguous expansion, but + there is still space available on system. On systems for which + this is known to be useful (i.e. most linux kernels), this occurs + only when programs allocate huge amounts of memory. Between this, + and the fact that mmap regions tend to be limited, the size should + be large, to avoid too many mmap calls and thus avoid running out + of kernel resources. +*/ + +#ifndef MMAP_AS_MORECORE_SIZE +#define MMAP_AS_MORECORE_SIZE (1024 * 1024) +#endif + + + +/* + Define HAVE_MREMAP to make realloc() use mremap() to re-allocate + large blocks. This is currently only possible on Linux with + kernel versions newer than 1.3.77. +*/ + +#ifndef HAVE_MREMAP +#ifdef linux +#define HAVE_MREMAP 1 +#else +#define HAVE_MREMAP 0 +#endif + +#endif /* HAVE_MMAP */ + + +/* + + This version of malloc supports the standard SVID/XPG mallinfo + routine that returns a struct containing usage properties and + statistics. It should work on any SVID/XPG compliant system that has + a /usr/include/malloc.h defining struct mallinfo. (If you'd like to + install such a thing yourself, cut out the preliminary declarations + as described above and below and save them in a malloc.h file. But + there's no compelling reason to bother to do this.) + + The main declaration needed is the mallinfo struct that is returned + (by-copy) by mallinfo(). The SVID/XPG malloinfo struct contains a + bunch of field that are not even meaningful in this version of + malloc. These fields are are instead filled by mallinfo() with + other numbers that might be of interest. + + HAVE_USR_INCLUDE_MALLOC_H should be set if you have a + /usr/include/malloc.h file that includes a declaration of struct + mallinfo. If so, it is included; else an SVID2/XPG2 compliant + version is declared below. These must be precisely the same for + mallinfo() to work. + +*/ + +/* #define HAVE_USR_INCLUDE_MALLOC_H */ + +#ifdef HAVE_USR_INCLUDE_MALLOC_H +#include "/usr/include/malloc.h" +#else + +/* SVID2/XPG mallinfo structure */ + +struct mallinfo { + int arena; /* non-mmapped space allocated from system */ + int ordblks; /* number of free chunks */ + int smblks; /* number of fastbin blocks */ + int hblks; /* number of mmapped regions */ + int hblkhd; /* space in mmapped regions */ + int usmblks; /* maximum total allocated space */ + int fsmblks; /* space available in freed fastbin blocks */ + int uordblks; /* total allocated space */ + int fordblks; /* total free space */ + int keepcost; /* top-most, releasable (via malloc_trim) space */ +}; + +/* SVID2/XPG mallopt options */ + +#define M_MXFAST 1 /* Set maximum fastbin size */ +#define M_NLBLKS 2 /* UNUSED in this malloc */ +#define M_GRAIN 3 /* UNUSED in this malloc */ +#define M_KEEP 4 /* UNUSED in this malloc */ + + +#endif + + +/* Additional mallopt options supported in this malloc */ + +#ifndef M_TRIM_THRESHOLD +#define M_TRIM_THRESHOLD -1 +#endif + +#ifndef M_TOP_PAD +#define M_TOP_PAD -2 +#endif + +#ifndef M_MMAP_THRESHOLD +#define M_MMAP_THRESHOLD -3 +#endif + +#ifndef M_MMAP_MAX +#define M_MMAP_MAX -4 +#endif + + +/* + MXFAST is the maximum request size used for "fastbins", special bins + that hold returned chunks without consolidating their spaces. This + enables future requests for chunks of the same size to be handled + very quickly, but can increase fragmentation, and thus increase the + overall memory footprint of a program. + + This malloc manages fastbins very conservatively yet still + efficiently, so fragmentation is rarely a problem for values less + than or equal to the default. The maximum supported value of MXFAST + is 80. You wouldn't want it any higher than this anyway. Fastbins + are designed especially for use with many small structs, objects or + strings -- the default handles structs/objects/arrays with sizes up + to 8 4byte fields, or small strings representing words, tokens, + etc. Using fastbins for larger objects normally worsens + fragmentation without improving speed. + + MXFAST is set in REQUEST size units. It is internally used in + chunksize units, which adds padding and alignment. You can reduce + MXFAST to 0 to disable all use of fastbins. This causes the malloc + algorithm to be a close approximation of fifo-best-fit in all cases, + not just for larger requests, but will generally cause it to be + slower. + +*/ + +#ifndef DEFAULT_MXFAST +#define DEFAULT_MXFAST 64 +#endif + + +/* + M_TRIM_THRESHOLD is the maximum amount of unused top-most memory + to keep before releasing via malloc_trim in free(). + + Automatic trimming is mainly useful in long-lived programs. + Because trimming via sbrk can be slow on some systems, and can + sometimes be wasteful (in cases where programs immediately + afterward allocate more large chunks) the value should be high + enough so that your overall system performance would improve by + releasing. + + The trim threshold and the mmap control parameters (see below) + can be traded off with one another. Trimming and mmapping are + two different ways of releasing unused memory back to the + system. Between these two, it is often possible to keep + system-level demands of a long-lived program down to a bare + minimum. For example, in one test suite of sessions measuring + the XF86 X server on Linux, using a trim threshold of 128K and a + mmap threshold of 192K led to near-minimal long term resource + consumption. + + If you are using this malloc in a long-lived program, it should + pay to experiment with these values. As a rough guide, you + might set to a value close to the average size of a process + (program) running on your system. Releasing this much memory + would allow such a process to run in memory. Generally, it's + worth it to tune for trimming rather tham memory mapping when a + program undergoes phases where several large chunks are + allocated and released in ways that can reuse each other's + storage, perhaps mixed with phases where there are no such + chunks at all. And in well-behaved long-lived programs, + controlling release of large blocks via trimming versus mapping + is usually faster. + + However, in most programs, these parameters serve mainly as + protection against the system-level effects of carrying around + massive amounts of unneeded memory. Since frequent calls to + sbrk, mmap, and munmap otherwise degrade performance, the default + parameters are set to relatively high values that serve only as + safeguards. + + The default trim value is high enough to cause trimming only in + fairly extreme (by current memory consumption standards) cases. + It must be greater than page size to have any useful effect. To + disable trimming completely, you can set to (unsigned long)(-1); + + Trim settings interact with fastbin (MXFAST) settings: Unless + TRIM_FASTBINS is defined, automatic trimming never takes place upon + freeing a chunk with size less than or equal to MXFAST. Trimming is + instead delayed until subsequent freeing of larger chunks. However, + you can still force an attempted trim by calling malloc_trim. + + Also, trimming is not generally possible in cases where + the main arena is obtained via mmap. + +*/ + + +#ifndef DEFAULT_TRIM_THRESHOLD +#define DEFAULT_TRIM_THRESHOLD (128 * 1024) +#endif + + + +/* + M_TOP_PAD is the amount of extra `padding' space to allocate or + retain whenever sbrk is called. It is used in two ways internally: + + * When sbrk is called to extend the top of the arena to satisfy + a new malloc request, this much padding is added to the sbrk + request. + + * When malloc_trim is called automatically from free(), + it is used as the `pad' argument. + + In both cases, the actual amount of padding is rounded + so that the end of the arena is always a system page boundary. + + The main reason for using padding is to avoid calling sbrk so + often. Having even a small pad greatly reduces the likelihood + that nearly every malloc request during program start-up (or + after trimming) will invoke sbrk, which needlessly wastes + time. + + Automatic rounding-up to page-size units is normally sufficient + to avoid measurable overhead, so the default is 0. However, in + systems where sbrk is relatively slow, it can pay to increase + this value, at the expense of carrying around more memory than + the program needs. + +*/ + +#ifndef DEFAULT_TOP_PAD +#define DEFAULT_TOP_PAD (0) +#endif + +/* + + M_MMAP_THRESHOLD is the request size threshold for using mmap() + to service a request. Requests of at least this size that cannot + be allocated using already-existing space will be serviced via mmap. + (If enough normal freed space already exists it is used instead.) + + Using mmap segregates relatively large chunks of memory so that + they can be individually obtained and released from the host + system. A request serviced through mmap is never reused by any + other request (at least not directly; the system may just so + happen to remap successive requests to the same locations). + + Segregating space in this way has the benefit that mmapped space + can ALWAYS be individually released back to the system, which + helps keep the system level memory demands of a long-lived + program low. Mapped memory can never become `locked' between + other chunks, as can happen with normally allocated chunks, which + means that even trimming via malloc_trim would not release them. + + However, it has the disadvantages that: + + 1. The space cannot be reclaimed, consolidated, and then + used to service later requests, as happens with normal chunks. + 2. It can lead to more wastage because of mmap page alignment + requirements + 3. It causes malloc performance to be more dependent on host + system memory management support routines which may vary in + implementation quality and may impose arbitrary + limitations. Generally, servicing a request via normal + malloc steps is faster than going through a system's mmap. + + All together, these considerations should lead you to use mmap + only for relatively large requests. + +*/ + + +#ifndef DEFAULT_MMAP_THRESHOLD +#define DEFAULT_MMAP_THRESHOLD (128 * 1024) +#endif + +/* + M_MMAP_MAX is the maximum number of requests to simultaneously + service using mmap. This parameter exists because: + + 1. Some systems have a limited number of internal tables for + use by mmap. + 2. In most systems, overreliance on mmap can degrade overall + performance. + 3. If a program allocates many large regions, it is probably + better off using normal sbrk-based allocation routines that + can reclaim and reallocate normal heap memory. + + Setting to 0 disables use of mmap for servicing large requests. If + HAVE_MMAP is not set, the default value is 0, and attempts to set it + to non-zero values in mallopt will fail. +*/ + + + +#ifndef DEFAULT_MMAP_MAX +#if HAVE_MMAP +#define DEFAULT_MMAP_MAX (256) +#else +#define DEFAULT_MMAP_MAX (0) +#endif +#endif + + +/* + TRIM_FASTBINS controls whether free() of a very small chunk can + immediately lead to trimming. Setting to true (1) can reduce memory + footprint, but will almost always slow down (by a few percent) + programs that use a lot of small chunks. + + Define this only if you are willing to give up some speed to more + aggressively reduce system-level memory footprint when releasing + memory in programs that use many small chunks. You can get + essentially the same effect by setting MXFAST to 0, but this can + lead to even greater slowdowns in programs using many small chunks. + TRIM_FASTBINS is an in-between compile-time option, that disables + only those chunks bordering topmost memory from being placed in + fastbins. + +*/ + + +#ifndef TRIM_FASTBINS +#define TRIM_FASTBINS 0 +#endif + + +/* + MORECORE-related declarations. By default, rely on sbrk +*/ + + +#ifdef LACKS_UNISTD_H +#if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__) +#if __STD_C +extern Void_t* sbrk(ptrdiff_t); +#else +extern Void_t* sbrk(); +#endif +#endif +#endif + +/* + MORECORE is the name of the routine to call to obtain more memory + from the system. See below for general guidance on writing + alternative MORECORE functions, as well as a version for WIN32 and a + sample version for pre-OSX macos. +*/ + +#ifndef MORECORE +#define MORECORE sbrk +#endif + + +/* + MORECORE_FAILURE is the value returned upon failure of MORECORE + as well as mmap. Since it cannot be an otherwise valid memory address, + and must reflect values of standard sys calls, you probably ought not + try to redefine it. +*/ + +#ifndef MORECORE_FAILURE +#define MORECORE_FAILURE (-1) +#endif + +/* + If MORECORE_CONTIGUOUS is true, take advantage of fact that + consecutive calls to MORECORE with positive arguments always return + contiguous increasing addresses. This is true of unix sbrk. Even + if not defined, when regions happen to be contiguous, malloc will + permit allocations spanning regions obtained from different + calls. But defining this when applicable enables some stronger + consistency checks and space efficiencies. +*/ + + +#ifndef MORECORE_CONTIGUOUS +#define MORECORE_CONTIGUOUS 1 +#endif + + +/* + The system page size. To the extent possible, this malloc manages + memory from the system in page-size units. Note that this value is + cached during initialization into a field of malloc_state. So even + if malloc_getpagesize is a function, it is only called once. + + The following mechanics for getpagesize were adapted from bsd/gnu + getpagesize.h. If none of the system-probes here apply, a value of + 4096 is used, which should be OK: If they don't apply, then using + the actual value probably doesn't impact performance. +*/ + +#ifndef malloc_getpagesize + +#ifndef LACKS_UNISTD_H +# include +#endif + +# ifdef _SC_PAGESIZE /* some SVR4 systems omit an underscore */ +# ifndef _SC_PAGE_SIZE +# define _SC_PAGE_SIZE _SC_PAGESIZE +# endif +# endif + +# ifdef _SC_PAGE_SIZE +# define malloc_getpagesize sysconf(_SC_PAGE_SIZE) +# else +# if defined(BSD) || defined(DGUX) || defined(HAVE_GETPAGESIZE) + extern size_t getpagesize(); +# define malloc_getpagesize getpagesize() +# else +# ifdef WIN32 /* use supplied emulation of getpagesize */ +# define malloc_getpagesize getpagesize() +# else +# ifndef LACKS_SYS_PARAM_H +# include +# endif +# ifdef EXEC_PAGESIZE +# define malloc_getpagesize EXEC_PAGESIZE +# else +# ifdef NBPG +# ifndef CLSIZE +# define malloc_getpagesize NBPG +# else +# define malloc_getpagesize (NBPG * CLSIZE) +# endif +# else +# ifdef NBPC +# define malloc_getpagesize NBPC +# else +# ifdef PAGESIZE +# define malloc_getpagesize PAGESIZE +# else /* just guess */ +# define malloc_getpagesize (4096) +# endif +# endif +# endif +# endif +# endif +# endif +# endif +#endif + + +/* Two-phase Name mangling */ + +#ifndef USE_PUBLIC_MALLOC_WRAPPERS +#define cALLOc public_cALLOc +#define fREe public_fREe +#define cFREe public_cFREe +#define mALLOc public_mALLOc +#define mEMALIGn public_mEMALIGn +#define rEALLOc public_rEALLOc +#define vALLOc public_vALLOc +#define pVALLOc public_pVALLOc +#define mALLINFo public_mALLINFo +#define mALLOPt public_mALLOPt +#define mTRIm public_mTRIm +#define mSTATs public_mSTATs +#define mUSABLe public_mUSABLe +#endif + +#ifdef USE_DL_PREFIX +#define public_cALLOc dlcalloc +#define public_fREe dlfree +#define public_cFREe dlcfree +#define public_mALLOc dlmalloc +#define public_mEMALIGn dlmemalign +#define public_rEALLOc dlrealloc +#define public_vALLOc dlvalloc +#define public_pVALLOc dlpvalloc +#define public_mALLINFo dlmallinfo +#define public_mALLOPt dlmallopt +#define public_mTRIm dlmalloc_trim +#define public_mSTATs dlmalloc_stats +#define public_mUSABLe dlmalloc_usable_size +#else /* USE_DL_PREFIX */ +#define public_cALLOc calloc +#define public_fREe free +#define public_cFREe cfree +#define public_mALLOc malloc +#define public_mEMALIGn memalign +#define public_rEALLOc realloc +#define public_vALLOc valloc +#define public_pVALLOc pvalloc +#define public_mALLINFo mallinfo +#define public_mALLOPt mallopt +#define public_mTRIm malloc_trim +#define public_mSTATs malloc_stats +#define public_mUSABLe malloc_usable_size +#endif /* USE_DL_PREFIX */ + +#if __STD_C + +Void_t* public_mALLOc(size_t); +void public_fREe(Void_t*); +Void_t* public_rEALLOc(Void_t*, size_t); +Void_t* public_mEMALIGn(size_t, size_t); +Void_t* public_vALLOc(size_t); +Void_t* public_pVALLOc(size_t); +Void_t* public_cALLOc(size_t, size_t); +void public_cFREe(Void_t*); +int public_mTRIm(size_t); +size_t public_mUSABLe(Void_t*); +void public_mSTATs(); +int public_mALLOPt(int, int); +struct mallinfo public_mALLINFo(void); +#else +Void_t* public_mALLOc(); +void public_fREe(); +Void_t* public_rEALLOc(); +Void_t* public_mEMALIGn(); +Void_t* public_vALLOc(); +Void_t* public_pVALLOc(); +Void_t* public_cALLOc(); +void public_cFREe(); +int public_mTRIm(); +size_t public_mUSABLe(); +void public_mSTATs(); +int public_mALLOPt(); +struct mallinfo public_mALLINFo(); +#endif + + +#ifdef __cplusplus +}; /* end of extern "C" */ +#endif + + + +/* ---------- To make a malloc.h, end cutting here ------------ */ + + +/* Declarations of internal utilities defined below */ + + + + +#ifdef USE_PUBLIC_MALLOC_WRAPPERS +#if __STD_C + +static Void_t* mALLOc(size_t); +static void fREe(Void_t*); +static Void_t* rEALLOc(Void_t*, size_t); +static Void_t* mEMALIGn(size_t, size_t); +static Void_t* vALLOc(size_t); +static Void_t* pVALLOc(size_t); +static Void_t* cALLOc(size_t, size_t); +static void cFREe(Void_t*); +static int mTRIm(size_t); +static size_t mUSABLe(Void_t*); +static void mSTATs(); +static int mALLOPt(int, int); +static struct mallinfo mALLINFo(void); +#else +static Void_t* mALLOc(); +static void fREe(); +static Void_t* rEALLOc(); +static Void_t* mEMALIGn(); +static Void_t* vALLOc(); +static Void_t* pVALLOc(); +static Void_t* cALLOc(); +static void cFREe(); +static int mTRIm(); +static size_t mUSABLe(); +static void mSTATs(); +static int mALLOPt(); +static struct mallinfo mALLINFo(); +#endif +#endif + + + +/* ---------- public wrappers --------------- */ + +#ifdef USE_PUBLIC_MALLOC_WRAPPERS + +/* + MALLOC_PREACTION and MALLOC_POSTACTION should be + defined to return 0 on success, and nonzero on failure. + The return value of MALLOC_POSTACTION is currently ignored + in wrapper functions since there is no reasonable default + action to take on failure. +*/ + + +#ifdef USE_MALLOC_LOCK + +#ifdef WIN32 + +static int mALLOC_MUTEx; + +#define MALLOC_PREACTION slwait(&mALLOC_MUTEx) +#define MALLOC_POSTACTION slrelease(&mALLOC_MUTEx) + +#else + +#include + +static pthread_mutex_t mALLOC_MUTEx = PTHREAD_MUTEX_INITIALIZER; + +#define MALLOC_PREACTION pthread_mutex_lock(&mALLOC_MUTEx) +#define MALLOC_POSTACTION pthread_mutex_unlock(&mALLOC_MUTEx) + +#endif /* USE_MALLOC_LOCK */ + +#else + +/* Substitute anything you like for these */ + +#define MALLOC_PREACTION (0) +#define MALLOC_POSTACTION (0) + +#endif + +Void_t* public_mALLOc(size_t bytes) { + Void_t* m; + if (MALLOC_PREACTION != 0) { + return 0; + } + m = mALLOc(bytes); + if (MALLOC_POSTACTION != 0) { + } + return m; +} + +void public_fREe(Void_t* m) { + if (MALLOC_PREACTION != 0) { + return; + } + fREe(m); + if (MALLOC_POSTACTION != 0) { + } +} + +Void_t* public_rEALLOc(Void_t* m, size_t bytes) { + if (MALLOC_PREACTION != 0) { + return 0; + } + m = rEALLOc(m, bytes); + if (MALLOC_POSTACTION != 0) { + } + return m; +} + +Void_t* public_mEMALIGn(size_t alignment, size_t bytes) { + Void_t* m; + if (MALLOC_PREACTION != 0) { + return 0; + } + m = mEMALIGn(alignment, bytes); + if (MALLOC_POSTACTION != 0) { + } + return m; +} + +Void_t* public_vALLOc(size_t bytes) { + Void_t* m; + if (MALLOC_PREACTION != 0) { + return 0; + } + m = vALLOc(bytes); + if (MALLOC_POSTACTION != 0) { + } + return m; +} + +Void_t* public_pVALLOc(size_t bytes) { + Void_t* m; + if (MALLOC_PREACTION != 0) { + return 0; + } + m = pVALLOc(bytes); + if (MALLOC_POSTACTION != 0) { + } + return m; +} + +Void_t* public_cALLOc(size_t n, size_t elem_size) { + Void_t* m; + if (MALLOC_PREACTION != 0) { + return 0; + } + m = cALLOc(n, elem_size); + if (MALLOC_POSTACTION != 0) { + } + return m; +} + +void public_cFREe(Void_t* m) { + if (MALLOC_PREACTION != 0) { + return; + } + cFREe(m); + if (MALLOC_POSTACTION != 0) { + } +} + +int public_mTRIm(size_t s) { + int result; + if (MALLOC_PREACTION != 0) { + return 0; + } + result = mTRIm(s); + if (MALLOC_POSTACTION != 0) { + } + return result; +} + + +size_t public_mUSABLe(Void_t* m) { + size_t result; + if (MALLOC_PREACTION != 0) { + return 0; + } + result = mUSABLe(m); + if (MALLOC_POSTACTION != 0) { + } + return result; +} + + +void public_mSTATs() { + if (MALLOC_PREACTION != 0) { + return; + } + mSTATs(); + if (MALLOC_POSTACTION != 0) { + } +} + +struct mallinfo public_mALLINFo() { + struct mallinfo m; + if (MALLOC_PREACTION != 0) { + return m; + } + m = mALLINFo(); + if (MALLOC_POSTACTION != 0) { + } + return m; +} + +int public_mALLOPt(int p, int v) { + int result; + if (MALLOC_PREACTION != 0) { + return 0; + } + result = mALLOPt(p, v); + if (MALLOC_POSTACTION != 0) { + } + return result; +} + +#endif + + + +/* ------------- Optional versions of memcopy ---------------- */ + + +#if USE_MEMCPY + +#define MALLOC_COPY(dest, src, nbytes, overlap) \ + ((overlap) ? memmove(dest, src, nbytes) : memcpy(dest, src, nbytes)) +#define MALLOC_ZERO(dest, nbytes) memset(dest, 0, nbytes) + +#else /* !USE_MEMCPY */ + +/* Use Duff's device for good zeroing/copying performance. */ + +#define MALLOC_ZERO(charp, nbytes) \ +do { \ + INTERNAL_SIZE_T* mzp = (INTERNAL_SIZE_T*)(charp); \ + long mctmp = (nbytes)/sizeof(INTERNAL_SIZE_T), mcn; \ + if (mctmp < 8) mcn = 0; else { mcn = (mctmp-1)/8; mctmp %= 8; } \ + switch (mctmp) { \ + case 0: for(;;) { *mzp++ = 0; \ + case 7: *mzp++ = 0; \ + case 6: *mzp++ = 0; \ + case 5: *mzp++ = 0; \ + case 4: *mzp++ = 0; \ + case 3: *mzp++ = 0; \ + case 2: *mzp++ = 0; \ + case 1: *mzp++ = 0; if(mcn <= 0) break; mcn--; } \ + } \ +} while(0) + +/* For overlapping case, dest is always _below_ src. */ + +#define MALLOC_COPY(dest,src,nbytes,overlap) \ +do { \ + INTERNAL_SIZE_T* mcsrc = (INTERNAL_SIZE_T*) src; \ + INTERNAL_SIZE_T* mcdst = (INTERNAL_SIZE_T*) dest; \ + long mctmp = (nbytes)/sizeof(INTERNAL_SIZE_T), mcn; \ + if (mctmp < 8) mcn = 0; else { mcn = (mctmp-1)/8; mctmp %= 8; } \ + switch (mctmp) { \ + case 0: for(;;) { *mcdst++ = *mcsrc++; \ + case 7: *mcdst++ = *mcsrc++; \ + case 6: *mcdst++ = *mcsrc++; \ + case 5: *mcdst++ = *mcsrc++; \ + case 4: *mcdst++ = *mcsrc++; \ + case 3: *mcdst++ = *mcsrc++; \ + case 2: *mcdst++ = *mcsrc++; \ + case 1: *mcdst++ = *mcsrc++; if(mcn <= 0) break; mcn--; } \ + } \ +} while(0) + +#endif + +/* ------------------ MMAP support ------------------ */ + + +#if HAVE_MMAP + +#include +#ifndef LACKS_SYS_MMAN_H +#include +#endif + +#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON) +#define MAP_ANONYMOUS MAP_ANON +#endif + + +/* + Nearly all versions of mmap support MAP_ANONYMOUS, + so the following is unlikely to be needed, but is + supplied just in case. +*/ + +#ifndef MAP_ANONYMOUS + +static int dev_zero_fd = -1; /* Cached file descriptor for /dev/zero. */ + +#define MMAP(addr, size, prot, flags) ((dev_zero_fd < 0) ? \ + (dev_zero_fd = open("/dev/zero", O_RDWR), \ + mmap((addr), (size), (prot), (flags), dev_zero_fd, 0)) : \ + mmap((addr), (size), (prot), (flags), dev_zero_fd, 0)) + +#else + +#define MMAP(addr, size, prot, flags) \ + (mmap((addr), (size), (prot), (flags)|MAP_ANONYMOUS, -1, 0)) + +#endif + +#endif /* HAVE_MMAP */ + + +/* ---------- Alternative MORECORE functions ------------ */ + + +/* + General Requirements for MORECORE. + + The MORECORE function must have the following properties: + + If MORECORE_CONTIGUOUS is false: + + * MORECORE must allocate in multiples of pagesize. It will + only be called with arguments that are multiples of pagesize. + + * MORECORE must page-align. That is, MORECORE(0) must + return an address at a page boundary. + + else (i.e. If MORECORE_CONTIGUOUS is true): + + * Consecutive calls to MORECORE with positive arguments + return increasing addresses, indicating that space has been + contiguously extended. + + * MORECORE need not allocate in multiples of pagesize. + Calls to MORECORE need not have args of multiples of pagesize. + + * MORECORE need not page-align. + + In either case: + + * MORECORE may allocate more memory than requested. (Or even less, + but this will generally result in a malloc failure.) + + * MORECORE must not allocate memory when given argument zero, but + instead return one past the end address of memory from previous + nonzero call. This malloc does NOT call MORECORE(0) + until at least one call with positive arguments is made, so + the initial value returned is not important. + + * Even though consecutive calls to MORECORE need not return contiguous + addresses, it must be OK for malloc'ed chunks to span multiple + regions in those cases where they do happen to be contiguous. + + * MORECORE need not handle negative arguments -- it may instead + just return MORECORE_FAILURE when given negative arguments. + Negative arguments are always multiples of pagesize. MORECORE + must not misinterpret negative args as large positive unsigned + args. + + There is some variation across systems about the type of the + argument to sbrk/MORECORE. If size_t is unsigned, then it cannot + actually be size_t, because sbrk supports negative args, so it is + normally the signed type of the same width as size_t (sometimes + declared as "intptr_t", and sometimes "ptrdiff_t"). It doesn't much + matter though. Internally, we use "long" as arguments, which should + work across all reasonable possibilities. + + Additionally, if MORECORE ever returns failure for a positive + request, and HAVE_MMAP is true, then mmap is used as a noncontiguous + system allocator. This is a useful backup strategy for systems with + holes in address spaces -- in this case sbrk cannot contiguously + expand the heap, but mmap may be able to map noncontiguous space. + If you'd like mmap to ALWAYS be used, you can define MORECORE to be + a function that always returns MORECORE_FAILURE. + + If you are using this malloc with something other than unix sbrk to + supply memory regions, you probably want to set MORECORE_CONTIGUOUS + as false. As an example, here is a custom allocator kindly + contributed for pre-OSX macOS. It uses virtually but not + necessarily physically contiguous non-paged memory (locked in, + present and won't get swapped out). You can use it by uncommenting + this section, adding some #includes, and setting up the appropriate + defines above: + + #define MORECORE osMoreCore + #define MORECORE_CONTIGUOUS 0 + + There is also a shutdown routine that should somehow be called for + cleanup upon program exit. + + #define MAX_POOL_ENTRIES 100 + #define MINIMUM_MORECORE_SIZE (64 * 1024) + static int next_os_pool; + void *our_os_pools[MAX_POOL_ENTRIES]; + + void *osMoreCore(int size) + { + void *ptr = 0; + static void *sbrk_top = 0; + + if (size > 0) + { + if (size < MINIMUM_MORECORE_SIZE) + size = MINIMUM_MORECORE_SIZE; + if (CurrentExecutionLevel() == kTaskLevel) + ptr = PoolAllocateResident(size + RM_PAGE_SIZE, 0); + if (ptr == 0) + { + return (void *) MORECORE_FAILURE; + } + // save ptrs so they can be freed during cleanup + our_os_pools[next_os_pool] = ptr; + next_os_pool++; + ptr = (void *) ((((unsigned long) ptr) + RM_PAGE_MASK) & ~RM_PAGE_MASK); + sbrk_top = (char *) ptr + size; + return ptr; + } + else if (size < 0) + { + // we don't currently support shrink behavior + return (void *) MORECORE_FAILURE; + } + else + { + return sbrk_top; + } + } + + // cleanup any allocated memory pools + // called as last thing before shutting down driver + + void osCleanupMem(void) + { + void **ptr; + + for (ptr = our_os_pools; ptr < &our_os_pools[MAX_POOL_ENTRIES]; ptr++) + if (*ptr) + { + PoolDeallocate(*ptr); + *ptr = 0; + } + } + +*/ + + + + + +/* + ----------------------- Chunk representations ----------------------- +*/ + + +/* + This struct declaration is misleading (but accurate and necessary). + It declares a "view" into memory allowing access to necessary + fields at known offsets from a given base. See explanation below. +*/ + +struct malloc_chunk { + + INTERNAL_SIZE_T prev_size; /* Size of previous chunk (if free). */ + INTERNAL_SIZE_T size; /* Size in bytes, including overhead. */ + + struct malloc_chunk* fd; /* double links -- used only if free. */ + struct malloc_chunk* bk; +}; + + +typedef struct malloc_chunk* mchunkptr; + +/* + + malloc_chunk details: + + (The following includes lightly edited explanations by Colin Plumb.) + + Chunks of memory are maintained using a `boundary tag' method as + described in e.g., Knuth or Standish. (See the paper by Paul + Wilson ftp://ftp.cs.utexas.edu/pub/garbage/allocsrv.ps for a + survey of such techniques.) Sizes of free chunks are stored both + in the front of each chunk and at the end. This makes + consolidating fragmented chunks into bigger chunks very fast. The + size fields also hold bits representing whether chunks are free or + in use. + + An allocated chunk looks like this: + + + chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Size of previous chunk, if allocated | | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Size of chunk, in bytes |P| + mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | User data starts here... . + . . + . (malloc_usable_space() bytes) . + . | +nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Size of chunk | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + + Where "chunk" is the front of the chunk for the purpose of most of + the malloc code, but "mem" is the pointer that is returned to the + user. "Nextchunk" is the beginning of the next contiguous chunk. + + Chunks always begin on even word boundries, so the mem portion + (which is returned to the user) is also on an even word boundary, and + thus double-word aligned. + + Free chunks are stored in circular doubly-linked lists, and look like this: + + chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Size of previous chunk | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + `head:' | Size of chunk, in bytes |P| + mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Forward pointer to next chunk in list | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Back pointer to previous chunk in list | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Unused space (may be 0 bytes long) . + . . + . | +nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + `foot:' | Size of chunk, in bytes | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + The P (PREV_INUSE) bit, stored in the unused low-order bit of the + chunk size (which is always a multiple of two words), is an in-use + bit for the *previous* chunk. If that bit is *clear*, then the + word before the current chunk size contains the previous chunk + size, and can be used to find the front of the previous chunk. + The very first chunk allocated always has this bit set, + preventing access to non-existent (or non-owned) memory. If + prev_inuse is set for any given chunk, then you CANNOT determine + the size of the previous chunk, and might even get a memory + addressing fault when trying to do so. + + Note that the `foot' of the current chunk is actually represented + as the prev_size of the NEXT chunk. (This makes it easier to + deal with alignments etc). + + The two exceptions to all this are + + 1. The special chunk `top' doesn't bother using the + trailing size field since there is no next contiguous chunk + that would have to index off it. After initialization, `top' + is forced to always exist. If it would become less than + MINSIZE bytes long, it is replenished. + + 2. Chunks allocated via mmap, which have the second-lowest-order + bit (IS_MMAPPED) set in their size fields. Because they are + allocated one-by-one, each must contain its own trailing size field. + +*/ + + + +/* + Size and alignment checks and conversions +*/ + +/* conversion from malloc headers to user pointers, and back */ + +#define chunk2mem(p) ((Void_t*)((char*)(p) + 2*SIZE_SZ)) +#define mem2chunk(mem) ((mchunkptr)((char*)(mem) - 2*SIZE_SZ)) + +/* The smallest possible chunk */ +#define MIN_CHUNK_SIZE (sizeof(struct malloc_chunk)) + +/* The smallest size we can malloc is an aligned minimal chunk */ + +#define MINSIZE ((MIN_CHUNK_SIZE+MALLOC_ALIGN_MASK) & ~MALLOC_ALIGN_MASK) + +/* Check if m has acceptable alignment */ + +#define aligned_OK(m) (((unsigned long)((m)) & (MALLOC_ALIGN_MASK)) == 0) + +/* + Check for negative/huge sizes. + This cannot just test for < 0 because argument might + be an unsigned type of uncertain width. +*/ + +#define IS_NEGATIVE(x) \ + ((unsigned long)x >= \ + (unsigned long)((((INTERNAL_SIZE_T)(1)) << ((SIZE_SZ)*8 - 1)))) + + +/* pad request bytes into a usable size -- internal version */ + +#define request2size(req) \ + (((req) + SIZE_SZ + MALLOC_ALIGN_MASK < MINSIZE) ? \ + MINSIZE : \ + ((req) + SIZE_SZ + MALLOC_ALIGN_MASK) & ~MALLOC_ALIGN_MASK) + + +/* + Same, except check for negative/huge arguments. + This lets through args that are positive but wrap into + negatives when padded. However, these are trapped + elsewhere. +*/ + +#define checked_request2size(req, sz) \ + if (IS_NEGATIVE(req)) { \ + MALLOC_FAILURE_ACTION; \ + return 0; \ + } \ + (sz) = request2size(req); + + + + +/* + Physical chunk operations +*/ + + +/* size field is or'ed with PREV_INUSE when previous adjacent chunk in use */ + +#define PREV_INUSE 0x1 + + +/* size field is or'ed with IS_MMAPPED if the chunk was obtained with mmap() */ + +#define IS_MMAPPED 0x2 + + +/* Bits to mask off when extracting size */ + +#define SIZE_BITS (PREV_INUSE|IS_MMAPPED) + + +/* Ptr to next physical malloc_chunk. */ + +#define next_chunk(p) ((mchunkptr)( ((char*)(p)) + ((p)->size & ~PREV_INUSE) )) + + +/* Ptr to previous physical malloc_chunk */ + +#define prev_chunk(p) ((mchunkptr)( ((char*)(p)) - ((p)->prev_size) )) + + +/* Treat space at ptr + offset as a chunk */ + +#define chunk_at_offset(p, s) ((mchunkptr)(((char*)(p)) + (s))) + + + + +/* + Dealing with use bits + + Note: IS_MMAPPED is intentionally not masked off from size field in + macros for which mmapped chunks should never be seen. This should + cause helpful core dumps to occur if it is tried by accident by + people extending or adapting this malloc. + +*/ + + +/* extract p's inuse bit */ + +#define inuse(p)\ +((((mchunkptr)(((char*)(p))+((p)->size & ~PREV_INUSE)))->size) & PREV_INUSE) + + +/* extract inuse bit of previous chunk */ + +#define prev_inuse(p) ((p)->size & PREV_INUSE) + + +/* check for mmap()'ed chunk */ + +#define chunk_is_mmapped(p) ((p)->size & IS_MMAPPED) + + +/* set/clear chunk as being inuse without otherwise disturbing */ + +#define set_inuse(p)\ +((mchunkptr)(((char*)(p)) + ((p)->size & ~PREV_INUSE)))->size |= PREV_INUSE + +#define clear_inuse(p)\ +((mchunkptr)(((char*)(p)) + ((p)->size & ~PREV_INUSE)))->size &= ~(PREV_INUSE) + + +/* check/set/clear inuse bits in known places */ + +#define inuse_bit_at_offset(p, s)\ + (((mchunkptr)(((char*)(p)) + (s)))->size & PREV_INUSE) + +#define set_inuse_bit_at_offset(p, s)\ + (((mchunkptr)(((char*)(p)) + (s)))->size |= PREV_INUSE) + +#define clear_inuse_bit_at_offset(p, s)\ + (((mchunkptr)(((char*)(p)) + (s)))->size &= ~(PREV_INUSE)) + + + + +/* + Dealing with size fields +*/ + +/* Get size, ignoring use bits */ + +#define chunksize(p) ((p)->size & ~(SIZE_BITS)) + +/* Set size at head, without disturbing its use bit */ + +#define set_head_size(p, s) ((p)->size = (((p)->size & PREV_INUSE) | (s))) + +/* Set size/use field */ + +#define set_head(p, s) ((p)->size = (s)) + +/* Set size at footer (only when chunk is not in use) */ + +#define set_foot(p, s) (((mchunkptr)((char*)(p) + (s)))->prev_size = (s)) + + + + + +/* + ------------------ Internal data structures -------------------- + + All internal state is held in an instance of malloc_state defined + below. There are no other static variables, except in two optional + cases: + * If USE_MALLOC_LOCK is defined, the mALLOC_MUTEx declared + above. + * If HAVE_MMAP is true, but mmap doesn't support + MAP_ANONYMOUS, a dummy file descriptor for mmap. + + Beware of lots of tricks that minimize the total space + requirements. The result is a little over 1K bytes (for 4byte + pointers and size_t.) + +*/ + +/* + + Bins + + An array of bin headers for free chunks. Each bin is doubly + linked. The bins are approximately proportionally (log) spaced. + There are a lot of these bins (128). This may look excessive, but + works very well in practice. Most bins hold sizes that are + unusual as malloc request sizes, but are more usual for fragments + and consolidated sets of chunks, which is what these bins hold, so + they can be found quickly. All procedures maintain the invariant + that no consolidated chunk physically borders another one, so each + chunk in a list is known to be preceeded and followed by either + inuse chunks or the ends of memory. + + Chunks in bins are kept in size order, with ties going to the + approximately least recently used chunk. Ordering is irrelevant + for the small bins, which all contain the same-sized chunks, but + facilitates best-fit allocation for larger chunks. (These lists + are just sequential. Keeping them in order almost never requires + enough traversal to warrant using fancier ordered data + structures.) Chunks of the same size are linked with the most + recently freed at the front, and allocations are taken from the + back. This results in LRU (FIFO) allocation order, which tends + to give each chunk an equal opportunity to be consolidated with + adjacent freed chunks, resulting in larger free chunks and less + fragmentation. + + To simplify use in double-linked lists, each bin header acts + as a malloc_chunk. This avoids special-casing for headers. + But to conserve space and (mainly) improve locality, we allocate + only the fd/bk pointers of bins, and then use repositioning tricks + to treat these as the fields of a malloc_chunk*. +*/ + +typedef struct malloc_chunk* mbinptr; + +#define NBINS 128 + + +/* addressing -- note that bin_at(0) does not exist */ + +#define bin_at(m, i) ((mbinptr)((char*)&((m)->bins[(i)<<1]) - (SIZE_SZ<<1))) + + +/* analog of ++bin */ + +#define next_bin(b) ((mbinptr)((char*)(b) + (sizeof(mchunkptr)<<1))) + + +/* Reminders about list directionality within bins */ + +#define first(b) ((b)->fd) +#define last(b) ((b)->bk) + +/* + Take a chunk off a bin list +*/ + +#define unlink(P, BK, FD) { \ + FD = P->fd; \ + BK = P->bk; \ + FD->bk = BK; \ + BK->fd = FD; \ +} + +/* + Indexing bins + + Bins for sizes < 512 bytes contain chunks of all the same size, spaced + 8 bytes apart. Larger bins are approximately logarithmically spaced: + + 64 bins of size 8 + 32 bins of size 64 + 16 bins of size 512 + 8 bins of size 4096 + 4 bins of size 32768 + 2 bins of size 262144 + 1 bin of size what's left + + There is actually a little bit of slop in the numbers in bin_index + for the sake of speed. This makes no difference elsewhere. + + The bins top out at around 1mb because we expect to service large + chunks via mmap. + +*/ + +/* The first NSMALLBIN bins (and fastbins) hold only one size */ +#define NSMALLBINS 64 +#define SMALLBIN_WIDTH 8 +#define MIN_LARGE_SIZE 512 + +#define in_smallbin_range(sz) ((sz) < MIN_LARGE_SIZE) + +#define smallbin_index(sz) (((unsigned)(sz)) >> 3) + +#define largebin_index(sz) \ +(((((unsigned long)(sz)) >> 6) <= 32)? 56 + (((unsigned long)(sz)) >> 6): \ + ((((unsigned long)(sz)) >> 9) <= 20)? 91 + (((unsigned long)(sz)) >> 9): \ + ((((unsigned long)(sz)) >> 12) <= 10)? 110 + (((unsigned long)(sz)) >> 12): \ + ((((unsigned long)(sz)) >> 15) <= 4)? 119 + (((unsigned long)(sz)) >> 15): \ + ((((unsigned long)(sz)) >> 18) <= 2)? 124 + (((unsigned long)(sz)) >> 18): \ + 126) + +#define bin_index(sz) \ + ((in_smallbin_range(sz)) ? smallbin_index(sz) : largebin_index(sz)) + + +/* + Unsorted chunks + + All remainders from chunk splits, as well as all returned chunks, + are first placed in the "unsorted" bin. They are then placed + in regular bins after malloc gives them ONE chance to be used before + binning. So, basically, the unsorted_chunks list acts as a queue, + with chunks being placed on it in free (and malloc_consolidate), + and taken off (to be either used or placed in bins) in malloc. + +*/ + + +/* The otherwise unindexable 1-bin is used to hold unsorted chunks. */ + +#define unsorted_chunks(M) (bin_at(M, 1)) + + +/* + Top + + The top-most available chunk (i.e., the one bordering the end of + available memory) is treated specially. It is never included in + any bin, is used only if no other chunk is available, and is + released back to the system if it is very large (see + M_TRIM_THRESHOLD). `top' is never properly linked to its bin + since it is always handled specially. Because top initially + points to its own bin with initial zero size, thus forcing + extension on the first malloc request, we avoid having any special + code in malloc to check whether it even exists yet. But we still + need to do so when getting memory from system, so we make + initial_top treat the bin as a legal but unusable chunk during the + interval between initialization and the first call to + sYSMALLOc. (This is somewhat delicate, since it relies on + the 2 preceding words to be zero during this interval as well.) +*/ + + +/* Conveniently, the unsorted bin can be used as dummy top on first call */ +#define initial_top(M) (unsorted_chunks(M)) + +/* + Binmap + + To help compensate for the large number of bins, a one-level index + structure is used for bin-by-bin searching. `binmap' is a + bitvector recording whether bins are definitely empty so they can + be skipped over during during traversals. The bits are NOT always + cleared as soon as bins are empty, but instead only + when they are noticed to be empty during traversal in malloc. + +*/ + +/* Conservatively use 32 bits per map word, even if on 64bit system */ +#define BINMAPSHIFT 5 +#define BITSPERMAP (1U << BINMAPSHIFT) +#define BINMAPSIZE (NBINS / BITSPERMAP) + +#define idx2block(i) ((i) >> BINMAPSHIFT) +#define idx2bit(i) ((1U << ((i) & ((1U << BINMAPSHIFT)-1)))) + +#define mark_bin(m,i) ((m)->binmap[idx2block(i)] |= idx2bit(i)) +#define unmark_bin(m,i) ((m)->binmap[idx2block(i)] &= ~(idx2bit(i))) +#define get_binmap(m,i) ((m)->binmap[idx2block(i)] & idx2bit(i)) + + +/* + Fastbins + + An array of lists holding recently freed small chunks. Fastbins + are not doubly linked. It is faster to single-link them, and + since chunks are never removed from the middles of these lists, + double linking is not necessary. + + Chunks in fastbins keep their inuse bit set, so they cannot + be consolidated with other free chunks. malloc_consolidate + releases all chunks in fastbins and consolidates them with + other free chunks. +*/ + +typedef struct malloc_chunk* mfastbinptr; + +/* offset 2 to use otherwise unindexable first 2 bins */ +#define fastbin_index(sz) ((((unsigned int)(sz)) >> 3) - 2) + +/* The maximum fastbin request size we support */ +#define MAX_FAST_SIZE 80 + +#define NFASTBINS (fastbin_index(request2size(MAX_FAST_SIZE))+1) + + + +/* + Flag bit held in max_fast indicating that there probably are some + fastbin chunks . It is set true on entering a chunk into any fastbin, + and cleared only in malloc_consolidate. + + The truth value is inverted so that have_fastchunks will be true + upon startup (since statics are zero-filled). +*/ + + +#define have_fastchunks(M) (((M)->max_fast & 1U) == 0) +#define clear_fastchunks(M) ((M)->max_fast |= 1U) +#define set_fastchunks(M) ((M)->max_fast &= ~1U) + +/* + Initialization value of max_fast. + Use impossibly small value if 0. + Value also has flag bit clear. +*/ +#define req2max_fast(s) (((((s) == 0)? SMALLBIN_WIDTH: request2size(s))) | 1U) + + +/* + NONCONTIGUOUS_REGIONS is a special value for sbrk_base indicating that + MORECORE does not return contiguous regions. In this case, we do not check + or assume that the address of each chunk is at least sbrk_base. Otherwise, + contiguity is exploited in merging together, when possible, results + from consecutive MORECORE calls. + + The possible values for sbrk_base are: + MORECORE_FAILURE: + MORECORE has not yet been called, but we expect contiguous space + NONCONTIGUOUS_REGIONS: + we don't expect or rely on contiguous space + any other legal address: + the first address returned by MORECORE when contiguous +*/ + +#define NONCONTIGUOUS_REGIONS ((char*)(-3)) + + +/* + ----------- Internal state representation and initialization ----------- +*/ + + +struct malloc_state { + + /* The maximum chunk size to be eligible for fastbin */ + INTERNAL_SIZE_T max_fast; /* low bit used as fastbin flag */ + + /* Base of the topmost chunk -- not otherwise kept in a bin */ + mchunkptr top; + + /* The remainder from the most recent split of a small request */ + mchunkptr last_remainder; + + /* Fastbins */ + mfastbinptr fastbins[NFASTBINS]; + + /* Normal bins packed as described above */ + mchunkptr bins[NBINS * 2]; + + /* Bitmap of bins */ + unsigned int binmap[BINMAPSIZE]; + + /* Tunable parameters */ + unsigned long trim_threshold; + INTERNAL_SIZE_T top_pad; + INTERNAL_SIZE_T mmap_threshold; + + /* Memory map support */ + int n_mmaps; + int n_mmaps_max; + int max_n_mmaps; + + /* Bookkeeping for sbrk */ + unsigned int pagesize; /* Cache malloc_getpagesize */ + char* sbrk_base; /* first address returned by sbrk, + or NONCONTIGUOUS_REGIONS */ + /* Statistics */ + + INTERNAL_SIZE_T mmapped_mem; + INTERNAL_SIZE_T sbrked_mem; + + INTERNAL_SIZE_T max_sbrked_mem; + INTERNAL_SIZE_T max_mmapped_mem; + INTERNAL_SIZE_T max_total_mem; +}; + +typedef struct malloc_state *mstate; + +/* + There is exactly one instance of this struct in this malloc. + + If you are adapting this malloc in a way that does NOT use a static + malloc_state, you MUST explicitly zero-fill it before using. This + malloc relies on the property that malloc_state is initialized to + all zeroes (as is true of C statics). + +*/ + +static struct malloc_state av_; /* never directly referenced */ + +/* + All uses of av_ are via get_malloc_state(). + This simplifies construction of multithreaded, etc extensions. + + At most one call to get_malloc_state is made per invocation of + the public versions of malloc, free, and all other routines + except realloc, valloc, and vpalloc. Also, it is called + in check* routines if DEBUG is set. +*/ + +#define get_malloc_state() (&(av_)) + +/* + Initialize a malloc_state struct. + + This is called only from within malloc_consolidate, which needs + be called in the same contexts anyway. It is never called directly + outside of malloc_consolidate because some optimizing compilers try + to inline it at all call points, which turns out not to be an + optimization at all. (Inlining it only in malloc_consolidate is fine though.) +*/ + +#if __STD_C +static void malloc_init_state(mstate av) +#else +static void malloc_init_state(av) mstate av; +#endif +{ + int i; + mbinptr bin; + + + /* Uncomment this if you are not using a static av */ + /* MALLOC_ZERO(av, sizeof(struct malloc_state); */ + + /* Establish circular links for normal bins */ + for (i = 1; i < NBINS; ++i) { + bin = bin_at(av,i); + bin->fd = bin->bk = bin; + } + + av->max_fast = req2max_fast(DEFAULT_MXFAST); + + av->top_pad = DEFAULT_TOP_PAD; + av->n_mmaps_max = DEFAULT_MMAP_MAX; + av->mmap_threshold = DEFAULT_MMAP_THRESHOLD; + +#if MORECORE_CONTIGUOUS + av->trim_threshold = DEFAULT_TRIM_THRESHOLD; + av->sbrk_base = (char*)MORECORE_FAILURE; +#else + av->trim_threshold = (unsigned long)(-1); + av->sbrk_base = NONCONTIGUOUS_REGIONS; +#endif + + av->top = initial_top(av); + av->pagesize = malloc_getpagesize; +} + +/* + Other internal utilities operating on mstates +*/ + +#if __STD_C +static Void_t* sYSMALLOc(INTERNAL_SIZE_T, mstate); +static int sYSTRIm(size_t, mstate); +static void malloc_consolidate(mstate); +#else +static Void_t* sYSMALLOc(); +static int sYSTRIm(); +static void malloc_consolidate(); +#endif + + +/* + Debugging support + + These routines make a number of assertions about the states + of data structures that should be true at all times. If any + are not true, it's very likely that a user program has somehow + trashed memory. (It's also possible that there is a coding error + in malloc. In which case, please report it!) + +*/ + +#if ! DEBUG + +#define check_chunk(P) +#define check_free_chunk(P) +#define check_inuse_chunk(P) +#define check_remalloced_chunk(P,N) +#define check_malloced_chunk(P,N) +#define check_malloc_state() + +#else +#define check_chunk(P) do_check_chunk(P) +#define check_free_chunk(P) do_check_free_chunk(P) +#define check_inuse_chunk(P) do_check_inuse_chunk(P) +#define check_remalloced_chunk(P,N) do_check_remalloced_chunk(P,N) +#define check_malloced_chunk(P,N) do_check_malloced_chunk(P,N) +#define check_malloc_state() do_check_malloc_state() + + +/* + Properties of all chunks +*/ + +#if __STD_C +static void do_check_chunk(mchunkptr p) +#else +static void do_check_chunk(p) mchunkptr p; +#endif +{ + + mstate av = get_malloc_state(); + unsigned long sz = chunksize(p); + + if (!chunk_is_mmapped(p)) { + + /* Has legal address ... */ + if (av->sbrk_base != NONCONTIGUOUS_REGIONS) { + assert(((char*)p) >= ((char*)(av->sbrk_base))); + } + + if (p != av->top) { + if (av->sbrk_base != NONCONTIGUOUS_REGIONS) { + assert(((char*)p + sz) <= ((char*)(av->top))); + } + } + else { + if (av->sbrk_base != NONCONTIGUOUS_REGIONS) { + assert(((char*)p + sz) <= ((char*)(av->sbrk_base) + av->sbrked_mem)); + } + /* top size is always at least MINSIZE */ + assert((long)(sz) >= (long)(MINSIZE)); + /* top predecessor always marked inuse */ + assert(prev_inuse(p)); + } + + } + else { +#if HAVE_MMAP + /* address is outside main heap */ + /* unless mmap has been used as sbrk backup */ + if (av->sbrk_base != NONCONTIGUOUS_REGIONS) { + assert(! (((char*)p) >= ((char*)av->sbrk_base) && + ((char*)p) < ((char*)(av->sbrk_base) + av->sbrked_mem))); + } + /* chunk is page-aligned */ + assert(((p->prev_size + sz) & (av->pagesize-1)) == 0); + /* mem is aligned */ + assert(aligned_OK(chunk2mem(p))); +#else + /* force an appropriate assert violation if debug set */ + assert(!chunk_is_mmapped(p)); +#endif + } + +} + +/* + Properties of free chunks +*/ + + +#if __STD_C +static void do_check_free_chunk(mchunkptr p) +#else +static void do_check_free_chunk(p) mchunkptr p; +#endif +{ + mstate av = get_malloc_state(); + + INTERNAL_SIZE_T sz = p->size & ~PREV_INUSE; + mchunkptr next = chunk_at_offset(p, sz); + + do_check_chunk(p); + + /* Chunk must claim to be free ... */ + assert(!inuse(p)); + assert (!chunk_is_mmapped(p)); + + /* Unless a special marker, must have OK fields */ + if ((unsigned long)sz >= (unsigned long)MINSIZE) + { + assert((sz & MALLOC_ALIGN_MASK) == 0); + assert(aligned_OK(chunk2mem(p))); + /* ... matching footer field */ + assert(next->prev_size == sz); + /* ... and is fully consolidated */ + assert(prev_inuse(p)); + assert (next == av->top || inuse(next)); + + /* ... and has minimally sane links */ + assert(p->fd->bk == p); + assert(p->bk->fd == p); + } + else /* markers are always of size SIZE_SZ */ + assert(sz == SIZE_SZ); +} + +/* + Properties of inuse chunks +*/ + + +#if __STD_C +static void do_check_inuse_chunk(mchunkptr p) +#else +static void do_check_inuse_chunk(p) mchunkptr p; +#endif +{ + mstate av = get_malloc_state(); + mchunkptr next; + do_check_chunk(p); + + if (chunk_is_mmapped(p)) + return; /* mmapped chunks have no next/prev */ + + /* Check whether it claims to be in use ... */ + assert(inuse(p)); + + next = next_chunk(p); + + /* ... and is surrounded by OK chunks. + Since more things can be checked with free chunks than inuse ones, + if an inuse chunk borders them and debug is on, it's worth doing them. + */ + if (!prev_inuse(p)) { + /* Note that we cannot even look at prev unless it is not inuse */ + mchunkptr prv = prev_chunk(p); + assert(next_chunk(prv) == p); + do_check_free_chunk(prv); + } + + if (next == av->top) { + assert(prev_inuse(next)); + assert(chunksize(next) >= MINSIZE); + } + else if (!inuse(next)) + do_check_free_chunk(next); + +} + +/* + Properties of chunks recycled from fastbins +*/ + +#if __STD_C +static void do_check_remalloced_chunk(mchunkptr p, INTERNAL_SIZE_T s) +#else +static void do_check_remalloced_chunk(p, s) mchunkptr p; INTERNAL_SIZE_T s; +#endif +{ + + INTERNAL_SIZE_T sz = p->size & ~PREV_INUSE; + + do_check_inuse_chunk(p); + + /* Legal size ... */ + assert((sz & MALLOC_ALIGN_MASK) == 0); + assert((long)sz - (long)MINSIZE >= 0); + assert((long)sz - (long)s >= 0); + assert((long)sz - (long)(s + MINSIZE) < 0); + + /* ... and alignment */ + assert(aligned_OK(chunk2mem(p))); + +} + +/* + Properties of nonrecycled chunks at the point they are malloced +*/ + +#if __STD_C +static void do_check_malloced_chunk(mchunkptr p, INTERNAL_SIZE_T s) +#else +static void do_check_malloced_chunk(p, s) mchunkptr p; INTERNAL_SIZE_T s; +#endif +{ + /* same as recycled case ... */ + do_check_remalloced_chunk(p, s); + + /* + ... plus, must obey implementation invariant that prev_inuse is + always true of any allocated chunk; i.e., that each allocated + chunk borders either a previously allocated and still in-use + chunk, or the base of its memory arena. This is ensured + by making all allocations from the the `lowest' part of any found + chunk. This does not necessarily hold however for chunks + recycled via fastbins. + */ + + assert(prev_inuse(p)); +} + + +/* + Properties of malloc_state. + + This may be useful for debugging malloc, as well as detecting user + programmer errors that somehow write into malloc_state. +*/ + +static void do_check_malloc_state() +{ + mstate av = get_malloc_state(); + int i; + mchunkptr p; + mchunkptr q; + mbinptr b; + unsigned int biton; + int empty; + unsigned int idx; + INTERNAL_SIZE_T size; + unsigned long total = 0; + int max_fast_bin; + + + /* internal size_t must be no wider than pointer type */ + assert(sizeof(INTERNAL_SIZE_T) <= sizeof(char*)); + + /* alignment is a power of 2 */ + assert((MALLOC_ALIGNMENT & (MALLOC_ALIGNMENT-1)) == 0); + + /* cannot run remaining checks until fully initialized */ + if (av->top == 0 || av->top == initial_top(av)) + return; + + /* pagesize is a power of 2 */ + assert((av->pagesize & (av->pagesize-1)) == 0); + + /* properties of fastbins */ + + /* max_fast is in allowed range */ + + assert((av->max_fast & ~1) <= request2size(MAX_FAST_SIZE)); + + max_fast_bin = fastbin_index(av->max_fast); + + for (i = 0; i < NFASTBINS; ++i) { + p = av->fastbins[i]; + + /* all bins past max_fast are empty */ + if (i > max_fast_bin) + assert(p == 0); + + while (p != 0) { + /* each chunk claims to be inuse */ + do_check_inuse_chunk(p); + total += chunksize(p); + /* chunk belongs in this bin */ + assert(fastbin_index(chunksize(p)) == i); + p = p->fd; + } + } + + if (total != 0) + assert(have_fastchunks(av)); + + /* check normal bins */ + for (i = 1; i < NBINS; ++i) { + b = bin_at(av,i); + + /* binmap is accurate (except for bin 1 == unsorted_chunks) */ + if (i >= 2) { + biton = get_binmap(av,i); + empty = last(b) == b; + if (!biton) + assert(empty); + else if (!empty) + assert(biton); + } + + for (p = last(b); p != b; p = p->bk) { + /* each chunk claims to be free */ + do_check_free_chunk(p); + size = chunksize(p); + total += size; + if (i >= 2) { + /* chunk belongs in bin */ + idx = bin_index(size); + assert(idx == i); + /* lists are sorted */ + assert(p->bk == b || chunksize(p->bk) >= chunksize(p)); + } + /* chunk is followed by a legal chain of inuse chunks */ + for (q = next_chunk(p); + q != av->top && inuse(q) && (long)(chunksize(q)) >= (long)MINSIZE; + q = next_chunk(q)) + do_check_inuse_chunk(q); + + } + } + + /* top chunk is OK */ + check_chunk(av->top); + + /* sanity checks for statistics */ + + assert(total <= (unsigned long)(av->max_total_mem)); + assert(av->n_mmaps >= 0); + assert(av->n_mmaps <= av->n_mmaps_max); + assert(av->n_mmaps <= av->max_n_mmaps); + assert(av->max_n_mmaps <= av->n_mmaps_max); + + assert((unsigned long)(av->sbrked_mem) <= + (unsigned long)(av->max_sbrked_mem)); + + assert((unsigned long)(av->mmapped_mem) <= + (unsigned long)(av->max_mmapped_mem)); + + assert((unsigned long)(av->max_total_mem) >= + (unsigned long)(av->mmapped_mem) + (unsigned long)(av->sbrked_mem)); + +} + + +#endif + + + + + +/* ----------- Routines dealing with system allocation -------------- */ + +/* + Handle malloc cases requiring more memory from system. + malloc relays to sYSMALLOc if it cannot allocate out of + existing memory. + + On entry, it is assumed that av->top does not have enough + space to service request for nb bytes, thus requiring more meory + from system. +*/ + +#if __STD_C +static Void_t* sYSMALLOc(INTERNAL_SIZE_T nb, mstate av) +#else +static Void_t* sYSMALLOc(nb, av) INTERNAL_SIZE_T nb; mstate av; +#endif +{ + mchunkptr old_top; /* incoming value of av->top */ + INTERNAL_SIZE_T old_size; /* its size */ + char* old_end; /* its end address */ + + long size; /* arg to first MORECORE or mmap call */ + char* brk; /* return value from MORECORE */ + char* mm; /* return value from mmap call*/ + + long correction; /* arg to 2nd MORECORE call */ + char* snd_brk; /* 2nd return val */ + + INTERNAL_SIZE_T front_misalign; /* unusable bytes at front of new space */ + INTERNAL_SIZE_T end_misalign; /* partial page left at end of new space */ + char* aligned_brk; /* aligned offset into brk */ + + mchunkptr p; /* the allocated/returned chunk */ + mchunkptr remainder; /* remainder from allocation */ + long remainder_size; /* its size */ + + unsigned long sum; /* for updating stats */ + + size_t pagemask = av->pagesize - 1; + + /* + If have mmap, and the request size meets the mmap threshold, and + the system supports mmap, and there are few enough currently + allocated mmapped regions, and a call to mmap succeeds, try to + directly map this request rather than expanding top. + */ + +#if HAVE_MMAP + if ((unsigned long)nb >= (unsigned long)(av->mmap_threshold) && + (av->n_mmaps < av->n_mmaps_max)) { + + /* + Round up size to nearest page. For mmapped chunks, the overhead + is one SIZE_SZ unit larger than for normal chunks, because there + is no following chunk whose prev_size field could be used. + */ + size = (nb + SIZE_SZ + MALLOC_ALIGN_MASK + pagemask) & ~pagemask; + + mm = (char*)(MMAP(0, size, PROT_READ|PROT_WRITE, MAP_PRIVATE)); + + if (mm != (char*)(MORECORE_FAILURE)) { + + /* + The offset to the start of the mmapped region is stored + in the prev_size field of the chunk. This allows us to adjust + returned start address to meet alignment requirements here + and in memalign(), and still be able to compute proper + address argument for later munmap in free() and realloc(). + */ + + front_misalign = (INTERNAL_SIZE_T)chunk2mem(mm) & MALLOC_ALIGN_MASK; + if (front_misalign > 0) { + correction = MALLOC_ALIGNMENT - front_misalign; + p = (mchunkptr)(mm + correction); + p->prev_size = correction; + set_head(p, (size - correction) |IS_MMAPPED); + } + else { + p = (mchunkptr)mm; + set_head(p, size|IS_MMAPPED); + } + + check_chunk(p); + + /* update statistics */ + + if (++av->n_mmaps > av->max_n_mmaps) + av->max_n_mmaps = av->n_mmaps; + + sum = av->mmapped_mem += size; + if (sum > (unsigned long)(av->max_mmapped_mem)) + av->max_mmapped_mem = sum; + sum += av->sbrked_mem; + if (sum > (unsigned long)(av->max_total_mem)) + av->max_total_mem = sum; + + return chunk2mem(p); + } + } +#endif + + /* record incoming configuration of top */ + + old_top = av->top; + old_size = chunksize(old_top); + old_end = (char*)(chunk_at_offset(old_top, old_size)); + + brk = snd_brk = (char*)(MORECORE_FAILURE); + + /* + If not the first time through, we require old_size to be + at least MINSIZE and to have prev_inuse set. + */ + + assert(old_top == initial_top(av) || + ((unsigned long) (old_size) >= (unsigned long)(MINSIZE) && + prev_inuse(old_top))); + + + /* Request enough space for nb + pad + overhead */ + + size = nb + av->top_pad + MINSIZE; + + /* + If contiguous, we can subtract out existing space that we hope to + combine with new space. We add it back later only if + we don't actually get contiguous space. + */ + + if (av->sbrk_base != NONCONTIGUOUS_REGIONS) + size -= old_size; + + /* + Round to a multiple of page size. + If MORECORE is not contiguous, this ensures that we only call it + with whole-page arguments. And if MORECORE is contiguous and + this is not first time through, this preserves page-alignment of + previous calls. Otherwise, we re-correct anyway to page-align below. + */ + + size = (size + pagemask) & ~pagemask; + + /* + Don't try to call MORECORE if argument is so big as to appear + negative. Note that since mmap takes size_t arg, it may succeed + below even if we cannot call MORECORE. + */ + + if (size > 0) + brk = (char*)(MORECORE(size)); + + /* + If have mmap, try using it as a backup when MORECORE fails. This + is worth doing on systems that have "holes" in address space, so + sbrk cannot extend to give contiguous space, but space is available + elsewhere. Note that we ignore mmap max count and threshold limits, + since there is no reason to artificially limit use here. + */ + +#if HAVE_MMAP + if (brk == (char*)(MORECORE_FAILURE)) { + + /* Cannot merge with old top, so add its size back in */ + + if (av->sbrk_base != NONCONTIGUOUS_REGIONS) + size = (size + old_size + pagemask) & ~pagemask; + + /* If we are relying on mmap as backup, then use larger units */ + + if ((unsigned long)size < (unsigned long)MMAP_AS_MORECORE_SIZE) + size = MMAP_AS_MORECORE_SIZE; + + brk = (char*)(MMAP(0, size, PROT_READ|PROT_WRITE, MAP_PRIVATE)); + + if (brk != (char*)(MORECORE_FAILURE)) { + + /* We do not need, and cannot use, another sbrk call to find end */ + snd_brk = brk + size; + + /* + Record that we no longer have a contiguous sbrk region. + After the first time mmap is used as backup, we cannot + ever rely on contiguous space. + */ + av->sbrk_base = NONCONTIGUOUS_REGIONS; + } + } +#endif + + if (brk != (char*)(MORECORE_FAILURE)) { + + av->sbrked_mem += size; + + /* + If MORECORE extends previous space, we can likewise extend top size. + */ + + if (brk == old_end && snd_brk == (char*)(MORECORE_FAILURE)) { + set_head(old_top, (size + old_size) | PREV_INUSE); + } + + /* + Otherwise, make adjustments guided by the special values of + av->sbrk_base (MORECORE_FAILURE or NONCONTIGUOUS_REGIONS): + + * If the first time through or noncontiguous, we need to call sbrk + just to find out where the end of memory lies. + + * We need to ensure that all returned chunks from malloc will meet + MALLOC_ALIGNMENT + + * If there was an intervening foreign sbrk, we need to adjust sbrk + request size to account for fact that we will not be able to + combine new space with existing space in old_top. + + * Almost all systems internally allocate whole pages at a time, in + which case we might as well use the whole last page of request. + So we allocate enough more memory to hit a page boundary now, + which in turn causes future contiguous calls to page-align. + + */ + + else { + front_misalign = 0; + end_misalign = 0; + correction = 0; + aligned_brk = brk; + + /* handle contiguous cases */ + if (av->sbrk_base != NONCONTIGUOUS_REGIONS) { + + /* Guarantee alignment of first new chunk made from this space */ + + front_misalign = (INTERNAL_SIZE_T)chunk2mem(brk) & MALLOC_ALIGN_MASK; + if (front_misalign > 0) { + + /* + Skip over some bytes to arrive at an aligned position. + We don't need to specially mark these wasted front bytes. + They will never be accessed anyway because + prev_inuse of av->top (and any chunk created from its start) + is always true after initialization. + */ + + correction = MALLOC_ALIGNMENT - front_misalign; + aligned_brk += correction; + } + + /* + If this isn't adjacent to a previous sbrk, then we will not + be able to merge with old_top space, so must add to 2nd request. + */ + + correction += old_size; + + /* Pad out to hit a page boundary */ + + end_misalign = (INTERNAL_SIZE_T)(brk + size + correction); + correction += ((end_misalign + pagemask) & ~pagemask) - end_misalign; + + assert(correction >= 0); + + snd_brk = (char*)(MORECORE(correction)); + + /* + If can't allocate correction, try to at least find out current + brk. It might be enough to proceed without failing. + + Note that if second sbrk did NOT fail, we assume that space + is contiguous with first sbrk. This is a safe assumption unless + program is multithreaded but doesn't use locks and a foreign sbrk + occurred between our first and second calls. + */ + + if (snd_brk == (char*)(MORECORE_FAILURE)) { + correction = 0; + snd_brk = (char*)(MORECORE(0)); + } + } + + /* handle non-contiguous cases */ + else { + + /* MORECORE/mmap must correctly align etc */ + assert(((unsigned long)chunk2mem(brk) & MALLOC_ALIGN_MASK) == 0); + + /* Find out current end of memory */ + if (snd_brk == (char*)(MORECORE_FAILURE)) { + snd_brk = (char*)(MORECORE(0)); + } + + /* This must lie on a page boundary */ + if (snd_brk != (char*)(MORECORE_FAILURE)) { + assert(((INTERNAL_SIZE_T)(snd_brk) & pagemask) == 0); + } + } + + /* Adjust top based on results of second sbrk */ + if (snd_brk != (char*)(MORECORE_FAILURE)) { + + av->top = (mchunkptr)aligned_brk; + set_head(av->top, (snd_brk - aligned_brk + correction) | PREV_INUSE); + + av->sbrked_mem += correction; + + /* If first time through and contiguous, record base */ + if (old_top == initial_top(av)) { + if (av->sbrk_base == (char*)(MORECORE_FAILURE)) + av->sbrk_base = brk; + } + + /* + Otherwise, we either have a gap due to foreign sbrk or a + non-contiguous region. Insert a double fencepost at old_top + to prevent consolidation with space we don't own. These + fenceposts are artificial chunks that are marked as inuse + and are in any case too small to use. We need two to make + sizes and alignments work out. + */ + + else { + + /* + Shrink old_top to insert fenceposts, keeping size a + multiple of MALLOC_ALIGNMENT. + */ + old_size = (old_size - 3*SIZE_SZ) & ~MALLOC_ALIGN_MASK; + set_head(old_top, old_size | PREV_INUSE); + + /* + Note that the following assignments overwrite old_top when + old_size was previously MINSIZE. This is intentional. We + need the fencepost, even if old_top otherwise gets lost. + */ + chunk_at_offset(old_top, old_size )->size = + SIZE_SZ|PREV_INUSE; + + chunk_at_offset(old_top, old_size + SIZE_SZ)->size = + SIZE_SZ|PREV_INUSE; + + /* If possible, release the rest. */ + if (old_size >= MINSIZE) + fREe(chunk2mem(old_top)); + + } + } + } + + /* Update statistics */ + + sum = av->sbrked_mem; + if (sum > (unsigned long)(av->max_sbrked_mem)) + av->max_sbrked_mem = sum; + + sum += av->mmapped_mem; + if (sum > (unsigned long)(av->max_total_mem)) + av->max_total_mem = sum; + + check_malloc_state(); + + /* finally, do the allocation */ + + p = av->top; + size = chunksize(p); + remainder_size = (long)size - (long)nb; + + /* check that one of the above allocation paths succeeded */ + if (remainder_size >= (long)MINSIZE) { + remainder = chunk_at_offset(p, nb); + av->top = remainder; + set_head(p, nb | PREV_INUSE); + set_head(remainder, remainder_size | PREV_INUSE); + + check_malloced_chunk(p, nb); + return chunk2mem(p); + } + } + + /* catch all failure paths */ + MALLOC_FAILURE_ACTION; + return 0; +} + + +/* + sYSTRIm is an inverse of sorts to sYSMALLOc. + It gives memory back to the system (via negative + arguments to sbrk) if there is unused memory at the `high' end of + the malloc pool. It is called automatically by free() + when top space exceeds the trim threshold. + returns 1 if it actually released any memory, else 0. +*/ + +#if __STD_C +static int sYSTRIm(size_t pad, mstate av) +#else +static int sYSTRIm(pad, av) size_t pad; mstate av; +#endif +{ + long top_size; /* Amount of top-most memory */ + long extra; /* Amount to release */ + long released; /* Amount actually released */ + char* current_brk; /* address returned by pre-check sbrk call */ + char* new_brk; /* address returned by post-check sbrk call */ + size_t pagesz; + + /* Don't bother trying if sbrk doesn't provide contiguous regions */ + if (av->sbrk_base != NONCONTIGUOUS_REGIONS) { + + pagesz = av->pagesize; + top_size = chunksize(av->top); + + /* Release in pagesize units, keeping at least one page */ + extra = ((top_size - pad - MINSIZE + (pagesz-1)) / pagesz - 1) * pagesz; + + if (extra > 0) { + + /* + Only proceed if end of memory is where we last set it. + This avoids problems if there were foreign sbrk calls. + */ + current_brk = (char*)(MORECORE(0)); + if (current_brk == (char*)(av->top) + top_size) { + + /* + Attempt to release memory. We ignore return value, + and instead call again to find out where new end of memory is. + This avoids problems if first call releases less than we asked, + of if failure somehow altered brk value. (We could still + encounter problems if it altered brk in some very bad way, + but the only thing we can do is adjust anyway, which will cause + some downstream failure.) + */ + + MORECORE(-extra); + new_brk = (char*)(MORECORE(0)); + + if (new_brk != (char*)MORECORE_FAILURE) { + released = (long)(current_brk - new_brk); + + if (released != 0) { + /* Success. Adjust top. */ + av->sbrked_mem -= released; + set_head(av->top, (top_size - released) | PREV_INUSE); + check_malloc_state(); + return 1; + } + } + } + } + } + + return 0; +} + +/* ----------------------- Main public routines ----------------------- */ + + +/* + Malloc routine. See running comments for algorithm description. +*/ + +#if __STD_C +Void_t* mALLOc(size_t bytes) +#else + Void_t* mALLOc(bytes) size_t bytes; +#endif +{ + mstate av = get_malloc_state(); + + INTERNAL_SIZE_T nb; /* normalized request size */ + unsigned int idx; /* associated bin index */ + mbinptr bin; /* associated bin */ + mfastbinptr* fb; /* associated fastbin */ + + mchunkptr victim; /* inspected/selected chunk */ + INTERNAL_SIZE_T size; /* its size */ + int victim_index; /* its bin index */ + + mchunkptr remainder; /* remainder from a split */ + long remainder_size; /* its size */ + + unsigned int block; /* bit map traverser */ + unsigned int bit; /* bit map traverser */ + unsigned int map; /* current word of binmap */ + + mchunkptr fwd; /* misc temp for linking */ + mchunkptr bck; /* misc temp for linking */ + + + /* + Check request for legality and convert to internal form, nb. + This rejects negative arguments when size_t is treated as + signed. It also rejects arguments that are so large that the size + appears negative when aligned and padded. The converted form + adds SIZE_T bytes overhead plus possibly more to obtain necessary + alignment and/or to obtain a size of at least MINSIZE, the + smallest allocatable size. + */ + + checked_request2size(bytes, nb); + + /* + If the size qualifies as a fastbin, first check corresponding bin. + This code is safe to execute even if av not yet initialized, so we + can try it first, which saves some time on this fast path. + */ + + if (nb <= av->max_fast) { + fb = &(av->fastbins[(fastbin_index(nb))]); + if ( (victim = *fb) != 0) { + *fb = victim->fd; + check_remalloced_chunk(victim, nb); + return chunk2mem(victim); + } + } + + /* + If a small request, check regular bin. Since these "smallbins" + hold one size each, no searching within bins is necessary. + + (If a large request, we need to wait until unsorted chunks are + processed to find best fit. But for small ones, fits are exact + anyway, so we can check now, which is faster.) + */ + + if (in_smallbin_range(nb)) { + idx = smallbin_index(nb); + bin = bin_at(av,idx); + + if ( (victim = last(bin)) != bin) { + if (victim == 0) /* initialization check */ + malloc_consolidate(av); + else { + bck = victim->bk; + set_inuse_bit_at_offset(victim, nb); + bin->bk = bck; + bck->fd = bin; + + check_malloced_chunk(victim, nb); + return chunk2mem(victim); + } + } + } + + /* + If a large request, consolidate fastbins before continuing. + While it might look excessive to kill all fastbins before + even seeing if there is space available, this avoids + fragmentation problems normally associated with fastbins. + Also, in practice, programs tend to have runs of either small or + large requests, but less often mixtures, so consolidation is not + usually invoked all that often. + */ + + else { + idx = largebin_index(nb); + if (have_fastchunks(av)) /* consolidation/initialization check */ + malloc_consolidate(av); + } + + + /* + Process recently freed or remaindered chunks, taking one only if + it is exact fit, or, if a small request, it is the remainder from + the most recent non-exact fit. Place other traversed chunks in + bins. Note that this step is the only place in any routine where + chunks are placed in bins. + + The outer loop here is needed because we might not realize until + near the end of malloc that we should have consolidated, so must + do so and retry. This happens at most once, and only when we would + otherwise need to expand memory to service a "small" request. + */ + + + for(;;) { + + while ( (victim = unsorted_chunks(av)->bk) != unsorted_chunks(av)) { + bck = victim->bk; + size = chunksize(victim); + + /* + If a small request, try to use last remainder if it is the + only chunk in unsorted bin. This helps promote locality for + runs of consecutive small requests. This is the only + exception to best-fit. + */ + + if (in_smallbin_range(nb) && + victim == av->last_remainder && + bck == unsorted_chunks(av) && + (remainder_size = (long)size - (long)nb) >= (long)MINSIZE) { + + /* split and reattach remainder */ + remainder = chunk_at_offset(victim, nb); + unsorted_chunks(av)->bk = unsorted_chunks(av)->fd = remainder; + av->last_remainder = remainder; + remainder->bk = remainder->fd = unsorted_chunks(av); + + set_head(victim, nb | PREV_INUSE); + set_head(remainder, remainder_size | PREV_INUSE); + set_foot(remainder, remainder_size); + + check_malloced_chunk(victim, nb); + return chunk2mem(victim); + } + + /* remove from unsorted list */ + unsorted_chunks(av)->bk = bck; + bck->fd = unsorted_chunks(av); + + /* Take now instead of binning if exact fit */ + + if (size == nb) { + set_inuse_bit_at_offset(victim, size); + check_malloced_chunk(victim, nb); + return chunk2mem(victim); + } + + /* place chunk in bin */ + + if (in_smallbin_range(size)) { + victim_index = smallbin_index(size); + bck = bin_at(av, victim_index); + fwd = bck->fd; + } + else { + victim_index = largebin_index(size); + bck = bin_at(av, victim_index); + fwd = bck->fd; + + /* maintain large bins in sorted order */ + if (fwd != bck) { + /* if smaller than smallest, bypass loop below */ + if ((unsigned long)size <= + (unsigned long)(chunksize(bck->bk))) { + fwd = bck; + bck = bck->bk; + } + else { + while (fwd != bck && + (unsigned long)size < (unsigned long)(chunksize(fwd))) { + fwd = fwd->fd; + } + bck = fwd->bk; + } + } + } + + mark_bin(av, victim_index); + victim->bk = bck; + victim->fd = fwd; + fwd->bk = victim; + bck->fd = victim; + } + + /* + If a large request, scan through the chunks of current bin in + sorted order to find smallest that fits. This is the only step + where an unbounded number of chunks might be scanned without doing + anything useful with them. However the lists tend to be very + short. + */ + + if (!in_smallbin_range(nb)) { + bin = bin_at(av, idx); + + /* skip scan if largest chunk is too small */ + if ((victim = last(bin)) != bin && + (long)(chunksize(first(bin))) - (long)(nb) >= 0) { + do { + size = chunksize(victim); + remainder_size = (long)size - (long)nb; + + if (remainder_size >= 0) { + unlink(victim, bck, fwd); + + /* Exhaust */ + if (remainder_size < (long)MINSIZE) { + set_inuse_bit_at_offset(victim, size); + check_malloced_chunk(victim, nb); + return chunk2mem(victim); + } + /* Split */ + else { + remainder = chunk_at_offset(victim, nb); + unsorted_chunks(av)->bk = unsorted_chunks(av)->fd = remainder; + remainder->bk = remainder->fd = unsorted_chunks(av); + set_head(victim, nb | PREV_INUSE); + set_head(remainder, remainder_size | PREV_INUSE); + set_foot(remainder, remainder_size); + check_malloced_chunk(victim, nb); + return chunk2mem(victim); + } + } + } while ( (victim = victim->bk) != bin); + } + } + + /* + Search for a chunk by scanning bins, starting with next largest + bin. This search is strictly by best-fit; i.e., the smallest + (with ties going to approximately the least recently used) chunk + that fits is selected. + + The bitmap avoids needing to check that most blocks are nonempty. + The particular case of skipping all bins during warm-up phases + when no chunks have been returned yet is faster than it might look. + */ + + ++idx; + bin = bin_at(av,idx); + block = idx2block(idx); + map = av->binmap[block]; + bit = idx2bit(idx); + + for (;;) { + /* + Skip rest of block if there are no more set bits in this block. + */ + + if (bit > map || bit == 0) { + for (;;) { + if (++block >= BINMAPSIZE) /* out of bins */ + break; + + else if ( (map = av->binmap[block]) != 0) { + bin = bin_at(av, (block << BINMAPSHIFT)); + bit = 1; + break; + } + } + /* Optimizers seem to like this double-break better than goto */ + if (block >= BINMAPSIZE) + break; + } + + /* Advance to bin with set bit. There must be one. */ + while ((bit & map) == 0) { + bin = next_bin(bin); + bit <<= 1; + } + + victim = last(bin); + + /* False alarm -- the bin is empty. Clear the bit. */ + if (victim == bin) { + av->binmap[block] = map &= ~bit; /* Write through */ + bin = next_bin(bin); + bit <<= 1; + } + + /* We know the first chunk in this bin is big enough to use. */ + else { + size = chunksize(victim); + remainder_size = (long)size - (long)nb; + + assert(remainder_size >= 0); + + /* unlink */ + bck = victim->bk; + bin->bk = bck; + bck->fd = bin; + + + /* Exhaust */ + if (remainder_size < (long)MINSIZE) { + set_inuse_bit_at_offset(victim, size); + check_malloced_chunk(victim, nb); + return chunk2mem(victim); + } + + /* Split */ + else { + remainder = chunk_at_offset(victim, nb); + + unsorted_chunks(av)->bk = unsorted_chunks(av)->fd = remainder; + remainder->bk = remainder->fd = unsorted_chunks(av); + /* advertise as last remainder */ + if (in_smallbin_range(nb)) + av->last_remainder = remainder; + + set_head(victim, nb | PREV_INUSE); + set_head(remainder, remainder_size | PREV_INUSE); + set_foot(remainder, remainder_size); + check_malloced_chunk(victim, nb); + return chunk2mem(victim); + } + } + } + + /* + If large enough, split off the chunk bordering the end of memory + ("top"). Note that this use of top is in accord with the best-fit search + rule. In effect, top is treated as larger (and thus less well + fitting) than any other available chunk since it can be extended + to be as large as necessary (up to system limitations). + + We require that "top" always exists (i.e., has size >= MINSIZE) + after initialization, so if it would otherwise be exhuasted by + current request, it is replenished. (Among the reasons for + ensuring it exists is that we may need MINSIZE space to put in + fenceposts in sysmalloc.) + */ + + victim = av->top; + size = chunksize(victim); + remainder_size = (long)size - (long)nb; + + if (remainder_size >= (long)MINSIZE) { + remainder = chunk_at_offset(victim, nb); + av->top = remainder; + set_head(victim, nb | PREV_INUSE); + set_head(remainder, remainder_size | PREV_INUSE); + + check_malloced_chunk(victim, nb); + return chunk2mem(victim); + } + + /* + If there is space available in fastbins, consolidate and retry, + to possibly avoid expanding memory. This can occur only if nb is + in smallbin range so we didn't consolidate upon entry. + */ + + else if (have_fastchunks(av)) { + assert(in_smallbin_range(nb)); + idx = smallbin_index(nb); /* restore original bin index */ + malloc_consolidate(av); + } + + /* + Otherwise, relay to handle system-dependent cases + */ + else + return sYSMALLOc(nb, av); + } +} + + + +/* + Free routine. See running comments for algorithm description. +*/ + +#if __STD_C +void fREe(Void_t* mem) +#else +void fREe(mem) Void_t* mem; +#endif +{ + mstate av = get_malloc_state(); + + mchunkptr p; /* chunk corresponding to mem */ + INTERNAL_SIZE_T size; /* its size */ + mfastbinptr* fb; /* associated fastbin */ + mchunkptr nextchunk; /* next contiguous chunk */ + INTERNAL_SIZE_T nextsize; /* its size */ + int nextinuse; /* true if nextchunk is used */ + INTERNAL_SIZE_T prevsize; /* size of previous contiguous chunk */ + mchunkptr bck; /* misc temp for linking */ + mchunkptr fwd; /* misc temp for linking */ + + + /* free(0) has no effect */ + if (mem != 0) { + + p = mem2chunk(mem); + check_inuse_chunk(p); + + size = chunksize(p); + + /* + If eligible, place chunk on a fastbin so it can be found + and used quickly in malloc. + */ + + if ((unsigned long)size <= (unsigned long)av->max_fast + +#if TRIM_FASTBINS + /* + If TRIM_FASTBINS set, don't place chunks + bordering top into fastbins + */ + && (chunk_at_offset(p, size) != av->top) +#endif + ) { + + set_fastchunks(av); + fb = &(av->fastbins[fastbin_index(size)]); + p->fd = *fb; + *fb = p; + } + + /* + Consolidate non-mmapped chunks as they arrive. + */ + + else if (!chunk_is_mmapped(p)) { + + nextchunk = chunk_at_offset(p, size); + + /* consolidate backward */ + if (!prev_inuse(p)) { + prevsize = p->prev_size; + size += prevsize; + p = chunk_at_offset(p, -((long) prevsize)); + unlink(p, bck, fwd); + } + + nextsize = chunksize(nextchunk); + + if (nextchunk != av->top) { + + /* get and clear inuse bit */ + nextinuse = inuse_bit_at_offset(nextchunk, nextsize); + set_head(nextchunk, nextsize); + + /* consolidate forward */ + if (!nextinuse) { + unlink(nextchunk, bck, fwd); + size += nextsize; + } + + /* + Place chunk in unsorted chunk list. Chunks are + not placed into regular bins until after they have + been given one chance to be used in malloc. + */ + + bck = unsorted_chunks(av); + fwd = bck->fd; + p->bk = bck; + p->fd = fwd; + bck->fd = p; + fwd->bk = p; + + set_head(p, size | PREV_INUSE); + set_foot(p, size); + } + + /* + If the chunk borders the current high end of memory, + consolidate into top + */ + + else { + size += nextsize; + set_head(p, size | PREV_INUSE); + av->top = p; + + /* + If the total unused topmost memory exceeds trim + threshold, ask malloc_trim to reduce top. + + Unless max_fast is 0, we don't know if there are fastbins + bordering top, so we cannot tell for sure whether threshold has + been reached unless fastbins are consolidated. But we don't + want to consolidate on each free. As a compromise, + consolidation is performed if half the threshold is + reached. + + */ + + if ((unsigned long)(size) > (unsigned long)(av->trim_threshold / 2)) { + if (have_fastchunks(av)) { + malloc_consolidate(av); + size = chunksize(av->top); + } + + if ((unsigned long)(size) > (unsigned long)(av->trim_threshold)) + sYSTRIm(av->top_pad, av); + } + } + } + + /* + If the chunk was allocated via mmap, release via munmap() + Note that if HAVE_MMAP is false but chunk_is_mmapped is + true, then user must have overwritten memory. There's nothing + we can do to catch this error unless DEBUG is set, in which case + check_inuse_chunk (above) will have triggered error. + */ + + else { +#if HAVE_MMAP + int ret; + INTERNAL_SIZE_T offset = p->prev_size; + av->n_mmaps--; + av->mmapped_mem -= (size + offset); + ret = munmap((char*)p - offset, size + offset); + /* munmap returns non-zero on failure */ + assert(ret == 0); +#endif + } + } +} + + + +/* + malloc_consolidate is a specialized version of free() that tears + down chunks held in fastbins. Free itself cannot be used for this + purpose since, among other things, it might place chunks back onto + fastbins. So, instead, we need to use a minor variant of the same + code. + + Also, because this routine needs to be called the first time through + malloc anyway, it turns out to be the perfect place to bury + initialization code. +*/ + +#if __STD_C +static void malloc_consolidate(mstate av) +#else +static void malloc_consolidate(av) mstate av; +#endif +{ + mfastbinptr* fb; + mfastbinptr* maxfb; + mchunkptr p; + mchunkptr nextp; + mchunkptr unsorted_bin; + mchunkptr first_unsorted; + + /* These have same use as in free() */ + mchunkptr nextchunk; + INTERNAL_SIZE_T size; + INTERNAL_SIZE_T nextsize; + INTERNAL_SIZE_T prevsize; + int nextinuse; + mchunkptr bck; + mchunkptr fwd; + + /* + If max_fast is 0, we know that malloc hasn't + yet been initialized, in which case do so. + */ + + if (av->max_fast == 0) { + malloc_init_state(av); + check_malloc_state(); + } + else if (have_fastchunks(av)) { + clear_fastchunks(av); + + unsorted_bin = unsorted_chunks(av); + + /* + Remove each chunk from fast bin and consolidate it, placing it + then in unsorted bin. Among other reasons for doing this, + placing in unsorted bin avoids needing to calculate actual bins + until malloc is sure that chunks aren't immediately going to be + reused anyway. + */ + + maxfb = &(av->fastbins[fastbin_index(av->max_fast)]); + fb = &(av->fastbins[0]); + do { + if ( (p = *fb) != 0) { + *fb = 0; + + do { + check_inuse_chunk(p); + nextp = p->fd; + + /* Slightly streamlined version of consolidation code in free() */ + size = p->size & ~PREV_INUSE; + nextchunk = chunk_at_offset(p, size); + + if (!prev_inuse(p)) { + prevsize = p->prev_size; + size += prevsize; + p = chunk_at_offset(p, -((long) prevsize)); + unlink(p, bck, fwd); + } + + nextsize = chunksize(nextchunk); + + if (nextchunk != av->top) { + + nextinuse = inuse_bit_at_offset(nextchunk, nextsize); + set_head(nextchunk, nextsize); + + if (!nextinuse) { + size += nextsize; + unlink(nextchunk, bck, fwd); + } + + first_unsorted = unsorted_bin->fd; + unsorted_bin->fd = p; + first_unsorted->bk = p; + + set_head(p, size | PREV_INUSE); + p->bk = unsorted_bin; + p->fd = first_unsorted; + set_foot(p, size); + } + + else { + size += nextsize; + set_head(p, size | PREV_INUSE); + av->top = p; + } + + } while ( (p = nextp) != 0); + + } + } while (fb++ != maxfb); + } +} + + + + +/* + Realloc algorithm cases: + + * Chunks that were obtained via mmap cannot be extended or shrunk + unless HAVE_MREMAP is defined, in which case mremap is used. + Otherwise, if the reallocation is for additional space, they are + copied. If for less, they are just left alone. + + * Otherwise, if the reallocation is for additional space, and the + chunk can be extended, it is, else a malloc-copy-free sequence is + taken. There are several different ways that a chunk could be + extended. All are tried: + + * Extending forward into following adjacent free chunk. + * Shifting backwards, joining preceding adjacent space + * Both shifting backwards and extending forward. + * Extending into newly sbrked space + + * If there is not enough memory available to realloc, realloc + returns null, but does NOT free the existing space. + + * If the reallocation is for less space, the newly unused space is + lopped off and freed. Unless the #define REALLOC_ZERO_BYTES_FREES + is set, realloc with a size argument of zero (re)allocates a + minimum-sized chunk. + + + The old unix realloc convention of allowing the last-free'd chunk + to be used as an argument to realloc is no longer supported. + I don't know of any programs still relying on this feature, + and allowing it would also allow too many other incorrect + usages of realloc to be sensible. +*/ + +#if __STD_C +Void_t* rEALLOc(Void_t* oldmem, size_t bytes) +#else +Void_t* rEALLOc(oldmem, bytes) Void_t* oldmem; size_t bytes; +#endif +{ + mstate av = get_malloc_state(); + + INTERNAL_SIZE_T nb; /* padded request size */ + + mchunkptr oldp; /* chunk corresponding to oldmem */ + INTERNAL_SIZE_T oldsize; /* its size */ + + mchunkptr newp; /* chunk to return */ + INTERNAL_SIZE_T newsize; /* its size */ + Void_t* newmem; /* corresponding user mem */ + + mchunkptr next; /* next contiguous chunk after oldp */ + mchunkptr prev; /* previous contiguous chunk before oldp */ + + mchunkptr remainder; /* extra space at end of newp */ + long remainder_size; /* its size */ + + mchunkptr bck; /* misc temp for linking */ + mchunkptr fwd; /* misc temp for linking */ + + INTERNAL_SIZE_T copysize; /* bytes to copy */ + int ncopies; /* INTERNAL_SIZE_T words to copy */ + INTERNAL_SIZE_T* s; /* copy source */ + INTERNAL_SIZE_T* d; /* copy destination */ + + +#ifdef REALLOC_ZERO_BYTES_FREES + if (bytes == 0) { + fREe(oldmem); + return 0; + } +#endif + + /* realloc of null is supposed to be same as malloc */ + if (oldmem == 0) return mALLOc(bytes); + + checked_request2size(bytes, nb); + + oldp = mem2chunk(oldmem); + oldsize = chunksize(oldp); + + check_inuse_chunk(oldp); + + if (!chunk_is_mmapped(oldp)) { + + if ((unsigned long)(oldsize) >= (unsigned long)(nb)) { + /* already big enough; split below */ + newp = oldp; + newsize = oldsize; + } + + else { + newp = 0; + newsize = 0; + + next = chunk_at_offset(oldp, oldsize); + + if (next == av->top) { /* Expand forward into top */ + newsize = oldsize + chunksize(next); + + if ((unsigned long)(newsize) >= (unsigned long)(nb + MINSIZE)) { + set_head_size(oldp, nb); + av->top = chunk_at_offset(oldp, nb); + set_head(av->top, (newsize - nb) | PREV_INUSE); + return chunk2mem(oldp); + } + + else if (!prev_inuse(oldp)) { /* Shift backwards + top */ + prev = prev_chunk(oldp); + newsize += chunksize(prev); + + if ((unsigned long)(newsize) >= (unsigned long)(nb + MINSIZE)) { + newp = prev; + unlink(prev, bck, fwd); + av->top = chunk_at_offset(newp, nb); + set_head(av->top, (newsize - nb) | PREV_INUSE); + newsize = nb; + } + } + } + + else if (!inuse(next)) { /* Forward into next chunk */ + newsize = oldsize + chunksize(next); + + if (((unsigned long)(newsize) >= (unsigned long)(nb))) { + newp = oldp; + unlink(next, bck, fwd); + } + + else if (!prev_inuse(oldp)) { /* Forward + backward */ + prev = prev_chunk(oldp); + newsize += chunksize(prev); + + if (((unsigned long)(newsize) >= (unsigned long)(nb))) { + newp = prev; + unlink(prev, bck, fwd); + unlink(next, bck, fwd); + } + } + } + + else if (!prev_inuse(oldp)) { /* Backward only */ + prev = prev_chunk(oldp); + newsize = oldsize + chunksize(prev); + + if ((unsigned long)(newsize) >= (unsigned long)(nb)) { + newp = prev; + unlink(prev, bck, fwd); + } + } + + if (newp != 0) { + if (newp != oldp) { + /* Backward copies are not worth unrolling */ + MALLOC_COPY(chunk2mem(newp), oldmem, oldsize - SIZE_SZ, 1); + } + } + + /* Must allocate */ + else { + newmem = mALLOc(nb - MALLOC_ALIGN_MASK); + if (newmem == 0) + return 0; /* propagate failure */ + + newp = mem2chunk(newmem); + newsize = chunksize(newp); + + /* + Avoid copy if newp is next chunk after oldp. + */ + if (newp == next) { + newsize += oldsize; + newp = oldp; + } + else { + + /* + Unroll copy of <= 36 bytes (72 if 8byte sizes) + We know that contents have an odd number of + INTERNAL_SIZE_T-sized words; minimally 3. + */ + + copysize = oldsize - SIZE_SZ; + s = (INTERNAL_SIZE_T*)oldmem; + d = (INTERNAL_SIZE_T*)(chunk2mem(newp)); + ncopies = copysize / sizeof(INTERNAL_SIZE_T); + assert(ncopies >= 3); + + if (ncopies > 9) + MALLOC_COPY(d, s, copysize, 0); + + else { + *(d+0) = *(s+0); + *(d+1) = *(s+1); + *(d+2) = *(s+2); + if (ncopies > 4) { + *(d+3) = *(s+3); + *(d+4) = *(s+4); + if (ncopies > 6) { + *(d+5) = *(s+5); + *(d+6) = *(s+6); + if (ncopies > 8) { + *(d+7) = *(s+7); + *(d+8) = *(s+8); + } + } + } + } + + fREe(oldmem); + check_inuse_chunk(newp); + return chunk2mem(newp); + } + } + } + + + /* If possible, free extra space in old or extended chunk */ + + remainder_size = (long)newsize - (long)nb; + assert(remainder_size >= 0); + + if (remainder_size >= (long)MINSIZE) { /* split remainder */ + remainder = chunk_at_offset(newp, nb); + set_head_size(newp, nb); + set_head(remainder, remainder_size | PREV_INUSE); + /* Mark remainder as inuse so free() won't complain */ + set_inuse_bit_at_offset(remainder, remainder_size); + fREe(chunk2mem(remainder)); + } + + else { /* not enough extra to split off */ + set_head_size(newp, newsize); + set_inuse_bit_at_offset(newp, newsize); + } + + check_inuse_chunk(newp); + return chunk2mem(newp); + } + + /* + Handle mmap cases + */ + + else { +#if HAVE_MMAP + +#if HAVE_MREMAP + INTERNAL_SIZE_T offset = oldp->prev_size; + size_t pagemask = av->pagesize - 1; + char *cp; + unsigned long sum; + + /* Note the extra SIZE_SZ overhead */ + newsize = (nb + offset + SIZE_SZ + pagemask) & ~pagemask; + + /* don't need to remap if still within same page */ + if (oldsize == newsize - offset) + return oldmem; + + cp = (char*)mremap((char*)oldp - offset, oldsize + offset, newsize, 1); + + if (cp != (char*)MORECORE_FAILURE) { + + newp = (mchunkptr)(cp + offset); + set_head(newp, (newsize - offset)|IS_MMAPPED); + + assert(aligned_OK(chunk2mem(newp))); + assert((newp->prev_size == offset)); + + /* update statistics */ + sum = av->mmapped_mem += newsize - oldsize; + if (sum > (unsigned long)(av->max_mmapped_mem)) + av->max_mmapped_mem = sum; + sum += av->sbrked_mem; + if (sum > (unsigned long)(av->max_total_mem)) + av->max_total_mem = sum; + + return chunk2mem(newp); + } + +#endif + + /* Note the extra SIZE_SZ overhead. */ + if ((long)oldsize - (long)SIZE_SZ >= (long)nb) + newmem = oldmem; /* do nothing */ + else { + /* Must alloc, copy, free. */ + newmem = mALLOc(nb - MALLOC_ALIGN_MASK); + if (newmem != 0) { + MALLOC_COPY(newmem, oldmem, oldsize - 2*SIZE_SZ, 0); + fREe(oldmem); + } + } + return newmem; + +#else + /* If !HAVE_MMAP, but chunk_is_mmapped, user must have overwritten mem */ + check_malloc_state(); + MALLOC_FAILURE_ACTION; + return 0; +#endif + } + +} + + + +/* + memalign requests more than enough space from malloc, finds a spot + within that chunk that meets the alignment request, and then + possibly frees the leading and trailing space. + + Alignments must be powers of two. If the argument is not a + power of two, the nearest greater power is used. + + 8-byte alignment is guaranteed by normal malloc calls, so don't + bother calling memalign with an argument of 8 or less. + + Overreliance on memalign is a sure way to fragment space. +*/ + + +#if __STD_C +Void_t* mEMALIGn(size_t alignment, size_t bytes) +#else +Void_t* mEMALIGn(alignment, bytes) size_t alignment; size_t bytes; +#endif +{ + INTERNAL_SIZE_T nb; /* padded request size */ + char* m; /* memory returned by malloc call */ + mchunkptr p; /* corresponding chunk */ + char* brk; /* alignment point within p */ + mchunkptr newp; /* chunk to return */ + INTERNAL_SIZE_T newsize; /* its size */ + INTERNAL_SIZE_T leadsize; /* leading space befor alignment point */ + mchunkptr remainder; /* spare room at end to split off */ + long remainder_size; /* its size */ + + + /* If need less alignment than we give anyway, just relay to malloc */ + + if (alignment <= MALLOC_ALIGNMENT) return mALLOc(bytes); + + /* Otherwise, ensure that it is at least a minimum chunk size */ + + if (alignment < MINSIZE) alignment = MINSIZE; + + /* Make sure alignment is power of 2 (in case MINSIZE is not). */ + if ((alignment & (alignment - 1)) != 0) { + size_t a = MALLOC_ALIGNMENT * 2; + while ((unsigned long)a < (unsigned long)alignment) a <<= 1; + alignment = a; + } + + checked_request2size(bytes, nb); + + /* Call malloc with worst case padding to hit alignment. */ + + m = (char*)(mALLOc(nb + alignment + MINSIZE)); + + if (m == 0) return 0; /* propagate failure */ + + p = mem2chunk(m); + + if ((((unsigned long)(m)) % alignment) != 0) { /* misaligned */ + + /* + Find an aligned spot inside chunk. Since we need to give back + leading space in a chunk of at least MINSIZE, if the first + calculation places us at a spot with less than MINSIZE leader, + we can move to the next aligned spot -- we've allocated enough + total room so that this is always possible. + */ + + brk = (char*)mem2chunk(((unsigned long)(m + alignment - 1)) & + -((signed long) alignment)); + if ((long)(brk - (char*)(p)) < (long)MINSIZE) + brk = brk + alignment; + + newp = (mchunkptr)brk; + leadsize = brk - (char*)(p); + newsize = chunksize(p) - leadsize; + + /* For mmapped chunks, just adjust offset */ + if (chunk_is_mmapped(p)) { + newp->prev_size = p->prev_size + leadsize; + set_head(newp, newsize|IS_MMAPPED); + return chunk2mem(newp); + } + + /* Otherwise, give back leader, use the rest */ + + set_head(newp, newsize | PREV_INUSE); + set_inuse_bit_at_offset(newp, newsize); + set_head_size(p, leadsize); + fREe(chunk2mem(p)); + p = newp; + + assert (newsize >= nb && + (((unsigned long)(chunk2mem(p))) % alignment) == 0); + } + + /* Also give back spare room at the end */ + if (!chunk_is_mmapped(p)) { + + remainder_size = (long)(chunksize(p)) - (long)nb; + + if (remainder_size >= (long)MINSIZE) { + remainder = chunk_at_offset(p, nb); + set_head(remainder, remainder_size | PREV_INUSE); + set_head_size(p, nb); + fREe(chunk2mem(remainder)); + } + } + + check_inuse_chunk(p); + return chunk2mem(p); + +} + + + + +/* + calloc calls malloc, then zeroes out the allocated chunk. +*/ + +#if __STD_C +Void_t* cALLOc(size_t n_elements, size_t elem_size) +#else +Void_t* cALLOc(n_elements, elem_size) size_t n_elements; size_t elem_size; +#endif +{ + mchunkptr p; + INTERNAL_SIZE_T clearsize; + int nclears; + INTERNAL_SIZE_T* d; + + Void_t* mem = mALLOc(n_elements * elem_size); + + if (mem != 0) { + p = mem2chunk(mem); + if (!chunk_is_mmapped(p)) { /* don't need to clear mmapped space */ + + /* + Unroll clear of <= 36 bytes (72 if 8byte sizes) + We know that contents have an odd number of + INTERNAL_SIZE_T-sized words; minimally 3. + */ + + d = (INTERNAL_SIZE_T*)mem; + clearsize = chunksize(p) - SIZE_SZ; + nclears = clearsize / sizeof(INTERNAL_SIZE_T); + assert(nclears >= 3); + + if (nclears > 9) + MALLOC_ZERO(d, clearsize); + + else { + *(d+0) = 0; + *(d+1) = 0; + *(d+2) = 0; + if (nclears > 4) { + *(d+3) = 0; + *(d+4) = 0; + if (nclears > 6) { + *(d+5) = 0; + *(d+6) = 0; + if (nclears > 8) { + *(d+7) = 0; + *(d+8) = 0; + } + } + } + } + } + } + return mem; +} + + +/* + cfree just calls free. It is needed/defined on some systems + that pair it with calloc, presumably for odd historical reasons + (such as: cfree is used in example code in first edition of K&R). +*/ + +#if __STD_C +void cFREe(Void_t *mem) +#else +void cFREe(mem) Void_t *mem; +#endif +{ + fREe(mem); +} + + + + + +/* + valloc just invokes memalign with alignment argument equal + to the page size of the system (or as near to this as can + be figured out from all the includes/defines above.) +*/ + +#if __STD_C +Void_t* vALLOc(size_t bytes) +#else +Void_t* vALLOc(bytes) size_t bytes; +#endif +{ + /* Ensure initialization/consolidation */ + mstate av = get_malloc_state(); + malloc_consolidate(av); + return mEMALIGn(av->pagesize, bytes); +} + +/* + pvalloc just invokes valloc for the nearest pagesize + that will accommodate request +*/ + + +#if __STD_C +Void_t* pVALLOc(size_t bytes) +#else +Void_t* pVALLOc(bytes) size_t bytes; +#endif +{ + mstate av = get_malloc_state(); + size_t pagesz; + + /* Ensure initialization/consolidation */ + malloc_consolidate(av); + + pagesz = av->pagesize; + return mEMALIGn(pagesz, (bytes + pagesz - 1) & ~(pagesz - 1)); +} + + +/* + Malloc_Trim gives memory back to the system (via negative + arguments to sbrk) if there is unused memory at the `high' end of + the malloc pool. You can call this after freeing large blocks of + memory to potentially reduce the system-level memory requirements + of a program. However, it cannot guarantee to reduce memory. Under + some allocation patterns, some large free blocks of memory will be + locked between two used chunks, so they cannot be given back to + the system. + + The `pad' argument to malloc_trim represents the amount of free + trailing space to leave untrimmed. If this argument is zero, + only the minimum amount of memory to maintain internal data + structures will be left (one page or less). Non-zero arguments + can be supplied to maintain enough trailing space to service + future expected allocations without having to re-obtain memory + from the system. + + Malloc_trim returns 1 if it actually released any memory, else 0. +*/ + +#if __STD_C +int mTRIm(size_t pad) +#else +int mTRIm(pad) size_t pad; +#endif +{ + mstate av = get_malloc_state(); + /* Ensure initialization/consolidation */ + malloc_consolidate(av); + + return sYSTRIm(pad, av); +} + +/* + malloc_usable_size tells you how many bytes you can actually use in + an allocated chunk, which may be more than you requested (although + often not). You can use this many bytes without worrying about + overwriting other allocated objects. Not a particularly great + programming practice, but still sometimes useful. +*/ + +#if __STD_C +size_t mUSABLe(Void_t* mem) +#else +size_t mUSABLe(mem) Void_t* mem; +#endif +{ + mchunkptr p; + if (mem != 0) { + p = mem2chunk(mem); + if (chunk_is_mmapped(p)) + return chunksize(p) - 2*SIZE_SZ; + else if (inuse(p)) + return chunksize(p) - SIZE_SZ; + } + return 0; +} + + + + +/* + mallinfo returns a copy of updated current mallinfo. +*/ + +struct mallinfo mALLINFo() +{ + mstate av = get_malloc_state(); + struct mallinfo mi; + int i; + mbinptr b; + mchunkptr p; + INTERNAL_SIZE_T avail; + int navail; + int nfastblocks; + int fastbytes; + + /* Ensure initialization */ + if (av->top == 0) malloc_consolidate(av); + + check_malloc_state(); + + /* Account for top */ + avail = chunksize(av->top); + navail = 1; /* top always exists */ + + /* traverse fastbins */ + nfastblocks = 0; + fastbytes = 0; + + for (i = 0; i < NFASTBINS; ++i) { + for (p = av->fastbins[i]; p != 0; p = p->fd) { + ++nfastblocks; + fastbytes += chunksize(p); + } + } + + avail += fastbytes; + + /* traverse regular bins */ + for (i = 1; i < NBINS; ++i) { + b = bin_at(av, i); + for (p = last(b); p != b; p = p->bk) { + avail += chunksize(p); + navail++; + } + } + + mi.smblks = nfastblocks; + mi.ordblks = navail; + mi.fordblks = avail; + mi.uordblks = av->sbrked_mem - avail; + mi.arena = av->sbrked_mem; + mi.hblks = av->n_mmaps; + mi.hblkhd = av->mmapped_mem; + mi.fsmblks = fastbytes; + mi.keepcost = chunksize(av->top); + mi.usmblks = av->max_total_mem; + return mi; +} + + + +/* + malloc_stats prints on stderr the amount of space obtained from the + system (both via sbrk and mmap), the maximum amount (which may be + more than current if malloc_trim and/or munmap got called), and the + current number of bytes allocated via malloc (or realloc, etc) but + not yet freed. Note that this is the number of bytes allocated, not + the number requested. It will be larger than the number requested + because of alignment and bookkeeping overhead. Because it includes + alignment wastage as being in use, this figure may be greater than zero + even when no user-level chunks are allocated. + + The reported current and maximum system memory can be inaccurate if + a program makes other calls to system memory allocation functions + (normally sbrk) outside of malloc. + + malloc_stats prints only the most commonly interesting statistics. + More information can be obtained by calling mallinfo. +*/ + +void mSTATs() +{ + struct mallinfo mi = mALLINFo(); + +#ifdef WIN32 + { + unsigned long free, reserved, committed; + vminfo (&free, &reserved, &committed); + fprintf(stderr, "free bytes = %10lu\n", + free); + fprintf(stderr, "reserved bytes = %10lu\n", + reserved); + fprintf(stderr, "committed bytes = %10lu\n", + committed); + } +#endif + + + fprintf(stderr, "max system bytes = %10lu\n", + (unsigned long)(mi.usmblks)); + fprintf(stderr, "system bytes = %10lu\n", + (unsigned long)(mi.arena + mi.hblkhd)); + fprintf(stderr, "in use bytes = %10lu\n", + (unsigned long)(mi.uordblks + mi.hblkhd)); + +#ifdef WIN32 + { + unsigned long kernel, user; + if (cpuinfo (TRUE, &kernel, &user)) { + fprintf(stderr, "kernel ms = %10lu\n", + kernel); + fprintf(stderr, "user ms = %10lu\n", + user); + } + } +#endif +} + + + +/* + mallopt is the general SVID/XPG interface to tunable parameters. + The format is to provide a (parameter-number, parameter-value) + pair. mallopt then sets the corresponding parameter to the + argument value if it can (i.e., so long as the value is + meaningful), and returns 1 if successful else 0. See descriptions + of tunable parameters above for meanings. +*/ + +#if __STD_C +int mALLOPt(int param_number, int value) +#else +int mALLOPt(param_number, value) int param_number; int value; +#endif +{ + mstate av = get_malloc_state(); + /* Ensure initialization/consolidation */ + malloc_consolidate(av); + + switch(param_number) { + case M_MXFAST: + if (value >= 0 && value <= MAX_FAST_SIZE) { + av->max_fast = req2max_fast(value); + return 1; + } + else + return 0; + + case M_TRIM_THRESHOLD: + av->trim_threshold = value; + return 1; + + case M_TOP_PAD: + av->top_pad = value; + return 1; + + case M_MMAP_THRESHOLD: + av->mmap_threshold = value; + return 1; + + case M_MMAP_MAX: +#if HAVE_MMAP + av->n_mmaps_max = value; + return 1; +#else + if (value != 0) + return 0; + else { + av->n_mmaps_max = value; + return 1; + } +#endif + + default: + return 0; + } +} + + +/* -------------------------------------------------------------- */ + +/* + Emulation of sbrk for win32. + Donated by J. Walter . + For additional information about this code, and malloc on Win32, see + http://www.genesys-e.de/jwalter/ + +*/ + + +#ifdef WIN32 + +#ifdef _DEBUG +/* #define TRACE */ +#endif + +/* Support for USE_MALLOC_LOCK */ +#ifdef USE_MALLOC_LOCK + +/* Wait for spin lock */ +static int slwait (int *sl) { + while (InterlockedCompareExchange ((void **) sl, (void *) 1, (void *) 0) != 0) + Sleep (0); + return 0; +} + +/* Release spin lock */ +static int slrelease (int *sl) { + InterlockedExchange (sl, 0); + return 0; +} + +#ifdef NEEDED +/* Spin lock for emulation code */ +static int g_sl; +#endif + +#endif /* USE_MALLOC_LOCK */ + +/* getpagesize for windows */ +static long getpagesize (void) { + static long g_pagesize = 0; + if (! g_pagesize) { + SYSTEM_INFO system_info; + GetSystemInfo (&system_info); + g_pagesize = system_info.dwPageSize; + } + return g_pagesize; +} +static long getregionsize (void) { + static long g_regionsize = 0; + if (! g_regionsize) { + SYSTEM_INFO system_info; + GetSystemInfo (&system_info); + g_regionsize = system_info.dwAllocationGranularity; + } + return g_regionsize; +} + +/* A region list entry */ +typedef struct _region_list_entry { + void *top_allocated; + void *top_committed; + void *top_reserved; + long reserve_size; + struct _region_list_entry *previous; +} region_list_entry; + +/* Allocate and link a region entry in the region list */ +static int region_list_append (region_list_entry **last, void *base_reserved, long reserve_size) { + region_list_entry *next = HeapAlloc (GetProcessHeap (), 0, sizeof (region_list_entry)); + if (! next) + return FALSE; + next->top_allocated = (char *) base_reserved; + next->top_committed = (char *) base_reserved; + next->top_reserved = (char *) base_reserved + reserve_size; + next->reserve_size = reserve_size; + next->previous = *last; + *last = next; + return TRUE; +} +/* Free and unlink the last region entry from the region list */ +static int region_list_remove (region_list_entry **last) { + region_list_entry *previous = (*last)->previous; + if (! HeapFree (GetProcessHeap (), sizeof (region_list_entry), *last)) + return FALSE; + *last = previous; + return TRUE; +} + +#define CEIL(size,to) (((size)+(to)-1)&~((to)-1)) +#define FLOOR(size,to) ((size)&~((to)-1)) + +#define SBRK_SCALE 0 +/* #define SBRK_SCALE 1 */ +/* #define SBRK_SCALE 2 */ +/* #define SBRK_SCALE 4 */ + +/* sbrk for windows */ +static void *sbrk (long size) { + static long g_pagesize, g_my_pagesize; + static long g_regionsize, g_my_regionsize; + static region_list_entry *g_last; + void *result = (void *) MORECORE_FAILURE; +#ifdef TRACE + printf ("sbrk %d\n", size); +#endif +#if defined (USE_MALLOC_LOCK) && defined (NEEDED) + /* Wait for spin lock */ + slwait (&g_sl); +#endif + /* First time initialization */ + if (! g_pagesize) { + g_pagesize = getpagesize (); + g_my_pagesize = g_pagesize << SBRK_SCALE; + } + if (! g_regionsize) { + g_regionsize = getregionsize (); + g_my_regionsize = g_regionsize << SBRK_SCALE; + } + if (! g_last) { + if (! region_list_append (&g_last, 0, 0)) + goto sbrk_exit; + } + /* Assert invariants */ + assert (g_last); + assert ((char *) g_last->top_reserved - g_last->reserve_size <= (char *) g_last->top_allocated && + g_last->top_allocated <= g_last->top_committed); + assert ((char *) g_last->top_reserved - g_last->reserve_size <= (char *) g_last->top_committed && + g_last->top_committed <= g_last->top_reserved && + (unsigned) g_last->top_committed % g_pagesize == 0); + assert ((unsigned) g_last->top_reserved % g_regionsize == 0); + assert ((unsigned) g_last->reserve_size % g_regionsize == 0); + /* Allocation requested? */ + if (size >= 0) { + /* Allocation size is the requested size */ + long allocate_size = size; + /* Compute the size to commit */ + long to_commit = (char *) g_last->top_allocated + allocate_size - (char *) g_last->top_committed; + /* Do we reach the commit limit? */ + if (to_commit > 0) { + /* Round size to commit */ + long commit_size = CEIL (to_commit, g_my_pagesize); + /* Compute the size to reserve */ + long to_reserve = (char *) g_last->top_committed + commit_size - (char *) g_last->top_reserved; + /* Do we reach the reserve limit? */ + if (to_reserve > 0) { + /* Compute the remaining size to commit in the current region */ + long remaining_commit_size = (char *) g_last->top_reserved - (char *) g_last->top_committed; + if (remaining_commit_size > 0) { + /* Assert preconditions */ + assert ((unsigned) g_last->top_committed % g_pagesize == 0); + assert (0 < remaining_commit_size && remaining_commit_size % g_pagesize == 0); { + /* Commit this */ + void *base_committed = VirtualAlloc (g_last->top_committed, remaining_commit_size, + MEM_COMMIT, PAGE_READWRITE); + /* Check returned pointer for consistency */ + if (base_committed != g_last->top_committed) + goto sbrk_exit; + /* Assert postconditions */ + assert ((unsigned) base_committed % g_pagesize == 0); +#ifdef TRACE + printf ("Commit %p %d\n", base_committed, remaining_commit_size); +#endif + /* Adjust the regions commit top */ + g_last->top_committed = (char *) base_committed + remaining_commit_size; + } + } { + /* Now we are going to search and reserve. */ + int contiguous = -1; + int found = FALSE; + MEMORY_BASIC_INFORMATION memory_info; + void *base_reserved; + long reserve_size; + do { + /* Assume contiguous memory */ + contiguous = TRUE; + /* Round size to reserve */ + reserve_size = CEIL (to_reserve, g_my_regionsize); + /* Start with the current region's top */ + memory_info.BaseAddress = g_last->top_reserved; + /* Assert preconditions */ + assert ((unsigned) memory_info.BaseAddress % g_pagesize == 0); + assert (0 < reserve_size && reserve_size % g_regionsize == 0); + while (VirtualQuery (memory_info.BaseAddress, &memory_info, sizeof (memory_info))) { + /* Assert postconditions */ + assert ((unsigned) memory_info.BaseAddress % g_pagesize == 0); +#ifdef TRACE + printf ("Query %p %d %s\n", memory_info.BaseAddress, memory_info.RegionSize, + memory_info.State == MEM_FREE ? "FREE": + (memory_info.State == MEM_RESERVE ? "RESERVED": + (memory_info.State == MEM_COMMIT ? "COMMITTED": "?"))); +#endif + /* Region is free, well aligned and big enough: we are done */ + if (memory_info.State == MEM_FREE && + (unsigned) memory_info.BaseAddress % g_regionsize == 0 && + memory_info.RegionSize >= (unsigned) reserve_size) { + found = TRUE; + break; + } + /* From now on we can't get contiguous memory! */ + contiguous = FALSE; + /* Recompute size to reserve */ + reserve_size = CEIL (allocate_size, g_my_regionsize); + memory_info.BaseAddress = (char *) memory_info.BaseAddress + memory_info.RegionSize; + /* Assert preconditions */ + assert ((unsigned) memory_info.BaseAddress % g_pagesize == 0); + assert (0 < reserve_size && reserve_size % g_regionsize == 0); + } + /* Search failed? */ + if (! found) + goto sbrk_exit; + /* Assert preconditions */ + assert ((unsigned) memory_info.BaseAddress % g_regionsize == 0); + assert (0 < reserve_size && reserve_size % g_regionsize == 0); + /* Try to reserve this */ + base_reserved = VirtualAlloc (memory_info.BaseAddress, reserve_size, + MEM_RESERVE, PAGE_NOACCESS); + if (! base_reserved) { + int rc = GetLastError (); + if (rc != ERROR_INVALID_ADDRESS) + goto sbrk_exit; + } + /* A null pointer signals (hopefully) a race condition with another thread. */ + /* In this case, we try again. */ + } while (! base_reserved); + /* Check returned pointer for consistency */ + if (memory_info.BaseAddress && base_reserved != memory_info.BaseAddress) + goto sbrk_exit; + /* Assert postconditions */ + assert ((unsigned) base_reserved % g_regionsize == 0); +#ifdef TRACE + printf ("Reserve %p %d\n", base_reserved, reserve_size); +#endif + /* Did we get contiguous memory? */ + if (contiguous) { + long start_size = (char *) g_last->top_committed - (char *) g_last->top_allocated; + /* Adjust allocation size */ + allocate_size -= start_size; + /* Adjust the regions allocation top */ + g_last->top_allocated = g_last->top_committed; + /* Recompute the size to commit */ + to_commit = (char *) g_last->top_allocated + allocate_size - (char *) g_last->top_committed; + /* Round size to commit */ + commit_size = CEIL (to_commit, g_my_pagesize); + } + /* Append the new region to the list */ + if (! region_list_append (&g_last, base_reserved, reserve_size)) + goto sbrk_exit; + /* Didn't we get contiguous memory? */ + if (! contiguous) { + /* Recompute the size to commit */ + to_commit = (char *) g_last->top_allocated + allocate_size - (char *) g_last->top_committed; + /* Round size to commit */ + commit_size = CEIL (to_commit, g_my_pagesize); + } + } + } + /* Assert preconditions */ + assert ((unsigned) g_last->top_committed % g_pagesize == 0); + assert (0 < commit_size && commit_size % g_pagesize == 0); { + /* Commit this */ + void *base_committed = VirtualAlloc (g_last->top_committed, commit_size, + MEM_COMMIT, PAGE_READWRITE); + /* Check returned pointer for consistency */ + if (base_committed != g_last->top_committed) + goto sbrk_exit; + /* Assert postconditions */ + assert ((unsigned) base_committed % g_pagesize == 0); +#ifdef TRACE + printf ("Commit %p %d\n", base_committed, commit_size); +#endif + /* Adjust the regions commit top */ + g_last->top_committed = (char *) base_committed + commit_size; + } + } + /* Adjust the regions allocation top */ + g_last->top_allocated = (char *) g_last->top_allocated + allocate_size; + result = (char *) g_last->top_allocated - size; + /* Deallocation requested? */ + } else if (size < 0) { + long deallocate_size = - size; + /* As long as we have a region to release */ + while ((char *) g_last->top_allocated - deallocate_size < (char *) g_last->top_reserved - g_last->reserve_size) { + /* Get the size to release */ + long release_size = g_last->reserve_size; + /* Get the base address */ + void *base_reserved = (char *) g_last->top_reserved - release_size; + /* Assert preconditions */ + assert ((unsigned) base_reserved % g_regionsize == 0); + assert (0 < release_size && release_size % g_regionsize == 0); { + /* Release this */ + int rc = VirtualFree (base_reserved, 0, + MEM_RELEASE); + /* Check returned code for consistency */ + if (! rc) + goto sbrk_exit; +#ifdef TRACE + printf ("Release %p %d\n", base_reserved, release_size); +#endif + } + /* Adjust deallocation size */ + deallocate_size -= (char *) g_last->top_allocated - (char *) base_reserved; + /* Remove the old region from the list */ + if (! region_list_remove (&g_last)) + goto sbrk_exit; + } { + /* Compute the size to decommit */ + long to_decommit = (char *) g_last->top_committed - ((char *) g_last->top_allocated - deallocate_size); + if (to_decommit >= g_my_pagesize) { + /* Compute the size to decommit */ + long decommit_size = FLOOR (to_decommit, g_my_pagesize); + /* Compute the base address */ + void *base_committed = (char *) g_last->top_committed - decommit_size; + /* Assert preconditions */ + assert ((unsigned) base_committed % g_pagesize == 0); + assert (0 < decommit_size && decommit_size % g_pagesize == 0); { + /* Decommit this */ + int rc = VirtualFree ((char *) base_committed, decommit_size, + MEM_DECOMMIT); + /* Check returned code for consistency */ + if (! rc) + goto sbrk_exit; +#ifdef TRACE + printf ("Decommit %p %d\n", base_committed, decommit_size); +#endif + } + /* Adjust deallocation size and regions commit and allocate top */ + deallocate_size -= (char *) g_last->top_allocated - (char *) base_committed; + g_last->top_committed = base_committed; + g_last->top_allocated = base_committed; + } + } + /* Adjust regions allocate top */ + g_last->top_allocated = (char *) g_last->top_allocated - deallocate_size; + /* Check for underflow */ + if ((char *) g_last->top_reserved - g_last->reserve_size > (char *) g_last->top_allocated || + g_last->top_allocated > g_last->top_committed) { + /* Adjust regions allocate top */ + g_last->top_allocated = (char *) g_last->top_reserved - g_last->reserve_size; + goto sbrk_exit; + } + result = g_last->top_allocated; + } + /* Assert invariants */ + assert (g_last); + assert ((char *) g_last->top_reserved - g_last->reserve_size <= (char *) g_last->top_allocated && + g_last->top_allocated <= g_last->top_committed); + assert ((char *) g_last->top_reserved - g_last->reserve_size <= (char *) g_last->top_committed && + g_last->top_committed <= g_last->top_reserved && + (unsigned) g_last->top_committed % g_pagesize == 0); + assert ((unsigned) g_last->top_reserved % g_regionsize == 0); + assert ((unsigned) g_last->reserve_size % g_regionsize == 0); + +sbrk_exit: +#if defined (USE_MALLOC_LOCK) && defined (NEEDED) + /* Release spin lock */ + slrelease (&g_sl); +#endif + return result; +} + +/* mmap for windows */ +static void *mmap (void *ptr, long size, long prot, long type, long handle, long arg) { + static long g_pagesize; + static long g_regionsize; +#ifdef TRACE + printf ("mmap %d\n", size); +#endif +#if defined (USE_MALLOC_LOCK) && defined (NEEDED) + /* Wait for spin lock */ + slwait (&g_sl); +#endif + /* First time initialization */ + if (! g_pagesize) + g_pagesize = getpagesize (); + if (! g_regionsize) + g_regionsize = getregionsize (); + /* Assert preconditions */ + assert ((unsigned) ptr % g_regionsize == 0); + assert (size % g_pagesize == 0); + /* Allocate this */ + ptr = VirtualAlloc (ptr, size, + MEM_RESERVE | MEM_COMMIT | MEM_TOP_DOWN, PAGE_READWRITE); + if (! ptr) { + ptr = (void *) MORECORE_FAILURE; + goto mmap_exit; + } + /* Assert postconditions */ + assert ((unsigned) ptr % g_regionsize == 0); +#ifdef TRACE + printf ("Commit %p %d\n", ptr, size); +#endif +mmap_exit: +#if defined (USE_MALLOC_LOCK) && defined (NEEDED) + /* Release spin lock */ + slrelease (&g_sl); +#endif + return ptr; +} + +/* munmap for windows */ +static long munmap (void *ptr, long size) { + static long g_pagesize; + static long g_regionsize; + int rc = MUNMAP_FAILURE; +#ifdef TRACE + printf ("munmap %p %d\n", ptr, size); +#endif +#if defined (USE_MALLOC_LOCK) && defined (NEEDED) + /* Wait for spin lock */ + slwait (&g_sl); +#endif + /* First time initialization */ + if (! g_pagesize) + g_pagesize = getpagesize (); + if (! g_regionsize) + g_regionsize = getregionsize (); + /* Assert preconditions */ + assert ((unsigned) ptr % g_regionsize == 0); + assert (size % g_pagesize == 0); + /* Free this */ + if (! VirtualFree (ptr, 0, + MEM_RELEASE)) + goto munmap_exit; + rc = 0; +#ifdef TRACE + printf ("Release %p %d\n", ptr, size); +#endif +munmap_exit: +#if defined (USE_MALLOC_LOCK) && defined (NEEDED) + /* Release spin lock */ + slrelease (&g_sl); +#endif + return rc; +} + +static void vminfo (unsigned long *free, unsigned long *reserved, unsigned long *committed) { + MEMORY_BASIC_INFORMATION memory_info; + memory_info.BaseAddress = 0; + *free = *reserved = *committed = 0; + while (VirtualQuery (memory_info.BaseAddress, &memory_info, sizeof (memory_info))) { + switch (memory_info.State) { + case MEM_FREE: + *free += memory_info.RegionSize; + break; + case MEM_RESERVE: + *reserved += memory_info.RegionSize; + break; + case MEM_COMMIT: + *committed += memory_info.RegionSize; + break; + } + memory_info.BaseAddress = (char *) memory_info.BaseAddress + memory_info.RegionSize; + } +} + +static int cpuinfo (int whole, unsigned long *kernel, unsigned long *user) { + if (whole) { + __int64 creation64, exit64, kernel64, user64; + int rc = GetProcessTimes (GetCurrentProcess (), + (FILETIME *) &creation64, + (FILETIME *) &exit64, + (FILETIME *) &kernel64, + (FILETIME *) &user64); + if (! rc) { + *kernel = 0; + *user = 0; + return FALSE; + } + *kernel = (unsigned long) (kernel64 / 10000); + *user = (unsigned long) (user64 / 10000); + return TRUE; + } else { + __int64 creation64, exit64, kernel64, user64; + int rc = GetThreadTimes (GetCurrentThread (), + (FILETIME *) &creation64, + (FILETIME *) &exit64, + (FILETIME *) &kernel64, + (FILETIME *) &user64); + if (! rc) { + *kernel = 0; + *user = 0; + return FALSE; + } + *kernel = (unsigned long) (kernel64 / 10000); + *user = (unsigned long) (user64 / 10000); + return TRUE; + } +} + +#endif /* WIN32 */ + +/* + +History: + + V2.7.0 + * new WIN32 sbrk, mmap, munmap, lock code from . + * Allow override of MALLOC_ALIGNMENT (Thanks to Ruud Waij for + helping test this.) + * memalign: check alignment arg + * realloc: use memmove when regions may overlap. + * Collect all cases in malloc requiring system memory into sYSMALLOc + * Use mmap as backup to sbrk, if available; fold these mmap-related + operations into others. + * Place all internal state in malloc_state + * Introduce fastbins (although similar to 2.5.1) + * Many minor tunings and cosmetic improvements + * Introduce USE_PUBLIC_MALLOC_WRAPPERS, USE_MALLOC_LOCK + * Introduce MALLOC_FAILURE_ACTION, MORECORE_CONTIGUOUS + Thanks to Tony E. Bennett and others. + * Adjust request2size to fit with MALLOC_FAILURE_ACTION. + * Include errno.h to support default failure action. + * Further improve WIN32 'sbrk()' emulation's 'findRegion()' routine + to avoid infinite loop when allocating initial memory larger + than RESERVED_SIZE and/or subsequent memory larger than + NEXT_SIZE. Thanks to Andreas Mueller + for finding this one. + + V2.6.6 Sun Dec 5 07:42:19 1999 Doug Lea (dl at gee) + * return null for negative arguments + * Added Several WIN32 cleanups from Martin C. Fong + * Add 'LACKS_SYS_PARAM_H' for those systems without 'sys/param.h' + (e.g. WIN32 platforms) + * Cleanup header file inclusion for WIN32 platforms + * Cleanup code to avoid Microsoft Visual C++ compiler complaints + * Add 'USE_DL_PREFIX' to quickly allow co-existence with existing + memory allocation routines + * Set 'malloc_getpagesize' for WIN32 platforms (needs more work) + * Use 'assert' rather than 'ASSERT' in WIN32 code to conform to + usage of 'assert' in non-WIN32 code + * Improve WIN32 'sbrk()' emulation's 'findRegion()' routine to + avoid infinite loop + * Always call 'fREe()' rather than 'free()' + + V2.6.5 Wed Jun 17 15:57:31 1998 Doug Lea (dl at gee) + * Fixed ordering problem with boundary-stamping + + V2.6.3 Sun May 19 08:17:58 1996 Doug Lea (dl at gee) + * Added pvalloc, as recommended by H.J. Liu + * Added 64bit pointer support mainly from Wolfram Gloger + * Added anonymously donated WIN32 sbrk emulation + * Malloc, calloc, getpagesize: add optimizations from Raymond Nijssen + * malloc_extend_top: fix mask error that caused wastage after + foreign sbrks + * Add linux mremap support code from HJ Liu + + V2.6.2 Tue Dec 5 06:52:55 1995 Doug Lea (dl at gee) + * Integrated most documentation with the code. + * Add support for mmap, with help from + Wolfram Gloger (Gloger@lrz.uni-muenchen.de). + * Use last_remainder in more cases. + * Pack bins using idea from colin@nyx10.cs.du.edu + * Use ordered bins instead of best-fit threshhold + * Eliminate block-local decls to simplify tracing and debugging. + * Support another case of realloc via move into top + * Fix error occuring when initial sbrk_base not word-aligned. + * Rely on page size for units instead of SBRK_UNIT to + avoid surprises about sbrk alignment conventions. + * Add mallinfo, mallopt. Thanks to Raymond Nijssen + (raymond@es.ele.tue.nl) for the suggestion. + * Add `pad' argument to malloc_trim and top_pad mallopt parameter. + * More precautions for cases where other routines call sbrk, + courtesy of Wolfram Gloger (Gloger@lrz.uni-muenchen.de). + * Added macros etc., allowing use in linux libc from + H.J. Lu (hjl@gnu.ai.mit.edu) + * Inverted this history list + + V2.6.1 Sat Dec 2 14:10:57 1995 Doug Lea (dl at gee) + * Re-tuned and fixed to behave more nicely with V2.6.0 changes. + * Removed all preallocation code since under current scheme + the work required to undo bad preallocations exceeds + the work saved in good cases for most test programs. + * No longer use return list or unconsolidated bins since + no scheme using them consistently outperforms those that don't + given above changes. + * Use best fit for very large chunks to prevent some worst-cases. + * Added some support for debugging + + V2.6.0 Sat Nov 4 07:05:23 1995 Doug Lea (dl at gee) + * Removed footers when chunks are in use. Thanks to + Paul Wilson (wilson@cs.texas.edu) for the suggestion. + + V2.5.4 Wed Nov 1 07:54:51 1995 Doug Lea (dl at gee) + * Added malloc_trim, with help from Wolfram Gloger + (wmglo@Dent.MED.Uni-Muenchen.DE). + + V2.5.3 Tue Apr 26 10:16:01 1994 Doug Lea (dl at g) + + V2.5.2 Tue Apr 5 16:20:40 1994 Doug Lea (dl at g) + * realloc: try to expand in both directions + * malloc: swap order of clean-bin strategy; + * realloc: only conditionally expand backwards + * Try not to scavenge used bins + * Use bin counts as a guide to preallocation + * Occasionally bin return list chunks in first scan + * Add a few optimizations from colin@nyx10.cs.du.edu + + V2.5.1 Sat Aug 14 15:40:43 1993 Doug Lea (dl at g) + * faster bin computation & slightly different binning + * merged all consolidations to one part of malloc proper + (eliminating old malloc_find_space & malloc_clean_bin) + * Scan 2 returns chunks (not just 1) + * Propagate failure in realloc if malloc returns 0 + * Add stuff to allow compilation on non-ANSI compilers + from kpv@research.att.com + + V2.5 Sat Aug 7 07:41:59 1993 Doug Lea (dl at g.oswego.edu) + * removed potential for odd address access in prev_chunk + * removed dependency on getpagesize.h + * misc cosmetics and a bit more internal documentation + * anticosmetics: mangled names in macros to evade debugger strangeness + * tested on sparc, hp-700, dec-mips, rs6000 + with gcc & native cc (hp, dec only) allowing + Detlefs & Zorn comparison study (in SIGPLAN Notices.) + + Trial version Fri Aug 28 13:14:29 1992 Doug Lea (dl at g.oswego.edu) + * Based loosely on libg++-1.2X malloc. (It retains some of the overall + structure of old version, but most details differ.) + +*/ + + diff --git a/src/libs/xpcom18a4/xpcom/build/nsOS2VACLegacy.cpp b/src/libs/xpcom18a4/xpcom/build/nsOS2VACLegacy.cpp new file mode 100644 index 00000000..c9c04b30 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/build/nsOS2VACLegacy.cpp @@ -0,0 +1,753 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 the Mozilla.org code. + * + * The Initial Developer of the Original Code is + * innotek GmbH. + * Portions created by the Initial Developer are Copyright (C) 2003 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * innotek GmbH / Knut St. Osmundsen + * + * 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 ***** */ + +/* + * This module contains wrappers for a handful of XPCOM methods which someone + * have been so kind as to link their plugins against. This module will only + * provide the minimum of what necessary to make legacy plugins work with + * the GCC based mozilla. Luckily this only means the IBM oji JAVA plugins. + * + * Actually, I haven't seen npoji6 calling any of these yet. + */ + +/******************************************************************************* +* Defined Constants And Macros * +*******************************************************************************/ +/** @group Visual Age for C++ v3.6.5 target (OS/2). */ +/* @{ */ +/** Indicate Visual Age for C++ v3.6.5 target */ +#define VFT_VAC365 1 +/** VFTable/Interface Calling Convention for Win32. */ +#define VFTCALL _Optlink +/** First Entry which VAC uses. */ +#define VFTFIRST_DECL unsigned uFirst[2] +#define VFTFIRST_VAL() {0, 0}, +/** This deltas which VAC uses. */ +#define VFTDELTA_DECL(n) unsigned uDelta##n +#define VFTDELTA_VAL() 0, +/** @} */ + + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include "nscore.h" +#include "nsIServiceManagerUtils.h" + + +/******************************************************************************* +* Structures and Typedefs * +*******************************************************************************/ +#ifndef __cplusplus +typedef struct nsID +{ + PRUint32 m0; + PRUint16 m1; + PRUint16 m2; + PRUint8 m3[8]; +} nsID, nsCID, nsIID; +#define REFNSIID const nsIID * + +typedef PRUint32 nsrefcnt; +#endif + + +/** + * nsISupports vftable. + */ +typedef struct vftable_nsISupports +{ + VFTFIRST_DECL; + nsresult (*VFTCALL QueryInterface)(void *pvThis, REFNSIID aIID, void** aInstancePtr); + VFTDELTA_DECL(QueryInterface); + nsrefcnt (*VFTCALL AddRef)(void *pvThis); + VFTDELTA_DECL(AddRef); + nsrefcnt (*VFTCALL Release)(void *pvThis); + VFTDELTA_DECL(Release); +} VFTnsISupports; + +/** + * nsGetServiceByCID::nsCOMPtr_helper vftable. + */ +typedef struct vftable_nsGetServiceByCID_nsCOMPtr_helper +{ + VFTFIRST_DECL; + /* virtual nsresult operator()( const nsIID&, void** ) const; */ + nsresult (*VFTCALL __operator_paratheses)(void *pvThis, REFNSIID aIID, void** aInstancePtr); + VFTDELTA_DECL(__operator_paratheses); + void * (*VFTCALL __destructor)(void *pvThis, unsigned __dtorFlags, unsigned __vtt); + VFTDELTA_DECL(__destructor); +} VFTnsGetServiceByCID_nsCOMPtr_helper; + +/** + * nsQueryInterface::nsCOMPtr_helper vftable. + */ +typedef struct vftable_nsQueryInterface_nsCOMPtr_helper +{ + VFTFIRST_DECL; + nsresult (*VFTCALL __operator_paratheses)(void *pvThis, REFNSIID aIID, void** aInstancePtr); + VFTDELTA_DECL(__operator_paratheses); +} VFTnsQueryInterface_nsCOMPtr_helper; + + + + +/** + * nsISupport object. + */ +typedef struct obj_nsISupports +{ + VFTnsISupports *pVFT; +} obj_nsISupports; + +/** + * nsCOMPtr_base object. + */ +typedef struct obj_nsCOMPtr_base +{ + obj_nsISupports *mRawPtr; +} obj_nsCOMPtr_base; + +/** + * nsGetServiceByCID_nsCOMPtr_helper object. + */ +typedef struct obj_nsGetServiceByCID_nsCOMPtr_helper +{ + VFTnsGetServiceByCID_nsCOMPtr_helper *pVFT; /* ?? */ + nsID *mCID; /* const nsCID& */ + void *mServiceManager;/* nsCOMPtr */ + nsresult *mErrorPtr; +} obj_nsGetServiceByCID_nsCOMPtr_helper; + +/** + * nsQueryInterface_nsCOMPtr_helper object. + */ +typedef struct obj_nsQueryInterface_nsCOMPtr_helper +{ + VFTnsQueryInterface_nsCOMPtr_helper *pVFT; /* ?? */ + obj_nsISupports *mRawPtr; /* const nsCID& */ + nsresult *mErrorPtr; +} obj_nsQueryInterface_nsCOMPtr_helper; + + + + +/** + * nsCOMPtr_base::~nsCOMPtr_base() + * + * @remark This guys doing the oji plugin have been very unfortunate to link in this + * without any similar new operator. The object is thus created in the plugin + * but freed by xpcom.dll. As the plugin and mozilla have different CRTs this + * is a good way of asking for trouble. But, they guys've been lucky, the VAC + * CRT might just handle this ok. + * However, we cannot perform this delete as we have no VAC CRT around, and + * hence we will leak this object. + * ---- + * assembly: + public __dt__13nsCOMPtr_baseFv +__dt__13nsCOMPtr_baseFv proc + push ebp + mov ebp,esp + sub esp,08h + mov [ebp+08h],eax; this + mov [ebp+0ch],edx; __dtorFlags + +; 63 if ( mRawPtr ) + mov eax,[ebp+08h]; this + cmp dword ptr [eax],0h + je @BLBL4 + +; 64 NSCAP_RELEASE(this, mRawPtr); + mov ecx,[ebp+08h]; this + mov ecx,[ecx] + mov ecx,[ecx] + mov eax,[ebp+08h]; this + mov eax,[eax] + add eax,[ecx+01ch] + mov ecx,[ebp+08h]; this + mov ecx,[ecx] + mov ecx,[ecx] + call dword ptr [ecx+018h] +@BLBL4: + +; 65 } + test byte ptr [ebp+0ch],01h; __dtorFlags + je @BLBL6 + mov eax,[ebp+08h]; this + call __dl__FPv +@BLBL6: + mov eax,[ebp+08h]; this + add esp,08h + pop ebp + ret +__dt__13nsCOMPtr_baseFv endp +*/ +extern "C" void * VFTCALL __dt__13nsCOMPtr_baseFv(void *pvThis, unsigned __dtorFlags) +{ + obj_nsCOMPtr_base *pThis = (obj_nsCOMPtr_base*)pvThis; +//asm("int $3"); + if (pThis->mRawPtr) + { + /* NSCAP_RELEASE(this, mRawPtr); */ + pThis->mRawPtr->pVFT->Release((char*)pThis->mRawPtr + pThis->mRawPtr->pVFT->uDeltaRelease); + } + + /* + * Delete the object... + * (As memtioned before we'll rather leak this.) + */ + #if 0 + if (!(__dtorFlags & 1)) + __dl__FPv(this) + #endif + + return pvThis; +} + +/** workaround for _Optlink bug.. */ +extern "C" void * VFTCALL _dt__13nsCOMPtr_baseFv(void *pvThis, unsigned __dtorFlags) +{ + return __dt__13nsCOMPtr_baseFv(pvThis, __dtorFlags); +} + + + +/** + * + * ----- + * assembly: +; 92 nsGetServiceByCID::operator()( const nsIID& aIID, void** aInstancePtr ) const + align 010h + + public __cl__17nsGetServiceByCIDCFRC4nsIDPPv +__cl__17nsGetServiceByCIDCFRC4nsIDPPv proc + push ebp + mov ebp,esp + sub esp,014h + push ebx + sub esp,08h + mov [ebp+08h],eax; this + mov [ebp+0ch],edx; aIID + mov [ebp+010h],ecx; aInstancePtr + +; 94 nsresult status = NS_ERROR_FAILURE; + mov dword ptr [ebp-04h],080004005h; status + +; 95 if ( mServiceManager ) { + mov eax,[ebp+08h]; this + add eax,08h + call __opP13nsDerivedSafeXT17nsIServiceManager___8nsCOMPtrXT17nsIServiceManager_CFv + test eax,eax + je @BLBL13 + +; 96 status = mServiceManager->GetService(mCID, aIID, (void**)aInstancePtr); + mov eax,[ebp+08h]; this + add eax,08h + call __rf__8nsCOMPtrXT17nsIServiceManager_CFv + mov [ebp-08h],eax; __212 + mov eax,[ebp+010h]; aInstancePtr + push eax + mov ecx,[ebp+0ch]; aIID + mov edx,[ebp+08h]; this + mov edx,[edx+04h] + mov ebx,[ebp-08h]; __212 + mov ebx,[ebx] + mov eax,[ebp-08h]; __212 + add eax,[ebx+024h] + sub esp,0ch + mov ebx,[ebp-08h]; __212 + mov ebx,[ebx] + call dword ptr [ebx+020h] + add esp,010h + mov [ebp-04h],eax; status + +; 97 } else { + jmp @BLBL14 + align 010h +@BLBL13: + +; 95 if ( mServiceManager ) { + +; 98 nsCOMPtr mgr; + lea eax,[ebp-0ch]; mgr + call __ct__8nsCOMPtrXT17nsIServiceManager_Fv + +; 99 NS_GetServiceManager(getter_AddRefs(mgr)); + lea edx,[ebp-0ch]; mgr + lea eax,[ebp-010h]; __216 + call getter_AddRefs__FR8nsCOMPtrXT17nsIServiceManager_ + sub esp,04h + lea eax,[ebp-010h]; __216 + sub esp,04h + call __opPP17nsIServiceManager__15nsGetterAddRefsXT17nsIServiceManager_Fv + add esp,08h + call NS_GetServiceManager + mov edx,02h + lea eax,[ebp-010h]; __216 + call __dt__15nsGetterAddRefsXT17nsIServiceManager_Fv + +; 100 if (mgr) + lea eax,[ebp-0ch]; mgr + call __opP13nsDerivedSafeXT17nsIServiceManager___8nsCOMPtrXT17nsIServiceManager_CFv + test eax,eax + je @BLBL15 + +; 101 status = mgr->GetService(mCID, aIID, (void**)aInstancePtr); + lea eax,[ebp-0ch]; mgr + call __rf__8nsCOMPtrXT17nsIServiceManager_CFv + mov [ebp-014h],eax; __217 + mov eax,[ebp+010h]; aInstancePtr + push eax + mov ecx,[ebp+0ch]; aIID + mov edx,[ebp+08h]; this + mov edx,[edx+04h] + mov ebx,[ebp-014h]; __217 + mov ebx,[ebx] + mov eax,[ebp-014h]; __217 + add eax,[ebx+024h] + sub esp,0ch + mov ebx,[ebp-014h]; __217 + mov ebx,[ebx] + call dword ptr [ebx+020h] + add esp,010h + mov [ebp-04h],eax; status +@BLBL15: + +; 102 } + mov edx,02h + lea eax,[ebp-0ch]; mgr + call __dt__8nsCOMPtrXT17nsIServiceManager_Fv +@BLBL14: + +; 103 if ( NS_FAILED(status) ) + test byte ptr [ebp-01h],080h; status + je @BLBL16 + +; 104 *aInstancePtr = 0; + mov eax,[ebp+010h]; aInstancePtr + mov dword ptr [eax],0h +@BLBL16: + +; 106 if ( mErrorPtr ) + mov eax,[ebp+08h]; this + cmp dword ptr [eax+0ch],0h + je @BLBL17 + +; 107 *mErrorPtr = status; + mov eax,[ebp+08h]; this + mov eax,[eax+0ch] + mov ebx,[ebp-04h]; status + mov [eax],ebx +@BLBL17: + +; 108 return status; + mov eax,[ebp-04h]; status + add esp,08h + pop ebx + mov esp,ebp + pop ebp + ret +__cl__17nsGetServiceByCIDCFRC4nsIDPPv endp + + * ----- + * C++ Code: +nsresult +nsGetServiceByCID::operator()( const nsIID& aIID, void** aInstancePtr ) const +{ + nsresult status = NS_ERROR_FAILURE; + if ( mServiceManager ) { + status = mServiceManager->GetService(mCID, aIID, (void**)aInstancePtr); + } else { + nsCOMPtr mgr; + NS_GetServiceManager(getter_AddRefs(mgr)); + if (mgr) + status = mgr->GetService(mCID, aIID, (void**)aInstancePtr); + } + if ( NS_FAILED(status) ) + *aInstancePtr = 0; + + if ( mErrorPtr ) + *mErrorPtr = status; + return status; +} + */ +extern "C" nsresult VFTCALL GSBC_COM__operator_paratheses(void *pvThis, REFNSIID aIID, void** aInstancePtr) +{ + obj_nsGetServiceByCID_nsCOMPtr_helper *pThis = (obj_nsGetServiceByCID_nsCOMPtr_helper *)pvThis; + nsresult status = NS_ERROR_FAILURE; +//asm("int $3"); + + /* For convenience we don't use mServiceManager here because it's a wrapped object. + * We ASSUME that there is only one service manager floating around.... + */ + nsCOMPtr mgr; + NS_GetServiceManager(getter_AddRefs(mgr)); + if (mgr) + status = mgr->GetService(*pThis->mCID, aIID, (void**)aInstancePtr); + + if (NS_FAILED(status)) + *aInstancePtr = 0; + + if (pThis->mErrorPtr) + *pThis->mErrorPtr = status; + return status; +} + +/** + * Just a destructor. + * ----- + * assembly: +; 59 virtual ~nsGetServiceByCID() {}; + align 010h + +__dt__17nsGetServiceByCIDFv proc + push ebp + mov ebp,esp + sub esp,08h + mov [ebp+08h],eax; this + mov [ebp+0ch],edx; __dtorFlags + mov [ebp+010h],ecx; __vtt + mov eax,[ebp+08h]; this + mov dword ptr [eax],offset FLAT:__vft17nsGetServiceByCID15nsCOMPtr_helper + mov edx,02h + mov eax,[ebp+08h]; this + add eax,08h + call __dt__8nsCOMPtrXT17nsIServiceManager_Fv + test byte ptr [ebp+0ch],01h; __dtorFlags + je @BLBL24 + mov eax,[ebp+08h]; this + call __dl__FPv +@BLBL24: + mov eax,[ebp+08h]; this + add esp,08h + pop ebp + ret +__dt__17nsGetServiceByCIDFv endp + */ +extern "C" void * VFTCALL GSBC_COM__destructor(void *pvThis, unsigned __dtorFlags, unsigned __vtt) +{ + obj_nsGetServiceByCID_nsCOMPtr_helper *pThis = (obj_nsGetServiceByCID_nsCOMPtr_helper *)pvThis; +//asm("int $3"); + + /* + * Because previously mentioned issues with VAC heaps, we'll + * not do anything in here. + * (We will then skip destruction of all parents and such, but + * I don't think that will hurt anyone.) + */ + __dtorFlags = __dtorFlags; + __vtt = __vtt; + return pThis; +} + + +/** + * VFT for nsGetServiceByCID::nsCOMPtr_helper or something like that. + * It's just implementing an operator() and the destructor. + * + * @remark We need to skip an underscore to get the name right. + * ---- + * assembly: +__vft17nsGetServiceByCID15nsCOMPtr_helper dd 0 + db 0h,0h,0h,0h + dd offset FLAT:__cl__17nsGetServiceByCIDCFRC4nsIDPPv + db 0h,0h,0h,0h + dd offset FLAT:__dt__17nsGetServiceByCIDFv + db 0h,0h,0h,0h + */ +extern const VFTnsGetServiceByCID_nsCOMPtr_helper _vft17nsGetServiceByCID15nsCOMPtr_helper = +{ + VFTFIRST_VAL() + GSBC_COM__operator_paratheses, VFTDELTA_VAL() + GSBC_COM__destructor, VFTDELTA_VAL() +}; + + + +/** + * + * ----- + * assembly +; 42 nsQueryInterface::operator()( const nsIID& aIID, void** answer ) const + align 010h + + public __cl__16nsQueryInterfaceCFRC4nsIDPPv +__cl__16nsQueryInterfaceCFRC4nsIDPPv proc + push ebp + mov ebp,esp + sub esp,08h + push ebx + sub esp,0ch + mov [ebp+08h],eax; this + mov [ebp+0ch],edx; aIID + mov [ebp+010h],ecx; answer + +; 45 if ( mRawPtr ) + mov eax,[ebp+08h]; this + cmp dword ptr [eax+04h],0h + je @BLBL1 + +; 46 { +; 47 status = mRawPtr->QueryInterface(aIID, answer); + mov ecx,[ebp+010h]; answer + mov edx,[ebp+0ch]; aIID + mov ebx,[ebp+08h]; this + mov ebx,[ebx+04h] + mov ebx,[ebx] + mov eax,[ebp+08h]; this + mov eax,[eax+04h] + add eax,[ebx+0ch] + mov ebx,[ebp+08h]; this + mov ebx,[ebx+04h] + mov ebx,[ebx] + call dword ptr [ebx+08h] + mov [ebp-04h],eax; status + +; 48 #ifdef NSCAP_FEATURE_TEST_NONNULL_QUERY_SUCCEEDS +; 49 NS_WARN_IF_FALSE(NS_SUCCEEDED(status), "interface not found---were you expecting that?"); +; 50 #endif +; 51 } + jmp @BLBL2 + align 010h +@BLBL1: + +; 45 if ( mRawPtr ) + +; 53 status = NS_ERROR_NULL_POINTER; + mov dword ptr [ebp-04h],080004003h; status +@BLBL2: + +; 55 if ( mErrorPtr ) + mov eax,[ebp+08h]; this + cmp dword ptr [eax+08h],0h + je @BLBL3 + +; 56 *mErrorPtr = status; + mov eax,[ebp+08h]; this + mov eax,[eax+08h] + mov ebx,[ebp-04h]; status + mov [eax],ebx +@BLBL3: + +; 57 return status; + mov eax,[ebp-04h]; status + add esp,0ch + pop ebx + mov esp,ebp + pop ebp + ret +__cl__16nsQueryInterfaceCFRC4nsIDPPv endp + + * ----- + * C++ Code: +nsresult +nsQueryInterface::operator()( const nsIID& aIID, void** answer ) const + { + nsresult status; + if ( mRawPtr ) + { + status = mRawPtr->QueryInterface(aIID, answer); +#ifdef NSCAP_FEATURE_TEST_NONNULL_QUERY_SUCCEEDS + NS_WARN_IF_FALSE(NS_SUCCEEDED(status), "interface not found---were you expecting that?"); +#endif + } + else + status = NS_ERROR_NULL_POINTER; + + if ( mErrorPtr ) + *mErrorPtr = status; + return status; + } + */ +extern "C" nsresult VFTCALL QI_COM__operator_paratheses(void *pvThis, REFNSIID aIID, void** aInstancePtr) +{ + obj_nsQueryInterface_nsCOMPtr_helper *pThis = (obj_nsQueryInterface_nsCOMPtr_helper *)pvThis; + nsresult status = NS_ERROR_NULL_POINTER; +//asm("int $3"); + + if (pThis->mRawPtr) + { + status = pThis->mRawPtr->pVFT->QueryInterface(pThis->mRawPtr, aIID, aInstancePtr); + /* don't care about warnings, do we? */ + } + + if (pThis->mErrorPtr) + *pThis->mErrorPtr = status; + return status; +} + + + +/** + * VFT for nsQueryInterface::nsCOMPtr_helper or something like that. + * No destructor, only an operator(). + * + * @remark We need to skip an underscore to get the name right. + * ----- + * assembly: +__vft16nsQueryInterface15nsCOMPtr_helper dd 0 + db 0h,0h,0h,0h + dd offset FLAT:__cl__16nsQueryInterfaceCFRC4nsIDPPv + db 0h,0h,0h,0h + */ +extern const VFTnsQueryInterface_nsCOMPtr_helper _vft16nsQueryInterface15nsCOMPtr_helper = +{ + VFTFIRST_VAL() + QI_COM__operator_paratheses, VFTDELTA_VAL() +}; + +/** + * + * ----- + * C++ Code: +void +assign_assuming_AddRef( nsISupports* newPtr ) +{ + / * + |AddRef()|ing the new value (before entering this function) before + |Release()|ing the old lets us safely ignore the self-assignment case. + We must, however, be careful only to |Release()| _after_ doing the + assignment, in case the |Release()| leads to our _own_ destruction, + which would, in turn, cause an incorrect second |Release()| of our old + pointer. Thank for discovering this. + * / + nsISupports* oldPtr = mRawPtr; + mRawPtr = newPtr; + NSCAP_LOG_ASSIGNMENT(this, newPtr); + NSCAP_LOG_RELEASE(this, oldPtr); + if ( oldPtr ) + NSCAP_RELEASE(this, oldPtr); +} + */ +extern "C" void VFTCALL assign_assuming_AddRef__13nsCOMPtr_baseFP11nsISupports(void *pvThis, obj_nsISupports *newPtr) +{ + obj_nsCOMPtr_base *pThis = (obj_nsCOMPtr_base *)pvThis; + obj_nsISupports *oldPtr; + + oldPtr = pThis->mRawPtr; + pThis->mRawPtr = newPtr; + if (oldPtr) + { + /* NSCAP_RELEASE(this, oldPtr); */ + pThis->mRawPtr->pVFT->Release(oldPtr + oldPtr->pVFT->uDeltaRelease); + } +} + + + + +/** + * + * ----- + * Assembly: +; 77 nsCOMPtr_base::assign_from_helper( const nsCOMPtr_helper& helper, const nsIID& iid ) + align 010h + + public assign_from_helper__13nsCOMPtr_baseFRC15nsCOMPtr_helperRC4nsID +assign_from_helper__13nsCOMPtr_baseFRC15nsCOMPtr_helperRC4nsID proc + push ebp + mov ebp,esp + sub esp,08h + push ebx + sub esp,0ch + mov [ebp+08h],eax; this + mov [ebp+0ch],edx; helper + mov [ebp+010h],ecx; iid + +; 80 if ( NS_FAILED( helper(iid, NS_REINTERPRET_CAST(void**, &newRawPtr)) ) ) + lea ecx,[ebp-04h]; newRawPtr + mov edx,[ebp+010h]; iid + mov ebx,[ebp+0ch]; helper + mov ebx,[ebx] + mov eax,[ebp+0ch]; helper + add eax,[ebx+0ch] + mov ebx,[ebp+0ch]; helper + mov ebx,[ebx] + call dword ptr [ebx+08h] + test eax,080000000h + je @BLBL8 + +; 81 newRawPtr = 0; + mov dword ptr [ebp-04h],0h; newRawPtr +@BLBL8: + +; 82 assign_assuming_AddRef(newRawPtr); + mov edx,[ebp-04h]; newRawPtr + mov eax,[ebp+08h]; this + call assign_assuming_AddRef__13nsCOMPtr_baseFP11nsISupports + add esp,0ch + pop ebx + mov esp,ebp + pop ebp + ret +assign_from_helper__13nsCOMPtr_baseFRC15nsCOMPtr_helperRC4nsID endp + + * ----- + * C Code: +void +nsCOMPtr_base::assign_from_helper( const nsCOMPtr_helper& helper, const nsIID& iid ) + { + nsISupports* newRawPtr; + if ( NS_FAILED( helper(iid, NS_REINTERPRET_CAST(void**, &newRawPtr)) ) ) + newRawPtr = 0; + assign_assuming_AddRef(newRawPtr); + } + */ +extern "C" void VFTCALL assign_from_helper__13nsCOMPtr_baseFRC15nsCOMPtr_helperRC4nsID( + void *pvThis, void * helper, REFNSIID iid) +{ + obj_nsCOMPtr_base *pThis = (obj_nsCOMPtr_base *)pvThis; + obj_nsISupports* newRawPtr = NULL; + nsresult status = NS_ERROR_FAILURE; +//asm("int $3"); + + /* this may or may not be correct but the layout is the same. */ + obj_nsQueryInterface_nsCOMPtr_helper * pHelper = (obj_nsQueryInterface_nsCOMPtr_helper*)helper; + + /* if ( NS_FAILED( helper(iid, NS_REINTERPRET_CAST(void**, &newRawPtr)) ) ) */ + status = pHelper->pVFT->__operator_paratheses((char*)pHelper + pHelper->pVFT->uDelta__operator_paratheses, + iid, (void**)&newRawPtr); + if (NS_FAILED(status)) + newRawPtr = 0; + + /* assign_assuming_AddRef(newRawPtr); */ + assign_assuming_AddRef__13nsCOMPtr_baseFP11nsISupports(pThis, newRawPtr); +} + + + diff --git a/src/libs/xpcom18a4/xpcom/build/nsStringAPI.cpp b/src/libs/xpcom18a4/xpcom/build/nsStringAPI.cpp new file mode 100644 index 00000000..ca9a76e4 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/build/nsStringAPI.cpp @@ -0,0 +1,261 @@ +/* vim:set ts=2 sw=2 et cindent: */ +/* ***** 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 IBM Corporation. + * Portions created by IBM Corporation are Copyright (C) 2003 + * IBM Corporation. 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 "nsString.h" +#include "nsCharTraits.h" + +#define NS_STRINGAPI_IMPL +#include "nsStringAPI.h" +#include "nsNativeCharsetUtils.h" + +/* ------------------------------------------------------------------------- */ + +NS_STRINGAPI(nsresult) +NS_StringContainerInit(nsStringContainer &aContainer) +{ + NS_ASSERTION(sizeof(nsStringContainer) >= sizeof(nsString), + "nsStringContainer is not large enough"); + + // use placement new to avoid heap allocating nsString object + new (&aContainer) nsString(); + + return NS_OK; +} + +NS_STRINGAPI(void) +NS_StringContainerFinish(nsStringContainer &aContainer) +{ + // call the nsString dtor + NS_REINTERPRET_CAST(nsString *, &aContainer)->~nsString(); +} + +/* ------------------------------------------------------------------------- */ + +NS_STRINGAPI(PRUint32) +NS_StringGetData(const nsAString &aStr, const PRUnichar **aData, + PRBool *aTerminated) +{ + if (aTerminated) + *aTerminated = aStr.IsTerminated(); + + nsAString::const_iterator begin; + aStr.BeginReading(begin); + *aData = begin.get(); + return begin.size_forward(); +} + +NS_STRINGAPI(PRUnichar *) +NS_StringCloneData(const nsAString &aStr) +{ + return ToNewUnicode(aStr); +} + +NS_STRINGAPI(nsresult) +NS_StringSetData(nsAString &aStr, const PRUnichar *aData, PRUint32 aDataLength) +{ + aStr.Assign(aData, aDataLength); + return NS_OK; // XXX report errors +} + +NS_STRINGAPI(nsresult) +NS_StringSetDataRange(nsAString &aStr, + PRUint32 aCutOffset, PRUint32 aCutLength, + const PRUnichar *aData, PRUint32 aDataLength) +{ + if (aCutOffset == PR_UINT32_MAX) + { + // append case + if (aData) + aStr.Append(aData, aDataLength); + return NS_OK; // XXX report errors + } + + if (aCutLength == PR_UINT32_MAX) + aCutLength = aStr.Length() - aCutOffset; + + if (aData) + { + if (aDataLength == PR_UINT32_MAX) + aStr.Replace(aCutOffset, aCutLength, nsDependentString(aData)); + else + aStr.Replace(aCutOffset, aCutLength, Substring(aData, aData + aDataLength)); + } + else + aStr.Cut(aCutOffset, aCutLength); + + return NS_OK; // XXX report errors +} + +NS_STRINGAPI(nsresult) +NS_StringCopy(nsAString &aDest, const nsAString &aSrc) +{ + aDest.Assign(aSrc); + return NS_OK; // XXX report errors +} + +/* ------------------------------------------------------------------------- */ + +NS_STRINGAPI(nsresult) +NS_CStringContainerInit(nsCStringContainer &aContainer) +{ + NS_ASSERTION(sizeof(nsCStringContainer) >= sizeof(nsCString), + "nsCStringContainer is not large enough"); + + // use placement new to avoid heap allocating nsCString object + new (&aContainer) nsCString(); + + return NS_OK; +} + +NS_STRINGAPI(void) +NS_CStringContainerFinish(nsCStringContainer &aContainer) +{ + // call the nsCString dtor + NS_REINTERPRET_CAST(nsCString *, &aContainer)->~nsCString(); +} + +/* ------------------------------------------------------------------------- */ + +NS_STRINGAPI(PRUint32) +NS_CStringGetData(const nsACString &aStr, const char **aData, + PRBool *aTerminated) +{ + if (aTerminated) + *aTerminated = aStr.IsTerminated(); + + nsACString::const_iterator begin; + aStr.BeginReading(begin); + *aData = begin.get(); + return begin.size_forward(); +} + +NS_STRINGAPI(char *) +NS_CStringCloneData(const nsACString &aStr) +{ + return ToNewCString(aStr); +} + +NS_STRINGAPI(nsresult) +NS_CStringSetData(nsACString &aStr, const char *aData, PRUint32 aDataLength) +{ + aStr.Assign(aData, aDataLength); + return NS_OK; // XXX report errors +} + +NS_STRINGAPI(nsresult) +NS_CStringSetDataRange(nsACString &aStr, + PRUint32 aCutOffset, PRUint32 aCutLength, + const char *aData, PRUint32 aDataLength) +{ + if (aCutOffset == PR_UINT32_MAX) + { + // append case + if (aData) + aStr.Append(aData, aDataLength); + return NS_OK; // XXX report errors + } + + if (aCutLength == PR_UINT32_MAX) + aCutLength = aStr.Length() - aCutOffset; + + if (aData) + { + if (aDataLength == PR_UINT32_MAX) + aStr.Replace(aCutOffset, aCutLength, nsDependentCString(aData)); + else + aStr.Replace(aCutOffset, aCutLength, Substring(aData, aData + aDataLength)); + } + else + aStr.Cut(aCutOffset, aCutLength); + + return NS_OK; // XXX report errors +} + +NS_STRINGAPI(nsresult) +NS_CStringCopy(nsACString &aDest, const nsACString &aSrc) +{ + aDest.Assign(aSrc); + return NS_OK; // XXX report errors +} + +/* ------------------------------------------------------------------------- */ + +NS_STRINGAPI(nsresult) +NS_CStringToUTF16(const nsACString &aSrc, + nsCStringEncoding aSrcEncoding, + nsAString &aDest) +{ + switch (aSrcEncoding) + { + case NS_CSTRING_ENCODING_ASCII: + CopyASCIItoUTF16(aSrc, aDest); + break; + case NS_CSTRING_ENCODING_UTF8: + CopyUTF8toUTF16(aSrc, aDest); + break; + case NS_CSTRING_ENCODING_NATIVE_FILESYSTEM: + NS_CopyNativeToUnicode(aSrc, aDest); + break; + default: + return NS_ERROR_NOT_IMPLEMENTED; + } + + return NS_OK; // XXX report errors +} + +NS_STRINGAPI(nsresult) +NS_UTF16ToCString(const nsAString &aSrc, + nsCStringEncoding aDestEncoding, + nsACString &aDest) +{ + switch (aDestEncoding) + { + case NS_CSTRING_ENCODING_ASCII: + LossyCopyUTF16toASCII(aSrc, aDest); + break; + case NS_CSTRING_ENCODING_UTF8: + CopyUTF16toUTF8(aSrc, aDest); + break; + case NS_CSTRING_ENCODING_NATIVE_FILESYSTEM: + NS_CopyUnicodeToNative(aSrc, aDest); + break; + default: + return NS_ERROR_NOT_IMPLEMENTED; + } + + return NS_OK; // XXX report errors +} diff --git a/src/libs/xpcom18a4/xpcom/build/nsXPCOM.h b/src/libs/xpcom18a4/xpcom/build/nsXPCOM.h new file mode 100644 index 00000000..4e60c74e --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/build/nsXPCOM.h @@ -0,0 +1,217 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +#ifndef nsXPCOM_h__ +#define nsXPCOM_h__ + +#include "nscore.h" +#include "nsXPCOMCID.h" + +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +#define NS_InitXPCOM2 VBoxNsxpNS_InitXPCOM2 +#define NS_ShutdownXPCOM VBoxNsxpNS_ShutdownXPCOM +#define NS_NewNativeLocalFile VBoxNsxpNS_NewNativeLocalFile +#define NS_GetServiceManager VBoxNsxpNS_GetServiceManager +#define NS_GetComponentManager VBoxNsxpNS_GetComponentManager +#define NS_GetComponentRegistrar VBoxNsxpNS_GetComponentRegistrar +#define NS_GetDebug VBoxNsxpNS_GetDebug +#define NS_GetMemoryManager VBoxNsxpNS_GetMemoryManager +#define NS_GetTraceRefcnt VBoxNsxpNS_GetTraceRefcnt +#define NS_NewLocalFile VBoxNsxpNS_NewLocalFile +#endif /* VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + +class nsAString; +class nsACString; + +class nsIComponentManager; +class nsIComponentRegistrar; +class nsIServiceManager; +class nsIFile; +class nsILocalFile; +class nsIDirectoryServiceProvider; +class nsIMemory; +class nsIDebug; +class nsITraceRefcnt; + +/** + * Initialises XPCOM. You must call this method before proceeding + * to use xpcom. The one exception is that you may call + * NS_NewLocalFile to create a nsIFile. + * + * @status FROZEN + * + * @note Use NS_NewLocalFile or NS_NewNativeLocalFile + * to create the file object you supply as the bin directory path in this + * call. The function may be safely called before the rest of XPCOM or + * embedding has been initialised. + * + * @param result The service manager. You may pass null. + * + * @param binDirectory The directory containing the component + * registry and runtime libraries; + * or use nsnull to use the working + * directory. + * + * @param appFileLocationProvider The object to be used by Gecko that specifies + * to Gecko where to find profiles, the component + * registry preferences and so on; or use + * nsnull for the default behaviour. + * + * @see NS_NewLocalFile + * @see nsILocalFile + * @see nsIDirectoryServiceProvider + * + * @return NS_OK for success; + * NS_ERROR_NOT_INITIALIZED if static globals were not initialied, which + * can happen if XPCOM is reloaded, but did not completly shutdown. + * other error codes indicate a failure during initialisation. + * + */ +extern "C" NS_COM nsresult +NS_InitXPCOM2(nsIServiceManager* *result, + nsIFile* binDirectory, + nsIDirectoryServiceProvider* appFileLocationProvider); +/** + * Shutdown XPCOM. You must call this method after you are finished + * using xpcom. + * + * @status FROZEN + * + * @param servMgr The service manager which was returned by NS_InitXPCOM2. + * This will release servMgr. You may pass null. + * + * @return NS_OK for success; + * other error codes indicate a failure during initialisation. + * + */ +extern "C" NS_COM nsresult +NS_ShutdownXPCOM(nsIServiceManager* servMgr); + + +/** + * Public Method to access to the service manager. + * + * @status FROZEN + * @param result Interface pointer to the service manager + * + * @return NS_OK for success; + * other error codes indicate a failure during initialisation. + * + */ +extern "C" NS_COM nsresult +NS_GetServiceManager(nsIServiceManager* *result); + +/** + * Public Method to access to the component manager. + * + * @status FROZEN + * @param result Interface pointer to the service + * + * @return NS_OK for success; + * other error codes indicate a failure during initialisation. + * + */ +extern "C" NS_COM nsresult +NS_GetComponentManager(nsIComponentManager* *result); + +/** + * Public Method to access to the component registration manager. + * + * @status FROZEN + * @param result Interface pointer to the service + * + * @return NS_OK for success; + * other error codes indicate a failure during initialisation. + * + */ +extern "C" NS_COM nsresult +NS_GetComponentRegistrar(nsIComponentRegistrar* *result); + +/** + * Public Method to access to the memory manager. See nsIMemory + * + * @status FROZEN + * @param result Interface pointer to the memory manager + * + * @return NS_OK for success; + * other error codes indicate a failure during initialisation. + * + */ +extern "C" NS_COM nsresult +NS_GetMemoryManager(nsIMemory* *result); + +/** + * Public Method to create an instance of a nsILocalFile. This function + * may be called prior to NS_InitXPCOM2. + * + * @status FROZEN + * + * @param path + * A string which specifies a full file path to a + * location. Relative paths will be treated as an + * error (NS_ERROR_FILE_UNRECOGNIZED_PATH). + * |NS_NewNativeLocalFile|'s path must be in the + * filesystem charset. + * @param followLinks + * This attribute will determine if the nsLocalFile will auto + * resolve symbolic links. By default, this value will be false + * on all non unix systems. On unix, this attribute is effectively + * a noop. + * @param result Interface pointer to a new instance of an nsILocalFile + * + * @return NS_OK for success; + * other error codes indicate a failure. + */ + +extern "C" NS_COM nsresult +NS_NewLocalFile(const nsAString &path, + PRBool followLinks, + nsILocalFile* *result); + +extern "C" NS_COM nsresult +NS_NewNativeLocalFile(const nsACString &path, + PRBool followLinks, + nsILocalFile* *result); + + +extern "C" NS_COM nsresult +NS_GetDebug(nsIDebug* *result); + +extern "C" NS_COM nsresult +NS_GetTraceRefcnt(nsITraceRefcnt* *result); + +#endif diff --git a/src/libs/xpcom18a4/xpcom/build/nsXPCOMCID.h b/src/libs/xpcom18a4/xpcom/build/nsXPCOMCID.h new file mode 100644 index 00000000..d5bd039c --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/build/nsXPCOMCID.h @@ -0,0 +1,174 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +#ifndef nsXPCOMCID_h__ +#define nsXPCOMCID_h__ + +/** + * XPCOM Directory Service Contract ID + * The directory service provides ways to obtain file system locations. The + * directory service is a singleton. + * + * This contract supports the nsIDirectoryService and the nsIProperties + * interfaces. + * + */ +#define NS_DIRECTORY_SERVICE_CONTRACTID "@mozilla.org/file/directory_service;1" + +/** + * XPCOM File + * The file abstraction provides ways to obtain and access files and + * directories located on the local system. + * + * This contract supports the nsIFile interface and the nsILocalFile interface. + * This contract may also support platform specific interfaces such as + * nsILocalFileMac on platforms where additional interfaces are required. + * + */ +#define NS_LOCAL_FILE_CONTRACTID "@mozilla.org/file/local;1" + +/** + * XPCOM Category Manager Contract ID + * The contract supports the nsICategoryManager interface. The + * category manager is a singleton. + */ +#define NS_CATEGORYMANAGER_CONTRACTID "@mozilla.org/categorymanager;1" + +/** + * XPCOM Properties Object Contract ID + * Simple mapping object which supports the nsIProperties interface. + */ +#define NS_PROPERTIES_CONTRACTID "@mozilla.org/properties;1" + +/** + * XPCOM Array Object ContractID + * Simple array implementation which supports the nsIArray and + * nsIMutableArray interfaces. + */ +#define NS_ARRAY_CONTRACTID "@mozilla.org/array;1" + +/** + * The following are the CIDs and Contract IDs of the nsISupports wrappers for + * primative types. + */ +#define NS_SUPPORTS_ID_CID \ +{ 0xacf8dc40, 0x4a25, 0x11d3, \ +{ 0x98, 0x90, 0x0, 0x60, 0x8, 0x96, 0x24, 0x22 } } +#define NS_SUPPORTS_ID_CONTRACTID "@mozilla.org/supports-id;1" + +#define NS_SUPPORTS_CSTRING_CID \ +{ 0xacf8dc41, 0x4a25, 0x11d3, \ +{ 0x98, 0x90, 0x0, 0x60, 0x8, 0x96, 0x24, 0x22 } } +#define NS_SUPPORTS_CSTRING_CONTRACTID "@mozilla.org/supports-cstring;1" + +#define NS_SUPPORTS_STRING_CID \ +{ 0xacf8dc42, 0x4a25, 0x11d3, \ +{ 0x98, 0x90, 0x0, 0x60, 0x8, 0x96, 0x24, 0x22 } } +#define NS_SUPPORTS_STRING_CONTRACTID "@mozilla.org/supports-string;1" + +#define NS_SUPPORTS_PRBOOL_CID \ +{ 0xacf8dc43, 0x4a25, 0x11d3, \ +{ 0x98, 0x90, 0x0, 0x60, 0x8, 0x96, 0x24, 0x22 } } +#define NS_SUPPORTS_PRBOOL_CONTRACTID "@mozilla.org/supports-PRBool;1" + +#define NS_SUPPORTS_PRUINT8_CID \ +{ 0xacf8dc44, 0x4a25, 0x11d3, \ +{ 0x98, 0x90, 0x0, 0x60, 0x8, 0x96, 0x24, 0x22 } } +#define NS_SUPPORTS_PRUINT8_CONTRACTID "@mozilla.org/supports-PRUint8;1" + +#define NS_SUPPORTS_PRUINT16_CID \ +{ 0xacf8dc46, 0x4a25, 0x11d3, \ +{ 0x98, 0x90, 0x0, 0x60, 0x8, 0x96, 0x24, 0x22 } } +#define NS_SUPPORTS_PRUINT16_CONTRACTID "@mozilla.org/supports-PRUint16;1" + +#define NS_SUPPORTS_PRUINT32_CID \ +{ 0xacf8dc47, 0x4a25, 0x11d3, \ +{ 0x98, 0x90, 0x0, 0x60, 0x8, 0x96, 0x24, 0x22 } } +#define NS_SUPPORTS_PRUINT32_CONTRACTID "@mozilla.org/supports-PRUint32;1" + +#define NS_SUPPORTS_PRUINT64_CID \ +{ 0xacf8dc48, 0x4a25, 0x11d3, \ +{ 0x98, 0x90, 0x0, 0x60, 0x8, 0x96, 0x24, 0x22 } } +#define NS_SUPPORTS_PRUINT64_CONTRACTID "@mozilla.org/supports-PRUint64;1" + +#define NS_SUPPORTS_PRTIME_CID \ +{ 0xacf8dc49, 0x4a25, 0x11d3, \ +{ 0x98, 0x90, 0x0, 0x60, 0x8, 0x96, 0x24, 0x22 } } +#define NS_SUPPORTS_PRTIME_CONTRACTID "@mozilla.org/supports-PRTime;1" + +#define NS_SUPPORTS_CHAR_CID \ +{ 0xacf8dc4a, 0x4a25, 0x11d3, \ +{ 0x98, 0x90, 0x0, 0x60, 0x8, 0x96, 0x24, 0x22 } } +#define NS_SUPPORTS_CHAR_CONTRACTID "@mozilla.org/supports-char;1" + +#define NS_SUPPORTS_PRINT16_CID \ +{ 0xacf8dc4b, 0x4a25, 0x11d3, \ +{ 0x98, 0x90, 0x0, 0x60, 0x8, 0x96, 0x24, 0x22 } } +#define NS_SUPPORTS_PRINT16_CONTRACTID "@mozilla.org/supports-PRInt16;1" + +#define NS_SUPPORTS_PRINT32_CID \ +{ 0xacf8dc4c, 0x4a25, 0x11d3, \ +{ 0x98, 0x90, 0x0, 0x60, 0x8, 0x96, 0x24, 0x22 } } +#define NS_SUPPORTS_PRINT32_CONTRACTID "@mozilla.org/supports-PRInt32;1" + +#define NS_SUPPORTS_PRINT64_CID \ +{ 0xacf8dc4d, 0x4a25, 0x11d3, \ +{ 0x98, 0x90, 0x0, 0x60, 0x8, 0x96, 0x24, 0x22 } } +#define NS_SUPPORTS_PRINT64_CONTRACTID "@mozilla.org/supports-PRInt64;1" + +#define NS_SUPPORTS_FLOAT_CID \ +{ 0xcbf86870, 0x4ac0, 0x11d3, \ +{ 0xba, 0xea, 0x0, 0x80, 0x5f, 0x8a, 0x5d, 0xd7 } } +#define NS_SUPPORTS_FLOAT_CONTRACTID "@mozilla.org/supports-float;1" + +#define NS_SUPPORTS_DOUBLE_CID \ +{ 0xcbf86871, 0x4ac0, 0x11d3, \ +{ 0xba, 0xea, 0x0, 0x80, 0x5f, 0x8a, 0x5d, 0xd7 } } +#define NS_SUPPORTS_DOUBLE_CONTRACTID "@mozilla.org/supports-double;1" + +#define NS_SUPPORTS_VOID_CID \ +{ 0xaf10f3e0, 0x568d, 0x11d3, \ +{ 0xba, 0xf8, 0x0, 0x80, 0x5f, 0x8a, 0x5d, 0xd7 } } +#define NS_SUPPORTS_VOID_CONTRACTID "@mozilla.org/supports-void;1" + +#define NS_SUPPORTS_INTERFACE_POINTER_CID \ +{ 0xA99FEBBA, 0x1DD1, 0x11B2, \ +{ 0xA9, 0x43, 0xB0, 0x23, 0x34, 0xA6, 0xD0, 0x83 } } +#define NS_SUPPORTS_INTERFACE_POINTER_CONTRACTID "@mozilla.org/supports-interface-pointer;1" + + +#endif diff --git a/src/libs/xpcom18a4/xpcom/build/nsXPCOMPrivate.h b/src/libs/xpcom18a4/xpcom/build/nsXPCOMPrivate.h new file mode 100644 index 00000000..cd526ba3 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/build/nsXPCOMPrivate.h @@ -0,0 +1,228 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* vim:set ts=4 sw=4 et cindent: */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +#ifndef nsXPComPrivate_h__ +#define nsXPComPrivate_h__ + +#include "nscore.h" +#include "nsXPCOM.h" + +class nsStringContainer; +class nsCStringContainer; + +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +#define NS_GetFrozenFunctions VBoxNsxpNS_GetFrozenFunctions +#define NS_RegisterXPCOMExitRoutine VBoxNsxpNS_RegisterXPCOMExitRoutine +#define NS_UnregisterXPCOMExitRoutine VBoxNsxpNS_UnregisterXPCOMExitRoutine +#endif /* VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + +/** + * Private Method to register an exit routine. This method + * allows you to setup a callback that will be called from + * the NS_ShutdownXPCOM function after all services and + * components have gone away. + * + * This API is for the exclusive use of the xpcom glue library. + * + * Note that these APIs are NOT threadsafe and must be called on the + * main thread. + * + * @status FROZEN + * @param exitRoutine pointer to user defined callback function + * of type XPCOMExitRoutine. + * @param priority higher priorities are called before lower + * priorities. + * + * @return NS_OK for success; + * other error codes indicate a failure. + * + */ +typedef NS_CALLBACK(XPCOMExitRoutine)(void); + +extern "C" NS_COM nsresult +NS_RegisterXPCOMExitRoutine(XPCOMExitRoutine exitRoutine, PRUint32 priority); + +extern "C" NS_COM nsresult +NS_UnregisterXPCOMExitRoutine(XPCOMExitRoutine exitRoutine); + + +// PUBLIC +typedef nsresult (* InitFunc)(nsIServiceManager* *result, nsIFile* binDirectory, nsIDirectoryServiceProvider* appFileLocationProvider); +typedef nsresult (* ShutdownFunc)(nsIServiceManager* servMgr); +typedef nsresult (* GetServiceManagerFunc)(nsIServiceManager* *result); +typedef nsresult (* GetComponentManagerFunc)(nsIComponentManager* *result); +typedef nsresult (* GetComponentRegistrarFunc)(nsIComponentRegistrar* *result); +typedef nsresult (* GetMemoryManagerFunc)(nsIMemory* *result); +typedef nsresult (* NewLocalFileFunc)(const nsAString &path, PRBool followLinks, nsILocalFile* *result); +typedef nsresult (* NewNativeLocalFileFunc)(const nsACString &path, PRBool followLinks, nsILocalFile* *result); + +typedef nsresult (* GetDebugFunc)(nsIDebug* *result); +typedef nsresult (* GetTraceRefcntFunc)(nsITraceRefcnt* *result); + +typedef nsresult (* StringContainerInitFunc)(nsStringContainer&); +typedef void (* StringContainerFinishFunc)(nsStringContainer&); +typedef PRUint32 (* StringGetDataFunc)(const nsAString&, const PRUnichar**, PRBool*); +typedef PRUnichar* (* StringCloneDataFunc)(const nsAString&); +typedef nsresult (* StringSetDataFunc)(nsAString&, const PRUnichar*, PRUint32); +typedef nsresult (* StringSetDataRangeFunc)(nsAString&, PRUint32, PRUint32, const PRUnichar*, PRUint32); +typedef nsresult (* StringCopyFunc)(nsAString &, const nsAString &); + +typedef nsresult (* CStringContainerInitFunc)(nsCStringContainer&); +typedef void (* CStringContainerFinishFunc)(nsCStringContainer&); +typedef PRUint32 (* CStringGetDataFunc)(const nsACString&, const char**, PRBool*); +typedef char* (* CStringCloneDataFunc)(const nsACString&); +typedef nsresult (* CStringSetDataFunc)(nsACString&, const char*, PRUint32); +typedef nsresult (* CStringSetDataRangeFunc)(nsACString&, PRUint32, PRUint32, const char*, PRUint32); +typedef nsresult (* CStringCopyFunc)(nsACString &, const nsACString &); + +typedef nsresult (* CStringToUTF16)(const nsACString &, PRUint32, const nsAString &); +typedef nsresult (* UTF16ToCString)(const nsAString &, PRUint32, const nsACString &); + +// PRIVATE +typedef nsresult (* RegisterXPCOMExitRoutineFunc)(XPCOMExitRoutine exitRoutine, PRUint32 priority); +typedef nsresult (* UnregisterXPCOMExitRoutineFunc)(XPCOMExitRoutine exitRoutine); + +typedef struct XPCOMFunctions{ + PRUint32 version; + PRUint32 size; + + InitFunc init; + ShutdownFunc shutdown; + GetServiceManagerFunc getServiceManager; + GetComponentManagerFunc getComponentManager; + GetComponentRegistrarFunc getComponentRegistrar; + GetMemoryManagerFunc getMemoryManager; + NewLocalFileFunc newLocalFile; + NewNativeLocalFileFunc newNativeLocalFile; + + RegisterXPCOMExitRoutineFunc registerExitRoutine; + UnregisterXPCOMExitRoutineFunc unregisterExitRoutine; + + // Added for Mozilla 1.5 + GetDebugFunc getDebug; + GetTraceRefcntFunc getTraceRefcnt; + + // Added for Mozilla 1.7 + StringContainerInitFunc stringContainerInit; + StringContainerFinishFunc stringContainerFinish; + StringGetDataFunc stringGetData; + StringSetDataFunc stringSetData; + StringSetDataRangeFunc stringSetDataRange; + StringCopyFunc stringCopy; + CStringContainerInitFunc cstringContainerInit; + CStringContainerFinishFunc cstringContainerFinish; + CStringGetDataFunc cstringGetData; + CStringSetDataFunc cstringSetData; + CStringSetDataRangeFunc cstringSetDataRange; + CStringCopyFunc cstringCopy; + CStringToUTF16 cstringToUTF16; + UTF16ToCString utf16ToCString; + StringCloneDataFunc stringCloneData; + CStringCloneDataFunc cstringCloneData; + +} XPCOMFunctions; + +typedef nsresult (PR_CALLBACK *GetFrozenFunctionsFunc)(XPCOMFunctions *entryPoints, const char* libraryPath); +extern "C" NS_COM nsresult +NS_GetFrozenFunctions(XPCOMFunctions *entryPoints, const char* libraryPath); + +// think hard before changing this +#define XPCOM_GLUE_VERSION 1 + + +/* XPCOM Specific Defines + * + * XPCOM_DLL - name of the loadable xpcom library on disk. + * XPCOM_SEARCH_KEY - name of the environment variable that can be + * modified to include additional search paths. + * GRE_CONF_NAME - Name of the GRE Configuration file + */ + +#ifdef XPCOM_DLL_BASE +#define XPCOM_DLL XPCOM_DLL_BASE MOZ_DLL_SUFFIX +#endif + +#if defined(XP_WIN32) || defined(XP_OS2) + +#define XPCOM_SEARCH_KEY "PATH" +#define GRE_CONF_NAME "gre.config" +#define GRE_WIN_REG_LOC "Software\\mozilla.org\\GRE\\" +#ifndef XPCOM_DLL +#define XPCOM_DLL "xpcom"MOZ_DLL_SUFFIX +#endif + +#elif defined(XP_BEOS) + +#define XPCOM_SEARCH_KEY "ADDON_PATH" +#define GRE_CONF_NAME ".gre.config" +#define GRE_CONF_PATH "/boot/home/config/settings/GRE/gre.conf" +#ifndef XPCOM_DLL +#define XPCOM_DLL "libxpcom"MOZ_DLL_SUFFIX +#endif + +#else // Unix + +#ifndef XPCOM_DLL +#define XPCOM_DLL "libxpcom"MOZ_DLL_SUFFIX +#endif + +// you have to love apple.. +#ifdef XP_MACOSX +#define XPCOM_SEARCH_KEY "DYLD_LIBRARY_PATH" +#else +#define XPCOM_SEARCH_KEY "LD_LIBRARY_PATH" +#endif + +#define GRE_CONF_NAME ".gre.config" +#define GRE_CONF_PATH "/etc/gre.conf" +#define GRE_CONF_DIR "/etc/gre.d/" +#endif + +#if defined(XP_WIN) || defined(XP_OS2) + #define XPCOM_FILE_PATH_SEPARATOR "\\" + #define XPCOM_ENV_PATH_SEPARATOR ";" +#elif defined(XP_UNIX) || defined(XP_BEOS) + #define XPCOM_FILE_PATH_SEPARATOR "/" + #define XPCOM_ENV_PATH_SEPARATOR ":" +#else + #error need_to_define_your_file_path_separator_and_illegal_characters +#endif + +#endif + + diff --git a/src/libs/xpcom18a4/xpcom/build/nsXPComInit.cpp b/src/libs/xpcom18a4/xpcom/build/nsXPComInit.cpp new file mode 100644 index 00000000..65d84b6b --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/build/nsXPComInit.cpp @@ -0,0 +1,1079 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsXPCOM.h" +#include "nsXPCOMPrivate.h" +#include "nscore.h" +#include "prlink.h" +#include "nsCOMPtr.h" +#include "nsObserverList.h" +#include "nsObserverService.h" +#include "nsProperties.h" +#include "nsIProperties.h" +#include "nsPersistentProperties.h" +#include "nsScriptableInputStream.h" +#include "nsBinaryStream.h" +#include "nsStorageStream.h" + +#include "nsMemoryImpl.h" +#include "nsDebugImpl.h" +#include "nsTraceRefcntImpl.h" +#include "nsErrorService.h" +#include "nsByteBuffer.h" + +#include "nsSupportsArray.h" +#include "nsArray.h" +#include "nsSupportsPrimitives.h" +#include "nsConsoleService.h" +#include "nsExceptionService.h" + +#include "nsComponentManager.h" +#include "nsCategoryManagerUtils.h" +#include "nsIServiceManager.h" +#include "nsGenericFactory.h" + +#include "nsEventQueueService.h" +#include "nsEventQueue.h" +#ifdef VBOX +# include "nsEventQueueUtils.h" +# include "nsProxyRelease.h" +#endif /* VBOX */ + +#include "nsIProxyObjectManager.h" +#include "nsProxyEventPrivate.h" // access to the impl of nsProxyObjectManager for the generic factory registration. + +#include "xptinfo.h" +#include "nsIInterfaceInfoManager.h" + +#include "nsTimerImpl.h" +#include "TimerThread.h" + +#include "nsThread.h" +#include "nsProcess.h" +#include "nsEnvironment.h" + +#include "nsEmptyEnumerator.h" + +#include "nsILocalFile.h" +#include "nsLocalFile.h" +#if defined(XP_UNIX) || defined(XP_OS2) +#include "nsNativeCharsetUtils.h" +#endif +#include "nsDirectoryService.h" +#include "nsDirectoryServiceDefs.h" +#include "nsCategoryManager.h" +#include "nsICategoryManager.h" +#include "nsStringStream.h" +#include "nsMultiplexInputStream.h" + +#include "nsFastLoadService.h" + +#include "nsAtomService.h" +#include "nsAtomTable.h" +#include "nsTraceRefcnt.h" +#include "nsTimelineService.h" + +#include "nsVariant.h" + +#ifdef GC_LEAK_DETECTOR +#include "nsLeakDetector.h" +#endif +#include "nsRecyclingAllocator.h" + +#include "SpecialSystemDirectory.h" + +#include "ipcdclient.h" +#include "ipcService.h" +#include "ipcConfig.h" +#include "ipcCID.h" +#include "ipcLockService.h" +#include "ipcLockCID.h" +#include "tmTransactionService.h" +#include "ipcDConnectService.h" + +#include + +// Registry Factory creation function defined in nsRegistry.cpp +// We hook into this function locally to create and register the registry +// Since noone outside xpcom needs to know about this and nsRegistry.cpp +// does not have a local include file, we are putting this definition +// here rather than in nsIRegistry.h +extern nsresult NS_RegistryGetFactory(nsIFactory** aFactory); +extern nsresult NS_CategoryManagerGetFactory( nsIFactory** ); + +#ifdef DEBUG +extern void _FreeAutoLockStatics(); +#endif + +static NS_DEFINE_CID(kComponentManagerCID, NS_COMPONENTMANAGER_CID); +static NS_DEFINE_CID(kMemoryCID, NS_MEMORY_CID); +static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID); + +NS_GENERIC_FACTORY_CONSTRUCTOR(nsProcess) +NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsEventQueueServiceImpl, Init) + +#define NS_ENVIRONMENT_CLASSNAME "Environment Service" + +#include "nsXPCOM.h" +// ds/nsISupportsPrimitives +#define NS_SUPPORTS_ID_CLASSNAME "Supports ID" +#define NS_SUPPORTS_CSTRING_CLASSNAME "Supports String" +#define NS_SUPPORTS_STRING_CLASSNAME "Supports WString" +#define NS_SUPPORTS_PRBOOL_CLASSNAME "Supports PRBool" +#define NS_SUPPORTS_PRUINT8_CLASSNAME "Supports PRUint8" +#define NS_SUPPORTS_PRUINT16_CLASSNAME "Supports PRUint16" +#define NS_SUPPORTS_PRUINT32_CLASSNAME "Supports PRUint32" +#define NS_SUPPORTS_PRUINT64_CLASSNAME "Supports PRUint64" +#define NS_SUPPORTS_PRTIME_CLASSNAME "Supports PRTime" +#define NS_SUPPORTS_CHAR_CLASSNAME "Supports Char" +#define NS_SUPPORTS_PRINT16_CLASSNAME "Supports PRInt16" +#define NS_SUPPORTS_PRINT32_CLASSNAME "Supports PRInt32" +#define NS_SUPPORTS_PRINT64_CLASSNAME "Supports PRInt64" +#define NS_SUPPORTS_FLOAT_CLASSNAME "Supports float" +#define NS_SUPPORTS_DOUBLE_CLASSNAME "Supports double" +#define NS_SUPPORTS_VOID_CLASSNAME "Supports void" +#define NS_SUPPORTS_INTERFACE_POINTER_CLASSNAME "Supports interface pointer" + +NS_GENERIC_FACTORY_CONSTRUCTOR(nsSupportsIDImpl) +NS_GENERIC_FACTORY_CONSTRUCTOR(nsSupportsStringImpl) +NS_GENERIC_FACTORY_CONSTRUCTOR(nsSupportsCStringImpl) +NS_GENERIC_FACTORY_CONSTRUCTOR(nsSupportsPRBoolImpl) +NS_GENERIC_FACTORY_CONSTRUCTOR(nsSupportsPRUint8Impl) +NS_GENERIC_FACTORY_CONSTRUCTOR(nsSupportsPRUint16Impl) +NS_GENERIC_FACTORY_CONSTRUCTOR(nsSupportsPRUint32Impl) +NS_GENERIC_FACTORY_CONSTRUCTOR(nsSupportsPRUint64Impl) +NS_GENERIC_FACTORY_CONSTRUCTOR(nsSupportsPRTimeImpl) +NS_GENERIC_FACTORY_CONSTRUCTOR(nsSupportsCharImpl) +NS_GENERIC_FACTORY_CONSTRUCTOR(nsSupportsPRInt16Impl) +NS_GENERIC_FACTORY_CONSTRUCTOR(nsSupportsPRInt32Impl) +NS_GENERIC_FACTORY_CONSTRUCTOR(nsSupportsPRInt64Impl) +NS_GENERIC_FACTORY_CONSTRUCTOR(nsSupportsFloatImpl) +NS_GENERIC_FACTORY_CONSTRUCTOR(nsSupportsDoubleImpl) +NS_GENERIC_FACTORY_CONSTRUCTOR(nsSupportsVoidImpl) +NS_GENERIC_FACTORY_CONSTRUCTOR(nsSupportsInterfacePointerImpl) + +NS_GENERIC_FACTORY_CONSTRUCTOR(nsArray) +NS_GENERIC_FACTORY_CONSTRUCTOR(nsConsoleService) +NS_GENERIC_FACTORY_CONSTRUCTOR(nsAtomService) +NS_GENERIC_FACTORY_CONSTRUCTOR(nsExceptionService) +NS_GENERIC_FACTORY_CONSTRUCTOR(nsTimerImpl) +NS_GENERIC_FACTORY_CONSTRUCTOR(nsTimerManager) +NS_GENERIC_FACTORY_CONSTRUCTOR(nsBinaryOutputStream) +NS_GENERIC_FACTORY_CONSTRUCTOR(nsBinaryInputStream) +NS_GENERIC_FACTORY_CONSTRUCTOR(nsStorageStream) + +NS_GENERIC_FACTORY_CONSTRUCTOR(nsVariant) + +NS_GENERIC_FACTORY_CONSTRUCTOR(nsRecyclingAllocatorImpl) + +#ifdef MOZ_TIMELINE +NS_GENERIC_FACTORY_CONSTRUCTOR(nsTimelineService) +#endif + +static NS_METHOD +nsXPTIInterfaceInfoManagerGetSingleton(nsISupports* outer, + const nsIID& aIID, + void* *aInstancePtr) +{ + NS_ENSURE_ARG_POINTER(aInstancePtr); + NS_ENSURE_TRUE(!outer, NS_ERROR_NO_AGGREGATION); + + nsCOMPtr iim(dont_AddRef(XPTI_GetInterfaceInfoManager())); + if (!iim) { + return NS_ERROR_FAILURE; + } + + return iim->QueryInterface(aIID, aInstancePtr); +} + + +PR_STATIC_CALLBACK(nsresult) +RegisterGenericFactory(nsIComponentRegistrar* registrar, + const nsModuleComponentInfo *info) +{ + nsresult rv; + nsIGenericFactory* fact; + rv = NS_NewGenericFactory(&fact, info); + if (NS_FAILED(rv)) return rv; + + rv = registrar->RegisterFactory(info->mCID, + info->mDescription, + info->mContractID, + fact); + NS_RELEASE(fact); + return rv; +} + +// In order to support the installer, we need +// to be told out of band if we should cause +// an autoregister. If the file ".autoreg" exists in the binary +// directory, we check its timestamp against the timestamp of the +// compreg.dat file. If the .autoreg file is newer, we autoregister. +static PRBool CheckUpdateFile() +{ + nsresult rv; + nsCOMPtr directoryService; + nsDirectoryService::Create(nsnull, + NS_GET_IID(nsIProperties), + getter_AddRefs(directoryService)); + + if (!directoryService) + return PR_FALSE; + + nsCOMPtr file; + rv = directoryService->Get(NS_XPCOM_CURRENT_PROCESS_DIR, + NS_GET_IID(nsIFile), + getter_AddRefs(file)); + + if (NS_FAILED(rv)) { + NS_WARNING("Getting NS_XPCOM_CURRENT_PROCESS_DIR failed"); + return PR_FALSE; + } + + file->AppendNative(nsDependentCString(".autoreg")); + + PRBool exists; + file->Exists(&exists); + if (!exists) + return PR_FALSE; + + nsCOMPtr compregFile; + rv = directoryService->Get(NS_XPCOM_COMPONENT_REGISTRY_FILE, + NS_GET_IID(nsIFile), + getter_AddRefs(compregFile)); + + + if (NS_FAILED(rv)) { + NS_WARNING("Getting NS_XPCOM_COMPONENT_REGISTRY_FILE failed"); + return PR_FALSE; + } + + // Don't need to check whether compreg exists; if it doesn't + // we won't even be here. + + PRInt64 compregModTime, autoregModTime; + compregFile->GetLastModifiedTime(&compregModTime); + file->GetLastModifiedTime(&autoregModTime); + + return LL_CMP(autoregModTime, >, compregModTime); +} + +#if 0 /// @todo later +NS_GENERIC_FACTORY_CONSTRUCTOR(ipcService) +NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(ipcLockService, Init) +NS_GENERIC_FACTORY_CONSTRUCTOR(tmTransactionService) +NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(ipcDConnectService, Init) + +// enable this code to make the IPC DCONNECT service auto-start. +NS_METHOD +ipcDConnectServiceRegisterProc(nsIComponentManager *aCompMgr, + nsIFile *aPath, + const char *registryLocation, + const char *componentType, + const nsModuleComponentInfo *info) +{ + // + // add ipcService to the XPCOM startup category + // + nsCOMPtr catman(do_GetService(NS_CATEGORYMANAGER_CONTRACTID)); + if (catman) { + nsXPIDLCString prevEntry; + catman->AddCategoryEntry(NS_XPCOM_STARTUP_OBSERVER_ID, "ipcDConnectService", + IPC_DCONNECTSERVICE_CONTRACTID, PR_TRUE, PR_TRUE, + getter_Copies(prevEntry)); + } + return NS_OK; +} + +NS_METHOD +ipcDConnectServiceUnregisterProc(nsIComponentManager *aCompMgr, + nsIFile *aPath, + const char *registryLocation, + const nsModuleComponentInfo *info) +{ + nsCOMPtr catman(do_GetService(NS_CATEGORYMANAGER_CONTRACTID)); + if (catman) + catman->DeleteCategoryEntry(NS_XPCOM_STARTUP_OBSERVER_ID, + IPC_DCONNECTSERVICE_CONTRACTID, PR_TRUE); + return NS_OK; +} +#endif + +nsComponentManagerImpl* nsComponentManagerImpl::gComponentManager = NULL; +nsIProperties *gDirectoryService = NULL; +PRBool gXPCOMShuttingDown = PR_FALSE; + +// For each class that wishes to support nsIClassInfo, add a line like this +// NS_DECL_CLASSINFO(nsMyClass) + +#define COMPONENT(NAME, Ctor) \ + { NS_##NAME##_CLASSNAME, NS_##NAME##_CID, NS_##NAME##_CONTRACTID, Ctor } + +#define COMPONENT_CI(NAME, Ctor, Class) \ + { NS_##NAME##_CLASSNAME, NS_##NAME##_CID, NS_##NAME##_CONTRACTID, Ctor, \ + NULL, NULL, NULL, NS_CI_INTERFACE_GETTER_NAME(Class), NULL, \ + &NS_CLASSINFO_NAME(Class) } + +static const nsModuleComponentInfo components[] = { + COMPONENT(MEMORY, nsMemoryImpl::Create), + COMPONENT(DEBUG, nsDebugImpl::Create), +#define NS_ERRORSERVICE_CLASSNAME NS_ERRORSERVICE_NAME + COMPONENT(ERRORSERVICE, nsErrorService::Create), + + COMPONENT(BYTEBUFFER, ByteBufferImpl::Create), + COMPONENT(SCRIPTABLEINPUTSTREAM, nsScriptableInputStream::Create), + COMPONENT(BINARYINPUTSTREAM, nsBinaryInputStreamConstructor), + COMPONENT(BINARYOUTPUTSTREAM, nsBinaryOutputStreamConstructor), + COMPONENT(STORAGESTREAM, nsStorageStreamConstructor), + +#define NS_PROPERTIES_CLASSNAME "Properties" + COMPONENT(PROPERTIES, nsProperties::Create), + +#define NS_PERSISTENTPROPERTIES_CID NS_IPERSISTENTPROPERTIES_CID /* sigh */ + COMPONENT(PERSISTENTPROPERTIES, nsPersistentProperties::Create), + + COMPONENT(SUPPORTSARRAY, nsSupportsArray::Create), + COMPONENT(ARRAY, nsArrayConstructor), + COMPONENT(CONSOLESERVICE, nsConsoleServiceConstructor), + COMPONENT(EXCEPTIONSERVICE, nsExceptionServiceConstructor), + COMPONENT(ATOMSERVICE, nsAtomServiceConstructor), +#ifdef MOZ_TIMELINE + COMPONENT(TIMELINESERVICE, nsTimelineServiceConstructor), +#endif + COMPONENT(OBSERVERSERVICE, nsObserverService::Create), + COMPONENT(GENERICFACTORY, nsGenericFactory::Create), + COMPONENT(EVENTQUEUESERVICE, nsEventQueueServiceImplConstructor), + COMPONENT(EVENTQUEUE, nsEventQueueImpl::Create), + COMPONENT(THREAD, nsThread::Create), + +#define NS_XPCOMPROXY_CID NS_PROXYEVENT_MANAGER_CID + COMPONENT(XPCOMPROXY, nsProxyObjectManager::Create), + + COMPONENT(TIMER, nsTimerImplConstructor), + COMPONENT(TIMERMANAGER, nsTimerManagerConstructor), + +#define COMPONENT_SUPPORTS(TYPE, Type) \ + COMPONENT(SUPPORTS_##TYPE, nsSupports##Type##ImplConstructor) + + COMPONENT_SUPPORTS(ID, ID), + COMPONENT_SUPPORTS(STRING, String), + COMPONENT_SUPPORTS(CSTRING, CString), + COMPONENT_SUPPORTS(PRBOOL, PRBool), + COMPONENT_SUPPORTS(PRUINT8, PRUint8), + COMPONENT_SUPPORTS(PRUINT16, PRUint16), + COMPONENT_SUPPORTS(PRUINT32, PRUint32), + COMPONENT_SUPPORTS(PRUINT64, PRUint64), + COMPONENT_SUPPORTS(PRTIME, PRTime), + COMPONENT_SUPPORTS(CHAR, Char), + COMPONENT_SUPPORTS(PRINT16, PRInt16), + COMPONENT_SUPPORTS(PRINT32, PRInt32), + COMPONENT_SUPPORTS(PRINT64, PRInt64), + COMPONENT_SUPPORTS(FLOAT, Float), + COMPONENT_SUPPORTS(DOUBLE, Double), + COMPONENT_SUPPORTS(VOID, Void), + COMPONENT_SUPPORTS(INTERFACE_POINTER, InterfacePointer), + +#undef COMPONENT_SUPPORTS +#define NS_LOCAL_FILE_CLASSNAME "Local File Specification" + COMPONENT(LOCAL_FILE, nsLocalFile::nsLocalFileConstructor), +#define NS_DIRECTORY_SERVICE_CLASSNAME "nsIFile Directory Service" + COMPONENT(DIRECTORY_SERVICE, nsDirectoryService::Create), + COMPONENT(PROCESS, nsProcessConstructor), + COMPONENT(ENVIRONMENT, nsEnvironment::Create), + + COMPONENT(STRINGINPUTSTREAM, nsStringInputStreamConstructor), + COMPONENT(MULTIPLEXINPUTSTREAM, nsMultiplexInputStreamConstructor), + + COMPONENT(FASTLOADSERVICE, nsFastLoadService::Create), + COMPONENT(VARIANT, nsVariantConstructor), + COMPONENT(INTERFACEINFOMANAGER_SERVICE, nsXPTIInterfaceInfoManagerGetSingleton), + + COMPONENT(RECYCLINGALLOCATOR, nsRecyclingAllocatorImplConstructor), + +#if 0 /// @todo later + { IPC_SERVICE_CLASSNAME, + IPC_SERVICE_CID, + IPC_SERVICE_CONTRACTID, + ipcServiceConstructor }, + /* + ipcServiceRegisterProc, + ipcServiceUnregisterProc }, + */ + // + // extensions go here: + // + { IPC_LOCKSERVICE_CLASSNAME, + IPC_LOCKSERVICE_CID, + IPC_LOCKSERVICE_CONTRACTID, + ipcLockServiceConstructor }, + { IPC_TRANSACTIONSERVICE_CLASSNAME, + IPC_TRANSACTIONSERVICE_CID, + IPC_TRANSACTIONSERVICE_CONTRACTID, + tmTransactionServiceConstructor }, + +#ifdef BUILD_DCONNECT + { IPC_DCONNECTSERVICE_CLASSNAME, + IPC_DCONNECTSERVICE_CID, + IPC_DCONNECTSERVICE_CONTRACTID, + ipcDConnectServiceConstructor, + ipcDConnectServiceRegisterProc, + ipcDConnectServiceUnregisterProc }, +#endif +#endif +}; + +#undef COMPONENT + +const int components_length = sizeof(components) / sizeof(components[0]); + +// gMemory will be freed during shutdown. +static nsIMemory* gMemory = nsnull; +nsresult NS_COM NS_GetMemoryManager(nsIMemory* *result) +{ + nsresult rv = NS_OK; + if (!gMemory) + { + rv = nsMemoryImpl::Create(nsnull, + NS_GET_IID(nsIMemory), + (void**)&gMemory); + } + NS_IF_ADDREF(*result = gMemory); + return rv; +} + +// gDebug will be freed during shutdown. +static nsIDebug* gDebug = nsnull; +nsresult NS_COM NS_GetDebug(nsIDebug** result) +{ + nsresult rv = NS_OK; + if (!gDebug) + { + rv = nsDebugImpl::Create(nsnull, + NS_GET_IID(nsIDebug), + (void**)&gDebug); + } + NS_IF_ADDREF(*result = gDebug); + return rv; +} + +#ifdef NS_BUILD_REFCNT_LOGGING +// gTraceRefcnt will be freed during shutdown. +static nsITraceRefcnt* gTraceRefcnt = nsnull; +#endif + +nsresult NS_COM NS_GetTraceRefcnt(nsITraceRefcnt** result) +{ +#ifdef NS_BUILD_REFCNT_LOGGING + nsresult rv = NS_OK; + if (!gTraceRefcnt) + { + rv = nsTraceRefcntImpl::Create(nsnull, + NS_GET_IID(nsITraceRefcnt), + (void**)&gTraceRefcnt); + } + NS_IF_ADDREF(*result = gTraceRefcnt); + return rv; +#else + return NS_ERROR_NOT_INITIALIZED; +#endif +} + +nsresult NS_COM NS_InitXPCOM(nsIServiceManager* *result, + nsIFile* binDirectory) +{ + return NS_InitXPCOM2(result, binDirectory, nsnull); +} + +nsresult NS_COM NS_InitXPCOM2(nsIServiceManager* *result, + nsIFile* binDirectory, + nsIDirectoryServiceProvider* appFileLocationProvider) +{ + nsresult rv = NS_OK; + + // We are not shutting down + gXPCOMShuttingDown = PR_FALSE; + +#ifdef NS_BUILD_REFCNT_LOGGING + nsTraceRefcntImpl::Startup(); +#endif + + // Establish the main thread here. + rv = nsIThread::SetMainThread(); + if (NS_FAILED(rv)) return rv; + + // Set up the timer globals/timer thread + rv = nsTimerImpl::Startup(); + NS_ENSURE_SUCCESS(rv, rv); + + // Startup the memory manager + rv = nsMemoryImpl::Startup(); + if (NS_FAILED(rv)) return rv; + + // If the locale hasn't already been setup by our embedder, + // get us out of the "C" locale and into the system + if (strcmp(setlocale(LC_ALL, NULL), "C") == 0) + setlocale(LC_ALL, ""); + +#if defined(XP_UNIX) || defined(XP_OS2) + NS_StartupNativeCharsetUtils(); +#endif + NS_StartupLocalFile(); + + StartupSpecialSystemDirectory(); + + // Start the directory service so that the component manager init can use it. + rv = nsDirectoryService::Create(nsnull, + NS_GET_IID(nsIProperties), + (void**)&gDirectoryService); + if (NS_FAILED(rv)) + return rv; + + nsCOMPtr dirService = do_QueryInterface(gDirectoryService, &rv); + if (NS_FAILED(rv)) + return rv; + rv = dirService->Init(); + if (NS_FAILED(rv)) + return rv; + + // Create the Component/Service Manager + nsComponentManagerImpl *compMgr = NULL; + + if (nsComponentManagerImpl::gComponentManager == NULL) + { + compMgr = new nsComponentManagerImpl(); + if (compMgr == NULL) + return NS_ERROR_OUT_OF_MEMORY; + NS_ADDREF(compMgr); + + nsCOMPtr xpcomLib; + + PRBool value; + if (binDirectory) + { + rv = binDirectory->IsDirectory(&value); + + if (NS_SUCCEEDED(rv) && value) { + gDirectoryService->Set(NS_XPCOM_INIT_CURRENT_PROCESS_DIR, binDirectory); + binDirectory->Clone(getter_AddRefs(xpcomLib)); + } + } + else { + gDirectoryService->Get(NS_XPCOM_CURRENT_PROCESS_DIR, + NS_GET_IID(nsIFile), + getter_AddRefs(xpcomLib)); + } + + if (xpcomLib) { + xpcomLib->AppendNative(nsDependentCString(XPCOM_DLL)); + gDirectoryService->Set(NS_XPCOM_LIBRARY_FILE, xpcomLib); + } + + if (appFileLocationProvider) { + rv = dirService->RegisterProvider(appFileLocationProvider); + if (NS_FAILED(rv)) return rv; + } + + rv = compMgr->Init(); + if (NS_FAILED(rv)) + { + NS_RELEASE(compMgr); + return rv; + } + + nsComponentManagerImpl::gComponentManager = compMgr; + + if (result) { + nsIServiceManager *serviceManager = + NS_STATIC_CAST(nsIServiceManager*, compMgr); + + NS_ADDREF(*result = serviceManager); + } + } + + nsCOMPtr memory; + NS_GetMemoryManager(getter_AddRefs(memory)); + // dougt - these calls will be moved into a new interface when nsIComponentManager is frozen. + rv = compMgr->RegisterService(kMemoryCID, memory); + if (NS_FAILED(rv)) return rv; + + rv = compMgr->RegisterService(kComponentManagerCID, NS_STATIC_CAST(nsIComponentManager*, compMgr)); + if (NS_FAILED(rv)) return rv; + +#ifdef GC_LEAK_DETECTOR + rv = NS_InitLeakDetector(); + if (NS_FAILED(rv)) return rv; +#endif + + // 2. Register the global services with the component manager so that + // clients can create new objects. + + // Category Manager + { + nsCOMPtr categoryManagerFactory; + if ( NS_FAILED(rv = NS_CategoryManagerGetFactory(getter_AddRefs(categoryManagerFactory))) ) + return rv; + + NS_DEFINE_CID(kCategoryManagerCID, NS_CATEGORYMANAGER_CID); + + rv = compMgr->RegisterFactory(kCategoryManagerCID, + NS_CATEGORYMANAGER_CLASSNAME, + NS_CATEGORYMANAGER_CONTRACTID, + categoryManagerFactory, + PR_TRUE); + if ( NS_FAILED(rv) ) return rv; + } + + // what I want to do here is QI for a Component Registration Manager. Since this + // has not been invented yet, QI to the obsolete manager. Kids, don't do this at home. + nsCOMPtr registrar = do_QueryInterface( + NS_STATIC_CAST(nsIComponentManager*,compMgr), &rv); + if (registrar) { + for (int i = 0; i < components_length; i++) + RegisterGenericFactory(registrar, &components[i]); + } + rv = nsComponentManagerImpl::gComponentManager->ReadPersistentRegistry(); +#ifdef DEBUG + if (NS_FAILED(rv)) { + printf("No Persistent Registry Found.\n"); + } +#endif + +#if 0 /// @todo later + rv = IPC_Init(); + if (NS_FAILED(rv)) + return rv; +#endif + + if ( NS_FAILED(rv) || CheckUpdateFile()) { + // if we find no persistent registry, we will try to autoregister + // the default components directory. + nsComponentManagerImpl::gComponentManager->AutoRegister(nsnull); + + // If the application is using a GRE, then, + // auto register components in the GRE directory as well. + // + // The application indicates that it's using an GRE by + // returning a valid nsIFile when queried (via appFileLocProvider) + // for the NS_GRE_DIR atom as shown below + // + + if ( appFileLocationProvider ) { + nsCOMPtr greDir; + PRBool persistent = PR_TRUE; + + appFileLocationProvider->GetFile(NS_GRE_DIR, &persistent, getter_AddRefs(greDir)); + + if (greDir) { +#ifdef DEBUG_dougt + printf("start - Registering GRE components\n"); +#endif + rv = gDirectoryService->Get(NS_GRE_COMPONENT_DIR, + NS_GET_IID(nsIFile), + getter_AddRefs(greDir)); + if (NS_FAILED(rv)) { + NS_ERROR("Could not get GRE components directory!"); + return rv; + } + + // If the GRE contains any loaders, we want to know about it so that we can cause another + // autoregistration of the applications component directory. + int loaderCount = nsComponentManagerImpl::gComponentManager->GetLoaderCount(); + rv = nsComponentManagerImpl::gComponentManager->AutoRegister(greDir); + + if (loaderCount != nsComponentManagerImpl::gComponentManager->GetLoaderCount()) + nsComponentManagerImpl::gComponentManager->AutoRegisterNonNativeComponents(nsnull); + +#ifdef DEBUG_dougt + printf("end - Registering GRE components\n"); +#endif + if (NS_FAILED(rv)) { + NS_ERROR("Could not AutoRegister GRE components"); + return rv; + } + } + } + + // + // If additional component directories have been specified, then + // register them as well. + // + + nsCOMPtr dirList; + gDirectoryService->Get(NS_XPCOM_COMPONENT_DIR_LIST, + NS_GET_IID(nsISimpleEnumerator), + getter_AddRefs(dirList)); + if (dirList) { + PRBool hasMore; + while (NS_SUCCEEDED(dirList->HasMoreElements(&hasMore)) && hasMore) { + nsCOMPtr elem; + dirList->GetNext(getter_AddRefs(elem)); + if (elem) { + nsCOMPtr dir = do_QueryInterface(elem); + if (dir) + nsComponentManagerImpl::gComponentManager->AutoRegister(dir); + + // XXX should we worry about new component loaders being + // XXX defined by this process? + } + } + } + + + // Make sure the compreg file's mod time is current. + nsCOMPtr compregFile; + rv = gDirectoryService->Get(NS_XPCOM_COMPONENT_REGISTRY_FILE, + NS_GET_IID(nsIFile), + getter_AddRefs(compregFile)); + compregFile->SetLastModifiedTime(PR_Now() / 1000); + } + + // Pay the cost at startup time of starting this singleton. + nsIInterfaceInfoManager* iim = XPTI_GetInterfaceInfoManager(); + NS_IF_RELEASE(iim); +#ifdef VBOX + // Must initialize the EventQueueService singleton before anyone is + // using it. The notification below creates a thread which races creating + // the EventQueueService creation otherwise, no matter what. + nsCOMPtr eventQ; + rv = NS_GetMainEventQ(getter_AddRefs(eventQ)); + if (NS_FAILED(rv)) { + NS_ERROR("Could not create event queue for main thread"); + /* this is just a build-time hack, to reference NS_ProxyRelease */ + if (rv == 666) + NS_ProxyRelease(nsnull, nsnull); + return rv; + } +#endif /* VBOX */ + + // Notify observers of xpcom autoregistration start + NS_CreateServicesFromCategory(NS_XPCOM_STARTUP_OBSERVER_ID, + nsnull, + NS_XPCOM_STARTUP_OBSERVER_ID); + + return NS_OK; +} + + +static nsVoidArray* gExitRoutines; + +static void CallExitRoutines() +{ + if (!gExitRoutines) + return; + + PRInt32 count = gExitRoutines->Count(); + for (PRInt32 i = 0; i < count; i++) { + XPCOMExitRoutine func = (XPCOMExitRoutine) gExitRoutines->ElementAt(i); + func(); + } + gExitRoutines->Clear(); + delete gExitRoutines; + gExitRoutines = nsnull; +} + +nsresult NS_COM +NS_RegisterXPCOMExitRoutine(XPCOMExitRoutine exitRoutine, PRUint32 priority) +{ + // priority are not used right now. It will need to be implemented as more + // classes are moved into the glue library --dougt + if (!gExitRoutines) { + gExitRoutines = new nsVoidArray(); + if (!gExitRoutines) { + NS_WARNING("Failed to allocate gExitRoutines"); + return NS_ERROR_FAILURE; + } + } + + PRBool okay = gExitRoutines->AppendElement((void*)exitRoutine); + return okay ? NS_OK : NS_ERROR_FAILURE; +} + +nsresult NS_COM +NS_UnregisterXPCOMExitRoutine(XPCOMExitRoutine exitRoutine) +{ + if (!gExitRoutines) + return NS_ERROR_FAILURE; + + PRBool okay = gExitRoutines->RemoveElement((void*)exitRoutine); + return okay ? NS_OK : NS_ERROR_FAILURE; +} + + +// +// NS_ShutdownXPCOM() +// +// The shutdown sequence for xpcom would be +// +// - Release the Global Service Manager +// - Release all service instances held by the global service manager +// - Release the Global Service Manager itself +// - Release the Component Manager +// - Release all factories cached by the Component Manager +// - Unload Libraries +// - Release Contractid Cache held by Component Manager +// - Release dll abstraction held by Component Manager +// - Release the Registry held by Component Manager +// - Finally, release the component manager itself +// +nsresult NS_COM NS_ShutdownXPCOM(nsIServiceManager* servMgr) +{ + + // Notify observers of xpcom shutting down + nsresult rv = NS_OK; + { + // Block it so that the COMPtr will get deleted before we hit + // servicemanager shutdown + nsCOMPtr observerService = + do_GetService("@mozilla.org/observer-service;1", &rv); + if (NS_SUCCEEDED(rv)) + { + nsCOMPtr mgr; + rv = NS_GetServiceManager(getter_AddRefs(mgr)); + if (NS_SUCCEEDED(rv)) + { + (void) observerService->NotifyObservers(mgr, + NS_XPCOM_SHUTDOWN_OBSERVER_ID, + nsnull); + } + } + } + + // grab the event queue so that we can process events one last time before exiting + nsCOMPtr currentQ; + { + nsCOMPtr eventQService = + do_GetService(kEventQueueServiceCID, &rv); + + if (eventQService) { + eventQService->GetThreadEventQueue(NS_CURRENT_THREAD, getter_AddRefs(currentQ)); + } + } + // XPCOM is officially in shutdown mode NOW + // Set this only after the observers have been notified as this + // will cause servicemanager to become inaccessible. + gXPCOMShuttingDown = PR_TRUE; + +#ifdef DEBUG_dougt + fprintf(stderr, "* * * * XPCOM shutdown. Access will be denied * * * * \n"); +#endif + +#if 0 /// @todo later + IPC_Shutdown(); +#endif + + // We may have AddRef'd for the caller of NS_InitXPCOM, so release it + // here again: + NS_IF_RELEASE(servMgr); + + // Shutdown global servicemanager + if (nsComponentManagerImpl::gComponentManager) { + nsComponentManagerImpl::gComponentManager->FreeServices(); + } + nsServiceManager::ShutdownGlobalServiceManager(nsnull); + + if (currentQ) { + currentQ->ProcessPendingEvents(); + currentQ = 0; + } + + nsProxyObjectManager::Shutdown(); + + // Release the directory service + NS_IF_RELEASE(gDirectoryService); + + // Shutdown nsLocalFile string conversion + NS_ShutdownLocalFile(); +#ifdef XP_UNIX + NS_ShutdownNativeCharsetUtils(); +#endif + + // Shutdown the timer thread and all timers that might still be alive before + // shutting down the component manager + nsTimerImpl::Shutdown(); + + CallExitRoutines(); + + // Shutdown xpcom. This will release all loaders and cause others holding + // a refcount to the component manager to release it. + if (nsComponentManagerImpl::gComponentManager) { + rv = (nsComponentManagerImpl::gComponentManager)->Shutdown(); + NS_ASSERTION(NS_SUCCEEDED(rv), "Component Manager shutdown failed."); + } else + NS_WARNING("Component Manager was never created ..."); + + // Release our own singletons + // Do this _after_ shutting down the component manager, because the + // JS component loader will use XPConnect to call nsIModule::canUnload, + // and that will spin up the InterfaceInfoManager again -- bad mojo + XPTI_FreeInterfaceInfoManager(); + + // Finally, release the component manager last because it unloads the + // libraries: + if (nsComponentManagerImpl::gComponentManager) { + nsrefcnt cnt; + NS_RELEASE2(nsComponentManagerImpl::gComponentManager, cnt); + NS_WARN_IF_FALSE(cnt == 0, "Component Manager being held past XPCOM shutdown."); + } + nsComponentManagerImpl::gComponentManager = nsnull; + +#ifdef DEBUG + _FreeAutoLockStatics(); +#endif + + ShutdownSpecialSystemDirectory(); + + EmptyEnumeratorImpl::Shutdown(); + nsMemoryImpl::Shutdown(); + NS_IF_RELEASE(gMemory); + + nsThread::Shutdown(); + NS_PurgeAtomTable(); + + NS_IF_RELEASE(gDebug); + +#ifdef NS_BUILD_REFCNT_LOGGING + nsTraceRefcntImpl::DumpStatistics(); + nsTraceRefcntImpl::ResetStatistics(); + nsTraceRefcntImpl::Shutdown(); +#endif + +#ifdef GC_LEAK_DETECTOR + // Shutdown the Leak detector. + NS_ShutdownLeakDetector(); +#endif + + return NS_OK; +} + +#define GET_FUNC(_tag, _decl, _name) \ + functions->_tag = (_decl) PR_FindSymbol(xpcomLib, _name); \ + if (!functions->_tag) goto end + +nsresult NS_COM PR_CALLBACK +NS_GetFrozenFunctions(XPCOMFunctions *functions, const char* libraryPath) +{ + if (!functions) + return NS_ERROR_OUT_OF_MEMORY; + + if (functions->version != XPCOM_GLUE_VERSION) + return NS_ERROR_FAILURE; + + PRLibrary *xpcomLib = PR_LoadLibrary(libraryPath); + if (!xpcomLib) + return NS_ERROR_FAILURE; + + nsresult rv = NS_ERROR_FAILURE; + +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP + GET_FUNC(init, InitFunc, "VBoxNsxpNS_InitXPCOM2"); + GET_FUNC(shutdown, ShutdownFunc, "VBoxNsxpNS_ShutdownXPCOM"); + GET_FUNC(getServiceManager, GetServiceManagerFunc, "VBoxNsxpNS_GetServiceManager"); + GET_FUNC(getComponentManager, GetComponentManagerFunc, "VBoxNsxpNS_GetComponentManager"); + GET_FUNC(getComponentRegistrar, GetComponentRegistrarFunc, "VBoxNsxpNS_GetComponentRegistrar"); + GET_FUNC(getMemoryManager, GetMemoryManagerFunc, "VBoxNsxpNS_GetMemoryManager"); + GET_FUNC(newLocalFile, NewLocalFileFunc, "VBoxNsxpNS_NewLocalFile"); + GET_FUNC(newNativeLocalFile, NewNativeLocalFileFunc, "VBoxNsxpNS_NewNativeLocalFile"); + GET_FUNC(registerExitRoutine, RegisterXPCOMExitRoutineFunc, "VBoxNsxpNS_RegisterXPCOMExitRoutine"); + GET_FUNC(unregisterExitRoutine, UnregisterXPCOMExitRoutineFunc, "VBoxNsxpNS_UnregisterXPCOMExitRoutine"); +#else /* !VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + GET_FUNC(init, InitFunc, "NS_InitXPCOM2"); + GET_FUNC(shutdown, ShutdownFunc, "NS_ShutdownXPCOM"); + GET_FUNC(getServiceManager, GetServiceManagerFunc, "NS_GetServiceManager"); + GET_FUNC(getComponentManager, GetComponentManagerFunc, "NS_GetComponentManager"); + GET_FUNC(getComponentRegistrar, GetComponentRegistrarFunc, "NS_GetComponentRegistrar"); + GET_FUNC(getMemoryManager, GetMemoryManagerFunc, "NS_GetMemoryManager"); + GET_FUNC(newLocalFile, NewLocalFileFunc, "NS_NewLocalFile"); + GET_FUNC(newNativeLocalFile, NewNativeLocalFileFunc, "NS_NewNativeLocalFile"); + GET_FUNC(registerExitRoutine, RegisterXPCOMExitRoutineFunc, "NS_RegisterXPCOMExitRoutine"); + GET_FUNC(unregisterExitRoutine, UnregisterXPCOMExitRoutineFunc, "NS_UnregisterXPCOMExitRoutine"); +#endif /* !VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + + // these functions were added post 1.4 (need to check size of |functions|) + if (functions->size > offsetof(XPCOMFunctions, getTraceRefcnt)) { +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP + GET_FUNC(getDebug, GetDebugFunc, "VBoxNsxpNS_GetDebug"); + GET_FUNC(getTraceRefcnt, GetTraceRefcntFunc, "VBoxNsxpNS_GetTraceRefcnt"); +#else /* !VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + GET_FUNC(getDebug, GetDebugFunc, "NS_GetDebug"); + GET_FUNC(getTraceRefcnt, GetTraceRefcntFunc, "NS_GetTraceRefcnt"); +#endif /* !VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + } + + // these functions were added post 1.6 (need to check size of |functions|) + if (functions->size > offsetof(XPCOMFunctions, cstringCloneData)) { +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP + GET_FUNC(stringContainerInit, StringContainerInitFunc, "VBoxNsxpNS_StringContainerInit"); + GET_FUNC(stringContainerFinish, StringContainerFinishFunc, "VBoxNsxpNS_StringContainerFinish"); + GET_FUNC(stringGetData, StringGetDataFunc, "VBoxNsxpNS_StringGetData"); + GET_FUNC(stringSetData, StringSetDataFunc, "VBoxNsxpNS_StringSetData"); + GET_FUNC(stringSetDataRange, StringSetDataRangeFunc, "VBoxNsxpNS_StringSetDataRange"); + GET_FUNC(stringCopy, StringCopyFunc, "VBoxNsxpNS_StringCopy"); + GET_FUNC(cstringContainerInit, CStringContainerInitFunc, "VBoxNsxpNS_CStringContainerInit"); + GET_FUNC(cstringContainerFinish, CStringContainerFinishFunc, "VBoxNsxpNS_CStringContainerFinish"); + GET_FUNC(cstringGetData, CStringGetDataFunc, "VBoxNsxpNS_CStringGetData"); + GET_FUNC(cstringSetData, CStringSetDataFunc, "VBoxNsxpNS_CStringSetData"); + GET_FUNC(cstringSetDataRange, CStringSetDataRangeFunc, "VBoxNsxpNS_CStringSetDataRange"); + GET_FUNC(cstringCopy, CStringCopyFunc, "VBoxNsxpNS_CStringCopy"); + GET_FUNC(cstringToUTF16, CStringToUTF16, "VBoxNsxpNS_CStringToUTF16"); + GET_FUNC(utf16ToCString, UTF16ToCString, "VBoxNsxpNS_UTF16ToCString"); + GET_FUNC(stringCloneData, StringCloneDataFunc, "VBoxNsxpNS_StringCloneData"); + GET_FUNC(cstringCloneData, CStringCloneDataFunc, "VBoxNsxpNS_CStringCloneData"); +#else /* !VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + GET_FUNC(stringContainerInit, StringContainerInitFunc, "NS_StringContainerInit"); + GET_FUNC(stringContainerFinish, StringContainerFinishFunc, "NS_StringContainerFinish"); + GET_FUNC(stringGetData, StringGetDataFunc, "NS_StringGetData"); + GET_FUNC(stringSetData, StringSetDataFunc, "NS_StringSetData"); + GET_FUNC(stringSetDataRange, StringSetDataRangeFunc, "NS_StringSetDataRange"); + GET_FUNC(stringCopy, StringCopyFunc, "NS_StringCopy"); + GET_FUNC(cstringContainerInit, CStringContainerInitFunc, "NS_CStringContainerInit"); + GET_FUNC(cstringContainerFinish, CStringContainerFinishFunc, "NS_CStringContainerFinish"); + GET_FUNC(cstringGetData, CStringGetDataFunc, "NS_CStringGetData"); + GET_FUNC(cstringSetData, CStringSetDataFunc, "NS_CStringSetData"); + GET_FUNC(cstringSetDataRange, CStringSetDataRangeFunc, "NS_CStringSetDataRange"); + GET_FUNC(cstringCopy, CStringCopyFunc, "NS_CStringCopy"); + GET_FUNC(cstringToUTF16, CStringToUTF16, "NS_CStringToUTF16"); + GET_FUNC(utf16ToCString, UTF16ToCString, "NS_UTF16ToCString"); + GET_FUNC(stringCloneData, StringCloneDataFunc, "NS_StringCloneData"); + GET_FUNC(cstringCloneData, CStringCloneDataFunc, "NS_CStringCloneData"); +#endif /* !VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + } + + rv = NS_OK; +end: + PR_UnloadLibrary(xpcomLib); // the library is refcnt'ed above by the caller. + return rv; +} diff --git a/src/libs/xpcom18a4/xpcom/build/win32.order b/src/libs/xpcom18a4/xpcom/build/win32.order new file mode 100644 index 00000000..ce6856ba --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/build/win32.order @@ -0,0 +1,1514 @@ +??1nsCOMPtr_base@@QAE@XZ ; 33017395 +?ElementAt@nsVoidArray@@QBEPAXH@Z ; 14120786 +?AddRef@nsEventQueueServiceImpl@@UAGKXZ ; 13612685 +?Release@AtomImpl@@UAGKXZ ; 13067618 +?Initialize@nsStr@@SAXAAU1@W4eCharSize@@@Z ; 9860800 +?Reference@nsCWeakProxy@@QAEPAXXZ ; 9283082 +?Free@nsStr@@CAHAAU1@@Z ; 8492496 +?Destroy@nsStr@@SAXAAU1@@Z ; 8159980 +??1nsString@@UAE@XZ ; 7681847 +??0nsString@@QAE@XZ ; 7538998 +?GetWritableFragment@nsString@@MAEPAGAAU?$nsWritableFragment@G@@W4nsFragmentRequest@@I@Z ; 7387979 +?Initialize@nsStr@@SAXAAU1@PADIIW4eCharSize@@H@Z ; 7301440 +??1nsAutoString@@UAE@XZ ; 6828894 +??0nsAutoString@@QAE@XZ ; 6681318 +?normalize_forward@?$nsReadingIterator@G@@QAEXXZ ; 6469200 +?normalize_forward@?$nsWritingIterator@D@@QAEXXZ ; 4717355 +?StrTruncate@nsStr@@SAXAAU1@I@Z ; 4534497 +?assign_from_helper@nsCOMPtr_base@@QAEXABVnsCOMPtr_helper@@ABUnsID@@@Z ; 4516612 +??0nsHashKey@@IAE@XZ ; 4270805 +??1nsHashKey@@UAE@XZ ; 4268636 +??RnsQueryInterface@@UBEIABUnsID@@PAPAX@Z ; 4148520 +?SetLength@nsCString@@UAEXI@Z ; 4098410 +?Get@nsHashtable@@QAEPAXPAVnsHashKey@@@Z ; 3790063 +?GetFlatBufferHandle@nsLocalString@@UBEPBV?$nsBufferHandle@G@@XZ ; 3747888 +?BeginReading@nsACString@@QBEAAV?$nsReadingIterator@D@@AAV2@@Z ; 3649883 +?FindChar1@@YAHPBDIHGHH@Z ; 2533672 +?BeginWriting@nsACString@@QAEAAV?$nsWritingIterator@D@@AAV2@@Z ; 2226534 +?advance@?$nsWritingIterator@G@@QAEAAV1@H@Z ; 2049632 +?advance@?$nsReadingIterator@G@@QAEAAV1@H@Z ; 1995545 +?GetReadableFragment@nsAFlatCString@@MBEPBDAAU?$nsReadableFragment@D@@W4nsFragmentRequest@@I@Z ; 1948988 +?Count@nsSupportsArray@@UAGIPAI@Z ; 1839978 +?readable_distance@?$nsCharSourceTraits@V?$nsReadingIterator@G@@@@SAIABV?$nsReadingIterator@G@@0@Z ; 1802375 +?GetReadableFragment@nsCString@@MBEPBDAAU?$nsReadableFragment@D@@W4nsFragmentRequest@@I@Z ; 1763345 +??0nsQueryInterface@@QAE@PAVnsISupports@@PAI@Z ; 1655422 +?copy_string@@YAAAV?$nsWritingIterator@G@@AAV?$nsReadingIterator@G@@ABV2@AAV1@@Z ; 1487171 +?GetWritableFragment@nsAFlatString@@MAEPAGAAU?$nsWritableFragment@G@@W4nsFragmentRequest@@I@Z ; 1391163 +?advance@?$nsWritingIterator@D@@QAEAAV1@H@Z ; 1335661 +?Equals@nsAString@@QBEHABV1@@Z ; 1318787 +?move@?$nsCharTraits@G@@SAPAGPAGPBGI@Z ; 1315826 +?assign_with_AddRef@nsCOMPtr_base@@QAEXPAVnsISupports@@@Z ; 1259090 +?write@?$nsWritingIterator@G@@QAEIPBGI@Z ; 1243674 +?Get@nsSupportsHashtable@@QAEPAVnsISupports@@PAVnsHashKey@@@Z ; 1199544 +?GetUnicode@nsString@@QBEPBGXZ ; 1141413 +?StrAppend@nsStr@@SAXAAU1@ABU1@IH@Z ; 1102413 +?FindChar@nsString@@QBEHGHHH@Z ; 1090463 +?FindChar@nsStr@@SAHABU1@GHHH@Z ; 1090463 +?FindChar2@@YAHPBDIHGHH@Z ; 1056090 +?ElementAt@nsSupportsArray@@UAGPAVnsISupports@@I@Z ; 1055798 +?InsertElementAt@nsVoidArray@@QAEHPAXH@Z ; 926721 +?Compare2To2@@YAHPBD0IH@Z ; 920121 +?EnumerateForwards@nsSupportsArray@@UAGHP6AHPAVnsISupports@@PAX@Z1@Z ; 908730 +?strncasecmp@nsCRT@@SAHPBG0I@Z ; 896894 +?StrCompare@nsStr@@SAHABU1@0HH@Z ; 886450 +?Free@nsMemoryImpl@@UAGXPAX@Z ; 842646 +?Free@nsMemory@@SAXPAX@Z ; 832569 +?Distance@@YAIABV?$nsReadingIterator@G@@0@Z ; 801833 +?copy_string@@YAAAV?$CalculateLength@G@@AAV?$nsReadingIterator@G@@ABV2@AAV1@@Z ; 801833 +?Compare2To1@@YAHPBD0IH@Z ; 797802 +?Alloc@nsMemoryImpl@@UAGPAXI@Z ; 795063 +?Length@nsAFlatString@@UBEIXZ ; 789895 +?advance@?$nsReadingIterator@D@@QAEAAV1@H@Z ; 778072 +?copy_string@@YAAAV?$nsWritingIterator@D@@AAV?$nsReadingIterator@D@@ABV2@AAV1@@Z ; 738318 +?Alloc@nsMemory@@SAPAXI@Z ; 731916 +?write@?$nsWritingIterator@D@@QAEIPBDI@Z ; 724438 +?EqualsWithConversion@nsString@@QBEHABV1@HH@Z ; 680848 +?EqualsIgnoreCase@nsString@@QBEHABV1@@Z ; 680848 +?Length@nsAFlatCString@@UBEIXZ ; 674814 +?GetReadableFragment@nsSlidingSubstring@@MBEPBGAAU?$nsReadableFragment@G@@W4nsFragmentRequest@@I@Z ; 671287 +?do_AppendFromReadable@nsAString@@MAEXABV1@@Z ; 657779 +?Compare@@YAHABVnsAString@@0@Z ; 630913 +?do_AssignFromReadable@nsAString@@MAEXABV1@@Z ; 630139 +?CopyChars2To2@@YAXPADHPBDII@Z ; 615216 +?do_AppendFromReadable@nsACString@@MAEXABV1@@Z ; 584996 +?ObjectAt@nsDeque@@QBEPAXH@Z ; 568869 +?InsertElementAt@nsSupportsArray@@UAGHPAVnsISupports@@I@Z ; 548718 +?AssignFromReadable@nsACString@@IAEXABV1@@Z ; 534684 +??0nsLocalCString@@QAE@PBD@Z ; 525422 +?strlen@nsCRT@@SAIPBG@Z ; 517372 +?get@nsString@@UBEPBGXZ ; 500471 +?GrowCapacity@nsStr@@SAHAAU1@I@Z ; 493115 +?Realloc@nsStr@@CAHAAU1@I@Z ; 493115 +?Alloc@nsStr@@CAHAAU1@I@Z ; 493115 +?EnsureCapacity@nsStr@@SAHAAU1@I@Z ; 493115 +??0nsVoidArray@@QAE@XZ ; 490358 +?strncmp@nsCRT@@SAHPBGPBDI@Z ; 489334 +??1nsVoidArray@@UAE@XZ ; 481308 +??1nsCString@@UAE@XZ ; 478019 +?RemoveElementAt@nsVoidArray@@QAEHH@Z ; 473592 +?AppendElement@nsSupportsArray@@UAGIPAVnsISupports@@@Z ; 464186 +?AppendWithConversion@nsCString@@QAEXG@Z ; 452063 +??0nsCString@@QAE@XZ ; 449721 +?do_AppendFromElementPtr@nsACString@@MAEXPBD@Z ; 427640 +?SetArraySize@nsVoidArray@@IAEXH@Z ; 425906 +?get@nsPromiseFlatCString@@UBEPBDXZ ; 413903 +?Alloc@nsFixedSizeAllocator@@QAEPAXI@Z ; 411293 +??0nsPromiseFlatString@@IAE@ABVnsAString@@@Z ; 410015 +?Free@nsFixedSizeAllocator@@SAXPAXI@Z ; 401028 +?strcmp@nsCRT@@SAHPBG0@Z ; 400500 +??1nsPromiseFlatString@@UAE@XZ ; 398346 +??1nsCAutoString@@UAE@XZ ; 391273 +?GetFlatBufferHandle@nsCString@@MBEPBV?$nsBufferHandle@D@@XZ ; 385981 +?Push@nsDeque@@QAEAAV1@PAX@Z ; 367628 +?Equals@nsIDKey@@UBEHPBVnsHashKey@@@Z ; 358933 +?Clear@nsSupportsArray@@UAGIXZ ; 352217 +?AppendFromReadable@nsAString@@IAEXABV1@@Z ; 352181 +?strncasecmp@nsCRT@@SAHPBGPBDI@Z ; 330906 +?IsAsciiAlpha@nsCRT@@SAHG@Z ; 327047 +??0nsCAutoString@@QAE@XZ ; 311314 +?Clear@nsVoidArray@@QAEXXZ ; 287750 +?Compare1To1@@YAHPBD0IH@Z ; 276525 +?Length@nsSlidingSubstring@@UBEIXZ ; 264724 +?PopFront@nsDeque@@QAEPAXXZ ; 260861 +?AcquireNonOwningReference@Buffer@nsSharedBufferList@@QBEXXZ ; 256259 +?Distance@Position@nsSharedBufferList@@SAHABU12@0@Z ; 254042 +?DiscardUnreferencedPrefix@nsSlidingSharedBufferList@@QAEXPAVBuffer@nsSharedBufferList@@@Z ; 254040 +?ReleaseNonOwningReference@Buffer@nsSharedBufferList@@QBEXXZ ; 254040 +??1nsCStringKey@@UAE@XZ ; 253255 +?HashCode@nsCRT@@SAIPBDPAI@Z ; 251093 +?HashCode@nsCStringKey@@UBEIXZ ; 250679 +?NS_GetGlobalComponentManager@@YAIPAPAVnsIComponentManager@@@Z ; 250625 +??1nsAFlatString@@UAE@XZ ; 249908 +??0nsAFlatString@@QAE@XZ ; 243174 +?Equals@nsCStringKey@@UBEHPBVnsHashKey@@@Z ; 238528 +?IsAsciiSpace@nsCRT@@SAHG@Z ; 238314 +?CopyChars1To2@@YAXPADHPBDII@Z ; 237716 +??0nsLocalString@@QAE@PBGI@Z ; 236845 +?NS_NewAtom@@YAPAVnsIAtom@@ABVnsAString@@@Z ; 235384 +?Release@nsSupportsArray@@UAGKXZ ; 229149 +?GetParameterCount@nsProxyObjectCallInfo@@QBEIXZ ; 228843 +??0nsAutoVoidArray@@QAE@XZ ; 223605 +?do_AppendFromElementPtrLength@nsAString@@MAEXPBGI@Z ; 221664 +?AppendWithConversion@nsString@@QAEXPBDH@Z ; 216212 +?ChangeCase@nsStr@@SAXAAU1@H@Z ; 211594 +?length@?$nsCharTraits@G@@SAIPBG@Z ; 206064 +??0nsLocalString@@QAE@PBG@Z ; 205367 +?SetArrayOwner@nsVoidArray@@IAEXH@Z ; 202301 +?GetFactoryEntry@nsComponentManagerImpl@@IAEPAVnsFactoryEntry@@ABUnsID@@H@Z ; 198436 +?FindFactory@nsComponentManagerImpl@@UAGIABUnsID@@PAPAVnsIFactory@@@Z ; 198385 +?GetFactory@nsFactoryEntry@@QAEIPAPAVnsIFactory@@PAVnsComponentManagerImpl@@@Z ; 198384 +?CreateInstance@nsComponentManagerImpl@@UAGIABUnsID@@PAVnsISupports@@0PAPAX@Z ; 198351 +?ToLowerCase@nsString@@QAEXXZ ; 198180 +?Remove@nsHashtable@@QAEPAXPAVnsHashKey@@@Z ; 191685 +?ToString@AtomImpl@@UAGIAAVnsAString@@@Z ; 189337 +?First@nsAString@@QBEGXZ ; 189245 +?release_ownership_of_buffer_list@nsSlidingSubstring@@AAEXXZ ; 188763 +?IndexOf@nsVoidArray@@QBEHPAX@Z ; 175677 +?StartAssignmentByValue@nsXPIDLString@@AAEPAPAGXZ ; 173850 +?SetCapacity@nsString@@UAEXI@Z ; 170493 +?CopyChars2To1@@YAXPADHPBDII@Z ; 168065 +?Put@nsHashtable@@QAEPAXPAVnsHashKey@@PAX@Z ; 160536 +?DiscardPrefix@nsSlidingString@@QAEXABV?$nsReadingIterator@G@@@Z ; 159450 +?StrAssign@nsStr@@SAXAAU1@ABU1@IH@Z ; 154324 +?Trim@nsStr@@SAXAAU1@PBDHH@Z ; 154152 +?SetCapacity@nsCString@@UAEXI@Z ; 151535 +?GetGlobalServiceManager@nsServiceManager@@SAIPAPAVnsIServiceManager@@@Z ; 148522 +?GetService@nsServiceManagerImpl@@UAGIABUnsID@@0PAPAVnsISupports@@PAVnsIShutdownListener@@@Z ; 146024 +?AddListener@nsServiceEntry@@QAEIPAVnsIShutdownListener@@@Z ; 146022 +?GetUnicode@AtomImpl@@UAGIPAPBG@Z ; 143965 +?Pop@nsDeque@@QAEPAXXZ ; 143309 +??RnsQueryReferent@@UBEIABUnsID@@PAPAX@Z ; 142474 +?normalize_backward@?$nsReadingIterator@G@@QAEXXZ ; 142302 +?QueryReferent@nsWeakReference@@UAGIABUnsID@@PAPAX@Z ; 142237 +?AddRef@nsStorageStream@@UAGKXZ ; 141846 +?Assign@nsACString@@QAEXPBD@Z ; 141606 +?FindCharInSet@nsStr@@SAHABU1@0HH@Z ; 138161 +?FindCharInSet@nsCString@@QBEHPBDH@Z ; 138161 +?CreateInstance@nsComponentManager@@SAIABUnsID@@PAVnsISupports@@0PAPAX@Z ; 137059 +??0nsCStringKey@@QAE@PBDHW4Ownership@0@@Z ; 136293 +??1nsXPIDLCString@@UAE@XZ ; 134911 +??0nsString@@QAE@ABV0@@Z ; 134194 +?do_AssignFromReadable@nsACString@@MAEXABV1@@Z ; 128929 +?ConvertCase1@@YAHPADIH@Z ; 128876 +?AssignWithConversion@nsCString@@QAEXPBGH@Z ; 122216 +?do_AppendFromElement@nsACString@@MAEXD@Z ; 120364 +?Write@FileImpl@@UAGIPBDIPAI@Z ; 120089 +?AssignWithConversion@nsCString@@QAEXABVnsString@@@Z ; 119962 +?AddRef@nsSupportsStringImpl@@UAGKXZ ; 118646 +??0nsCStringKey@@QAE@ABVnsCString@@@Z ; 117124 +?GetResolveState@xptiInterfaceInfo@@QBEEXZ ; 117066 +?AppendUnicodeTo@@YAXABV?$nsReadingIterator@G@@0AAVnsAString@@@Z ; 115792 +?AssignWithConversion@nsString@@QAEXPBD@Z ; 115695 +?Last@nsAString@@QBEGXZ ; 115018 +?ContractIDToClassID@nsComponentManagerImpl@@UAGIPBDPAUnsID@@@Z ; 112973 +?ToNewCString@nsCString@@QBEPADXZ ; 110413 +?LookupLowercasedKeyword@@YAHABVnsCString@@PAVnsHashtable@@@Z ; 110405 +?IsAsciiDigit@nsCRT@@SAHG@Z ; 107530 +?Remove@nsSupportsHashtable@@QAEHPAVnsHashKey@@PAPAVnsISupports@@@Z ; 106325 +??0nsAutoString@@QAE@ABVnsString@@@Z ; 103799 +?CompareWithConversion@nsString@@QBEHPBDHH@Z ; 102438 +?EqualsWithConversion@nsString@@QBEHPBDHH@Z ; 101441 +?Lookup@nsStaticCaseInsensitiveNameTable@@QAEHABVnsString@@@Z ; 101178 +?Trim@nsString@@QAEXPBDHHH@Z ; 100923 +?Release@nsWeakReference@@UAGKXZ ; 100809 +?GetReadableFragment@nsPromiseSubstring@@MBEPBGAAU?$nsReadableFragment@G@@W4nsFragmentRequest@@I@Z ; 98711 +?GetService@nsServiceManager@@SAIABUnsID@@0PAPAVnsISupports@@PAVnsIShutdownListener@@@Z ; 97630 +?write@nsOutputStream@@QAEHPBXH@Z ; 96747 +?Init@nsXPTCVariant@@QAEXABUnsXPTCMiniVariant@@ABVnsXPTType@@E@Z ; 95698 +?acquire_ownership_of_buffer_list@nsSlidingString@@ABEXXZ ; 94592 +?ReleaseReference@nsSlidingSharedBufferList@@QAEXXZ ; 94590 +??1nsSlidingSubstring@@UAE@XZ ; 94580 +??0nsSlidingSubstring@@QAE@XZ ; 94173 +?RemoveElement@nsVoidArray@@QAEHPAX@Z ; 91746 +??RnsGetServiceByCID@@UBEIABUnsID@@PAPAX@Z ; 91521 +??0nsGetServiceByCID@@QAE@ABUnsID@@PAVnsISupports@@PAI@Z ; 91521 +?Release@nsEventQueueImpl@@UAGKXZ ; 87880 +?EqualsIgnoreCase@nsString@@QBEHPBDH@Z ; 86030 +?Init@NS_ConvertUTF8toUCS2@@IAEXPBDI@Z ; 85607 +?Rebind@nsSlidingSubstring@@QAEXABVnsSlidingString@@ABV?$nsReadingIterator@G@@1@Z ; 83943 +?do_AppendFromElementPtr@nsAString@@MAEXPBG@Z ; 83867 +??0nsSupportsArray@@QAE@XZ ; 83106 +?ConvertCase2@@YAHPADIH@Z ; 82718 +?DeleteArray@nsSupportsArray@@IAEXXZ ; 82548 +??1nsSupportsArray@@UAE@XZ ; 82548 +?QueryInterface@nsSupportsArray@@UAGIABUnsID@@PAPAX@Z ; 81918 +?Create@nsSupportsArray@@SGIPAVnsISupports@@ABUnsID@@PAPAX@Z ; 81725 +?NS_NewISupportsArray@@YAIPAPAVnsISupportsArray@@@Z ; 81666 +?CopyChars1To1@@YAXPADHPBDII@Z ; 81524 +??_EnsSupportsArray@@UAEPAXI@Z ; 81168 +?GetMethodInfo@xptiInterfaceInfo@@UAGIGPAPBVnsXPTMethodInfo@@@Z ; 78229 +?Release@xptiInterfaceInfo@@UAGKXZ ; 76117 +?do_AssignFromElementPtr@nsAString@@MAEXPBG@Z ; 73811 +?copy_string@@YAAAPAGAAV?$nsReadingIterator@G@@ABV1@AAPAG@Z ; 71847 +?GetReadableFragment@nsPromiseCSubstring@@MBEPBDAAU?$nsReadableFragment@D@@W4nsFragmentRequest@@I@Z ; 71331 +?GetBuffer@ByteBufferImpl@@UBGPADXZ ; 71201 +?Read@ConverterInputStream@@UAGIPAGIIPAI@Z ; 70839 +?Read@nsPersistentProperties@@QAEHXZ ; 70367 +?do_AssignFromElementPtr@nsACString@@MAEXPBD@Z ; 62916 +?Length@nsPromiseCSubstring@@UBEIXZ ; 62793 +?CompareWithConversion@nsCString@@QBEHPBDHH@Z ; 62172 +??0NS_ConvertASCIItoUCS2@@QAE@PBD@Z ; 61750 +?CreateInstanceByContractID@nsComponentManagerImpl@@UAGIPBDPAVnsISupports@@ABUnsID@@PAPAX@Z ; 61075 +?CreateInstance@nsComponentManager@@SAIPBDPAVnsISupports@@ABUnsID@@PAPAX@Z ; 61075 +?Exit@nsAutoMonitor@@QAEXXZ ; 59293 +?Enter@nsAutoMonitor@@QAEXXZ ; 59293 +PL_GetEventOwner ; 55295 +?RefCountInInterfacePointers@nsProxyObjectCallInfo@@AAEXH@Z ; 55218 +?Clone@nsMemory@@SAPAXPBXI@Z ; 53069 +?Promises@nsAString@@UBEHABV1@@Z ; 52421 +?Promises@nsPromiseSubstring@@UBEHABVnsAString@@@Z ; 52287 +?ContractIDToClassID@nsComponentManager@@SAIPBDPAUnsID@@@Z ; 51898 +?GetStringValue@nsStaticCaseInsensitiveNameTable@@QAEABVnsCString@@H@Z ; 51863 +?CopyUnicodeTo@@YAXABV?$nsReadingIterator@G@@0AAVnsAString@@@Z ; 51424 +??RnsGetInterface@@UBEIABUnsID@@PAPAX@Z ; 51014 +?GetService@nsServiceManager@@SAIPBDABUnsID@@PAPAVnsISupports@@PAVnsIShutdownListener@@@Z ; 50614 +?GetService@nsServiceManagerImpl@@UAGIPBDABUnsID@@PAPAVnsISupports@@PAVnsIShutdownListener@@@Z ; 50608 +?GetElementAt@nsSupportsArray@@UAGIIPAPAVnsISupports@@@Z ; 50421 +??0nsCAutoString@@QAE@PBD@Z ; 50288 +?Release@nsGenericFactory@@UAGKXZ ; 48967 +?Release@nsLocalFile@@UAGKXZ ; 48924 +?CreateInstance@nsGenericFactory@@UAGIPAVnsISupports@@ABUnsID@@PAPAX@Z ; 47807 +?ToNewUnicode@@YAPAGABVnsAString@@@Z ; 47476 +?Equals@nsSupportsArray@@UAGHPBVnsISupportsArray@@@Z ; 47394 +?QueryInterface@nsWeakReference@@UAGIABUnsID@@PAPAX@Z ; 47232 +?ToInteger@nsString@@QBEHPAHI@Z ; 46397 +??0nsGetServiceByContractID@@QAE@PBDPAVnsISupports@@PAI@Z ; 45960 +??RnsGetServiceByContractID@@UBEIABUnsID@@PAPAX@Z ; 45960 +?Reset@nsHashtable@@QAEXP6AHPAVnsHashKey@@PAX1@Z1@Z ; 45160 +?Reset@nsHashtable@@QAEXXZ ; 44779 +?strdup@nsCRT@@SAPAGPBG@Z ; 44542 +?strndup@nsCRT@@SAPAGPBGI@Z ; 44542 +PL_InitEvent ; 42216 +PL_DestroyEvent ; 42216 +?Release@nsProxyObject@@UAGKXZ ; 42053 +?HashCode@nsCRT@@SAIPBGPAI@Z ; 41515 +?MakeDirty@nsLocalFile@@AAEXXZ ; 40921 +?CompressSet@nsStr@@SAXAAU1@PBDHH@Z ; 40756 +?FindSubstr@nsStr@@SAHABU1@0HHH@Z ; 40557 +XPTC_InvokeByIndex ; 40446 +?QueryInterface@nsEventQueueImpl@@UAGIABUnsID@@PAPAX@Z ; 40010 +?Peek@nsDeque@@QAEPAXXZ ; 39695 +?ToUpper@nsCRT@@SAGG@Z ; 39657 +?CopyStrings@nsProxyObjectCallInfo@@AAEXH@Z ; 39492 +PL_DHashTableOperate ; 39446 +??0nsDeque@@QAE@PAVnsDequeFunctor@@@Z ; 38500 +?Empty@nsDeque@@QAEAAV1@XZ ; 38489 +??1nsDeque@@QAE@XZ ; 38489 +?Erase@nsDeque@@QAEAAV1@XZ ; 38489 +?GetSegmentCount@nsSegmentedBuffer@@QAEIXZ ; 38168 +?Release@nsProxyEventObject@@UAGKXZ ; 37461 +?ReplaceElementAt@nsVoidArray@@QAEHPAXH@Z ; 37379 +??0nsAutoString@@QAE@PBG@Z ; 35740 +PL_GetEvent ; 34422 +PL_HandleEvent ; 34415 +PL_PostEvent ; 34415 +?PostEvent@nsEventQueueImpl@@UAG?AW4PRStatus@@PAUPLEvent@@@Z ; 34353 +?strncmp@nsCRT@@SAHPBG0I@Z ; 34311 +?Cut@nsAString@@UAEXII@Z ; 33933 +?Release@nsThread@@UAGKXZ ; 32675 +?GetInstance@nsProxyObjectManager@@SAPAV1@XZ ; 31747 +?EqualsWithConversion@nsCString@@QBEHPBGHH@Z ; 31327 +?CompareWithConversion@nsCString@@QBEHPBGHH@Z ; 31327 +?GetRealObject@nsProxyObject@@QBEPAVnsISupports@@XZ ; 30180 +PL_DHashStringKey ; 29743 +?QueryInterface@nsEventQueueServiceImpl@@UAGIABUnsID@@PAPAX@Z ; 29645 +?GetReadSegment@nsPipe@@QAEIIPAPBDPAI@Z ; 29618 +??1nsXPIDLString@@UAE@XZ ; 29310 +?Release@nsProxyEventClass@@UAGKXZ ; 29259 +??0nsPromiseSubstring@@QAE@ABVnsAString@@II@Z ; 29232 +?Compact@nsSupportsArray@@UAGIXZ ; 28635 +?Mid@nsAString@@QBEIAAV1@II@Z ; 28616 +?AssignFromPromise@nsAString@@IAEXABV1@@Z ; 28510 +?get@nsAFlatString@@UBEPBGXZ ; 28400 +?Equals@nsACString@@QBEHABV1@@Z ; 28339 +?convertMiniVariantToVariant@nsProxyObject@@AAEIPAVnsXPTMethodInfo@@PAUnsXPTCMiniVariant@@PAPAUnsXPTCVariant@@PAE@Z ; 27609 +??_EnsProxyObjectCallInfo@@UAEPAXI@Z ; 27609 +?Post@nsProxyObject@@QAEIIPAVnsXPTMethodInfo@@PAUnsXPTCMiniVariant@@PAVnsIInterfaceInfo@@@Z ; 27609 +??1nsProxyObjectCallInfo@@UAE@XZ ; 27609 +?CallMethod@nsProxyEventObject@@UAGIGPBVnsXPTMethodInfo@@PAUnsXPTCMiniVariant@@@Z ; 27609 +??0nsProxyObjectCallInfo@@QAE@PAVnsProxyObject@@PAVnsXPTMethodInfo@@IPAUnsXPTCVariant@@IPAUPLEvent@@@Z ; 27609 +?Append@NS_ConvertUCS2toUTF8@@IAEXPBGI@Z ; 27265 +?ReplaceChar@nsString@@QAEXPBDG@Z ; 26980 +?CompressSet@nsString@@QAEXPBDGHH@Z ; 26980 +?CompressChars2@@YAHPADIPBD@Z ; 26980 +?CompressWhitespace@nsString@@QAEXHH@Z ; 26980 +?assign_assuming_AddRef@nsCOMPtr_base@@IAEXPAVnsISupports@@@Z ; 26695 +?do_AssignFromElement@nsAString@@MAEXG@Z ; 25781 +??0nsCAutoString@@QAE@ABVCBufDescriptor@@@Z ; 25669 +??0CBufDescriptor@@QAE@PADHIH@Z ; 25623 +?RemoveElementAt@nsSupportsArray@@UAGHI@Z ; 25489 +PL_IsQueueOnCurrentThread ; 25382 +?GetInterfaceInfo@nsProxyEventObject@@UAGIPAPAVnsIInterfaceInfo@@@Z ; 25038 +?Equals@nsACString@@QBEHPBD@Z ; 24972 +?ReadSegments@nsPipeInputStream@nsPipe@@UAGIP6GIPAVnsIInputStream@@PAXPBDIIPAI@Z1I3@Z ; 24934 +?Cut@nsACString@@UAEXII@Z ; 24343 +?RemoveElement@nsSupportsArray@@UAGHPBVnsISupports@@I@Z ; 24174 +?RemoveElement@nsSupportsArray@@UAGIPAVnsISupports@@@Z ; 24174 +??0nsPromiseCSubstring@@QAE@ABVnsACString@@II@Z ; 23764 +?Mid@nsACString@@QBEIAAV1@II@Z ; 23764 +?AssignFromPromise@nsACString@@IAEXABV1@@Z ; 23764 +?ToNewUnicode@nsString@@QBEPAGXZ ; 23688 +?Last@nsACString@@QBEDXZ ; 22996 +?AssignWithConversion@nsCString@@QAEXABVnsAString@@@Z ; 22923 +?IsQueueOnCurrentThread@nsEventQueueImpl@@UAGIPAH@Z ; 22307 +?AppendWithConversion@nsString@@QAEXD@Z ; 22276 +?Compare1To2@@YAHPBD0IH@Z ; 22272 +?GetIID@xptiInterfaceInfo@@UAGIPAPAUnsID@@@Z ; 21683 +?Find@nsString@@QBEHPBDHHH@Z ; 21620 +?AppendFromReadable@nsACString@@IAEXABV1@@Z ; 21546 +??0nsLocalCString@@QAE@PBDI@Z ; 21266 +??0nsAString@@QAE@XZ ; 20650 +?HashCode@nsProxyEventKey@@UBEIXZ ; 20409 +?QueryInterface@nsLocalFile@@UAGIABUnsID@@PAPAX@Z ; 19832 +?QueryElementAt@nsSupportsArray@@UAGIIABUnsID@@PAPAX@Z ; 19439 +?HashCode@nsStringKey@@UBEIXZ ; 19128 +??1nsStringKey@@UAE@XZ ; 18271 +??RnsCreateInstanceByContractID@@UBEIABUnsID@@PAPAX@Z ; 17842 +?GetTypelibGuts@xptiWorkingSet@@QAEPAVxptiTypelibGuts@@ABVxptiTypelib@@@Z ; 17499 +?GetInfoAtNoAddRef@xptiTypelibGuts@@QAEPAVxptiInterfaceInfo@@G@Z ; 17499 +?GetInfoForParam@xptiInterfaceInfo@@UAGIGPBVnsXPTParamInfo@@PAPAVnsIInterfaceInfo@@@Z ; 17441 +?GetIIDForParam@xptiInterfaceInfo@@UAGIGPBVnsXPTParamInfo@@PAPAUnsID@@@Z ; 17381 +?Find@nsString@@QBEHABV1@HHH@Z ; 17158 +?NS_NewAtom@@YAPAVnsIAtom@@PBG@Z ; 17124 +?Delete@nsStr@@SAXAAU1@II@Z ; 17080 +?QueryInterface@nsProxyEventObject@@UAGIABUnsID@@PAPAX@Z ; 17047 +?StripChars@nsStr@@SAXAAU1@PBD@Z ; 16392 +?StripChars@nsCString@@QAEXPBD@Z ; 16392 +?Equals@nsVoidKey@@UBEHPBVnsHashKey@@@Z ; 15797 +?StripChar@nsString@@QAEXGH@Z ; 15611 +?do_AppendFromElementPtrLength@nsACString@@MAEXPBDI@Z ; 15433 +?NS_NewAtom@@YAPAVnsIAtom@@PBD@Z ; 14915 +?strcasecmp@nsCRT@@SAHPBG0@Z ; 14605 +?GetNewOrUsedClass@nsProxyEventClass@@SAPAV1@ABUnsID@@@Z ; 14587 +?do_GetService@@YA?BVnsGetServiceByCID@@ABUnsID@@PAI@Z ; 14568 +??0nsProxyEventObject@@QAE@PAVnsIEventQueue@@HPAVnsISupports@@PAVnsProxyEventClass@@PAV0@@Z ; 14476 +??0nsProxyObject@@QAE@PAVnsIEventQueue@@HPAVnsISupports@@@Z ; 14476 +??1nsProxyEventObject@@UAE@XZ ; 14444 +??_EnsProxyObject@@UAEPAXI@Z ; 14444 +??_EnsProxyEventObject@@UAEPAXI@Z ; 14444 +??1nsProxyObject@@UAE@XZ ; 14444 +?ReleaseData@nsSimpleCharString@@IAEXXZ ; 14127 +??1?$nsSharedBufferHandle@G@@QAE@XZ ; 13784 +?CompressChars1@@YAHPADIPBD@Z ; 13776 +?CompressSet@nsCString@@QAEXPBDGHH@Z ; 13776 +?ReplaceChar@nsCString@@QAEXPBDG@Z ; 13776 +??0NS_ConvertUCS2toUTF8@@QAE@ABVnsAString@@@Z ; 13501 +??0nsCString@@QAE@ABVnsACString@@@Z ; 13490 +?Compact@nsVoidArray@@QAEXXZ ; 13069 +?ResolveAndStat@nsLocalFile@@AAEIH@Z ; 13042 +?Trim@nsCString@@QAEXPBDHHH@Z ; 12473 +?ToCString@nsString@@QBEPADPADII@Z ; 12467 +?Copy@nsXPIDLCString@@SAPADPBD@Z ; 12345 +?StripChars1@@YAHPADIPBD@Z ; 12243 +PL_ProcessPendingEvents ; 11979 +?copy_string@@YAAAV?$LossyConvertEncoding@GD@@AAV?$nsReadingIterator@G@@ABV2@AAV1@@Z ; 11800 +?ToNewCString@@YAPADABVnsAString@@@Z ; 11800 +?ToNewUTF8String@@YAPADABVnsAString@@@Z ; 11776 +?Release@nsProxyObjectManager@@UAGKXZ ; 11736 +??1nsCommonString@@UAE@XZ ; 11669 +?UnlinkBuffer@nsSharedBufferList@@QAEPAVBuffer@1@PAV21@@Z ; 11567 +?FindItem@nsAVLTree@@QBEPAXPAX@Z ; 11472 +?ReallocData@nsSimpleCharString@@IAEXI@Z ; 11366 +?ShiftCharsLeft@@YAXPADIII@Z ; 11222 +?GetYoungest@nsEventQueueImpl@@UAGIPAPAVnsIEventQueue@@@Z ; 10964 +?SetFollowLinks@nsLocalFile@@UAGIH@Z ; 10936 +?GetYoungestEventQueue@nsEventQueueServiceImpl@@AAEIPAVnsIEventQueue@@PAPAV2@@Z ; 10928 +?GetThreadEventQueue@nsEventQueueServiceImpl@@UAGIPAUPRThread@@PAPAVnsIEventQueue@@@Z ; 10925 +??0nsSharedBufferList@@QAE@PAVBuffer@0@@Z ; 10649 +?init_range_from_buffer_list@nsSlidingSubstring@@AAEXXZ ; 10649 +?DestroyBuffers@nsSharedBufferList@@IAEXXZ ; 10647 +??_EnsSlidingSharedBufferList@@UAEPAXI@Z ; 10647 +??1nsSharedBufferList@@UAE@XZ ; 10647 +??RnsCreateInstanceByCID@@UBEIABUnsID@@PAPAX@Z ; 10636 +?Put@nsSupportsHashtable@@QAEHPAVnsHashKey@@PAVnsISupports@@PAPAV3@@Z ; 10605 +?ToLowerCase@nsString@@QBEXAAV1@@Z ; 10514 +?GetPath@nsLocalFile@@UAGIPAPAD@Z ; 10449 +??0nsStringKey@@QAE@PBGHW4Ownership@0@@Z ; 10430 +?AddRef@nsPipeInputStream@nsPipe@@UAGKXZ ; 10377 +?Release@nsPipeInputStream@nsPipe@@UAGKXZ ; 10375 +?Rebind@nsSlidingSubstring@@QAEXABVnsAString@@@Z ; 10240 +?PeekFront@nsDeque@@QAEPAXXZ ; 10192 +??2AtomImpl@@SAPAXIABVnsAString@@@Z ; 10144 +??0AtomImpl@@QAE@XZ ; 10144 +?ResolveEventQueue@nsEventQueueServiceImpl@@UAGIPAVnsIEventQueue@@PAPAV2@@Z ; 10065 +?ToNewUTF8String@nsString@@QBEPADXZ ; 10047 +PL_DHashTableEnumerate ; 9813 +?AddBucket@nsFixedSizeAllocator@@IAEII@Z ; 9776 +?AppendWithConversion@nsCString@@QAEXABVnsString@@H@Z ; 9758 +?Right@nsACString@@QBEIAAV1@I@Z ; 9591 +?Lookup@nsStaticCaseInsensitiveNameTable@@QAEHABVnsCString@@@Z ; 9227 +?Enumerate@nsHashtable@@QAEXP6AHPAVnsHashKey@@PAX1@Z1@Z ; 9133 +?GetParent@xptiInterfaceInfo@@UAGIPAPAVnsIInterfaceInfo@@@Z ; 9105 +_md_EventReceiverProc@16 ; 9061 +?InitWithPath@nsLocalFile@@UAGIPBD@Z ; 8986 +??0nsLocalFile@@QAE@XZ ; 8981 +??_EnsLocalFile@@UAEPAXI@Z ; 8977 +??1nsLocalFile@@UAE@XZ ; 8977 +NS_NewLocalFile ; 8952 +?GetWriteSegment@nsPipe@@QAEIPAPADPAI@Z ; 8809 +?GetProxyForObject@nsProxyObjectManager@@UAGIPAVnsIEventQueue@@ABUnsID@@PAVnsISupports@@HPAPAX@Z ; 8762 +?GetNewOrUsedProxy@nsProxyEventObject@@SAPAV1@PAVnsIEventQueue@@HPAVnsISupports@@ABUnsID@@@Z ; 8762 +?Equals@nsProxyEventKey@@UBEHPBVnsHashKey@@@Z ; 8745 +?AddRef@nsPipeOutputStream@nsPipe@@UAGKXZ ; 8650 +?Release@nsPipeOutputStream@nsPipe@@UAGKXZ ; 8649 +?Read@nsPipeInputStream@nsPipe@@UAGIPADIPAI@Z ; 8617 +??4nsXPIDLCString@@QAEAAV0@PBD@Z ; 8570 +??1nsSimpleCharString@@QAE@XZ ; 8555 +?Equals@nsStringKey@@UBEHPBVnsHashKey@@@Z ; 8497 +?AddRefData@nsSimpleCharString@@IAEXXZ ; 8367 +?Init@nsFixedSizeAllocator@@QAEIPBDPBIHHH@Z ; 7954 +??0nsStringKey@@QAE@ABVnsAString@@@Z ; 7944 +?Release@nsArrayEnumerator@@UAGKXZ ; 7923 +?PostCompleted@nsProxyObjectCallInfo@@QAEXXZ ; 7863 +?SetCompleted@nsProxyObjectCallInfo@@QAEXXZ ; 7863 +??0nsCString@@QAE@ABV0@@Z ; 7622 +?AppendNewSegment@nsSegmentedBuffer@@QAEPADXZ ; 7622 +??_GAtomImpl@@UAEPAXI@Z ; 7566 +??1AtomImpl@@UAE@XZ ; 7566 +??0nsCString@@QAE@PBD@Z ; 7541 +??0nsAutoString@@QAE@ABVCBufDescriptor@@@Z ; 7529 +??0NS_ConvertASCIItoUCS2@@QAE@PBDI@Z ; 7452 +??0nsString@@QAE@ABVnsAString@@@Z ; 7419 +??0CBufDescriptor@@QAE@PAGHIH@Z ; 7406 +??0nsCreateInstanceByContractID@@QAE@PBDPAVnsISupports@@PAI@Z ; 7402 +?EnumerateForwards@nsVoidArray@@QAEHP6AHPAX0@Z0@Z ; 7195 +?AppendInt@nsCString@@QAEXHH@Z ; 7047 +??RnsGetWeakReference@@UBEIABUnsID@@PAPAX@Z ; 7028 +?NS_GetWeakReference@@YAPAVnsIWeakReference@@PAVnsISupports@@PAI@Z ; 7022 +?Clone@nsLocalFile@@UAGIPAPAVnsIFile@@@Z ; 6960 +?AppendRelativePath@nsLocalFile@@UAGIPBD@Z ; 6927 +?Empty@nsSegmentedBuffer@@QAEXXZ ; 6878 +??_EnsIDKey@@UAEPAXI@Z ; 6876 +?Append@nsLocalFile@@UAGIPBD@Z ; 6818 +?RFindChar@nsStr@@SAHABU1@GHHH@Z ; 6753 +?RFindChar@nsString@@QBEHGHHH@Z ; 6753 +?GetWeakReference@nsSupportsWeakReference@@UAGIPAPAVnsIWeakReference@@@Z ; 6751 +?Release@nsMemoryImpl@@UAGKXZ ; 6468 +??1nsSupportsWeakReference@@UAE@XZ ; 6428 +?SetNonBlocking@nsPipeInputStream@nsPipe@@UAGIH@Z ; 6306 +PL_DHashTableRawRemove ; 6270 +?GetNext@nsArrayEnumerator@@UAGIPAPAVnsISupports@@@Z ; 6180 +?ReleaseService@nsServiceManagerImpl@@UAGIABUnsID@@PAVnsISupports@@PAVnsIShutdownListener@@@Z ; 6156 +?RFindSubstr@nsStr@@SAHABU1@0HHH@Z ; 6056 +?RFind@nsCString@@QBEHPBDHHH@Z ; 6052 +?HasMoreElements@nsDirEnumerator@@UAGIPAH@Z ; 5962 +?QueryInterface@nsProxyObjectManager@@UAGIABUnsID@@PAPAX@Z ; 5920 +?GetReadableFragment@nsSlidingString@@MBEPBGAAU?$nsReadableFragment@G@@W4nsFragmentRequest@@I@Z ; 5909 +?ShiftDoubleCharsLeft@@YAXPADIII@Z ; 5858 +?Clone@nsProxyEventKey@@UBEPAVnsHashKey@@XZ ; 5832 +?IsManagerShutdown@nsProxyObjectManager@@SAHXZ ; 5823 +?ReleaseService@nsServiceManager@@SAIABUnsID@@PAVnsISupports@@PAVnsIShutdownListener@@@Z ; 5681 +??4nsSimpleCharString@@QAEXABV0@@Z ; 5572 +?Copy@nsXPIDLString@@SAPAGPBG@Z ; 5526 +??0nsString@@QAE@PBG@Z ; 5504 +?Find@nsProxyEventObject@@QAEPAV1@ABUnsID@@@Z ; 5501 +?WriteSegments@nsPipeOutputStream@nsPipe@@UAGIP6GIPAVnsIOutputStream@@PAXPADIIPAI@Z1I3@Z ; 5497 +?Read@StringUnicharInputStream@@UAGIPAGIIPAI@Z ; 5482 +?WriteFrom@nsPipeOutputStream@nsPipe@@UAGIPAVnsIInputStream@@IPAI@Z ; 5388 +?ToNewCString@nsString@@QBEPADXZ ; 5351 +?Release@nsInputStreamTee@@UAGKXZ ; 5341 +?IndexOf@nsSupportsArray@@UAGHPBVnsISupports@@@Z ; 5281 +?IndexOfStartingAt@nsSupportsArray@@UAGHPBVnsISupports@@I@Z ; 5281 +??6nsOutputStream@@QAEAAV0@PBD@Z ; 5112 +?ToInteger@nsCString@@QBEHPAHI@Z ; 5109 +?do_AssignFromElementPtrLength@nsACString@@MAEXPBDI@Z ; 5103 +?Exists@nsLocalFile@@UAGIPAH@Z ; 5085 +?PL_HashTableInit@@YA?AW4PRStatus@@PAUPLHashTable@@IP6AIPBX@ZP6AH11@Z3PBUPLHashAllocOps@@PAX@Z ; 4964 +??0nsHashtable@@QAE@IH@Z ; 4964 +?Get@nsInt2StrHashtable@@QAEPADI@Z ; 4864 +??BnsSimpleCharString@@QAEPADXZ ; 4785 +?GetConstant@xptiInterfaceInfo@@UAGIGPAPBVnsXPTConstant@@@Z ; 4716 +?PL_HashTableFinalize@@YAXPAUPLHashTable@@@Z ; 4596 +??1nsHashtable@@UAE@XZ ; 4596 +?do_AssignFromElementPtrLength@nsAString@@MAEXPBGI@Z ; 4541 +?Error@nsFileSpec@@QBEIXZ ; 4535 +?GetSpecialEventQueue@nsEventQueueServiceImpl@@UAGIHPAPAVnsIEventQueue@@@Z ; 4454 +?GetStringProperty@nsPersistentProperties@@UAGIABVnsString@@AAV2@@Z ; 4441 +?DumpStatistics@nsTraceRefcnt@@SAIW4StatisticsType@1@PAU_iobuf@@@Z ; 4434 +?GetBufferHandle@nsPrivateSharableString@@UBEPBV?$nsBufferHandle@G@@XZ ; 4434 +?Release@xptiInterfaceInfoManager@@UAGKXZ ; 4417 +?Clone@nsCStringKey@@UBEPAVnsHashKey@@XZ ; 4332 +?normalize_backward@?$nsWritingIterator@D@@QAEXXZ ; 4288 +??1nsFileSpec@@UAE@XZ ; 4256 +?AddRef@BasicStringImpl@@UAGKXZ ; 4185 +??_EnsCStringKey@@UAEPAXI@Z ; 4173 +?ToCString@nsCString@@QBEPADPADII@Z ; 4056 +?First@nsDequeIterator@@QAEAAV1@XZ ; 4049 +??_EnsSubsumeStr@@UAEPAXI@Z ; 4048 +?InsertStringAt@nsStringArray@@QAEHABVnsAString@@H@Z ; 4026 +?Release@BasicStringImpl@@UAGKXZ ; 3967 +?ReleaseValues@nsProperties@@SAHPAVnsHashKey@@PAX1@Z ; 3966 +?StripChars2@@YAHPADIPBD@Z ; 3927 +?ToFloat@nsString@@QBEMPAH@Z ; 3910 +?Release@nsThreadPool@@UAGKXZ ; 3896 +??0nsPromiseFlatCString@@IAE@ABVnsACString@@@Z ; 3888 +??1nsPromiseFlatCString@@UAE@XZ ; 3878 +?Clone@nsStringKey@@UBEPAVnsHashKey@@XZ ; 3824 +?RFindChar2@@YAHPBDIHGHH@Z ; 3738 +??_EnsStringKey@@UAEPAXI@Z ; 3721 +?Alloc@ArenaImpl@@UAGPAXI@Z ; 3688 +?DeleteFirstSegment@nsSegmentedBuffer@@QAEHXZ ; 3646 +?OpenANSIFileDesc@nsLocalFile@@UAGIPBDPAPAU_iobuf@@@Z ; 3547 +?EqualsWithConversion@nsCString@@QBEHPBDHH@Z ; 3544 +?EqualsIgnoreCase@nsCString@@QBEHPBDH@Z ; 3544 +?ResolvePath@nsLocalFile@@AAEIPBDHPAPAD@Z ; 3539 +?CopyFrom@nsSimpleCharString@@QAEXPBDI@Z ; 3498 +?FindCharInReadable@@YAHGAAV?$nsReadingIterator@G@@ABV1@@Z ; 3480 +??0nsPromiseSubstring@@QAE@ABV?$nsReadingIterator@G@@0@Z ; 3431 +?GetStringUTF8@nsRegistry@@UAGIIPBDPAPAD@Z ; 3345 +??0nsSegmentedBuffer@@QAE@XZ ; 3334 +??1nsSegmentedBuffer@@QAE@XZ ; 3333 +?GetInfoForName@xptiInterfaceInfoManager@@UAGIPBDPAPAVnsIInterfaceInfo@@@Z ; 3332 +?Init@nsSegmentedBuffer@@QAEIIIPAVnsIMemory@@@Z ; 3307 +?HasInterfaceRecord@xptiInterfaceInfo@@QBEHXZ ; 3300 +?Compare@@YAHABVnsACString@@0@Z ; 3236 +?vsmprintf@nsTextFormatter@@SAPAGPBGPAD@Z ; 3228 +?smprintf@nsTextFormatter@@SAPAGPBGZZ ; 3228 +?QueryInterface@nsMemoryImpl@@UAGIABUnsID@@PAPAX@Z ; 3156 +??0nsPipe@@QAE@XZ ; 3153 +?Close@nsPipeOutputStream@nsPipe@@UAGIXZ ; 3153 +?SetObserver@nsPipeInputStream@nsPipe@@UAGIPAVnsIInputStreamObserver@@@Z ; 3153 +?Initialize@nsPipe@@UAGIIIHHPAVnsIMemory@@@Z ; 3153 +?NS_NewPipe@@YAIPAPAVnsIInputStream@@PAPAVnsIOutputStream@@IIHHPAVnsIMemory@@@Z ; 3153 +?Close@nsPipeInputStream@nsPipe@@UAGIXZ ; 3152 +??1nsPipe@@UAE@XZ ; 3152 +??_GnsPipe@@UAEPAXI@Z ; 3152 +?GetLeafName@nsLocalFile@@UAGIPAPAD@Z ; 3138 +?Parse@nsID@@QAEHPBD@Z ; 3088 +?GetLeaf@nsSimpleCharString@@QBEPADD@Z ; 3070 +?GetLeafName@nsFileSpec@@QBEPADXZ ; 3070 +?Flush@nsPipeOutputStream@nsPipe@@UAGIXZ ; 3043 +?CheckForDeactivation@nsEventQueueImpl@@AAEXXZ ; 3018 +?RFindChar1@@YAHPBDIHGHH@Z ; 3015 +??0nsCAutoString@@QAE@ABVnsACString@@@Z ; 3014 +?GetNext@nsDirEnumerator@@UAGIPAPAVnsISupports@@@Z ; 2976 +?ProcessPendingEvents@nsEventQueueImpl@@UAGIXZ ; 2951 +?GetInterfaceInfoManagerNoAddRef@xptiInterfaceInfoManager@@SAPAV1@XZ ; 2948 +?CountChar@nsAString@@QBEIG@Z ; 2937 +?AppendInt@nsString@@QAEXHH@Z ; 2922 +?ToUpperCase@nsString@@QAEXXZ ; 2900 +nsUnescapeCount ; 2828 +nsUnescape ; 2828 +??0nsSimpleCharString@@QAE@ABV0@@Z ; 2795 +??4nsFileSpec@@QAEXABV0@@Z ; 2739 +??0nsFileSpec@@QAE@ABV0@@Z ; 2731 +?StripWhitespace@nsString@@QAEXXZ ; 2714 +XPTI_GetInterfaceInfoManager ; 2696 +?StringAt@nsStringArray@@QBEPAVnsString@@H@Z ; 2681 +??0nsArrayEnumerator@@QAE@PAVnsISupportsArray@@@Z ; 2637 +??1nsArrayEnumerator@@UAE@XZ ; 2637 +?GetPRThread@nsThread@@UAGIPAPAUPRThread@@@Z ; 2623 +?GetMainThread@nsIThread@@SAIPAPAV1@@Z ; 2622 +NS_NewArrayEnumerator ; 2582 +??_EnsArrayEnumerator@@UAEPAXI@Z ; 2582 +?CallQueryInterfaceOnProxy@nsProxyEventClass@@AAEIPAVnsProxyEventObject@@ABUnsID@@PAPAV2@@Z ; 2571 +?GetQueue@nsProxyEventObject@@QBEPAVnsIEventQueue@@XZ ; 2571 +?DelegatedQueryInterface@nsProxyEventClass@@UAGIPAVnsProxyEventObject@@ABUnsID@@PAPAX@Z ; 2571 +?GetRealObject@nsProxyEventObject@@QBEPAVnsISupports@@XZ ; 2571 +??_EnsWeakReference@@EAEPAXI@Z ; 2556 +?ReadSegments@ConstCharImpl@@MAGIP6GIPAVnsIInputStream@@PAXPBDIIPAI@Z1I3@Z ; 2520 +?IsDone@nsRegSubtreeEnumerator@@UAGIXZ ; 2490 +?Next@nsRegSubtreeEnumerator@@UAGIXZ ; 2490 +?advance@nsRegSubtreeEnumerator@@MAGIXZ ; 2451 +?GetErrorStringBundleKey@nsErrorService@@UAGIIPAPAD@Z ; 2432 +?GetErrorStringBundle@nsErrorService@@UAGIFPAPAD@Z ; 2432 +?GetIndexOf@nsSupportsArray@@UAGIPAVnsISupports@@PAH@Z ; 2409 +?ToNewUnicode@nsCString@@QBEPAGXZ ; 2376 +?ToNewCString@@YAPADABVnsACString@@@Z ; 2364 +?copy_string@@YAAAPADAAV?$nsReadingIterator@D@@ABV1@AAPAD@Z ; 2364 +?WriteSegmentFun@nsInputStreamTee@@CGIPAVnsIInputStream@@PAXPBDIIPAI@Z ; 2346 +?CurrentItemInPlaceUTF8@nsRegSubtreeEnumerator@@UAGIPAIPAPBD@Z ; 2320 +PL_DHashAllocTable ; 2253 +?Release@nsFileSpecImpl@@UAGKXZ ; 2241 +?GetSharedBufferHandle@nsCommonCString@@MBEPBV?$nsSharedBufferHandle@D@@XZ ; 2217 +?assign@nsCommonString@@IAEXABVnsAString@@@Z ; 2217 +?ReleaseReference@?$nsSharedBufferHandle@G@@QBEXXZ ; 2217 +?NS_AllocateContiguousHandleWithData@@YAPAV?$nsSharedBufferHandle@G@@PBV1@ABVnsAString@@I@Z ; 2217 +?QueryInterface@nsFileSpecImpl@@UAGIABUnsID@@PAPAX@Z ; 2172 +?GetRequest@nsThreadPool@@QAEPAVnsIRunnable@@PAVnsIThread@@@Z ; 2147 +PL_DHashFreeTable ; 2125 +?Clear@nsCStringArray@@QAEXXZ ; 2122 +?ReadSegments@nsInputStreamTee@@UAGIP6GIPAVnsIInputStream@@PAXPBDIIPAI@Z1I3@Z ; 2115 +?TeeSegment@nsInputStreamTee@@AAEIPBDI@Z ; 2045 +?DispatchRequest@nsThreadPool@@UAGIPAVnsIRunnable@@@Z ; 2038 +??1nsThreadPoolBusyBody@@QAE@XZ ; 2038 +??0nsThreadPoolBusyBody@@QAE@PAVnsThreadPool@@@Z ; 2038 +??0nsCreateInstanceByCID@@QAE@ABUnsID@@PAVnsISupports@@PAI@Z ; 2029 +?ReplaceChar@nsCString@@QAEXGG@Z ; 2022 +?CloseStream@nsFileSpecImpl@@UAGIXZ ; 1968 +?do_InsertFromReadable@nsACString@@MAEXABV1@I@Z ; 1965 +?do_InsertFromElement@nsACString@@MAEXDI@Z ; 1965 +??_EnsFileSpecImpl@@UAEPAXI@Z ; 1955 +??1nsFileSpecImpl@@UAE@XZ ; 1955 +??0nsSimpleCharString@@QAE@PBD@Z ; 1936 +?RFindCharInSet@nsCString@@QBEHPBDH@Z ; 1913 +?RFindCharInSet@nsStr@@SAHABU1@0HH@Z ; 1913 +?Release@ByteBufferImpl@@UAGKXZ ; 1905 +?SkipWhiteSpace@nsPersistentProperties@@QAEHH@Z ; 1898 +?First@nsACString@@QBEDXZ ; 1881 +??0nsVoidArray@@QAE@H@Z ; 1876 +?copy_string_backward@@YAAAV?$nsWritingIterator@D@@ABV?$nsReadingIterator@D@@AAV2@AAV1@@Z ; 1834 +?QueryInterface@nsPipeInputStream@nsPipe@@UAGIABUnsID@@PAPAX@Z ; 1782 +?QueryInterface@nsPipe@@UAGIABUnsID@@PAPAX@Z ; 1782 +?CountCharInReadable@@YAIABVnsAString@@G@Z ; 1767 +?IsDirectory@nsLocalFile@@UAGIPAH@Z ; 1765 +?GetFileSpec@nsFileSpecImpl@@UAGIPAVnsFileSpec@@@Z ; 1765 +?CopyUnicodeTo@@YAPAGABVnsAString@@IPAGI@Z ; 1749 +NS_QuickSort ; 1729 +??1nsStringArray@@UAE@XZ ; 1709 +??0nsStringArray@@QAE@XZ ; 1709 +?IsScriptable@xptiInterfaceInfo@@UAGIPAH@Z ; 1690 +?Find@nsCString@@QBEHPBGHHH@Z ; 1674 +?SetLeafName@nsFileSpec@@QAEXPBD@Z ; 1670 +?LeafReplace@nsSimpleCharString@@QAEXDPBD@Z ; 1670 +?NextLine@ManifestLineReader@@QAEHXZ ; 1658 +??0nsFileSpec@@QAE@XZ ; 1656 +PL_DHashTableInit ; 1622 +??4nsSimpleCharString@@QAEXPBD@Z ; 1598 +?GetInterfaceIsArgNumberForParam@xptiInterfaceInfo@@UAGIGPBVnsXPTParamInfo@@PAE@Z ; 1555 +?Init@nsInputStreamTee@@UAGIPAVnsIInputStream@@PAVnsIOutputStream@@@Z ; 1550 +?QueryInterface@nsInputStreamTee@@UAGIABUnsID@@PAPAX@Z ; 1550 +?Right@nsAString@@QBEIAAV1@I@Z ; 1518 +PL_DHashTableFinish ; 1494 +??0nsFileSpecImpl@@QAE@ABVnsFileSpec@@@Z ; 1446 +?MakeInterface@nsFileSpecImpl@@SAIABVnsFileSpec@@PAPAVnsIFileSpec@@@Z ; 1446 +?NS_NewFileSpecWithSpec@@YAIABVnsFileSpec@@PAPAVnsIFileSpec@@@Z ; 1437 +??0xptiInterfaceInfo@@QAE@PBDABUnsID@@ABVxptiTypelib@@PAVxptiWorkingSet@@@Z ; 1434 +?CopyName@xptiInterfaceInfo@@AAEXPBDPAVxptiWorkingSet@@@Z ; 1434 +?SetScriptableFlag@xptiInterfaceInfo@@QAEXH@Z ; 1434 +??1xptiInterfaceInfo@@UAE@XZ ; 1427 +??_GxptiInterfaceInfo@@UAEPAXI@Z ; 1427 +??1nsSupportsHashtable@@UAE@XZ ; 1406 +??0nsACString@@QAE@XZ ; 1361 +?Exists@nsHashtable@@QAEHPAVnsHashKey@@@Z ; 1348 +?SetData@nsSupportsVoidImpl@@UAGIPAX@Z ; 1337 +??0BasicStringImpl@@QAE@XZ ; 1319 +?QueryInterface@BasicStringImpl@@UAGIABUnsID@@PAPAX@Z ; 1319 +??0ConstCharImpl@@QAE@PBDH@Z ; 1319 +?NewMonitor@nsAutoMonitor@@SAPAUPRMonitor@@PBD@Z ; 1312 +??1BasicStringImpl@@UAE@XZ ; 1309 +?DestroyMonitor@nsAutoMonitor@@SAXPAUPRMonitor@@@Z ; 1309 +??_EBasicStringImpl@@UAEPAXI@Z ; 1309 +?Enter@nsAutoCMonitor@@QAEXXZ ; 1307 +?Exit@nsAutoCMonitor@@QAEXXZ ; 1307 +?StringAllocator_wchar_t@@YAAAV?$nsStringAllocator@G@@XZ ; 1306 +?get_allocator@?$nsSharedBufferHandle@G@@IBEAAV?$nsStringAllocator@G@@XZ ; 1306 +?Deallocate@?$XPCOM_StringAllocator@G@@UBEXPAG@Z ; 1306 +NS_NewCharInputStream ; 1303 +?Release@nsRegSubtreeEnumerator@@UAGKXZ ; 1289 +??0nsDequeIterator@@QAE@ABVnsDeque@@H@Z ; 1284 +??FnsDequeIterator@@QAEPAXXZ ; 1284 +?End@nsDeque@@QBE?AVnsDequeIterator@@XZ ; 1284 +?OpenNSPRFileDesc@nsLocalFile@@UAGIHHPAPAUPRFileDesc@@@Z ; 1275 +?StrInsert@nsStr@@SAXAAU1@IABU1@IH@Z ; 1266 +?InsertWithConversion@nsString@@QAEXPBDIH@Z ; 1266 +?ShiftDoubleCharsRight@@YAXPADIII@Z ; 1266 +??0nsSupportsVoidImpl@@QAE@XZ ; 1260 +??_GnsSupportsVoidImpl@@UAEPAXI@Z ; 1260 +??1nsSupportsVoidImpl@@UAE@XZ ; 1260 +?QueryInterface@nsSupportsVoidImpl@@UAGIABUnsID@@PAPAX@Z ; 1260 +?QueryInterface@ConverterInputStream@@UAGIABUnsID@@PAPAX@Z ; 1258 +?get_at_eof@nsRandomAccessInputStream@@MBEHXZ ; 1241 +?GetAtEOF@FileImpl@@UAGIPAH@Z ; 1241 +?get_at_eof@nsRandomAccessStoreClient@@MBEHXZ ; 1241 +?GetTargetArraySize@nsObserverListEnumerator@@ABEIXZ ; 1208 +??YnsSimpleCharString@@QAEXPBD@Z ; 1187 +??_EStringUnicharInputStream@@UAEPAXI@Z ; 1178 +??1StringUnicharInputStream@@UAE@XZ ; 1178 +??0StringUnicharInputStream@@QAE@PAVnsString@@@Z ; 1178 +?NS_NewStringUnicharInputStream@@YAIPAPAVnsIUnicharInputStream@@PAVnsString@@@Z ; 1178 +??0nsInputStreamTee@@QAE@XZ ; 1164 +??_GnsInputStreamTee@@UAEPAXI@Z ; 1164 +??1nsInputStreamTee@@UAE@XZ ; 1164 +?NS_NewInputStreamTee@@YAIPAPAVnsIInputStream@@PAV1@PAVnsIOutputStream@@@Z ; 1164 +?GetTypelibRecord@xptiInterfaceInfo@@QBEABVxptiTypelib@@XZ ; 1156 +?Write@nsStorageStream@@UAGIPBDIPAI@Z ; 1138 +?GetObserverList@nsObserverService@@EAGIPBGPAPAVnsIObserverList@@@Z ; 1119 +?HasMoreElements@nsArrayEnumerator@@UAGIPAH@Z ; 1100 +?GetCString@nsFileSpec@@QBEPBDXZ ; 1098 +PL_DHashVoidPtrKeyStub ; 1098 +?strtok@nsCRT@@SAPADPADPBDPAPAD@Z ; 1084 +?GetInfoForIID@xptiInterfaceInfoManager@@UAGIPBUnsID@@PAPAVnsIInterfaceInfo@@@Z ; 1081 +??_EnsSupportsArrayEnumerator@@UAEPAXI@Z ; 1065 +??0nsSupportsArrayEnumerator@@QAE@PAVnsISupportsArray@@@Z ; 1065 +??1nsSupportsArrayEnumerator@@UAE@XZ ; 1065 +?Enumerate@nsSupportsArray@@UAGIPAPAVnsIEnumerator@@@Z ; 1065 +?First@nsSupportsArrayEnumerator@@UAGIXZ ; 1065 +?WriteFully@nsBinaryOutputStream@@QAEIPBDI@Z ; 1055 +?CurrentItem@nsSupportsArrayEnumerator@@UAGIPAPAVnsISupports@@@Z ; 1053 +?GetConstantCount@xptiInterfaceInfo@@UAGIPAG@Z ; 1040 +?Clone@nsIDKey@@UBEPAVnsHashKey@@XZ ; 1035 +?SetStringProperty@nsPersistentProperties@@UAGIABVnsString@@AAV2@1@Z ; 1006 +?Next@nsSupportsArrayEnumerator@@UAGIXZ ; 993 +?Release@nsStorageInputStream@@UAGKXZ ; 981 +?GetMethodCount@xptiInterfaceInfo@@UAGIPAG@Z ; 970 +?QueryInterface@nsObserverService@@UAGIABUnsID@@PAPAX@Z ; 948 +?FindChar@nsAString@@QBEHGI@Z ; 941 +?LinkBuffer@nsSharedBufferList@@QAEXPAVBuffer@1@00@Z ; 920 +?IsIID@xptiInterfaceInfo@@UAGIPBUnsID@@PAH@Z ; 918 +?AppendBuffer@nsSlidingString@@QAEXPAG00@Z ; 900 +??1nsFilePath@@UAE@XZ ; 886 +?NativeToUnix@nsFileSpecHelpers@@YAXAAVnsSimpleCharString@@@Z ; 886 +?SetDeallocator@nsDeque@@QAEXPAVnsDequeFunctor@@@Z ; 885 +?IsASCII@@YAHABVnsAString@@@Z ; 875 +?SkipLine@nsPersistentProperties@@QAEHH@Z ; 862 +?EnumerateObserverList@nsObserverService@@UAGIPBGPAPAVnsIEnumerator@@@Z ; 855 +?EnumerateObserverList@nsObserverList@@UAGIPAPAVnsIEnumerator@@@Z ; 855 +??4nsPersistentFileDescriptor@@QAEXABVnsFileSpec@@@Z ; 849 +??1nsPersistentFileDescriptor@@UAE@XZ ; 849 +??0nsPersistentFileDescriptor@@QAE@ABVnsFileSpec@@@Z ; 849 +?GetData@nsPersistentFileDescriptor@@QBEXAAVnsSimpleCharString@@@Z ; 849 +?GetPersistentDescriptorString@nsFileSpecImpl@@UAGIPAPAD@Z ; 849 +?FindInReadable@@YAHABVnsAString@@AAV?$nsReadingIterator@G@@1@Z ; 819 +?nsCID_Destroy@@YAHPAVnsHashKey@@PAX1@Z ; 773 +?Read@nsInputStreamTee@@UAGIPADIPAI@Z ; 769 +??1nsFactoryEntry@@QAE@XZ ; 737 +?nsFactoryEntry_Destroy@@YAHPAVnsHashKey@@PAX1@Z ; 733 +??0nsFileSpecImpl@@QAE@XZ ; 726 +?NS_NewFileSpec@@YAIPAPAVnsIFileSpec@@@Z ; 726 +?Create@nsFileSpecImpl@@SGIPAVnsISupports@@ABUnsID@@PAPAX@Z ; 726 +?UnixToNative@nsFileSpecHelpers@@YAXAAVnsSimpleCharString@@@Z ; 719 +?Invalidate@xptiInterfaceInfo@@QAEXXZ ; 717 +?AppendWithConversion@nsCString@@QAEXPBGH@Z ; 697 +??0nsFactoryEntry@@QAE@ABUnsID@@PBD1PAVnsIComponentLoader@@@Z ; 695 +?SetInfoAt@xptiTypelibGuts@@QAEIGPAVxptiInterfaceInfo@@@Z ; 683 +PL_DHashGetKeyStub ; 678 +PL_DHashMoveEntryStub ; 678 +?GrowCapacity@nsDeque@@AAEAAV1@XZ ; 673 +?AssignWithConversion@nsString@@QAEXPBDH@Z ; 665 +??4nsFilePath@@QAEXABVnsFileSpec@@@Z ; 659 +??0nsFilePath@@QAE@ABVnsFileSpec@@@Z ; 659 +?Canonify@nsFileSpecHelpers@@YAXAAVnsSimpleCharString@@H@Z ; 653 +?FromFileSpec@nsFileSpecImpl@@UAGIPBVnsIFileSpec@@@Z ; 652 +?GetValueType@nsRegistry@@UAGIIPBDPAI@Z ; 652 +?GetBytesUTF8@nsRegistry@@UAGIIPBDPAIPAPAE@Z ; 651 +?Write32@nsBinaryOutputStream@@UAGII@Z ; 649 +?EnumerateBackwards@nsSupportsArray@@UAGHP6AHPAVnsISupports@@PAX@Z1@Z ; 648 +?SetFromFileSpec@nsFileSpecImpl@@UAGIABVnsFileSpec@@@Z ; 634 +?smprintf_free@nsTextFormatter@@SAXPAG@Z ; 623 +?nsEndl@@YAAAVnsOutputStream@@AAV1@@Z ; 615 +?QueryInterface@nsGenericFactory@@UAGIABUnsID@@PAPAX@Z ; 606 +?Equals@nsAString@@QBEHPBG@Z ; 599 +?strcasecmp@nsCRT@@SAHPBGPBD@Z ; 585 +?put@nsOutputStream@@QAEXD@Z ; 572 +?IsFile@nsLocalFile@@UAGIPAH@Z ; 570 +?ForEach@nsDeque@@QBEXAAVnsDequeFunctor@@@Z ; 558 +?Release@EmptyEnumeratorImpl@@UAGKXZ ; 553 +NS_NewEmptyEnumerator ; 553 +?HasMoreElements@EmptyEnumeratorImpl@@UAGIPAH@Z ; 552 +?AddRef@FileImpl@@UAGKXZ ; 549 +?Release@FileImpl@@UAGKXZ ; 542 +?snprintf@nsTextFormatter@@SAIPAGIPBGZZ ; 534 +?vsnprintf@nsTextFormatter@@SAIPAGIPBGPAD@Z ; 534 +?Available@nsPipeInputStream@nsPipe@@UAGIPAI@Z ; 533 +?PushFront@nsDeque@@QAEAAV1@PAX@Z ; 522 +?AddItem@nsAVLTree@@QAE?AW4eAVLStatus@@PAX@Z ; 518 +??0nsAutoString@@QAE@PBGH@Z ; 509 +?IsDone@nsObserverListEnumerator@@UAGIXZ ; 479 +?MoveToIndex@nsObserverListEnumerator@@AAEII@Z ; 479 +?ReleaseService@nsServiceManager@@SAIPBDPAVnsISupports@@PAVnsIShutdownListener@@@Z ; 477 +?ReleaseService@nsServiceManagerImpl@@UAGIPBDPAVnsISupports@@PAVnsIShutdownListener@@@Z ; 477 +?AppendWithConversion@nsCString@@QAEXABVnsAString@@@Z ; 467 +?CreateDll@nsNativeComponentLoader@@AAEIPAVnsIFile@@PBDPA_J2PAPAVnsDll@@@Z ; 466 +?Flush@FileImpl@@UAGIXZ ; 455 +??1nsNSPRPath@@UAE@XZ ; 444 +??BnsNSPRPath@@QBEPBDXZ ; 444 +??0nsByteArrayInputStream@@QAE@PADI@Z ; 443 +??_EnsByteArrayInputStream@@UAEPAXI@Z ; 443 +??1nsByteArrayInputStream@@UAE@XZ ; 443 +?QueryInterface@nsByteArrayInputStream@@UAGIABUnsID@@PAPAX@Z ; 443 +?NS_NewByteArrayInputStream@@YAIPAPAVnsIByteArrayInputStream@@PADK@Z ; 443 +PL_DHashMatchEntryStub ; 442 +?ScriptableFlagIsValid@xptiInterfaceInfo@@ABEHXZ ; 439 +?PartiallyResolveLocked@xptiInterfaceInfo@@QAEHPAUXPTInterfaceDescriptor@@PAVxptiWorkingSet@@@Z ; 439 +??1xptiInterfaceGuts@@QAE@XZ ; 439 +?QueryInterface@FileImpl@@UAGIABUnsID@@PAPAX@Z ; 433 +??1xptiFile@@QAE@XZ ; 424 +?QueryInterface@nsSupportsStringImpl@@UAGIABUnsID@@PAPAX@Z ; 422 +?ReplaceChar@nsString@@QAEXGG@Z ; 421 +?Notify@nsObserverService@@UAGIPAVnsISupports@@PBG1@Z ; 416 +??0nsSlidingString@@QAE@PAG00@Z ; 408 +?NewWrappingBuffer@nsSharedBufferList@@SAPAVBuffer@1@PAG00@Z ; 408 +??0nsSlidingSubstring@@IAE@PAVnsSlidingSharedBufferList@@@Z ; 408 +??0nsCStringArray@@QAE@XZ ; 394 +??1nsCStringArray@@UAE@XZ ; 393 +??EnsDirectoryIterator@@QAEAAV0@XZ ; 377 +?Reset@nsSupportsHashtable@@QAEXXZ ; 370 +?ReadSegments@nsByteArrayInputStream@@UAGIP6GIPAVnsIInputStream@@PAXPBDIIPAI@Z1I3@Z ; 356 +?GetFileSize@nsLocalFile@@UAGIPA_J@Z ; 354 +?SetDataWithLength@nsSupportsStringImpl@@UAGIIPBD@Z ; 344 +??0nsSupportsStringImpl@@QAE@XZ ; 344 +??1nsSupportsStringImpl@@UAE@XZ ; 337 +??_EnsSupportsStringImpl@@UAEPAXI@Z ; 337 +?GetModule@nsDll@@QAEIPAVnsISupports@@PAPAVnsIModule@@@Z ; 331 +?Release@nsStorageStream@@UAGKXZ ; 328 +?Release@nsSupportsIDImpl@@UAGKXZ ; 327 +?CopyASCIItoUCS2@@YAXABVnsACString@@AAVnsAString@@@Z ; 327 +?copy_string@@YAAAV?$LossyConvertEncoding@DG@@AAV?$nsReadingIterator@D@@ABV2@AAV1@@Z ; 327 +??_EnsCString@@UAEPAXI@Z ; 324 +?StringAt@nsStringArray@@QBEXHAAVnsAString@@@Z ; 321 +?ToString@nsID@@QBEPADXZ ; 319 +?GetLength@UnicharBufferImpl@@UBGHXZ ; 316 +?Fill@ByteBufferImpl@@UAGHPAIPAVnsIInputStream@@I@Z ; 316 +?Fill@ConverterInputStream@@IAEHPAI@Z ; 316 +?copy_string_backward@@YAAAV?$nsWritingIterator@G@@ABV?$nsReadingIterator@G@@AAV2@AAV1@@Z ; 310 +?do_InsertFromReadable@nsAString@@MAEXABV1@I@Z ; 310 +??0nsFileSpec@@QAE@PBDH@Z ; 307 +?SetData@nsSupportsStringImpl@@UAGIPBD@Z ; 295 +?InsertCStringAt@nsCStringArray@@QAEHABVnsCString@@H@Z ; 288 +??YnsFileSpec@@QAEXPBD@Z ; 281 +?CompressWhitespace@nsCString@@QAEXHH@Z ; 278 +?GetFactory@nsNativeComponentLoader@@UAGIABUnsID@@PBD1PAPAVnsIFactory@@@Z ; 273 +?GetFactoryFromModule@nsNativeComponentLoader@@AAEIPAVnsDll@@ABUnsID@@PAPAVnsIFactory@@@Z ; 273 +?GetReadableFragment@nsPromiseConcatenation@@MBEPBGAAU?$nsReadableFragment@G@@W4nsFragmentRequest@@I@Z ; 268 +?Load@nsDll@@QAEHXZ ; 254 +?HasMoreElements@nsAdapterEnumerator@@UAGIPAH@Z ; 251 +?Next@nsObserverListEnumerator@@UAGIXZ ; 250 +??0nsSubsumeStr@@QAE@XZ ; 250 +?Subsume@nsSubsumeStr@@QAEHPAGHH@Z ; 250 +?CurrentItem@nsObserverListEnumerator@@UAGIPAPAVnsISupports@@@Z ; 250 +?Release@nsRegistryNode@@UAGKXZ ; 245 +?PrepareEncoder@nsFSStringConversion@@CAIXZ ; 241 +?UCSToNewFS@nsFSStringConversion@@SAIPBGPAPAD@Z ; 241 +?Write@nsBinaryOutputStream@@UAGIPBDIPAI@Z ; 238 +?IsDirectory@nsFileSpec@@QBEHXZ ; 236 +?QueryInterface@nsConjoiningEnumerator@@UAGIABUnsID@@PAPAX@Z ; 236 +_DllMain@12 ; 235 +??_GnsObserverListEnumerator@@UAEPAXI@Z ; 229 +?First@nsObserverListEnumerator@@UAGIXZ ; 229 +??0nsObserverListEnumerator@@QAE@PAVnsISupportsArray@@@Z ; 229 +?SetComponentInfo@nsGenericFactory@@UAGIPAUnsModuleComponentInfo@@@Z ; 228 +?NS_NewGenericFactory@@YAIPAPAVnsIGenericFactory@@PAUnsModuleComponentInfo@@@Z ; 228 +?Create@nsGenericFactory@@SGIPAVnsISupports@@ABUnsID@@PAPAX@Z ; 228 +??0nsGenericFactory@@QAE@PAUnsModuleComponentInfo@@@Z ; 228 +?do_InsertFromElementPtrLength@nsAString@@MAEXPBGII@Z ; 227 +??1nsGenericFactory@@UAE@XZ ; 226 +?GetBufferSize@ByteBufferImpl@@UBGIXZ ; 226 +??_EnsGenericFactory@@UAEPAXI@Z ; 226 +??4nsFileSpec@@QAEXABVnsFilePath@@@Z ; 219 +?GetLastModifiedTime@nsLocalFile@@UAGIPA_J@Z ; 217 +?RFindInReadable@@YAHABVnsAString@@AAV?$nsReadingIterator@G@@1@Z ; 217 +?GetTarget@nsLocalFile@@UAGIPAPAD@Z ; 216 +?CopyFields@xptiFile@@AAEXABV1@@Z ; 212 +??0xptiFile@@QAE@XZ ; 212 +?ConvertStringLineBreaks@nsLinebreakConverter@@SAIAAVnsString@@W4ELinebreakType@1@1@Z ; 212 +??0xptiFile@@QAE@ABVnsInt64@@0PBDPAVxptiWorkingSet@@PAUXPTHeader@@@Z ; 212 +?QueryInterface@nsDirectoryService@@UAGIABUnsID@@PAPAX@Z ; 211 +?ReplaceSubstring@nsString@@QAEXABV1@0@Z ; 210 +?GetLongLong@nsRegistry@@UAGIIPBDPA_J@Z ; 210 +??0nsSimpleCharString@@QAE@ABVnsString@@@Z ; 209 +PL_DHashClearEntryStub ; 209 +??4nsSimpleCharString@@QAEXABVnsString@@@Z ; 209 +?Release@nsDirectoryService@@UAGKXZ ; 208 +?GetType@xptiFileType@@SA?AW4Type@1@PBD@Z ; 208 +?AutoRegisterComponent@nsNativeComponentLoader@@UAGIHPAVnsIFile@@PAH@Z ; 208 +?SetLeafName@nsFileSpecImpl@@UAGIPBD@Z ; 207 +?SetLeafName@nsFileSpec@@QAEXABVnsString@@@Z ; 203 +??0nsFilePath@@QAE@ABVnsString@@H@Z ; 203 +nsEscapeHTML ; 200 +?SetActivityIsLegal@nsTraceRefcnt@@SAXH@Z ; 198 +?GetProxy@nsCWeakReferent@@QAEPAVnsCWeakProxy@@XZ ; 196 +??0nsCWeakProxy@@QAE@PAXPAVnsCWeakReferent@@@Z ; 196 +??0nsCWeakReferent@@QAE@PAX@Z ; 196 +?ReleaseReference@nsCWeakProxy@@QAEXXZ ; 195 +??_EnsCWeakProxy@@UAEPAXI@Z ; 195 +??1nsCWeakProxy@@UAE@XZ ; 195 +??1nsCWeakReferent@@UAE@XZ ; 195 +nsEscape ; 178 +nsEscapeCount ; 178 +?GetIsOpen@FileImpl@@UAGIPAH@Z ; 177 +?Exists@nsFileSpec@@QBEHXZ ; 173 +?read@nsInputStream@@QAEHPAXH@Z ; 171 +?Read@FileImpl@@UAGIPADIPAI@Z ; 171 +??0nsAutoString@@QAE@G@Z ; 170 +?GetClassObject@nsGenericModule@@UAGIPAVnsIComponentManager@@ABUnsID@@1PAPAX@Z ; 169 +?Get@nsDirectoryService@@UAGIPBDABUnsID@@PAPAX@Z ; 165 +?Seek@nsStorageStream@@AAGIH@Z ; 164 +?SetLength@nsStorageStream@@UAGII@Z ; 164 +?Close@FileImpl@@UAGIXZ ; 163 +?WriteStringZ@nsBinaryOutputStream@@UAGIPBD@Z ; 163 +?AppendElements@nsSupportsArray@@UAGHPAVnsISupportsArray@@@Z ; 162 +?Write8@nsBinaryOutputStream@@UAGIE@Z ; 162 +?AddObserver@nsObserverService@@UAGIPAVnsIObserver@@PBG@Z ; 158 +?AddObserver@nsObserverList@@UAGIPAVnsIObserver@@@Z ; 158 +?read@ConstCharImpl@@MAEHPADI@Z ; 156 +?Read@BasicStringImpl@@UAGIPADIPAI@Z ; 156 +?GetGlobalMemoryService@nsMemory@@SAPAVnsIMemory@@XZ ; 155 +?GetData@nsSupportsStringImpl@@UAGIPAPAD@Z ; 153 +??0nsCAutoString@@QAE@PBDH@Z ; 152 +??0nsObjectHashtable@@QAE@P6APAXPAVnsHashKey@@PAX1@Z1P6AH011@Z1IH@Z ; 140 +??0ArenaImpl@@QAE@XZ ; 139 +?Init@ArenaImpl@@UAGII@Z ; 139 +?Create@ArenaImpl@@SGIPAVnsISupports@@ABUnsID@@PAPAX@Z ; 139 +?NS_NewHeapArena@@YAIPAPAVnsIArena@@I@Z ; 139 +?QueryInterface@ArenaImpl@@UAGIABUnsID@@PAPAX@Z ; 139 +??1nsObjectHashtable@@UAE@XZ ; 138 +?Reset@nsObjectHashtable@@QAEXXZ ; 138 +?ResolveLocked@xptiInterfaceInfo@@AAEHPAVxptiWorkingSet@@@Z ; 129 +?GetNext@nsAdapterEnumerator@@UAGIPAPAVnsISupports@@@Z ; 129 +?GetCompleted@nsProxyObjectCallInfo@@QAEHXZ ; 124 +??0CBufDescriptor@@QAE@PBGHIH@Z ; 123 +??0nsServiceEntry@@QAE@ABUnsID@@PAVnsISupports@@@Z ; 122 +?NotifyListeners@nsServiceEntry@@QAEIXZ ; 122 +??1nsServiceEntry@@QAE@XZ ; 122 +?Resolve@xptiInterfaceInfo@@AAEHPAVxptiWorkingSet@@@Z ; 122 +??4nsFileSpec@@QAEXPBD@Z ; 121 +?QueryInterface@nsRegistryNode@@UAGIABUnsID@@PAPAX@Z ; 114 +?RegisterThreadSelf@nsThread@@QAEIXZ ; 114 +?FindSymbol@nsDll@@QAEPAXPBD@Z ; 114 +??_GnsRegistryNode@@UAEPAXI@Z ; 114 +??0nsThread@@QAE@XZ ; 114 +??0nsRegistryNode@@QAE@PAXPADJ@Z ; 114 +?CurrentItem@nsRegSubtreeEnumerator@@UAGIPAPAVnsISupports@@@Z ; 114 +??1nsRegistryNode@@UAE@XZ ; 114 +?Init@nsThread@@UAGIPAVnsIRunnable@@IW4PRThreadPriority@@W4PRThreadScope@@W4PRThreadState@@@Z ; 113 +?NS_NewThread@@YAIPAPAVnsIThread@@PAVnsIRunnable@@IW4PRThreadState@@W4PRThreadPriority@@W4PRThreadScope@@@Z ; 113 +?WaitUntilReadyToStartMain@nsThread@@QAEXXZ ; 113 +?Main@nsThread@@SAXPAX@Z ; 113 +??1ArenaImpl@@UAE@XZ ; 112 +??_GArenaImpl@@UAEPAXI@Z ; 112 +?GetKey@nsRegistryNode@@UAGIPAI@Z ; 112 +?Exit@nsThread@@SAXPAX@Z ; 111 +??1nsThread@@UAE@XZ ; 110 +?GetCurrent@nsIThread@@SAIPAPAV1@@Z ; 110 +??_GnsThread@@UAEPAXI@Z ; 110 +?WriteToLog@xptiInterfaceInfoManager@@SAXPBDZZ ; 110 +?GetIThread@nsIThread@@SAIPAUPRThread@@PAPAV1@@Z ; 110 +?Write@nsPipeOutputStream@nsPipe@@UAGIPBDIPAI@Z ; 109 +?AddThread@nsThreadPool@@IAEIXZ ; 109 +?Run@nsThreadPoolRunnable@@UAGIXZ ; 109 +??0nsThreadPoolRunnable@@QAE@PAVnsThreadPool@@@Z ; 109 +?DeleteLastElement@nsSupportsArray@@UAGIPAVnsISupports@@@Z ; 108 +??_GnsThreadPoolRunnable@@UAEPAXI@Z ; 108 +?RemoveLastElement@nsSupportsArray@@UAGHPBVnsISupports@@@Z ; 108 +?RemoveThread@nsThreadPool@@IAEIPAVnsIThread@@@Z ; 108 +??1nsThreadPoolRunnable@@UAE@XZ ; 108 +?GetNameUTF8@nsRegistryNode@@UAGIPAPAD@Z ; 108 +?RemoveObserver@nsObserverService@@UAGIPAVnsIObserver@@PBG@Z ; 106 +?RemoveObserver@nsObserverList@@UAGIPAVnsIObserver@@@Z ; 106 +?Contains@nsLocalFile@@UAGIPAVnsIFile@@HPAH@Z ; 104 +?RegistryLocationForSpec@nsComponentManagerImpl@@UAGIPAVnsIFile@@PAPAD@Z ; 104 +?Close@ConverterInputStream@@UAGIXZ ; 103 +??1nsDll@@QAE@XZ ; 103 +?Init@nsDll@@AAEXPAVnsIFile@@@Z ; 100 +??0nsDll@@QAE@PAVnsIFile@@PBDPA_J2@Z ; 100 +?SpecForRegistryLocation@nsComponentManagerImpl@@UAGIPBDPAPAVnsIFile@@@Z ; 100 +?UnescapeKey@nsRegistry@@UAGIPAEIPAIPAPAE@Z ; 99 +?GetRegistryDllInfo@nsNativeComponentLoader@@AAEIIPA_J0@Z ; 99 +NS_NewIOFileStream ; 98 +?Open@FileImpl@@UAGIABVnsFileSpec@@HH@Z ; 98 +??1FileImpl@@UAE@XZ ; 98 +??_GFileImpl@@UAEPAXI@Z ; 98 +??0FileImpl@@QAE@ABVnsFileSpec@@HH@Z ; 98 +?HasChanged@nsDll@@QAEHXZ ; 94 +?Read@nsByteArrayInputStream@@UAGIPADIPAI@Z ; 87 +PL_DHashGetStubOps ; 86 +??0nsStorageStream@@QAE@XZ ; 83 +?NS_NewStorageStream@@YAIIIPAPAVnsIStorageStream@@@Z ; 83 +??1nsStorageStream@@UAE@XZ ; 83 +?Init@nsStorageStream@@QAGIIIPAVnsIMemory@@@Z ; 83 +??_EnsStorageStream@@UAEPAXI@Z ; 83 +?GetOutputStream@nsStorageStream@@UAGIHPAPAVnsIOutputStream@@@Z ; 82 +?WriteBytes@nsBinaryOutputStream@@UAGIPBDI@Z ; 82 +??0nsBinaryOutputStream@@QAE@PAVnsIOutputStream@@@Z ; 81 +?Write16@nsBinaryOutputStream@@UAGIG@Z ; 81 +??1nsStorageInputStream@@UAE@XZ ; 81 +?Available@nsStorageInputStream@@UAGIPAI@Z ; 81 +?NewInputStream@nsStorageStream@@UAGIHPAPAVnsIInputStream@@@Z ; 81 +??_EnsStorageInputStream@@UAEPAXI@Z ; 81 +?WriteFloat@nsBinaryOutputStream@@UAGIM@Z ; 81 +?NS_NewBinaryOutputStream@@YAIPAPAVnsIBinaryOutputStream@@PAVnsIOutputStream@@@Z ; 81 +?Release@nsBinaryOutputStream@@UAGKXZ ; 81 +??_EnsBinaryOutputStream@@UAEPAXI@Z ; 81 +?Read@nsStorageInputStream@@UAGIPADIPAI@Z ; 81 +??0nsStorageInputStream@@QAE@PAVnsStorageStream@@I@Z ; 81 +??_EConverterInputStream@@UAEPAXI@Z ; 80 +??0ByteBufferImpl@@QAE@XZ ; 80 +?QueryInterface@nsSupportsPRInt32Impl@@UAGIABUnsID@@PAPAX@Z ; 80 +?NS_NewUnicharBuffer@@YAIPAPAVnsIUnicharBuffer@@PAVnsISupports@@I@Z ; 80 +?NS_NewB2UConverter@@YAIPAPAVnsIUnicodeDecoder@@PAVnsISupports@@PAVnsString@@@Z ; 80 +?QueryInterface@UnicharBufferImpl@@UAGIABUnsID@@PAPAX@Z ; 80 +??1ByteBufferImpl@@UAE@XZ ; 80 +?Init@UnicharBufferImpl@@UAGII@Z ; 80 +??0UnicharBufferImpl@@QAE@XZ ; 80 +?Create@UnicharBufferImpl@@SGIPAVnsISupports@@ABUnsID@@PAPAX@Z ; 80 +?NS_NewByteBuffer@@YAIPAPAVnsIByteBuffer@@PAVnsISupports@@I@Z ; 80 +?Init@ByteBufferImpl@@UAGII@Z ; 80 +?QueryInterface@ByteBufferImpl@@UAGIABUnsID@@PAPAX@Z ; 80 +??0ConverterInputStream@@QAE@PAVnsIInputStream@@PAVnsIUnicodeDecoder@@I@Z ; 80 +??1UnicharBufferImpl@@UAE@XZ ; 80 +??_EUnicharBufferImpl@@UAEPAXI@Z ; 80 +?NS_NewConverterStream@@YAIPAPAVnsIUnicharInputStream@@PAVnsISupports@@PAVnsIInputStream@@HPAVnsString@@@Z ; 80 +??_EByteBufferImpl@@UAEPAXI@Z ; 80 +??1ConverterInputStream@@UAE@XZ ; 80 +?Create@ByteBufferImpl@@SGIPAVnsISupports@@ABUnsID@@PAPAX@Z ; 80 +?is_open@nsFileClient@@QBEHXZ ; 79 +?GetData@nsSupportsPRBoolImpl@@UAGIPAH@Z ; 78 +??0nsSupportsPRInt32Impl@@QAE@XZ ; 77 +?SetNativePath@nsFileSpecImpl@@UAGIPBD@Z ; 74 +?InsertFromReadable@nsAString@@IAEXABV1@I@Z ; 74 +?ToString@nsSupportsStringImpl@@UAGIPAPAD@Z ; 74 +?IsDone@nsSupportsArrayEnumerator@@UAGIXZ ; 73 +?AllocateBuffers@FileImpl@@IAEIII@Z ; 71 +??1nsOutputStream@@UAE@XZ ; 71 +??_EnsSupportsPRInt32Impl@@UAEPAXI@Z ; 70 +??1nsOutputFileStream@@UAE@XZ ; 70 +?AssignFrom@nsOutputFileStream@@IAEXPAVnsISupports@@@Z ; 70 +??0nsRandomAccessOutputStream@@IAE@XZ ; 70 +??0nsOutputStream@@QAE@PAVnsIOutputStream@@@Z ; 70 +??1nsRandomAccessOutputStream@@UAE@XZ ; 70 +??1nsSupportsPRInt32Impl@@UAE@XZ ; 70 +??0nsDirectoryIterator@@QAE@ABVnsFileSpec@@H@Z ; 68 +??1nsDirectoryIterator@@UAE@XZ ; 68 +?Promises@nsPromiseCConcatenation@@UBEHABVnsACString@@@Z ; 67 +?Length@nsPromiseConcatenation@@UBEIXZ ; 67 +?AppendFromPromise@nsAString@@IAEXABV1@@Z ; 67 +?IndexOf@nsStringArray@@QBEHABVnsAString@@@Z ; 67 +??0nsOutputFileStream@@QAE@ABVnsFileSpec@@HH@Z ; 67 +?Available@nsInputStreamTee@@UAGIPAI@Z ; 66 +?HashContractID@nsComponentManagerImpl@@IAEIPBDABUnsID@@@Z ; 65 +??0nsSubsumeCStr@@QAE@PADHH@Z ; 65 +?close@nsInputStream@@QAEIXZ ; 65 +?HandleEvent@nsEventQueueImpl@@UAGIPAUPLEvent@@@Z ; 62 +?PostAndWait@nsProxyObject@@QAEIPAVnsProxyObjectCallInfo@@@Z ; 62 +?WaitForEvent@nsEventQueueImpl@@UAGIPAPAUPLEvent@@@Z ; 62 +?SetCallersQueue@nsProxyObjectCallInfo@@QAEXPAVnsIEventQueue@@@Z ; 62 +PL_PostSynchronousEvent ; 62 +?PostSynchronousEvent@nsEventQueueImpl@@UAGIPAUPLEvent@@PAPAX@Z ; 62 +PL_WaitForEvent ; 62 +?strcmp@nsCRT@@SAHPBGPBD@Z ; 60 +?ns_file_convert_result@@YAIH@Z ; 60 +?Load@nsLocalFile@@UAGIPAPAUPRLibrary@@@Z ; 54 +?hash_enumerator@@YAHPAVnsHashKey@@PAX1@Z ; 53 +?Shutdown@nsDll@@QAEIXZ ; 53 +??1nsAdapterEnumerator@@UAE@XZ ; 51 +?IsDone@nsHashtableEnumerator@@UAGIXZ ; 51 +?CurrentItem@nsHashtableEnumerator@@UAGIPAPAVnsISupports@@@Z ; 51 +?Next@nsHashtableEnumerator@@UAGIXZ ; 51 +??0nsAdapterEnumerator@@QAE@PAVnsIEnumerator@@@Z ; 51 +??HnsFileSpec@@QBE?AV0@PBD@Z ; 50 +?Read32@nsBinaryInputStream@@UAGIPAI@Z ; 50 +?Available@nsByteArrayInputStream@@UAGIPAI@Z ; 50 +?flush@nsOutputFileStream@@UAEIXZ ; 49 +?RegisterComponentCommon@nsComponentManagerImpl@@IAEIABUnsID@@PBD11HH1@Z ; 48 +??0nsString@@QAE@AAVnsSubsumeStr@@@Z ; 47 +??0nsSubsumeStr@@QAE@PAGHH@Z ; 47 +??0CBufDescriptor@@QAE@PBDHIH@Z ; 46 +?Initialize@nsGenericModule@@IAEIXZ ; 45 +??0nsGenericModule@@QAE@PBDIPAUnsModuleComponentInfo@@P6AXPAVnsIModule@@@Z@Z ; 45 +?CanUnload@nsGenericModule@@UAGIPAVnsIComponentManager@@PAH@Z ; 45 +?Shutdown@nsGenericModule@@IAEXXZ ; 45 +?NS_NewGenericModule@@YAIPBDIPAUnsModuleComponentInfo@@P6AXPAVnsIModule@@@ZPAPAV2@@Z ; 45 +?GetLoaderForType@nsComponentManagerImpl@@IAEIPBDPAPAVnsIComponentLoader@@@Z ; 45 +?QueryInterface@nsGenericModule@@UAGIABUnsID@@PAPAX@Z ; 45 +??_EnsGenericModule@@UAEPAXI@Z ; 45 +??1nsGenericModule@@UAE@XZ ; 45 +?OnRegister@nsNativeComponentLoader@@UAGIABUnsID@@PBD111HH@Z ; 44 +?GetLeafName@nsFileSpecImpl@@UAGIPAPAD@Z ; 44 +?QueryInterface@AtomImpl@@UAGIABUnsID@@PAPAX@Z ; 44 +?find_category@nsCategoryManager@@AAEPAVCategoryNode@@PBD@Z ; 44 +?RegistryNameForLib@nsComponentManagerImpl@@IAEIPBDPAPAD@Z ; 44 +?RegisterComponentLib@nsComponentManager@@SAIABUnsID@@PBD11HH@Z ; 44 +?RegisterComponentLib@nsComponentManagerImpl@@UAGIABUnsID@@PBD11HH@Z ; 44 +?RegisterFactory@nsComponentManagerImpl@@UAGIABUnsID@@PBD1PAVnsIFactory@@H@Z ; 42 +??0nsFactoryEntry@@QAE@ABUnsID@@PAVnsIFactory@@@Z ; 42 +?copy_string@@YAAAV?$ConvertToUpperCase@G@@AAV?$nsWritingIterator@G@@ABV2@AAV1@@Z ; 40 +?ResolveSymlink@nsFileSpec@@QAEIAAH@Z ; 40 +?ToUpperCase@@YAXAAVnsAString@@@Z ; 40 +?advance@nsRegValueEnumerator@@UAGIXZ ; 39 +?Release@nsPersistentProperties@@UAGKXZ ; 39 +?ToNewString@nsString@@QBEPAV1@XZ ; 38 +?IsValid@xptiWorkingSet@@QBEHXZ ; 38 +?GetComponentsDir@xptiInterfaceInfoManager@@QAEHPAPAVnsILocalFile@@@Z ; 37 +??1xptiTypelibGuts@@QAE@XZ ; 36 +??0xptiTypelibGuts@@QAE@PAUXPTHeader@@@Z ; 36 +?LoadFile@xptiInterfaceInfoManager@@QAEHABVxptiTypelib@@PAVxptiWorkingSet@@@Z ; 36 +?SetHeader@xptiFile@@QAEHPAUXPTHeader@@@Z ; 36 +?ReadXPTFile@xptiInterfaceInfoManager@@AAEPAUXPTHeader@@PAVnsILocalFile@@PAVxptiWorkingSet@@@Z ; 36 +?ConvertBreaks@@YAPAGPBGAAHPBD2@Z ; 35 +?ConvertUnicharLineBreaksInSitu@nsLinebreakConverter@@SAIPAPAGW4ELinebreakType@1@1HPAH@Z ; 35 +?CountLinebreaks@@YAHPBGHPBD@Z ; 35 +?FindFactory@nsComponentManager@@SAIABUnsID@@PAPAVnsIFactory@@@Z ; 34 +??1nsRegistryValue@@UAE@XZ ; 32 +??_GnsRegistryValue@@UAEPAXI@Z ; 32 +?getInfo@nsRegistryValue@@IAEIXZ ; 32 +?find_leaf@CategoryNode@@QAEPAVnsCString@@PBD@Z ; 32 +??0nsRegistryValue@@QAE@PAXJK@Z ; 32 +?QueryInterface@nsRegistryValue@@UAGIABUnsID@@PAPAX@Z ; 32 +?GetNameUTF8@nsRegistryValue@@UAGIPAPAD@Z ; 32 +?AddCategoryEntry@nsCategoryManager@@UAGIPBD00HHPAPAD@Z ; 32 +?CurrentItem@nsRegValueEnumerator@@UAGIPAPAVnsISupports@@@Z ; 32 +??1nsInputFileStream@@UAE@XZ ; 29 +??YnsFileSpec@@QAEXABVnsString@@@Z ; 29 +?Release@nsAppFileLocationProvider@@UAGKXZ ; 29 +??0nsInputStream@@QAE@PAVnsIInputStream@@@Z ; 29 +??1nsRandomAccessInputStream@@UAE@XZ ; 29 +??1nsInputStream@@UAE@XZ ; 29 +?IsLowMemory@nsMemoryImpl@@UAGIPAH@Z ; 29 +??8nsFileSpec@@QBEHABV0@@Z ; 28 +?QueryInterface@nsAppFileLocationProvider@@UAGIABUnsID@@PAPAX@Z ; 27 +?copy_string@@YAAAV?$CalculateLength@D@@AAV?$nsReadingIterator@D@@ABV2@AAV1@@Z ; 26 +?Distance@@YAIABV?$nsReadingIterator@D@@0@Z ; 26 +?GetFile@nsAppFileLocationProvider@@UAGIPBDPAHPAPAVnsIFile@@@Z ; 26 +?nsLocalFileConstructor@nsLocalFile@@SGIPAVnsISupports@@ABUnsID@@PAPAX@Z ; 26 +?GetFactoryFromNSGetFactory@nsNativeComponentLoader@@AAEIPAVnsDll@@ABUnsID@@PAVnsIServiceManager@@PAPAVnsIFactory@@@Z ; 25 +?Release@nsRegistry@@UAGKXZ ; 25 +?First@nsRegSubtreeEnumerator@@UAGIXZ ; 24 +??1nsRegSubtreeEnumerator@@UAE@XZ ; 24 +??0nsRegSubtreeEnumerator@@QAE@PAXJH@Z ; 24 +?Set@nsDirectoryService@@UAGIPBDPAVnsISupports@@@Z ; 24 +??_GnsRegSubtreeEnumerator@@UAEPAXI@Z ; 24 +??0nsPersistentProperties@@QAE@XZ ; 23 +?Load@nsPersistentProperties@@UAGIPAVnsIInputStream@@@Z ; 23 +?Create@nsPersistentProperties@@SGIPAVnsISupports@@ABUnsID@@PAPAX@Z ; 23 +?QueryInterface@nsPersistentProperties@@UAGIABUnsID@@PAPAX@Z ; 23 +??1nsFileURL@@UAE@XZ ; 20 +?SetPersistentDescriptor@nsLocalFile@@UAGIPBD@Z ; 20 +?Close@BasicStringImpl@@UAGIXZ ; 20 +??4nsFileURL@@QAEXABVnsFilePath@@@Z ; 20 +?ReplaceElementAt@nsSupportsArray@@UAGHPAVnsISupports@@I@Z ; 20 +?NS_AllocateContiguousHandleWithData@@YAPAVBuffer@nsSharedBufferList@@PBV12@ABVnsLocalString@@I@Z ; 20 +?QueryInterface@nsRegistry@@UAGIABUnsID@@PAPAX@Z ; 19 +?SetCharAt@nsCString@@QAEHGI@Z ; 19 +??0nsSpecialSystemDirectory@@QAE@W4SystemDirectories@0@@Z ; 18 +?GetFileSize@nsFileSpec@@QBEIXZ ; 18 +?Exists@nsFileSpecImpl@@UAGIPAH@Z ; 18 +?GetSubtree@nsRegistry@@UAGIIPBDPAI@Z ; 18 +??4nsSpecialSystemDirectory@@QAEXW4SystemDirectories@0@@Z ; 18 +??1nsSpecialSystemDirectory@@UAE@XZ ; 18 +??0nsRandomAccessInputStream@@IAE@XZ ; 17 +??0nsObserverList@@QAE@XZ ; 17 +??1nsObserverList@@UAE@XZ ; 17 +?EnumerateSubtrees@nsRegistry@@UAGIIPAPAVnsIEnumerator@@@Z ; 17 +?NS_NewObserverList@@YAIPAPAVnsIObserverList@@@Z ; 17 +?AssignFrom@nsInputFileStream@@IAEXPAVnsISupports@@@Z ; 17 +??0nsInputFileStream@@QAE@ABVnsFileSpec@@HH@Z ; 17 +?QueryInterface@nsObserverList@@UAGIABUnsID@@PAPAX@Z ; 17 +??_GnsObserverList@@UAEPAXI@Z ; 17 +?Unescape@nsSimpleCharString@@QAEXXZ ; 16 +?SetCharAt@nsString@@QAEHGI@Z ; 16 +??1nsOpaqueKey@@UAE@XZ ; 16 +??1nsPersistentProperties@@UAE@XZ ; 16 +??_EnsPersistentProperties@@UAEPAXI@Z ; 16 +??0nsFilePath@@QAE@PBDH@Z ; 16 +??0nsOpaqueKey@@QAE@PBDIW4Ownership@0@@Z ; 16 +?AppendRelativeUnixPath@nsFileSpecImpl@@UAGIPBD@Z ; 15 +??0nsCString@@QAE@PBDH@Z ; 15 +?GetString@nsRegistry@@UAGIIPBGPAPAG@Z ; 15 +?SetStringUTF8@nsRegistry@@UAGIIPBD0@Z ; 15 +?SetString@nsRegistry@@UAGIIPBG0@Z ; 15 +?ReleaseElements@nsHashtableEnumerator@@EAGIXZ ; 14 +PL_GetEventQueueMonitor ; 14 +?ReadStringZ@nsBinaryInputStream@@UAGIPAPAD@Z ; 14 +?EscapeKey@nsRegistry@@UAGIPAEIPAIPAPAE@Z ; 14 +?AppendFromPromise@nsACString@@IAEXABV1@@Z ; 13 +?FindCharInReadable@@YAHDAAV?$nsReadingIterator@D@@ABV1@@Z ; 13 +??0nsPromiseCSubstring@@QAE@ABV?$nsReadingIterator@D@@0@Z ; 13 +?GetName@xptiInterfaceInfo@@UAGIPAPAD@Z ; 12 +?StartAssignmentByReference@nsXPIDLCString@@AAEPAPBDXZ ; 12 +??0nsFileURL@@QAE@ABVnsFileSpec@@@Z ; 12 +?ConvertFromFileSystemCharset@nsFileSpec@@IAEPAGPBD@Z ; 12 +?Read8@nsBinaryInputStream@@UAGIPAE@Z ; 12 +?IsHidden@nsLocalFile@@UAGIPAH@Z ; 12 +?BufferHashCode@nsCRT@@SAIPBDI@Z ; 12 +?GetFileSystemCharset@nsFileSpec@@KAXAAVnsString@@@Z ; 12 +??0nsRandomAccessStoreClient@@QAE@ABV?$nsCOMPtr@VnsIRandomAccessStore@@@@@Z ; 12 +??0nsFileClient@@QAE@ABV?$nsCOMPtr@VnsIOpenFile@@@@@Z ; 12 +?SetLongLong@nsRegistry@@UAGIIPBDPA_J@Z ; 12 +??0nsInputFileStream@@QAE@PAVnsIInputStream@@@Z ; 12 +?HashCode@nsOpaqueKey@@UBEIXZ ; 12 +??0nsRandomAccessInputStream@@QAE@PAVnsIInputStream@@@Z ; 12 +??4nsFileURL@@QAEXABVnsFileSpec@@@Z ; 12 +?AddRef@nsCategoryManager@@UAGKXZ ; 11 +?Release@nsCategoryManager@@UAGKXZ ; 11 +?GetFile@nsDirectoryService@@UAGIPBDPAHPAPAVnsIFile@@@Z ; 11 +??0nsProxyEventClass@@IAE@ABUnsID@@PAVnsIInterfaceInfo@@@Z ; 11 +?Read@nsFileSpecImpl@@UAGIPAPADHPAH@Z ; 11 +?InsertReadable@nsSlidingString@@IAEXABVnsAString@@ABV?$nsReadingIterator@G@@@Z ; 10 +NS_NewTypicalInputFileStream ; 10 +??1nsCommonCString@@UAE@XZ ; 10 +?SplitBuffer@nsSharedBufferList@@QAEXABUPosition@1@W4SplitDisposition@1@@Z ; 10 +?OpenStreamForReading@nsFileSpecImpl@@UAGIXZ ; 10 +PL_IsQueueNative ; 10 +?Release@nsRegistryFactory@@UAGKXZ ; 10 +??0ConstStringImpl@@QAE@ABVnsCString@@@Z ; 10 +?ResolveSymlink@nsFileSpecImpl@@UAGIXZ ; 10 +?IsQueueNative@nsEventQueueImpl@@UAGIPAH@Z ; 10 +??1nsACString@@UAE@XZ ; 10 +?Clone@nsVoidKey@@UBEPAVnsHashKey@@XZ ; 10 +NS_NewCStringInputStream ; 10 +?QueryInterface@nsRegSubtreeEnumerator@@UAGIABUnsID@@PAPAX@Z ; 9 +?GetFileSize@nsFileSpecImpl@@UAGIPAI@Z ; 9 +?GetTypeForParam@xptiInterfaceInfo@@UAGIGPBVnsXPTParamInfo@@GPAVnsXPTType@@@Z ; 9 +?Exists@nsDirectoryIteratorImpl@@UAGIPAH@Z ; 9 +?do_InsertFromElement@nsAString@@MAEXGI@Z ; 9 +?Create@nsDirectoryService@@SGIPAVnsISupports@@ABUnsID@@PAPAX@Z ; 9 +?QueryInterface@nsCategoryManager@@UAGIABUnsID@@PAPAX@Z ; 9 +?GetFileContents@nsFileSpecImpl@@UAGIPAPAD@Z ; 9 +?GetTypeInArray@xptiInterfaceInfo@@EAGIPBVnsXPTParamInfo@@GPAPBUXPTTypeDescriptor@@@Z ; 9 +?IsOpen@nsRegistry@@UAGIPAH@Z ; 9 +?set_at_eof@nsRandomAccessStoreClient@@MAEXH@Z ; 8 +??0nsFilePath@@QAE@ABVnsFileURL@@@Z ; 8 +?GetLengthIsArgNumberForParam@xptiInterfaceInfo@@UAGIGPBVnsXPTParamInfo@@GPAE@Z ; 8 +?SetAtEOF@FileImpl@@UAGIH@Z ; 8 +?GetSubtreeRaw@nsRegistry@@UAGIIPBDPAI@Z ; 8 +?Delete@nsFileSpec@@QBEXH@Z ; 8 +??_EnsDirEnumerator@@UAEPAXI@Z ; 8 +??_EnsHashtable@@UAEPAXI@Z ; 8 +?ReadBytes@nsBinaryInputStream@@UAGIPAPADI@Z ; 8 +?Next@nsDirectoryIteratorImpl@@UAGIXZ ; 8 +?GetDirectoryEntries@nsLocalFile@@UAGIPAPAVnsISimpleEnumerator@@@Z ; 8 +??0nsFileURL@@QAE@PBDH@Z ; 8 +?EnumerateCategory@nsCategoryManager@@UAGIPBDPAPAVnsISimpleEnumerator@@@Z ; 8 +??0nsDirEnumerator@@QAE@XZ ; 8 +?Put@nsInt2StrHashtable@@QAEIIPBD@Z ; 8 +??0nsFileSpec@@QAE@ABVnsFileURL@@@Z ; 8 +?GetCurrentSpec@nsDirectoryIteratorImpl@@UAGIPAPAVnsIFileSpec@@@Z ; 8 +?Init@nsDirEnumerator@@QAEIPAVnsILocalFile@@@Z ; 8 +??1nsDirEnumerator@@UAE@XZ ; 8 +?MakeAllDirectories@nsFileSpecHelpers@@YAXPBDH@Z ; 8 +?NotifyObservers@nsEventQueueImpl@@AAEXPBD@Z ; 8 +?Reset@nsHashtableEnumerator@@EAGIPAVnsHashtable@@P6GIPAVnsHashKey@@PAX2PAPAVnsISupports@@@Z2@Z ; 7 +NS_NewHashtableEnumerator ; 7 +?GetLeafName@nsFileSpec@@QAEXAAVnsString@@@Z ; 7 +??1nsHashtableEnumerator@@UAE@XZ ; 7 +??0CategoryNode@@QAE@XZ ; 7 +?IsASCII@nsString@@QAEHPBG@Z ; 7 +NS_NewAdapterEnumerator ; 7 +??0nsRegValueEnumerator@@QAE@PAXJ@Z ; 7 +??1nsProxyEventClass@@MAE@XZ ; 7 +?Realloc@nsMemoryImpl@@UAGPAXPAXI@Z ; 7 +?EnterMonitor@nsEventQueueImpl@@UAGIXZ ; 7 +??_EnsHashtableEnumerator@@UAEPAXI@Z ; 7 +?First@nsHashtableEnumerator@@UAGIXZ ; 7 +?RegisterErrorStringBundleKey@nsErrorService@@UAGIIPBD@Z ; 7 +?EnumerateValues@nsRegistry@@UAGIIPAPAVnsIEnumerator@@@Z ; 7 +?GetSizeIsArgNumberForParam@xptiInterfaceInfo@@UAGIGPBVnsXPTParamInfo@@GPAE@Z ; 7 +??0nsHashtableEnumerator@@QAE@PAVnsHashtable@@P6GIPAVnsHashKey@@PAX2PAPAVnsISupports@@@Z2@Z ; 7 +??_EnsAdapterEnumerator@@UAEPAXI@Z ; 7 +?Release@nsComponentManagerImpl@@UAGKXZ ; 7 +??_GCategoryNode@@UAEPAXI@Z ; 7 +?Delete@nsLocalFile@@UAGIH@Z ; 7 +??_GnsProxyEventClass@@MAEPAXI@Z ; 7 +?ExitMonitor@nsEventQueueImpl@@UAGIXZ ; 7 +??0nsBinaryInputStream@@QAE@PAVnsIInputStream@@@Z ; 6 +?OpenWellKnownRegistry@nsRegistry@@UAGIH@Z ; 6 +??0nsStaticCaseInsensitiveNameTable@@QAE@XZ ; 6 +??0nsXPIDLString@@QAE@XZ ; 6 +?NS_NewBinaryInputStream@@YAIPAPAVnsIBinaryInputStream@@PAVnsIInputStream@@@Z ; 6 +?SetYounger@nsEventQueueImpl@@UAGIPAVnsPIEventQueueChain@@@Z ; 6 +?MakeUnique@nsFileSpec@@QAEXXZ ; 6 +?Release@nsBinaryInputStream@@UAGKXZ ; 6 +??_GnsBinaryInputStream@@UAEPAXI@Z ; 6 +?ConvertUnknownBreaks@@YAPADPBDAAH0@Z ; 6 +?Read16@nsBinaryInputStream@@UAGIPAG@Z ; 6 +?AddSubtreeRaw@nsRegistry@@UAGIIPBDPAI@Z ; 6 +?Init@nsStaticCaseInsensitiveNameTable@@QAEHQAPBDH@Z ; 6 +?IsFile@nsFileSpec@@QBEHXZ ; 6 +??0nsFileSpec@@QAE@ABVnsString@@H@Z ; 6 +?ConvertLineBreaks@nsLinebreakConverter@@SAPADPBDW4ELinebreakType@1@1HPAH@Z ; 6 +NS_NewByteInputStream ; 6 +?ReadFloat@nsBinaryInputStream@@UAGIPAM@Z ; 6 +?Realloc@nsMemory@@SAPAXPAXI@Z ; 6 +??1nsStaticCaseInsensitiveNameTable@@QAE@XZ ; 6 +?GetLength@nsStorageStream@@UAGIPAI@Z ; 6 +??_GnsRegistry@@UAEPAXI@Z ; 5 +??_EnsObjectHashtable@@UAEPAXI@Z ; 5 +?CloneMozBinDirectory@nsAppFileLocationProvider@@IAGIPAPAVnsILocalFile@@@Z ; 5 +?StripWhitespace@nsCString@@QAEXXZ ; 5 +??0nsRegistry@@QAE@XZ ; 5 +?MakeNewQueue@nsEventQueueServiceImpl@@EAGIPAUPRThread@@HPAPAVnsIEventQueue@@@Z ; 5 +?StopAcceptingEvents@nsEventQueueImpl@@UAGIXZ ; 5 +??1nsRegistry@@UAE@XZ ; 5 +?Create@nsEventQueueImpl@@SGIPAVnsISupports@@ABUnsID@@PAPAX@Z ; 5 +?Close@nsRegistry@@MAGIXZ ; 5 +?CreateInstance@nsRegistryFactory@@UAGIPAVnsISupports@@ABUnsID@@PAPAX@Z ; 5 +?InitFromPRThread@nsEventQueueImpl@@UAGIPAUPRThread@@H@Z ; 5 +??4nsFileSpec@@QAEXABVnsString@@@Z ; 5 +?NS_FileSpecToIFile@@YAIPAVnsFileSpec@@PAPAVnsILocalFile@@@Z ; 5 +?QueryInterface@nsComponentManagerImpl@@UAGIABUnsID@@PAPAX@Z ; 5 +?GetNativePathString@nsFileSpec@@QAEXAAVnsString@@@Z ; 5 +??0nsEventQueueImpl@@QAE@XZ ; 5 +?do_GetService@@YA?BVnsGetServiceByContractID@@PBDPAI@Z ; 5 +PL_EventAvailable ; 4 +?RFind@nsString@@QBEHABV1@HHH@Z ; 4 +?RegisterComponentSpec@nsComponentManagerImpl@@UAGIABUnsID@@PBD1PAVnsIFile@@HH@Z ; 4 +?FSToNewUCS@nsFSStringConversion@@SAIPBDPAPAG@Z ; 4 +?GetCategoryEntry@nsCategoryManager@@UAGIPBD0PAPAD@Z ; 4 +?RegisterComponentWithType@nsComponentManagerImpl@@UAGIABUnsID@@PBD1PAVnsIFile@@1HH1@Z ; 4 +PL_CreateNativeEventQueue ; 4 +?RemoveStringAt@nsStringArray@@QAEHH@Z ; 4 +?PrepareDecoder@nsFSStringConversion@@CAIXZ ; 4 +?GetName@nsRegistryNode@@UAGIPAPAG@Z ; 4 +?Clone@nsOpaqueKey@@UBEPAVnsHashKey@@XZ ; 4 +?SetBufferSize@nsRegistry@@QAEHH@Z ; 4 +?GetCategoryEntryRaw@nsCategoryManager@@UAGIPBD0PAPAD@Z ; 4 +?AddSubtree@nsRegistry@@UAGIIPBDPAI@Z ; 4 +??_EnsOpaqueKey@@UAEPAXI@Z ; 4 +?GetOutputStream@nsFileSpecImpl@@UAGIPAPAVnsIOutputStream@@@Z ; 3 +NS_NewTypicalOutputFileStream ; 3 +?PushThreadEventQueue@nsEventQueueServiceImpl@@UAGIPAPAVnsIEventQueue@@@Z ; 3 +?QueryInterface@nsConsoleService@@UAGIABUnsID@@PAPAX@Z ; 3 +?PopThreadEventQueue@nsEventQueueServiceImpl@@UAGIPAVnsIEventQueue@@@Z ; 3 +PL_MapEvents ; 3 +?Unlink@nsEventQueueImpl@@UAGIXZ ; 3 +?SetElder@nsEventQueueImpl@@UAGIPAVnsPIEventQueueChain@@@Z ; 3 +?AppendQueue@nsEventQueueImpl@@UAGIPAVnsIEventQueue@@@Z ; 3 +??1nsEventQueueImpl@@UAE@XZ ; 3 +?OpenStreamForWriting@nsFileSpecImpl@@UAGIXZ ; 3 +??0nsOutputFileStream@@QAE@PAVnsIFileSpec@@@Z ; 3 +?LogMessage@nsConsoleService@@UAGIPAVnsIConsoleMessage@@@Z ; 3 +PL_DestroyEventQueue ; 3 +?IsRegistered@nsComponentManagerImpl@@UAGIABUnsID@@PAH@Z ; 3 +?GetCurrentProcessDirectory@nsDirectoryService@@AAEIPAPAVnsILocalFile@@@Z ; 3 +??_EnsEventQueueImpl@@UAEPAXI@Z ; 3 +?CreateDirectory@nsFileSpec@@QAEXH@Z ; 3 +??0nsDll@@QAE@PBDH@Z ; 3 +??1nsAVLTree@@QAE@XZ ; 2 +?NewFileArray@xptiWorkingSet@@QAEHI@Z ; 2 +?ToUpper@nsCRT@@SADD@Z ; 2 +??1nsInt2StrHashtable@@UAE@XZ ; 2 +?GetUnicodeLeafName@nsLocalFile@@UAGIPAPAG@Z ; 2 +?CompareWithConversion@nsString@@QBEHABV1@HH@Z ; 2 +?Read@xptiManifest@@SAHPAVxptiInterfaceInfoManager@@PAVxptiWorkingSet@@@Z ; 2 +??0nsMemoryImpl@@QAE@XZ ; 2 +??1xptiWorkingSet@@QAE@XZ ; 2 +?Create@nsMemoryImpl@@SGIPAVnsISupports@@ABUnsID@@PAPAX@Z ; 2 +??0nsRegistryFactory@@QAE@XZ ; 2 +?NS_ErrorAccordingToNSPR@@YAIXZ ; 2 +?ClearHashTables@xptiWorkingSet@@QAEXXZ ; 2 +??_ExptiFile@@QAEPAXI@Z ; 2 +?AppendUnicode@nsLocalFile@@UAGIPBG@Z ; 2 +?Release@MemoryFlusher@@UAGKXZ ; 2 +??_EnsSupportsHashtable@@UAEPAXI@Z ; 2 +?CreateEventQueue@nsEventQueueServiceImpl@@EAGIPAUPRThread@@H@Z ; 2 +??1xptiAutoLog@@QAE@XZ ; 2 +NS_RegistryGetFactory ; 2 +?ClearFiles@xptiWorkingSet@@QAEXXZ ; 2 +??0xptiWorkingSet@@QAE@XZ ; 2 +?Tell@FileImpl@@UAGIPAH@Z ; 2 +?RegisterProvider@nsDirectoryService@@UAGIPAVnsIDirectoryServiceProvider@@@Z ; 2 +?GetKey@nsRegistry@@UAGIIPBGPAI@Z ; 2 +?ClearZipItems@xptiWorkingSet@@QAEXXZ ; 2 +?readline@nsRandomAccessInputStream@@QAEHPADH@Z ; 2 +??0nsAVLTree@@QAE@AAVnsAVLNodeComparitor@@PAVnsAVLNodeFunctor@@@Z ; 2 +?GetManifestDir@xptiInterfaceInfoManager@@QAEHPAPAVnsILocalFile@@@Z ; 2 +??0xptiAutoLog@@QAE@PAVxptiInterfaceInfoManager@@PAVnsILocalFile@@H@Z ; 2 +?tell@nsRandomAccessStoreClient@@QAEHXZ ; 2 +NS_NewUnicodeLocalFile ; 2 +??0nsInt2StrHashtable@@QAE@XZ ; 2 +?seek@nsRandomAccessStoreClient@@QAEXW4PRSeekWhence@@H@Z ; 2 +?Open@nsRegistry@@UAGIPBD@Z ; 2 +?QueryInterface@nsErrorService@@UAGIABUnsID@@PAPAX@Z ; 2 +?RegisterService@nsServiceManagerImpl@@UAGIABUnsID@@PAVnsISupports@@@Z ; 2 +?Seek@FileImpl@@UAGIW4PRSeekWhence@@H@Z ; 2 +?GetUnicodePath@nsLocalFile@@UAGIPAPAG@Z ; 2 +?AddRef@MemoryFlusher@@UAGKXZ ; 2 +?PrepareFSCharset@nsFSStringConversion@@CAIXZ ; 2 +??_EnsDirectoryService@@UAEPAXI@Z ; 1 +?NS_ShutdownXPCOM@@YAIPAVnsIServiceManager@@@Z ; 1 +?AutoRegister@nsComponentManagerImpl@@UAGIHPAVnsIFile@@@Z ; 1 +?OnShutdown@HandleCaseConversionShutdown3@@UAGIABUnsID@@PAVnsISupports@@@Z ; 1 +?GetParent@nsFileSpec@@QBEXAAV1@@Z ; 1 +??1nsConsoleService@@UAE@XZ ; 1 +??0nsComponentManagerImpl@@QAE@XZ ; 1 +?PlatformVersionCheck@nsComponentManagerImpl@@IAEIPAI@Z ; 1 +?PlatformInit@nsComponentManagerImpl@@IAEIXZ ; 1 +??_EnsAppFileLocationProvider@@MAEPAXI@Z ; 1 +??_EnsVoidArray@@UAEPAXI@Z ; 1 +??RnsGetServiceFromCategory@@UBEIABUnsID@@PAPAX@Z ; 1 +??0nsIOFileStream@@QAE@ABVnsFileSpec@@HH@Z ; 1 +?NS_PurgeAtomTable@@YAXXZ ; 1 +??0nsProxyObjectManager@@QAE@XZ ; 1 +?NS_NewThreadPool@@YAIPAPAVnsIThreadPool@@IIIW4PRThreadPriority@@W4PRThreadScope@@@Z ; 1 +?GetNext@EmptyEnumeratorImpl@@UAGIPAPAVnsISupports@@@Z ; 1 +??_GxptiInterfaceInfoManager@@UAEPAXI@Z ; 1 +?ReallocLastSegment@nsSegmentedBuffer@@QAEHI@Z ; 1 +??0nsNativeComponentLoader@@QAE@XZ ; 1 +?Init@nsComponentManagerImpl@@QAEIXZ ; 1 +?CreateMonitoredThreadEventQueue@nsEventQueueServiceImpl@@UAGIXZ ; 1 +?UnloadLibraries@nsComponentManagerImpl@@IAEIPAVnsIServiceManager@@H@Z ; 1 +?Run@MemoryFlusher@@UAGIXZ ; 1 +??1nsDirectoryService@@UAE@XZ ; 1 +?SetRegistryDllInfo@nsNativeComponentLoader@@AAEIPBDPA_J1@Z ; 1 +??1nsDirectoryIteratorImpl@@UAE@XZ ; 1 +?DestroyThreadEventQueue@nsEventQueueServiceImpl@@UAGIXZ ; 1 +?GetInt@nsRegistry@@UAGIIPBDPAH@Z ; 1 +??0MemoryFlusher@@IAE@PAVnsMemoryImpl@@@Z ; 1 +?EnumerateBackwards@nsCStringArray@@QAEHP6AHAAVnsCString@@PAX@Z1@Z ; 1 +?GetParent@nsFileSpecImpl@@UAGIPAPAVnsIFileSpec@@@Z ; 1 +?BuildFileList@xptiInterfaceInfoManager@@AAEHPAPAVnsISupportsArray@@@Z ; 1 +??1nsServiceManagerImpl@@MAE@XZ ; 1 +??1nsObserverService@@UAE@XZ ; 1 +?GetRegistryDllInfo@nsNativeComponentLoader@@AAEIPBDPA_J1@Z ; 1 +?Shutdown@nsMemoryImpl@@SAIXZ ; 1 +NS_CategoryManagerGetFactory ; 1 +?Create@nsProxyObjectManager@@SGIPAVnsISupports@@ABUnsID@@PAPAX@Z ; 1 +??_EnsDirectoryIteratorImpl@@UAEPAXI@Z ; 1 +??1nsAppFileLocationProvider@@MAE@XZ ; 1 +?GetProductDirectory@nsAppFileLocationProvider@@IAGIPAPAVnsILocalFile@@@Z ; 1 +??0?$nsCOMPtr@VnsIServiceManager@@@@QAE@ABVnsCOMPtr_helper@@@Z ; 1 +??_EnsNativeComponentLoader@@UAEPAXI@Z ; 1 +?Create@nsObserverService@@SGIPAVnsISupports@@ABUnsID@@PAPAX@Z ; 1 +??0nsCategoryManager@@AAE@XZ ; 1 +??1nsIOFileStream@@UAE@XZ ; 1 +??1nsCategoryManager@@UAE@XZ ; 1 +?InvalidateInterfaceInfos@xptiWorkingSet@@QAEXXZ ; 1 +?PlatformPrePopulateRegistry@nsComponentManagerImpl@@QAEIXZ ; 1 +?NS_InitXPCOM2@@YAIPAPAVnsIServiceManager@@PAVnsIFile@@PAVnsIDirectoryServiceProvider@@@Z ; 1 +??_EnsDirectoryIterator@@UAEPAXI@Z ; 1 +?IsValid@xptiInterfaceInfoManager@@AAEHXZ ; 1 +?Shutdown@xptiZipLoader@@SAXXZ ; 1 +?Init@nsDirectoryService@@UAGIXZ ; 1 +?Create@nsErrorService@@SGIPAVnsISupports@@ABUnsID@@PAPAX@Z ; 1 +?RegisterDeferredComponents@nsNativeComponentLoader@@UAGIHPAH@Z ; 1 +?Shutdown@nsComponentManagerImpl@@QAEIXZ ; 1 +?Shutdown@nsThread@@SAXXZ ; 1 +?Sync@nsDll@@QAEIXZ ; 1 +?Startup@nsMemoryImpl@@SAIXZ ; 1 +?Define@nsDirectoryService@@UAGIPBDPAVnsISupports@@@Z ; 1 +?SetMainThread@nsIThread@@SAIXZ ; 1 +?ShutdownSpecialSystemDirectory@@YAXXZ ; 1 +?Init@nsNativeComponentLoader@@UAGIPAVnsIComponentManager@@PAVnsISupports@@@Z ; 1 +??0nsCategoryManagerFactory@@QAE@XZ ; 1 +?RegisterErrorStringBundle@nsErrorService@@UAGIFPBD@Z ; 1 +??0nsDirectoryService@@QAE@XZ ; 1 +?RegisterFactory@nsComponentManager@@SAIABUnsID@@PBD1PAVnsIFactory@@H@Z ; 1 +?AutoRegisterImpl@nsComponentManagerImpl@@AAEIHPAVnsIFile@@@Z ; 1 +?DetermineAutoRegStrategy@xptiInterfaceInfoManager@@AAE?AW4AutoRegMode@1@PAVnsISupportsArray@@PAVxptiWorkingSet@@@Z ; 1 +??0nsAppFileLocationProvider@@QAE@XZ ; 1 +??1MemoryFlusher@@MAE@XZ ; 1 +?Create@nsLocalFile@@UAGIII@Z ; 1 +?Join@nsThread@@UAGIXZ ; 1 +??_GnsProxyObjectManager@@UAEPAXI@Z ; 1 +?LogStats@xptiInterfaceInfoManager@@AAEXXZ ; 1 +?Valid@nsFileSpec@@QBEHXZ ; 1 +?NS_InitXPCOM@@YAIPAPAVnsIServiceManager@@PAVnsIFile@@@Z ; 1 +?ShutdownGlobalServiceManager@nsServiceManager@@SAIPAPAVnsIServiceManager@@@Z ; 1 +??1xptiInterfaceInfoManager@@UAE@XZ ; 1 +??_GnsComponentManagerImpl@@UAEPAXI@Z ; 1 +?FreeInterfaceInfoManager@xptiInterfaceInfoManager@@SAXXZ ; 1 +?Create@MemoryFlusher@@SAIPAPAV1@PAVnsMemoryImpl@@@Z ; 1 +??_EnsErrorService@@UAEPAXI@Z ; 1 +??1nsProxyObjectManager@@UAE@XZ ; 1 +??0nsConsoleService@@QAE@XZ ; 1 +?AutoRegisterComponents@nsNativeComponentLoader@@UAGIHPAVnsIFile@@@Z ; 1 +?AutoRegister@nsComponentManager@@SAIHPAVnsIFile@@@Z ; 1 +?QueryInterface@nsDirectoryIteratorImpl@@UAGIABUnsID@@PAPAX@Z ; 1 +??_EMemoryFlusher@@MAEPAXI@Z ; 1 +?initialize@nsCategoryManager@@AAEIXZ ; 1 +?AutoRegisterInterfaces@xptiInterfaceInfoManager@@UAGIXZ ; 1 +PL_CreateMonitoredEventQueue ; 1 +??_GnsCategoryManager@@UAEPAXI@Z ; 1 +?Close@nsStorageStream@@UAGIXZ ; 1 +?Init@nsThreadPool@@UAGIIIIW4PRThreadPriority@@W4PRThreadScope@@@Z ; 1 +??0nsObserverService@@QAE@XZ ; 1 +?Create@nsEventQueueServiceImpl@@SGIPAVnsISupports@@ABUnsID@@PAPAX@Z ; 1 +??0xptiInterfaceInfoManager@@AAE@XZ ; 1 +?GetDllSpec@nsDll@@QAEIPAPAVnsIFile@@@Z ; 1 +??_EnsServiceManagerImpl@@MAEPAXI@Z ; 1 +?SelfRegisterDll@nsNativeComponentLoader@@AAEIPAVnsDll@@PBDH@Z ; 1 +?UnloadAll@nsNativeComponentLoader@@UAGIH@Z ; 1 +??0?$nsCOMPtr@VnsIOutputStream@@@@QAE@ABVnsCOMPtr_helper@@@Z ; 1 +?Undefine@nsDirectoryService@@UAGIPBD@Z ; 1 +??0nsDirectoryIteratorImpl@@QAE@XZ ; 1 +??0CCaseConversionServiceInitializer@@QAE@XZ ; 1 +??1nsComponentManagerImpl@@UAE@XZ ; 1 +?RegisterComponentsInDir@nsNativeComponentLoader@@MAGIHPAVnsIFile@@@Z ; 1 +??0nsEventQueueServiceImpl@@QAE@XZ ; 1 +?CreateInstance@nsCategoryManagerFactory@@UAGIPAVnsISupports@@ABUnsID@@PAPAX@Z ; 1 +??_GnsObserverService@@UAEPAXI@Z ; 1 +XPTI_FreeInterfaceInfoManager ; 1 +?Stop@MemoryFlusher@@QAEIXZ ; 1 +?CreateThreadEventQueue@nsEventQueueServiceImpl@@UAGIXZ ; 1 +??0nsServiceManagerImpl@@QAE@XZ ; 1 +??1nsNativeComponentLoader@@UAE@XZ ; 1 +??0nsThreadPool@@QAE@XZ ; 1 +?NS_ShutdownLocalFile@@YAXXZ ; 1 +??_GHandleCaseConversionShutdown3@@UAEPAXI@Z ; 1 +?Init@nsDirectoryIteratorImpl@@UAGIPAVnsIFileSpec@@H@Z ; 1 +??0nsErrorService@@QAE@XZ ; 1 +??_EnsConsoleService@@UAEPAXI@Z ; 1 +??0nsSlidingSubstring@@QAE@ABVnsAString@@@Z ; 1 +?CleanUp@nsFSStringConversion@@SAXXZ ; 1 +?Create@nsDirectoryIteratorImpl@@SGIPAVnsISupports@@ABUnsID@@PAPAX@Z ; 1 diff --git a/src/libs/xpcom18a4/xpcom/build/xpcom-tests.pkg b/src/libs/xpcom18a4/xpcom/build/xpcom-tests.pkg new file mode 100644 index 00000000..8a32b21f --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/build/xpcom-tests.pkg @@ -0,0 +1,47 @@ +[xpcom-tests] +#if USE_SHORT_LIBNAME +dist/bin/components/@DLLP@tdynamic@DLLS@ +dist/bin/components/@DLLP@MyServce@DLLS@ +dist/bin/components/@DLLP@xpcomsmp@DLLS@ +#else +dist/bin/components/@DLLP@testdynamic@DLLS@ +dist/bin/components/@DLLP@MyService@DLLS@ +dist/bin/components/@DLLP@xpcomsample@DLLS@ +#endif +dist/bin/components/nsSample.js +!xpt dist/bin/components/xpcomsample.xpt +dist/bin/nsTestSample@BINS@ +dist/bin/res/test.properties +dist/bin/res/samples/xpconnect-sample.html +!xpt dist/bin/components/proxytest.xpt +dist/bin/proxytests@BINS@ + +dist/bin/PrimitiveTest@BINS@ +dist/bin/SimpleTypeLib@BINS@ +dist/bin/TestInterfaceInfo@BINS@ +dist/bin/TestXPTCInvoke@BINS@ + +dist/bin/nsIFileEnumerator@BINS@ +dist/bin/nsIFileTest@BINS@ +dist/bin/TestArray@BINS@ +dist/bin/TestAtoms@BINS@ +dist/bin/TestAutoLock@BINS@ +dist/bin/TestCallTemplates@BINS@ +dist/bin/TestCOMPtr@BINS@ +dist/bin/TestCOMPtrEq@BINS@ +dist/bin/TestCRT@BINS@ +dist/bin/TestFactory@BINS@ +dist/bin/TestHashtables@BINS@ +dist/bin/TestID@BINS@ +dist/bin/TestObserverService@BINS@ +dist/bin/TestPermanentAtoms@BINS@ +dist/bin/TestPipes@BINS@ +dist/bin/TestServMgr@BINS@ +dist/bin/TestThreads@BINS@ +dist/bin/TestXPIDLString@BINS@ +dist/bin/TestDeque@BINS@ +dist/bin/TestAutoPtr@BINS@ + +#if OS_ARCH==WINNT +dist/bin/TestCOM.exe +#endif diff --git a/src/libs/xpcom18a4/xpcom/build/xpcom.pkg b/src/libs/xpcom18a4/xpcom/build/xpcom.pkg new file mode 100644 index 00000000..eab0e19d --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/build/xpcom.pkg @@ -0,0 +1,106 @@ +[xpcom] +dist/bin/@DLLP@xpcom@DLLS@ +!xpt dist/bin/components/xpcom_base.xpt +!xpt dist/bin/components/xpcom_components.xpt +!xpt dist/bin/components/xpcom_ds.xpt +!xpt dist/bin/components/xpcom_io.xpt +!xpt dist/bin/components/xpcom_xpti.xpt + +#if OS_ARCH==WINNT +!xpt dist/bin/components/xpcom_thread.xpt +!xpt dist/bin/components/proxyObject.xpt +#else +!xpt dist/bin/components/xpcom_threads.xpt +!xpt dist/bin/components/proxyObjInst.xpt +#endif + +[gecko-support] +dist/bin/regxpcom@BINS@ +dist/bin/xpt_dump@BINS@ +dist/bin/xpt_link@BINS@ +#if MOZ_DEBUG +#if OS_ARCH==WINNT +dist/bin/windbgdlg.exe +#endif +#endif + +# xpidl.exe is not licensed MPL, so we don't include it with applications. +# It is only included in the developer (SDK) packages. +[gecko-devel] +dist/bin/xpidl@BINS@ + +# put NSPR here, because hacking the NSPR build system is too painful +# xxxbsmedberg: this doesn't obey --with-system-nspr +[nspr] +dist/bin/@DLLP@nspr4@DLLS@ +dist/bin/@DLLP@plc4@DLLS@ +dist/bin/@DLLP@plds4@DLLS@ + +[nspr-devel] +dist/lib/@LIBP@nspr4@LIBS@ +dist/lib/@LIBP@plc4@LIBS@ +dist/lib/@LIBP@plds4@LIBS@ +dist/include/nspr/private/pprio.h +dist/include/nspr/private/pprthred.h +dist/include/nspr/private/prpriv.h +dist/include/nspr/prcpucfg.h +dist/include/nspr/obsolete/pralarm.h +dist/include/nspr/obsolete/probslet.h +dist/include/nspr/obsolete/protypes.h +dist/include/nspr/obsolete/prsem.h +dist/include/nspr/nspr.h +dist/include/nspr/pratom.h +dist/include/nspr/prbit.h +dist/include/nspr/prclist.h +dist/include/nspr/prcmon.h +dist/include/nspr/prcountr.h +dist/include/nspr/prcvar.h +dist/include/nspr/prdtoa.h +dist/include/nspr/prenv.h +dist/include/nspr/prerr.h +dist/include/nspr/prerror.h +dist/include/nspr/prinet.h +dist/include/nspr/prinit.h +dist/include/nspr/prinrval.h +dist/include/nspr/prio.h +dist/include/nspr/pripcsem.h +dist/include/nspr/prlink.h +dist/include/nspr/prlock.h +dist/include/nspr/prlog.h +dist/include/nspr/prlong.h +dist/include/nspr/prmem.h +dist/include/nspr/prmon.h +dist/include/nspr/prmwait.h +dist/include/nspr/prnetdb.h +dist/include/nspr/prolock.h +dist/include/nspr/prpdce.h +dist/include/nspr/prprf.h +dist/include/nspr/prproces.h +dist/include/nspr/prrng.h +dist/include/nspr/prrwlock.h +dist/include/nspr/prshma.h +dist/include/nspr/prshm.h +dist/include/nspr/prsystem.h +dist/include/nspr/prthread.h +dist/include/nspr/prtime.h +dist/include/nspr/prtpool.h +dist/include/nspr/prtrace.h +dist/include/nspr/prtypes.h +dist/include/nspr/prvrsion.h +dist/include/nspr/prwin16.h +dist/include/nspr/plarenas.h +dist/include/nspr/plarena.h +dist/include/nspr/plhash.h +dist/include/nspr/plbase64.h +dist/include/nspr/plerror.h +dist/include/nspr/plgetopt.h +dist/include/nspr/plresolv.h +dist/include/nspr/plstr.h + +[unpackaged-files] +!optional dist/bin/.autoreg +!optional dist/bin/components/xpti.dat +!optional dist/bin/components/compreg.dat +#if OS_ARCH==WINNT +dist/bin/rebasedlls.exe +#endif diff --git a/src/libs/xpcom18a4/xpcom/build/xpcom_alpha.def b/src/libs/xpcom18a4/xpcom/build/xpcom_alpha.def new file mode 100644 index 00000000..966f2ea4 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/build/xpcom_alpha.def @@ -0,0 +1,252 @@ +LIBRARY xpcom +DESCRIPTION "xpcom library" + +EXPORTS + ?Stub3@nsXPTCStubBase@@UAAIXZ + ?Stub4@nsXPTCStubBase@@UAAIXZ + ?Stub5@nsXPTCStubBase@@UAAIXZ + ?Stub6@nsXPTCStubBase@@UAAIXZ + ?Stub7@nsXPTCStubBase@@UAAIXZ + ?Stub8@nsXPTCStubBase@@UAAIXZ + ?Stub9@nsXPTCStubBase@@UAAIXZ + ?Stub10@nsXPTCStubBase@@UAAIXZ + ?Stub11@nsXPTCStubBase@@UAAIXZ + ?Stub12@nsXPTCStubBase@@UAAIXZ + ?Stub13@nsXPTCStubBase@@UAAIXZ + ?Stub14@nsXPTCStubBase@@UAAIXZ + ?Stub15@nsXPTCStubBase@@UAAIXZ + ?Stub16@nsXPTCStubBase@@UAAIXZ + ?Stub17@nsXPTCStubBase@@UAAIXZ + ?Stub18@nsXPTCStubBase@@UAAIXZ + ?Stub19@nsXPTCStubBase@@UAAIXZ + ?Stub20@nsXPTCStubBase@@UAAIXZ + ?Stub21@nsXPTCStubBase@@UAAIXZ + ?Stub22@nsXPTCStubBase@@UAAIXZ + ?Stub23@nsXPTCStubBase@@UAAIXZ + ?Stub24@nsXPTCStubBase@@UAAIXZ + ?Stub25@nsXPTCStubBase@@UAAIXZ + ?Stub26@nsXPTCStubBase@@UAAIXZ + ?Stub27@nsXPTCStubBase@@UAAIXZ + ?Stub28@nsXPTCStubBase@@UAAIXZ + ?Stub29@nsXPTCStubBase@@UAAIXZ + ?Stub30@nsXPTCStubBase@@UAAIXZ + ?Stub31@nsXPTCStubBase@@UAAIXZ + ?Stub32@nsXPTCStubBase@@UAAIXZ + ?Stub33@nsXPTCStubBase@@UAAIXZ + ?Stub34@nsXPTCStubBase@@UAAIXZ + ?Stub35@nsXPTCStubBase@@UAAIXZ + ?Stub36@nsXPTCStubBase@@UAAIXZ + ?Stub37@nsXPTCStubBase@@UAAIXZ + ?Stub38@nsXPTCStubBase@@UAAIXZ + ?Stub39@nsXPTCStubBase@@UAAIXZ + ?Stub40@nsXPTCStubBase@@UAAIXZ + ?Stub41@nsXPTCStubBase@@UAAIXZ + ?Stub42@nsXPTCStubBase@@UAAIXZ + ?Stub43@nsXPTCStubBase@@UAAIXZ + ?Stub44@nsXPTCStubBase@@UAAIXZ + ?Stub45@nsXPTCStubBase@@UAAIXZ + ?Stub46@nsXPTCStubBase@@UAAIXZ + ?Stub47@nsXPTCStubBase@@UAAIXZ + ?Stub48@nsXPTCStubBase@@UAAIXZ + ?Stub49@nsXPTCStubBase@@UAAIXZ + ?Stub50@nsXPTCStubBase@@UAAIXZ + ?Stub51@nsXPTCStubBase@@UAAIXZ + ?Stub52@nsXPTCStubBase@@UAAIXZ + ?Stub53@nsXPTCStubBase@@UAAIXZ + ?Stub54@nsXPTCStubBase@@UAAIXZ + ?Stub55@nsXPTCStubBase@@UAAIXZ + ?Stub56@nsXPTCStubBase@@UAAIXZ + ?Stub57@nsXPTCStubBase@@UAAIXZ + ?Stub58@nsXPTCStubBase@@UAAIXZ + ?Stub59@nsXPTCStubBase@@UAAIXZ + ?Stub60@nsXPTCStubBase@@UAAIXZ + ?Stub61@nsXPTCStubBase@@UAAIXZ + ?Stub62@nsXPTCStubBase@@UAAIXZ + ?Stub63@nsXPTCStubBase@@UAAIXZ + ?Stub64@nsXPTCStubBase@@UAAIXZ + ?Stub65@nsXPTCStubBase@@UAAIXZ + ?Stub66@nsXPTCStubBase@@UAAIXZ + ?Stub67@nsXPTCStubBase@@UAAIXZ + ?Stub68@nsXPTCStubBase@@UAAIXZ + ?Stub69@nsXPTCStubBase@@UAAIXZ + ?Stub70@nsXPTCStubBase@@UAAIXZ + ?Stub71@nsXPTCStubBase@@UAAIXZ + ?Stub72@nsXPTCStubBase@@UAAIXZ + ?Stub73@nsXPTCStubBase@@UAAIXZ + ?Stub74@nsXPTCStubBase@@UAAIXZ + ?Stub75@nsXPTCStubBase@@UAAIXZ + ?Stub76@nsXPTCStubBase@@UAAIXZ + ?Stub77@nsXPTCStubBase@@UAAIXZ + ?Stub78@nsXPTCStubBase@@UAAIXZ + ?Stub79@nsXPTCStubBase@@UAAIXZ + ?Stub80@nsXPTCStubBase@@UAAIXZ + ?Stub81@nsXPTCStubBase@@UAAIXZ + ?Stub82@nsXPTCStubBase@@UAAIXZ + ?Stub83@nsXPTCStubBase@@UAAIXZ + ?Stub84@nsXPTCStubBase@@UAAIXZ + ?Stub85@nsXPTCStubBase@@UAAIXZ + ?Stub86@nsXPTCStubBase@@UAAIXZ + ?Stub87@nsXPTCStubBase@@UAAIXZ + ?Stub88@nsXPTCStubBase@@UAAIXZ + ?Stub89@nsXPTCStubBase@@UAAIXZ + ?Stub90@nsXPTCStubBase@@UAAIXZ + ?Stub91@nsXPTCStubBase@@UAAIXZ + ?Stub92@nsXPTCStubBase@@UAAIXZ + ?Stub93@nsXPTCStubBase@@UAAIXZ + ?Stub94@nsXPTCStubBase@@UAAIXZ + ?Stub95@nsXPTCStubBase@@UAAIXZ + ?Stub96@nsXPTCStubBase@@UAAIXZ + ?Stub97@nsXPTCStubBase@@UAAIXZ + ?Stub98@nsXPTCStubBase@@UAAIXZ + ?Stub99@nsXPTCStubBase@@UAAIXZ + ?Stub100@nsXPTCStubBase@@UAAIXZ + ?Stub101@nsXPTCStubBase@@UAAIXZ + ?Stub102@nsXPTCStubBase@@UAAIXZ + ?Stub103@nsXPTCStubBase@@UAAIXZ + ?Stub104@nsXPTCStubBase@@UAAIXZ + ?Stub105@nsXPTCStubBase@@UAAIXZ + ?Stub106@nsXPTCStubBase@@UAAIXZ + ?Stub107@nsXPTCStubBase@@UAAIXZ + ?Stub108@nsXPTCStubBase@@UAAIXZ + ?Stub109@nsXPTCStubBase@@UAAIXZ + ?Stub110@nsXPTCStubBase@@UAAIXZ + ?Stub111@nsXPTCStubBase@@UAAIXZ + ?Stub112@nsXPTCStubBase@@UAAIXZ + ?Stub113@nsXPTCStubBase@@UAAIXZ + ?Stub114@nsXPTCStubBase@@UAAIXZ + ?Stub115@nsXPTCStubBase@@UAAIXZ + ?Stub116@nsXPTCStubBase@@UAAIXZ + ?Stub117@nsXPTCStubBase@@UAAIXZ + ?Stub118@nsXPTCStubBase@@UAAIXZ + ?Stub119@nsXPTCStubBase@@UAAIXZ + ?Stub120@nsXPTCStubBase@@UAAIXZ + ?Stub121@nsXPTCStubBase@@UAAIXZ + ?Stub122@nsXPTCStubBase@@UAAIXZ + ?Stub123@nsXPTCStubBase@@UAAIXZ + ?Stub124@nsXPTCStubBase@@UAAIXZ + ?Stub125@nsXPTCStubBase@@UAAIXZ + ?Stub126@nsXPTCStubBase@@UAAIXZ + ?Stub127@nsXPTCStubBase@@UAAIXZ + ?Stub128@nsXPTCStubBase@@UAAIXZ + ?Stub129@nsXPTCStubBase@@UAAIXZ + ?Stub130@nsXPTCStubBase@@UAAIXZ + ?Stub131@nsXPTCStubBase@@UAAIXZ + ?Stub132@nsXPTCStubBase@@UAAIXZ + ?Stub133@nsXPTCStubBase@@UAAIXZ + ?Stub134@nsXPTCStubBase@@UAAIXZ + ?Stub135@nsXPTCStubBase@@UAAIXZ + ?Stub136@nsXPTCStubBase@@UAAIXZ + ?Stub137@nsXPTCStubBase@@UAAIXZ + ?Stub138@nsXPTCStubBase@@UAAIXZ + ?Stub139@nsXPTCStubBase@@UAAIXZ + ?Stub140@nsXPTCStubBase@@UAAIXZ + ?Stub141@nsXPTCStubBase@@UAAIXZ + ?Stub142@nsXPTCStubBase@@UAAIXZ + ?Stub143@nsXPTCStubBase@@UAAIXZ + ?Stub144@nsXPTCStubBase@@UAAIXZ + ?Stub145@nsXPTCStubBase@@UAAIXZ + ?Stub146@nsXPTCStubBase@@UAAIXZ + ?Stub147@nsXPTCStubBase@@UAAIXZ + ?Stub148@nsXPTCStubBase@@UAAIXZ + ?Stub149@nsXPTCStubBase@@UAAIXZ + ?Stub150@nsXPTCStubBase@@UAAIXZ + ?Stub151@nsXPTCStubBase@@UAAIXZ + ?Stub152@nsXPTCStubBase@@UAAIXZ + ?Stub153@nsXPTCStubBase@@UAAIXZ + ?Stub154@nsXPTCStubBase@@UAAIXZ + ?Stub155@nsXPTCStubBase@@UAAIXZ + ?Stub156@nsXPTCStubBase@@UAAIXZ + ?Stub157@nsXPTCStubBase@@UAAIXZ + ?Stub158@nsXPTCStubBase@@UAAIXZ + ?Stub159@nsXPTCStubBase@@UAAIXZ + ?Stub160@nsXPTCStubBase@@UAAIXZ + ?Stub161@nsXPTCStubBase@@UAAIXZ + ?Stub162@nsXPTCStubBase@@UAAIXZ + ?Stub163@nsXPTCStubBase@@UAAIXZ + ?Stub164@nsXPTCStubBase@@UAAIXZ + ?Stub165@nsXPTCStubBase@@UAAIXZ + ?Stub166@nsXPTCStubBase@@UAAIXZ + ?Stub167@nsXPTCStubBase@@UAAIXZ + ?Stub168@nsXPTCStubBase@@UAAIXZ + ?Stub169@nsXPTCStubBase@@UAAIXZ + ?Stub170@nsXPTCStubBase@@UAAIXZ + ?Stub171@nsXPTCStubBase@@UAAIXZ + ?Stub172@nsXPTCStubBase@@UAAIXZ + ?Stub173@nsXPTCStubBase@@UAAIXZ + ?Stub174@nsXPTCStubBase@@UAAIXZ + ?Stub175@nsXPTCStubBase@@UAAIXZ + ?Stub176@nsXPTCStubBase@@UAAIXZ + ?Stub177@nsXPTCStubBase@@UAAIXZ + ?Stub178@nsXPTCStubBase@@UAAIXZ + ?Stub179@nsXPTCStubBase@@UAAIXZ + ?Stub180@nsXPTCStubBase@@UAAIXZ + ?Stub181@nsXPTCStubBase@@UAAIXZ + ?Stub182@nsXPTCStubBase@@UAAIXZ + ?Stub183@nsXPTCStubBase@@UAAIXZ + ?Stub184@nsXPTCStubBase@@UAAIXZ + ?Stub185@nsXPTCStubBase@@UAAIXZ + ?Stub186@nsXPTCStubBase@@UAAIXZ + ?Stub187@nsXPTCStubBase@@UAAIXZ + ?Stub188@nsXPTCStubBase@@UAAIXZ + ?Stub189@nsXPTCStubBase@@UAAIXZ + ?Stub190@nsXPTCStubBase@@UAAIXZ + ?Stub191@nsXPTCStubBase@@UAAIXZ + ?Stub192@nsXPTCStubBase@@UAAIXZ + ?Stub193@nsXPTCStubBase@@UAAIXZ + ?Stub194@nsXPTCStubBase@@UAAIXZ + ?Stub195@nsXPTCStubBase@@UAAIXZ + ?Stub196@nsXPTCStubBase@@UAAIXZ + ?Stub197@nsXPTCStubBase@@UAAIXZ + ?Stub198@nsXPTCStubBase@@UAAIXZ + ?Stub199@nsXPTCStubBase@@UAAIXZ + ?Stub200@nsXPTCStubBase@@UAAIXZ + ?Stub201@nsXPTCStubBase@@UAAIXZ + ?Stub202@nsXPTCStubBase@@UAAIXZ + ?Stub203@nsXPTCStubBase@@UAAIXZ + ?Stub204@nsXPTCStubBase@@UAAIXZ + ?Stub205@nsXPTCStubBase@@UAAIXZ + ?Stub206@nsXPTCStubBase@@UAAIXZ + ?Stub207@nsXPTCStubBase@@UAAIXZ + ?Stub208@nsXPTCStubBase@@UAAIXZ + ?Stub209@nsXPTCStubBase@@UAAIXZ + ?Stub210@nsXPTCStubBase@@UAAIXZ + ?Stub211@nsXPTCStubBase@@UAAIXZ + ?Stub212@nsXPTCStubBase@@UAAIXZ + ?Stub213@nsXPTCStubBase@@UAAIXZ + ?Stub214@nsXPTCStubBase@@UAAIXZ + ?Stub215@nsXPTCStubBase@@UAAIXZ + ?Stub216@nsXPTCStubBase@@UAAIXZ + ?Stub217@nsXPTCStubBase@@UAAIXZ + ?Stub218@nsXPTCStubBase@@UAAIXZ + ?Stub219@nsXPTCStubBase@@UAAIXZ + ?Stub220@nsXPTCStubBase@@UAAIXZ + ?Stub221@nsXPTCStubBase@@UAAIXZ + ?Stub222@nsXPTCStubBase@@UAAIXZ + ?Stub223@nsXPTCStubBase@@UAAIXZ + ?Stub224@nsXPTCStubBase@@UAAIXZ + ?Stub225@nsXPTCStubBase@@UAAIXZ + ?Stub226@nsXPTCStubBase@@UAAIXZ + ?Stub227@nsXPTCStubBase@@UAAIXZ + ?Stub228@nsXPTCStubBase@@UAAIXZ + ?Stub229@nsXPTCStubBase@@UAAIXZ + ?Stub230@nsXPTCStubBase@@UAAIXZ + ?Stub231@nsXPTCStubBase@@UAAIXZ + ?Stub232@nsXPTCStubBase@@UAAIXZ + ?Stub233@nsXPTCStubBase@@UAAIXZ + ?Stub234@nsXPTCStubBase@@UAAIXZ + ?Stub235@nsXPTCStubBase@@UAAIXZ + ?Stub236@nsXPTCStubBase@@UAAIXZ + ?Stub237@nsXPTCStubBase@@UAAIXZ + ?Stub238@nsXPTCStubBase@@UAAIXZ + ?Stub239@nsXPTCStubBase@@UAAIXZ + ?Stub240@nsXPTCStubBase@@UAAIXZ + ?Stub241@nsXPTCStubBase@@UAAIXZ + ?Stub242@nsXPTCStubBase@@UAAIXZ + ?Stub243@nsXPTCStubBase@@UAAIXZ + ?Stub244@nsXPTCStubBase@@UAAIXZ + ?Stub245@nsXPTCStubBase@@UAAIXZ + ?Stub246@nsXPTCStubBase@@UAAIXZ + ?Stub247@nsXPTCStubBase@@UAAIXZ + ?Stub248@nsXPTCStubBase@@UAAIXZ + ?Stub249@nsXPTCStubBase@@UAAIXZ + diff --git a/src/libs/xpcom18a4/xpcom/components/.cvsignore b/src/libs/xpcom18a4/xpcom/components/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/components/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/xpcom/components/Makefile.in b/src/libs/xpcom18a4/xpcom/components/Makefile.in new file mode 100644 index 00000000..68614854 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/components/Makefile.in @@ -0,0 +1,107 @@ +# +# ***** 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.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of 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 ***** + +DEPTH = ../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = xpcom +XPIDL_MODULE = xpcom_components +LIBRARY_NAME = xpcomcomponents_s +GRE_MODULE = 1 + +REQUIRES = string \ + $(NULL) + +CPPSRCS = \ + nsCategoryManager.cpp \ + nsComponentManager.cpp \ + nsComponentManagerObsolete.cpp \ + nsNativeComponentLoader.cpp \ + nsServiceManagerObsolete.cpp \ + xcDll.cpp \ + $(NULL) + +ifdef MOZ_STATIC_COMPONENT_LOADER +CPPSRCS += nsStaticComponentLoader.cpp +endif + +EXPORTS = \ + nsCategoryManagerUtils.h \ + nsComponentManagerUtils.h \ + nsComponentManagerObsolete.h \ + nsIServiceManagerUtils.h \ + nsIServiceManagerObsolete.h \ + nsModule.h \ + nsNativeComponentLoader.h \ + nsStaticComponent.h \ + nsObsoleteModuleLoading.h \ + xcDll.h \ + $(NULL) + +XPIDLSRCS = \ + nsIComponentLoader.idl \ + nsIComponentLoaderManager.idl \ + nsIComponentManagerObsolete.idl \ + nsINativeComponentLoader.idl \ + $(NULL) + +SDK_XPIDLSRCS = \ + nsIClassInfo.idl \ + nsIComponentRegistrar.idl \ + nsIFactory.idl \ + nsIModule.idl \ + nsIServiceManager.idl \ + nsIComponentManager.idl \ + nsICategoryManager.idl \ + $(NULL) + +EXPORTS := $(addprefix $(srcdir)/, $(EXPORTS)) + +LOCAL_INCLUDES = -I$(srcdir)/../base -I$(srcdir)/../thread -I$(srcdir)/../ds -I.. + +# we don't want the shared lib, but we want to force the creation of a static lib. +FORCE_STATIC_LIB = 1 + +# Force use of PIC +FORCE_USE_PIC = 1 +include $(topsrcdir)/config/rules.mk + +DEFINES += -D_IMPL_NS_COM -DEXPORT_XPTI_API diff --git a/src/libs/xpcom18a4/xpcom/components/nsCategoryManager.cpp b/src/libs/xpcom18a4/xpcom/components/nsCategoryManager.cpp new file mode 100644 index 00000000..d7202bdb --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/components/nsCategoryManager.cpp @@ -0,0 +1,799 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Scott Collins + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +#define PL_ARENA_CONST_ALIGN_MASK 7 + +#include "nsICategoryManager.h" +#include "nsCategoryManager.h" + +#include "plarena.h" +#include "prio.h" +#include "prprf.h" +#include "prlock.h" +#include "nsCOMPtr.h" +#include "nsTHashtable.h" +#include "nsClassHashtable.h" +#include "nsIFactory.h" +#include "nsIStringEnumerator.h" +#include "nsSupportsPrimitives.h" +#include "nsIServiceManagerUtils.h" +#include "nsIObserver.h" +#include "nsReadableUtils.h" +#include "nsCRT.h" +#include "nsEnumeratorUtils.h" + +class nsIComponentLoaderManager; + +/* + CategoryDatabase + contains 0 or more 1-1 mappings of string to Category + each Category contains 0 or more 1-1 mappings of string keys to string values + + In other words, the CategoryDatabase is a tree, whose root is a hashtable. + Internal nodes (or Categories) are hashtables. Leaf nodes are strings. + + The leaf strings are allocated in an arena, because we assume they're not + going to change much ;) +*/ + +#define NS_CATEGORYMANAGER_ARENA_SIZE (1024 * 8) + +// pulled in from nsComponentManager.cpp +char* ArenaStrdup(const char* s, PLArenaPool* aArena); + +// +// BaseStringEnumerator is subclassed by EntryEnumerator and +// CategoryEnumerator +// +class BaseStringEnumerator + : public nsISimpleEnumerator, + nsIUTF8StringEnumerator +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSISIMPLEENUMERATOR + NS_DECL_NSIUTF8STRINGENUMERATOR + +protected: + BaseStringEnumerator() + : mArray(nsnull), + mCount(0), + mSimpleCurItem(0), + mStringCurItem(0) { } + + // A virtual destructor is needed here because subclasses of + // BaseStringEnumerator do not implement their own Release() method. + + virtual ~BaseStringEnumerator() + { + if (mArray) + delete[] mArray; + } + + const char** mArray; + PRUint32 mCount; + PRUint32 mSimpleCurItem; + PRUint32 mStringCurItem; +}; + +NS_IMPL_ISUPPORTS2(BaseStringEnumerator, nsISimpleEnumerator, nsIUTF8StringEnumerator) + +NS_IMETHODIMP +BaseStringEnumerator::HasMoreElements(PRBool *_retval) +{ + *_retval = (mSimpleCurItem < mCount); + + return NS_OK; +} + +NS_IMETHODIMP +BaseStringEnumerator::GetNext(nsISupports **_retval) +{ + if (mSimpleCurItem >= mCount) + return NS_ERROR_FAILURE; + + nsSupportsDependentCString* str = + new nsSupportsDependentCString(mArray[mSimpleCurItem++]); + if (!str) + return NS_ERROR_OUT_OF_MEMORY; + + *_retval = str; + NS_ADDREF(*_retval); + return NS_OK; +} + +NS_IMETHODIMP +BaseStringEnumerator::HasMore(PRBool *_retval) +{ + *_retval = (mStringCurItem < mCount); + + return NS_OK; +} + +NS_IMETHODIMP +BaseStringEnumerator::GetNext(nsACString& _retval) +{ + if (mStringCurItem >= mCount) + return NS_ERROR_FAILURE; + + _retval = nsDependentCString(mArray[mStringCurItem++]); + return NS_OK; +} + + +// +// EntryEnumerator is the wrapper that allows nsICategoryManager::EnumerateCategory +// +class EntryEnumerator + : public BaseStringEnumerator +{ +public: + static EntryEnumerator* Create(nsTHashtable& aTable); + +private: + static PLDHashOperator PR_CALLBACK + enumfunc_createenumerator(CategoryLeaf* aLeaf, void* userArg); +}; + + +PLDHashOperator PR_CALLBACK +EntryEnumerator::enumfunc_createenumerator(CategoryLeaf* aLeaf, void* userArg) +{ + EntryEnumerator* mythis = NS_STATIC_CAST(EntryEnumerator*, userArg); + mythis->mArray[mythis->mCount++] = aLeaf->GetKey(); + + return PL_DHASH_NEXT; +} + +EntryEnumerator* +EntryEnumerator::Create(nsTHashtable& aTable) +{ + EntryEnumerator* enumObj = new EntryEnumerator(); + if (!enumObj) + return nsnull; + + enumObj->mArray = new char const* [aTable.Count()]; + if (!enumObj->mArray) { + delete enumObj; + return nsnull; + } + + aTable.EnumerateEntries(enumfunc_createenumerator, enumObj); + + return enumObj; +} + + +// +// CategoryNode implementations +// + +CategoryNode* +CategoryNode::Create(PLArenaPool* aArena) +{ + CategoryNode* node = new(aArena) CategoryNode(); + if (!node) + return nsnull; + + if (!node->mTable.Init()) { + delete node; + return nsnull; + } + + node->mLock = PR_NewLock(); + if (!node->mLock) { + delete node; + return nsnull; + } + + return node; +} + +CategoryNode::~CategoryNode() +{ + if (mLock) + PR_DestroyLock(mLock); +} + +void* +CategoryNode::operator new(size_t aSize, PLArenaPool* aArena) +{ + void* p; + PL_ARENA_ALLOCATE(p, aArena, aSize); + return p; +} + +NS_METHOD +CategoryNode::GetLeaf(const char* aEntryName, + char** _retval) +{ + PR_Lock(mLock); + nsresult rv = NS_ERROR_NOT_AVAILABLE; + CategoryLeaf* ent = + mTable.GetEntry(aEntryName); + + // we only want the non-persistent value + if (ent && ent->nonpValue) { + *_retval = nsCRT::strdup(ent->nonpValue); + if (*_retval) + rv = NS_OK; + } + PR_Unlock(mLock); + + return rv; +} + +NS_METHOD +CategoryNode::AddLeaf(const char* aEntryName, + const char* aValue, + PRBool aPersist, + PRBool aReplace, + char** _retval, + PLArenaPool* aArena) +{ + PR_Lock(mLock); + CategoryLeaf* leaf = + mTable.GetEntry(aEntryName); + + nsresult rv = NS_OK; + if (leaf) { + //if the entry was found, aReplace must be specified + if (!aReplace && (leaf->nonpValue || (aPersist && leaf->pValue ))) + rv = NS_ERROR_INVALID_ARG; + } else { + const char* arenaEntryName = ArenaStrdup(aEntryName, aArena); + if (!arenaEntryName) { + rv = NS_ERROR_OUT_OF_MEMORY; + } else { + leaf = mTable.PutEntry(arenaEntryName); + if (!leaf) + rv = NS_ERROR_OUT_OF_MEMORY; + } + } + + if (NS_SUCCEEDED(rv)) { + const char* arenaValue = ArenaStrdup(aValue, aArena); + if (!arenaValue) { + rv = NS_ERROR_OUT_OF_MEMORY; + } else { + leaf->nonpValue = arenaValue; + if (aPersist) + leaf->pValue = arenaValue; + } + } + + PR_Unlock(mLock); + return rv; +} + +NS_METHOD +CategoryNode::DeleteLeaf(const char* aEntryName, + PRBool aDontPersist) +{ + // we don't throw any errors, because it normally doesn't matter + // and it makes JS a lot cleaner + PR_Lock(mLock); + + if (aDontPersist) { + // we can just remove the entire hash entry without introspection + mTable.RemoveEntry(aEntryName); + } else { + // if we are keeping the persistent value, we need to look at + // the contents of the current entry + CategoryLeaf* leaf = mTable.GetEntry(aEntryName); + if (leaf) { + if (leaf->pValue) { + leaf->nonpValue = nsnull; + } else { + // if there is no persistent value, just remove the entry + mTable.RawRemoveEntry(leaf); + } + } + } + PR_Unlock(mLock); + + return NS_OK; +} + +NS_METHOD +CategoryNode::Enumerate(nsISimpleEnumerator **_retval) +{ + NS_ENSURE_ARG_POINTER(_retval); + + PR_Lock(mLock); + EntryEnumerator* enumObj = EntryEnumerator::Create(mTable); + PR_Unlock(mLock); + + if (!enumObj) + return NS_ERROR_OUT_OF_MEMORY; + + *_retval = enumObj; + NS_ADDREF(*_retval); + return NS_OK; +} + +struct persistent_userstruct { + PRFileDesc* fd; + const char* categoryName; + PRBool success; +}; + +PLDHashOperator PR_CALLBACK +enumfunc_pentries(CategoryLeaf* aLeaf, void* userArg) +{ + persistent_userstruct* args = + NS_STATIC_CAST(persistent_userstruct*, userArg); + + PLDHashOperator status = PL_DHASH_NEXT; + + if (aLeaf->pValue) { + if (PR_fprintf(args->fd, + "%s,%s,%s\n", + args->categoryName, + aLeaf->GetKey(), + aLeaf->pValue) == (PRUint32) -1) { + args->success = PR_FALSE; + status = PL_DHASH_STOP; + } + } + + return status; +} + +PRBool +CategoryNode::WritePersistentEntries(PRFileDesc* fd, const char* aCategoryName) +{ + persistent_userstruct args = { + fd, + aCategoryName, + PR_TRUE + }; + + PR_Lock(mLock); + mTable.EnumerateEntries(enumfunc_pentries, &args); + PR_Unlock(mLock); + + return args.success; +} + + +// +// CategoryEnumerator class +// + +class CategoryEnumerator + : public BaseStringEnumerator +{ +public: + static CategoryEnumerator* Create(nsClassHashtable& aTable); + +private: + static PLDHashOperator PR_CALLBACK + enumfunc_createenumerator(const char* aStr, + CategoryNode* aNode, + void* userArg); +}; + +CategoryEnumerator* +CategoryEnumerator::Create(nsClassHashtable& aTable) +{ + CategoryEnumerator* enumObj = new CategoryEnumerator(); + if (!enumObj) + return nsnull; + + enumObj->mArray = new const char* [aTable.Count()]; + if (!enumObj->mArray) { + delete enumObj; + return nsnull; + } + + aTable.EnumerateRead(enumfunc_createenumerator, enumObj); + + return enumObj; +} + +PLDHashOperator PR_CALLBACK +CategoryEnumerator::enumfunc_createenumerator(const char* aStr, CategoryNode* aNode, void* userArg) +{ + CategoryEnumerator* mythis = NS_STATIC_CAST(CategoryEnumerator*, userArg); + + // if a category has no entries, we pretend it doesn't exist + if (aNode->Count()) + mythis->mArray[mythis->mCount++] = aStr; + + return PL_DHASH_NEXT; +} + + +// +// nsCategoryManager implementations +// + +NS_IMPL_THREADSAFE_ISUPPORTS1(nsCategoryManager, nsICategoryManager) + +nsCategoryManager* +nsCategoryManager::Create() +{ + nsCategoryManager* manager = new nsCategoryManager(); + + if (!manager) + return nsnull; + + PL_INIT_ARENA_POOL(&(manager->mArena), "CategoryManagerArena", + NS_CATEGORYMANAGER_ARENA_SIZE); // this never fails + + if (!manager->mTable.Init()) { + delete manager; + return nsnull; + } + + manager->mLock = PR_NewLock(); + + if (!manager->mLock) { + delete manager; + return nsnull; + } + + return manager; +} + +nsCategoryManager::~nsCategoryManager() +{ + if (mLock) + PR_DestroyLock(mLock); + + // the hashtable contains entries that must be deleted before the arena is + // destroyed, or else you will have PRLocks undestroyed and other Really + // Bad Stuff (TM) + mTable.Clear(); + + PL_FinishArenaPool(&mArena); +} + +inline CategoryNode* +nsCategoryManager::get_category(const char* aName) { + CategoryNode* node; + if (!mTable.Get(aName, &node)) { + return nsnull; + } + return node; +} + +NS_IMETHODIMP +nsCategoryManager::GetCategoryEntry( const char *aCategoryName, + const char *aEntryName, + char **_retval ) +{ + NS_ENSURE_ARG_POINTER(aCategoryName); + NS_ENSURE_ARG_POINTER(aEntryName); + NS_ENSURE_ARG_POINTER(_retval); + + nsresult status = NS_ERROR_NOT_AVAILABLE; + + PR_Lock(mLock); + CategoryNode* category = get_category(aCategoryName); + PR_Unlock(mLock); + + if (category) { + status = category->GetLeaf(aEntryName, _retval); + } + + return status; +} + +NS_IMETHODIMP +nsCategoryManager::AddCategoryEntry( const char *aCategoryName, + const char *aEntryName, + const char *aValue, + PRBool aPersist, + PRBool aReplace, + char **_retval ) +{ + NS_ENSURE_ARG_POINTER(aCategoryName); + NS_ENSURE_ARG_POINTER(aEntryName); + NS_ENSURE_ARG_POINTER(aValue); + + // Before we can insert a new entry, we'll need to + // find the |CategoryNode| to put it in... + PR_Lock(mLock); + CategoryNode* category = get_category(aCategoryName); + + if (!category) { + // That category doesn't exist yet; let's make it. + category = CategoryNode::Create(&mArena); + + char* categoryName = ArenaStrdup(aCategoryName, &mArena); + mTable.Put(categoryName, category); + } + PR_Unlock(mLock); + + if (!category) + return NS_ERROR_OUT_OF_MEMORY; + + return category->AddLeaf(aEntryName, + aValue, + aPersist, + aReplace, + _retval, + &mArena); +} + +NS_IMETHODIMP +nsCategoryManager::DeleteCategoryEntry( const char *aCategoryName, + const char *aEntryName, + PRBool aDontPersist) +{ + NS_ENSURE_ARG_POINTER(aCategoryName); + NS_ENSURE_ARG_POINTER(aEntryName); + + /* + Note: no errors are reported since failure to delete + probably won't hurt you, and returning errors seriously + inconveniences JS clients + */ + + PR_Lock(mLock); + CategoryNode* category = get_category(aCategoryName); + PR_Unlock(mLock); + + if (!category) + return NS_OK; + + return category->DeleteLeaf(aEntryName, + aDontPersist); +} + +NS_IMETHODIMP +nsCategoryManager::DeleteCategory( const char *aCategoryName ) +{ + NS_ENSURE_ARG_POINTER(aCategoryName); + + // the categories are arena-allocated, so we don't + // actually delete them. We just remove all of the + // leaf nodes. + + PR_Lock(mLock); + CategoryNode* category = get_category(aCategoryName); + PR_Unlock(mLock); + + if (category) + category->Clear(); + + return NS_OK; +} + +NS_IMETHODIMP +nsCategoryManager::EnumerateCategory( const char *aCategoryName, + nsISimpleEnumerator **_retval ) +{ + NS_ENSURE_ARG_POINTER(aCategoryName); + NS_ENSURE_ARG_POINTER(_retval); + + PR_Lock(mLock); + CategoryNode* category = get_category(aCategoryName); + PR_Unlock(mLock); + + if (!category) { + return NS_NewEmptyEnumerator(_retval); + } + + return category->Enumerate(_retval); +} + +NS_IMETHODIMP +nsCategoryManager::EnumerateCategories(nsISimpleEnumerator **_retval) +{ + NS_ENSURE_ARG_POINTER(_retval); + + PR_Lock(mLock); + CategoryEnumerator* enumObj = CategoryEnumerator::Create(mTable); + PR_Unlock(mLock); + + if (!enumObj) + return NS_ERROR_OUT_OF_MEMORY; + + *_retval = enumObj; + NS_ADDREF(*_retval); + return NS_OK; +} + +struct writecat_struct { + PRFileDesc* fd; + PRBool success; +}; + +PLDHashOperator PR_CALLBACK +enumfunc_categories(const char* aKey, CategoryNode* aCategory, void* userArg) +{ + writecat_struct* args = NS_STATIC_CAST(writecat_struct*, userArg); + + PLDHashOperator result = PL_DHASH_NEXT; + + if (!aCategory->WritePersistentEntries(args->fd, aKey)) { + args->success = PR_FALSE; + result = PL_DHASH_STOP; + } + + return result; +} + +NS_METHOD +nsCategoryManager::WriteCategoryManagerToRegistry(PRFileDesc* fd) +{ + writecat_struct args = { + fd, + PR_TRUE + }; + + PR_Lock(mLock); + mTable.EnumerateRead(enumfunc_categories, &args); + PR_Unlock(mLock); + + if (!args.success) { + return NS_ERROR_UNEXPECTED; + } + + return NS_OK; +} + +class nsCategoryManagerFactory : public nsIFactory + { + public: + nsCategoryManagerFactory() { } + + NS_DECL_ISUPPORTS + NS_DECL_NSIFACTORY + }; + +NS_IMPL_ISUPPORTS1(nsCategoryManagerFactory, nsIFactory) + +NS_IMETHODIMP +nsCategoryManagerFactory::CreateInstance( nsISupports* aOuter, const nsIID& aIID, void** aResult ) + { + NS_ENSURE_ARG_POINTER(aResult); + + *aResult = 0; + + nsresult status = NS_OK; + if ( aOuter ) + status = NS_ERROR_NO_AGGREGATION; + else + { + nsCategoryManager* raw_category_manager = nsCategoryManager::Create(); + nsCOMPtr new_category_manager = raw_category_manager; + if ( new_category_manager ) + status = new_category_manager->QueryInterface(aIID, aResult); + else + status = NS_ERROR_OUT_OF_MEMORY; + } + + return status; + } + +NS_IMETHODIMP +nsCategoryManagerFactory::LockFactory( PRBool ) + { + // Not implemented... + return NS_OK; + } + +nsresult +NS_CategoryManagerGetFactory( nsIFactory** aFactory ) + { + // assert(aFactory); + + nsresult status; + + *aFactory = 0; + nsIFactory* new_factory = NS_STATIC_CAST(nsIFactory*, new nsCategoryManagerFactory); + if (new_factory) + { + *aFactory = new_factory; + NS_ADDREF(*aFactory); + status = NS_OK; + } + else + status = NS_ERROR_OUT_OF_MEMORY; + + return status; + } + + + +/* + * CreateServicesFromCategory() + * + * Given a category, this convenience functions enumerates the category and + * creates a service of every CID or ContractID registered under the category. + * If observerTopic is non null and the service implements nsIObserver, + * this will attempt to notify the observer with the origin, observerTopic string + * as parameter. + */ +NS_COM nsresult +NS_CreateServicesFromCategory(const char *category, + nsISupports *origin, + const char *observerTopic) +{ + nsresult rv = NS_OK; + + int nFailed = 0; + nsCOMPtr categoryManager = + do_GetService("@mozilla.org/categorymanager;1", &rv); + if (!categoryManager) return rv; + + nsCOMPtr enumerator; + rv = categoryManager->EnumerateCategory(category, + getter_AddRefs(enumerator)); + if (NS_FAILED(rv)) return rv; + + nsCOMPtr entry; + while (NS_SUCCEEDED(enumerator->GetNext(getter_AddRefs(entry)))) { + // From here on just skip any error we get. + nsCOMPtr catEntry = do_QueryInterface(entry, &rv); + if (NS_FAILED(rv)) { + nFailed++; + continue; + } + nsCAutoString entryString; + rv = catEntry->GetData(entryString); + if (NS_FAILED(rv)) { + nFailed++; + continue; + } + nsXPIDLCString contractID; + rv = categoryManager->GetCategoryEntry(category,entryString.get(), getter_Copies(contractID)); + if (NS_FAILED(rv)) { + nFailed++; + continue; + } + + nsCOMPtr instance = do_GetService(contractID, &rv); + if (NS_FAILED(rv)) { + nFailed++; + continue; + } + + if (observerTopic) { + // try an observer, if it implements it. + nsCOMPtr observer = do_QueryInterface(instance, &rv); + if (NS_SUCCEEDED(rv) && observer) + observer->Observe(origin, observerTopic, EmptyString().get()); + } + } + return (nFailed ? NS_ERROR_FAILURE : NS_OK); +} diff --git a/src/libs/xpcom18a4/xpcom/components/nsCategoryManager.h b/src/libs/xpcom18a4/xpcom/components/nsCategoryManager.h new file mode 100644 index 00000000..a5cdb59a --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/components/nsCategoryManager.h @@ -0,0 +1,159 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + + +#ifndef NSCATEGORYMANAGER_H +#define NSCATEGORYMANAGER_H + +#include "prio.h" +#include "prlock.h" +#include "plarena.h" +#include "nsClassHashtable.h" +#include "nsICategoryManager.h" + +#define NS_CATEGORYMANAGER_CLASSNAME "Category Manager" + +/* 16d222a6-1dd2-11b2-b693-f38b02c021b2 */ +#define NS_CATEGORYMANAGER_CID \ +{ 0x16d222a6, 0x1dd2, 0x11b2, \ + {0xb6, 0x93, 0xf3, 0x8b, 0x02, 0xc0, 0x21, 0xb2} } + +/** + * a "leaf-node", managed by the nsCategoryNode hashtable. + * + * we need to keep a "persistent value" (which will be written to the registry) + * and a non-persistent value (for the current runtime): these are usually + * the same, except when aPersist==PR_FALSE. The strings are permanently arena- + * allocated, and will never go away. + */ +class CategoryLeaf : public nsDepCharHashKey +{ +public: + CategoryLeaf(const char* aKey) + : nsDepCharHashKey(aKey), + pValue(nsnull), + nonpValue(nsnull) { } + const char* pValue; + const char* nonpValue; +}; + + +/** + * CategoryNode keeps a hashtable of it's entries. + * the CategoryNode itself is permanently allocated in + * the arena. + */ +class CategoryNode +{ +public: + NS_METHOD GetLeaf(const char* aEntryName, + char** _retval); + + NS_METHOD AddLeaf(const char* aEntryName, + const char* aValue, + PRBool aPersist, + PRBool aReplace, + char** _retval, + PLArenaPool* aArena); + + NS_METHOD DeleteLeaf(const char* aEntryName, + PRBool aDontPersist); + + void Clear() { + PR_Lock(mLock); + mTable.Clear(); + PR_Unlock(mLock); + } + + PRUint32 Count() { + PR_Lock(mLock); + PRUint32 tCount = mTable.Count(); + PR_Unlock(mLock); + return tCount; + } + + NS_METHOD Enumerate(nsISimpleEnumerator** _retval); + + PRBool WritePersistentEntries(PRFileDesc* fd, const char* aCategoryName); + + // CategoryNode is arena-allocated, with the strings + static CategoryNode* Create(PLArenaPool* aArena); + ~CategoryNode(); + void operator delete(void*) { } + +private: + CategoryNode() : mLock(nsnull) { } + void* operator new(size_t aSize, PLArenaPool* aArena); + + nsTHashtable mTable; + PRLock* mLock; +}; + + +/** + * The main implementation of nsICategoryManager. + * + * This implementation is thread-safe. + */ +class nsCategoryManager + : public nsICategoryManager +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSICATEGORYMANAGER + + /** + * Write the categories to the XPCOM persistent registry. + * This is to be used by nsComponentManagerImpl (and NO ONE ELSE). + */ + NS_METHOD WriteCategoryManagerToRegistry(PRFileDesc* fd); + + nsCategoryManager() : mLock(nsnull) { } +private: + friend class nsCategoryManagerFactory; + static nsCategoryManager* Create(); + + ~nsCategoryManager(); + + CategoryNode* get_category(const char* aName); + + PLArenaPool mArena; + nsClassHashtable mTable; + PRLock* mLock; +}; + +#endif diff --git a/src/libs/xpcom18a4/xpcom/components/nsCategoryManagerUtils.h b/src/libs/xpcom18a4/xpcom/components/nsCategoryManagerUtils.h new file mode 100644 index 00000000..54a9fcec --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/components/nsCategoryManagerUtils.h @@ -0,0 +1,88 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +#ifndef nsCategoryManagerUtils_h__ +#define nsCategoryManagerUtils_h__ + +#include "nsICategoryManager.h" +#include "nsCOMPtr.h" + +NS_COM nsresult +NS_CreateServicesFromCategory(const char *category, + nsISupports *origin, + const char *observerTopic); + +class NS_COM nsCreateInstanceFromCategory : public nsCOMPtr_helper +{ +public: + nsCreateInstanceFromCategory(const char *aCategory, const char *aEntry, + nsISupports *aOuter, nsresult *aErrorPtr) + : mCategory(aCategory), + mEntry(aEntry), + mErrorPtr(aErrorPtr) + { + // nothing else to do; + } + virtual nsresult NS_FASTCALL operator()( const nsIID& aIID, void** aInstancePtr) const; + +private: + const char *mCategory; // Do not free. This char * is not owned. + const char *mEntry; // Do not free. This char * is not owned. + + nsISupports *mOuter; + nsresult *mErrorPtr; + +}; + +inline +const nsCreateInstanceFromCategory +do_CreateInstanceFromCategory( const char *aCategory, const char *aEntry, + nsresult *aErrorPtr = 0) +{ + return nsCreateInstanceFromCategory(aCategory, aEntry, 0, aErrorPtr); +} + +inline +const nsCreateInstanceFromCategory +do_CreateInstanceFromCategory( const char *aCategory, const char *aEntry, + nsISupports *aOuter, nsresult *aErrorPtr = 0) +{ + return nsCreateInstanceFromCategory(aCategory, aEntry, aOuter, aErrorPtr); +} + + +#endif diff --git a/src/libs/xpcom18a4/xpcom/components/nsComponentManager.cpp b/src/libs/xpcom18a4/xpcom/components/nsComponentManager.cpp new file mode 100644 index 00000000..980b0565 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/components/nsComponentManager.cpp @@ -0,0 +1,3794 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** + * + * This Original Code has been modified by IBM Corporation. + * Modifications made by IBM described herein are + * Copyright (c) International Business Machines + * Corporation, 2000 + * + * Modifications to Mozilla code or documentation + * identified per MPL Section 3.3 + * + * Date Modified by Description of modification + * 04/20/2000 IBM Corp. Added PR_CALLBACK for Optlink use in OS2 + */ +#include +#include "nscore.h" +#include "nsISupports.h" +#include "nspr.h" +#include "nsCRT.h" // for atoll +// Arena used by component manager for storing contractid string, dll +// location strings and small objects +// CAUTION: Arena align mask needs to be defined before including plarena.h +// currently from nsComponentManager.h +#define PL_ARENA_CONST_ALIGN_MASK 7 +#define NS_CM_BLOCK_SIZE (1024 * 8) + +#include "nsAutoLock.h" +#include "nsCOMPtr.h" +#include "nsComponentManager.h" +#include "nsComponentManagerObsolete.h" +#include "nsDirectoryService.h" +#include "nsDirectoryServiceDefs.h" +#include "nsCategoryManager.h" +#include "nsCategoryManagerUtils.h" +#include "nsIComponentLoader.h" +#include "nsIEnumerator.h" +#include "nsIInterfaceInfoManager.h" +#include "nsIModule.h" +#include "nsIObserverService.h" +#include "nsISimpleEnumerator.h" +#include "nsXPCOM.h" +#include "nsISupportsPrimitives.h" +#include "nsLocalFile.h" +#include "nsNativeComponentLoader.h" +#include "nsReadableUtils.h" +#include "nsString.h" +#include "nsXPIDLString.h" +#include "prcmon.h" +#include "xptinfo.h" // this after nsISupports, to pick up IID so that xpt stuff doesn't try to define it itself... + +#include "nsInt64.h" +#include "nsManifestLineReader.h" + +#include NEW_H // for placement new + + +#ifdef XP_BEOS +#include +#include +#endif + +#include "prlog.h" + +PRLogModuleInfo* nsComponentManagerLog = nsnull; + +#if 0 || defined (DEBUG_timeless) + #define SHOW_DENIED_ON_SHUTDOWN + #define SHOW_CI_ON_EXISTING_SERVICE + #define XPCOM_CHECK_PENDING_CIDS +#endif + +// Loader Types +#define NS_LOADER_DATA_ALLOC_STEP 6 + +// Bloated registry buffer size to improve startup performance -- needs to +// be big enough to fit the entire file into memory or it'll thrash. +// 512K is big enough to allow for some future growth in the registry. +#define BIG_REGISTRY_BUFLEN (512*1024) + +// Common Key Names +const char classIDKeyName[]="classID"; +const char classesKeyName[]="contractID"; +const char componentLoadersKeyName[]="componentLoaders"; +const char componentsKeyName[]="components"; +const char xpcomComponentsKeyName[]="software/mozilla/XPCOM/components"; +const char xpcomKeyName[]="software/mozilla/XPCOM"; + +// Common Value Names +const char classIDValueName[]="ClassID"; +const char classNameValueName[]="ClassName"; +const char componentCountValueName[]="ComponentsCount"; +const char componentTypeValueName[]="ComponentType"; +const char contractIDValueName[]="ContractID"; +const char fileSizeValueName[]="FileSize"; +const char inprocServerValueName[]="InprocServer"; +const char lastModValueName[]="LastModTimeStamp"; +const char nativeComponentType[]="application/x-mozilla-native"; +const char staticComponentType[]="application/x-mozilla-static"; +const char versionValueName[]="VersionString"; + +const static char XPCOM_ABSCOMPONENT_PREFIX[] = "abs:"; +const static char XPCOM_RELCOMPONENT_PREFIX[] = "rel:"; +const static char XPCOM_GRECOMPONENT_PREFIX[] = "gre:"; + +static const char gIDFormat[] = + "{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}"; + + +#define NS_EMPTY_IID \ +{ \ + 0x00000000, \ + 0x0000, \ + 0x0000, \ + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} \ +} + +NS_DEFINE_CID(kEmptyCID, NS_EMPTY_IID); +NS_DEFINE_CID(kCategoryManagerCID, NS_CATEGORYMANAGER_CID); + +#define UID_STRING_LENGTH 39 + +// Set to true from NS_ShutdownXPCOM. +extern PRBool gXPCOMShuttingDown; + +static void GetIDString(const nsID& aCID, char buf[UID_STRING_LENGTH]) +{ + PR_snprintf(buf, UID_STRING_LENGTH, gIDFormat, + aCID.m0, (PRUint32) aCID.m1, (PRUint32) aCID.m2, + (PRUint32) aCID.m3[0], (PRUint32) aCID.m3[1], + (PRUint32) aCID.m3[2], (PRUint32) aCID.m3[3], + (PRUint32) aCID.m3[4], (PRUint32) aCID.m3[5], + (PRUint32) aCID.m3[6], (PRUint32) aCID.m3[7]); +} + +nsresult +nsCreateInstanceFromCategory::operator()(const nsIID& aIID, void** aInstancePtr) const +{ + /* + * If I were a real man, I would consolidate this with + * nsGetServiceFromContractID::operator(). + */ + nsresult rv; + nsXPIDLCString value; + nsCOMPtr compMgr; + nsCOMPtr catman = + do_GetService(kCategoryManagerCID, &rv); + + if (NS_FAILED(rv)) goto error; + + if (!mCategory || !mEntry) { + // when categories have defaults, use that for null mEntry + rv = NS_ERROR_NULL_POINTER; + goto error; + } + + /* find the contractID for category.entry */ + rv = catman->GetCategoryEntry(mCategory, mEntry, + getter_Copies(value)); + if (NS_FAILED(rv)) goto error; + if (!value) { + rv = NS_ERROR_SERVICE_NOT_AVAILABLE; + goto error; + } + NS_GetComponentManager(getter_AddRefs(compMgr)); + if (!compMgr) + return NS_ERROR_FAILURE; + compMgr->CreateInstanceByContractID(value, + mOuter, + aIID, + aInstancePtr); + if (NS_FAILED(rv)) { + error: + *aInstancePtr = 0; + } + + *mErrorPtr = rv; + return rv; +} + + +nsresult +nsGetServiceFromCategory::operator()(const nsIID& aIID, void** aInstancePtr) const +{ + nsresult rv; + nsXPIDLCString value; + nsCOMPtr catman = + do_GetService(kCategoryManagerCID, &rv); + if (NS_FAILED(rv)) goto error; + if (!mCategory || !mEntry) { + // when categories have defaults, use that for null mEntry + rv = NS_ERROR_NULL_POINTER; + goto error; + } + /* find the contractID for category.entry */ + rv = catman->GetCategoryEntry(mCategory, mEntry, + getter_Copies(value)); + if (NS_FAILED(rv)) goto error; + if (!value) { + rv = NS_ERROR_SERVICE_NOT_AVAILABLE; + goto error; + } + if (mServiceManager) { + rv = mServiceManager->GetServiceByContractID(value, aIID, (void**)aInstancePtr); + } else { + nsCOMPtr mgr; + NS_GetServiceManager(getter_AddRefs(mgr)); + if (mgr) + rv = mgr->GetServiceByContractID(value, aIID, (void**)aInstancePtr); + } + if (NS_FAILED(rv)) { + error: + *aInstancePtr = 0; + } + *mErrorPtr = rv; + return rv; +} + +//////////////////////////////////////////////////////////////////////////////// +// Arena helper functions +//////////////////////////////////////////////////////////////////////////////// +char * +ArenaStrndup(const char *s, PRUint32 len, PLArenaPool *arena) +{ + void *mem; + // Include trailing null in the len + PL_ARENA_ALLOCATE(mem, arena, len+1); + if (mem) + memcpy(mem, s, len+1); + return NS_STATIC_CAST(char *, mem); +} + +char* +ArenaStrdup(const char *s, PLArenaPool *arena) +{ + return ArenaStrndup(s, strlen(s), arena); +} + +//////////////////////////////////////////////////////////////////////////////// +// Hashtable Callbacks +//////////////////////////////////////////////////////////////////////////////// + +PRBool PR_CALLBACK +nsFactoryEntry_Destroy(nsHashKey *aKey, void *aData, void* closure); + +PR_STATIC_CALLBACK(const void *) +factory_GetKey(PLDHashTable *aTable, PLDHashEntryHdr *aHdr) +{ + nsFactoryTableEntry* entry = NS_STATIC_CAST(nsFactoryTableEntry*, aHdr); + + return &entry->mFactoryEntry->mCid; +} + +PR_STATIC_CALLBACK(PLDHashNumber) +factory_HashKey(PLDHashTable *aTable, const void *aKey) +{ + const nsCID *cidp = NS_REINTERPRET_CAST(const nsCID*, aKey); + + return cidp->m0; +} + +PR_STATIC_CALLBACK(PRBool) +factory_MatchEntry(PLDHashTable *aTable, const PLDHashEntryHdr *aHdr, + const void *aKey) +{ + const nsFactoryTableEntry* entry = + NS_STATIC_CAST(const nsFactoryTableEntry*, aHdr); + const nsCID *cidp = NS_REINTERPRET_CAST(const nsCID*, aKey); + + return (entry->mFactoryEntry->mCid).Equals(*cidp); +} + +PR_STATIC_CALLBACK(void) +factory_ClearEntry(PLDHashTable *aTable, PLDHashEntryHdr *aHdr) +{ + nsFactoryTableEntry* entry = NS_STATIC_CAST(nsFactoryTableEntry*, aHdr); + // nsFactoryEntry is arena allocated. So we dont delete it. + // We call the destructor by hand. + entry->mFactoryEntry->~nsFactoryEntry(); + PL_DHashClearEntryStub(aTable, aHdr); +} + +static const PLDHashTableOps factory_DHashTableOps = { + PL_DHashAllocTable, + PL_DHashFreeTable, + factory_GetKey, + factory_HashKey, + factory_MatchEntry, + PL_DHashMoveEntryStub, + factory_ClearEntry, + PL_DHashFinalizeStub, +}; + +PR_STATIC_CALLBACK(void) +contractID_ClearEntry(PLDHashTable *aTable, PLDHashEntryHdr *aHdr) +{ + nsContractIDTableEntry* entry = NS_STATIC_CAST(nsContractIDTableEntry*, aHdr); + if (entry->mFactoryEntry->mTypeIndex == NS_COMPONENT_TYPE_SERVICE_ONLY && + entry->mFactoryEntry->mCid.Equals(kEmptyCID)) { + // this object is owned by the hash. + // nsFactoryEntry is arena allocated. So we dont delete it. + // We call the destructor by hand. + entry->mFactoryEntry->~nsFactoryEntry(); + } + + // contractIDs are arena allocated. No need to free them. + + PL_DHashClearEntryStub(aTable, aHdr); +} + +static const PLDHashTableOps contractID_DHashTableOps = { + PL_DHashAllocTable, + PL_DHashFreeTable, + PL_DHashGetKeyStub, + PL_DHashStringKey, + PL_DHashMatchStringKey, + PL_DHashMoveEntryStub, + contractID_ClearEntry, + PL_DHashFinalizeStub, +}; + +//////////////////////////////////////////////////////////////////////////////// +// nsFactoryEntry +//////////////////////////////////////////////////////////////////////////////// + +MOZ_DECL_CTOR_COUNTER(nsFactoryEntry) +nsFactoryEntry::nsFactoryEntry(const nsCID &aClass, + const char *aLocation, + PRUint32 locationlen, + int aType, + class nsFactoryEntry* parent) +: mCid(aClass), mTypeIndex(aType), mParent(parent) +{ + // Arena allocate the location string + mLocation = ArenaStrndup(aLocation, locationlen, &nsComponentManagerImpl::gComponentManager->mArena); +} + +nsFactoryEntry::nsFactoryEntry(const nsCID &aClass, + nsIFactory *aFactory, + class nsFactoryEntry* parent) +: mCid(aClass), mTypeIndex(NS_COMPONENT_TYPE_FACTORY_ONLY), mParent(parent) +{ + mFactory = aFactory; + mLocation = nsnull; +} + +// nsFactoryEntry is usually arena allocated including the strings it +// holds. So we call destructor by hand. +nsFactoryEntry::~nsFactoryEntry(void) +{ + // Release the reference to the factory + mFactory = nsnull; + + // Release any service reference + mServiceObject = nsnull; + + // nsFactoryEntry is arena allocated. So we dont delete it. + // We call the destructor by hand. + if (mParent) + mParent->~nsFactoryEntry(); +} + +nsresult +nsFactoryEntry::ReInit(const nsCID &aClass, const char *aLocation, int aType) +{ + NS_ENSURE_TRUE(mTypeIndex != NS_COMPONENT_TYPE_FACTORY_ONLY, NS_ERROR_INVALID_ARG); + // cid has to match + // SERVICE_ONLY entries can be promoted to an entry of another type + NS_ENSURE_TRUE((mTypeIndex == NS_COMPONENT_TYPE_SERVICE_ONLY || mCid.Equals(aClass)), + NS_ERROR_INVALID_ARG); + + // Arena allocate the location string + mLocation = ArenaStrdup(aLocation, &nsComponentManagerImpl::gComponentManager->mArena); + + mTypeIndex = aType; + return NS_OK; +} + +//////////////////////////////////////////////////////////////////////////////// +// Hashtable Enumeration +//////////////////////////////////////////////////////////////////////////////// +typedef NS_CALLBACK(EnumeratorConverter)(PLDHashTable *table, + const PLDHashEntryHdr *hdr, + void *data, + nsISupports **retval); + +class PLDHashTableEnumeratorImpl : public nsIBidirectionalEnumerator, + public nsISimpleEnumerator +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIENUMERATOR + NS_DECL_NSIBIDIRECTIONALENUMERATOR + NS_DECL_NSISIMPLEENUMERATOR + + PLDHashTableEnumeratorImpl(PLDHashTable *table, + EnumeratorConverter converter, + void *converterData); + PRInt32 Count() { return mCount; } +private: + PLDHashTableEnumeratorImpl(); /* no implementation */ + + ~PLDHashTableEnumeratorImpl(); + NS_IMETHODIMP ReleaseElements(); + + nsVoidArray mElements; + PRInt32 mCount, mCurrent; + PRMonitor* mMonitor; + + struct Closure { + PRBool succeeded; + EnumeratorConverter converter; + void *data; + PLDHashTableEnumeratorImpl *impl; + }; + + static PLDHashOperator PR_CALLBACK Enumerator(PLDHashTable *table, + PLDHashEntryHdr *hdr, + PRUint32 number, + void *data); +}; + +// static +PLDHashOperator PR_CALLBACK +PLDHashTableEnumeratorImpl::Enumerator(PLDHashTable *table, + PLDHashEntryHdr *hdr, + PRUint32 number, + void *data) +{ + Closure *c = NS_REINTERPRET_CAST(Closure *, data); + nsISupports *converted; + if (NS_FAILED(c->converter(table, hdr, c->data, &converted)) || + !c->impl->mElements.AppendElement(converted)) { + c->succeeded = PR_FALSE; + return PL_DHASH_STOP; + } + + c->succeeded = PR_TRUE; + return PL_DHASH_NEXT; +} + +PLDHashTableEnumeratorImpl::PLDHashTableEnumeratorImpl(PLDHashTable *table, + EnumeratorConverter converter, + void *converterData) +: mCurrent(0) +{ + mMonitor = nsAutoMonitor::NewMonitor("PLDHashTableEnumeratorImpl"); + NS_ASSERTION(mMonitor, "NULL Monitor"); + + nsAutoMonitor mon(mMonitor); + + Closure c = { PR_FALSE, converter, converterData, this }; + mCount = PL_DHashTableEnumerate(table, Enumerator, &c); + if (!c.succeeded) { + ReleaseElements(); + mCount = 0; + } +} + +NS_IMPL_ISUPPORTS3(PLDHashTableEnumeratorImpl, + nsIBidirectionalEnumerator, + nsIEnumerator, + nsISimpleEnumerator) + +PLDHashTableEnumeratorImpl::~PLDHashTableEnumeratorImpl() +{ + (void) ReleaseElements(); + + // Destroy the Lock + if (mMonitor) + nsAutoMonitor::DestroyMonitor(mMonitor); +} + +NS_IMETHODIMP +PLDHashTableEnumeratorImpl::ReleaseElements() +{ + for (PRInt32 i = 0; i < mCount; i++) { + nsISupports *supports = NS_REINTERPRET_CAST(nsISupports *, + mElements[i]); + NS_IF_RELEASE(supports); + } + return NS_OK; +} + +NS_IMETHODIMP +PL_NewDHashTableEnumerator(PLDHashTable *table, + EnumeratorConverter converter, + void *converterData, + PLDHashTableEnumeratorImpl **retval) +{ + PLDHashTableEnumeratorImpl *impl = + new PLDHashTableEnumeratorImpl(table, converter, converterData); + + if (!impl) + return NS_ERROR_OUT_OF_MEMORY; + + NS_ADDREF(impl); + + if (impl->Count() == -1) { + // conversion failed + NS_RELEASE(impl); + return NS_ERROR_FAILURE; + } + + *retval = impl; + return NS_OK; +} + +NS_IMETHODIMP +PLDHashTableEnumeratorImpl::First() +{ + if (!mCount) + return NS_ERROR_FAILURE; + + mCurrent = 0; + return NS_OK; +} + +NS_IMETHODIMP +PLDHashTableEnumeratorImpl::Last() +{ + if (!mCount) + return NS_ERROR_FAILURE; + mCurrent = mCount - 1; + return NS_OK; +} + +NS_IMETHODIMP +PLDHashTableEnumeratorImpl::Prev() +{ + if (!mCurrent) + return NS_ERROR_FAILURE; + + mCurrent--; + return NS_OK; +} + +NS_IMETHODIMP +PLDHashTableEnumeratorImpl::Next() +{ + // If empty or we're past the end, or we are at the end return error + if (!mCount || (mCurrent == mCount) || (++mCurrent == mCount)) + return NS_ERROR_FAILURE; + + return NS_OK; +} + +NS_IMETHODIMP +PLDHashTableEnumeratorImpl::CurrentItem(nsISupports **retval) +{ + if (!mCount || mCurrent == mCount) + return NS_ERROR_FAILURE; + + *retval = NS_REINTERPRET_CAST(nsISupports *, mElements[mCurrent]); + if (*retval) + NS_ADDREF(*retval); + + return NS_OK; +} + +NS_IMETHODIMP +PLDHashTableEnumeratorImpl::IsDone() +{ + if (!mCount || (mCurrent == mCount)) + return NS_OK; + + return NS_ENUMERATOR_FALSE; +} + +NS_IMETHODIMP +PLDHashTableEnumeratorImpl::HasMoreElements(PRBool *_retval) +{ + if (!mCount || (mCurrent == mCount)) + *_retval = PR_FALSE; + else + *_retval = PR_TRUE; + + return NS_OK; +} + +NS_IMETHODIMP +PLDHashTableEnumeratorImpl::GetNext(nsISupports **_retval) +{ + nsresult rv = Next(); + if (NS_FAILED(rv)) return rv; + + return CurrentItem(_retval); +} + +static NS_IMETHODIMP +ConvertFactoryEntryToCID(PLDHashTable *table, + const PLDHashEntryHdr *hdr, + void *data, nsISupports **retval) +{ + nsresult rv; + nsCOMPtr wrapper; + + nsComponentManagerImpl *cm = NS_STATIC_CAST(nsComponentManagerImpl *, data); + + rv = cm->CreateInstanceByContractID(NS_SUPPORTS_ID_CONTRACTID, nsnull, + NS_GET_IID(nsISupportsID), getter_AddRefs(wrapper)); + + NS_ENSURE_SUCCESS(rv, rv); + + const nsFactoryTableEntry *entry = + NS_REINTERPRET_CAST(const nsFactoryTableEntry *, hdr); + if (entry) { + nsFactoryEntry *fe = entry->mFactoryEntry; + + wrapper->SetData(&fe->mCid); + *retval = wrapper; + NS_ADDREF(*retval); + return NS_OK; + } + *retval = nsnull; + + return rv; +} + +static NS_IMETHODIMP +ConvertContractIDKeyToString(PLDHashTable *table, + const PLDHashEntryHdr *hdr, + void *data, nsISupports **retval) +{ + nsresult rv; + nsCOMPtr wrapper; + + nsComponentManagerImpl *cm = NS_STATIC_CAST(nsComponentManagerImpl *, data); + + rv = cm->CreateInstanceByContractID(NS_SUPPORTS_CSTRING_CONTRACTID, nsnull, + NS_GET_IID(nsISupportsCString), getter_AddRefs(wrapper)); + + NS_ENSURE_SUCCESS(rv, rv); + + const nsContractIDTableEntry *entry = + NS_REINTERPRET_CAST(const nsContractIDTableEntry *, hdr); + + wrapper->SetData(nsDependentCString(entry->mContractID, + entry->mContractIDLen)); + *retval = wrapper; + NS_ADDREF(*retval); + return NS_OK; +} + +// this is safe to call during InitXPCOM +static nsresult GetLocationFromDirectoryService(const char* prop, + nsIFile** aDirectory) +{ + nsCOMPtr directoryService; + nsDirectoryService::Create(nsnull, + NS_GET_IID(nsIProperties), + getter_AddRefs(directoryService)); + + if (!directoryService) + return NS_ERROR_FAILURE; + + return directoryService->Get(prop, + NS_GET_IID(nsIFile), + (void**)aDirectory); +} + + +//////////////////////////////////////////////////////////////////////////////// +// nsComponentManagerImpl +//////////////////////////////////////////////////////////////////////////////// + + +nsComponentManagerImpl::nsComponentManagerImpl() + : + mMon(NULL), + mNativeComponentLoader(0), +#ifdef ENABLE_STATIC_COMPONENT_LOADER + mStaticComponentLoader(0), +#endif + mShuttingDown(NS_SHUTDOWN_NEVERHAPPENED), + mLoaderData(nsnull), + mRegistryDirty(PR_FALSE) +{ + mFactories.ops = nsnull; + mContractIDs.ops = nsnull; +} + +nsresult nsComponentManagerImpl::Init(void) +{ + PR_ASSERT(mShuttingDown != NS_SHUTDOWN_INPROGRESS); + if (mShuttingDown == NS_SHUTDOWN_INPROGRESS) + return NS_ERROR_FAILURE; + + mShuttingDown = NS_SHUTDOWN_NEVERHAPPENED; + + if (nsComponentManagerLog == nsnull) + { + nsComponentManagerLog = PR_NewLogModule("nsComponentManager"); + } + + // Initialize our arena + PL_INIT_ARENA_POOL(&mArena, "ComponentManagerArena", NS_CM_BLOCK_SIZE); + + if (!mFactories.ops) { + if (!PL_DHashTableInit(&mFactories, &factory_DHashTableOps, + 0, sizeof(nsFactoryTableEntry), + 1024)) { + mFactories.ops = nsnull; + return NS_ERROR_OUT_OF_MEMORY; + } + + // Minimum alpha uses k=2 because nsFactoryTableEntry saves two + // words compared to what a chained hash table requires. + PL_DHashTableSetAlphaBounds(&mFactories, + 0.875, + PL_DHASH_MIN_ALPHA(&mFactories, 2)); + } + + if (!mContractIDs.ops) { + if (!PL_DHashTableInit(&mContractIDs, &contractID_DHashTableOps, + 0, sizeof(nsContractIDTableEntry), + 1024)) { + mContractIDs.ops = nsnull; + return NS_ERROR_OUT_OF_MEMORY; + } + + // Minimum alpha uses k=1 because nsContractIDTableEntry saves one + // word compared to what a chained hash table requires. +#if 0 + PL_DHashTableSetAlphaBounds(&mContractIDs, + 0.875, + PL_DHASH_MIN_ALPHA(&mContractIDs, 1)); +#endif + } + if (mMon == nsnull) { + mMon = nsAutoMonitor::NewMonitor("nsComponentManagerImpl"); + if (mMon == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + } + + if (mNativeComponentLoader == nsnull) { + /* Create the NativeComponentLoader */ + mNativeComponentLoader = new nsNativeComponentLoader(); + if (!mNativeComponentLoader) + return NS_ERROR_OUT_OF_MEMORY; + NS_ADDREF(mNativeComponentLoader); + + nsresult rv = mNativeComponentLoader->Init(this, nsnull); + if (NS_FAILED(rv)) + return rv; + } + + // Add predefined loaders + mLoaderData = (nsLoaderdata *) PR_Malloc(sizeof(nsLoaderdata) * NS_LOADER_DATA_ALLOC_STEP); + if (!mLoaderData) + return NS_ERROR_OUT_OF_MEMORY; + mMaxNLoaderData = NS_LOADER_DATA_ALLOC_STEP; + + mNLoaderData = NS_COMPONENT_TYPE_NATIVE; + mLoaderData[mNLoaderData].type = PL_strdup(nativeComponentType); + mLoaderData[mNLoaderData].loader = mNativeComponentLoader; + NS_ADDREF(mLoaderData[mNLoaderData].loader); + mNLoaderData++; + +#ifdef ENABLE_STATIC_COMPONENT_LOADER + if (mStaticComponentLoader == nsnull) { + extern nsresult NS_NewStaticComponentLoader(nsIComponentLoader **); + NS_NewStaticComponentLoader(&mStaticComponentLoader); + if (!mStaticComponentLoader) + return NS_ERROR_OUT_OF_MEMORY; + } + + mLoaderData[mNLoaderData].type = PL_strdup(staticComponentType); + mLoaderData[mNLoaderData].loader = mStaticComponentLoader; + NS_ADDREF(mLoaderData[mNLoaderData].loader); + mNLoaderData++; + + if (mStaticComponentLoader) { + /* Init the static loader */ + mStaticComponentLoader->Init(this, nsnull); + } +#endif + GetLocationFromDirectoryService(NS_XPCOM_COMPONENT_DIR, getter_AddRefs(mComponentsDir)); + if (!mComponentsDir) + return NS_ERROR_OUT_OF_MEMORY; + + nsCAutoString componentDescriptor; + nsresult rv = mComponentsDir->GetNativePath(componentDescriptor); + if (NS_FAILED(rv)) + return rv; + + mComponentsOffset = componentDescriptor.Length(); + + GetLocationFromDirectoryService(NS_GRE_COMPONENT_DIR, getter_AddRefs(mGREComponentsDir)); + if (mGREComponentsDir) { + nsresult rv = mGREComponentsDir->GetNativePath(componentDescriptor); + if (NS_FAILED(rv)) { + NS_WARNING("No GRE component manager"); + return rv; + } + mGREComponentsOffset = componentDescriptor.Length(); + } + + GetLocationFromDirectoryService(NS_XPCOM_COMPONENT_REGISTRY_FILE, + getter_AddRefs(mRegistryFile)); + + if(!mRegistryFile) { + NS_WARNING("No Component Registry file was found in the directory service"); + return NS_ERROR_FAILURE; + } + + PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG, + ("nsComponentManager: Initialized.")); + + return NS_OK; +} + +PRIntn PR_CALLBACK AutoRegEntryDestroy(nsHashKey *aKey, void *aData, void* aClosure) +{ + delete (AutoRegEntry*)aData; + return kHashEnumerateNext; +} + +nsresult nsComponentManagerImpl::Shutdown(void) +{ + PR_ASSERT(mShuttingDown == NS_SHUTDOWN_NEVERHAPPENED); + if (mShuttingDown != NS_SHUTDOWN_NEVERHAPPENED) + return NS_ERROR_FAILURE; + + mShuttingDown = NS_SHUTDOWN_INPROGRESS; + + // Shutdown the component manager + PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG, ("nsComponentManager: Beginning Shutdown.")); + + PRInt32 i; + + // Write out our component data file. + if (mRegistryDirty) { + nsresult rv = WritePersistentRegistry(); + if (NS_FAILED(rv)) { + PR_LOG(nsComponentManagerLog, PR_LOG_ERROR, ("nsComponentManager: Could not write out perisistant registry.")); +#ifdef DEBUG + printf("Could not write out perisistant registry!\n"); +#endif + } + } + + mAutoRegEntries.Reset(AutoRegEntryDestroy); + + // Release all cached factories + if (mContractIDs.ops) { + PL_DHashTableFinish(&mContractIDs); + mContractIDs.ops = nsnull; + } + if (mFactories.ops) { + PL_DHashTableFinish(&mFactories); + mFactories.ops = nsnull; + } + // Unload libraries + UnloadLibraries(nsnull, NS_Shutdown); + + // delete arena for strings and small objects + PL_FinishArenaPool(&mArena); + + mComponentsDir = 0; + + mCategoryManager = 0; + + // Release all the component data - loaders and type strings + for (i=0; i < mNLoaderData; i++) { + NS_IF_RELEASE(mLoaderData[i].loader); + PL_strfree((char *)mLoaderData[i].type); + } + PR_Free(mLoaderData); + mLoaderData = nsnull; + + // we have an extra reference on this one, which is probably a good thing + NS_IF_RELEASE(mNativeComponentLoader); +#ifdef ENABLE_STATIC_COMPONENT_LOADER + NS_IF_RELEASE(mStaticComponentLoader); +#endif + + mShuttingDown = NS_SHUTDOWN_COMPLETE; + + PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG, ("nsComponentManager: Shutdown complete.")); + + return NS_OK; +} + +nsComponentManagerImpl::~nsComponentManagerImpl() +{ + PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG, ("nsComponentManager: Beginning destruction.")); + + if (mShuttingDown != NS_SHUTDOWN_COMPLETE) + Shutdown(); + + if (mMon) { + nsAutoMonitor::DestroyMonitor(mMon); + } + PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG, ("nsComponentManager: Destroyed.")); +} + +NS_IMPL_THREADSAFE_ISUPPORTS8(nsComponentManagerImpl, + nsIComponentManager, + nsIServiceManager, + nsISupportsWeakReference, + nsIInterfaceRequestor, + nsIComponentRegistrar, + nsIServiceManagerObsolete, + nsIComponentManagerObsolete, + nsIComponentLoaderManager) + + +nsresult +nsComponentManagerImpl::GetInterface(const nsIID & uuid, void **result) +{ + if (uuid.Equals(NS_GET_IID(nsINativeComponentLoader))) + { + if (!mNativeComponentLoader) + return NS_ERROR_NOT_INITIALIZED; + + return mNativeComponentLoader->QueryInterface(uuid, result); + } + + NS_WARNING("This isn't supported"); + // fall through to QI as anything QIable is a superset of what can be + // got via the GetInterface() + return QueryInterface(uuid, result); +} + +//////////////////////////////////////////////////////////////////////////////// +// nsComponentManagerImpl: Platform methods +//////////////////////////////////////////////////////////////////////////////// + +#define PERSISTENT_REGISTRY_VERSION_MINOR 5 +#define PERSISTENT_REGISTRY_VERSION_MAJOR 0 + + +AutoRegEntry::AutoRegEntry(const nsACString& name, PRInt64* modDate) : + mName(ToNewCString(name)), + mNameLen(name.Length()), + mData(nsnull), + mModDate(*modDate) +{ +} + +AutoRegEntry::~AutoRegEntry() +{ + if (mName) PL_strfree(mName); + if (mData) PL_strfree(mData); +} + +PRBool +AutoRegEntry::Modified(PRInt64 *date) +{ + return !LL_EQ(*date, mModDate); +} + +void +AutoRegEntry::SetOptionalData(const char* data) +{ + if (mData) + PL_strfree(mData); + + if (!data) { + mData = nsnull; + return; + } + + mData = PL_strdup(data); +} + +static +PRBool ReadSectionHeader(nsManifestLineReader& reader, const char *token) +{ + while (1) + { + if (*reader.LinePtr() == '[') + { + char* p = reader.LinePtr() + (reader.LineLength() - 1); + if (*p != ']') + break; + *p = 0; + + char* values[1]; + int lengths[1]; + if (2 != reader.ParseLine(values, lengths, 1)) + break; + + // ignore the leading '[' + if (0 != PL_strcmp(values[0]+1, token)) + break; + + return PR_TRUE; + } + + if (!reader.NextLine()) + break; + } + return PR_FALSE; +} + +nsresult +nsComponentManagerImpl::ReadPersistentRegistry() +{ + + // populate Category Manager. need to get this early so that we don't get + // skipped by 'goto out' + nsresult rv = GetService(kCategoryManagerCID, + NS_GET_IID(nsICategoryManager), + getter_AddRefs(mCategoryManager)); + if (NS_FAILED(rv)) + return rv; + + nsAutoMonitor mon(mMon); + nsManifestLineReader reader; + + if (!mComponentsDir) + return NS_ERROR_NOT_INITIALIZED; // this should have been set by Init(). + + PRFileDesc* fd = nsnull; + + // Set From Init + if (!mRegistryFile) { + return NS_ERROR_FILE_NOT_FOUND; + } + + nsCOMPtr file; + mRegistryFile->Clone(getter_AddRefs(file)); + if (!file) + return NS_ERROR_OUT_OF_MEMORY; + + nsCOMPtr localFile(do_QueryInterface(file)); + + rv = localFile->OpenNSPRFileDesc(PR_RDONLY, 0444, &fd); + if (NS_FAILED(rv)) + return rv; + + PRInt64 fileSize; + rv = localFile->GetFileSize(&fileSize); + if (NS_FAILED(rv)) + { + PR_Close(fd); + return rv; + } + + PRInt32 flen = nsInt64(fileSize); + if (flen == 0) + { + PR_Close(fd); + NS_WARNING("Persistent Registry Empty!"); + return NS_OK; // ERROR CONDITION + } + + char* registry = new char[flen+1]; + if (!registry) + goto out; + + if (flen > PR_Read(fd, registry, flen)) + { + rv = NS_ERROR_FAILURE; + goto out; + } + registry[flen] = '\0'; + + reader.Init(registry, flen); + + if (ReadSectionHeader(reader, "HEADER")) + goto out; + + if (!reader.NextLine()) + goto out; + + char* values[6]; + int lengths[6]; + + // VersionLiteral,major,minor + if (3 != reader.ParseLine(values, lengths, 3)) + goto out; + + // VersionLiteral + if (!nsDependentCString(values[0], lengths[0]).EqualsLiteral("Version")) + goto out; + + // major + if (PERSISTENT_REGISTRY_VERSION_MAJOR != atoi(values[1])) + goto out; + + // minor + if (PERSISTENT_REGISTRY_VERSION_MINOR != atoi(values[2])) + goto out; + + if (ReadSectionHeader(reader, "COMPONENTS")) + goto out; + + while (1) + { + if (!reader.NextLine()) + break; + + //name,last_modification_date[,optionaldata] + int parts = reader.ParseLine(values, lengths, 3); + if (2 > parts) + break; + + PRInt64 a = nsCRT::atoll(values[1]); + AutoRegEntry *entry = + new AutoRegEntry(nsDependentCString(values[0], lengths[0]), &a); + + if (!entry) + return NS_ERROR_OUT_OF_MEMORY; + + if (parts == 3) + entry->SetOptionalData(values[2]); + + nsCStringKey key((const char*)values[0]); + mAutoRegEntries.Put(&key, entry); + } + + if (ReadSectionHeader(reader, "CLASSIDS")) + goto out; + + while (1) + { + if (!reader.NextLine()) + break; + + // cid,contract_id,type,class_name,inproc_server + if (5 != reader.ParseLine(values, lengths, 5)) + break; + + nsCID aClass; + if (!aClass.Parse(values[0])) + continue; + + int loadertype = GetLoaderType(values[2]); + if (loadertype < 0) { + rv = AddLoaderType(values[2], &loadertype); + if (NS_FAILED(rv)) + continue; + } + + void *mem; + PL_ARENA_ALLOCATE(mem, &mArena, sizeof(nsFactoryEntry)); + if (!mem) + return NS_ERROR_OUT_OF_MEMORY; + + nsFactoryEntry *entry = new (mem) nsFactoryEntry(aClass, values[4], lengths[4], loadertype); + + nsFactoryTableEntry* factoryTableEntry = + NS_STATIC_CAST(nsFactoryTableEntry*, + PL_DHashTableOperate(&mFactories, + &aClass, + PL_DHASH_ADD)); + + if (!factoryTableEntry) + return NS_ERROR_OUT_OF_MEMORY; + + factoryTableEntry->mFactoryEntry = entry; + + } + + if (ReadSectionHeader(reader, "CONTRACTIDS")) + goto out; + + while (1) + { + if (!reader.NextLine()) + break; + + //contractID,cid + if (2 != reader.ParseLine(values, lengths, 2)) + break; + + nsCID aClass; + if (!aClass.Parse(values[1])) + continue; + + + //need to find the location for this cid. + nsFactoryEntry *cidEntry = GetFactoryEntry(aClass); + if (!cidEntry || cidEntry->mTypeIndex < 0) + continue; //what should we really do? + + nsContractIDTableEntry* contractIDTableEntry = + NS_STATIC_CAST(nsContractIDTableEntry*, + PL_DHashTableOperate(&mContractIDs, + values[0], + PL_DHASH_ADD)); + if (!contractIDTableEntry) { + continue; + } + + if (!contractIDTableEntry->mContractID) { + contractIDTableEntry->mContractID = ArenaStrndup(values[0], lengths[0], &mArena); + contractIDTableEntry->mContractIDLen = lengths[0]; + } + + contractIDTableEntry->mFactoryEntry = cidEntry; + } + +#ifdef XPCOM_CHECK_PENDING_CIDS + { +/* + * If you get Asserts when you define SHOW_CI_ON_EXISTING_SERVICE and want to + * track down their cause, then you should add the contracts listed by the + * assertion to abusedContracts. The next time you run your xpcom app, xpcom + * will assert the first time the object associated with the contract is + * instantiated (which in many cases is the source of the problem). + * + * If you're doing this then you might want to NOP and soft breakpoint the + * lines labeled: NOP_AND_BREAK. + * + * Otherwise XPCOM will refuse to create the object for the caller, which + * while reasonable at some level, will almost certainly cause the app to + * stop functioning normally. + */ + static char abusedContracts[][128] = { + /*// Example contracts: + "@mozilla.org/rdf/container;1", + "@mozilla.org/intl/charsetalias;1", + "@mozilla.org/locale/win32-locale;1", + "@mozilla.org/widget/lookandfeel/win;1", + // */ + { 0 } + }; + for (int i=0; abusedContracts[i] && *abusedContracts[i]; i++) { + nsFactoryEntry *entry = nsnull; + nsContractIDTableEntry* contractIDTableEntry = + NS_STATIC_CAST(nsContractIDTableEntry*, + PL_DHashTableOperate(&mContractIDs, abusedContracts[i], + PL_DHASH_LOOKUP)); + + if (PL_DHASH_ENTRY_IS_BUSY(contractIDTableEntry)) { + entry = contractIDTableEntry->mFactoryEntry; + AddPendingCID(entry->mCid); + } + } + } +#endif + + if (ReadSectionHeader(reader, "CATEGORIES")) + goto out; + + while (1) + { + if (!reader.NextLine()) + break; + + //type,name,value + if (3 != reader.ParseLine(values, lengths, 3)) + break; + + mCategoryManager->AddCategoryEntry(values[0], + values[1], + values[2], + PR_TRUE, + PR_TRUE, + 0); + } + + mRegistryDirty = PR_FALSE; +out: + if (fd) + PR_Close(fd); + + if (registry) + delete [] registry; + + return rv; +} + +struct PersistentWriterArgs +{ + PRFileDesc *mFD; + nsLoaderdata *mLoaderData; +}; + +PR_STATIC_CALLBACK(PLDHashOperator) +ContractIDWriter(PLDHashTable *table, + PLDHashEntryHdr *hdr, + PRUint32 number, + void *arg) +{ + char *contractID = ((nsContractIDTableEntry*)hdr)->mContractID; + nsFactoryEntry *factoryEntry = ((nsContractIDTableEntry*)hdr)->mFactoryEntry; + + // for now, we only save out the top most parent. + while (factoryEntry->mParent) + factoryEntry = factoryEntry->mParent; + + if (factoryEntry->mTypeIndex < 0) + return PL_DHASH_NEXT; + + PRFileDesc* fd = ((PersistentWriterArgs*)arg)->mFD; + + char cidString[UID_STRING_LENGTH]; + GetIDString(factoryEntry->mCid, cidString); + PR_fprintf(fd, "%s,%s\n", contractID, cidString); // what if this fails? + return PL_DHASH_NEXT; +} + +PR_STATIC_CALLBACK(PLDHashOperator) +ClassIDWriter(PLDHashTable *table, + PLDHashEntryHdr *hdr, + PRUint32 number, + void *arg) +{ + nsFactoryEntry *factoryEntry = ((nsFactoryTableEntry*)hdr)->mFactoryEntry; + PRFileDesc* fd = ((PersistentWriterArgs*)arg)->mFD; + nsLoaderdata *loaderData = ((PersistentWriterArgs*)arg)->mLoaderData; + + // for now, we only save out the top most parent. + while (factoryEntry->mParent) + factoryEntry = factoryEntry->mParent; + + if (factoryEntry->mTypeIndex < 0) { + return PL_DHASH_NEXT; + } + + char cidString[UID_STRING_LENGTH]; + GetIDString(factoryEntry->mCid, cidString); + + char *contractID = nsnull, *className = nsnull; + + nsCOMPtr classInfo = do_QueryInterface(factoryEntry->mFactory); + if (classInfo) + { + classInfo->GetContractID(&contractID); + classInfo->GetClassDescription(&className); + } + + const char * loaderName = nsnull; + if (factoryEntry->mTypeIndex) + loaderName = loaderData[factoryEntry->mTypeIndex].type; + + char* location = factoryEntry->mLocation; + + // cid,contract_id,type,class_name,inproc_server + PR_fprintf(fd, + "%s,%s,%s,%s,%s\n", + cidString, + (contractID ? contractID : ""), + (loaderName ? loaderName : ""), + (className ? className : ""), + (location ? location : "")); + + if (contractID) + PR_Free(contractID); + if (className) + PR_Free(className); + + return PL_DHASH_NEXT; +} + +PRIntn PR_CALLBACK +AutoRegEntryWriter(nsHashKey *aKey, void *aData, void* aClosure) +{ + PRFileDesc* fd = (PRFileDesc*) aClosure; + AutoRegEntry* entry = (AutoRegEntry*) aData; + + const char* extraData = entry->GetOptionalData(); + const char *fmt; + if (extraData) + fmt = "%s,%lld,%s\n"; + else + fmt = "%s,%lld\n"; + PR_fprintf(fd, fmt, entry->GetName().get(), entry->GetDate(), extraData); + + return PR_TRUE; +} + +nsresult +nsComponentManagerImpl::WritePersistentRegistry() +{ + if (!mRegistryFile) + return NS_ERROR_FAILURE; // this should have been set by Init(). + + nsCOMPtr file; + mRegistryFile->Clone(getter_AddRefs(file)); + if (!file) + return NS_ERROR_OUT_OF_MEMORY; + + nsCOMPtr localFile(do_QueryInterface(file)); + + nsCAutoString originalLeafName; + localFile->GetNativeLeafName(originalLeafName); + + nsCAutoString leafName; + leafName.Assign(originalLeafName + NS_LITERAL_CSTRING(".tmp")); + + localFile->SetNativeLeafName(leafName); + + PRFileDesc* fd = nsnull; + nsresult rv = localFile->OpenNSPRFileDesc(PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE, 0600, &fd); + if (NS_FAILED(rv)) + return rv; + + if (PR_fprintf(fd, "Generated File. Do not edit.\n") == (PRUint32) -1) { + rv = NS_ERROR_UNEXPECTED; + goto out; + } + + if (PR_fprintf(fd, "\n[HEADER]\nVersion,%d,%d\n", + PERSISTENT_REGISTRY_VERSION_MAJOR, + PERSISTENT_REGISTRY_VERSION_MINOR) == (PRUint32) -1) { + rv = NS_ERROR_UNEXPECTED; + goto out; + } + + if (PR_fprintf(fd, "\n[COMPONENTS]\n") == (PRUint32) -1) { + rv = NS_ERROR_UNEXPECTED; + goto out; + } + + mAutoRegEntries.Enumerate(AutoRegEntryWriter, (void*)fd); + + PersistentWriterArgs args; + args.mFD = fd; + args.mLoaderData = mLoaderData; + + if (PR_fprintf(fd, "\n[CLASSIDS]\n") == (PRUint32) -1) { + rv = NS_ERROR_UNEXPECTED; + goto out; + } + + + PL_DHashTableEnumerate(&mFactories, ClassIDWriter, (void*)&args); + + if (PR_fprintf(fd, "\n[CONTRACTIDS]\n") == (PRUint32) -1) { + rv = NS_ERROR_UNEXPECTED; + goto out; + } + + + PL_DHashTableEnumerate(&mContractIDs, ContractIDWriter, (void*)&args); + + if (PR_fprintf(fd, "\n[CATEGORIES]\n") == (PRUint32) -1) { + rv = NS_ERROR_UNEXPECTED; + goto out; + } + + + if (!mCategoryManager) { + NS_WARNING("Could not access category manager. Will not be able to save categories!"); + rv = NS_ERROR_UNEXPECTED; + } else { + rv = mCategoryManager->WriteCategoryManagerToRegistry(fd); + } + +out: + if (fd) + PR_Close(fd); + + // don't create the file is there was a problem???? + NS_ENSURE_SUCCESS(rv, rv); + + if (!mRegistryFile) + return NS_ERROR_NOT_INITIALIZED; + + PRBool exists; + if(NS_FAILED(mRegistryFile->Exists(&exists))) + return PR_FALSE; + + if(exists && NS_FAILED(mRegistryFile->Remove(PR_FALSE))) + return PR_FALSE; + + nsCOMPtr parent; + mRegistryFile->GetParent(getter_AddRefs(parent)); + + rv = localFile->MoveToNative(parent, originalLeafName); + mRegistryDirty = PR_FALSE; + + return rv; +} + + +//////////////////////////////////////////////////////////////////////////////// +// Hash Functions +//////////////////////////////////////////////////////////////////////////////// +nsresult +nsComponentManagerImpl::HashContractID(const char *aContractID, + PRUint32 aContractIDLen, + nsFactoryEntry *fe) +{ + if(!aContractID || !aContractIDLen) + return NS_ERROR_NULL_POINTER; + + nsAutoMonitor mon(mMon); + + nsContractIDTableEntry* contractIDTableEntry = + NS_STATIC_CAST(nsContractIDTableEntry*, + PL_DHashTableOperate(&mContractIDs, aContractID, + PL_DHASH_ADD)); + if (!contractIDTableEntry) + return NS_ERROR_OUT_OF_MEMORY; + + NS_ASSERTION(!contractIDTableEntry->mContractID || !strcmp(contractIDTableEntry->mContractID, aContractID), "contractid conflict"); + + if (!contractIDTableEntry->mContractID) { + contractIDTableEntry->mContractID = ArenaStrndup(aContractID, aContractIDLen, &mArena); + contractIDTableEntry->mContractIDLen = aContractIDLen; + } + + contractIDTableEntry->mFactoryEntry = fe; + + return NS_OK; +} + +/** + * LoadFactory() + * + * Given a FactoryEntry, this loads the dll if it has to, find the NSGetFactory + * symbol, calls the routine to create a new factory and returns it to the + * caller. + * + * No attempt is made to store the factory in any form anywhere. + */ +nsresult +nsComponentManagerImpl::LoadFactory(nsFactoryEntry *aEntry, + nsIFactory **aFactory) +{ + + if (!aFactory) + return NS_ERROR_NULL_POINTER; + *aFactory = nsnull; + + nsresult rv; + rv = aEntry->GetFactory(aFactory, this); + if (NS_FAILED(rv)) { + PR_LOG(nsComponentManagerLog, PR_LOG_ERROR, + ("nsComponentManager: FAILED to load factory from %s (%s)\n", + (const char *)aEntry->mLocation, mLoaderData[aEntry->mTypeIndex].type)); + return rv; + } + + return NS_OK; +} + +nsFactoryEntry * +nsComponentManagerImpl::GetFactoryEntry(const char *aContractID, + PRUint32 aContractIDLen) +{ + nsFactoryEntry *fe = nsnull; + { + nsAutoMonitor mon(mMon); + + nsContractIDTableEntry* contractIDTableEntry = + NS_STATIC_CAST(nsContractIDTableEntry*, + PL_DHashTableOperate(&mContractIDs, aContractID, + PL_DHASH_LOOKUP)); + + + if (PL_DHASH_ENTRY_IS_BUSY(contractIDTableEntry)) { + fe = contractIDTableEntry->mFactoryEntry; + } + } //exit monitor + + return fe; +} + + +nsFactoryEntry * +nsComponentManagerImpl::GetFactoryEntry(const nsCID &aClass) +{ + nsFactoryEntry *entry = nsnull; + { + nsAutoMonitor mon(mMon); + + nsFactoryTableEntry* factoryTableEntry = + NS_STATIC_CAST(nsFactoryTableEntry*, + PL_DHashTableOperate(&mFactories, &aClass, + PL_DHASH_LOOKUP)); + + if (PL_DHASH_ENTRY_IS_BUSY(factoryTableEntry)) { + entry = factoryTableEntry->mFactoryEntry; + } + } // exit monitor + + return entry; +} + + +/** + * FindFactory() + * + * Given a classID, this finds the factory for this CID by first searching the + * local CID<->factory mapping. Next it searches for a Dll that implements + * this classID and calls LoadFactory() to create the factory. + * + * Again, no attempt is made at storing the factory. + */ +nsresult +nsComponentManagerImpl::FindFactory(const nsCID &aClass, + nsIFactory **aFactory) +{ + PR_ASSERT(aFactory != nsnull); + + nsFactoryEntry *entry = GetFactoryEntry(aClass); + + if (!entry) + return NS_ERROR_FACTORY_NOT_REGISTERED; + + return entry->GetFactory(aFactory, this); +} + + +nsresult +nsComponentManagerImpl::FindFactory(const char *contractID, + PRUint32 aContractIDLen, + nsIFactory **aFactory) +{ + PR_ASSERT(aFactory != nsnull); + + nsFactoryEntry *entry = GetFactoryEntry(contractID, aContractIDLen); + + if (!entry) + return NS_ERROR_FACTORY_NOT_REGISTERED; + + return entry->GetFactory(aFactory, this); +} + +/** + * GetClassObject() + * + * Given a classID, this finds the singleton ClassObject that implements the CID. + * Returns an interface of type aIID off the singleton classobject. + */ +nsresult +nsComponentManagerImpl::GetClassObject(const nsCID &aClass, const nsIID &aIID, + void **aResult) +{ + nsresult rv; + + nsCOMPtr factory; + +#ifdef PR_LOGGING + if (PR_LOG_TEST(nsComponentManagerLog, PR_LOG_DEBUG)) + { + char *buf = aClass.ToString(); + PR_LogPrint("nsComponentManager: GetClassObject(%s)", buf); + if (buf) + PR_Free(buf); + } +#endif + + PR_ASSERT(aResult != nsnull); + + rv = FindFactory(aClass, getter_AddRefs(factory)); + if (NS_FAILED(rv)) return rv; + + rv = factory->QueryInterface(aIID, aResult); + + PR_LOG(nsComponentManagerLog, PR_LOG_WARNING, + ("\t\tGetClassObject() %s", NS_SUCCEEDED(rv) ? "succeeded" : "FAILED")); + + return rv; +} + + +nsresult +nsComponentManagerImpl::GetClassObjectByContractID(const char *contractID, + const nsIID &aIID, + void **aResult) +{ + nsresult rv; + + nsCOMPtr factory; + +#ifdef PR_LOGGING + if (PR_LOG_TEST(nsComponentManagerLog, PR_LOG_DEBUG)) + { + PR_LogPrint("nsComponentManager: GetClassObject(%s)", contractID); + } +#endif + + PR_ASSERT(aResult != nsnull); + + rv = FindFactory(contractID, strlen(contractID), getter_AddRefs(factory)); + if (NS_FAILED(rv)) return rv; + + rv = factory->QueryInterface(aIID, aResult); + + PR_LOG(nsComponentManagerLog, PR_LOG_WARNING, + ("\t\tGetClassObject() %s", NS_SUCCEEDED(rv) ? "succeeded" : "FAILED")); + + return rv; +} + +/** + * ContractIDToClassID() + * + * Mapping function from a ContractID to a classID. Directly talks to the registry. + * + */ +nsresult +nsComponentManagerImpl::ContractIDToClassID(const char *aContractID, nsCID *aClass) +{ + NS_PRECONDITION(aContractID != nsnull, "null ptr"); + if (!aContractID) + return NS_ERROR_NULL_POINTER; + + NS_PRECONDITION(aClass != nsnull, "null ptr"); + if (!aClass) + return NS_ERROR_NULL_POINTER; + + nsresult rv = NS_ERROR_FACTORY_NOT_REGISTERED; + + nsFactoryEntry *fe = GetFactoryEntry(aContractID, strlen(aContractID)); + if (fe) { + *aClass = fe->mCid; + rv = NS_OK; + } +#ifdef PR_LOGGING + if (PR_LOG_TEST(nsComponentManagerLog, PR_LOG_WARNING)) { + char *buf = 0; + if (NS_SUCCEEDED(rv)) + buf = aClass->ToString(); + PR_LOG(nsComponentManagerLog, PR_LOG_WARNING, + ("nsComponentManager: ContractIDToClassID(%s)->%s", aContractID, + NS_SUCCEEDED(rv) ? buf : "[FAILED]")); + if (buf) + PR_Free(buf); + } +#endif + return rv; +} + +/** + * CLSIDToContractID() + * + * Translates a classID to a {ContractID, Class Name}. Does direct registry + * access to do the translation. + * + * NOTE: Since this isn't heavily used, we arent caching this. + */ +nsresult +nsComponentManagerImpl::CLSIDToContractID(const nsCID &aClass, + char* *aClassName, + char* *aContractID) +{ + NS_WARNING("Need to implement CLSIDToContractID"); + + nsresult rv = NS_ERROR_FACTORY_NOT_REGISTERED; +#ifdef PR_LOGGING + if (PR_LOG_TEST(nsComponentManagerLog, PR_LOG_WARNING)) + { + char *buf = aClass.ToString(); + PR_LOG(nsComponentManagerLog, PR_LOG_WARNING, + ("nsComponentManager: CLSIDToContractID(%s)->%s", buf, + NS_SUCCEEDED(rv) ? *aContractID : "[FAILED]")); + if (buf) + PR_Free(buf); + } +#endif + return rv; +} + +#ifdef XPCOM_CHECK_PENDING_CIDS + +// This method must be called from within the mMon monitor +nsresult +nsComponentManagerImpl::AddPendingCID(const nsCID &aClass) +{ + int max = mPendingCIDs.Count(); + for (int index = 0; index < max; index++) + { + nsCID *cidp = (nsCID*) mPendingCIDs.ElementAt(index); + NS_ASSERTION(cidp, "Bad CID in pending list"); + if (cidp->Equals(aClass)) { + nsXPIDLCString cid; + cid.Adopt(aClass.ToString()); + nsCAutoString message; + message = NS_LITERAL_CSTRING("Creation of \"") + + cid + NS_LITERAL_CSTRING("\" in progress (Reentrant GS - see bug 194568)"); + // Note that you may see this assertion by near-simultaneous + // calls to GetService on multiple threads. + NS_WARNING(message.get()); + return NS_ERROR_NOT_AVAILABLE; + } + } + mPendingCIDs.AppendElement((void*)&aClass); + return NS_OK; +} + +// This method must be called from within the mMon monitor +void +nsComponentManagerImpl::RemovePendingCID(const nsCID &aClass) +{ + mPendingCIDs.RemoveElement((void*)&aClass); +} +#endif +/** + * CreateInstance() + * + * Create an instance of an object that implements an interface and belongs + * to the implementation aClass using the factory. The factory is immediately + * released and not held onto for any longer. + */ +nsresult +nsComponentManagerImpl::CreateInstance(const nsCID &aClass, + nsISupports *aDelegate, + const nsIID &aIID, + void **aResult) +{ + // test this first, since there's no point in creating a component during + // shutdown -- whether it's available or not would depend on the order it + // occurs in the list + if (gXPCOMShuttingDown) { + // When processing shutdown, dont process new GetService() requests +#ifdef SHOW_DENIED_ON_SHUTDOWN + nsXPIDLCString cid, iid; + cid.Adopt(aClass.ToString()); + iid.Adopt(aIID.ToString()); + fprintf(stderr, "Creating new instance on shutdown. Denied.\n" + " CID: %s\n IID: %s\n", cid.get(), iid.get()); +#endif /* SHOW_DENIED_ON_SHUTDOWN */ + return NS_ERROR_UNEXPECTED; + } + + if (aResult == nsnull) + { + return NS_ERROR_NULL_POINTER; + } + *aResult = nsnull; + + nsFactoryEntry *entry = GetFactoryEntry(aClass); + + if (!entry) + return NS_ERROR_FACTORY_NOT_REGISTERED; + +#ifdef SHOW_CI_ON_EXISTING_SERVICE + if (entry->mServiceObject) { + nsXPIDLCString cid; + cid.Adopt(aClass.ToString()); + nsCAutoString message; + message = NS_LITERAL_CSTRING("You are calling CreateInstance \"") + + cid + NS_LITERAL_CSTRING("\" when a service for this CID already exists!"); + NS_ERROR(message.get()); + } +#endif + + nsIFactory *factory = nsnull; + nsresult rv = entry->GetFactory(&factory, this); + + if (NS_SUCCEEDED(rv)) + { + rv = factory->CreateInstance(aDelegate, aIID, aResult); + NS_RELEASE(factory); + } + else + { + // Translate error values + rv = NS_ERROR_FACTORY_NOT_REGISTERED; + } + +#ifdef PR_LOGGING + if (PR_LOG_TEST(nsComponentManagerLog, PR_LOG_WARNING)) + { + char *buf = aClass.ToString(); + PR_LOG(nsComponentManagerLog, PR_LOG_WARNING, + ("nsComponentManager: CreateInstance(%s) %s", buf, + NS_SUCCEEDED(rv) ? "succeeded" : "FAILED")); + if (buf) + PR_Free(buf); + } +#endif + + return rv; +} + +/** + * CreateInstanceByContractID() + * + * A variant of CreateInstance() that creates an instance of the object that + * implements the interface aIID and whose implementation has a contractID aContractID. + * + * This is only a convenience routine that turns around can calls the + * CreateInstance() with classid and iid. + */ +nsresult +nsComponentManagerImpl::CreateInstanceByContractID(const char *aContractID, + nsISupports *aDelegate, + const nsIID &aIID, + void **aResult) +{ + // test this first, since there's no point in creating a component during + // shutdown -- whether it's available or not would depend on the order it + // occurs in the list + if (gXPCOMShuttingDown) { + // When processing shutdown, dont process new GetService() requests +#ifdef SHOW_DENIED_ON_SHUTDOWN + nsXPIDLCString iid; + iid.Adopt(aIID.ToString()); + fprintf(stderr, "Creating new instance on shutdown. Denied.\n" + " ContractID: %s\n IID: %s\n", aContractID, iid.get()); +#endif /* SHOW_DENIED_ON_SHUTDOWN */ + return NS_ERROR_UNEXPECTED; + } + + if (aResult == nsnull) + { + return NS_ERROR_NULL_POINTER; + } + *aResult = nsnull; + + nsFactoryEntry *entry = GetFactoryEntry(aContractID, strlen(aContractID)); + + if (!entry) + return NS_ERROR_FACTORY_NOT_REGISTERED; + +#ifdef SHOW_CI_ON_EXISTING_SERVICE + if (entry->mServiceObject) { + nsCAutoString message; + message = + NS_LITERAL_CSTRING("You are calling CreateInstance \"") + + nsDependentCString(aContractID) + + NS_LITERAL_CSTRING("\" when a service for this CID already exists! " + "Add it to abusedContracts to track down the service consumer."); + NS_ERROR(message.get()); + } +#endif + + nsIFactory *factory = nsnull; + nsresult rv = entry->GetFactory(&factory, this); + + if (NS_SUCCEEDED(rv)) + { + + rv = factory->CreateInstance(aDelegate, aIID, aResult); + NS_RELEASE(factory); + } + else + { + // Translate error values + if (rv != NS_ERROR_SOCKET_FAIL) + rv = NS_ERROR_FACTORY_NOT_REGISTERED; + } + + PR_LOG(nsComponentManagerLog, PR_LOG_WARNING, + ("nsComponentManager: CreateInstanceByContractID(%s) %s", aContractID, + NS_SUCCEEDED(rv) ? "succeeded" : "FAILED")); + + return rv; +} + +// Service Manager Impl +static +PLDHashOperator PR_CALLBACK +FreeServiceFactoryEntryEnumerate(PLDHashTable *aTable, + PLDHashEntryHdr *aHdr, + PRUint32 aNumber, + void *aData) +{ + nsFactoryTableEntry* entry = NS_STATIC_CAST(nsFactoryTableEntry*, aHdr); + + if (!entry->mFactoryEntry) + return PL_DHASH_NEXT; + + nsFactoryEntry* factoryEntry = entry->mFactoryEntry; + factoryEntry->mServiceObject = nsnull; + return PL_DHASH_NEXT; +} + +static +PLDHashOperator PR_CALLBACK +FreeServiceContractIDEntryEnumerate(PLDHashTable *aTable, + PLDHashEntryHdr *aHdr, + PRUint32 aNumber, + void *aData) +{ + nsContractIDTableEntry* entry = NS_STATIC_CAST(nsContractIDTableEntry*, aHdr); + + if (!entry->mFactoryEntry) + return PL_DHASH_NEXT; + + nsFactoryEntry* factoryEntry = entry->mFactoryEntry; + factoryEntry->mServiceObject = nsnull; + return PL_DHASH_NEXT; +} + +nsresult +nsComponentManagerImpl::FreeServices() +{ + NS_ASSERTION(gXPCOMShuttingDown, "Must be shutting down in order to free all services"); + + if (!gXPCOMShuttingDown) + return NS_ERROR_FAILURE; + + if (mContractIDs.ops) { + PL_DHashTableEnumerate(&mContractIDs, FreeServiceContractIDEntryEnumerate, nsnull); + } + + + if (mFactories.ops) { + PL_DHashTableEnumerate(&mFactories, FreeServiceFactoryEntryEnumerate, nsnull); + } + + return NS_OK; +} + +NS_IMETHODIMP +nsComponentManagerImpl::GetService(const nsCID& aClass, + const nsIID& aIID, + void* *result) +{ + // test this first, since there's no point in returning a service during + // shutdown -- whether it's available or not would depend on the order it + // occurs in the list + if (gXPCOMShuttingDown) { + // When processing shutdown, dont process new GetService() requests +#ifdef SHOW_DENIED_ON_SHUTDOWN + nsXPIDLCString cid, iid; + cid.Adopt(aClass.ToString()); + iid.Adopt(aIID.ToString()); + fprintf(stderr, "Getting service on shutdown. Denied.\n" + " CID: %s\n IID: %s\n", cid.get(), iid.get()); +#endif /* SHOW_DENIED_ON_SHUTDOWN */ + return NS_ERROR_UNEXPECTED; + } + + nsAutoMonitor mon(mMon); + + nsresult rv = NS_OK; + nsIDKey key(aClass); + nsFactoryEntry* entry = nsnull; + nsFactoryTableEntry* factoryTableEntry = + NS_STATIC_CAST(nsFactoryTableEntry*, + PL_DHashTableOperate(&mFactories, &aClass, + PL_DHASH_LOOKUP)); + + if (PL_DHASH_ENTRY_IS_BUSY(factoryTableEntry)) { + entry = factoryTableEntry->mFactoryEntry; + } + + if (entry && entry->mServiceObject) { + return entry->mServiceObject->QueryInterface(aIID, result); + } + +#ifdef XPCOM_CHECK_PENDING_CIDS + rv = AddPendingCID(aClass); + if (NS_FAILED(rv)) + return rv; // NOP_AND_BREAK +#endif + nsCOMPtr service; + // We need to not be holding the service manager's monitor while calling + // CreateInstance, because it invokes user code which could try to re-enter + // the service manager: + mon.Exit(); + + rv = CreateInstance(aClass, nsnull, aIID, getter_AddRefs(service)); + + mon.Enter(); + +#ifdef XPCOM_CHECK_PENDING_CIDS + RemovePendingCID(aClass); +#endif + + if (NS_FAILED(rv)) + return rv; + + if (!entry) { // second hash lookup for GetService + nsFactoryTableEntry* factoryTableEntry = + NS_STATIC_CAST(nsFactoryTableEntry*, + PL_DHashTableOperate(&mFactories, &aClass, + PL_DHASH_LOOKUP)); + if (PL_DHASH_ENTRY_IS_BUSY(factoryTableEntry)) { + entry = factoryTableEntry->mFactoryEntry; + } + NS_ASSERTION(entry, "we should have a factory entry since CI succeeded - we should not get here"); + if (!entry) return NS_ERROR_FAILURE; + } + + entry->mServiceObject = service; + *result = service.get(); + NS_ADDREF(NS_STATIC_CAST(nsISupports*, (*result))); + return rv; +} + +NS_IMETHODIMP +nsComponentManagerImpl::RegisterService(const nsCID& aClass, nsISupports* aService) +{ + nsAutoMonitor mon(mMon); + + // check to see if we have a factory entry for the service + nsFactoryEntry *entry = GetFactoryEntry(aClass); + + if (!entry) { // XXXdougt - should we require that all services register factories?? probably not. + void *mem; + PL_ARENA_ALLOCATE(mem, &mArena, sizeof(nsFactoryEntry)); + if (!mem) + return NS_ERROR_OUT_OF_MEMORY; + entry = new (mem) nsFactoryEntry(aClass, nsnull); + + entry->mTypeIndex = NS_COMPONENT_TYPE_SERVICE_ONLY; + nsFactoryTableEntry* factoryTableEntry = + NS_STATIC_CAST(nsFactoryTableEntry*, + PL_DHashTableOperate(&mFactories, &aClass, + PL_DHASH_ADD)); + if (!factoryTableEntry) + return NS_ERROR_OUT_OF_MEMORY; + + factoryTableEntry->mFactoryEntry = entry; + } + else { + if (entry->mServiceObject) + return NS_ERROR_FAILURE; + } + + entry->mServiceObject = aService; + return NS_OK; +} + +NS_IMETHODIMP +nsComponentManagerImpl::UnregisterService(const nsCID& aClass) +{ + nsresult rv = NS_OK; + + nsFactoryEntry* entry = nsnull; + + nsAutoMonitor mon(mMon); + + nsFactoryTableEntry* factoryTableEntry = + NS_STATIC_CAST(nsFactoryTableEntry*, + PL_DHashTableOperate(&mFactories, &aClass, + PL_DHASH_LOOKUP)); + + if (PL_DHASH_ENTRY_IS_BUSY(factoryTableEntry)) { + entry = factoryTableEntry->mFactoryEntry; + } + + if (!entry || !entry->mServiceObject) + return NS_ERROR_SERVICE_NOT_AVAILABLE; + + entry->mServiceObject = nsnull; + return rv; +} + +NS_IMETHODIMP +nsComponentManagerImpl::RegisterService(const char* aContractID, nsISupports* aService) +{ + + nsAutoMonitor mon(mMon); + + // check to see if we have a factory entry for the service + PRUint32 contractIDLen = strlen(aContractID); + nsFactoryEntry *entry = GetFactoryEntry(aContractID, contractIDLen); + + if (!entry) { // XXXdougt - should we require that all services register factories?? probably not. + void *mem; + PL_ARENA_ALLOCATE(mem, &mArena, sizeof(nsFactoryEntry)); + if (!mem) + return NS_ERROR_OUT_OF_MEMORY; + entry = new (mem) nsFactoryEntry(kEmptyCID, nsnull); + + entry->mTypeIndex = NS_COMPONENT_TYPE_SERVICE_ONLY; + + nsContractIDTableEntry* contractIDTableEntry = + NS_STATIC_CAST(nsContractIDTableEntry*, + PL_DHashTableOperate(&mContractIDs, aContractID, + PL_DHASH_ADD)); + if (!contractIDTableEntry) { + delete entry; + return NS_ERROR_OUT_OF_MEMORY; + } + + if (!contractIDTableEntry->mContractID) { + contractIDTableEntry->mContractID = + ArenaStrndup(aContractID, contractIDLen, &mArena); + + contractIDTableEntry->mContractIDLen = contractIDLen; + } + + contractIDTableEntry->mFactoryEntry = entry; + } + else { + if (entry->mServiceObject) + return NS_ERROR_FAILURE; + } + + entry->mServiceObject = aService; + return NS_OK; +} + + +NS_IMETHODIMP +nsComponentManagerImpl::IsServiceInstantiated(const nsCID & aClass, + const nsIID& aIID, + PRBool *result) +{ + // Now we want to get the service if we already got it. If not, we dont want + // to create an instance of it. mmh! + + // test this first, since there's no point in returning a service during + // shutdown -- whether it's available or not would depend on the order it + // occurs in the list + if (gXPCOMShuttingDown) { + // When processing shutdown, dont process new GetService() requests +#ifdef SHOW_DENIED_ON_SHUTDOWN + nsXPIDLCString cid, iid; + cid.Adopt(aClass.ToString()); + iid.Adopt(aIID.ToString()); + fprintf(stderr, "Checking for service on shutdown. Denied.\n" + " CID: %s\n IID: %s\n", cid.get(), iid.get()); +#endif /* SHOW_DENIED_ON_SHUTDOWN */ + return NS_ERROR_UNEXPECTED; + } + + nsresult rv = NS_ERROR_SERVICE_NOT_AVAILABLE; + nsFactoryEntry* entry = nsnull; + nsFactoryTableEntry* factoryTableEntry = + NS_STATIC_CAST(nsFactoryTableEntry*, + PL_DHashTableOperate(&mFactories, &aClass, + PL_DHASH_LOOKUP)); + + if (PL_DHASH_ENTRY_IS_BUSY(factoryTableEntry)) { + entry = factoryTableEntry->mFactoryEntry; + } + + if (entry && entry->mServiceObject) { + nsCOMPtr service; + rv = entry->mServiceObject->QueryInterface(aIID, getter_AddRefs(service)); + *result = (service!=nsnull); + } + return rv; + +} + +NS_IMETHODIMP nsComponentManagerImpl::IsServiceInstantiatedByContractID(const char *aContractID, + const nsIID& aIID, + PRBool *result) +{ + // Now we want to get the service if we already got it. If not, we dont want + // to create an instance of it. mmh! + + // test this first, since there's no point in returning a service during + // shutdown -- whether it's available or not would depend on the order it + // occurs in the list + if (gXPCOMShuttingDown) { + // When processing shutdown, dont process new GetService() requests +#ifdef SHOW_DENIED_ON_SHUTDOWN + nsXPIDLCString iid; + iid.Adopt(aIID.ToString()); + fprintf(stderr, "Checking for service on shutdown. Denied.\n" + " ContractID: %s\n IID: %s\n", aContractID, iid.get()); +#endif /* SHOW_DENIED_ON_SHUTDOWN */ + return NS_ERROR_UNEXPECTED; + } + + nsresult rv = NS_ERROR_SERVICE_NOT_AVAILABLE; + nsFactoryEntry *entry = nsnull; + { + nsAutoMonitor mon(mMon); + + nsContractIDTableEntry* contractIDTableEntry = + NS_STATIC_CAST(nsContractIDTableEntry*, + PL_DHashTableOperate(&mContractIDs, aContractID, + PL_DHASH_LOOKUP)); + + if (PL_DHASH_ENTRY_IS_BUSY(contractIDTableEntry)) { + entry = contractIDTableEntry->mFactoryEntry; + } + } // exit monitor + + if (entry && entry->mServiceObject) { + nsCOMPtr service; + rv = entry->mServiceObject->QueryInterface(aIID, getter_AddRefs(service)); + *result = (service!=nsnull); + } + return rv; +} + + +NS_IMETHODIMP +nsComponentManagerImpl::UnregisterService(const char* aContractID) +{ + nsresult rv = NS_OK; + + nsAutoMonitor mon(mMon); + + nsFactoryEntry *entry = nsnull; + nsContractIDTableEntry* contractIDTableEntry = + NS_STATIC_CAST(nsContractIDTableEntry*, + PL_DHashTableOperate(&mContractIDs, aContractID, + PL_DHASH_LOOKUP)); + + if (PL_DHASH_ENTRY_IS_BUSY(contractIDTableEntry)) { + entry = contractIDTableEntry->mFactoryEntry; + } + + if (!entry || !entry->mServiceObject) + return NS_ERROR_SERVICE_NOT_AVAILABLE; + + entry->mServiceObject = nsnull; + return rv; +} + +NS_IMETHODIMP +nsComponentManagerImpl::GetServiceByContractID(const char* aContractID, + const nsIID& aIID, + void* *result) +{ + // test this first, since there's no point in returning a service during + // shutdown -- whether it's available or not would depend on the order it + // occurs in the list + if (gXPCOMShuttingDown) { + // When processing shutdown, dont process new GetService() requests +#ifdef SHOW_DENIED_ON_SHUTDOWN + nsXPIDLCString iid; + iid.Adopt(aIID.ToString()); + fprintf(stderr, "Getting service on shutdown. Denied.\n" + " ContractID: %s\n IID: %s\n", aContractID, iid.get()); +#endif /* SHOW_DENIED_ON_SHUTDOWN */ + return NS_ERROR_UNEXPECTED; + } + + nsAutoMonitor mon(mMon); + + nsresult rv = NS_OK; + nsFactoryEntry *entry = nsnull; + nsContractIDTableEntry* contractIDTableEntry = + NS_STATIC_CAST(nsContractIDTableEntry*, + PL_DHashTableOperate(&mContractIDs, aContractID, + PL_DHASH_LOOKUP)); + + if (PL_DHASH_ENTRY_IS_BUSY(contractIDTableEntry)) { + entry = contractIDTableEntry->mFactoryEntry; + } + + if (entry) { + if (entry->mServiceObject) { + return entry->mServiceObject->QueryInterface(aIID, result); + } +#ifdef XPCOM_CHECK_PENDING_CIDS + rv = AddPendingCID(entry->mCid); + if (NS_FAILED(rv)) + return rv; // NOP_AND_BREAK +#endif + } + + nsCOMPtr service; + // We need to not be holding the service manager's monitor while calling + // CreateInstance, because it invokes user code which could try to re-enter + // the service manager: + mon.Exit(); + + rv = CreateInstanceByContractID(aContractID, nsnull, aIID, getter_AddRefs(service)); + + mon.Enter(); + +#ifdef XPCOM_CHECK_PENDING_CIDS + if (entry) + RemovePendingCID(entry->mCid); +#endif + + if (NS_FAILED(rv)) + return rv; + + if (!entry) { // second hash lookup for GetService + nsContractIDTableEntry* contractIDTableEntry = + NS_STATIC_CAST(nsContractIDTableEntry*, + PL_DHashTableOperate(&mContractIDs, aContractID, + PL_DHASH_LOOKUP)); + + if (PL_DHASH_ENTRY_IS_BUSY(contractIDTableEntry)) { + entry = contractIDTableEntry->mFactoryEntry; + } + NS_ASSERTION(entry, "we should have a factory entry since CI succeeded - we should not get here"); + if (!entry) return NS_ERROR_FAILURE; + } + + entry->mServiceObject = service; + *result = service.get(); + NS_ADDREF(NS_STATIC_CAST(nsISupports*, *result)); + return rv; +} + +NS_IMETHODIMP +nsComponentManagerImpl::GetService(const nsCID& aClass, const nsIID& aIID, + nsISupports* *result, + nsIShutdownListener* shutdownListener) +{ + return GetService(aClass, aIID, (void**)result); +} + +NS_IMETHODIMP +nsComponentManagerImpl::GetService(const char* aContractID, const nsIID& aIID, + nsISupports* *result, + nsIShutdownListener* shutdownListener) +{ + return GetServiceByContractID(aContractID, aIID, (void**)result); +} + + +NS_IMETHODIMP +nsComponentManagerImpl::ReleaseService(const nsCID& aClass, nsISupports* service, + nsIShutdownListener* shutdownListener) +{ + NS_IF_RELEASE(service); + return NS_OK; +} + +NS_IMETHODIMP +nsComponentManagerImpl::ReleaseService(const char* aContractID, nsISupports* service, + nsIShutdownListener* shutdownListener) +{ + NS_IF_RELEASE(service); + return NS_OK; +} + +/* + * I want an efficient way to allocate a buffer to the right size + * and stick the prefix and dllName in, then be able to hand that buffer + * off to the FactoryEntry. Is that so wrong? + * + * *regName is allocated on success. + * + * This should live in nsNativeComponentLoader.cpp, I think. + */ +static nsresult +MakeRegistryName(const char *aDllName, const char *prefix, char **regName) +{ + char *registryName; + + PRUint32 len = strlen(prefix); + + PRUint32 registryNameLen = strlen(aDllName) + len; + registryName = (char *)nsMemory::Alloc(registryNameLen + 1); + + // from here on it, we want len sans terminating NUL + + if (!registryName) + return NS_ERROR_OUT_OF_MEMORY; + + memcpy(registryName, prefix, len); + strcpy(registryName + len, aDllName); + registryName[registryNameLen] = '\0'; + *regName = registryName; + +#ifdef DEBUG_shaver_off + fprintf(stderr, "MakeRegistryName(%s, %s, &[%s])\n", + aDllName, prefix, *regName); +#endif + + return NS_OK; +} + +nsresult +nsComponentManagerImpl::RegistryLocationForSpec(nsIFile *aSpec, + char **aRegistryName) +{ + nsresult rv; + + if (!mComponentsDir) + return NS_ERROR_NOT_INITIALIZED; + + if (!aSpec) { + *aRegistryName = PL_strdup(""); + return NS_OK; + } + + + // First check to see if this component is in the application + // components directory + PRBool containedIn; + mComponentsDir->Contains(aSpec, PR_TRUE, &containedIn); + + nsCAutoString nativePathString; + + if (containedIn){ + rv = aSpec->GetNativePath(nativePathString); + if (NS_FAILED(rv)) + return rv; + + const char* relativeLocation = nativePathString.get() + mComponentsOffset + 1; + return MakeRegistryName(relativeLocation, XPCOM_RELCOMPONENT_PREFIX, aRegistryName); + } + + // Next check to see if this component is in the GRE + // components directory + + mGREComponentsDir->Contains(aSpec, PR_TRUE, &containedIn); + + if (containedIn){ + rv = aSpec->GetNativePath(nativePathString); + if (NS_FAILED(rv)) + return rv; + + const char* relativeLocation = nativePathString.get() + mGREComponentsOffset + 1; + return MakeRegistryName(relativeLocation, XPCOM_GRECOMPONENT_PREFIX, aRegistryName); + } + + /* absolute names include volume info on Mac, so persistent descriptor */ + rv = aSpec->GetNativePath(nativePathString); + if (NS_FAILED(rv)) + return rv; + return MakeRegistryName(nativePathString.get(), XPCOM_ABSCOMPONENT_PREFIX, aRegistryName); +} + +nsresult +nsComponentManagerImpl::SpecForRegistryLocation(const char *aLocation, + nsIFile **aSpec) +{ + // i18n: assuming aLocation is encoded for the current locale + + nsresult rv; + if (!aLocation || !aSpec) + return NS_ERROR_NULL_POINTER; + + /* abs:/full/path/to/libcomponent.so */ + if (!strncmp(aLocation, XPCOM_ABSCOMPONENT_PREFIX, 4)) { + + nsLocalFile* file = new nsLocalFile; + if (!file) return NS_ERROR_FAILURE; + + rv = file->InitWithNativePath(nsDependentCString((char *)aLocation + 4)); + file->QueryInterface(NS_GET_IID(nsILocalFile), (void**)aSpec); + return rv; + } + + if (!strncmp(aLocation, XPCOM_RELCOMPONENT_PREFIX, 4)) { + + if (!mComponentsDir) + return NS_ERROR_NOT_INITIALIZED; + + nsILocalFile* file = nsnull; + rv = mComponentsDir->Clone((nsIFile**)&file); + + if (NS_FAILED(rv)) return rv; + + rv = file->AppendRelativeNativePath(nsDependentCString(aLocation + 4)); + *aSpec = file; + return rv; + } + + if (!strncmp(aLocation, XPCOM_GRECOMPONENT_PREFIX, 4)) { + + if (!mGREComponentsDir) + return NS_ERROR_NOT_INITIALIZED; + + nsILocalFile* file = nsnull; + rv = mGREComponentsDir->Clone((nsIFile**)&file); + + if (NS_FAILED(rv)) return rv; + + rv = file->AppendRelativeNativePath(nsDependentCString(aLocation + 4)); + *aSpec = file; + return rv; + } + + *aSpec = nsnull; + return NS_ERROR_INVALID_ARG; +} + +/** + * RegisterFactory() + * + * Register a factory to be responsible for creation of implementation of + * classID aClass. Plus creates as association of aClassName and aContractID + * to the classID. If replace is PR_TRUE, we replace any existing registrations + * with this one. + * + * Once registration is complete, we add the class to the factories cache + * that we maintain. The factories cache is the ONLY place where these + * registrations are ever kept. + * + * The other RegisterFunctions create a loader mapping and persistent + * location, but we just slam it into the cache here. And we don't call the + * loader's OnRegister function, either. + */ +nsresult +nsComponentManagerImpl::RegisterFactory(const nsCID &aClass, + const char *aClassName, + const char *aContractID, + nsIFactory *aFactory, + PRBool aReplace) +{ + nsAutoMonitor mon(mMon); +#ifdef PR_LOGGING + if (PR_LOG_TEST(nsComponentManagerLog, PR_LOG_WARNING)) + { + char *buf = aClass.ToString(); + PR_LOG(nsComponentManagerLog, PR_LOG_WARNING, + ("nsComponentManager: RegisterFactory(%s, %s)", buf, + (aContractID ? aContractID : "(null)"))); + if (buf) + PR_Free(buf); + } +#endif + nsFactoryEntry *entry = nsnull; + nsFactoryTableEntry* factoryTableEntry = NS_STATIC_CAST(nsFactoryTableEntry*, + PL_DHashTableOperate(&mFactories, + &aClass, + PL_DHASH_ADD)); + + if (!factoryTableEntry) + return NS_ERROR_OUT_OF_MEMORY; + + + if (PL_DHASH_ENTRY_IS_BUSY(factoryTableEntry)) { + entry = factoryTableEntry->mFactoryEntry; + } + + if (entry && !aReplace) + { + // Already registered + PR_LOG(nsComponentManagerLog, PR_LOG_ERROR, + ("\t\tFactory already registered.")); + return NS_ERROR_FACTORY_EXISTS; + } + + void *mem; + PL_ARENA_ALLOCATE(mem, &mArena, sizeof(nsFactoryEntry)); + if (!mem) + return NS_ERROR_OUT_OF_MEMORY; + + entry = new (mem) nsFactoryEntry(aClass, aFactory, entry); + + if (!entry) + return NS_ERROR_OUT_OF_MEMORY; + + factoryTableEntry->mFactoryEntry = entry; + + // Update the ContractID->CLSID Map + if (aContractID) { + nsresult rv = HashContractID(aContractID, strlen(aContractID), entry); + if (NS_FAILED(rv)) { + PR_LOG(nsComponentManagerLog, PR_LOG_WARNING, + ("\t\tFactory register succeeded. " + "Hashing contractid (%s) FAILED.", aContractID)); + return rv; + } + } + + PR_LOG(nsComponentManagerLog, PR_LOG_WARNING, + ("\t\tFactory register succeeded contractid=%s.", + aContractID ? aContractID : "")); + + return NS_OK; +} + +nsresult +nsComponentManagerImpl::RegisterComponent(const nsCID &aClass, + const char *aClassName, + const char *aContractID, + const char *aPersistentDescriptor, + PRBool aReplace, + PRBool aPersist) +{ + return RegisterComponentCommon(aClass, aClassName, + aContractID, + aContractID ? strlen(aContractID) : 0, + aPersistentDescriptor, + aPersistentDescriptor ? + strlen(aPersistentDescriptor) : 0, + aReplace, aPersist, + nativeComponentType); +} + +nsresult +nsComponentManagerImpl::RegisterComponentWithType(const nsCID &aClass, + const char *aClassName, + const char *aContractID, + nsIFile *aSpec, + const char *aLocation, + PRBool aReplace, + PRBool aPersist, + const char *aType) +{ + return RegisterComponentCommon(aClass, aClassName, + aContractID, + aContractID ? strlen(aContractID) : 0, + aLocation, + aLocation ? strlen(aLocation) : 0, + aReplace, aPersist, + aType); +} + +/* + * Register a component, using whatever they stuck in the nsIFile. + */ +nsresult +nsComponentManagerImpl::RegisterComponentSpec(const nsCID &aClass, + const char *aClassName, + const char *aContractID, + nsIFile *aLibrarySpec, + PRBool aReplace, + PRBool aPersist) +{ + nsXPIDLCString registryName; + nsresult rv = RegistryLocationForSpec(aLibrarySpec, getter_Copies(registryName)); + if (NS_FAILED(rv)) + return rv; + + rv = RegisterComponentWithType(aClass, aClassName, + aContractID, + aLibrarySpec, + registryName, + aReplace, aPersist, + nativeComponentType); + return rv; +} + +nsresult +nsComponentManagerImpl::RegisterComponentLib(const nsCID &aClass, + const char *aClassName, + const char *aContractID, + const char *aDllName, + PRBool aReplace, + PRBool aPersist) +{ + // deprecated and obsolete. + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* + * Add a component to the known universe of components. + + * Once we enter this function, we own aRegistryName, and must free it + * or hand it to nsFactoryEntry. Common exit point ``out'' helps keep us + * sane. + */ + +nsresult +nsComponentManagerImpl::RegisterComponentCommon(const nsCID &aClass, + const char *aClassName, + const char *aContractID, + PRUint32 aContractIDLen, + const char *aRegistryName, + PRUint32 aRegistryNameLen, + PRBool aReplace, + PRBool aPersist, + const char *aType) +{ + nsIDKey key(aClass); + nsAutoMonitor mon(mMon); + + nsFactoryEntry *entry = GetFactoryEntry(aClass); + + // Normalize proid and classname + const char *contractID = (aContractID && *aContractID) ? aContractID : nsnull; + const char *className = (aClassName && *aClassName) ? aClassName : nsnull; +#ifdef PR_LOGGING + if (PR_LOG_TEST(nsComponentManagerLog, PR_LOG_WARNING)) + { + char *buf = aClass.ToString(); + PR_LOG(nsComponentManagerLog, PR_LOG_WARNING, + ("nsComponentManager: RegisterComponentCommon(%s, %s, %s, %s)", + buf, + contractID ? contractID : "(null)", + aRegistryName, aType)); + if (buf) + PR_Free(buf); + } +#endif + if (entry && !aReplace) { + PR_LOG(nsComponentManagerLog, PR_LOG_ERROR, + ("\t\tFactory already registered.")); + return NS_ERROR_FACTORY_EXISTS; + } + + int typeIndex = GetLoaderType(aType); + + nsCOMPtr loader; + nsresult rv = GetLoaderForType(typeIndex, getter_AddRefs(loader)); + if (NS_FAILED(rv)) { + PR_LOG(nsComponentManagerLog, PR_LOG_ERROR, + ("\t\tgetting loader for %s FAILED\n", aType)); + return rv; + } + + if (entry) { + entry->ReInit(aClass, aRegistryName, typeIndex); + } + else { + + // Arena allocate the nsFactoryEntry + void *mem; + PL_ARENA_ALLOCATE(mem, &mArena, sizeof(nsFactoryEntry)); + if (!mem) + return NS_ERROR_OUT_OF_MEMORY; + + mRegistryDirty = PR_TRUE; + entry = new (mem) nsFactoryEntry(aClass, + aRegistryName, aRegistryNameLen, + typeIndex); + if (!entry) + return NS_ERROR_OUT_OF_MEMORY; + + nsFactoryTableEntry* factoryTableEntry = + NS_STATIC_CAST(nsFactoryTableEntry*, + PL_DHashTableOperate(&mFactories, &aClass, + PL_DHASH_ADD)); + + if (!factoryTableEntry) + return NS_ERROR_OUT_OF_MEMORY; + + factoryTableEntry->mFactoryEntry = entry; + } + + // Update the ContractID->CLSID Map + if (contractID) { + rv = HashContractID(contractID, aContractIDLen, entry); + if (NS_FAILED(rv)) { + PR_LOG(nsComponentManagerLog, PR_LOG_ERROR, + ("\t\tHashContractID(%s) FAILED\n", contractID)); + return rv; + } + } + return rv; +} + + +nsresult +nsComponentManagerImpl::GetLoaderForType(int aType, + nsIComponentLoader **aLoader) +{ + nsresult rv; + + // Make sure we have a valid type + if (aType < 0 || aType >= mNLoaderData) + return NS_ERROR_INVALID_ARG; + + *aLoader = mLoaderData[aType].loader; + if (*aLoader) { + NS_ADDREF(*aLoader); + return NS_OK; + } + + nsCOMPtr loader; + loader = do_GetServiceFromCategory("component-loader", mLoaderData[aType].type, &rv); + if (NS_FAILED(rv)) + return rv; + + rv = loader->Init(this, nsnull); + + if (NS_SUCCEEDED(rv)) { + mLoaderData[aType].loader = loader; + NS_ADDREF(mLoaderData[aType].loader); + *aLoader = loader; + NS_ADDREF(*aLoader); + } + return rv; +} + + + +// Convert a loader type string into an index into the component data +// array. Empty loader types are converted to NATIVE. Returns -1 if +// loader type cannot be determined. +int +nsComponentManagerImpl::GetLoaderType(const char *typeStr) +{ + if (!typeStr || !*typeStr) { + // Empty type strings are NATIVE + return NS_COMPONENT_TYPE_NATIVE; + } + + for (int i=NS_COMPONENT_TYPE_NATIVE; i= 0) { + *aTypeIndex = typeIndex; + return NS_OK; + } + + // Add the loader type + if (mNLoaderData >= mMaxNLoaderData) { + NS_ASSERTION(mNLoaderData == mMaxNLoaderData, + "Memory corruption. nsComponentManagerImpl::mLoaderData array overrun."); + // Need to increase our loader array + nsLoaderdata *new_mLoaderData = (nsLoaderdata *) PR_Realloc(mLoaderData, (mMaxNLoaderData + NS_LOADER_DATA_ALLOC_STEP) * sizeof(nsLoaderdata)); + if (!new_mLoaderData) + return NS_ERROR_OUT_OF_MEMORY; + mLoaderData = new_mLoaderData; + mMaxNLoaderData += NS_LOADER_DATA_ALLOC_STEP; + } + + typeIndex = mNLoaderData; + mLoaderData[typeIndex].type = PL_strdup(typeStr); + if (!mLoaderData[typeIndex].type) { + // mmh! no memory. return failure. + return NS_ERROR_OUT_OF_MEMORY; + } + mLoaderData[typeIndex].loader = nsnull; + mNLoaderData++; + + *aTypeIndex = typeIndex; + return NS_OK; +} + +typedef struct +{ + const nsCID* cid; + const char* regName; + nsIFactory* factory; +} UnregisterConditions; + +static PLDHashOperator PR_CALLBACK +DeleteFoundCIDs(PLDHashTable *aTable, + PLDHashEntryHdr *aHdr, + PRUint32 aNumber, + void *aData) +{ + nsContractIDTableEntry* entry = NS_STATIC_CAST(nsContractIDTableEntry*, aHdr); + + if (!entry->mFactoryEntry) + return PL_DHASH_NEXT; + + UnregisterConditions* data = (UnregisterConditions*)aData; + + nsFactoryEntry* factoryEntry = entry->mFactoryEntry; + if (data->cid->Equals(factoryEntry->mCid) && + ((data->regName && !PL_strcasecmp(factoryEntry->mLocation, data->regName)) || + (data->factory && data->factory == factoryEntry->mFactory.get()))) + return PL_DHASH_REMOVE; + + return PL_DHASH_NEXT; +} + +void +nsComponentManagerImpl::DeleteContractIDEntriesByCID(const nsCID* aClass, const char*registryName) +{ + UnregisterConditions aData; + aData.cid = aClass; + aData.regName = registryName; + aData.factory = nsnull; + PL_DHashTableEnumerate(&mContractIDs, DeleteFoundCIDs, (void*)&aData); + +} + +void +nsComponentManagerImpl::DeleteContractIDEntriesByCID(const nsCID* aClass, nsIFactory* factory) +{ + UnregisterConditions aData; + aData.cid = aClass; + aData.regName = nsnull; + aData.factory = factory; + PL_DHashTableEnumerate(&mContractIDs, DeleteFoundCIDs, (void*)&aData); +} + +nsresult +nsComponentManagerImpl::UnregisterFactory(const nsCID &aClass, + nsIFactory *aFactory) +{ +#ifdef PR_LOGGING + if (PR_LOG_TEST(nsComponentManagerLog, PR_LOG_WARNING)) + { + char *buf = aClass.ToString(); + PR_LOG(nsComponentManagerLog, PR_LOG_WARNING, + ("nsComponentManager: UnregisterFactory(%s)", buf)); + if (buf) + PR_Free(buf); + } +#endif + nsFactoryEntry *old; + + // first delete all contract id entries that are registered with this cid. + DeleteContractIDEntriesByCID(&aClass, aFactory); + + // next check to see if there is a CID registered + nsresult rv = NS_ERROR_FACTORY_NOT_REGISTERED; + old = GetFactoryEntry(aClass); + + if (old && (old->mFactory.get() == aFactory)) + { + nsAutoMonitor mon(mMon); + PL_DHashTableOperate(&mFactories, &aClass, PL_DHASH_REMOVE); + rv = NS_OK; + } + + PR_LOG(nsComponentManagerLog, PR_LOG_WARNING, + ("\t\tUnregisterFactory() %s", + NS_SUCCEEDED(rv) ? "succeeded" : "FAILED")); + return rv; +} + +nsresult +nsComponentManagerImpl::UnregisterComponent(const nsCID &aClass, + const char *registryName) +{ +#ifdef PR_LOGGING + if (PR_LOG_TEST(nsComponentManagerLog, PR_LOG_WARNING)) + { + char *buf = aClass.ToString(); + PR_LOG(nsComponentManagerLog, PR_LOG_WARNING, + ("nsComponentManager: UnregisterComponent(%s)", buf)); + if (buf) + PR_Free(buf); + } +#endif + + NS_ENSURE_ARG_POINTER(registryName); + nsFactoryEntry *old; + + // first delete all contract id entries that are registered with this cid. + DeleteContractIDEntriesByCID(&aClass, registryName); + + // next check to see if there is a CID registered + old = GetFactoryEntry(aClass); + if (old && old->mLocation && !PL_strcasecmp(old->mLocation, registryName)) + { + nsAutoMonitor mon(mMon); + PL_DHashTableOperate(&mFactories, &aClass, PL_DHASH_REMOVE); + } + + PR_LOG(nsComponentManagerLog, PR_LOG_WARNING, + ("nsComponentManager: Factory unregister(%s) succeeded.", registryName)); + + return NS_OK; +} + +nsresult +nsComponentManagerImpl::UnregisterComponentSpec(const nsCID &aClass, + nsIFile *aLibrarySpec) +{ + nsXPIDLCString registryName; + nsresult rv = RegistryLocationForSpec(aLibrarySpec, getter_Copies(registryName)); + if (NS_FAILED(rv)) return rv; + return UnregisterComponent(aClass, registryName); +} + +// XXX Need to pass in aWhen and servicemanager +nsresult +nsComponentManagerImpl::FreeLibraries(void) +{ + return UnloadLibraries(NS_STATIC_CAST(nsIServiceManager*, this), NS_Timer); // XXX when +} + +// Private implementation of unloading libraries +nsresult +nsComponentManagerImpl::UnloadLibraries(nsIServiceManager *serviceMgr, PRInt32 aWhen) +{ + nsresult rv = NS_OK; + + nsAutoMonitor mon(mMon); + + PR_LOG(nsComponentManagerLog, PR_LOG_WARNING, + ("nsComponentManager: Unloading Libraries.")); + + // UnloadAll the loaders + /* iterate over all known loaders and ask them to autoregister. */ + // Skip mNativeComponentLoader + for (int i=NS_COMPONENT_TYPE_NATIVE + 1; iUnloadAll(aWhen); + if (NS_FAILED(rv)) + break; + } + } + + // UnloadAll the native loader + rv = mNativeComponentLoader->UnloadAll(aWhen); + return rv; +} + +//////////////////////////////////////////////////////////////////////////////// + +/** + * AutoRegister(RegistrationInstant, const char *directory) + * + * Given a directory in the following format, this will ensure proper registration + * of all components. No default directory is looked at. + * + * Directory and fullname are what NSPR will accept. For eg. + * WIN y:/home/dp/mozilla/dist/bin + * UNIX /home/dp/mozilla/dist/bin + * MAC /Hard drive/mozilla/dist/apprunner + * + * This will take care not loading already registered dlls, finding and + * registering new dlls, re-registration of modified dlls + * + */ + +nsresult +nsComponentManagerImpl::AutoRegister(PRInt32 when, nsIFile *inDirSpec) +{ + return AutoRegisterImpl(when, inDirSpec); +} + +nsresult +nsComponentManagerImpl::AutoRegisterImpl(PRInt32 when, + nsIFile *inDirSpec, + PRBool fileIsCompDir) +{ + nsCOMPtr dir; + nsresult rv; + +#ifdef DEBUG + // testing release behaviour + if (getenv("XPCOM_NO_AUTOREG")) + return NS_OK; +#endif + if (inDirSpec) + { + // Use supplied components' directory + dir = inDirSpec; + } + else + { + mComponentsDir->Clone(getter_AddRefs(dir)); + if (!dir) + return NS_ERROR_NOT_INITIALIZED; + } + + nsCOMPtr iim = + dont_AddRef(XPTI_GetInterfaceInfoManager()); + + if (!iim) + return NS_ERROR_UNEXPECTED; + + // Notify observers of xpcom autoregistration start + NS_CreateServicesFromCategory(NS_XPCOM_AUTOREGISTRATION_OBSERVER_ID, + nsnull, + "start"); + + /* do the native loader first, so we can find other loaders */ + rv = mNativeComponentLoader->AutoRegisterComponents((PRInt32)when, dir); + if (NS_FAILED(rv)) return rv; + +#ifdef ENABLE_STATIC_COMPONENT_LOADER + rv = mStaticComponentLoader->AutoRegisterComponents((PRInt32)when, inDirSpec); + if (NS_FAILED(rv)) return rv; +#endif + + /* do InterfaceInfoManager after native loader so it can use components. */ + rv = iim->AutoRegisterInterfaces(); + if (NS_FAILED(rv)) return rv; + + if (!mCategoryManager) { + NS_WARNING("mCategoryManager is null"); + return NS_ERROR_UNEXPECTED; + } + + nsCOMPtr loaderEnum; + rv = mCategoryManager->EnumerateCategory("component-loader", + getter_AddRefs(loaderEnum)); + if (NS_FAILED(rv)) return rv; + + PRBool hasMore; + while (NS_SUCCEEDED(loaderEnum->HasMoreElements(&hasMore)) && hasMore) { + nsCOMPtr supports; + if (NS_FAILED(loaderEnum->GetNext(getter_AddRefs(supports)))) + continue; + + nsCOMPtr supStr = do_QueryInterface(supports); + if (!supStr) + continue; + + nsCAutoString loaderType; + if (NS_FAILED(supStr->GetData(loaderType))) + continue; + + // We depend on the loader being created. Add the loader type and + // create the loader object too. + nsCOMPtr loader; + int typeIndex; + rv = AddLoaderType(loaderType.get(), &typeIndex); + if (NS_FAILED(rv)) + return rv; + GetLoaderForType(typeIndex, getter_AddRefs(loader)); + } + + rv = AutoRegisterNonNativeComponents(dir.get()); + + // Notify observers of xpcom autoregistration completion + NS_CreateServicesFromCategory(NS_XPCOM_AUTOREGISTRATION_OBSERVER_ID, + nsnull, + "end"); + + if (mRegistryDirty) + FlushPersistentStore(PR_TRUE); + return rv; +} + +nsresult +nsComponentManagerImpl::AutoRegisterNonNativeComponents(nsIFile* spec) +{ + nsresult rv = NS_OK; + nsCOMPtr directory = spec; + + if (!directory) { + mComponentsDir->Clone(getter_AddRefs(directory)); + if (!directory) + return NS_ERROR_NOT_INITIALIZED; + } + + for (int i = 1; i < mNLoaderData; i++) { + if (!mLoaderData[i].loader) { + rv = GetLoaderForType(i, &mLoaderData[i].loader); + if (NS_FAILED(rv)) + continue; + } + rv = mLoaderData[i].loader->AutoRegisterComponents(0, directory); + if (NS_FAILED(rv)) + break; + } + + if (NS_SUCCEEDED(rv)) + { + PRBool registered; + do { + registered = PR_FALSE; + for (int i = 0; i < mNLoaderData; i++) { + PRBool b = PR_FALSE; + if (mLoaderData[i].loader) { + rv = mLoaderData[i].loader->RegisterDeferredComponents(0, &b); + if (NS_FAILED(rv)) + continue; + registered |= b; + } + } + } while (NS_SUCCEEDED(rv) && registered); + } + return rv; +} +nsresult +nsComponentManagerImpl::AutoRegisterComponent(PRInt32 when, + nsIFile *component) +{ + nsresult rv = NS_OK, res = NS_ERROR_FACTORY_NOT_REGISTERED; + /* + * Do we have to give the native loader first crack at it? + * I vote ``no''. + */ + for (int i = 0; i < mNLoaderData; i++) { + PRBool didRegister; + if (!mLoaderData[i].loader) { + nsCOMPtr loader; + rv = GetLoaderForType(i, getter_AddRefs(loader)); + if (NS_FAILED(rv)) + continue; + // |GetLoaderForType| has filled in |mLoaderData[i].loader|: + NS_ASSERTION(loader == mLoaderData[i].loader, "oops"); + } + rv = mLoaderData[i].loader->AutoRegisterComponent((int)when, component, &didRegister); + if (NS_FAILED(rv)) { + res = rv; + } else if (didRegister) { + return rv; + } + } + return res; +} + +nsresult +nsComponentManagerImpl::AutoUnregisterComponent(PRInt32 when, + nsIFile *component) +{ + nsresult rv = NS_OK; + for (int i = 0; i < mNLoaderData; i++) { + PRBool didUnRegister; + if (!mLoaderData[i].loader) { + rv = GetLoaderForType(i, &mLoaderData[i].loader); + if (NS_FAILED(rv)) + continue; + } + rv = mLoaderData[i].loader->AutoUnregisterComponent(when, component, &didUnRegister); + if (NS_SUCCEEDED(rv) && didUnRegister) { + // we need to remove this file from our list of known libraries. + RemoveFileInfo(component, nsnull); + mRegistryDirty = PR_TRUE; + break; + } + } + return NS_FAILED(rv) ? NS_ERROR_FACTORY_NOT_REGISTERED : NS_OK; +} + +nsresult +nsComponentManagerImpl::IsRegistered(const nsCID &aClass, + PRBool *aRegistered) +{ + if (!aRegistered) + { + NS_ASSERTION(0, "null ptr"); + return NS_ERROR_NULL_POINTER; + } + *aRegistered = (nsnull != GetFactoryEntry(aClass)); + return NS_OK; +} + +nsresult +nsComponentManagerImpl::EnumerateCLSIDs(nsIEnumerator** aEnumerator) +{ + NS_ASSERTION(aEnumerator != nsnull, "null ptr"); + if (!aEnumerator) + { + return NS_ERROR_NULL_POINTER; + } + *aEnumerator = nsnull; + + nsresult rv; + + PLDHashTableEnumeratorImpl *aEnum; + rv = PL_NewDHashTableEnumerator(&mFactories, + ConvertFactoryEntryToCID, + (void*)this, + &aEnum); + if (NS_FAILED(rv)) + return rv; + + *aEnumerator = NS_STATIC_CAST(nsIEnumerator*, aEnum); + return NS_OK; +} + +nsresult +nsComponentManagerImpl::EnumerateContractIDs(nsIEnumerator** aEnumerator) +{ + NS_ASSERTION(aEnumerator != nsnull, "null ptr"); + if (!aEnumerator) + { + return NS_ERROR_NULL_POINTER; + } + + *aEnumerator = nsnull; + + nsresult rv; + PLDHashTableEnumeratorImpl *aEnum; + rv = PL_NewDHashTableEnumerator(&mContractIDs, + ConvertContractIDKeyToString, + (void*)this, + &aEnum); + if (NS_FAILED(rv)) + return rv; + + *aEnumerator = NS_STATIC_CAST(nsIEnumerator*, aEnum); + return NS_OK; +} + +// nsIComponentRegistrar + +NS_IMETHODIMP +nsComponentManagerImpl::AutoRegister(nsIFile *aSpec) +{ + if (aSpec == nsnull) + return AutoRegisterImpl(0, aSpec); + + PRBool directory; + aSpec->IsDirectory(&directory); + + if (directory) + return AutoRegisterImpl(0, aSpec, PR_FALSE); + + return AutoRegisterComponent(0, aSpec); +} + +NS_IMETHODIMP +nsComponentManagerImpl::AutoUnregister(nsIFile *aSpec) +{ + // unregistering a complete directory is not implmeneted yet...FIX + if (aSpec == nsnull) + return NS_ERROR_NOT_IMPLEMENTED; + + PRBool directory; + aSpec->IsDirectory(&directory); + + if (directory) + return NS_ERROR_NOT_IMPLEMENTED; + + return AutoUnregisterComponent(0, aSpec); +} + +NS_IMETHODIMP +nsComponentManagerImpl::RegisterFactory(const nsCID & aClass, + const char *aClassName, + const char *aContractID, + nsIFactory *aFactory) +{ + return RegisterFactory(aClass, + aClassName, + aContractID, + aFactory, + PR_TRUE); +} + +NS_IMETHODIMP +nsComponentManagerImpl::RegisterFactoryLocation(const nsCID & aClass, + const char *aClassName, + const char *aContractID, + nsIFile *aFile, + const char *loaderStr, + const char *aType) +{ + nsXPIDLCString registryName; + + if (!loaderStr) + { + nsresult rv = RegistryLocationForSpec(aFile, getter_Copies(registryName)); + if (NS_FAILED(rv)) + return rv; + } + + nsresult rv; + rv = RegisterComponentWithType(aClass, + aClassName, + aContractID, + aFile, + (loaderStr ? loaderStr : registryName.get()), + PR_TRUE, + PR_TRUE, + (aType ? aType : nativeComponentType)); + return rv; +} + +NS_IMETHODIMP +nsComponentManagerImpl::UnregisterFactoryLocation(const nsCID & aClass, + nsIFile *aFile) +{ + return UnregisterComponentSpec(aClass, aFile); +} + +NS_IMETHODIMP +nsComponentManagerImpl::IsCIDRegistered(const nsCID & aClass, + PRBool *_retval) +{ + return IsRegistered(aClass, _retval); +} + +NS_IMETHODIMP +nsComponentManagerImpl::IsContractIDRegistered(const char *aClass, + PRBool *_retval) +{ + nsFactoryEntry *entry = GetFactoryEntry(aClass, strlen(aClass)); + + if (entry) + *_retval = PR_TRUE; + else + *_retval = PR_FALSE; + return NS_OK; +} + +NS_IMETHODIMP +nsComponentManagerImpl::EnumerateCIDs(nsISimpleEnumerator **aEnumerator) +{ + NS_ASSERTION(aEnumerator != nsnull, "null ptr"); + + if (!aEnumerator) + return NS_ERROR_NULL_POINTER; + + *aEnumerator = nsnull; + + nsresult rv; + PLDHashTableEnumeratorImpl *aEnum; + rv = PL_NewDHashTableEnumerator(&mFactories, + ConvertFactoryEntryToCID, + (void*)this, + &aEnum); + if (NS_FAILED(rv)) + return rv; + + *aEnumerator = NS_STATIC_CAST(nsISimpleEnumerator*, aEnum); + return NS_OK; +} + +NS_IMETHODIMP +nsComponentManagerImpl::EnumerateContractIDs(nsISimpleEnumerator **aEnumerator) +{ + NS_ASSERTION(aEnumerator != nsnull, "null ptr"); + if (!aEnumerator) + return NS_ERROR_NULL_POINTER; + + *aEnumerator = nsnull; + + nsresult rv; + PLDHashTableEnumeratorImpl *aEnum; + rv = PL_NewDHashTableEnumerator(&mContractIDs, + ConvertContractIDKeyToString, + (void*)this, + &aEnum); + if (NS_FAILED(rv)) + return rv; + + *aEnumerator = NS_STATIC_CAST(nsISimpleEnumerator*, aEnum); + return NS_OK; +} + +NS_IMETHODIMP +nsComponentManagerImpl::CIDToContractID(const nsCID & aClass, + char **_retval) +{ + return CLSIDToContractID(aClass, + nsnull, + _retval); +} + +NS_IMETHODIMP +nsComponentManagerImpl::ContractIDToCID(const char *aContractID, + nsCID * *_retval) +{ + *_retval = (nsCID*) nsMemory::Alloc(sizeof(nsCID)); + if (!*_retval) + return NS_ERROR_OUT_OF_MEMORY; + + nsresult rv = ContractIDToClassID(aContractID, *_retval); + if (NS_FAILED(rv)) { + nsMemory::Free(*_retval); + *_retval = nsnull; + } + return rv; +} + +// end nsIComponentRegistrar + + + + +NS_IMETHODIMP +nsComponentManagerImpl::HasFileChanged(nsIFile *file, const char *loaderString, PRInt64 modDate, PRBool *_retval) +{ + *_retval = PR_TRUE; + + nsXPIDLCString registryName; + nsresult rv = RegistryLocationForSpec(file, getter_Copies(registryName)); + if (NS_FAILED(rv)) + return rv; + + nsCStringKey key(registryName); + AutoRegEntry* entry = (AutoRegEntry*)mAutoRegEntries.Get(&key); + if (entry) + *_retval = entry->Modified(&modDate); + else + *_retval = PR_TRUE; + + return NS_OK; +} + +NS_IMETHODIMP +nsComponentManagerImpl::SaveFileInfo(nsIFile *file, const char *loaderString, PRInt64 modDate) +{ + mRegistryDirty = PR_TRUE; + nsXPIDLCString registryName; + nsresult rv = RegistryLocationForSpec(file, getter_Copies(registryName)); + if (NS_FAILED(rv)) + return rv; + + // check to see if exists in the array before adding it so that we don't have dups. + nsCStringKey key(registryName); + AutoRegEntry* entry = (AutoRegEntry*)mAutoRegEntries.Get(&key); + + if (entry) + { + entry->SetDate(&modDate); + return NS_OK; + } + + entry = new AutoRegEntry(registryName, &modDate); + if (!entry) + return NS_ERROR_OUT_OF_MEMORY; + + mAutoRegEntries.Put(&key, entry); + return NS_OK; +} + +NS_IMETHODIMP +nsComponentManagerImpl::RemoveFileInfo(nsIFile *file, const char *loaderString) +{ + mRegistryDirty = PR_TRUE; + nsXPIDLCString registryName; + nsresult rv = RegistryLocationForSpec(file, getter_Copies(registryName)); + if (NS_FAILED(rv)) + return rv; + + nsCStringKey key(registryName); + AutoRegEntry* entry = (AutoRegEntry*)mAutoRegEntries.Remove(&key); + if (entry) + delete entry; + + return NS_OK; +} + +NS_IMETHODIMP +nsComponentManagerImpl::GetOptionalData(nsIFile *file, + const char *loaderString, + char **_retval) +{ + nsXPIDLCString registryName; + nsresult rv = RegistryLocationForSpec(file, getter_Copies(registryName)); + if (NS_FAILED(rv)) + return rv; + + nsCStringKey key(registryName); + AutoRegEntry* entry = (AutoRegEntry*)mAutoRegEntries.Get(&key); + if (!entry) { + return NS_ERROR_NOT_INITIALIZED; + } + const char* opData = entry->GetOptionalData(); + + if (opData) + *_retval = ToNewCString(nsDependentCString(opData)); + else + *_retval = nsnull; + return NS_OK; + } + +NS_IMETHODIMP +nsComponentManagerImpl::SetOptionalData(nsIFile *file, + const char *loaderString, + const char *data) +{ + nsXPIDLCString registryName; + nsresult rv = RegistryLocationForSpec(file, getter_Copies(registryName)); + if (NS_FAILED(rv)) + return rv; + + nsCStringKey key(registryName); + AutoRegEntry* entry = (AutoRegEntry*)mAutoRegEntries.Get(&key); + + if (!entry) { + PRInt64 zero = LL_Zero(); + entry = new AutoRegEntry(registryName, &zero); + if (!entry) + return NS_ERROR_OUT_OF_MEMORY; + + mAutoRegEntries.Put(&key, entry); + } + + entry->SetOptionalData(data); + + return NS_OK; + } + + +NS_IMETHODIMP +nsComponentManagerImpl::FlushPersistentStore(PRBool now) +{ + mRegistryDirty = PR_TRUE; + if (now) + return WritePersistentRegistry(); + + return NS_OK; +} + + +//////////////////////////////////////////////////////////////////////////////// +// Static Access Functions +//////////////////////////////////////////////////////////////////////////////// + +NS_COM nsresult +NS_GetGlobalComponentManager(nsIComponentManager* *result) +{ +#ifdef DEBUG_dougt + // NS_WARNING("DEPRECATED FUNCTION: Use NS_GetComponentManager"); +#endif + nsresult rv = NS_OK; + + if (nsComponentManagerImpl::gComponentManager == nsnull) + { + // XPCOM needs initialization. + rv = NS_InitXPCOM2(nsnull, nsnull, nsnull); + } + + if (NS_SUCCEEDED(rv)) + { + // NO ADDREF since this is never intended to be released. + // See nsComponentManagerObsolete.h for the reason for such + // casting uglyness + *result = (nsIComponentManager*)(void*)(nsIComponentManagerObsolete*) nsComponentManagerImpl::gComponentManager; + } + + return rv; +} + +NS_COM nsresult +NS_GetComponentManager(nsIComponentManager* *result) +{ + if (nsComponentManagerImpl::gComponentManager == nsnull) + { + // XPCOM needs initialization. + nsresult rv = NS_InitXPCOM2(nsnull, nsnull, nsnull); + if (NS_FAILED(rv)) + return rv; + } + + *result = NS_STATIC_CAST(nsIComponentManager*, + nsComponentManagerImpl::gComponentManager); + NS_IF_ADDREF(*result); + return NS_OK; +} + +NS_COM nsresult +NS_GetServiceManager(nsIServiceManager* *result) +{ + nsresult rv = NS_OK; + + if (nsComponentManagerImpl::gComponentManager == nsnull) + { +#ifdef VBOX + // While XPCOM might need initialization, we're not in a position + // to pass the right values to this call. This is actually triggered + // on object destruction, so there is no point in re-initializing, + // and actually the attempt would lead to nested calls to + // xptiInterfaceInfoManager::BuildFileSearchPath, which it detects + // as unsafe in debug builds. Just fail, no real problem. +#ifdef DEBUG + printf("NS_GetServiceManager: no current instance, suppressed XPCOM initialization!\n"); +#endif + rv = NS_ERROR_SERVICE_NOT_AVAILABLE; +#else /* !VBOX */ + // XPCOM needs initialization. + rv = NS_InitXPCOM2(nsnull, nsnull, nsnull); +#endif /* !VBOX */ + } + + if (NS_FAILED(rv)) + return rv; + + *result = NS_STATIC_CAST(nsIServiceManager*, + nsComponentManagerImpl::gComponentManager); + NS_IF_ADDREF(*result); + return NS_OK; +} + + +NS_COM nsresult +NS_GetComponentRegistrar(nsIComponentRegistrar* *result) +{ + nsresult rv = NS_OK; + + if (nsComponentManagerImpl::gComponentManager == nsnull) + { + // XPCOM needs initialization. + rv = NS_InitXPCOM2(nsnull, nsnull, nsnull); + } + + if (NS_FAILED(rv)) + return rv; + + *result = NS_STATIC_CAST(nsIComponentRegistrar*, + nsComponentManagerImpl::gComponentManager); + NS_IF_ADDREF(*result); + return NS_OK; +} + + +// nsIComponentLoaderManager is not frozen, but is defined here +// so that I can use it internally in xpcom. +nsresult +NS_GetComponentLoaderManager(nsIComponentLoaderManager* *result) +{ + nsresult rv = NS_OK; + + if (nsComponentManagerImpl::gComponentManager == NULL) + { + // XPCOM needs initialization. + rv = NS_InitXPCOM2(nsnull, nsnull, nsnull); + } + + if (NS_FAILED(rv)) + return rv; + + *result = NS_STATIC_CAST(nsIComponentLoaderManager*, + nsComponentManagerImpl::gComponentManager); + NS_IF_ADDREF(*result); + return NS_OK; +} diff --git a/src/libs/xpcom18a4/xpcom/components/nsComponentManager.h b/src/libs/xpcom18a4/xpcom/components/nsComponentManager.h new file mode 100644 index 00000000..df128125 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/components/nsComponentManager.h @@ -0,0 +1,339 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +#ifndef nsComponentManager_h__ +#define nsComponentManager_h__ + +#include "nsXPCOM.h" + +#include "nsIComponentLoader.h" +#include "xpcom-private.h" +#include "nsNativeComponentLoader.h" +#include "nsIComponentManager.h" +#include "nsIComponentRegistrar.h" +#include "nsIComponentManagerObsolete.h" +#include "nsIComponentLoaderManager.h" +#include "nsCategoryManager.h" +#include "nsIServiceManager.h" +#include "nsIFactory.h" +#include "nsIInterfaceRequestor.h" +#include "nsIInterfaceRequestorUtils.h" +#include "pldhash.h" +#include "prtime.h" +#include "prmon.h" +#include "nsCOMPtr.h" +#include "nsWeakReference.h" +#include "nsXPIDLString.h" +#include "nsIFile.h" +#include "plarena.h" + +class nsFactoryEntry; +class nsDll; +class nsIServiceManager; + + +// Predefined loader types. Do not change the numbers. +// NATIVE should be 0 as it is being used as the first array index. +#define NS_COMPONENT_TYPE_NATIVE 0 +#define NS_COMPONENT_TYPE_FACTORY_ONLY -1 +// this define means that the factory entry only has a ContractID +// to service mapping and has no cid mapping. +#define NS_COMPONENT_TYPE_SERVICE_ONLY -2 + + +#ifdef DEBUG +#define XPCOM_CHECK_PENDING_CIDS +#endif +//////////////////////////////////////////////////////////////////////////////// + +// Array of Loaders and their type strings +struct nsLoaderdata { + nsIComponentLoader *loader; + const char *type; +}; + +class nsComponentManagerImpl + : public nsIComponentManager, + public nsIServiceManager, + public nsIComponentRegistrar, + public nsSupportsWeakReference, + public nsIInterfaceRequestor, + public nsIComponentLoaderManager, + public nsIServiceManagerObsolete, + public nsIComponentManagerObsolete +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIINTERFACEREQUESTOR + // Since the nsIComponentManagerObsolete and nsIComponentManager share some of the + // same interface function names, we have to manually define the functions here. + // The only function that is in nsIComponentManagerObsolete and is in nsIComponentManager + // is GetClassObjectContractID. + // + // nsIComponentManager function not in nsIComponentManagerObsolete: + NS_IMETHOD GetClassObjectByContractID(const char *aContractID, + const nsIID &aIID, + void **_retval); + + + NS_DECL_NSICOMPONENTMANAGEROBSOLETE + + // Since the nsIComponentManagerObsolete and nsIComponentRegistrar share some of the + // same interface function names, we have to manually define the functions here. + // the only function that is shared is UnregisterFactory + NS_IMETHOD AutoRegister(nsIFile *aSpec); + NS_IMETHOD AutoUnregister(nsIFile *aSpec); + NS_IMETHOD RegisterFactory(const nsCID & aClass, const char *aClassName, const char *aContractID, nsIFactory *aFactory); + // NS_IMETHOD UnregisterFactory(const nsCID & aClass, nsIFactory *aFactory); + NS_IMETHOD RegisterFactoryLocation(const nsCID & aClass, const char *aClassName, const char *aContractID, nsIFile *aFile, const char *loaderStr, const char *aType); + NS_IMETHOD UnregisterFactoryLocation(const nsCID & aClass, nsIFile *aFile); + NS_IMETHOD IsCIDRegistered(const nsCID & aClass, PRBool *_retval); + NS_IMETHOD IsContractIDRegistered(const char *aClass, PRBool *_retval); + NS_IMETHOD EnumerateCIDs(nsISimpleEnumerator **_retval); + NS_IMETHOD EnumerateContractIDs(nsISimpleEnumerator **_retval); + NS_IMETHOD CIDToContractID(const nsCID & aClass, char **_retval); + NS_IMETHOD ContractIDToCID(const char *aContractID, nsCID * *_retval); + + NS_DECL_NSISERVICEMANAGER + NS_DECL_NSISERVICEMANAGEROBSOLETE + NS_DECL_NSICOMPONENTLOADERMANAGER + + // nsComponentManagerImpl methods: + nsComponentManagerImpl(); + + static nsComponentManagerImpl* gComponentManager; + nsresult Init(void); + + nsresult WritePersistentRegistry(); + nsresult ReadPersistentRegistry(); + + nsresult Shutdown(void); + + nsresult FreeServices(); + + nsresult + NS_GetService(const char *aContractID, const nsIID& aIID, PRBool aDontCreate, nsISupports** result); + + nsresult RegisterComponentCommon(const nsCID &aClass, + const char *aClassName, + const char *aContractID, + PRUint32 aContractIDLen, + const char *aRegistryName, + PRUint32 aRegistryNameLen, + PRBool aReplace, PRBool aPersist, + const char *aType); + nsresult GetLoaderForType(int aType, + nsIComponentLoader **aLoader); + nsresult FindFactory(const char *contractID, PRUint32 aContractIDLen, nsIFactory **aFactory) ; + nsresult LoadFactory(nsFactoryEntry *aEntry, nsIFactory **aFactory); + + nsFactoryEntry *GetFactoryEntry(const char *aContractID, + PRUint32 aContractIDLen); + nsFactoryEntry *GetFactoryEntry(const nsCID &aClass); + + nsresult SyncComponentsInDir(PRInt32 when, nsIFile *dirSpec); + nsresult SelfRegisterDll(nsDll *dll); + nsresult SelfUnregisterDll(nsDll *dll); + nsresult HashContractID(const char *acontractID, PRUint32 aContractIDLen, + nsFactoryEntry *fe_ptr); + + void DeleteContractIDEntriesByCID(const nsCID* aClass, const char*registryName); + void DeleteContractIDEntriesByCID(const nsCID* aClass, nsIFactory* factory); + + nsresult UnloadLibraries(nsIServiceManager *servmgr, PRInt32 when); + + // Convert a loader type string into an index into the loader data + // array. Empty loader types are converted to NATIVE. Returns -1 if + // loader type cannot be determined. + int GetLoaderType(const char *typeStr); + + // Add a loader type if not already known. Out the typeIndex + // if the loader type is either added or already there; + // returns NS_OK or an error on failure. + nsresult AddLoaderType(const char *typeStr, int *typeIndex); + + int GetLoaderCount() { return mNLoaderData + 1; } + + // registers only the files in spec's location by loaders other than the + // native loader. This is an optimization method only. + nsresult AutoRegisterNonNativeComponents(nsIFile* spec); + + nsresult AutoRegisterImpl(PRInt32 when, nsIFile *inDirSpec, PRBool fileIsCompDir=PR_TRUE); + nsresult RemoveEntries(nsIFile* file); + + PLDHashTable mFactories; + PLDHashTable mContractIDs; + PRMonitor* mMon; + + nsNativeComponentLoader *mNativeComponentLoader; +#ifdef ENABLE_STATIC_COMPONENT_LOADER + nsIComponentLoader *mStaticComponentLoader; +#endif + nsCOMPtr mComponentsDir; + PRInt32 mComponentsOffset; + + nsCOMPtr mGREComponentsDir; + PRInt32 mGREComponentsOffset; + + nsCOMPtr mRegistryFile; + + // Shutdown + #define NS_SHUTDOWN_NEVERHAPPENED 0 + #define NS_SHUTDOWN_INPROGRESS 1 + #define NS_SHUTDOWN_COMPLETE 2 + PRUint32 mShuttingDown; + + nsLoaderdata *mLoaderData; + int mNLoaderData; + int mMaxNLoaderData; + + PRBool mRegistryDirty; + nsHashtable mAutoRegEntries; + nsCOMPtr mCategoryManager; + + PLArenaPool mArena; + +#ifdef XPCOM_CHECK_PENDING_CIDS + nsresult AddPendingCID(const nsCID &aClass); + void RemovePendingCID(const nsCID &aClass); + + nsVoidArray mPendingCIDs; +#endif + +private: + ~nsComponentManagerImpl(); +}; + + +#define NS_MAX_FILENAME_LEN 1024 + +#define NS_ERROR_IS_DIR NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_XPCOM, 24) + +//////////////////////////////////////////////////////////////////////////////// +/** + * Class: nsFactoryEntry() + * + * There are two types of FactoryEntries. + * + * 1. {CID, dll} mapping. + * Factory is a consequence of the dll. These can be either session + * specific or persistent based on whether we write this + * to the registry or not. + * + * 2. {CID, factory} mapping + * These are strictly session specific and in memory only. + */ + +class nsFactoryEntry { +public: + nsFactoryEntry(const nsCID &aClass, + const char *location, PRUint32 locationlen, int aType, class nsFactoryEntry* parent = nsnull); + nsFactoryEntry(const nsCID &aClass, nsIFactory *aFactory, class nsFactoryEntry* parent = nsnull); + ~nsFactoryEntry(); + + nsresult ReInit(const nsCID &aClass, const char *location, int aType); + + nsresult GetFactory(nsIFactory **aFactory, + nsComponentManagerImpl * mgr) { + if (mFactory) { + *aFactory = mFactory.get(); + NS_ADDREF(*aFactory); + return NS_OK; + } + + if (mTypeIndex < 0) + return NS_ERROR_FAILURE; + + nsresult rv; + nsCOMPtr loader; + rv = mgr->GetLoaderForType(mTypeIndex, getter_AddRefs(loader)); + if(NS_FAILED(rv)) + return rv; + + rv = loader->GetFactory(mCid, mLocation, mgr->mLoaderData[mTypeIndex].type, aFactory); + if (NS_SUCCEEDED(rv)) + mFactory = do_QueryInterface(*aFactory); + return rv; + } + + nsCID mCid; + nsCOMPtr mFactory; + // This is an index into the mLoaderData array that holds the type string and the loader + int mTypeIndex; + nsCOMPtr mServiceObject; + char* mLocation; + class nsFactoryEntry* mParent; +}; + +//////////////////////////////////////////////////////////////////////////////// + +struct nsFactoryTableEntry : public PLDHashEntryHdr { + nsFactoryEntry *mFactoryEntry; +}; + +struct nsContractIDTableEntry : public PLDHashEntryHdr { + char *mContractID; + PRUint32 mContractIDLen; + nsFactoryEntry *mFactoryEntry; +}; + + +class AutoRegEntry +{ +public: + AutoRegEntry(const nsACString& name, PRInt64* modDate); + ~AutoRegEntry(); + + const nsDependentCString GetName() + { return nsDependentCString(mName, mNameLen); } + PRInt64 GetDate() {return mModDate;} + void SetDate(PRInt64 *date) { mModDate = *date;} + PRBool Modified(PRInt64 *date); + + // this is the optional field line in the compreg.dat. + // it must not contain any comma's and it must be null terminated. + char* GetOptionalData() {return mData;}; + void SetOptionalData(const char* data); + +private: + char* mName; + PRUint32 mNameLen; + char* mData; + PRInt64 mModDate; +}; +#endif // nsComponentManager_h__ + diff --git a/src/libs/xpcom18a4/xpcom/components/nsComponentManagerObsolete.cpp b/src/libs/xpcom18a4/xpcom/components/nsComponentManagerObsolete.cpp new file mode 100644 index 00000000..fca77cf7 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/components/nsComponentManagerObsolete.cpp @@ -0,0 +1,271 @@ + +/* ***** 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 XPCOM. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +//////////////////////////////////////////////////////////////////////////////// +// Global Static Component Manager Methods +// (for when you need to link with xpcom) + +#include "nsIComponentManagerObsolete.h" +#include "nsComponentManagerObsolete.h" + + +nsresult +nsComponentManager::Initialize(void) +{ + return NS_OK; +} + +nsresult +nsComponentManager::FindFactory(const nsCID &aClass, + nsIFactory **aFactory) +{ + nsIComponentManagerObsolete* cm; + nsresult rv = NS_GetGlobalComponentManager((nsIComponentManager**)&cm); + if (NS_FAILED(rv)) return rv; + return cm->FindFactory(aClass, aFactory); +} + +nsresult +nsComponentManager::GetClassObject(const nsCID &aClass, const nsIID &aIID, + void **aResult) +{ + nsIComponentManagerObsolete* cm; + nsresult rv = NS_GetGlobalComponentManager((nsIComponentManager**)&cm); + if (NS_FAILED(rv)) return rv; + return cm->GetClassObject(aClass, aIID, aResult); +} + +nsresult +nsComponentManager::ContractIDToClassID(const char *aContractID, + nsCID *aClass) +{ + nsIComponentManagerObsolete* cm; + nsresult rv = NS_GetGlobalComponentManager((nsIComponentManager**)&cm); + if (NS_FAILED(rv)) return rv; + return cm->ContractIDToClassID(aContractID, aClass); +} + +nsresult +nsComponentManager::CLSIDToContractID(nsCID *aClass, + char* *aClassName, + char* *aContractID) +{ + nsIComponentManagerObsolete* cm; + nsresult rv = NS_GetGlobalComponentManager((nsIComponentManager**)&cm); + if (NS_FAILED(rv)) return rv; + return cm->CLSIDToContractID(*aClass, aClassName, aContractID); +} + +nsresult +nsComponentManager::CreateInstance(const nsCID &aClass, + nsISupports *aDelegate, + const nsIID &aIID, + void **aResult) +{ + nsIComponentManagerObsolete* cm; + nsresult rv = NS_GetGlobalComponentManager((nsIComponentManager**)&cm); + if (NS_FAILED(rv)) return rv; + return cm->CreateInstance(aClass, aDelegate, aIID, aResult); +} + +nsresult +nsComponentManager::CreateInstance(const char *aContractID, + nsISupports *aDelegate, + const nsIID &aIID, + void **aResult) +{ + nsIComponentManagerObsolete* cm; + nsresult rv = NS_GetGlobalComponentManager((nsIComponentManager**)&cm); + if (NS_FAILED(rv)) return rv; + return cm->CreateInstanceByContractID(aContractID, aDelegate, aIID, aResult); +} + +nsresult +nsComponentManager::RegisterFactory(const nsCID &aClass, + const char *aClassName, + const char *aContractID, + nsIFactory *aFactory, + PRBool aReplace) +{ + nsIComponentManagerObsolete* cm; + nsresult rv = NS_GetGlobalComponentManager((nsIComponentManager**)&cm); + if (NS_FAILED(rv)) return rv; + return cm->RegisterFactory(aClass, aClassName, aContractID, + aFactory, aReplace); +} + +nsresult +nsComponentManager::RegisterComponent(const nsCID &aClass, + const char *aClassName, + const char *aContractID, + const char *aLibraryPersistentDescriptor, + PRBool aReplace, + PRBool aPersist) +{ + nsIComponentManagerObsolete* cm; + nsresult rv = NS_GetGlobalComponentManager((nsIComponentManager**)&cm); + if (NS_FAILED(rv)) return rv; + return cm->RegisterComponent(aClass, aClassName, aContractID, + aLibraryPersistentDescriptor, aReplace, aPersist); +} + +nsresult +nsComponentManager::RegisterComponentSpec(const nsCID &aClass, + const char *aClassName, + const char *aContractID, + nsIFile *aLibrary, + PRBool aReplace, + PRBool aPersist) +{ + nsIComponentManagerObsolete* cm; + nsresult rv = NS_GetGlobalComponentManager((nsIComponentManager**)&cm); + if (NS_FAILED(rv)) return rv; + return cm->RegisterComponentSpec(aClass, aClassName, aContractID, + aLibrary, aReplace, aPersist); +} + +nsresult +nsComponentManager::RegisterComponentLib(const nsCID &aClass, + const char *aClassName, + const char *aContractID, + const char *adllName, + PRBool aReplace, + PRBool aPersist) +{ + nsIComponentManagerObsolete* cm; + nsresult rv = NS_GetGlobalComponentManager((nsIComponentManager**)&cm); + if (NS_FAILED(rv)) return rv; + return cm->RegisterComponentLib(aClass, aClassName, aContractID, + adllName, aReplace, aPersist); +} + +nsresult +nsComponentManager::UnregisterFactory(const nsCID &aClass, + nsIFactory *aFactory) +{ + nsIComponentManagerObsolete* cm; + nsresult rv = NS_GetGlobalComponentManager((nsIComponentManager**)&cm); + if (NS_FAILED(rv)) return rv; + return cm->UnregisterFactory(aClass, aFactory); +} + +nsresult +nsComponentManager::UnregisterComponent(const nsCID &aClass, + const char *aLibrary) +{ + nsIComponentManagerObsolete* cm; + nsresult rv = NS_GetGlobalComponentManager((nsIComponentManager**)&cm); + if (NS_FAILED(rv)) return rv; + return cm->UnregisterComponent(aClass, aLibrary); +} + +nsresult +nsComponentManager::UnregisterComponentSpec(const nsCID &aClass, + nsIFile *aLibrarySpec) +{ + nsIComponentManagerObsolete* cm; + nsresult rv = NS_GetGlobalComponentManager((nsIComponentManager**)&cm); + if (NS_FAILED(rv)) return rv; + return cm->UnregisterComponentSpec(aClass, aLibrarySpec); +} + +nsresult +nsComponentManager::FreeLibraries(void) +{ + nsIComponentManagerObsolete* cm; + nsresult rv = NS_GetGlobalComponentManager((nsIComponentManager**)&cm); + if (NS_FAILED(rv)) return rv; + return cm->FreeLibraries(); +} + +nsresult +nsComponentManager::AutoRegister(PRInt32 when, nsIFile *directory) +{ + nsIComponentManagerObsolete* cm; + nsresult rv = NS_GetGlobalComponentManager((nsIComponentManager**)&cm); + if (NS_FAILED(rv)) return rv; + return cm->AutoRegister(when, directory); +} + +nsresult +nsComponentManager::AutoRegisterComponent(PRInt32 when, + nsIFile *fullname) +{ + nsIComponentManagerObsolete* cm; + nsresult rv = NS_GetGlobalComponentManager((nsIComponentManager**)&cm); + if (NS_FAILED(rv)) return rv; + return cm->AutoRegisterComponent(when, fullname); +} + +nsresult +nsComponentManager::AutoUnregisterComponent(PRInt32 when, + nsIFile *fullname) +{ + nsIComponentManagerObsolete* cm; + nsresult rv = NS_GetGlobalComponentManager((nsIComponentManager**)&cm); + if (NS_FAILED(rv)) return rv; + return cm->AutoUnregisterComponent(when, fullname); +} + +nsresult +nsComponentManager::IsRegistered(const nsCID &aClass, + PRBool *aRegistered) +{ + nsIComponentManagerObsolete* cm; + nsresult rv = NS_GetGlobalComponentManager((nsIComponentManager**)&cm); + if (NS_FAILED(rv)) return rv; + return cm->IsRegistered(aClass, aRegistered); +} + +nsresult +nsComponentManager::EnumerateCLSIDs(nsIEnumerator** aEnumerator) +{ + nsIComponentManagerObsolete* cm; + nsresult rv = NS_GetGlobalComponentManager((nsIComponentManager**)&cm); + if (NS_FAILED(rv)) return rv; + return cm->EnumerateCLSIDs(aEnumerator); +} + +nsresult +nsComponentManager::EnumerateContractIDs(nsIEnumerator** aEnumerator) +{ + nsIComponentManagerObsolete* cm; + nsresult rv = NS_GetGlobalComponentManager((nsIComponentManager**)&cm); + if (NS_FAILED(rv)) return rv; + return cm->EnumerateContractIDs(aEnumerator); +} + diff --git a/src/libs/xpcom18a4/xpcom/components/nsComponentManagerObsolete.h b/src/libs/xpcom18a4/xpcom/components/nsComponentManagerObsolete.h new file mode 100644 index 00000000..dfcde87a --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/components/nsComponentManagerObsolete.h @@ -0,0 +1,185 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 XPCOM. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ +#ifndef nsComponentManagerObsolete_h___ +#define nsComponentManagerObsolete_h___ + +#include "nsIComponentManager.h" +#include "nsIComponentManagerObsolete.h" + +class nsIEnumerator; +class nsIFactory; +class nsIFile; +//////////////////////////////////////////////////////////////////// +// +// WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING +// +// Functions, classes, interfaces and types in this file are +// obsolete. Use at your own risk. +// Please see nsIComponentManager.idl for the supported interface +// to the component manager. +// +//////////////////////////////////////////////////////////////////// + + + +//////////////////////////////////////////////////////////////////// +// God save me from this evilness. Below is a very bad +// function. Its out var is really a nsIComponentManagerObsolete +// but it has been cast to a nsIComponentManager. +// The reason for such uglyness is that this function is require for +// backward compatiblity of some plugins. This funciton will +// be removed at some point. +//////////////////////////////////////////////////////////////////// + +extern NS_COM nsresult +NS_GetGlobalComponentManager(nsIComponentManager* *result); + + + + +class NS_COM nsComponentManager { +public: + static nsresult Initialize(void); + + // Finds a factory for a specific class ID + static nsresult FindFactory(const nsCID &aClass, + nsIFactory **aFactory); + + // Get the singleton class object that implements the CID aClass + static nsresult GetClassObject(const nsCID &aClass, const nsIID &aIID, + void **aResult); + + // Finds a class ID for a specific Program ID + static nsresult ContractIDToClassID(const char *aContractID, + nsCID *aClass); + + // Finds a Program ID for a specific class ID + // caller frees the result with delete[] + static nsresult CLSIDToContractID(nsCID *aClass, + char* *aClassName, + char* *aContractID); + + // Creates a class instance for a specific class ID + static nsresult CreateInstance(const nsCID &aClass, + nsISupports *aDelegate, + const nsIID &aIID, + void **aResult); + + // Convenience routine, creates a class instance for a specific ContractID + static nsresult CreateInstance(const char *aContractID, + nsISupports *aDelegate, + const nsIID &aIID, + void **aResult); + + // Manually registry a factory for a class + static nsresult RegisterFactory(const nsCID &aClass, + const char *aClassName, + const char *aContractID, + nsIFactory *aFactory, + PRBool aReplace); + + // Manually register a dynamically loaded component. + // The libraryPersistentDescriptor is what gets passed to the library + // self register function from ComponentManager. The format of this string + // is the same as nsIFile::GetPath() + // + // This function will go away in favour of RegisterComponentSpec. In fact, + // it internally turns around and calls RegisterComponentSpec. + static nsresult RegisterComponent(const nsCID &aClass, + const char *aClassName, + const char *aContractID, + const char *aLibraryPersistentDescriptor, + PRBool aReplace, + PRBool aPersist); + + // Register a component using its FileSpec as its identification + // This is the more prevalent use. + static nsresult RegisterComponentSpec(const nsCID &aClass, + const char *aClassName, + const char *aContractID, + nsIFile *aLibrary, + PRBool aReplace, + PRBool aPersist); + + // Register a component using its dllName. This could be a dll name with + // no path so that LD_LIBRARY_PATH on unix or PATH on win can load it. Or + // this could be a code fragment name on the Mac. + static nsresult RegisterComponentLib(const nsCID &aClass, + const char *aClassName, + const char *aContractID, + const char *adllName, + PRBool aReplace, + PRBool aPersist); + + + // Manually unregister a factory for a class + static nsresult UnregisterFactory(const nsCID &aClass, + nsIFactory *aFactory); + + // Manually unregister a dynamically loaded component + static nsresult UnregisterComponent(const nsCID &aClass, + const char *aLibrary); + + // Manually unregister a dynamically loaded component + static nsresult UnregisterComponentSpec(const nsCID &aClass, + nsIFile *aLibrarySpec); + + // Unload dynamically loaded factories that are not in use + static nsresult FreeLibraries(void); + ////////////////////////////////////////////////////////////////////////////// + // DLL registration support + + // If directory is NULL, then AutoRegister will try registering components + // in the default components directory. + static nsresult AutoRegister(PRInt32 when, nsIFile* directory); + static nsresult AutoRegisterComponent(PRInt32 when, nsIFile *component); + static nsresult AutoUnregisterComponent(PRInt32 when, nsIFile *component); + + // Is the given CID currently registered? + static nsresult IsRegistered(const nsCID &aClass, + PRBool *aRegistered); + + // Get an enumeration of all the CIDs + static nsresult EnumerateCLSIDs(nsIEnumerator** aEmumerator); + + // Get an enumeration of all the ContractIDs + static nsresult EnumerateContractIDs(nsIEnumerator** aEmumerator); + +}; + + +#endif diff --git a/src/libs/xpcom18a4/xpcom/components/nsComponentManagerUtils.h b/src/libs/xpcom18a4/xpcom/components/nsComponentManagerUtils.h new file mode 100644 index 00000000..cda56416 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/components/nsComponentManagerUtils.h @@ -0,0 +1,196 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org Code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +#ifndef nsComponentManagerUtils_h__ +#define nsComponentManagerUtils_h__ + +/* + * Do not include this file directly. Instead, + * |#include "nsIComponentManager.h"|. + */ + +#ifndef nsCOMPtr_h__ +#include "nsCOMPtr.h" +#endif + +#ifndef nsComponentManagerObsolete_h___ +#include "nsComponentManagerObsolete.h" +#endif + +#define NS_COMPONENTMANAGER_CID \ +{ /* 91775d60-d5dc-11d2-92fb-00e09805570f */ \ + 0x91775d60, \ + 0xd5dc, \ + 0x11d2, \ + {0x92, 0xfb, 0x00, 0xe0, 0x98, 0x05, 0x57, 0x0f} \ +} + +class NS_COM nsCreateInstanceByCID : public nsCOMPtr_helper +{ +public: + nsCreateInstanceByCID( const nsCID& aCID, nsISupports* aOuter, nsresult* aErrorPtr ) + : mCID(aCID), + mOuter(aOuter), + mErrorPtr(aErrorPtr) + { + // nothing else to do here + } + + virtual nsresult NS_FASTCALL operator()( const nsIID&, void** ) const; + +private: + const nsCID& mCID; + nsISupports* mOuter; + nsresult* mErrorPtr; +}; + +class NS_COM nsCreateInstanceByContractID : public nsCOMPtr_helper +{ +public: + nsCreateInstanceByContractID( const char* aContractID, nsISupports* aOuter, nsresult* aErrorPtr ) + : mContractID(aContractID), + mOuter(aOuter), + mErrorPtr(aErrorPtr) + { + // nothing else to do here + } + + virtual nsresult NS_FASTCALL operator()( const nsIID&, void** ) const; + +private: + const char* mContractID; + nsISupports* mOuter; + nsresult* mErrorPtr; +}; + +inline +const nsCreateInstanceByCID +do_CreateInstance( const nsCID& aCID, nsresult* error = 0 ) +{ + return nsCreateInstanceByCID(aCID, 0, error); +} + +inline +const nsCreateInstanceByCID +do_CreateInstance( const nsCID& aCID, nsISupports* aOuter, nsresult* error = 0 ) +{ + return nsCreateInstanceByCID(aCID, aOuter, error); +} + +inline +const nsCreateInstanceByContractID +do_CreateInstance( const char* aContractID, nsresult* error = 0 ) +{ + return nsCreateInstanceByContractID(aContractID, 0, error); +} + +inline +const nsCreateInstanceByContractID +do_CreateInstance( const char* aContractID, nsISupports* aOuter, nsresult* error = 0 ) +{ + return nsCreateInstanceByContractID(aContractID, aOuter, error); +} + +// type-safe shortcuts for calling |CreateInstance| +template +inline +nsresult +CallCreateInstance( const nsCID &aClass, + nsISupports *aDelegate, + DestinationType** aDestination ) +{ + NS_PRECONDITION(aDestination, "null parameter"); + + return nsComponentManager::CreateInstance(aClass, aDelegate, + NS_GET_IID(DestinationType), + NS_REINTERPRET_CAST(void**, aDestination)); +} + +template +inline +nsresult +CallCreateInstance( const nsCID &aClass, + DestinationType** aDestination ) +{ + NS_PRECONDITION(aDestination, "null parameter"); + + return nsComponentManager::CreateInstance(aClass, nsnull, + NS_GET_IID(DestinationType), + NS_REINTERPRET_CAST(void**, aDestination)); +} + +template +inline +nsresult +CallCreateInstance( const char *aContractID, + nsISupports *aDelegate, + DestinationType** aDestination ) +{ + NS_PRECONDITION(aContractID, "null parameter"); + NS_PRECONDITION(aDestination, "null parameter"); + + return nsComponentManager::CreateInstance(aContractID, + aDelegate, + NS_GET_IID(DestinationType), + NS_REINTERPRET_CAST(void**, aDestination)); +} + +template +inline +nsresult +CallCreateInstance( const char *aContractID, + DestinationType** aDestination ) +{ + NS_PRECONDITION(aContractID, "null parameter"); + NS_PRECONDITION(aDestination, "null parameter"); + + return nsComponentManager::CreateInstance(aContractID, nsnull, + NS_GET_IID(DestinationType), + NS_REINTERPRET_CAST(void**, aDestination)); +} + +/* keys for registry use */ +extern const char xpcomKeyName[]; +extern const char xpcomComponentsKeyName[]; +extern const char lastModValueName[]; +extern const char fileSizeValueName[]; +extern const char nativeComponentType[]; +extern const char staticComponentType[]; + +#endif /* nsComponentManagerUtils_h__ */ + + diff --git a/src/libs/xpcom18a4/xpcom/components/nsICategoryManager.idl b/src/libs/xpcom18a4/xpcom/components/nsICategoryManager.idl new file mode 100644 index 00000000..509f7870 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/components/nsICategoryManager.idl @@ -0,0 +1,101 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsISupports.idl" +#include "nsISimpleEnumerator.idl" + +/* + * nsICategoryManager + * @status FROZEN + */ + +[scriptable, uuid(3275b2cd-af6d-429a-80d7-f0c5120342ac)] +interface nsICategoryManager : nsISupports +{ + /** + * Get the value for the given category's entry. + * @param aCategory The name of the category ("protocol") + * @param aEntry The entry you're looking for ("http") + * @return The value. + */ + string getCategoryEntry(in string aCategory, in string aEntry); + + /** + * Add an entry to a category. + * @param aCategory The name of the category ("protocol") + * @param aEntry The entry to be added ("http") + * @param aValue The value for the entry ("moz.httprulez.1") + * @param aPersist Should this data persist between invocations? + * @param aReplace Should we replace an existing entry? + * @return Previous entry, if any + */ + string addCategoryEntry(in string aCategory, in string aEntry, + in string aValue, in boolean aPersist, + in boolean aReplace); + + /** + * Delete an entry from the category. + * @param aCategory The name of the category ("protocol") + * @param aEntry The entry to be added ("http") + * @param aPersist Delete persistent data from registry, if present? + */ + void deleteCategoryEntry(in string aCategory, in string aEntry, + in boolean aPersist); + + /** + * Delete a category and all entries. + * @param aCategory The category to be deleted. + */ + void deleteCategory(in string aCategory); + + /** + * Enumerate the entries in a category. + * @param aCategory The category to be enumerated. + * @return a simple enumerator, each result QIs to + * nsISupportsCString. + */ + nsISimpleEnumerator enumerateCategory(in string aCategory); + + /** + * Enumerate all existing categories + * @param aCategory The category to be enumerated. + * @return a simple enumerator, each result QIs to + * nsISupportsCString. + */ + nsISimpleEnumerator enumerateCategories(); +}; + diff --git a/src/libs/xpcom18a4/xpcom/components/nsIClassInfo.idl b/src/libs/xpcom18a4/xpcom/components/nsIClassInfo.idl new file mode 100644 index 00000000..e934057c --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/components/nsIClassInfo.idl @@ -0,0 +1,132 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** 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 Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * John Bandhauer + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsISupports.idl" +#include "nsIProgrammingLanguage.idl" + +/** + * Provides information about a specific implementation class + * @status FROZEN + */ + +[scriptable, uuid(986c11d0-f340-11d4-9075-0010a4e73d9a)] +interface nsIClassInfo : nsISupports +{ + /** + * Get an ordered list of the interface ids that instances of the class + * promise to implement. Note that nsISupports is an implicit member + * of any such list and need not be included. + * + * Should set *count = 0 and *array = null and return NS_OK if getting the + * list is not supported. + */ + void getInterfaces(out PRUint32 count, + [array, size_is(count), retval] out nsIIDPtr array); + + /** + * Get a language mapping specific helper object that may assist in using + * objects of this class in a specific lanaguage. For instance, if asked + * for the helper for nsIProgrammingLanguage::JAVASCRIPT this might return + * an object that can be QI'd into the nsIXPCScriptable interface to assist + * XPConnect in supplying JavaScript specific behavior to callers of the + * instance object. + * + * see: nsIProgrammingLanguage.idl + * + * Should return null if no helper available for given language. + */ + nsISupports getHelperForLanguage(in PRUint32 language); + + /** + * A contract ID through which an instance of this class can be created + * (or accessed as a service, if |flags & SINGLETON|), or null. + */ + readonly attribute string contractID; + + /** + * A human readable string naming the class, or null. + */ + readonly attribute string classDescription; + + /** + * A class ID through which an instance of this class can be created + * (or accessed as a service, if |flags & SINGLETON|), or null. + */ + readonly attribute nsCIDPtr classID; + + /** + * Return language type from list in nsIProgrammingLanguage + */ + + readonly attribute PRUint32 implementationLanguage; + + /** + * Bitflags for 'flags' attribute. + */ + const PRUint32 SINGLETON = 1 << 0; + const PRUint32 THREADSAFE = 1 << 1; + const PRUint32 MAIN_THREAD_ONLY = 1 << 2; + const PRUint32 DOM_OBJECT = 1 << 3; + const PRUint32 PLUGIN_OBJECT = 1 << 4; + const PRUint32 EAGER_CLASSINFO = 1 << 5; + /** + * 'flags' attribute bitflag: whether objects of this type implement + * nsIContent. + */ + const PRUint32 CONTENT_NODE = 1 << 6; + + // The high order bit is RESERVED for consumers of these flags. + // No implementor of this interface should ever return flags + // with this bit set. + const PRUint32 RESERVED = 1 << 31; + + + readonly attribute PRUint32 flags; + + /** + * Also a class ID through which an instance of this class can be created + * (or accessed as a service, if |flags & SINGLETON|). If the class does + * not have a CID, it should return NS_ERROR_NOT_AVAILABLE. This attribute + * exists so C++ callers can avoid allocating and freeing a CID, as would + * happen if they used classID. + */ + [notxpcom] readonly attribute nsCID classIDNoAlloc; + +}; diff --git a/src/libs/xpcom18a4/xpcom/components/nsIComponentLoader.idl b/src/libs/xpcom18a4/xpcom/components/nsIComponentLoader.idl new file mode 100644 index 00000000..d1b4be6e --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/components/nsIComponentLoader.idl @@ -0,0 +1,109 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** 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.org Code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsISupports.idl" +#include "nsIFactory.idl" +#include "nsIFile.idl" +#include "nsIComponentManager.idl" + +[object, uuid(c073cfc0-567c-11d3-aec1-0000f8e25c06)] +interface nsIComponentLoader : nsISupports { + + /** + * Get the factory for a given component. + */ + nsIFactory getFactory(in nsIIDRef aCID, in string aLocation, + in string aType); + + /** + * Initialize the loader. + * + * We use nsISupports here because nsIRegistry isn't IDLized yet. + */ + void init(in nsIComponentManager aCompMgr, in nsISupports aRegistry); + + /** + * Called when a component of the appropriate type is registered, + * to give the component loader an opportunity to do things like + * annotate the registry and such. + */ + void onRegister(in nsIIDRef aCID, in string aType, + in string aClassName, in string aContractID, + in string aLocation, in boolean aReplace, + in boolean aPersist); + + /** + * When is AutoRegistration occuring? + */ + const long Startup = 0; + const long Component = 1; + const long Timer = 2; + + /** + * AutoRegister components in the given directory. + */ + void autoRegisterComponents(in long aWhen, in nsIFile aDirectory); + + /** + * AutoRegister the given component. + * + * Returns true if the component was registered, false if it couldn't + * attempt to register the component (wrong type) and ``throws'' an + * NS_FAILED code if there was an error during registration. + */ + boolean autoRegisterComponent(in long aWhen, in nsIFile aComponent); + + /** + * AutoUnregister the given component. + * Returns true if the component was unregistered, false if it coudln't + * attempt to unregister the component (not found, wrong type). + */ + boolean autoUnregisterComponent(in long aWhen, in nsIFile aComponent); + + /** + * Register any deferred (NS_ERROR_FACTORY_REGISTER_AGAIN) components. + * Return registered-any-components? + */ + boolean registerDeferredComponents(in long aWhen); + + /** + * Unload all components that are willing. + */ + void unloadAll(in long aWhen); + +}; diff --git a/src/libs/xpcom18a4/xpcom/components/nsIComponentLoaderManager.idl b/src/libs/xpcom18a4/xpcom/components/nsIComponentLoaderManager.idl new file mode 100644 index 00000000..9f1784d6 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/components/nsIComponentLoaderManager.idl @@ -0,0 +1,72 @@ +/* ***** 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 XPCOM. + * + * The Initial Developer of the Original Code is Netscape Communications. + * Portions created by the Initial Developer are Copyright (C) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * 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 ***** */ + +/** + * The nsIComponentRegistrar interface. + * @status EXPERIMENTAL + * + * USE AT YOUR OWN RISK + * USE AT YOUR OWN RISK + * USE AT YOUR OWN RISK + * USE AT YOUR OWN RISK + * USE AT YOUR OWN RISK + * USE AT YOUR OWN RISK + */ + +#include "nsISupports.idl" + +interface nsIFile; + +[uuid(fce83d37-a3c0-4e09-ad9f-6842a984dbdf)] +interface nsIComponentLoaderManager : nsISupports +{ + boolean hasFileChanged(in nsIFile file, in string loaderString, in PRInt64 modDate); + void saveFileInfo(in nsIFile file, in string loaderString, in PRInt64 modDate); + void removeFileInfo(in nsIFile file, in string loaderString); + void flushPersistentStore(in boolean now); + + string getOptionalData(in nsIFile file, in string loaderString); + void setOptionalData(in nsIFile file, in string loaderString, in string value); +}; + + + + + + + + + + diff --git a/src/libs/xpcom18a4/xpcom/components/nsIComponentManager.idl b/src/libs/xpcom18a4/xpcom/components/nsIComponentManager.idl new file mode 100644 index 00000000..20661803 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/components/nsIComponentManager.idl @@ -0,0 +1,111 @@ +/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/** + * The nsIComponentManager interface. + * @status FROZEN + */ + +#include "nsISupports.idl" + +interface nsIFactory; + +[scriptable, uuid(a88e5a60-205a-4bb1-94e1-2628daf51eae)] +interface nsIComponentManager : nsISupports +{ + /** + * getClassObject + * + * Returns the factory object that can be used to create instances of + * CID aClass + * + * @param aClass The classid of the factory that is being requested + */ + void getClassObject(in nsCIDRef aClass, + in nsIIDRef aIID, + [iid_is(aIID),retval] out nsQIResult result); + + /** + * getClassObjectByContractID + * + * Returns the factory object that can be used to create instances of + * CID aClass + * + * @param aClass The classid of the factory that is being requested + */ + void getClassObjectByContractID(in string aContractID, + in nsIIDRef aIID, + [iid_is(aIID),retval] out nsQIResult result); + + + /** + * createInstance + * + * Create an instance of the CID aClass and return the interface aIID. + * + * @param aClass : ClassID of object instance requested + * @param aDelegate : Used for aggregation + * @param aIID : IID of interface requested + */ + void createInstance(in nsCIDRef aClass, + in nsISupports aDelegate, + in nsIIDRef aIID, + [iid_is(aIID),retval] out nsQIResult result); + + /** + * createInstanceByContractID + * + * Create an instance of the CID that implements aContractID and return the + * interface aIID. + * + * @param aContractID : aContractID of object instance requested + * @param aDelegate : Used for aggregation + * @param aIID : IID of interface requested + */ + void createInstanceByContractID(in string aContractID, + in nsISupports aDelegate, + in nsIIDRef aIID, + [iid_is(aIID),retval] out nsQIResult result); +}; + + +%{ C++ +#ifndef MOZILLA_STRICT_API +#include "nsComponentManagerUtils.h" +#include "nsComponentManagerObsolete.h" +#endif +%} C++ diff --git a/src/libs/xpcom18a4/xpcom/components/nsIComponentManagerObsolete.idl b/src/libs/xpcom18a4/xpcom/components/nsIComponentManagerObsolete.idl new file mode 100644 index 00000000..ac5f7975 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/components/nsIComponentManagerObsolete.idl @@ -0,0 +1,351 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org Code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsISupports.idl" +#include "nsIFactory.idl" + +interface nsIFile; +interface nsIEnumerator; + +[scriptable, uuid(8458a740-d5dc-11d2-92fb-00e09805570f)] +interface nsIComponentManagerObsolete : nsISupports +{ + /** + * findFactory + * + * Returns the factory object that can be used to create instances of + * CID aClass + * + * @param aClass The classid of the factory that is being requested + */ + nsIFactory findFactory(in nsCIDRef aClass); + + /** + * getClassObject + * + * @param aClass : CID of the class whose class object is requested + * @param aIID : IID of an interface that the class object is known to + * to implement. nsISupports and nsIFactory are known to + * be implemented by the class object. + */ + [noscript] voidPtr getClassObject(in nsCIDRef aClass, in nsIIDRef aIID); + + /** + * contractIDToClassID + * + * Get the ClassID for a given ContractID. Many ClassIDs may implement a + * ContractID. In such a situation, this returns the preferred ClassID, which + * happens to be the last registered ClassID. + * + * @param aContractID : Contractid for which ClassID is requested + * @return aClass : ClassID return + */ + [notxpcom] nsresult contractIDToClassID(in string aContractID, out nsCID aClass); + + /** + * classIDToContractid + * + * Get the ContractID for a given ClassID. A ClassIDs may implement multiple + * ContractIDs. This function return the last registered ContractID. + * + * @param aClass : ClassID for which ContractID is requested. + * @return aClassName : returns class name asssociated with aClass + * @return : ContractID last registered for aClass + */ + string CLSIDToContractID(in nsCIDRef aClass, out string aClassName); + + /** + * createInstance + * + * Create an instance of the CID aClass and return the interface aIID. + * + * @param aClass : ClassID of object instance requested + * @param aDelegate : Used for aggregation + * @param aIID : IID of interface requested + */ + [noscript] voidPtr createInstance(in nsCIDRef aClass, + in nsISupports aDelegate, + in nsIIDRef aIID); + + /** + * createInstanceByContractID + * + * Create an instance of the CID that implements aContractID and return the + * interface aIID. This is a convenience function that effectively does + * ContractIDToClassID() followed by CreateInstance(). + * + * @param aContractID : aContractID of object instance requested + * @param aDelegate : Used for aggregation + * @param aIID : IID of interface requested + */ + [noscript] voidPtr createInstanceByContractID(in string aContractID, + in nsISupports aDelegate, + in nsIIDRef IID); + /** + * registryLocationForSpec + * + * Given a file specification, return the registry representation of + * the filename. Files that are found relative to the components + * directory will have a registry representation + * "rel:" while filenames that are not, will have + * "abs:". + */ + string registryLocationForSpec(in nsIFile aSpec); + + /** + * specForRegistyLocation + * + * Create a file specification for the registry representation (rel:/abs:) + * got via registryLocationForSpec. + */ + nsIFile specForRegistryLocation(in string aLocation); + + /** + * registerFactory + * + * Register a factory and ContractID associated with CID aClass + * + * @param aClass : CID of object + * @param aClassName : Class Name of CID + * @param aContractID : ContractID associated with CID aClass + * @param aFactory : Factory that will be registered for CID aClass + * @param aReplace : Boolean that indicates whether to replace a previous + * registration for the CID aClass. + */ + void registerFactory(in nsCIDRef aClass, in string aClassName, + in string aContractID, in nsIFactory aFactory, + in boolean aReplace); + + /** + * registerComponent + * + * Register a native dll module via its registry representation as returned + * by registryLocationForSpec() as the container of CID implemenation + * aClass and associate aContractID and aClassName to the CID aClass. Native + * dll component type is assumed. + * + * @param aClass : CID implemenation contained in module + * @param aClassName : Class name associated with CID aClass + * @param aContractID : ContractID associated with CID aClass + * @param aLocation : Location of module (dll). Format of this is the + * registry representation as returned by + * registryLocationForSpec() + * @param aReplace : Boolean that indicates whether to replace a previous + * module registration for aClass. + * @param aPersist : Remember this registration across sessions. + */ + void registerComponent(in nsCIDRef aClass, in string aClassName, + in string aContractID, in string aLocation, + in boolean aReplace, in boolean aPersist); + + /** + * registerComponentWithType + * + * Register a module's location via its registry representation + * as returned by registryLocationForSpec() as the container of CID implemenation + * aClass of type aType and associate aContractID and aClassName to the CID aClass. + * + * @param aClass : CID implemenation contained in module + * @param aClassName : Class name associated with CID aClass + * @param aContractID : ContractID associated with CID aClass + * @param aSpec : Filename spec for module's location. + * @param aLocation : Location of module of type aType. Format of this string + * is the registry representation as returned by + * registryLocationForSpec() + * @param aReplace : Boolean that indicates whether to replace a previous + * loader registration for aClass. + * @param aPersist : Remember this registration across sessions. + * @param aType : Component Type of CID aClass. + */ + void registerComponentWithType(in nsCIDRef aClass, in string aClassName, + in string aContractID, in nsIFile aSpec, + in string aLocation, in boolean aReplace, + in boolean aPersist, in string aType); + + /** + * registerComponentSpec + * + * Register a native dll module via its file specification as the container + * of CID implemenation aClass and associate aContractID and aClassName to the + * CID aClass. Native dll component type is assumed. + * + * @param aClass : CID implemenation contained in module + * @param aClassName : Class name associated with CID aClass + * @param aContractID : ContractID associated with CID aClass + * @param aLibrary : File specification Location of module (dll). + * @param aReplace : Boolean that indicates whether to replace a previous + * module registration for aClass. + * @param aPersist : Remember this registration across sessions. + */ + void registerComponentSpec(in nsCIDRef aClass, in string aClassName, + in string aContractID, in nsIFile aLibrary, + in boolean aReplace, in boolean aPersist); + + /** + * registerComponentLib + * + * Register a native dll module via its dll name (not full path) as the + * container of CID implemenation aClass and associate aContractID and aClassName + * to the CID aClass. Native dll component type is assumed and the system + * services will be used to load this dll. + * + * @param aClass : CID implemenation contained in module + * @param aClassName : Class name associated with CID aClass + * @param aContractID : ContractID associated with CID aClass + * @param aDllNameLocation : Dll name of module. + * @param aReplace : Boolean that indicates whether to replace a previous + * module registration for aClass. + * @param aPersist : Remember this registration across sessions. + */ + void registerComponentLib(in nsCIDRef aClass, in string aClassName, + in string aContractID, in string aDllName, + in boolean aReplace, in boolean aPersist); + + /** + * unregisterFactory + * + * Unregister a factory associated with CID aClass. + * + * @param aClass : ClassID being unregistered + * @param aFactory : Factory previously registered to create instances of + * ClassID aClass. + */ + void unregisterFactory(in nsCIDRef aClass, in nsIFactory aFactory); + + /** + * unregisterComponent + * + * Disassociate module aLocation represented as registry location as returned + * by registryLocationForSpec() as containing ClassID aClass. + * + * @param aClass : ClassID being unregistered + * @param aLocation : Location of module. Format of this is the registry + * representation as returned by registryLocationForSpec(). + * Components of any type will be unregistered. + */ + void unregisterComponent(in nsCIDRef aClass, in string aLocation); + + /** + * unregisterComponentSpec + * + * Disassociate module references by file specification aLibrarySpec as + * containing ClassID aClass. + */ + void unregisterComponentSpec(in nsCIDRef aClass, in nsIFile aLibrarySpec); + + /** + * freeLibraries + * + * Enumerates all loaded modules and unloads unused modules. + */ + void freeLibraries(); + + /** + * ID values for 'when' + */ + const long NS_Startup = 0; + const long NS_Script = 1; + const long NS_Timer = 2; + const long NS_Shutdown = 3; + + /** + * autoRegister + * + * Enumerates directory looking for modules of all types and registers + * modules who have changed (modtime or size) since the last time + * autoRegister() was invoked. + * + * @param when : ID values of when the call is being made. + * @param directory : Directory the will be enumerated. + */ + void autoRegister(in long when, in nsIFile directory); + + /** + * autoRegisterComponent + * + * Loads module using appropriate loader and gives it an opportunity to + * register its CIDs if module's modtime or size changed since the last + * time this was called. + * + * @param when : ID values of when the call is being made. + * @param aFileLocation : File specification of module. + */ + void autoRegisterComponent(in long when, in nsIFile aFileLocation); + + /** + * autoUnregisterComponent + * + * Loads module using approriate loader and gives it an opportunity to + * unregister its CIDs + */ + void autoUnregisterComponent(in long when, in nsIFile aFileLocation); + + /** + * isRegistered + * + * Returns true if a factory or module is registered for CID aClass. + * + * @param aClass : ClassID queried for registeration + * @return : true if a factory or module is registered for CID aClass. + * false otherwise. + */ + boolean isRegistered(in nsCIDRef aClass); + + /** + * enumerateCLSIDs + * + * Enumerate the list of all registered ClassIDs. + * + * @return : enumerator for ClassIDs. + */ + nsIEnumerator enumerateCLSIDs(); + + /** + * enumerateContractIDs + * + * Enumerate the list of all registered ContractIDs. + * + * @return : enumerator for ContractIDs. + */ + nsIEnumerator enumerateContractIDs(); +}; + +%{ C++ +/* include after the class def'n, because it needs to see it. */ +#include "nsComponentManagerUtils.h" +%} C++ + diff --git a/src/libs/xpcom18a4/xpcom/components/nsIComponentManagerUtils.h b/src/libs/xpcom18a4/xpcom/components/nsIComponentManagerUtils.h new file mode 100644 index 00000000..a21ee7e3 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/components/nsIComponentManagerUtils.h @@ -0,0 +1,43 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 XPCOM. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +#ifndef nsIComponentManagerUtils_h__ +#define nsIComponentManagerUtils_h__ + + + +#endif diff --git a/src/libs/xpcom18a4/xpcom/components/nsIComponentRegistrar.idl b/src/libs/xpcom18a4/xpcom/components/nsIComponentRegistrar.idl new file mode 100644 index 00000000..2a4a55db --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/components/nsIComponentRegistrar.idl @@ -0,0 +1,243 @@ +/* ***** 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 XPCOM. + * + * The Initial Developer of the Original Code is Netscape Communications. + * Portions created by the Initial Developer are Copyright (C) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * 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 ***** */ + +/** + * The nsIComponentRegistrar interface. + * @status FROZEN + */ + +#include "nsISupports.idl" + +interface nsIFile; +interface nsIFactory; +interface nsISimpleEnumerator; + +[scriptable, uuid(2417cbfe-65ad-48a6-b4b6-eb84db174392)] +interface nsIComponentRegistrar : nsISupports +{ + /** + * autoRegister + * + * Register a component file or all component files in a directory. + * + * Component files must have an associated loader and export the required + * symbols which this loader defines. For example, if the given file is a + * native library (which is built into XPCOM), it must export the symbol + * "NSGetModule". Other loaders may have different semantics. + * + * This method may only be called from the main thread. + * + * @param aSpec : Filename spec for component file's location. If aSpec + * is a directory, then every component file in the + * directory will be registered. + * If the aSpec is null, then the application component's + * directory as defined by NS_XPCOM_COMPONENT_DIR will be + * registered (see nsIDirectoryService.idl) + * + * @return NS_OK : Registration was successful. + * NS_ERROR: Method failure. + */ + void autoRegister(in nsIFile aSpec); + + /** + * autoUnregister + * + * Unregister a component file or all component files in a directory. + * This method may only be called from the main thread. + * + * @param aSpec : Filename spec for component file's location. If aSpec + * is a directory, the every component file in the directory + * will be registered. + * If aSpec is null, then the application component's + * directory as defined by NS_XPCOM_COMPONENT_DIR will be + * registered. (see nsIDirectoryService.idl) + * + * @return NS_OK Unregistration was successful. + * NS_ERROR* Method failure. + */ + void autoUnregister(in nsIFile aSpec); + + + /** + * registerFactory + * + * Register a factory with a given ContractID, CID and Class Name. + * + * @param aClass : CID of object + * @param aClassName : Class Name of CID + * @param aContractID : ContractID associated with CID aClass + * @param aFactory : Factory that will be registered for CID aClass + * + * @return NS_OK Registration was successful. + * NS_ERROR* method failure. + */ + void registerFactory(in nsCIDRef aClass, + in string aClassName, + in string aContractID, + in nsIFactory aFactory); + + /** + * unregisterFactory + * + * Unregister a factory associated with CID aClass. + * + * @param aClass : CID being unregistered + * @param aFactory : Factory previously registered to create instances of + * CID aClass. + * + * @return NS_OK Unregistration was successful. + * NS_ERROR* Method failure. + */ + void unregisterFactory(in nsCIDRef aClass, + in nsIFactory aFactory); + + /** + * registerFactoryLocation + * + * Register a factory with a given ContractID, CID and Class Name + * + * @param aClass : CID of object + * @param aClassName : Class Name of CID + * @param aContractID : ContractID associated with CID aClass + * @param aFile : Component File. This file must have an associated + * loader and export the required symbols which this + * loader specifies. + * @param aLoaderStr : Opaque loader specific string. This value is + * passed into the nsIModule's registerSelf + * callback and must be fowarded unmodified when + * registering factories via their location. + * @param aType : Component Type of CID aClass. This value is + * passed into the nsIModule's registerSelf + * callback and must be fowarded unmodified when + * registering factories via their location. + * + * @return NS_OK Registration was successful. + * NS_ERROR* Method failure. + */ + void registerFactoryLocation(in nsCIDRef aClass, + in string aClassName, + in string aContractID, + in nsIFile aFile, + in string aLoaderStr, + in string aType); + + /** + * unregisterFactoryLocation + * + * Unregister a factory associated with CID aClass. + * + * @param aClass : CID being unregistered + * @param aFile : Component File previously registered + * + * @return NS_OK Unregistration was successful. + * NS_ERROR* Method failure. + */ + void unregisterFactoryLocation(in nsCIDRef aClass, + in nsIFile aFile); + + /** + * isCIDRegistered + * + * Returns true if a factory is registered for the CID. + * + * @param aClass : CID queried for registeration + * @return : true if a factory is registered for CID + * false otherwise. + */ + boolean isCIDRegistered(in nsCIDRef aClass); + + /** + * isContractIDRegistered + * + * Returns true if a factory is registered for the contract id. + * + * @param aClass : contract id queried for registeration + * @return : true if a factory is registered for contract id + * false otherwise. + */ + boolean isContractIDRegistered(in string aContractID); + + /** + * enumerateCIDs + * + * Enumerate the list of all registered CIDs. + * + * @return : enumerator for CIDs. Elements of the enumeration can be QI'ed + * for the nsISupportsID interface. From the nsISupportsID, you + * can obtain the actual CID. + */ + nsISimpleEnumerator enumerateCIDs(); + + /** + * enumerateContractIDs + * + * Enumerate the list of all registered ContractIDs. + * + * @return : enumerator for ContractIDs. Elements of the enumeration can be + * QI'ed for the nsISupportsCString interface. From the + * nsISupportsCString interface, you can obtain the actual + * Contract ID string. + */ + nsISimpleEnumerator enumerateContractIDs(); + + /** + * CIDToContractID + * + * Returns the Contract ID for a given CID, if one exists and is registered. + * + * @return : Contract ID. + */ + string CIDToContractID(in nsCIDRef aClass); + + /** + * contractIDToCID + * + * Returns the CID for a given Contract ID, if one exists and is registered. + * + * @return : Contract ID. + */ + nsCIDPtr contractIDToCID(in string aContractID); + +}; + + + + + + + + + + diff --git a/src/libs/xpcom18a4/xpcom/components/nsIFactory.idl b/src/libs/xpcom18a4/xpcom/components/nsIFactory.idl new file mode 100644 index 00000000..bda0b43a --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/components/nsIFactory.idl @@ -0,0 +1,79 @@ +/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsISupports.idl" + +/** + * A class factory allows the creation of nsISupports derived + * components without specifying a concrete base class. + * + * @status FROZEN + */ + +[scriptable, object, uuid(00000001-0000-0000-c000-000000000046)] +interface nsIFactory : nsISupports { + /** + * Creates an instance of a component. + * + * @param aOuter Pointer to a component that wishes to be aggregated + * in the resulting instance. This will be nsnull if no + * aggregation is requested. + * @param iid The IID of the interface being requested in + * the component which is being currently created. + * @param result [out] Pointer to the newly created instance, if successful. + * @return NS_OK - Component successfully created and the interface + * being requested was successfully returned in result. + * NS_NOINTERFACE - Interface not accessible. + * NS_ERROR_NO_AGGREGATION - if an 'outer' object is supplied, but the + * component is not aggregatable. + * NS_ERROR* - Method failure. + */ + void createInstance(in nsISupports aOuter, in nsIIDRef iid, + [retval, iid_is(iid)] out nsQIResult result); + + /** + * LockFactory provides the client a way to keep the component + * in memory until it is finished with it. The client can call + * LockFactory(PR_TRUE) to lock the factory and LockFactory(PR_FALSE) + * to release the factory. + * + * @param lock - Must be PR_TRUE or PR_FALSE + * @return NS_OK - If the lock operation was successful. + * NS_ERROR* - Method failure. + */ + void lockFactory(in PRBool lock); +}; diff --git a/src/libs/xpcom18a4/xpcom/components/nsIModule.idl b/src/libs/xpcom18a4/xpcom/components/nsIModule.idl new file mode 100644 index 00000000..a71b9b13 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/components/nsIModule.idl @@ -0,0 +1,115 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsISupports.idl" + +interface nsIFile; +interface nsIComponentManager; + +/** + * The nsIModule interface. + * @status FROZEN + */ + +[scriptable, uuid(7392D032-5371-11d3-994E-00805FD26FEE)] +interface nsIModule : nsISupports +{ + /** + * Object Instance Creation + * + * Obtains a Class Object from a nsIModule for a given CID and IID pair. + * This class object can either be query to a nsIFactory or a may be + * query to a nsIClassInfo. + * + * @param aCompMgr : The global component manager + * @param aClass : ClassID of object instance requested + * @param aIID : IID of interface requested + * + */ + void getClassObject(in nsIComponentManager aCompMgr, + in nsCIDRef aClass, + in nsIIDRef aIID, + [retval, iid_is(aIID)] out nsQIResult aResult); + + + /** + * One time registration callback + * + * When the nsIModule is discovered, this method will be + * called so that any setup registration can be preformed. + * + * @param aCompMgr : The global component manager + * @param aLocation : The location of the nsIModule on disk + * @param aLoaderStr: Opaque loader specific string + * @param aType : Loader Type being used to load this module + */ + void registerSelf(in nsIComponentManager aCompMgr, + in nsIFile aLocation, + in string aLoaderStr, + in string aType); + /** + * One time unregistration callback + * + * When the nsIModule is being unregistered, this method will be + * called so that any unregistration can be preformed + * + * @param aCompMgr : The global component manager + * @param aLocation : The location of the nsIModule on disk + * @param aLoaderStr : Opaque loader specific string + * + */ + void unregisterSelf(in nsIComponentManager aCompMgr, + in nsIFile aLocation, + in string aLoaderStr); + + /** + * Module load management + * + * @param aCompMgr : The global component manager + * + * @return indicates to the caller if the module can be unloaded. + * Returning PR_TRUE isn't a guarantee that the module will be + * unloaded. It constitues only willingness of the module to be + * unloaded. It is very important to ensure that no outstanding + * references to the module's code/data exist before returning + * PR_TRUE. + * Returning PR_FALSE guaratees that the module wont be unloaded. + */ + boolean canUnload(in nsIComponentManager aCompMgr); +}; + + diff --git a/src/libs/xpcom18a4/xpcom/components/nsINativeComponentLoader.idl b/src/libs/xpcom18a4/xpcom/components/nsINativeComponentLoader.idl new file mode 100644 index 00000000..c5d18111 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/components/nsINativeComponentLoader.idl @@ -0,0 +1,70 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2003 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsISupports.idl" + +interface nsIFile; + +[uuid(10d1a2a2-d816-458d-a4c3-0805ff0f7b31)] +interface nsINativeComponentLoader : nsISupports +{ + + /** + * addDependentLibrary + * + * This method informs the native component loader that the + * given component library referenced by |aFile| requires + * symbols that can be found in the library named |aLibName|. + * + * The native component loader is expected to resolve these + * external symobls prior to loading the component library. + * + * @param aFile + * The native component file location that is declaring a + * a dependency. This file is expected to be a DSO/DLL. + * + * @param aLibName + * This is a name of a library that the component requires. + * This file name is found in either the GRE bin directory + * or the application's bin directory. Full file path are + * also accepted. Passing nsnull for the |aLibName| will + * clear all dependencies. Note that non null aLibName + * values are expected to be in the native charset. + */ + + void addDependentLibrary(in nsIFile aFile, in string aLibName); +}; diff --git a/src/libs/xpcom18a4/xpcom/components/nsIServiceManager.idl b/src/libs/xpcom18a4/xpcom/components/nsIServiceManager.idl new file mode 100644 index 00000000..200c2a69 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/components/nsIServiceManager.idl @@ -0,0 +1,119 @@ +/* ***** 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 XPCOM. + * + * The Initial Developer of the Original Code is Netscape Communications. + * Portions created by the Initial Developer are Copyright (C) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * 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 "nsISupports.idl" + +/** + * The nsIServiceManager manager interface provides a means to obtain + * global services in an application. The service manager depends on the + * repository to find and instantiate factories to obtain services. + * + * Users of the service manager must first obtain a pointer to the global + * service manager by calling NS_GetServiceManager. After that, + * they can request specific services by calling GetService. When they are + * finished they can NS_RELEASE() the service as usual. + * + * A user of a service may keep references to particular services indefinitely + * and only must call Release when it shuts down. + * + * @status FROZEN + */ + +[scriptable, uuid(8bb35ed9-e332-462d-9155-4a002ab5c958)] +interface nsIServiceManager : nsISupports +{ + /** + * getServiceByContractID + * + * Returns the instance that implements aClass or aContractID and the + * interface aIID. This may result in the instance being created. + * + * @param aClass or aContractID : aClass or aContractID of object + * instance requested + * @param aIID : IID of interface requested + * @param result : resulting service + */ + void getService(in nsCIDRef aClass, + in nsIIDRef aIID, + [iid_is(aIID),retval] out nsQIResult result); + + void getServiceByContractID(in string aContractID, + in nsIIDRef aIID, + [iid_is(aIID),retval] out nsQIResult result); + + /** + * isServiceInstantiated + * + * isServiceInstantiated will return a true if the service has already + * been created, otherwise false + * + * @param aClass or aContractID : aClass or aContractID of object + * instance requested + * @param aIID : IID of interface requested + * @param aIID : IID of interface requested + */ + boolean isServiceInstantiated(in nsCIDRef aClass, in nsIIDRef aIID); + boolean isServiceInstantiatedByContractID(in string aContractID, in nsIIDRef aIID); +}; + + +%{C++ +#define NS_ERROR_SERVICE_NOT_AVAILABLE NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_XPCOM, 22) +/** + * @status DEPRECATED + */ +#define NS_ERROR_SERVICE_NOT_FOUND NS_ERROR_GENERATE_SUCCESS(NS_ERROR_MODULE_XPCOM, 22) +/** + * @status DEPRECATED + */ +#define NS_ERROR_SERVICE_IN_USE NS_ERROR_GENERATE_SUCCESS(NS_ERROR_MODULE_XPCOM, 23) + +// Observing xpcom startup. If you component has not been created, it will be. +#define NS_XPCOM_STARTUP_OBSERVER_ID "xpcom-startup" + +// Observing xpcom shutdown +#define NS_XPCOM_SHUTDOWN_OBSERVER_ID "xpcom-shutdown" + +// Observing xpcom autoregistration. Topics will be 'start' and 'stop'. +#define NS_XPCOM_AUTOREGISTRATION_OBSERVER_ID "xpcom-autoregistration" + +#ifndef MOZILLA_STRICT_API +#include "nsXPCOM.h" +#include "nsIServiceManagerUtils.h" +#include "nsIServiceManagerObsolete.h" +#endif +%} + diff --git a/src/libs/xpcom18a4/xpcom/components/nsIServiceManagerObsolete.h b/src/libs/xpcom18a4/xpcom/components/nsIServiceManagerObsolete.h new file mode 100644 index 00000000..dc229c76 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/components/nsIServiceManagerObsolete.h @@ -0,0 +1,250 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 XPCOM. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +#ifndef nsIServiceManagerObsolete_h___ +#define nsIServiceManagerObsolete_h___ + +//////////////////////////////////////////////////////////////////// +// +// WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING +// +// Functions, classes, interfaces and types in this file are +// obsolete. Use at your own risk. +// Please see nsIServiceManager.idl for the supported interface +// to the service manager. +// +//////////////////////////////////////////////////////////////////// + +#include "nsIComponentManager.h" +#include "nsID.h" + +#ifndef nsCOMPtr_h___ +#include "nsCOMPtr.h" +#endif + +class nsIServiceManager; +class nsIShutdownListener; +class nsIDirectoryServiceProvider; + +class nsServiceManagerObsolete; + +#define NS_ISERVICEMANAGER_OBSOLETE_IID \ +{ /* cf0df3b0-3401-11d2-8163-006008119d7a */ \ + 0xcf0df3b0, \ + 0x3401, \ + 0x11d2, \ + {0x81, 0x63, 0x00, 0x60, 0x08, 0x11, 0x9d, 0x7a} \ +} + +/** + * The nsIServiceManagerObsolete manager is obsolete. Please refer + * to nsIServiceManager. + */ +class nsIServiceManagerObsolete : public nsISupports { +public: + + NS_DEFINE_STATIC_IID_ACCESSOR(NS_ISERVICEMANAGER_OBSOLETE_IID); + + /** + * RegisterService may be called explicitly to register a service + * with the service manager. If a service is not registered explicitly, + * the component manager will be used to create an instance according + * to the class ID specified. + */ + NS_IMETHOD + RegisterService(const nsCID& aClass, nsISupports* aService) = 0; + + /** + * Requests a service to be shut down, possibly unloading its DLL. + * + * @returns NS_OK - if shutdown was successful and service was unloaded, + * @returns NS_ERROR_SERVICE_NOT_FOUND - if shutdown failed because + * the service was not currently loaded + * @returns NS_ERROR_SERVICE_IN_USE - if shutdown failed because some + * user of the service wouldn't voluntarily release it by using + * a shutdown listener. + */ + NS_IMETHOD + UnregisterService(const nsCID& aClass) = 0; + + NS_IMETHOD + GetService(const nsCID& aClass, const nsIID& aIID, + nsISupports* *result, + nsIShutdownListener* shutdownListener = nsnull) = 0; + + /* OBSOLETE: use NS_RELEASE(service) instead. */ + NS_IMETHOD + ReleaseService(const nsCID& aClass, nsISupports* service, + nsIShutdownListener* shutdownListener = nsnull) = 0; + + //////////////////////////////////////////////////////////////////////////// + // let's do it again, this time with ContractIDs... + + NS_IMETHOD + RegisterService(const char* aContractID, nsISupports* aService) = 0; + + NS_IMETHOD + UnregisterService(const char* aContractID) = 0; + + NS_IMETHOD + GetService(const char* aContractID, const nsIID& aIID, + nsISupports* *result, + nsIShutdownListener* shutdownListener = nsnull) = 0; + + /* OBSOLETE */ + NS_IMETHOD + ReleaseService(const char* aContractID, nsISupports* service, + nsIShutdownListener* shutdownListener = nsnull) = 0; + +}; + +// Interface to Global Services +class NS_COM nsServiceManager { +public: + + static nsresult + RegisterService(const nsCID& aClass, nsISupports* aService); + + static nsresult + UnregisterService(const nsCID& aClass); + + static nsresult + GetService(const nsCID& aClass, const nsIID& aIID, + nsISupports* *result, + nsIShutdownListener* shutdownListener = nsnull); + + /* OBSOLETE: use NS_RELEASE(service) instead. */ + static nsresult + ReleaseService(const nsCID& aClass, nsISupports* service, + nsIShutdownListener* shutdownListener = nsnull); + + //////////////////////////////////////////////////////////////////////////// + // let's do it again, this time with ContractIDs... + + static nsresult + RegisterService(const char* aContractID, nsISupports* aService); + + static nsresult + UnregisterService(const char* aContractID); + + static nsresult + GetService(const char* aContractID, const nsIID& aIID, + nsISupports* *result, + nsIShutdownListener* shutdownListener = nsnull); + + /* OBSOLETE: use NS_RELEASE(service) instead. */ + static nsresult + ReleaseService(const char* aContractID, nsISupports* service, + nsIShutdownListener* shutdownListener = nsnull); + + + //////////////////////////////////////////////////////////////////////////// + // These methods return really nsIServiceManagerObsolete, but they are + // statically cast to nsIServiceManager to preserve backwards compatiblity. + static nsresult GetGlobalServiceManager(nsIServiceManager* *result); + static nsresult ShutdownGlobalServiceManager(nsIServiceManager* *result); +}; + + +#define NS_DECL_NSISERVICEMANAGEROBSOLETE \ + NS_IMETHOD RegisterService(const nsCID& aClass, nsISupports* aService); \ + NS_IMETHOD UnregisterService(const nsCID& aClass);\ + NS_IMETHOD GetService(const nsCID& aClass, const nsIID& aIID, nsISupports* *result, nsIShutdownListener* shutdownListener);\ + NS_IMETHOD ReleaseService(const nsCID& aClass, nsISupports* service, nsIShutdownListener* shutdownListener);\ + NS_IMETHOD RegisterService(const char* aContractID, nsISupports* aService);\ + NS_IMETHOD UnregisterService(const char* aContractID);\ + NS_IMETHOD GetService(const char* aContractID, const nsIID& aIID, nsISupports* *result, nsIShutdownListener* shutdownListener);\ + NS_IMETHOD ReleaseService(const char* aContractID, nsISupports* service, nsIShutdownListener* shutdownListener); + +//////////////////////////////////////////////////////////////////////////////// + +#define NS_ISHUTDOWNLISTENER_IID \ +{ /* 56decae0-3406-11d2-8163-006008119d7a */ \ + 0x56decae0, \ + 0x3406, \ + 0x11d2, \ + {0x81, 0x63, 0x00, 0x60, 0x08, 0x11, 0x9d, 0x7a} \ +} + +class nsIShutdownListener; + + +template +inline +nsresult +CallGetService( const nsCID &aClass, + nsIShutdownListener* shutdownListener, + DestinationType** aDestination) +{ + NS_PRECONDITION(aDestination, "null parameter"); + + return nsServiceManager::GetService(aClass, + NS_GET_IID(DestinationType), + NS_REINTERPRET_CAST(nsISupports**, aDestination), + shutdownListener); +} + +template +inline +nsresult +CallGetService( const char *aContractID, + nsIShutdownListener* shutdownListener, + DestinationType** aDestination) +{ + NS_PRECONDITION(aContractID, "null parameter"); + NS_PRECONDITION(aDestination, "null parameter"); + + return nsServiceManager::GetService(aContractID, + NS_GET_IID(DestinationType), + NS_REINTERPRET_CAST(nsISupports**, aDestination), + shutdownListener); +} + +//////////////////////////////////////////////////////////////////////////////// + + +#endif /* nsIServiceManagerObsolete_h___ */ + + + + + + + + + + diff --git a/src/libs/xpcom18a4/xpcom/components/nsIServiceManagerUtils.h b/src/libs/xpcom18a4/xpcom/components/nsIServiceManagerUtils.h new file mode 100644 index 00000000..b7b432af --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/components/nsIServiceManagerUtils.h @@ -0,0 +1,185 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 XPCOM. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +#ifndef nsIServiceManagerUtils_h__ +#define nsIServiceManagerUtils_h__ + +#include "nsIServiceManager.h" +#include "nsIServiceManagerObsolete.h" +#include "nsCOMPtr.h" + +//////////////////////////////////////////////////////////////////////////// +// Using servicemanager with COMPtrs +class NS_COM nsGetServiceByCID : public nsCOMPtr_helper +{ + public: + nsGetServiceByCID( const nsCID& aCID, nsISupports* aServiceManager, nsresult* aErrorPtr ) + : mCID(aCID), + mServiceManager( do_QueryInterface(aServiceManager) ), + mErrorPtr(aErrorPtr) + { + // nothing else to do + } + + virtual nsresult NS_FASTCALL operator()( const nsIID&, void** ) const; + + private: + const nsCID& mCID; + nsCOMPtr mServiceManager; + nsresult* mErrorPtr; +}; + +inline +const nsGetServiceByCID +do_GetService( const nsCID& aCID, nsresult* error = 0 ) +{ + return nsGetServiceByCID(aCID, 0, error); +} + +inline +const nsGetServiceByCID +do_GetService( const nsCID& aCID, nsISupports* aServiceManager, nsresult* error = 0 ) +{ + return nsGetServiceByCID(aCID, aServiceManager, error); +} + +class NS_COM nsGetServiceByContractID : public nsCOMPtr_helper +{ + public: + nsGetServiceByContractID( const char* aContractID, nsISupports* aServiceManager, nsresult* aErrorPtr ) + : mContractID(aContractID), + mServiceManager( do_QueryInterface(aServiceManager) ), + mErrorPtr(aErrorPtr) + { + // nothing else to do + } + // Implement a dummy destructor to workaround linking issue on Solaris gcc 4.8.2 (see @bugref{5838}) + ~nsGetServiceByContractID() {} + + virtual nsresult NS_FASTCALL operator()( const nsIID&, void** ) const; + + private: + const char* mContractID; + nsCOMPtr mServiceManager; + nsresult* mErrorPtr; +}; + +inline +const nsGetServiceByContractID +do_GetService( const char* aContractID, nsresult* error = 0 ) +{ + return nsGetServiceByContractID(aContractID, 0, error); +} + +inline +const nsGetServiceByContractID +do_GetService( const char* aContractID, nsISupports* aServiceManager, nsresult* error = 0 ) +{ + return nsGetServiceByContractID(aContractID, aServiceManager, error); +} + +class nsGetServiceFromCategory : public nsCOMPtr_helper +{ + public: + nsGetServiceFromCategory(const char* aCategory, const char* aEntry, + nsISupports* aServiceManager, + nsresult* aErrorPtr) + : mCategory(aCategory), + mEntry(aEntry), + mServiceManager( do_QueryInterface(aServiceManager) ), + mErrorPtr(aErrorPtr) + { + // nothing else to do + } + + virtual nsresult NS_FASTCALL operator()( const nsIID&, void** ) const; + protected: + const char* mCategory; + const char* mEntry; + nsCOMPtr mServiceManager; + nsresult* mErrorPtr; +}; + +inline +const nsGetServiceFromCategory +do_GetServiceFromCategory( const char* category, const char* entry, + nsresult* error = 0) +{ + return nsGetServiceFromCategory(category, entry, 0, error); +} + +// type-safe shortcuts for calling |GetService| +template +inline +nsresult +CallGetService( const nsCID &aClass, + DestinationType** aDestination) +{ + NS_PRECONDITION(aDestination, "null parameter"); + + nsCOMPtr mgr; + nsresult rv = NS_GetServiceManager(getter_AddRefs(mgr)); + + if (NS_FAILED(rv)) + return rv; + + return mgr->GetService(aClass, + NS_GET_IID(DestinationType), + NS_REINTERPRET_CAST(void**, aDestination)); +} + +template +inline +nsresult +CallGetService( const char *aContractID, + DestinationType** aDestination) +{ + NS_PRECONDITION(aContractID, "null parameter"); + NS_PRECONDITION(aDestination, "null parameter"); + + nsCOMPtr mgr; + nsresult rv = NS_GetServiceManager(getter_AddRefs(mgr)); + + if (NS_FAILED(rv)) + return rv; + + return mgr->GetServiceByContractID(aContractID, + NS_GET_IID(DestinationType), + NS_REINTERPRET_CAST(void**, aDestination)); +} + +#endif diff --git a/src/libs/xpcom18a4/xpcom/components/nsModule.h b/src/libs/xpcom18a4/xpcom/components/nsModule.h new file mode 100644 index 00000000..56a06354 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/components/nsModule.h @@ -0,0 +1,58 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org Code. + * + * The Initial Developer of the Original Code is + * Marco Pesenti Gritti + * Portions created by the Initial Developer are Copyright (C) 2004 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +#ifndef nsModule_h__ +#define nsModule_h__ + +#include "nsIModule.h" +#include "nsIFile.h" +#include "nsIComponentManager.h" + +// Exported Function from module dll to Create the nsIModule +#define NS_GET_MODULE_SYMBOL "NSGetModule" + +extern "C" NS_EXPORT nsresult PR_CALLBACK +NSGetModule(nsIComponentManager *aCompMgr, + nsIFile* location, + nsIModule** return_cobj); + +typedef nsresult (PR_CALLBACK *nsGetModuleProc)(nsIComponentManager *aCompMgr, + nsIFile* location, + nsIModule** return_cobj); + + +#endif /* nsModule_h__ */ diff --git a/src/libs/xpcom18a4/xpcom/components/nsNativeComponentLoader.cpp b/src/libs/xpcom18a4/xpcom/components/nsNativeComponentLoader.cpp new file mode 100644 index 00000000..a3fd5df8 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/components/nsNativeComponentLoader.cpp @@ -0,0 +1,1150 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org Code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** + * This Original Code has been modified by IBM Corporation. + * Modifications made by IBM described herein are + * Copyright (c) International Business Machines + * Corporation, 2000 + * + * Modifications to Mozilla code or documentation + * identified per MPL Section 3.3 + * + * Date Modified by Description of modification + * 04/20/2000 IBM Corp. Added PR_CALLBACK for Optlink use in OS2 + */ + +#include "prmem.h" +#include "prerror.h" +#include "prsystem.h" // PR_GetDirectorySeparator +#include "nsNativeComponentLoader.h" +#include "nsComponentManager.h" +#include "nsCOMPtr.h" +#include "nsIServiceManager.h" +#include "nsIModule.h" +#include "xcDll.h" +#include "nsHashtable.h" +#include "nsXPIDLString.h" +#include "nsCRT.h" +#include "nsIObserverService.h" + +#if defined(XP_MAC) // sdagley dougt fix +#include +#include +#include "nsILocalFileMac.h" +#endif + +#include "prlog.h" +extern PRLogModuleInfo *nsComponentManagerLog; + +static PRBool PR_CALLBACK +DLLStore_Destroy(nsHashKey *aKey, void *aData, void* closure) +{ + nsDll* entry = NS_STATIC_CAST(nsDll*, aData); + delete entry; + return PR_TRUE; +} + +nsNativeComponentLoader::nsNativeComponentLoader() : + mCompMgr(nsnull), + mLoadedDependentLibs(16, PR_TRUE), + mDllStore(nsnull, nsnull, DLLStore_Destroy, + nsnull, 256, PR_TRUE) +{ +} + +NS_IMPL_THREADSAFE_ISUPPORTS2(nsNativeComponentLoader, + nsIComponentLoader, + nsINativeComponentLoader) + +NS_IMETHODIMP +nsNativeComponentLoader::GetFactory(const nsIID & aCID, + const char *aLocation, + const char *aType, + nsIFactory **_retval) +{ + nsresult rv; + + if (!_retval) + return NS_ERROR_NULL_POINTER; + + /* use a hashtable of WeakRefs to store the factory object? */ + + /* Should this all live in xcDll? */ + nsDll *dll; + rv = CreateDll(nsnull, aLocation, &dll); + if (NS_FAILED(rv)) + return rv; + + if (!dll) + return NS_ERROR_OUT_OF_MEMORY; + + if (!dll->IsLoaded()) { +#ifdef PR_LOGGING + nsXPIDLCString displayPath; + dll->GetDisplayPath(displayPath); + + PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG, + ("nsNativeComponentLoader: loading \"%s\"", + displayPath.get())); +#endif + if (!dll->Load()) { + + PR_LOG(nsComponentManagerLog, PR_LOG_ALWAYS, + ("nsNativeComponentLoader: load FAILED")); + + char errorMsg[1024] = ""; + + if (PR_GetErrorTextLength() < (int) sizeof(errorMsg)) + PR_GetErrorText(errorMsg); + + DumpLoadError(dll, "GetFactory", errorMsg); + + return NS_ERROR_FAILURE; + } + } + + /* Get service manager for factory */ + nsCOMPtr serviceMgr; + rv = NS_GetServiceManager(getter_AddRefs(serviceMgr)); + if (NS_FAILED(rv)) + return rv; // XXX translate error code? + + rv = GetFactoryFromModule(dll, aCID, _retval); + + PR_LOG(nsComponentManagerLog, NS_SUCCEEDED(rv) ? PR_LOG_DEBUG : PR_LOG_ERROR, + ("nsNativeComponentLoader: Factory creation %s for %s", + (NS_SUCCEEDED(rv) ? "succeeded" : "FAILED"), + aLocation)); + + // If the dll failed to get us a factory. But the dll registered that + // it would be able to create a factory for this CID. mmh! + // We cannot just delete the dll as the dll could be hosting + // other CID for which factory creation can pass. + // We will just let it be. The effect will be next time we try + // creating the object, we will query the dll again. Since the + // dll is loaded, this aint a big hit. So for optimized builds + // this is ok to limp along. + NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Factory creation failed"); + + return rv; +} + +NS_IMETHODIMP +nsNativeComponentLoader::Init(nsIComponentManager *aCompMgr, nsISupports *aReg) +{ + mCompMgr = aCompMgr; + if (!mCompMgr) + return NS_ERROR_INVALID_ARG; + + return NS_OK; +} + +NS_IMETHODIMP +nsNativeComponentLoader::AutoRegisterComponents(PRInt32 aWhen, + nsIFile *aDirectory) +{ +#ifdef DEBUG + /* do we _really_ want to print this every time? */ + fprintf(stderr, "nsNativeComponentLoader: autoregistering begins.\n"); +#endif + + nsresult rv = RegisterComponentsInDir(aWhen, aDirectory); + +#ifdef DEBUG + fprintf(stderr, "nsNativeComponentLoader: autoregistering %s\n", + NS_FAILED(rv) ? "FAILED" : "succeeded"); +#endif + + return rv; +} + +nsresult +nsNativeComponentLoader::RegisterComponentsInDir(PRInt32 when, + nsIFile *dir) +{ + nsresult rv = NS_ERROR_FAILURE; + PRBool isDir = PR_FALSE; + +#if 0 + // Going to many of these checks is a performance hit on the mac. + // Since these routines are called relatively infrequently and + // we will fail anyway down the line if a directory aint there, + // we are commenting this check out. + + // Make sure we are dealing with a directory + rv = dir->IsDirectory(&isDir); + if (NS_FAILED(rv)) return rv; + + if (!isDir) + return NS_ERROR_INVALID_ARG; +#endif /* 0 */ + + // Create a directory iterator + nsCOMPtr dirIterator; + rv = dir->GetDirectoryEntries(getter_AddRefs(dirIterator)); + + if (NS_FAILED(rv)) return rv; + + // whip through the directory to register every file + nsCOMPtr dirEntry; + PRBool more = PR_FALSE; + + rv = dirIterator->HasMoreElements(&more); + if (NS_FAILED(rv)) return rv; + while (more == PR_TRUE) + { + rv = dirIterator->GetNext((nsISupports**)getter_AddRefs(dirEntry)); + if (NS_SUCCEEDED(rv)) + { + rv = dirEntry->IsDirectory(&isDir); + if (NS_SUCCEEDED(rv)) + { + if (isDir == PR_TRUE) + { + // This is a directory. Grovel for components into the directory. +#ifdef RT_OS_DARWIN // But not if it's a debug bundle. + nsCAutoString leafName; + rv = dirEntry->GetNativeLeafName(leafName); + if ( NS_FAILED(rv) + || leafName.Length() < sizeof(".dSYM") + || PL_strcasecmp(leafName.get() + (leafName.Length() - sizeof(".dSYM") + 1), ".dSYM")) +#endif + rv = RegisterComponentsInDir(when, dirEntry); + } + else + { + PRBool registered; + // This is a file. Try to register it. + rv = AutoRegisterComponent(when, dirEntry, ®istered); + } + } + } + rv = dirIterator->HasMoreElements(&more); + if (NS_FAILED(rv)) return rv; + } + + return rv; +} + +static nsresult PR_CALLBACK +nsFreeLibrary(nsDll *dll, nsIServiceManager *serviceMgr, PRInt32 when) +{ + nsresult rv = NS_ERROR_FAILURE; + + if (!dll || dll->IsLoaded() == PR_FALSE) + { + return NS_ERROR_INVALID_ARG; + } + + // Get if the dll was marked for unload in an earlier round + PRBool dllMarkedForUnload = dll->IsMarkedForUnload(); + + // Reset dll marking for unload just in case we return with + // an error. + dll->MarkForUnload(PR_FALSE); + + PRBool canUnload = PR_FALSE; + + // Get the module object + nsCOMPtr mobj; + /* XXXshaver cheat and use the global component manager */ + rv = dll->GetModule(NS_STATIC_CAST(nsIComponentManager*, nsComponentManagerImpl::gComponentManager), + getter_AddRefs(mobj)); + if (NS_SUCCEEDED(rv)) + { + rv = mobj->CanUnload(nsComponentManagerImpl::gComponentManager, &canUnload); + } + + mobj = nsnull; // Release our reference to the module object + // When shutting down, whether we can unload the dll or not, + // we will shutdown the dll to release any memory it has got + if (when == nsIComponentManagerObsolete::NS_Shutdown) + { + dll->Shutdown(); + } + + // Check error status on CanUnload() call + if (NS_FAILED(rv)) + { +#ifdef PR_LOGGING + nsXPIDLCString displayPath; + dll->GetDisplayPath(displayPath); + + PR_LOG(nsComponentManagerLog, PR_LOG_ERROR, + ("nsNativeComponentLoader: nsIModule::CanUnload() returned error for %s.", + displayPath.get())); +#endif + return rv; + } + + if (canUnload) + { + if (dllMarkedForUnload) + { +#ifdef PR_LOGGING + nsXPIDLCString displayPath; + dll->GetDisplayPath(displayPath); + + PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG, + ("nsNativeComponentLoader: + Unloading \"%s\".", displayPath.get())); +#endif + +#ifdef DEBUG_dougt + // XXX dlls aren't counting their outstanding instances correctly + // XXX hence, dont unload until this gets enforced. + rv = dll->Unload(); +#endif /* 0 */ + } + else + { +#ifdef PR_LOGGING + nsXPIDLCString displayPath; + dll->GetDisplayPath(displayPath); + + PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG, + ("nsNativeComponentLoader: Ready for unload \"%s\".", displayPath.get())); +#endif + } + } + else + { +#ifdef PR_LOGGING + nsXPIDLCString displayPath; + dll->GetDisplayPath(displayPath); + + PR_LOG(nsComponentManagerLog, PR_LOG_WARNING, + ("nsNativeComponentLoader: NOT ready for unload %s", displayPath.get())); +#endif + rv = NS_ERROR_FAILURE; + } + return rv; +} + +struct freeLibrariesClosure +{ + nsIServiceManager *serviceMgr; + PRInt32 when; +}; + +static PRBool PR_CALLBACK +nsFreeLibraryEnum(nsHashKey *aKey, void *aData, void* closure) +{ + nsDll *dll = (nsDll *) aData; + struct freeLibrariesClosure *callData = (struct freeLibrariesClosure *) closure; + nsFreeLibrary(dll, + (callData ? callData->serviceMgr : NULL), + (callData ? callData->when : nsIComponentManagerObsolete::NS_Timer)); + return PR_TRUE; +} + +/* + * SelfRegisterDll + * + * Given a dll abstraction, this will load, selfregister the dll and + * unload the dll. + * + */ +nsresult +nsNativeComponentLoader::SelfRegisterDll(nsDll *dll, + const char *registryLocation, + PRBool deferred) +{ + // Precondition: dll is not loaded already, unless we're deferred + PR_ASSERT(deferred || dll->IsLoaded() == PR_FALSE); + + nsresult res; + nsCOMPtr serviceMgr; + res = NS_GetServiceManager(getter_AddRefs(serviceMgr)); + if (NS_FAILED(res)) return res; + + if (dll->Load() == PR_FALSE) + { + // Cannot load. Probably not a dll. + char errorMsg[1024] = "Cannot get error from nspr. Not enough memory."; + if (PR_GetErrorTextLength() < (int) sizeof(errorMsg)) + PR_GetErrorText(errorMsg); + + DumpLoadError(dll, "SelfRegisterDll", errorMsg); + + return NS_ERROR_FAILURE; + } + +#ifdef PR_LOGGING + nsXPIDLCString displayPath; + dll->GetDisplayPath(displayPath); + + PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG, + ("nsNativeComponentLoader: Loaded \"%s\".", displayPath.get())); +#endif + + // Tell the module to self register + nsCOMPtr fs; + nsCOMPtr mobj; + res = dll->GetModule(mCompMgr, getter_AddRefs(mobj)); + if (NS_SUCCEEDED(res)) + { + /************************************************************* + * WARNING: Why are use introducing 'res2' here and then * + * later assigning it to 'res' rather than just using 'res'? * + * This is because this code turns up a code-generation bug * + * in VC6 on NT. Assigning to 'res' on the next line causes * + * the value of 'dll' to get nulled out! The two seem to be * + * getting aliased together during compilation. * + *************************************************************/ + nsresult res2 = dll->GetDllSpec(getter_AddRefs(fs)); // don't change 'res2' -- see warning, above + if (NS_SUCCEEDED(res2)) { + // in the case of re-registering a component, we want to remove + // any optional data that this file may have had. + AddDependentLibrary(fs, nsnull); + + res = mobj->RegisterSelf(mCompMgr, fs, registryLocation, + nativeComponentType); + } + else + { + res = res2; // don't take this out -- see warning, above + +#ifdef PR_LOGGING + nsXPIDLCString displayPath; + dll->GetDisplayPath(displayPath); + PR_LOG(nsComponentManagerLog, PR_LOG_ERROR, + ("nsNativeComponentLoader: dll->GetDllSpec() on %s FAILED.", + displayPath.get())); +#endif + } + mobj = NULL; // Force a release of the Module object before unload() + } + + // Update the timestamp and size of the dll in registry + // Don't enter deferred modules in the registry, because it might only be + // able to register on some later autoreg, after another component has been + // installed. + if (res != NS_ERROR_FACTORY_REGISTER_AGAIN) { + PRInt64 modTime; + if (!fs) + return res; + + fs->GetLastModifiedTime(&modTime); + nsCOMPtr manager = do_QueryInterface(mCompMgr); + if (!manager) + return NS_ERROR_FAILURE; + + nsCOMPtr fs; + res = dll->GetDllSpec(getter_AddRefs(fs)); + if (NS_FAILED(res)) return res; + + manager->SaveFileInfo(fs, registryLocation, modTime); + } + + return res; +} + +// +// MOZ_DEMANGLE_SYMBOLS is only a linux + MOZ_DEBUG thing. +// + +#if defined(MOZ_DEMANGLE_SYMBOLS) +#include "nsTraceRefcntImpl.h" // for nsTraceRefcntImpl::DemangleSymbol() +#endif + +nsresult +nsNativeComponentLoader::DumpLoadError(nsDll *dll, + const char *aCallerName, + const char *aNsprErrorMsg) +{ + PR_ASSERT(aCallerName != NULL); + + if (nsnull == dll || nsnull == aNsprErrorMsg) + return NS_OK; + + nsCAutoString errorMsg(aNsprErrorMsg); + +#if defined(MOZ_DEMANGLE_SYMBOLS) + // Demangle undefined symbols + nsCAutoString undefinedMagicString("undefined symbol:"); + + PRInt32 offset = errorMsg.Find(undefinedMagicString, PR_TRUE); + + if (offset != kNotFound) + { + nsCAutoString symbol(errorMsg); + nsCAutoString demangledSymbol; + + symbol.Cut(0,offset); + + symbol.Cut(0,undefinedMagicString.Length()); + + symbol.StripWhitespace(); + + char demangled[4096] = "\0"; + + nsTraceRefcntImpl::DemangleSymbol(symbol.get(),demangled,sizeof(demangled)); + + if (demangled && *demangled != '\0') + demangledSymbol = demangled; + + if (!demangledSymbol.IsEmpty()) + { + nsCAutoString tmp(errorMsg); + + + tmp.Cut(offset + undefinedMagicString.Length(), + tmp.Length() - offset - undefinedMagicString.Length()); + + tmp += " \n"; + + tmp += demangledSymbol; + + errorMsg = tmp; + } + } +#endif // MOZ_DEMANGLE_SYMBOLS + nsXPIDLCString displayPath; + dll->GetDisplayPath(displayPath); + +#ifdef DEBUG + fprintf(stderr, + "nsNativeComponentLoader: %s(%s) Load FAILED with error: %s\n", + aCallerName, + displayPath.get(), + errorMsg.get()); +#endif + + // Do NSPR log +#ifdef PR_LOGGING + PR_LOG(nsComponentManagerLog, PR_LOG_ALWAYS, + ("nsNativeComponentLoader: %s(%s) Load FAILED with error: %s", + aCallerName, + displayPath.get(), + errorMsg.get())); +#endif + return NS_OK; +} + +nsresult +nsNativeComponentLoader::SelfUnregisterDll(nsDll *dll) +{ + nsresult res; + nsCOMPtr serviceMgr; + res = NS_GetServiceManager(getter_AddRefs(serviceMgr)); + if (NS_FAILED(res)) return res; + + if (dll->Load() == PR_FALSE) + { + // Cannot load. Probably not a dll. + return(NS_ERROR_FAILURE); + } + + // Tell the module to self register + nsCOMPtr mobj; + res = dll->GetModule(mCompMgr, getter_AddRefs(mobj)); + if (NS_SUCCEEDED(res)) + { +#ifdef PR_LOGGING + nsXPIDLCString displayPath; + dll->GetDisplayPath(displayPath); + + PR_LOG(nsComponentManagerLog, PR_LOG_ERROR, + ("nsNativeComponentLoader: %s using nsIModule to unregister self.", displayPath.get())); +#endif + nsCOMPtr fs; + res = dll->GetDllSpec(getter_AddRefs(fs)); + if (NS_FAILED(res)) return res; + // Get registry location for spec + nsXPIDLCString registryName; + + // what I want to do here is QI for a Component Registration Manager. Since this + // has not been invented yet, QI to the obsolete manager. Kids, don't do this at home. + nsCOMPtr obsoleteManager = do_QueryInterface(mCompMgr, &res); + if (obsoleteManager) + res = obsoleteManager->RegistryLocationForSpec(fs, getter_Copies(registryName)); + + if (NS_FAILED(res)) return res; + mobj->UnregisterSelf(mCompMgr, fs, registryName); + } + return res; +} + +nsresult +nsNativeComponentLoader::AutoUnregisterComponent(PRInt32 when, + nsIFile *component, + PRBool *unregistered) +{ + + nsresult rv = NS_ERROR_FAILURE; + + *unregistered = PR_FALSE; + + nsXPIDLCString persistentDescriptor; + // what I want to do here is QI for a Component Registration Manager. Since this + // has not been invented yet, QI to the obsolete manager. Kids, don't do this at home. + nsCOMPtr obsoleteManager = do_QueryInterface(mCompMgr, &rv); + if (obsoleteManager) + rv = obsoleteManager->RegistryLocationForSpec(component, + getter_Copies(persistentDescriptor)); + if (NS_FAILED(rv)) return rv; + + // Notify observers, if any, of autoregistration work + nsCOMPtr observerService = + do_GetService("@mozilla.org/observer-service;1", &rv); + if (NS_SUCCEEDED(rv)) + { + nsCOMPtr mgr; + rv = NS_GetServiceManager(getter_AddRefs(mgr)); + if (NS_SUCCEEDED(rv)) + { + (void) observerService->NotifyObservers(mgr, + NS_XPCOM_AUTOREGISTRATION_OBSERVER_ID, + NS_LITERAL_STRING("Unregistering native component").get()); + } + } + + nsDll *dll = NULL; + rv = CreateDll(component, persistentDescriptor, &dll); + if (NS_FAILED(rv) || dll == NULL) return rv; + + rv = SelfUnregisterDll(dll); + +#ifdef PR_LOGGING + nsXPIDLCString displayPath; + dll->GetDisplayPath(displayPath); + + PR_LOG(nsComponentManagerLog, NS_SUCCEEDED(rv) ? PR_LOG_DEBUG : PR_LOG_ERROR, + ("nsNativeComponentLoader: AutoUnregistration for %s %s.", + (NS_FAILED(rv) ? "FAILED" : "succeeded"), displayPath.get())); +#endif + + if (NS_FAILED(rv)) + return rv; + + // Remove any autoreg info about this dll + nsCStringKey key(persistentDescriptor); + mDllStore.RemoveAndDelete(&key); + + nsCOMPtr manager = do_QueryInterface(mCompMgr); + NS_ASSERTION(manager, "Something is terribly wrong"); + + manager->RemoveFileInfo(component, nsnull); + + *unregistered = PR_TRUE; + return rv; +} + +nsresult +nsNativeComponentLoader::AutoRegisterComponent(PRInt32 when, + nsIFile *component, + PRBool *registered) +{ + nsresult rv; + if (!registered) + return NS_ERROR_NULL_POINTER; + + *registered = PR_FALSE; + +#ifndef VBOX + /* this should be a pref or registry entry, or something */ + static const char *ValidDllExtensions[] = { + ".dll", /* Windows */ + ".so", /* Unix */ + ".shlb", /* Mac ? */ + ".dso", /* Unix ? */ + ".dylib", /* Unix: Mach */ + ".so.1.0", /* Unix: BSD */ + ".sl", /* Unix: HP-UX */ +#if defined(VMS) + ".exe", /* Open VMS */ +#endif + ".dlm", /* new for all platforms */ + NULL + }; + + *registered = PR_FALSE; + +#if 0 + // This is a performance hit on mac. Since we have already checked + // this; plus is we dont, load will fail anyway later on, this + // is being commented out. + + // Ensure we are dealing with a file as opposed to a dir + PRBool b = PR_FALSE; + + rv = component->IsFile(&b); + if (NS_FAILED(rv) || !b) + return rv; +#endif /* 0 */ + + // deal only with files that have a valid extension + PRBool validExtension = PR_FALSE; + +#if defined(XP_MAC) // sdagley dougt fix + // rjc - on Mac, check the file's type code (skip checking the creator code) + + nsCOMPtr localFileMac = do_QueryInterface(component); + if (localFileMac) + { + OSType type; + rv = localFileMac->GetFileType(&type); + if (NS_SUCCEEDED(rv)) + { + // on Mac, Mozilla shared libraries are of type 'shlb' + // Note: we don't check the creator (which for Mozilla is 'MOZZ') + // so that 3rd party shared libraries will be noticed! + validExtension = ((type == 'shlb') || (type == 'NSPL')); + } + } + +#else + nsCAutoString leafName; + rv = component->GetNativeLeafName(leafName); + if (NS_FAILED(rv)) return rv; + int flen = leafName.Length(); + for (int i=0; ValidDllExtensions[i] != NULL; i++) + { + int extlen = PL_strlen(ValidDllExtensions[i]); + + // Does fullname end with this extension + if (flen >= extlen && + !PL_strcasecmp(leafName.get() + (flen - extlen), ValidDllExtensions[i]) + ) + { + validExtension = PR_TRUE; + break; + } + } +#endif + + if (validExtension == PR_FALSE) + // Skip invalid extensions + return NS_OK; + +#else /* VBOX */ + /* VBox: Only one valid suffix exist, so dispense with the the list. */ +# ifdef RT_OS_DARWIN +# ifdef VBOX_IN_32_ON_64_MAIN_API + static const char s_szSuff[] = "-x86.dylib"; +# else + static const char s_szSuff[] = ".dylib"; + static const char s_szSuffInvalid[] = "-x86.dylib"; +# endif +# elif defined(RT_OS_OS2) || defined(RT_OS_WINDOWS) +# ifdef VBOX_IN_32_ON_64_MAIN_API + static const char s_szSuff[] = "-x86.dll"; +#else + static const char s_szSuff[] = ".dll"; + static const char s_szSuffInvalid[] = "-x86.dll"; +# endif +# else +# ifdef VBOX_IN_32_ON_64_MAIN_API + static const char s_szSuff[] = "-x86.so"; +#else + static const char s_szSuff[] = ".so"; + static const char s_szSuffInvalid[] = "-x86.so"; +# endif +# endif + + nsCAutoString strLeafName; + rv = component->GetNativeLeafName(strLeafName); + if (NS_FAILED(rv)) + return rv; + size_t cchLeafName = strLeafName.Length(); + if ( cchLeafName <= sizeof(s_szSuff) + || PL_strcasecmp(strLeafName.get() + cchLeafName - sizeof(s_szSuff) + 1, s_szSuff)) + { + PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG, ("Skipping '%s'...", strLeafName.get())); + return NS_OK; /* skip */ + } +# ifndef VBOX_IN_32_ON_64_MAIN_API + if ( cchLeafName >= sizeof(s_szSuffInvalid) + && !PL_strcasecmp(strLeafName.get() + cchLeafName - sizeof(s_szSuffInvalid) + 1, s_szSuffInvalid)) + { + PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG, ("Skipping '%s' (#2)...", strLeafName.get())); + return NS_OK; /* skip */ + } +# endif + PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG, ("... '%s'", strLeafName.get())); +#endif /* VBOX */ + + nsXPIDLCString persistentDescriptor; + // what I want to do here is QI for a Component Registration Manager. Since this + // has not been invented yet, QI to the obsolete manager. Kids, don't do this at home. + nsCOMPtr obsoleteManager = do_QueryInterface(mCompMgr, &rv); + if (obsoleteManager) + rv = obsoleteManager->RegistryLocationForSpec(component, + getter_Copies(persistentDescriptor)); + if (NS_FAILED(rv)) + return rv; + + nsCStringKey key(persistentDescriptor); + + // Get the registry representation of the dll, if any + nsDll *dll; + rv = CreateDll(component, persistentDescriptor, &dll); + if (NS_FAILED(rv)) + return rv; + + if (dll != NULL) + { + // We already have seen this dll. Check if this dll changed + if (!dll->HasChanged()) + { +#ifdef PR_LOGGING + nsXPIDLCString displayPath; + dll->GetDisplayPath(displayPath); + + // Dll hasn't changed. Skip. + PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG, + ("nsNativeComponentLoader: + nsDll not changed \"%s\". Skipping...", + displayPath.get())); +#endif + *registered = PR_TRUE; + return NS_OK; + } + + // Aagh! the dll has changed since the last time we saw it. + // re-register dll + + + // Notify observers, if any, of autoregistration work + nsCOMPtr observerService = + do_GetService("@mozilla.org/observer-service;1", &rv); + if (NS_SUCCEEDED(rv)) + { + nsCOMPtr mgr; + rv = NS_GetServiceManager(getter_AddRefs(mgr)); + if (NS_SUCCEEDED(rv)) + { + // this string can't come from a string bundle, because we + // don't have string bundles yet. + NS_ConvertASCIItoUCS2 fileName("(no name)"); + + // get the file name + nsCOMPtr dllSpec; + if (NS_SUCCEEDED(dll->GetDllSpec(getter_AddRefs(dllSpec))) && dllSpec) + { + dllSpec->GetLeafName(fileName); + } + + // this string can't come from a string bundle, because we + // don't have string bundles yet. + (void) observerService-> + NotifyObservers(mgr, + NS_XPCOM_AUTOREGISTRATION_OBSERVER_ID, + PromiseFlatString(NS_LITERAL_STRING("Registering native component ") + + fileName).get()); + } + } + + if (dll->IsLoaded()) + { + // We loaded the old version of the dll and now we find that the + // on-disk copy if newer. Try to unload the dll. + nsCOMPtr serviceMgr; + rv = NS_GetServiceManager(getter_AddRefs(serviceMgr)); + + rv = nsFreeLibrary(dll, serviceMgr, when); + if (NS_FAILED(rv)) + { + // THIS IS THE WORST SITUATION TO BE IN. + // Dll doesn't want to be unloaded. Cannot re-register + // this dll. +#ifdef PR_LOGGING + nsXPIDLCString displayPath; + dll->GetDisplayPath(displayPath); + + PR_LOG(nsComponentManagerLog, PR_LOG_WARNING, + ("nsNativeComponentLoader: *** Dll already loaded. " + "Cannot unload either. Hence cannot re-register " + "\"%s\". Skipping...", displayPath.get())); +#endif + return rv; + } + else { + // dll doesn't have a CanUnload proc. Guess it is + // ok to unload it. + dll->Unload(); +#ifdef PR_LOGGING + nsXPIDLCString displayPath; + dll->GetDisplayPath(displayPath); + PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG, + ("nsNativeComponentLoader: + Unloading \"%s\". (no CanUnloadProc).", + displayPath.get())); +#endif + } + + } // dll isloaded + + // Sanity. + if (dll->IsLoaded()) + { + // We went through all the above to make sure the dll + // is unloaded. And here we are with the dll still + // loaded. Whoever taught dp programming... +#ifdef PR_LOGGING + nsXPIDLCString displayPath; + dll->GetDisplayPath(displayPath); + PR_LOG(nsComponentManagerLog, PR_LOG_WARNING, + ("nsNativeComponentLoader: Dll still loaded. Cannot re-register " + "\"%s\". Skipping...", displayPath.get())); +#endif + return NS_ERROR_FAILURE; + } + } // dll != NULL + else + { + // Create and add the dll to the mDllStore + // It is ok to do this even if the creation of nsDll + // didnt succeed. That way we wont do this again + // when we encounter the same dll. + dll = new nsDll(component, this); + if (dll == NULL) + return NS_ERROR_OUT_OF_MEMORY; + mDllStore.Put(&key, (void *) dll); + } // dll == NULL + + // Either we are seeing the dll for the first time or the dll has + // changed since we last saw it and it is unloaded successfully. + // + // Now we can try register the dll for sure. + nsresult res = SelfRegisterDll(dll, persistentDescriptor, PR_FALSE); + if (NS_FAILED(res)) + { + if (res == NS_ERROR_FACTORY_REGISTER_AGAIN) { + /* defer for later loading */ + mDeferredComponents.AppendElement(dll); + *registered = PR_TRUE; + return NS_OK; + } else { +#ifdef PR_LOGGING + nsXPIDLCString displayPath; + dll->GetDisplayPath(displayPath); + + PR_LOG(nsComponentManagerLog, PR_LOG_ERROR, + ("nsNativeComponentLoader: Autoregistration FAILED for " + "\"%s\". Skipping...", displayPath.get())); +#endif + return NS_ERROR_FACTORY_NOT_REGISTERED; + } + } + else + { +#ifdef PR_LOGGING + nsXPIDLCString displayPath; + dll->GetDisplayPath(displayPath); + + PR_LOG(nsComponentManagerLog, PR_LOG_WARNING, + ("nsNativeComponentLoader: Autoregistration Passed for " + "\"%s\".", displayPath.get())); +#endif + // Marking dll along with modified time and size in the + // registry happens at PlatformRegister(). No need to do it + // here again. + *registered = PR_TRUE; + } + return NS_OK; +} + +nsresult +nsNativeComponentLoader::RegisterDeferredComponents(PRInt32 aWhen, + PRBool *aRegistered) +{ +#ifdef DEBUG + fprintf(stderr, "nNCL: registering deferred (%d)\n", + mDeferredComponents.Count()); +#endif + *aRegistered = PR_FALSE; + if (!mDeferredComponents.Count()) + return NS_OK; + + for (int i = mDeferredComponents.Count() - 1; i >= 0; i--) { + nsDll *dll = NS_STATIC_CAST(nsDll *, mDeferredComponents[i]); + nsresult rv = SelfRegisterDll(dll, + nsnull, + PR_TRUE); + if (rv != NS_ERROR_FACTORY_REGISTER_AGAIN) { + if (NS_SUCCEEDED(rv)) + *aRegistered = PR_TRUE; + mDeferredComponents.RemoveElementAt(i); + } + } +#ifdef DEBUG + if (*aRegistered) + fprintf(stderr, "nNCL: registered deferred, %d left\n", + mDeferredComponents.Count()); + else + fprintf(stderr, "nNCL: didn't register any components, %d left\n", + mDeferredComponents.Count()); +#endif + /* are there any fatal errors? */ + return NS_OK; +} + +nsresult +nsNativeComponentLoader::OnRegister(const nsIID &aCID, const char *aType, + const char *aClassName, + const char *aContractID, + const char *aLocation, + PRBool aReplace, + PRBool aPersist) +{ + return NS_OK; +} + +nsresult +nsNativeComponentLoader::UnloadAll(PRInt32 aWhen) +{ + PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG, ("nsNativeComponentLoader: Unloading....")); + + struct freeLibrariesClosure callData; + callData.serviceMgr = NULL; // XXX need to get this as a parameter + callData.when = aWhen; + + // Cycle through the dlls checking to see if they want to be unloaded + mDllStore.Enumerate(nsFreeLibraryEnum, &callData); + return NS_OK; +} + +// +// CreateDll +// The only way to create a dll or get it from the dll cache. This will +// be called in multiple situations: +// +// 1. Autoregister will create one for each dll it is trying to register. This +// call will be passing a spec in. +// {spec, NULL, 0, 0} +// +// 2. GetFactory() This will call CreateDll() with a null spec but will give +// the registry represented name of the dll. If modtime and size are zero, +// we will go the registry to find the right modtime and size. +// {NULL, rel:libpref.so, 0, 0} +// +// 3. Prepopulation of dllCache A dll object created off a registry entry. +// Specifically dll name is stored in rel: or abs: or lib: formats in the +// registry along with its lastModTime and fileSize. +// {NULL, rel:libpref.so, 8985659, 20987} +nsresult +nsNativeComponentLoader::CreateDll(nsIFile *aSpec, + const char *aLocation, + nsDll **aDll) +{ + nsDll *dll; + nsCOMPtr dllSpec; + nsCOMPtr spec; + nsresult rv; + + nsCStringKey key(aLocation); + dll = (nsDll *)mDllStore.Get(&key); + if (dll) + { + *aDll = dll; + return NS_OK; + } + + if (!aSpec) + { + // what I want to do here is QI for a Component Registration Manager. Since this + // has not been invented yet, QI to the obsolete manager. Kids, don't do this at home. + nsCOMPtr obsoleteManager = do_QueryInterface(mCompMgr, &rv); + if (obsoleteManager) + rv = obsoleteManager->SpecForRegistryLocation(aLocation, + getter_AddRefs(spec)); + if (NS_FAILED(rv)) + return rv; + } + else + { + spec = aSpec; + } + + if (!dll) + { + dll = new nsDll(spec, this); + if (!dll) + return NS_ERROR_OUT_OF_MEMORY; + } + + *aDll = dll; + mDllStore.Put(&key, dll); + return NS_OK; +} + +nsresult +nsNativeComponentLoader::GetFactoryFromModule(nsDll *aDll, const nsCID &aCID, + nsIFactory **aFactory) +{ + nsresult rv; + + nsCOMPtr module; + rv = aDll->GetModule(mCompMgr, getter_AddRefs(module)); + + if (NS_FAILED(rv)) + return rv; + + return module->GetClassObject(mCompMgr, aCID, NS_GET_IID(nsIFactory), + (void **)aFactory); +} + + +NS_IMETHODIMP +nsNativeComponentLoader::AddDependentLibrary(nsIFile* aFile, const char* libName) +{ + nsCOMPtr manager = do_QueryInterface(mCompMgr); + if (!manager) + { + NS_WARNING("Something is terribly wrong"); + return NS_ERROR_FAILURE; + } + + // the native component loader uses the optional data + // to store a space delimited list of dependent library + // names + + if (!libName) + { + manager->SetOptionalData(aFile, nsnull, nsnull); + return NS_OK; + } + + nsXPIDLCString data; + manager->GetOptionalData(aFile, nsnull, getter_Copies(data)); + + if (!data.IsEmpty()) + data.AppendLiteral(" "); + + data.Append(nsDependentCString(libName)); + + manager->SetOptionalData(aFile, nsnull, data); + return NS_OK; +} diff --git a/src/libs/xpcom18a4/xpcom/components/nsNativeComponentLoader.h b/src/libs/xpcom18a4/xpcom/components/nsNativeComponentLoader.h new file mode 100644 index 00000000..818596ec --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/components/nsNativeComponentLoader.h @@ -0,0 +1,84 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org Code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsISupports.h" +#include "nsIComponentLoader.h" +#include "nsIComponentManager.h" +#include "nsDirectoryService.h" +#include "nsCOMPtr.h" +#include "nsHashtable.h" +#include "nsVoidArray.h" +#include "xcDll.h" +#include "nsINativeComponentLoader.h" + +#ifndef nsNativeComponentLoader_h__ +#define nsNativeComponentLoader_h__ + +class nsNativeComponentLoader : public nsIComponentLoader, public nsINativeComponentLoader { + + public: + NS_DECL_ISUPPORTS + NS_DECL_NSICOMPONENTLOADER + NS_DECL_NSINATIVECOMPONENTLOADER + + nsNativeComponentLoader(); + + nsIComponentManager* mCompMgr; // weak reference -- backpointer + nsHashtable mLoadedDependentLibs; + + private: + nsObjectHashtable mDllStore; + nsVoidArray mDeferredComponents; + + ~nsNativeComponentLoader() {} + + NS_IMETHOD RegisterComponentsInDir(PRInt32 when, nsIFile *dir); + + nsresult CreateDll(nsIFile *aSpec, const char *aLocation, nsDll **aDll); + nsresult SelfRegisterDll(nsDll *dll, const char *registryLocation, + PRBool deferred); + nsresult SelfUnregisterDll(nsDll *dll); + nsresult GetFactoryFromModule(nsDll *aDll, const nsCID &aCID, + nsIFactory **aFactory); + + nsresult DumpLoadError(nsDll *dll, + const char *aCallerName, + const char *aNsprErrorMsg); +}; + +#endif /* nsNativeComponentLoader_h__ */ + diff --git a/src/libs/xpcom18a4/xpcom/components/nsObsoleteModuleLoading.h b/src/libs/xpcom18a4/xpcom/components/nsObsoleteModuleLoading.h new file mode 100644 index 00000000..da3e7a43 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/components/nsObsoleteModuleLoading.h @@ -0,0 +1,27 @@ + +#ifndef OBSOLETE_MODULE_LOADING +/* + * Prototypes for dynamic library export functions. Your DLL/DSO needs to export + * these methods to play in the component world. + * + * THIS IS OBSOLETE. Look at nsIModule.idl + */ + +extern "C" NS_EXPORT nsresult NSGetFactory(nsISupports* aServMgr, + const nsCID &aClass, + const char *aClassName, + const char *aContractID, + nsIFactory **aFactory); +extern "C" NS_EXPORT PRBool NSCanUnload(nsISupports* aServMgr); +extern "C" NS_EXPORT nsresult NSRegisterSelf(nsISupports* aServMgr, const char *fullpath); +extern "C" NS_EXPORT nsresult NSUnregisterSelf(nsISupports* aServMgr, const char *fullpath); + +typedef nsresult (*nsFactoryProc)(nsISupports* aServMgr, + const nsCID &aClass, + const char *aClassName, + const char *aContractID, + nsIFactory **aFactory); +typedef PRBool (*nsCanUnloadProc)(nsISupports* aServMgr); +typedef nsresult (*nsRegisterProc)(nsISupports* aServMgr, const char *path); +typedef nsresult (*nsUnregisterProc)(nsISupports* aServMgr, const char *path); +#endif /* OBSOLETE_MODULE_LOADING */ diff --git a/src/libs/xpcom18a4/xpcom/components/nsServiceManagerObsolete.cpp b/src/libs/xpcom18a4/xpcom/components/nsServiceManagerObsolete.cpp new file mode 100644 index 00000000..dd6856d6 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/components/nsServiceManagerObsolete.cpp @@ -0,0 +1,155 @@ +/* ***** 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 XPCOM. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsIServiceManager.h" +#include "nsIServiceManagerObsolete.h" +#include "nsComponentManager.h" + +extern PRBool gXPCOMShuttingDown; + +// Global service manager interface (see nsIServiceManagerObsolete.h) + +nsresult +nsServiceManager::GetGlobalServiceManager(nsIServiceManager* *result) +{ + if (gXPCOMShuttingDown) + return NS_ERROR_UNEXPECTED; + + if (nsComponentManagerImpl::gComponentManager == nsnull) + return NS_ERROR_UNEXPECTED; + + // this method does not addref for historical reasons. + // we return the nsIServiceManagerObsolete interface via a cast. + *result = (nsIServiceManager*) NS_STATIC_CAST(nsIServiceManagerObsolete*, + nsComponentManagerImpl::gComponentManager); + return NS_OK; +} + +nsresult +nsServiceManager::ShutdownGlobalServiceManager(nsIServiceManager* *result) +{ + return NS_OK; +} + +nsresult +nsServiceManager::GetService(const nsCID& aClass, const nsIID& aIID, + nsISupports* *result, + nsIShutdownListener* shutdownListener) +{ + + if (nsComponentManagerImpl::gComponentManager == nsnull) + return NS_ERROR_UNEXPECTED; + + return nsComponentManagerImpl::gComponentManager->GetService(aClass, aIID, (void**)result); +} + +nsresult +nsServiceManager::ReleaseService(const nsCID& aClass, nsISupports* service, + nsIShutdownListener* shutdownListener) +{ + NS_IF_RELEASE(service); + return NS_OK; +} + +nsresult +nsServiceManager::RegisterService(const nsCID& aClass, nsISupports* aService) +{ + + if (nsComponentManagerImpl::gComponentManager == nsnull) + return NS_ERROR_UNEXPECTED; + + return nsComponentManagerImpl::gComponentManager->RegisterService(aClass, aService); +} + +nsresult +nsServiceManager::UnregisterService(const nsCID& aClass) +{ + + if (nsComponentManagerImpl::gComponentManager == nsnull) + return NS_ERROR_UNEXPECTED; + + return nsComponentManagerImpl::gComponentManager->UnregisterService(aClass); +} + +//////////////////////////////////////////////////////////////////////////////// +// let's do it again, this time with ContractIDs... + +nsresult +nsServiceManager::GetService(const char* aContractID, const nsIID& aIID, + nsISupports* *result, + nsIShutdownListener* shutdownListener) +{ + + if (nsComponentManagerImpl::gComponentManager == nsnull) + return NS_ERROR_UNEXPECTED; + + return nsComponentManagerImpl::gComponentManager->GetServiceByContractID(aContractID, aIID, (void**)result); +} + +nsresult +nsServiceManager::ReleaseService(const char* aContractID, nsISupports* service, + nsIShutdownListener* shutdownListener) +{ + NS_RELEASE(service); + return NS_OK; +} + +nsresult +nsServiceManager::RegisterService(const char* aContractID, nsISupports* aService) +{ + + if (nsComponentManagerImpl::gComponentManager == nsnull) + return NS_ERROR_UNEXPECTED; + + return nsComponentManagerImpl::gComponentManager->RegisterService(aContractID, aService); +} + +nsresult +nsServiceManager::UnregisterService(const char* aContractID) +{ + // Don't create the global service manager here because we might + // be shutting down, and releasing all the services in its + // destructor + if (gXPCOMShuttingDown) + return NS_OK; + + if (nsComponentManagerImpl::gComponentManager == nsnull) + return NS_ERROR_UNEXPECTED; + + return nsComponentManagerImpl::gComponentManager->UnregisterService(aContractID); +} + diff --git a/src/libs/xpcom18a4/xpcom/components/nsStaticComponent.h b/src/libs/xpcom18a4/xpcom/components/nsStaticComponent.h new file mode 100644 index 00000000..c770afdc --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/components/nsStaticComponent.h @@ -0,0 +1,52 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * ***** 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.org Code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsIModule.h" +#include "nsModule.h" + +struct nsStaticModuleInfo { + const char *name; + nsGetModuleProc getModule; +}; + +// Must be implemented by some part of the app, if we're building the +// static component loader. +extern "C" { +typedef nsresult (PR_CALLBACK *NSGetStaticModuleInfoFunc)(nsStaticModuleInfo **info, PRUint32 *count); +extern NS_COM NSGetStaticModuleInfoFunc NSGetStaticModuleInfo; +} + diff --git a/src/libs/xpcom18a4/xpcom/components/nsStaticComponentLoader.cpp b/src/libs/xpcom18a4/xpcom/components/nsStaticComponentLoader.cpp new file mode 100644 index 00000000..b17b74bb --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/components/nsStaticComponentLoader.cpp @@ -0,0 +1,317 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * ***** 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.org Code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsStaticComponent.h" +#include "nsIComponentLoader.h" +#include "nsVoidArray.h" +#include "pldhash.h" +#include NEW_H +#include + +struct StaticModuleInfo : public PLDHashEntryHdr { + nsStaticModuleInfo info; + nsCOMPtr module; +}; + +class nsStaticComponentLoader : public nsIComponentLoader +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSICOMPONENTLOADER + + nsStaticComponentLoader() : + mAutoRegistered(PR_FALSE), mLoadedInfo(PR_FALSE) { + } + + static NS_HIDDEN_(PLDHashOperator) PR_CALLBACK + info_RegisterSelf(PLDHashTable *table, PLDHashEntryHdr *hdr, + PRUint32 number, void *arg); + +private: + ~nsStaticComponentLoader() { + if (mInfoHash.ops) + PL_DHashTableFinish(&mInfoHash); + } + +protected: + nsresult GetModuleInfo(); + nsresult GetInfoFor(const char *aLocation, StaticModuleInfo **retval); + + PRBool mAutoRegistered; + PRBool mLoadedInfo; + nsCOMPtr mComponentMgr; + PLDHashTable mInfoHash; + static PLDHashTableOps sInfoHashOps; + nsVoidArray mDeferredComponents; +}; + +PR_STATIC_CALLBACK(void) +info_ClearEntry(PLDHashTable *table, PLDHashEntryHdr *entry) +{ + StaticModuleInfo *info = NS_STATIC_CAST(StaticModuleInfo *, entry); + info->module = 0; + info->~StaticModuleInfo(); +} + +PR_STATIC_CALLBACK(PRBool) +info_InitEntry(PLDHashTable *table, PLDHashEntryHdr *entry, const void *key) +{ + // Construct so that our nsCOMPtr is zeroed, etc. + new (NS_STATIC_CAST(void *, entry)) StaticModuleInfo(); + return PR_TRUE; +} + +/* static */ PLDHashTableOps nsStaticComponentLoader::sInfoHashOps = { + PL_DHashAllocTable, PL_DHashFreeTable, + PL_DHashGetKeyStub, PL_DHashStringKey, PL_DHashMatchStringKey, + PL_DHashMoveEntryStub, info_ClearEntry, + PL_DHashFinalizeStub, info_InitEntry +}; + +NS_IMPL_THREADSAFE_ISUPPORTS1(nsStaticComponentLoader, nsIComponentLoader) + +NS_COM NSGetStaticModuleInfoFunc NSGetStaticModuleInfo; + +nsresult +nsStaticComponentLoader::GetModuleInfo() +{ + if (mLoadedInfo) + return NS_OK; + + if (!mInfoHash.ops) { // creation failed in init, why are we here? + NS_WARNING("operating on uninitialized static component loader"); + return NS_ERROR_NOT_INITIALIZED; + } + + if (! NSGetStaticModuleInfo) { + // We're a static build with no static modules to + // register. This can happen in shared uses (such as the GRE) + return NS_OK; + } + + nsStaticModuleInfo *infoList; + PRUint32 count; + nsresult rv; + if (NS_FAILED(rv = (*NSGetStaticModuleInfo)(&infoList, &count))) + return rv; + for (PRUint32 i = 0; i < count; i++) { + StaticModuleInfo *info = + NS_STATIC_CAST(StaticModuleInfo *, + PL_DHashTableOperate(&mInfoHash, infoList[i].name, + PL_DHASH_ADD)); + if (!info) + return NS_ERROR_OUT_OF_MEMORY; + info->info = infoList[i]; + } + + mLoadedInfo = PR_TRUE; + return NS_OK; +} + +nsresult +nsStaticComponentLoader::GetInfoFor(const char *aLocation, + StaticModuleInfo **retval) +{ + nsresult rv; + if (NS_FAILED(rv = GetModuleInfo())) + return rv; + + StaticModuleInfo *info = + NS_STATIC_CAST(StaticModuleInfo *, + PL_DHashTableOperate(&mInfoHash, aLocation, + PL_DHASH_LOOKUP)); + + if (PL_DHASH_ENTRY_IS_FREE(info)) + return NS_ERROR_FACTORY_NOT_REGISTERED; + + if (!info->module) { + rv = info->info.getModule(mComponentMgr, nsnull, + getter_AddRefs(info->module)); +#ifdef DEBUG + fprintf(stderr, "nSCL: GetInfoFor(\"%s\"): %x\n", aLocation, rv); +#endif + if (NS_FAILED(rv)) + return rv; + } + + *retval = info; + return NS_OK; +} + +NS_IMETHODIMP +nsStaticComponentLoader::Init(nsIComponentManager *mgr, nsISupports *aReg) +{ + mComponentMgr = mgr; + if (!PL_DHashTableInit(&mInfoHash, &sInfoHashOps, nsnull, + sizeof(StaticModuleInfo), 1024)) { + mInfoHash.ops = nsnull; + return NS_ERROR_OUT_OF_MEMORY; + } + return NS_OK; +} + +PLDHashOperator PR_CALLBACK +nsStaticComponentLoader::info_RegisterSelf(PLDHashTable *table, + PLDHashEntryHdr *hdr, + PRUint32 number, void *arg) +{ + nsStaticComponentLoader *loader = NS_STATIC_CAST(nsStaticComponentLoader *, + arg); + nsIComponentManager *mgr = loader->mComponentMgr; + StaticModuleInfo *info = NS_STATIC_CAST(StaticModuleInfo *, hdr); + + nsresult rv; + if (!info->module) { + rv = info->info.getModule(mgr, nsnull, getter_AddRefs(info->module)); +#ifdef DEBUG + fprintf(stderr, "nSCL: getModule(\"%s\"): %x\n", info->info.name, rv); +#endif + if (NS_FAILED(rv)) + return PL_DHASH_NEXT; // oh well. + } + + rv = info->module->RegisterSelf(mgr, nsnull, info->info.name, + staticComponentType); +#ifdef DEBUG + fprintf(stderr, "nSCL: autoreg of \"%s\": %x\n", info->info.name, rv); +#endif + + if (rv == NS_ERROR_FACTORY_REGISTER_AGAIN) + loader->mDeferredComponents.AppendElement(info); + + return PL_DHASH_NEXT; +} + +NS_IMETHODIMP +nsStaticComponentLoader::AutoRegisterComponents(PRInt32 when, nsIFile *dir) +{ + if (mAutoRegistered) + return NS_OK; + + // if a directory has been explicitly specified, then return early. we + // don't load static components from disk ;) + if (dir) + return NS_OK; + + nsresult rv; + if (NS_FAILED(rv = GetModuleInfo())) + return rv; + + PL_DHashTableEnumerate(&mInfoHash, info_RegisterSelf, this); + + mAutoRegistered = PR_TRUE; + return NS_OK; +} + +NS_IMETHODIMP +nsStaticComponentLoader::AutoUnregisterComponent(PRInt32 when, + nsIFile *component, + PRBool *retval) +{ + *retval = PR_FALSE; + return NS_OK; +} + +NS_IMETHODIMP +nsStaticComponentLoader::AutoRegisterComponent(PRInt32 when, nsIFile *component, + PRBool *retval) +{ + *retval = PR_FALSE; + return NS_OK; +} + +NS_IMETHODIMP +nsStaticComponentLoader::RegisterDeferredComponents(PRInt32 when, + PRBool *aRegistered) +{ + *aRegistered = PR_FALSE; + if (!mDeferredComponents.Count()) + return NS_OK; + + for (int i = mDeferredComponents.Count() - 1; i >= 0; i--) { + StaticModuleInfo *info = NS_STATIC_CAST(StaticModuleInfo *, + mDeferredComponents[i]); + nsresult rv = info->module->RegisterSelf(mComponentMgr, nsnull, + info->info.name, + staticComponentType); + if (rv != NS_ERROR_FACTORY_REGISTER_AGAIN) { + if (NS_SUCCEEDED(rv)) + *aRegistered = PR_TRUE; + mDeferredComponents.RemoveElementAt(i); + } + } + return NS_OK; +} + +NS_IMETHODIMP +nsStaticComponentLoader::OnRegister(const nsCID &aCID, const char *aType, + const char *aClassName, + const char *aContractID, + const char *aLocation, + PRBool aReplace, PRBool aPersist) +{ + return NS_OK; +} + +NS_IMETHODIMP +nsStaticComponentLoader::UnloadAll(PRInt32 aWhen) +{ + return NS_OK; +} + +NS_IMETHODIMP +nsStaticComponentLoader::GetFactory(const nsCID &aCID, const char *aLocation, + const char *aType, nsIFactory **_retval) +{ + StaticModuleInfo *info; + nsresult rv; + + if (NS_FAILED(rv = GetInfoFor(aLocation, &info))) + return rv; + + return info->module->GetClassObject(mComponentMgr, aCID, + NS_GET_IID(nsIFactory), + (void **)_retval); +} + +nsresult +NS_NewStaticComponentLoader(nsIComponentLoader **retval) +{ + NS_IF_ADDREF(*retval = NS_STATIC_CAST(nsIComponentLoader *, + new nsStaticComponentLoader)); + return *retval ? NS_OK : NS_ERROR_OUT_OF_MEMORY; +} diff --git a/src/libs/xpcom18a4/xpcom/components/xcDll.cpp b/src/libs/xpcom18a4/xpcom/components/xcDll.cpp new file mode 100644 index 00000000..494cf174 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/components/xcDll.cpp @@ -0,0 +1,457 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* nsDll + * + * Abstraction of a Dll. Stores modifiedTime and size for easy detection of + * change in dll. + * + * dp Suresh + */ + +#include "xcDll.h" +#include "nsDebug.h" +#include "nsIComponentManager.h" +#include "nsIComponentLoaderManager.h" +#include "nsIModule.h" +#include "nsILocalFile.h" +#include "nsDirectoryServiceDefs.h" +#include "nsDirectoryServiceUtils.h" +#include "nsCOMPtr.h" +#include "nsCRT.h" +#include "nsString.h" +#include "nsITimelineService.h" +#include "nsModule.h" +#ifdef DEBUG +#if defined(VMS) +#include +#include +#elif defined(XP_MACOSX) +#include +#endif +#endif /* defined(DEBUG) */ + +#include "nsTraceRefcntImpl.h" + +#define UNLOAD_DEPENDENT_LIBS +#ifdef HPUX +#undef UNLOAD_DEPENDENT_LIBS +#endif + +#include "nsNativeComponentLoader.h" +#ifdef VBOX_USE_IPRT_IN_XPCOM +# include "nsMemory.h" +#endif + +nsDll::nsDll(nsIFile *dllSpec, nsNativeComponentLoader *loader) + : m_dllSpec(do_QueryInterface(dllSpec)), + m_instance(NULL), + m_moduleObject(NULL), + m_loader(loader), + m_markForUnload(PR_FALSE) +{ + NS_ASSERTION(loader, "Null loader when creating a nsDLL"); +} + +nsDll::~nsDll(void) +{ + //#if DEBUG_dougt + // The dll gets deleted when the dllStore is destroyed. This happens on + // app shutdown. At that point, unloading dlls can cause crashes if we have + // - dll dependencies + // - callbacks + // - static dtors + // Hence turn it back on after all the above have been removed. + //Unload(); + //#endif +} + +void +nsDll::GetDisplayPath(nsACString& aLeafName) +{ + m_dllSpec->GetNativeLeafName(aLeafName); + + if (aLeafName.IsEmpty()) + aLeafName.AssignLiteral("unknown!"); +} + +PRBool +nsDll::HasChanged() +{ + nsCOMPtr manager = do_QueryInterface(m_loader->mCompMgr); + if (!manager) + return PR_TRUE; + + // If mod date has changed, then dll has changed + PRInt64 currentDate; + nsresult rv = m_dllSpec->GetLastModifiedTime(¤tDate); + if (NS_FAILED(rv)) + return PR_TRUE; + PRBool changed = PR_TRUE; + manager->HasFileChanged(m_dllSpec, nsnull, currentDate, &changed); + return changed; +} + +PRBool nsDll::Load(void) +{ + if (m_instance != NULL) + { + // Already loaded + return (PR_TRUE); + } + + if (m_dllSpec) + { +#ifdef NS_BUILD_REFCNT_LOGGING + nsTraceRefcntImpl::SetActivityIsLegal(PR_FALSE); +#endif + + // Load any library dependencies + // The Component Loader Manager may hold onto some extra data + // set by either the native component loader or the native + // component. We assume that this data is a space delimited + // listing of dependent libraries which are required to be + // loaded prior to us loading the given component. Once, the + // component is loaded into memory, we can release our hold + // on the dependent libraries with the assumption that the + // component library holds a reference via the OS so loader. + +#if defined(XP_UNIX) + nsCOMPtr manager = do_QueryInterface(m_loader->mCompMgr); + if (!manager) + return PR_TRUE; + + nsXPIDLCString extraData; + manager->GetOptionalData(m_dllSpec, nsnull, getter_Copies(extraData)); + +#ifdef UNLOAD_DEPENDENT_LIBS + nsVoidArray dependentLibArray; +#endif + + // if there was any extra data, treat it as a listing of dependent libs + if (extraData != nsnull) + { + // all dependent libraries are suppose to be in the "gre" directory. + // note that the gre directory is the same as the "bin" directory, + // when there isn't a real "gre" found. + + nsXPIDLCString path; + nsCOMPtr file; + NS_GetSpecialDirectory(NS_GRE_DIR, getter_AddRefs(file)); + + if (!file) + return NS_ERROR_FAILURE; + + // we are talking about a file in the GRE dir. Lets append something + // stupid right now, so that later we can just set the leaf name. + file->AppendNative(NS_LITERAL_CSTRING("dummy")); + +# ifdef VBOX_USE_IPRT_IN_XPCOM + char *buffer = (char *)nsMemory::Clone(extraData, strlen(extraData) + 1); +# else + char *buffer = strdup(extraData); +# endif + if (!buffer) + return NS_ERROR_OUT_OF_MEMORY; + + char* newStr; + char *token = nsCRT::strtok(buffer, " ", &newStr); + while (token!=nsnull) + { + nsCStringKey key(token); + if (m_loader->mLoadedDependentLibs.Get(&key)) { + token = nsCRT::strtok(newStr, " ", &newStr); + continue; + } + + m_loader->mLoadedDependentLibs.Put(&key, (void*)1); + + nsXPIDLCString libpath; + file->SetNativeLeafName(nsDependentCString(token)); + file->GetNativePath(path); + if (!path) + return NS_ERROR_FAILURE; + + // Load this dependent library with the global flag and stash + // the result for later so that we can unload it. + PRLibSpec libSpec; + libSpec.type = PR_LibSpec_Pathname; + + // if the depend library path starts with a / we are + // going to assume that it is a full path and should + // be loaded without prepending the gre diretory + // location. We could have short circuited the + // SetNativeLeafName above, but this is clearer and + // the common case is a relative path. + + if (token[0] == '/') + libSpec.value.pathname = token; + else + libSpec.value.pathname = path; + + PRLibrary* lib = PR_LoadLibraryWithFlags(libSpec, PR_LD_LAZY|PR_LD_GLOBAL); + // if we couldn't load the dependent library. We did the best we + // can. Now just let us fail later if this really was a required + // dependency. +#ifdef UNLOAD_DEPENDENT_LIBS + if (lib) + dependentLibArray.AppendElement((void*)lib); +#endif + + token = nsCRT::strtok(newStr, " ", &newStr); + } +# ifdef VBOX_USE_IPRT_IN_XPCOM + nsMemory::Free(buffer); +# else + free(buffer); +# endif + } +#endif + + // load the component + nsCOMPtr lf(do_QueryInterface(m_dllSpec)); + NS_ASSERTION(lf, "nsIFile here must implement a nsILocalFile"); + lf->Load(&m_instance); + +#if defined(XP_UNIX) + // Unload any of library dependencies we loaded earlier. The assumption + // here is that the component will have a "internal" reference count to + // the dependency library we just loaded. + // XXX should we unload later - or even at all? + +#ifdef UNLOAD_DEPENDENT_LIBS + if (extraData != nsnull) + { + PRInt32 arrayCount = dependentLibArray.Count(); + for (PRInt32 index = 0; index < arrayCount; index++) + PR_UnloadLibrary((PRLibrary*)dependentLibArray.ElementAt(index)); + } +#endif +#endif + +#ifdef NS_BUILD_REFCNT_LOGGING + nsTraceRefcntImpl::SetActivityIsLegal(PR_TRUE); + if (m_instance) { + // Inform refcnt tracer of new library so that calls through the + // new library can be traced. + nsXPIDLCString displayPath; + GetDisplayPath(displayPath); + nsTraceRefcntImpl::LoadLibrarySymbols(displayPath.get(), m_instance); + } +#endif + } + +#ifdef SHOULD_IMPLEMENT_BREAKAFTERLOAD + // Debugging help for components. Component dlls need to have their + // symbols loaded before we can put a breakpoint in the debugger. + // This will help figureing out the point when the dll was loaded. + nsXPIDLCString displayPath; + GetDisplayPath(displayPath); + BreakAfterLoad(displayPath.get()); +#endif + + return ((m_instance == NULL) ? PR_FALSE : PR_TRUE); +} + +PRBool nsDll::Unload(void) +{ + if (m_instance == NULL) + return (PR_FALSE); + + // Shutdown the dll + Shutdown(); + +#ifdef NS_BUILD_REFCNT_LOGGING + nsTraceRefcntImpl::SetActivityIsLegal(PR_FALSE); +#endif + PRStatus ret = PR_UnloadLibrary(m_instance); +#ifdef NS_BUILD_REFCNT_LOGGING + nsTraceRefcntImpl::SetActivityIsLegal(PR_TRUE); +#endif + + if (ret == PR_SUCCESS) + { + m_instance = NULL; + return (PR_TRUE); + } + else + return (PR_FALSE); +} + +void * nsDll::FindSymbol(const char *symbol) +{ + if (symbol == NULL) + return (NULL); + + // If not already loaded, load it now. + if (Load() != PR_TRUE) + return (NULL); + + return(PR_FindSymbol(m_instance, symbol)); +} + + +// Component dll specific functions +nsresult nsDll::GetDllSpec(nsIFile **fsobj) +{ + NS_ASSERTION(m_dllSpec, "m_dllSpec NULL"); + NS_ASSERTION(fsobj, "xcDll::GetModule : Null argument" ); + + *fsobj = m_dllSpec; + NS_ADDREF(*fsobj); + return NS_OK; +} + +nsresult nsDll::GetModule(nsISupports *servMgr, nsIModule **cobj) +{ + // using the backpointer of the loader. + nsIComponentManager* compMgr = m_loader->mCompMgr; + NS_ASSERTION(compMgr, "Global Component Manager is null" ); + if (!compMgr) return NS_ERROR_UNEXPECTED; + + NS_ASSERTION(cobj, "xcDll::GetModule : Null argument" ); + + if (m_moduleObject) + { + NS_ADDREF(m_moduleObject); + *cobj = m_moduleObject; + return NS_OK; + } + + // If not already loaded, load it now. + if (Load() != PR_TRUE) return NS_ERROR_FAILURE; + + // We need a nsIFile for location + if (!m_dllSpec) + { + return NS_ERROR_FAILURE; + } + + nsGetModuleProc proc = + (nsGetModuleProc) FindSymbol(NS_GET_MODULE_SYMBOL); + + if (proc == NULL) + return NS_ERROR_FACTORY_NOT_LOADED; + + nsresult rv = (*proc) (compMgr, m_dllSpec, &m_moduleObject); + if (NS_SUCCEEDED(rv)) + { + NS_ADDREF(m_moduleObject); + *cobj = m_moduleObject; + } + return rv; +} + + +// These are used by BreakAfterLoad, below. +#ifdef SHOULD_IMPLEMENT_BREAKAFTERLOAD +static nsCString *sBreakList[16]; +static int sBreakListCount = 0; +#endif + +nsresult nsDll::Shutdown(void) +{ + // Release the module object if we got one + nsrefcnt refcnt; + if (m_moduleObject) + { + NS_RELEASE2(m_moduleObject, refcnt); + NS_ASSERTION(refcnt == 0, "Dll moduleObject refcount non zero"); + } +#ifdef SHOULD_IMPLEMENT_BREAKAFTERLOAD + for (int i = 0; i < sBreakListCount; i++) + { + delete sBreakList[i]; + sBreakList[i] = nsnull; + } + sBreakListCount = 0; +#endif + return NS_OK; + +} +#ifdef SHOULD_IMPLEMENT_BREAKAFTERLOAD +void nsDll::BreakAfterLoad(const char *nsprPath) +{ + static PRBool firstTime = PR_TRUE; + + // return if invalid input + if (!nsprPath || !*nsprPath) return; + + // return if nothing to break on + if (!firstTime && sBreakListCount == 0) return; + + if (firstTime) + { + firstTime = PR_FALSE; + // Form the list of dlls to break on load + nsCAutoString envList(getenv("XPCOM_BREAK_ON_LOAD")); + if (envList.IsEmpty()) return; + PRInt32 ofset = 0; + PRInt32 start = 0; + do + { + ofset = envList.FindChar(':', start); + sBreakList[sBreakListCount] = new nsCString(); + envList.Mid(*(sBreakList[sBreakListCount]), start, ofset); + sBreakListCount++; + start = ofset + 1; + } + while (ofset != -1 && 16 > sBreakListCount); // avoiding vc6.0 compiler issue. count < thinks it is starting a template + } + + // Find the dllname part of the string + nsCString currentPath(nsprPath); + PRInt32 lastSep = currentPath.RFindCharInSet(":\\/"); + + for (int i=0; i 0) + { + // Loading a dll that we want to break on + // Put your breakpoint here + fprintf(stderr, "...Loading module %s\n", nsprPath); + // Break in the debugger here. +#if defined(__i386) && defined(__GNUC__) + asm("int $3"); +#elif defined(VMS) + lib$signal(SS$_DEBUG); +#elif defined(XP_MACOSX) + raise(SIGTRAP); +#endif + } + return; +} +#endif /* SHOULD_IMPLEMENT_BREAKAFTERLOAD */ diff --git a/src/libs/xpcom18a4/xpcom/components/xcDll.h b/src/libs/xpcom18a4/xpcom/components/xcDll.h new file mode 100644 index 00000000..5de5b0eb --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/components/xcDll.h @@ -0,0 +1,121 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Dll + * + * Programmatic representation of a dll. Stores modifiedTime and size for + * easy detection of change in dll. + * + * dp Suresh + */ + +#ifndef xcDll_h__ +#define xcDll_h__ + +#include "prio.h" +#include "prlink.h" +#include "nsISupports.h" +#include "nsILocalFile.h" +#include "nsCOMPtr.h" +#include "nsString.h" + +class nsNativeComponentLoader; + +#if defined(DEBUG) && !defined(XP_BEOS) +#define SHOULD_IMPLEMENT_BREAKAFTERLOAD +#endif + +class nsIModule; +class nsIServiceManager; + +typedef enum nsDllStatus +{ + DLL_OK = 0, + DLL_NO_MEM = 1, + DLL_STAT_ERROR = 2, + DLL_NOT_FILE = 3, + DLL_INVALID_PARAM = 4 +} nsDllStatus; + +class nsDll +{ +private: + nsCOMPtr m_dllSpec; + PRLibrary *m_instance; + nsIModule *m_moduleObject; + nsNativeComponentLoader *m_loader; + PRBool m_markForUnload; + + void Init(nsIFile *dllSpec); + +#ifdef SHOULD_IMPLEMENT_BREAKAFTERLOAD + void BreakAfterLoad(const char *nsprPath); +#endif + +public: + + nsDll(nsIFile *dllSpec, nsNativeComponentLoader* loader); + ~nsDll(void); + + // Dll Loading + PRBool Load(void); + PRBool Unload(void); + PRBool IsLoaded(void) + { + return ((m_instance != 0) ? PR_TRUE : PR_FALSE); + } + void MarkForUnload(PRBool mark) { m_markForUnload = mark; } + PRBool IsMarkedForUnload(void) { return m_markForUnload; } + + // Shutdown the dll. This will call any on unload hook for the dll. + // This wont unload the dll. Unload() implicitly calls Shutdown(). + nsresult Shutdown(void); + + void *FindSymbol(const char *symbol); + + PRBool HasChanged(void); + + void GetDisplayPath(nsACString& string); + + PRLibrary *GetInstance(void) { return (m_instance); } + + // NS_RELEASE() is required to be done on objects returned + nsresult GetDllSpec(nsIFile **dllSpec); + nsresult GetModule(nsISupports *servMgr, nsIModule **mobj); +}; + +#endif /* xcDll_h__ */ diff --git a/src/libs/xpcom18a4/xpcom/doc/README b/src/libs/xpcom18a4/xpcom/doc/README new file mode 100644 index 00000000..edef8772 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/doc/README @@ -0,0 +1,8 @@ + + + READ ME + + + +

+XPCOM documentation can be found at + * + * 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 "nsArray.h" +#include "nsArrayEnumerator.h" +#include "nsWeakReference.h" + +// used by IndexOf() +struct findIndexOfClosure +{ + nsISupports *targetElement; + PRUint32 startIndex; + PRUint32 resultIndex; +}; + +PR_STATIC_CALLBACK(PRBool) FindElementCallback(void* aElement, void* aClosure); + + +NS_IMPL_ISUPPORTS2(nsArray, nsIArray, nsIMutableArray) + +nsArray::~nsArray() +{ + Clear(); +} + +NS_IMETHODIMP +nsArray::GetLength(PRUint32* aLength) +{ + *aLength = mArray.Count(); + return NS_OK; +} + +NS_IMETHODIMP +nsArray::QueryElementAt(PRUint32 aIndex, + const nsIID& aIID, + void ** aResult) +{ + nsISupports * obj = mArray.ObjectAt(aIndex); + if (!obj) return NS_ERROR_UNEXPECTED; + + // no need to worry about a leak here, because ObjectAt() doesn't + // addref its result + return obj->QueryInterface(aIID, aResult); +} + +NS_IMETHODIMP +nsArray::IndexOf(PRUint32 aStartIndex, nsISupports* aElement, + PRUint32* aResult) +{ + // optimize for the common case by forwarding to mArray + if (aStartIndex == 0) { + *aResult = mArray.IndexOf(aElement); + if (*aResult == -1) + return NS_ERROR_FAILURE; + return NS_OK; + } + + findIndexOfClosure closure = { aElement, aStartIndex, 0 }; + PRBool notFound = mArray.EnumerateForwards(FindElementCallback, &closure); + if (notFound) + return NS_ERROR_FAILURE; + + *aResult = closure.resultIndex; + return NS_OK; +} + +NS_IMETHODIMP +nsArray::Enumerate(nsISimpleEnumerator **aResult) +{ + return NS_NewArrayEnumerator(aResult, NS_STATIC_CAST(nsIArray*, this)); +} + +// nsIMutableArray implementation + +NS_IMETHODIMP +nsArray::AppendElement(nsISupports* aElement, PRBool aWeak) +{ + PRBool result; + if (aWeak) { + nsCOMPtr elementRef = + getter_AddRefs(NS_STATIC_CAST(nsISupports*, + NS_GetWeakReference(aElement))); + NS_ASSERTION(elementRef, "AppendElement: Trying to use weak references on an object that doesn't support it"); + if (!elementRef) + return NS_ERROR_FAILURE; + result = mArray.AppendObject(elementRef); + } + + else { + // add the object directly + result = mArray.AppendObject(aElement); + } + return result ? NS_OK : NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +nsArray::RemoveElementAt(PRUint32 aIndex) +{ + PRBool result = mArray.RemoveObjectAt(aIndex); + return result ? NS_OK : NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +nsArray::InsertElementAt(nsISupports* aElement, PRUint32 aIndex, PRBool aWeak) +{ + nsCOMPtr elementRef; + if (aWeak) { + elementRef = + getter_AddRefs(NS_STATIC_CAST(nsISupports*, + NS_GetWeakReference(aElement))); + NS_ASSERTION(elementRef, "InsertElementAt: Trying to use weak references on an object that doesn't support it"); + if (!elementRef) + return NS_ERROR_FAILURE; + } else { + elementRef = aElement; + } + PRBool result = mArray.InsertObjectAt(elementRef, aIndex); + return result ? NS_OK : NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +nsArray::Clear() +{ + mArray.Clear(); + return NS_OK; +} + +// +// static helper routines +// +PRBool +FindElementCallback(void *aElement, void* aClosure) +{ + findIndexOfClosure* closure = + NS_STATIC_CAST(findIndexOfClosure*, aClosure); + + nsISupports* element = + NS_STATIC_CAST(nsISupports*, aElement); + + // don't start searching until we're past the startIndex + if (closure->resultIndex >= closure->startIndex && + element == closure->targetElement) { + return PR_FALSE; // stop! We found it + } + closure->resultIndex++; + + return PR_TRUE; +} + +// +// do_QueryElementAt helper stuff +// +nsresult +nsQueryArrayElementAt::operator()(const nsIID& aIID, void** aResult) const + { + nsresult status = mArray + ? mArray->QueryElementAt(mIndex, aIID, aResult) + : NS_ERROR_NULL_POINTER; + + if (mErrorPtr) + *mErrorPtr = status; + + return status; + } + +// +// exported constructor routines +// +nsresult +NS_NewArray(nsIMutableArray** aResult) +{ + nsArray* arr = new nsArray; + if (!arr) return NS_ERROR_OUT_OF_MEMORY; + + *aResult = NS_STATIC_CAST(nsIMutableArray*,arr); + NS_ADDREF(*aResult); + + return NS_OK; +} + +nsresult +NS_NewArray(nsIMutableArray** aResult, const nsCOMArray_base& aBaseArray) +{ + nsArray* arr = new nsArray(aBaseArray); + if (!arr) return NS_ERROR_OUT_OF_MEMORY; + + *aResult = NS_STATIC_CAST(nsIMutableArray*, arr); + NS_ADDREF(*aResult); + + return NS_OK; +} diff --git a/src/libs/xpcom18a4/xpcom/ds/nsArray.h b/src/libs/xpcom18a4/xpcom/ds/nsArray.h new file mode 100644 index 00000000..4a4f6cf2 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsArray.h @@ -0,0 +1,118 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 XPCOM Array implementation. + * + * The Initial Developer of the Original Code + * Netscape Communications Corp. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Alec Flett + * + * 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 ***** */ + +#ifndef nsArray_h__ +#define nsArray_h__ + +#include "nsIArray.h" +#include "nsCOMArray.h" +#include "nsCOMPtr.h" + +#define NS_ARRAY_CLASSNAME \ + "nsIArray implementation" + +// {35C66FD1-95E9-4e0a-80C5-C3BD2B375481} +#define NS_ARRAY_CID \ +{ 0x35c66fd1, 0x95e9, 0x4e0a, \ + { 0x80, 0xc5, 0xc3, 0xbd, 0x2b, 0x37, 0x54, 0x81 } } + + +// create a new, empty array +nsresult NS_COM +NS_NewArray(nsIMutableArray** aResult); + +// The resulting array will hold an owning reference to every element +// in the original nsCOMArray. This also means that any further +// changes to the original nsCOMArray will not affect the new +// array, and that the original array can go away and the new array +// will still hold valid elements. +nsresult NS_COM +NS_NewArray(nsIMutableArray** aResult, const nsCOMArray_base& base); + +// adapter class to map nsIArray->nsCOMArray +// do NOT declare this as a stack or member variable, use +// nsCOMArray instead! +// if you need to convert a nsCOMArray->nsIArray, see NS_NewArray above +class nsArray : public nsIMutableArray +{ +public: + nsArray() { } + nsArray(const nsCOMArray_base& aBaseArray) : mArray(aBaseArray) + { } + + NS_DECL_ISUPPORTS + NS_DECL_NSIARRAY + NS_DECL_NSIMUTABLEARRAY + +private: + ~nsArray(); + + nsCOMArray_base mArray; +}; + + +// helper class for do_QueryElementAt +class NS_COM nsQueryArrayElementAt : public nsCOMPtr_helper + { + public: + nsQueryArrayElementAt(nsIArray* aArray, PRUint32 aIndex, + nsresult* aErrorPtr) + : mArray(aArray), + mIndex(aIndex), + mErrorPtr(aErrorPtr) + { + // nothing else to do here + } + + virtual nsresult NS_FASTCALL operator()(const nsIID& aIID, void**) const; + + private: + nsIArray* mArray; + PRUint32 mIndex; + nsresult* mErrorPtr; + }; + +inline +const nsQueryArrayElementAt +do_QueryElementAt(nsIArray* aArray, PRUint32 aIndex, nsresult* aErrorPtr = 0) + { + return nsQueryArrayElementAt(aArray, aIndex, aErrorPtr); + } + + +#endif diff --git a/src/libs/xpcom18a4/xpcom/ds/nsArrayEnumerator.cpp b/src/libs/xpcom18a4/xpcom/ds/nsArrayEnumerator.cpp new file mode 100644 index 00000000..c105622a --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsArrayEnumerator.cpp @@ -0,0 +1,210 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 XPCOM Array implementation. + * + * The Initial Developer of the Original Code + * Netscape Communications Corp. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Alec Flett + * + * 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 "nsArrayEnumerator.h" + +NS_IMPL_ISUPPORTS1(nsSimpleArrayEnumerator, nsISimpleEnumerator) + +NS_IMETHODIMP +nsSimpleArrayEnumerator::HasMoreElements(PRBool* aResult) +{ + NS_PRECONDITION(aResult != 0, "null ptr"); + if (! aResult) + return NS_ERROR_NULL_POINTER; + + if (!mValueArray) { + *aResult = PR_FALSE; + return NS_OK; + } + + PRUint32 cnt; + nsresult rv = mValueArray->GetLength(&cnt); + if (NS_FAILED(rv)) return rv; + *aResult = (mIndex < cnt); + return NS_OK; +} + +NS_IMETHODIMP +nsSimpleArrayEnumerator::GetNext(nsISupports** aResult) +{ + NS_PRECONDITION(aResult != 0, "null ptr"); + if (! aResult) + return NS_ERROR_NULL_POINTER; + + if (!mValueArray) { + *aResult = nsnull; + return NS_OK; + } + + PRUint32 cnt; + nsresult rv = mValueArray->GetLength(&cnt); + if (NS_FAILED(rv)) return rv; + if (mIndex >= cnt) + return NS_ERROR_UNEXPECTED; + + return mValueArray->QueryElementAt(mIndex++, NS_GET_IID(nsISupports), (void**)aResult); +} + +extern NS_COM nsresult +NS_NewArrayEnumerator(nsISimpleEnumerator* *result, + nsIArray* array) +{ + nsSimpleArrayEnumerator* enumer = new nsSimpleArrayEnumerator(array); + if (enumer == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + + NS_ADDREF(*result = enumer); + return NS_OK; +} + +//////////////////////////////////////////////////////////////////////////////// + +// enumerator implementation for nsCOMArray +// creates a snapshot of the array in question +// you MUST use NS_NewArrayEnumerator to create this, so that +// allocation is done correctly +class nsCOMArrayEnumerator : public nsISimpleEnumerator +{ +public: + // nsISupports interface + NS_DECL_ISUPPORTS + + // nsISimpleEnumerator interface + NS_DECL_NSISIMPLEENUMERATOR + + // nsSimpleArrayEnumerator methods + nsCOMArrayEnumerator() : mIndex(0) { + } + + // specialized operator to make sure we make room for mValues + void* operator new (size_t size, const nsCOMArray_base& aArray) CPP_THROW_NEW; + void operator delete(void* ptr) { + ::operator delete(ptr); + } + +private: + ~nsCOMArrayEnumerator(void); + +protected: + PRUint32 mIndex; // current position + PRUint32 mArraySize; // size of the array + + // this is actually bigger + nsISupports* mValueArray[1]; +}; + +NS_IMPL_ISUPPORTS1(nsCOMArrayEnumerator, nsISimpleEnumerator) + +nsCOMArrayEnumerator::~nsCOMArrayEnumerator() +{ + // only release the entries that we haven't visited yet + for (; mIndex < mArraySize; ++mIndex) { + NS_IF_RELEASE(mValueArray[mIndex]); + } +} + +NS_IMETHODIMP +nsCOMArrayEnumerator::HasMoreElements(PRBool* aResult) +{ + NS_PRECONDITION(aResult != 0, "null ptr"); + if (! aResult) + return NS_ERROR_NULL_POINTER; + + *aResult = (mIndex < mArraySize); + return NS_OK; +} + +NS_IMETHODIMP +nsCOMArrayEnumerator::GetNext(nsISupports** aResult) +{ + NS_PRECONDITION(aResult != 0, "null ptr"); + if (! aResult) + return NS_ERROR_NULL_POINTER; + + if (mIndex >= mArraySize) + return NS_ERROR_UNEXPECTED; + + // pass the ownership of the reference to the caller. Since + // we AddRef'ed during creation of |this|, there is no need + // to AddRef here + *aResult = mValueArray[mIndex++]; + + // this really isn't necessary. just pretend this happens, since + // we'll never visit this value again! + // mValueArray[(mIndex-1)] = nsnull; + + return NS_OK; +} + +void* +nsCOMArrayEnumerator::operator new (size_t size, const nsCOMArray_base& aArray) + CPP_THROW_NEW +{ + // create enough space such that mValueArray points to a large + // enough value. Note that the initial value of size gives us + // space for mValueArray[0], so we must subtract + size += (aArray.Count() - 1) * sizeof(aArray[0]); + + // do the actual allocation + nsCOMArrayEnumerator * result = + NS_STATIC_CAST(nsCOMArrayEnumerator*, ::operator new(size)); + + // now need to copy over the values, and addref each one + // now this might seem like alot of work, but we're actually just + // doing all our AddRef's ahead of time since GetNext() doesn't + // need to AddRef() on the way out + PRUint32 i; + PRUint32 max = result->mArraySize = aArray.Count(); + for (i = 0; imValueArray[i] = aArray[i]; + NS_IF_ADDREF(result->mValueArray[i]); + } + + return result; +} + +extern NS_COM nsresult +NS_NewArrayEnumerator(nsISimpleEnumerator* *aResult, + const nsCOMArray_base& aArray) +{ + nsCOMArrayEnumerator *enumerator = new (aArray) nsCOMArrayEnumerator(); + if (!enumerator) return NS_ERROR_OUT_OF_MEMORY; + + NS_ADDREF(*aResult = enumerator); + return NS_OK; +} diff --git a/src/libs/xpcom18a4/xpcom/ds/nsArrayEnumerator.h b/src/libs/xpcom18a4/xpcom/ds/nsArrayEnumerator.h new file mode 100644 index 00000000..e22302b5 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsArrayEnumerator.h @@ -0,0 +1,87 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 XPCOM Array implementation. + * + * The Initial Developer of the Original Code + * Netscape Communications Corp. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Alec Flett + * + * 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 ***** */ + +#ifndef nsArrayEnumerator_h__ +#define nsArrayEnumerator_h__ + +// enumerator implementation for nsIArray + +#include "nsIArray.h" +#include "nsCOMArray.h" +#include "nsISimpleEnumerator.h" +#include "nsCOMPtr.h" + +class nsSimpleArrayEnumerator : public nsISimpleEnumerator +{ +public: + // nsISupports interface + NS_DECL_ISUPPORTS + + // nsISimpleEnumerator interface + NS_DECL_NSISIMPLEENUMERATOR + + // nsSimpleArrayEnumerator methods + nsSimpleArrayEnumerator(nsIArray* aValueArray) : + mValueArray(aValueArray), mIndex(0) { + } + +private: + ~nsSimpleArrayEnumerator() {} + +protected: + nsCOMPtr mValueArray; + PRUint32 mIndex; +}; + + +// Create an enumerator for an existing nsIArray implementation +// The enumerator holds an owning reference to the array. +extern NS_COM nsresult +NS_NewArrayEnumerator(nsISimpleEnumerator* *result, + nsIArray* array); + + +// create an enumerator for an existing nsCOMArray implementation +// The enumerator will hold an owning reference to each ELEMENT in +// the array. This means that the nsCOMArray can safely go away +// without its objects going away. +extern NS_COM nsresult +NS_NewArrayEnumerator(nsISimpleEnumerator* *aResult, + const nsCOMArray_base& aArray); + +#endif diff --git a/src/libs/xpcom18a4/xpcom/ds/nsAtomService.cpp b/src/libs/xpcom18a4/xpcom/ds/nsAtomService.cpp new file mode 100644 index 00000000..f0366043 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsAtomService.cpp @@ -0,0 +1,67 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Alec Flett + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsAtomService.h" + +NS_IMPL_THREADSAFE_ISUPPORTS1(nsAtomService, nsIAtomService) + +nsAtomService::nsAtomService() +{ +} + +nsresult +nsAtomService::GetAtom(const PRUnichar *aString, nsIAtom ** aResult) +{ + *aResult = NS_NewAtom(aString); + + if (!*aResult) + return NS_ERROR_OUT_OF_MEMORY; + + return NS_OK; +} + +nsresult +nsAtomService::GetPermanentAtom(const PRUnichar *aString, nsIAtom ** aResult) +{ + *aResult = NS_NewPermanentAtom(aString); + + if (!*aResult) + return NS_ERROR_OUT_OF_MEMORY; + + return NS_OK; +} diff --git a/src/libs/xpcom18a4/xpcom/ds/nsAtomService.h b/src/libs/xpcom18a4/xpcom/ds/nsAtomService.h new file mode 100644 index 00000000..ae036b80 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsAtomService.h @@ -0,0 +1,56 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Alec Flett + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +#ifndef __nsAtomService_h +#define __nsAtomService_h + +#include "nsIAtomService.h" + +class nsAtomService : public nsIAtomService +{ + public: + nsAtomService(); + NS_DECL_ISUPPORTS + + NS_DECL_NSIATOMSERVICE + + private: + ~nsAtomService() {} +}; + +#endif diff --git a/src/libs/xpcom18a4/xpcom/ds/nsAtomTable.cpp b/src/libs/xpcom18a4/xpcom/ds/nsAtomTable.cpp new file mode 100644 index 00000000..fc92dec8 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsAtomTable.cpp @@ -0,0 +1,616 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +// vim:cindent:ts=2:et:sw=2: +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsAtomTable.h" +#include "nsStaticAtom.h" +#include "nsString.h" +#include "nsReadableUtils.h" +#include "nsCRT.h" +#include "pldhash.h" +#include "prenv.h" +#include "nsVoidArray.h" + +#define PL_ARENA_CONST_ALIGN_MASK 3 +#include "plarena.h" + +class nsStaticAtomWrapper; + +/** + * The shared hash table for atom lookups. + * + * XXX This should be manipulated in a threadsafe way or we should make + * sure it's only manipulated from the main thread. Probably the latter + * is better, since the former would hurt performance. + * + * If |gAtomTable.ops| is 0, then the table is uninitialized. + */ +static PLDHashTable gAtomTable; + +// this is where we keep the nsStaticAtomWrapper objects + +static PLArenaPool* gStaticAtomArena = 0; + +class nsStaticAtomWrapper : public nsIAtom +{ +public: + nsStaticAtomWrapper(const nsStaticAtom* aAtom) : + mStaticAtom(aAtom) + { + MOZ_COUNT_CTOR(nsStaticAtomWrapper); + } + ~nsStaticAtomWrapper() { // no subclasses -> not virtual + // this is arena allocated and won't be called except in debug + // builds. If this function ever does anything non-debug, be sure + // to get rid of the ifdefs in AtomTableClearEntry! + MOZ_COUNT_DTOR(nsStaticAtomWrapper); + } + + NS_IMETHOD QueryInterface(REFNSIID aIID, + void** aInstancePtr); + NS_IMETHOD_(nsrefcnt) AddRef(void); + NS_IMETHOD_(nsrefcnt) Release(void); + + NS_DECL_NSIATOM + + const nsStaticAtom* GetStaticAtom() { + return mStaticAtom; + } +private: + const nsStaticAtom* mStaticAtom; +}; + +// the atomtableentry can contain either an AtomImpl or a +// nsStaticAtomWrapper, indicated by the first bit of PtrBits +typedef unsigned long PtrBits; + +struct AtomTableEntry : public PLDHashEntryHdr { + // mAtom & 0x1 means (mAtom & ~0x1) points to an nsStaticAtomWrapper + // else it points to an nsAtomImpl + PtrBits mAtom; + + inline PRBool IsStaticAtom() const { + return (mAtom & 0x1) != 0; + } + + inline void SetAtomImpl(AtomImpl* aAtom) { + NS_ASSERTION(aAtom, "Setting null atom"); + mAtom = PtrBits(aAtom); + } + + inline void SetStaticAtomWrapper(nsStaticAtomWrapper* aAtom) { + NS_ASSERTION(aAtom, "Setting null atom"); + NS_ASSERTION((PtrBits(aAtom) & ~0x1) == PtrBits(aAtom), + "Pointers must align or this is broken"); + + mAtom = PtrBits(aAtom) | 0x1; + } + + inline void ClearAtom() { + mAtom = nsnull; + } + + inline PRBool HasValue() const { + return (mAtom & ~0x1) != 0; + } + + // these accessors assume that you already know the type + inline AtomImpl *GetAtomImpl() const { + NS_ASSERTION(!IsStaticAtom(), "This is a static atom, not an AtomImpl"); + return (AtomImpl*) (mAtom & ~0x1); + } + + inline nsStaticAtomWrapper *GetStaticAtomWrapper() const { + NS_ASSERTION(IsStaticAtom(), "This is an AtomImpl, not a static atom"); + return (nsStaticAtomWrapper*) (mAtom & ~0x1); + } + + inline const nsStaticAtom* GetStaticAtom() const { + return GetStaticAtomWrapper()->GetStaticAtom(); + } + + // type-agnostic accessors + + // get the string buffer + inline const char* get() const { + return IsStaticAtom() ? GetStaticAtom()->mString : GetAtomImpl()->mString; + } + + // get an addreffed nsIAtom - not using already_AddRef'ed atom + // because the callers are not (and should not be) using nsCOMPtr + inline nsIAtom* GetAtom() const { + nsIAtom* result; + + if (IsStaticAtom()) + result = GetStaticAtomWrapper(); + else { + result = GetAtomImpl(); + NS_ADDREF(result); + } + + return result; + } +}; + +PR_STATIC_CALLBACK(const void *) +AtomTableGetKey(PLDHashTable *table, PLDHashEntryHdr *entry) +{ + AtomTableEntry *he = NS_STATIC_CAST(AtomTableEntry*, entry); + NS_ASSERTION(he->HasValue(), "Empty atom. how did that happen?"); + return he->get(); +} + +PR_STATIC_CALLBACK(PRBool) +AtomTableMatchKey(PLDHashTable *table, + const PLDHashEntryHdr *entry, + const void *key) +{ + const AtomTableEntry *he = NS_STATIC_CAST(const AtomTableEntry*, entry); + const char* keyStr = NS_STATIC_CAST(const char*, key); + return nsCRT::strcmp(keyStr, he->get()) == 0; +} + +PR_STATIC_CALLBACK(void) +AtomTableClearEntry(PLDHashTable *table, PLDHashEntryHdr *entry) +{ + AtomTableEntry *he = NS_STATIC_CAST(AtomTableEntry*, entry); + + he->keyHash = 0; + + if (!he->IsStaticAtom()) { + AtomImpl *atom = he->GetAtomImpl(); + // Normal |AtomImpl| atoms are deleted when their refcount hits 0, and + // they then remove themselves from the table. In other words, they + // are owned by the callers who own references to them. + // |PermanentAtomImpl| permanent atoms ignore their refcount and are + // deleted when they are removed from the table at table destruction. + // In other words, they are owned by the atom table. + if (atom->IsPermanent()) + delete NS_STATIC_CAST(PermanentAtomImpl*, atom); + } + else { + he->GetStaticAtomWrapper()->~nsStaticAtomWrapper(); + } + + he->ClearAtom(); +} + +static const PLDHashTableOps AtomTableOps = { + PL_DHashAllocTable, + PL_DHashFreeTable, + AtomTableGetKey, + PL_DHashStringKey, + AtomTableMatchKey, + PL_DHashMoveEntryStub, + AtomTableClearEntry, + PL_DHashFinalizeStub, + NULL +}; + + +#ifdef DEBUG + +PR_STATIC_CALLBACK(PLDHashOperator) +DumpAtomLeaks(PLDHashTable *table, PLDHashEntryHdr *he, + PRUint32 index, void *arg) +{ + AtomTableEntry *entry = NS_STATIC_CAST(AtomTableEntry*, he); + + if (entry->IsStaticAtom()) + return PL_DHASH_NEXT; + + AtomImpl* atom = entry->GetAtomImpl(); + if (!atom->IsPermanent()) { + ++*NS_STATIC_CAST(PRUint32*, arg); + const char *str; + atom->GetUTF8String(&str); + fputs(str, stdout); + fputs("\n", stdout); + } + return PL_DHASH_NEXT; +} + +#endif + +static inline +void PromoteToPermanent(AtomImpl* aAtom) +{ +#ifdef NS_BUILD_REFCNT_LOGGING + { + nsrefcnt refcount = aAtom->GetRefCount(); + do { + NS_LOG_RELEASE(aAtom, --refcount, "AtomImpl"); + } while (refcount); + } +#endif + aAtom = new (aAtom) PermanentAtomImpl(); +} + +void NS_PurgeAtomTable() +{ + if (gAtomTable.ops) { +#ifdef DEBUG + if (PR_GetEnv("MOZ_DUMP_ATOM_LEAKS")) { + PRUint32 leaked = 0; + printf("*** %d atoms still exist (including permanent):\n", + gAtomTable.entryCount); + PL_DHashTableEnumerate(&gAtomTable, DumpAtomLeaks, &leaked); + printf("*** %u non-permanent atoms leaked\n", leaked); + } +#endif + PL_DHashTableFinish(&gAtomTable); + gAtomTable.entryCount = 0; + gAtomTable.ops = nsnull; + + if (gStaticAtomArena) { + PL_FinishArenaPool(gStaticAtomArena); + delete gStaticAtomArena; + gStaticAtomArena = nsnull; + } + } +} + +AtomImpl::AtomImpl() +{ +} + +AtomImpl::~AtomImpl() +{ + NS_PRECONDITION(gAtomTable.ops, "uninitialized atom hashtable"); + // Permanent atoms are removed from the hashtable at shutdown, and we + // don't want to remove them twice. See comment above in + // |AtomTableClearEntry|. + if (!IsPermanent()) { + PL_DHashTableOperate(&gAtomTable, mString, PL_DHASH_REMOVE); + if (gAtomTable.entryCount == 0) { + PL_DHashTableFinish(&gAtomTable); + NS_ASSERTION(gAtomTable.entryCount == 0, + "PL_DHashTableFinish changed the entry count"); + } + } +} + +NS_IMPL_THREADSAFE_ISUPPORTS1(AtomImpl, nsIAtom) + +NS_IMETHODIMP_(nsrefcnt) PermanentAtomImpl::AddRef() +{ + return 2; +} + +NS_IMETHODIMP_(nsrefcnt) PermanentAtomImpl::Release() +{ + return 1; +} + +/* virtual */ PRBool +AtomImpl::IsPermanent() +{ + return PR_FALSE; +} + +/* virtual */ PRBool +PermanentAtomImpl::IsPermanent() +{ + return PR_TRUE; +} + +void* AtomImpl::operator new ( size_t size, const nsACString& aString ) CPP_THROW_NEW +{ + /* + Note: since the |size| will initially also include the |PRUnichar| member + |mString|, our size calculation will give us one character too many. + We use that extra character for a zero-terminator. + + Note: this construction is not guaranteed to be possible by the C++ + compiler. A more reliable scheme is used by |nsShared[C]String|s, see + http://lxr.mozilla.org/seamonkey/source/xpcom/ds/nsSharedString.h#174 + */ + size += aString.Length() * sizeof(char); + AtomImpl* ii = NS_STATIC_CAST(AtomImpl*, ::operator new(size)); + + char* toBegin = &ii->mString[0]; + nsACString::const_iterator fromBegin, fromEnd; + *copy_string(aString.BeginReading(fromBegin), aString.EndReading(fromEnd), toBegin) = '\0'; + return ii; +} + +void* PermanentAtomImpl::operator new ( size_t size, AtomImpl* aAtom ) CPP_THROW_NEW { + NS_ASSERTION(!aAtom->IsPermanent(), + "converting atom that's already permanent"); + + // Just let the constructor overwrite the vtable pointer. + return aAtom; +} + +NS_IMETHODIMP +AtomImpl::ToString(nsAString& aBuf) +{ + CopyUTF8toUTF16(nsDependentCString(mString), aBuf); + return NS_OK; +} + +NS_IMETHODIMP +AtomImpl::ToUTF8String(nsACString& aBuf) +{ + aBuf.Assign(mString); + return NS_OK; +} + +NS_IMETHODIMP +AtomImpl::GetUTF8String(const char **aResult) +{ + NS_PRECONDITION(aResult, "null out param"); + *aResult = mString; + return NS_OK; +} + +NS_IMETHODIMP +AtomImpl::EqualsUTF8(const nsACString& aString, PRBool* aResult) +{ + *aResult = aString.Equals(mString); + return NS_OK; +} + +NS_IMETHODIMP +AtomImpl::Equals(const nsAString& aString, PRBool* aResult) +{ + *aResult = NS_ConvertUTF16toUTF8(aString).Equals(mString); + return NS_OK; +} + +//---------------------------------------------------------------------- + +// wrapper class for the nsStaticAtom struct + +NS_IMETHODIMP_(nsrefcnt) +nsStaticAtomWrapper::AddRef() +{ + return 2; +} + +NS_IMETHODIMP_(nsrefcnt) +nsStaticAtomWrapper::Release() +{ + return 1; +} + +NS_IMPL_QUERY_INTERFACE1(nsStaticAtomWrapper, nsIAtom) + +NS_IMETHODIMP +nsStaticAtomWrapper::GetUTF8String(const char** aResult) +{ + *aResult = mStaticAtom->mString; + return NS_OK; +} + +NS_IMETHODIMP +nsStaticAtomWrapper::ToString(nsAString& aBuf) +{ + // static should always be always ASCII, to allow tools like gperf + // to generate the tables, and to avoid unnecessary conversion + NS_ASSERTION(nsCRT::IsAscii(mStaticAtom->mString), + "Data loss - atom should be ASCII"); + CopyASCIItoUCS2(nsDependentCString(mStaticAtom->mString), aBuf); + return NS_OK; +} + +NS_IMETHODIMP +nsStaticAtomWrapper::ToUTF8String(nsACString& aBuf) +{ + aBuf.Assign(mStaticAtom->mString); + return NS_OK; +} + +NS_IMETHODIMP +nsStaticAtomWrapper::EqualsUTF8(const nsACString& aString, PRBool* aResult) +{ + *aResult = aString.Equals(mStaticAtom->mString); + return NS_OK; +} + +NS_IMETHODIMP +nsStaticAtomWrapper::Equals(const nsAString& aString, PRBool* aResult) +{ + *aResult = NS_ConvertUCS2toUTF8(aString).Equals(mStaticAtom->mString); + return NS_OK; +} +//---------------------------------------------------------------------- + +NS_COM nsIAtom* NS_NewAtom(const char* isolatin1) +{ + return NS_NewAtom(nsDependentCString(isolatin1)); +} + +NS_COM nsIAtom* NS_NewPermanentAtom(const char* isolatin1) +{ + return NS_NewPermanentAtom(NS_ConvertASCIItoUCS2(isolatin1)); +} + +static nsStaticAtomWrapper* +WrapStaticAtom(const nsStaticAtom* aAtom) +{ + if (!gStaticAtomArena) { + gStaticAtomArena = new PLArenaPool; + if (!gStaticAtomArena) + return nsnull; + + PL_INIT_ARENA_POOL(gStaticAtomArena, "nsStaticAtomArena", 4096); + } + + void* mem; + PL_ARENA_ALLOCATE(mem, gStaticAtomArena, sizeof(nsStaticAtom)); + + nsStaticAtomWrapper* wrapper = + new (mem) nsStaticAtomWrapper(aAtom); + + return wrapper; +} + +static AtomTableEntry* GetAtomHashEntry(const char* aString) +{ + if (!gAtomTable.ops && + !PL_DHashTableInit(&gAtomTable, &AtomTableOps, 0, + sizeof(AtomTableEntry), 2048)) { + gAtomTable.ops = nsnull; + return nsnull; + } + return NS_STATIC_CAST(AtomTableEntry*, + PL_DHashTableOperate(&gAtomTable, + aString, + PL_DHASH_ADD)); +} + +NS_COM nsresult +NS_RegisterStaticAtoms(const nsStaticAtom* aAtoms, PRUint32 aAtomCount) +{ + // this does two things: + // 1) wraps each static atom in a wrapper, if necessary + // 2) initializes the address pointed to by each mAtom slot + + for (PRUint32 i=0; iHasValue() && aAtoms[i].mAtom) { + // there already is an atom with this name in the table.. but we + // still have to update mAtom + if (!he->IsStaticAtom() && !he->GetAtomImpl()->IsPermanent()) { + // since we wanted to create a static atom but there is + // already one there, we convert it to a non-refcounting + // permanent atom + PromoteToPermanent(he->GetAtomImpl()); + } + + // and now, if the consumer wants to remember this value in a + // slot, we do so + if (aAtoms[i].mAtom) + *aAtoms[i].mAtom = he->GetAtom(); + } + + else { + nsStaticAtomWrapper* atom = WrapStaticAtom(&aAtoms[i]); + NS_ASSERTION(atom, "Failed to wrap static atom"); + + // but even if atom is null, no real difference in code.. + he->SetStaticAtomWrapper(atom); + if (aAtoms[i].mAtom) + *aAtoms[i].mAtom = atom; + } + } + return NS_OK; +} + +NS_COM nsIAtom* NS_NewAtom( const nsAString& aString ) +{ + NS_ConvertUCS2toUTF8 utf8String(aString); + + return NS_NewAtom(utf8String); +} + +NS_COM +nsIAtom* +NS_NewAtom( const nsACString& aString ) +{ + AtomTableEntry *he = GetAtomHashEntry(PromiseFlatCString(aString).get()); + + if (he->HasValue()) + return he->GetAtom(); + + AtomImpl* atom = new (aString) AtomImpl(); + he->SetAtomImpl(atom); + if (!atom) { + PL_DHashTableRawRemove(&gAtomTable, he); + return nsnull; + } + + NS_ADDREF(atom); + return atom; +} + +NS_COM nsIAtom* NS_NewPermanentAtom( const nsAString& aString ) +{ + return NS_NewPermanentAtom(NS_ConvertUCS2toUTF8(aString)); +} + +NS_COM +nsIAtom* NS_NewPermanentAtom( const nsACString& aString ) +{ + AtomTableEntry *he = GetAtomHashEntry(PromiseFlatCString(aString).get()); + + if (he->HasValue() && he->IsStaticAtom()) + return he->GetStaticAtomWrapper(); + + // either there is no atom and we'll create an AtomImpl, + // or there is an existing AtomImpl + AtomImpl* atom = he->GetAtomImpl(); + + if (atom) { + // ensure that it's permanent + if (!atom->IsPermanent()) { + PromoteToPermanent(atom); + } + } else { + // otherwise, make a new atom + atom = new (aString) PermanentAtomImpl(); + he->SetAtomImpl(atom); + if ( !atom ) { + PL_DHashTableRawRemove(&gAtomTable, he); + return nsnull; + } + } + + NS_ADDREF(atom); + return atom; +} + +NS_COM nsIAtom* NS_NewAtom( const PRUnichar* str ) +{ + return NS_NewAtom(NS_ConvertUCS2toUTF8(str)); +} + +NS_COM nsIAtom* NS_NewPermanentAtom( const PRUnichar* str ) +{ + return NS_NewPermanentAtom(nsDependentString(str)); +} + +NS_COM nsrefcnt NS_GetNumberOfAtoms(void) +{ + return gAtomTable.entryCount; +} + diff --git a/src/libs/xpcom18a4/xpcom/ds/nsAtomTable.h b/src/libs/xpcom18a4/xpcom/ds/nsAtomTable.h new file mode 100644 index 00000000..d8971cf7 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsAtomTable.h @@ -0,0 +1,101 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +#ifndef nsAtomTable_h__ +#define nsAtomTable_h__ + +#include "nsIAtom.h" + +/** + * A threadsafely-refcounted implementation of nsIAtom. Note that + * AtomImpl objects are sometimes converted into PermanentAtomImpl + * objects using placement new and just overwriting the vtable pointer. + */ + +class AtomImpl : public nsIAtom { +public: + AtomImpl(); + +protected: + // We don't need a virtual destructor here because PermanentAtomImpl + // deletions aren't handled through Release(). + ~AtomImpl(); + +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIATOM + + virtual PRBool IsPermanent(); + + void* operator new(size_t size, const nsACString& aString) CPP_THROW_NEW; + + void operator delete(void* ptr) { + ::operator delete(ptr); + } + + // for |#ifdef NS_BUILD_REFCNT_LOGGING| access to reference count + nsrefcnt GetRefCount() { return mRefCnt; } + + // Actually more; 0 terminated. This slot is reserved for the + // terminating zero. + char mString[1]; +}; + +/** + * A non-refcounted implementation of nsIAtom. + */ + +class PermanentAtomImpl : public AtomImpl { +public: +#ifdef AIX + PermanentAtomImpl() : AtomImpl() {} +#endif + NS_IMETHOD_(nsrefcnt) AddRef(); + NS_IMETHOD_(nsrefcnt) Release(); + + virtual PRBool IsPermanent(); + + void* operator new(size_t size, const nsACString& aString) CPP_THROW_NEW { + return AtomImpl::operator new(size, aString); + } + void* operator new(size_t size, AtomImpl* aAtom) CPP_THROW_NEW; + +}; + +void NS_PurgeAtomTable(); + +#endif // nsAtomTable_h__ diff --git a/src/libs/xpcom18a4/xpcom/ds/nsAutoBuffer.h b/src/libs/xpcom18a4/xpcom/ds/nsAutoBuffer.h new file mode 100644 index 00000000..84011369 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsAutoBuffer.h @@ -0,0 +1,127 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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 auto buffer template. + * + * The Initial Developer of the Original Code is + * Conrad Carlen . + * Portions created by the Initial Developer are Copyright (C) 2004 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Jungshik Shin + * + * 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 ***** */ + +#ifndef nsAutoBuffer_h__ +#define nsAutoBuffer_h__ + +#ifndef nsMemory_h__ +#include "nsMemory.h" +#endif + +/** + * A buffer which will use stack space if the requested size will + * fit in the stack buffer and allocate from the heap if not. + * + * Below is a usage example : + * + * typedef nsAutoBuffer nsAutoUnicharBuffer; + * + * nsAutoUnicharBuffer buffer; + * + * if (!buffer.EnsureElemCapacity(initialLength)) + * return NS_ERROR_OUT_OF_MEMORY; + * + * PRUnichar *unicharPtr = buffer.get(); + * + * // add PRUnichar's to the buffer pointed to by |unicharPtr| as long as + * // the number of PRUnichar's is less than |intialLength| + * + * // increase the capacity + * if (!buffer.AddElemCapacity(extraLength)) + * return NS_ERROR_OUT_OF_MEMORY + * + * unicharPtr = buffer.get() + initialLength; + * + * //continue to add PRUnichar's.... + */ + +template +class nsAutoBuffer +{ +public: + nsAutoBuffer() : + mBufferPtr(mStackBuffer), + mCurElemCapacity(sz) + { + } + + ~nsAutoBuffer() + { + if (mBufferPtr != mStackBuffer) + nsMemory::Free(mBufferPtr); + } + + PRBool EnsureElemCapacity(PRInt32 inElemCapacity) + { + if (inElemCapacity <= mCurElemCapacity) + return PR_TRUE; + + T* newBuffer; + + if (mBufferPtr != mStackBuffer) + newBuffer = (T*)nsMemory::Realloc((void *)mBufferPtr, inElemCapacity * sizeof(T)); + else + newBuffer = (T*)nsMemory::Alloc(inElemCapacity * sizeof(T)); + + if (!newBuffer) + return PR_FALSE; + + if (mBufferPtr != mStackBuffer) + nsMemory::Free(mBufferPtr); + + mBufferPtr = newBuffer; + mCurElemCapacity = inElemCapacity; + return PR_TRUE; + } + + PRBool AddElemCapacity(PRInt32 inElemCapacity) + { + return EnsureElemCapacity(mCurElemCapacity + inElemCapacity); + } + + T* get() const { return mBufferPtr; } + PRInt32 GetElemCapacity() const { return mCurElemCapacity; } + +protected: + + T *mBufferPtr; + T mStackBuffer[sz]; + PRInt32 mCurElemCapacity; +}; + +#endif // nsAutoBuffer_h__ diff --git a/src/libs/xpcom18a4/xpcom/ds/nsBaseHashtable.h b/src/libs/xpcom18a4/xpcom/ds/nsBaseHashtable.h new file mode 100644 index 00000000..92300c2f --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsBaseHashtable.h @@ -0,0 +1,458 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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 C++ hashtable templates. + * + * The Initial Developer of the Original Code is + * Benjamin Smedberg. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * 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 ***** */ + +#ifndef nsBaseHashtable_h__ +#define nsBaseHashtable_h__ + +#include "nsTHashtable.h" +#include "prlock.h" +#include "nsDebug.h" + +template +class nsBaseHashtable; // forward declaration + +/** + * the private nsTHashtable::EntryType class used by nsBaseHashtable + * @see nsTHashtable for the specification of this class + * @see nsBaseHashtable for template parameters + */ +template +class nsBaseHashtableET : public KeyClass +{ +public: + DataType mData; + friend class nsTHashtable< nsBaseHashtableET >; + +private: + typedef typename KeyClass::KeyType KeyType; + typedef typename KeyClass::KeyTypePointer KeyTypePointer; + + nsBaseHashtableET(KeyTypePointer aKey); + nsBaseHashtableET(nsBaseHashtableET& toCopy); + ~nsBaseHashtableET(); +}; + +/** + * templated hashtable for simple data types + * This class manages simple data types that do not need construction or + * destruction. Thread-safety is optional, via a flag in Init() + * + * @param KeyClass a wrapper-class for the hashtable key, see nsHashKeys.h + * for a complete specification. + * @param DataType the datatype stored in the hashtable, + * for example, PRUint32 or nsCOMPtr. If UserDataType is not the same, + * DataType must implicitly cast to UserDataType + * @param UserDataType the user sees, for example PRUint32 or nsISupports* + */ +template +class nsBaseHashtable : + protected nsTHashtable< nsBaseHashtableET > +{ +public: + typedef typename KeyClass::KeyType KeyType; + typedef nsBaseHashtableET EntryType; + + // default constructor+destructor are fine + + /** + * Initialize the object. + * @param initSize the initial number of buckets in the hashtable, + * default 16 + * @param threadSafe whether to provide read/write + * locking on all class methods + * @return PR_TRUE if the object was initialized properly. + */ + PRBool Init(PRUint32 initSize = PL_DHASH_MIN_SIZE) + { return nsTHashtable::Init(initSize); } + + /** + * Check whether the table has been initialized. + * This function is especially useful for static hashtables. + * @return PR_TRUE if the table has been initialized. + */ + PRBool IsInitialized() const { return this->mTable.entrySize; } + + /** + * Return the number of entries in the table. + * @return number of entries + */ + PRUint32 Count() const + { return nsTHashtable::Count(); } + + /** + * retrieve the value for a key. + * @param aKey the key to retreive + * @param pData data associated with this key will be placed at this + * pointer. If you only need to check if the key exists, pData + * may be null. + * @return PR_TRUE if the key exists. If key does not exist, pData is not + * modified. + */ + PRBool Get(KeyType aKey, UserDataType* pData) const + { + EntryType* ent = this->GetEntry(aKey); + + if (!ent) + return PR_FALSE; + + if (pData) + *pData = ent->mData; + + return PR_TRUE; + } + + /** + * put a new value for the associated key + * @param aKey the key to put + * @param aData the new data + * @return always PR_TRUE, unless memory allocation failed + */ + PRBool Put(KeyType aKey, UserDataType aData) + { + EntryType* ent = this->PutEntry(aKey); + + if (!ent) + return PR_FALSE; + + ent->mData = aData; + + return PR_TRUE; + } + + /** + * remove the data for the associated key + * @param aKey the key to remove from the hashtable + */ + void Remove(KeyType aKey) { this->RemoveEntry(aKey); } + + /** + * function type provided by the application for enumeration. + * @param aKey the key being enumerated + * @param aData data being enumerated + * @parm userArg passed unchanged from Enumerate + * @return either + * @link PLDHashOperator::PL_DHASH_NEXT PL_DHASH_NEXT @endlink or + * @link PLDHashOperator::PL_DHASH_STOP PL_DHASH_STOP @endlink + */ + typedef PLDHashOperator + (*PR_CALLBACK EnumReadFunction)(KeyType aKey, + UserDataType aData, + void* userArg); + + /** + * enumerate entries in the hashtable, without allowing changes + * this function read-locks the hashtable, so other threads may read keys + * at the same time in multi-thread environments. + * @param enumFunc enumeration callback + * @param userArg passed unchanged to the EnumReadFunction + */ + PRUint32 EnumerateRead(EnumReadFunction enumFunc, void* userArg) const + { + NS_ASSERTION(this->mTable.entrySize, + "nsBaseHashtable was not initialized properly."); + + s_EnumReadArgs enumData = { enumFunc, userArg }; + return PL_DHashTableEnumerate(NS_CONST_CAST(PLDHashTable*, &this->mTable), + s_EnumReadStub, + &enumData); + } + + /** + * function type provided by the application for enumeration. + * @param aKey the key being enumerated + * @param aData Reference to data being enumerated, may be altered. e.g. for + * nsInterfaceHashtable this is an nsCOMPtr reference... + * @parm userArg passed unchanged from Enumerate + * @return bitflag combination of + * @link PLDHashOperator::PL_DHASH_REMOVE @endlink, + * @link PLDHashOperator::PL_DHASH_NEXT PL_DHASH_NEXT @endlink, or + * @link PLDHashOperator::PL_DHASH_STOP PL_DHASH_STOP @endlink + */ + typedef PLDHashOperator + (*PR_CALLBACK EnumFunction)(KeyType aKey, + DataType& aData, + void* userArg); + + /** + * enumerate entries in the hashtable, allowing changes. This + * functions write-locks the hashtable. + * @param enumFunc enumeration callback + * @param userArg passed unchanged to the EnumFunction + */ + PRUint32 Enumerate(EnumFunction enumFunc, void* userArg) + { + NS_ASSERTION(this->mTable.entrySize, + "nsBaseHashtable was not initialized properly."); + + s_EnumArgs enumData = { enumFunc, userArg }; + return PL_DHashTableEnumerate(&this->mTable, + s_EnumStub, + &enumData); + } + + /** + * reset the hashtable, removing all entries + */ + void Clear() { nsTHashtable::Clear(); } + +protected: + /** + * used internally during EnumerateRead. Allocated on the stack. + * @param func the enumerator passed to EnumerateRead + * @param userArg the userArg passed to EnumerateRead + */ + struct s_EnumReadArgs + { + EnumReadFunction func; + void* userArg; + }; + + static PLDHashOperator s_EnumReadStub(PLDHashTable *table, + PLDHashEntryHdr *hdr, + PRUint32 number, + void *arg); + + struct s_EnumArgs + { + EnumFunction func; + void* userArg; + }; + + static PLDHashOperator s_EnumStub(PLDHashTable *table, + PLDHashEntryHdr *hdr, + PRUint32 number, + void *arg); +}; + +/** + * This class is a thread-safe version of nsBaseHashtable. + */ +template +class nsBaseHashtableMT : + protected nsBaseHashtable +{ +public: + typedef typename + nsBaseHashtable::EntryType EntryType; + typedef typename + nsBaseHashtable::KeyType KeyType; + typedef typename + nsBaseHashtable::EnumFunction EnumFunction; + typedef typename + nsBaseHashtable::EnumReadFunction EnumReadFunction; + + nsBaseHashtableMT() : mLock(nsnull) { } + ~nsBaseHashtableMT(); + + PRBool Init(PRUint32 initSize = PL_DHASH_MIN_SIZE); + PRBool IsInitialized() const { return (PRBool) mLock; } + PRUint32 Count() const; + PRBool Get(KeyType aKey, UserDataType* pData) const; + PRBool Put(KeyType aKey, UserDataType aData); + void Remove(KeyType aKey); + + PRUint32 EnumerateRead(EnumReadFunction enumFunc, void* userArg) const; + PRUint32 Enumerate(EnumFunction enumFunc, void* userArg); + void Clear(); + +protected: + PRLock* mLock; +}; + + +// +// nsBaseHashtableET definitions +// + +template +nsBaseHashtableET::nsBaseHashtableET(KeyTypePointer aKey) : + KeyClass(aKey) +{ } + +template +nsBaseHashtableET::nsBaseHashtableET + (nsBaseHashtableET& toCopy) : + KeyClass(toCopy), + mData(toCopy.mData) +{ } + +template +nsBaseHashtableET::~nsBaseHashtableET() +{ } + + +// +// nsBaseHashtable definitions +// + +template +PLDHashOperator +nsBaseHashtable::s_EnumReadStub + (PLDHashTable *table, PLDHashEntryHdr *hdr, PRUint32 number, void* arg) +{ + EntryType* ent = NS_STATIC_CAST(EntryType*, hdr); + s_EnumReadArgs* eargs = (s_EnumReadArgs*) arg; + + PLDHashOperator res = (eargs->func)(ent->GetKey(), ent->mData, eargs->userArg); + + NS_ASSERTION( !(res & PL_DHASH_REMOVE ), + "PL_DHASH_REMOVE return during const enumeration; ignoring."); + + if (res & PL_DHASH_STOP) + return PL_DHASH_STOP; + + return PL_DHASH_NEXT; +} + +template +PLDHashOperator +nsBaseHashtable::s_EnumStub + (PLDHashTable *table, PLDHashEntryHdr *hdr, PRUint32 number, void* arg) +{ + EntryType* ent = NS_STATIC_CAST(EntryType*, hdr); + s_EnumArgs* eargs = (s_EnumArgs*) arg; + + return (eargs->func)(ent->GetKey(), ent->mData, eargs->userArg); +} + + +// +// nsBaseHashtableMT definitions +// + +template +nsBaseHashtableMT::~nsBaseHashtableMT() +{ + if (this->mLock) + PR_DestroyLock(this->mLock); +} + +template +PRBool +nsBaseHashtableMT::Init(PRUint32 initSize) +{ + if (!nsTHashtable::IsInitialized() && !nsTHashtable::Init(initSize)) + return PR_FALSE; + + this->mLock = PR_NewLock(); + NS_WARN_IF_FALSE(this->mLock, "Error creating lock during nsBaseHashtableL::Init()"); + + return (this->mLock != nsnull); +} + +template +PRUint32 +nsBaseHashtableMT::Count() const +{ + PR_Lock(this->mLock); + PRUint32 count = nsTHashtable::Count(); + PR_Unlock(this->mLock); + + return count; +} + +template +PRBool +nsBaseHashtableMT::Get(KeyType aKey, + UserDataType* pData) const +{ + PR_Lock(this->mLock); + PRBool res = + nsBaseHashtable::Get(aKey, pData); + PR_Unlock(this->mLock); + + return res; +} + +template +PRBool +nsBaseHashtableMT::Put(KeyType aKey, + UserDataType aData) +{ + PR_Lock(this->mLock); + PRBool res = + nsBaseHashtable::Put(aKey, aData); + PR_Unlock(this->mLock); + + return res; +} + +template +void +nsBaseHashtableMT::Remove(KeyType aKey) +{ + PR_Lock(this->mLock); + nsBaseHashtable::Remove(aKey); + PR_Unlock(this->mLock); +} + +template +PRUint32 +nsBaseHashtableMT::EnumerateRead + (EnumReadFunction fEnumCall, void* userArg) const +{ + PR_Lock(this->mLock); + PRUint32 count = + nsBaseHashtable::EnumerateRead(fEnumCall, userArg); + PR_Unlock(this->mLock); + + return count; +} + +template +PRUint32 +nsBaseHashtableMT::Enumerate + (EnumFunction fEnumCall, void* userArg) +{ + PR_Lock(this->mLock); + PRUint32 count = + nsBaseHashtable::Enumerate(fEnumCall, userArg); + PR_Unlock(this->mLock); + + return count; +} + +template +void +nsBaseHashtableMT::Clear() +{ + PR_Lock(this->mLock); + nsBaseHashtable::Clear(); + PR_Unlock(this->mLock); +} + +#endif // nsBaseHashtable_h__ diff --git a/src/libs/xpcom18a4/xpcom/ds/nsByteBuffer.cpp b/src/libs/xpcom18a4/xpcom/ds/nsByteBuffer.cpp new file mode 100644 index 00000000..a51ff9d6 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsByteBuffer.cpp @@ -0,0 +1,170 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Pierre Phaneuf + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsByteBuffer.h" +#include "nsIInputStream.h" +#include "nsCRT.h" + +#define MIN_BUFFER_SIZE 32 + +ByteBufferImpl::ByteBufferImpl(void) + : mBuffer(NULL), mSpace(0), mLength(0) +{ +} + +NS_IMETHODIMP +ByteBufferImpl::Init(PRUint32 aBufferSize) +{ + if (aBufferSize < MIN_BUFFER_SIZE) { + aBufferSize = MIN_BUFFER_SIZE; + } + mSpace = aBufferSize; + mLength = 0; + mBuffer = new char[aBufferSize]; + return mBuffer ? NS_OK : NS_ERROR_OUT_OF_MEMORY; +} + +NS_IMPL_ISUPPORTS1(ByteBufferImpl,nsIByteBuffer) + +ByteBufferImpl::~ByteBufferImpl() +{ + if (nsnull != mBuffer) { + delete[] mBuffer; + mBuffer = nsnull; + } + mLength = 0; +} + +NS_METHOD +ByteBufferImpl::Create(nsISupports *aOuter, REFNSIID aIID, void **aResult) +{ + if (aOuter) + return NS_ERROR_NO_AGGREGATION; + + ByteBufferImpl* it = new ByteBufferImpl(); + if (nsnull == it) + return NS_ERROR_OUT_OF_MEMORY; + + NS_ADDREF(it); + nsresult rv = it->QueryInterface(aIID, (void**)aResult); + NS_RELEASE(it); + return rv; +} + +NS_IMETHODIMP_(PRUint32) +ByteBufferImpl::GetLength(void) const +{ + return mLength; +} + +NS_IMETHODIMP_(PRUint32) +ByteBufferImpl::GetBufferSize(void) const +{ + return mSpace; +} + +NS_IMETHODIMP_(char*) +ByteBufferImpl::GetBuffer(void) const +{ + return mBuffer; +} + +NS_IMETHODIMP_(PRBool) +ByteBufferImpl::Grow(PRUint32 aNewSize) +{ + if (aNewSize < MIN_BUFFER_SIZE) { + aNewSize = MIN_BUFFER_SIZE; + } + char* newbuf = new char[aNewSize]; + if (nsnull != newbuf) { + if (0 != mLength) { + memcpy(newbuf, mBuffer, mLength); + } + delete[] mBuffer; + mBuffer = newbuf; + return PR_TRUE; + } + return PR_FALSE; +} + +NS_IMETHODIMP_(PRInt32) +ByteBufferImpl::Fill(nsresult* aErrorCode, nsIInputStream* aStream, + PRUint32 aKeep) +{ + NS_PRECONDITION(nsnull != aStream, "null stream"); + NS_PRECONDITION(aKeep <= mLength, "illegal keep count"); + if ((nsnull == aStream) || (PRUint32(aKeep) > PRUint32(mLength))) { + // whoops + *aErrorCode = NS_BASE_STREAM_ILLEGAL_ARGS; + return -1; + } + + if (0 != aKeep) { + // Slide over kept data + memmove(mBuffer, mBuffer + (mLength - aKeep), aKeep); + } + + // Read in some new data + mLength = aKeep; + PRUint32 nb; + *aErrorCode = aStream->Read(mBuffer + aKeep, mSpace - aKeep, &nb); + if (NS_SUCCEEDED(*aErrorCode)) { + mLength += nb; + } + else + nb = 0; + return nb; +} + +NS_COM nsresult NS_NewByteBuffer(nsIByteBuffer** aInstancePtrResult, + nsISupports* aOuter, + PRUint32 aBufferSize) +{ + nsresult rv; + nsIByteBuffer* buf; + rv = ByteBufferImpl::Create(aOuter, NS_GET_IID(nsIByteBuffer), (void**)&buf); + if (NS_FAILED(rv)) return rv; + + rv = buf->Init(aBufferSize); + if (NS_FAILED(rv)) { + NS_RELEASE(buf); + return rv; + } + *aInstancePtrResult = buf; + return rv; +} diff --git a/src/libs/xpcom18a4/xpcom/ds/nsByteBuffer.h b/src/libs/xpcom18a4/xpcom/ds/nsByteBuffer.h new file mode 100644 index 00000000..0a474570 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsByteBuffer.h @@ -0,0 +1,67 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +#ifndef nsByteBuffer_h__ +#define nsByteBuffer_h__ + +#include "nsIByteBuffer.h" + +class ByteBufferImpl : public nsIByteBuffer { +public: + ByteBufferImpl(void); + + NS_DECL_ISUPPORTS + + static NS_METHOD + Create(nsISupports *aOuter, REFNSIID aIID, void **aResult); + + NS_IMETHOD Init(PRUint32 aBufferSize); + NS_IMETHOD_(PRUint32) GetLength(void) const; + NS_IMETHOD_(PRUint32) GetBufferSize(void) const; + NS_IMETHOD_(char*) GetBuffer() const; + NS_IMETHOD_(PRBool) Grow(PRUint32 aNewSize); + NS_IMETHOD_(PRInt32) Fill(nsresult* aErrorCode, nsIInputStream* aStream, + PRUint32 aKeep); + + char* mBuffer; + PRUint32 mSpace; + PRUint32 mLength; +private: + ~ByteBufferImpl(); +}; + +#endif // nsByteBuffer_h__ diff --git a/src/libs/xpcom18a4/xpcom/ds/nsCOMArray.cpp b/src/libs/xpcom18a4/xpcom/ds/nsCOMArray.cpp new file mode 100644 index 00000000..9a270223 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsCOMArray.cpp @@ -0,0 +1,162 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 a COM aware array class. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corp. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Alec Flett + * + * 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 "nsCOMArray.h" +#include "nsCOMPtr.h" + +PR_STATIC_CALLBACK(PRBool) ReleaseObjects(void* aElement, void*); + +// implementations of non-trivial methods in nsCOMArray_base + +// copy constructor - we can't just memcpy here, because +// we have to make sure we own our own array buffer, and that each +// object gets another AddRef() +nsCOMArray_base::nsCOMArray_base(const nsCOMArray_base& aOther) +{ + // make sure we do only one allocation + mArray.SizeTo(aOther.Count()); + AppendObjects(aOther); +} + +nsCOMArray_base::~nsCOMArray_base() +{ + PRInt32 count = Count(), i; + for (i = 0; i < count; ++i) { + nsISupports* obj = ObjectAt(i); + NS_IF_RELEASE(obj); + } +} + +PRInt32 +nsCOMArray_base::IndexOfObject(nsISupports* aObject) const { + NS_ENSURE_TRUE(aObject, -1); + nsCOMPtr supports = do_QueryInterface(aObject); + NS_ENSURE_TRUE(supports, -1); + + PRInt32 i, count; + PRInt32 retval = -1; + count = mArray.Count(); + for (i = 0; i < count; ++i) { + nsCOMPtr arrayItem = + do_QueryInterface(NS_REINTERPRET_CAST(nsISupports*,mArray.ElementAt(i))); + if (arrayItem == supports) { + retval = i; + break; + } + } + return retval; +} + +PRBool +nsCOMArray_base::InsertObjectAt(nsISupports* aObject, PRInt32 aIndex) { + PRBool result = mArray.InsertElementAt(aObject, aIndex); + if (result) + NS_IF_ADDREF(aObject); + return result; +} + +PRBool +nsCOMArray_base::InsertObjectsAt(const nsCOMArray_base& aObjects, PRInt32 aIndex) { + PRBool result = mArray.InsertElementsAt(aObjects.mArray, aIndex); + if (result) { + // need to addref all these + PRInt32 count = aObjects.Count(); + for (PRInt32 i = 0; i < count; ++i) { + NS_IF_ADDREF(aObjects.ObjectAt(i)); + } + } + return result; +} + +PRBool +nsCOMArray_base::ReplaceObjectAt(nsISupports* aObject, PRInt32 aIndex) +{ + // its ok if oldObject is null here + nsISupports *oldObject = + NS_REINTERPRET_CAST(nsISupports*, mArray.SafeElementAt(aIndex)); + + PRBool result = mArray.ReplaceElementAt(aObject, aIndex); + + // ReplaceElementAt could fail, such as if the array grows + // so only release the existing object if the replacement succeeded + if (result) { + // Make sure to addref first, in case aObject == oldObject + NS_IF_ADDREF(aObject); + NS_IF_RELEASE(oldObject); + } + return result; +} + +PRBool +nsCOMArray_base::RemoveObject(nsISupports *aObject) +{ + PRBool result = mArray.RemoveElement(aObject); + if (result) + NS_IF_RELEASE(aObject); + return result; +} + +PRBool +nsCOMArray_base::RemoveObjectAt(PRInt32 aIndex) +{ + nsISupports* element = ObjectAt(aIndex); + if (element) { + PRBool result = mArray.RemoveElementAt(aIndex); + if (result) + NS_IF_RELEASE(element); + return result; + } + return PR_FALSE; +} + +// useful for destructors +PRBool +ReleaseObjects(void* aElement, void*) +{ + nsISupports* element = NS_STATIC_CAST(nsISupports*, aElement); + NS_IF_RELEASE(element); + return PR_TRUE; +} + +void +nsCOMArray_base::Clear() +{ + mArray.EnumerateForwards(ReleaseObjects, nsnull); + mArray.Clear(); +} + diff --git a/src/libs/xpcom18a4/xpcom/ds/nsCOMArray.h b/src/libs/xpcom18a4/xpcom/ds/nsCOMArray.h new file mode 100644 index 00000000..cbb728c0 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsCOMArray.h @@ -0,0 +1,267 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 a COM aware array class. + * + * The Initial Developer of the Original Code + * Netscape Communications Corp. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Alec Flett + * + * 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 ***** */ + +#ifndef nsCOMArray_h__ +#define nsCOMArray_h__ + +#include "nsVoidArray.h" +#include "nsISupports.h" + +// See below for the definition of nsCOMArray + +// a class that's nsISupports-specific, so that we can contain the +// work of this class in the XPCOM dll +class NS_COM nsCOMArray_base +{ + friend class nsArray; +protected: + nsCOMArray_base() {} + nsCOMArray_base(PRInt32 aCount) : mArray(aCount) {} + nsCOMArray_base(const nsCOMArray_base& other); + ~nsCOMArray_base(); + + PRInt32 IndexOf(nsISupports* aObject) const { + return mArray.IndexOf(aObject); + } + + PRInt32 IndexOfObject(nsISupports* aObject) const; + + PRBool EnumerateForwards(nsVoidArrayEnumFunc aFunc, void* aData) { + return mArray.EnumerateForwards(aFunc, aData); + } + + PRBool EnumerateBackwards(nsVoidArrayEnumFunc aFunc, void* aData) { + return mArray.EnumerateBackwards(aFunc, aData); + } + + void Sort(nsVoidArrayComparatorFunc aFunc, void* aData) { + mArray.Sort(aFunc, aData); + } + + // any method which is not a direct forward to mArray should + // avoid inline bodies, so that the compiler doesn't inline them + // all over the place + void Clear(); + PRBool InsertObjectAt(nsISupports* aObject, PRInt32 aIndex); + PRBool InsertObjectsAt(const nsCOMArray_base& aObjects, PRInt32 aIndex); + PRBool ReplaceObjectAt(nsISupports* aObject, PRInt32 aIndex); + PRBool AppendObject(nsISupports *aObject) { + return InsertObjectAt(aObject, Count()); + } + PRBool AppendObjects(const nsCOMArray_base& aObjects) { + return InsertObjectsAt(aObjects, Count()); + } + PRBool RemoveObject(nsISupports *aObject); + PRBool RemoveObjectAt(PRInt32 aIndex); + +public: + // override nsVoidArray stuff so that they can be accessed by + // consumers of nsCOMArray + PRInt32 Count() const { + return mArray.Count(); + } + + nsISupports* ObjectAt(PRInt32 aIndex) const { + return NS_STATIC_CAST(nsISupports*, mArray.FastElementAt(aIndex)); + } + + nsISupports* SafeObjectAt(PRInt32 aIndex) const { + return NS_STATIC_CAST(nsISupports*, mArray.SafeElementAt(aIndex)); + } + + nsISupports* operator[](PRInt32 aIndex) const { + return ObjectAt(aIndex); + } + +private: + + // the actual storage + nsVoidArray mArray; + + // don't implement these, defaults will muck with refcounts! + nsCOMArray_base& operator=(const nsCOMArray_base& other); +}; + +// a non-XPCOM, refcounting array of XPCOM objects +// used as a member variable or stack variable - this object is NOT +// refcounted, but the objects that it holds are +// +// most of the read-only accessors like ObjectAt()/etc do NOT refcount +// on the way out. This means that you can do one of two things: +// +// * does an addref, but holds onto a reference +// nsCOMPtr foo = array[i]; +// +// * avoids the refcount, but foo might go stale if array[i] is ever +// * modified/removed. Be careful not to NS_RELEASE(foo)! +// T* foo = array[i]; +// +// This array will accept null as an argument for any object, and will +// store null in the array, just like nsVoidArray. But that also means +// that methods like ObjectAt() may return null when referring to an +// existing, but null entry in the array. +template +class nsCOMArray : public nsCOMArray_base +{ + public: + nsCOMArray() {} + nsCOMArray(PRInt32 aCount) : nsCOMArray_base(aCount) {} + + // only to be used by trusted classes who are going to pass us the + // right type! + nsCOMArray(const nsCOMArray& aOther) : nsCOMArray_base(aOther) { } + + ~nsCOMArray() {} + + // these do NOT refcount on the way out, for speed + T* ObjectAt(PRInt32 aIndex) const { + return NS_STATIC_CAST(T*,nsCOMArray_base::ObjectAt(aIndex)); + } + + // these do NOT refcount on the way out, for speed + T* SafeObjectAt(PRInt32 aIndex) const { + return NS_STATIC_CAST(T*,nsCOMArray_base::SafeObjectAt(aIndex)); + } + + // indexing operator for syntactic sugar + T* operator[](PRInt32 aIndex) const { + return ObjectAt(aIndex); + } + + // index of the element in question.. does NOT refcount + // note: this does not check COM object identity. Use + // IndexOfObject() for that purpose + PRInt32 IndexOf(T* aObject) const { + return nsCOMArray_base::IndexOf(NS_STATIC_CAST(nsISupports*, aObject)); + } + + // index of the element in question.. be careful! + // this is much slower than IndexOf() because it uses + // QueryInterface to determine actual COM identity of the object + // if you need to do this frequently then consider enforcing + // COM object identity before adding/comparing elements + PRInt32 IndexOfObject(T* aObject) const { + return nsCOMArray_base::IndexOfObject(NS_STATIC_CAST(nsISupports*, aObject)); + } + + // inserts aObject at aIndex, shifting the objects at aIndex and + // later to make space + PRBool InsertObjectAt(T* aObject, PRInt32 aIndex) { + return nsCOMArray_base::InsertObjectAt(NS_STATIC_CAST(nsISupports*, aObject), aIndex); + } + + // inserts the objects from aObject at aIndex, shifting the + // objects at aIndex and later to make space + PRBool InsertObjectsAt(const nsCOMArray& aObjects, PRInt32 aIndex) { + return nsCOMArray_base::InsertObjectsAt(aObjects, aIndex); + } + + // replaces an existing element. Warning: if the array grows, + // the newly created entries will all be null + PRBool ReplaceObjectAt(T* aObject, PRInt32 aIndex) { + return nsCOMArray_base::ReplaceObjectAt(NS_STATIC_CAST(nsISupports*, aObject), aIndex); + } + + // override nsVoidArray stuff so that they can be accessed by + // other methods + + // elements in the array (including null elements!) + PRInt32 Count() const { + return nsCOMArray_base::Count(); + } + + // remove all elements in the array, and call NS_RELEASE on each one + void Clear() { + nsCOMArray_base::Clear(); + } + + // Enumerator callback function. Return PR_FALSE to stop + // Here's a more readable form: + // PRBool PR_CALLBACK enumerate(T* aElement, void* aData) + typedef PRBool (* PR_CALLBACK nsCOMArrayEnumFunc) + (T* aElement, void *aData); + + // enumerate through the array with a callback. + PRBool EnumerateForwards(nsCOMArrayEnumFunc aFunc, void* aData) { + return nsCOMArray_base::EnumerateForwards(nsVoidArrayEnumFunc(aFunc), + aData); + } + + PRBool EnumerateBackwards(nsCOMArrayEnumFunc aFunc, void* aData) { + return nsCOMArray_base::EnumerateBackwards(nsVoidArrayEnumFunc(aFunc), + aData); + } + + typedef int (* PR_CALLBACK nsCOMArrayComparatorFunc) + (T* aElement1, T* aElement2, void* aData); + + void Sort(nsCOMArrayComparatorFunc aFunc, void* aData) { + nsCOMArray_base::Sort(nsVoidArrayComparatorFunc(aFunc), aData); + } + + // append an object, growing the array as necessary + PRBool AppendObject(T *aObject) { + return nsCOMArray_base::AppendObject(NS_STATIC_CAST(nsISupports*, aObject)); + } + + // append objects, growing the array as necessary + PRBool AppendObjects(const nsCOMArray& aObjects) { + return nsCOMArray_base::AppendObjects(aObjects); + } + + // remove the first instance of the given object and shrink the + // array as necessary + // Warning: if you pass null here, it will remove the first null element + PRBool RemoveObject(T *aObject) { + return nsCOMArray_base::RemoveObject(NS_STATIC_CAST(nsISupports*, aObject)); + } + + // remove an element at a specific position, shrinking the array + // as necessary + PRBool RemoveObjectAt(PRInt32 aIndex) { + return nsCOMArray_base::RemoveObjectAt(aIndex); + } + +private: + + // don't implement these! + nsCOMArray& operator=(const nsCOMArray& other); +}; + + +#endif diff --git a/src/libs/xpcom18a4/xpcom/ds/nsCRT.cpp b/src/libs/xpcom18a4/xpcom/ds/nsCRT.cpp new file mode 100644 index 00000000..23392f94 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsCRT.cpp @@ -0,0 +1,534 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + + +/** + * MODULE NOTES: + * @update gess7/30/98 + * + * Much as I hate to do it, we were using string compares wrong. + * Often, programmers call functions like strcmp(s1,s2), and pass + * one or more null strings. Rather than blow up on these, I've + * added quick checks to ensure that cases like this don't cause + * us to fail. + * + * In general, if you pass a null into any of these string compare + * routines, we simply return 0. + */ + + +#include "nsCRT.h" +#include "nsIServiceManager.h" + +// XXX Bug: These tables don't lowercase the upper 128 characters properly + +// This table maps uppercase characters to lower case characters; +// characters that are neither upper nor lower case are unaffected. +static const unsigned char kUpper2Lower[256] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + 64, + + // upper band mapped to lower [A-Z] => [a-z] + 97, 98, 99,100,101,102,103,104,105,106,107,108,109,110,111, + 112,113,114,115,116,117,118,119,120,121,122, + + 91, 92, 93, 94, 95, + 96, 97, 98, 99,100,101,102,103,104,105,106,107,108,109,110,111, + 112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127, + 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, + 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159, + 160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175, + 176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191, + 192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207, + 208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223, + 224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239, + 240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255 +}; + +static const unsigned char kLower2Upper[256] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, + 96, + + // lower band mapped to upper [a-z] => [A-Z] + 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, + + 123,124,125,126,127, + 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, + 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159, + 160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175, + 176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191, + 192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207, + 208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223, + 224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239, + 240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255 +}; + +//---------------------------------------------------------------------- + +char nsCRT::ToUpper(char aChar) +{ + return (char)kLower2Upper[(unsigned char)aChar]; +} + +char nsCRT::ToLower(char aChar) +{ + return (char)kUpper2Lower[(unsigned char)aChar]; +} + +PRBool nsCRT::IsUpper(char aChar) +{ + return aChar != nsCRT::ToLower(aChar); +} + +PRBool nsCRT::IsLower(char aChar) +{ + return aChar != nsCRT::ToUpper(aChar); +} + +//////////////////////////////////////////////////////////////////////////////// +// My lovely strtok routine + +#define IS_DELIM(m, c) ((m)[(c) >> 3] & (1 << ((c) & 7))) +#define SET_DELIM(m, c) ((m)[(c) >> 3] |= (1 << ((c) & 7))) +#define DELIM_TABLE_SIZE 32 + +char* nsCRT::strtok(char* string, const char* delims, char* *newStr) +{ + NS_ASSERTION(string, "Unlike regular strtok, the first argument cannot be null."); + + char delimTable[DELIM_TABLE_SIZE]; + PRUint32 i; + char* result; + char* str = string; + + for (i = 0; i < DELIM_TABLE_SIZE; i++) + delimTable[i] = '\0'; + + for (i = 0; delims[i]; i++) { + SET_DELIM(delimTable, NS_STATIC_CAST(PRUint8, delims[i])); + } + NS_ASSERTION(delims[i] == '\0', "too many delimiters"); + + // skip to beginning + while (*str && IS_DELIM(delimTable, NS_STATIC_CAST(PRUint8, *str))) { + str++; + } + result = str; + + // fix up the end of the token + while (*str) { + if (IS_DELIM(delimTable, NS_STATIC_CAST(PRUint8, *str))) { + *str++ = '\0'; + break; + } + str++; + } + *newStr = str; + + return str == result ? NULL : result; +} + +//////////////////////////////////////////////////////////////////////////////// + +PRUint32 nsCRT::strlen(const PRUnichar* s) +{ + PRUint32 len = 0; + if(s) { + while (*s++ != 0) { + len++; + } + } + return len; +} + + +/** + * Compare unichar string ptrs, stopping at the 1st null + * NOTE: If both are null, we return 0. + * NOTE: We terminate the search upon encountering a NULL + * + * @update gess 11/10/99 + * @param s1 and s2 both point to unichar strings + * @return 0 if they match, -1 if s1s2 + */ +PRInt32 nsCRT::strcmp(const PRUnichar* s1, const PRUnichar* s2) { + if(s1 && s2) { + for (;;) { + PRUnichar c1 = *s1++; + PRUnichar c2 = *s2++; + if (c1 != c2) { + if (c1 < c2) return -1; + return 1; + } + if ((0==c1) || (0==c2)) break; + } + } + else { + if (s1) // s2 must have been null + return -1; + if (s2) // s1 must have been null + return 1; + } + return 0; +} + +/** + * Compare unichar string ptrs, stopping at the 1st null or nth char. + * NOTE: If either is null, we return 0. + * NOTE: We DO NOT terminate the search upon encountering NULL's before N + * + * @update gess 11/10/99 + * @param s1 and s2 both point to unichar strings + * @return 0 if they match, -1 if s1s2 + */ +PRInt32 nsCRT::strncmp(const PRUnichar* s1, const PRUnichar* s2, PRUint32 n) { + if(s1 && s2) { + if(n != 0) { + do { + PRUnichar c1 = *s1++; + PRUnichar c2 = *s2++; + if (c1 != c2) { + if (c1 < c2) return -1; + return 1; + } + } while (--n != 0); + } + } + return 0; +} + +PRUnichar* nsCRT::strdup(const PRUnichar* str) +{ + PRUint32 len = nsCRT::strlen(str); + return strndup(str, len); +} + +PRUnichar* nsCRT::strndup(const PRUnichar* str, PRUint32 len) +{ + nsCppSharedAllocator shared_allocator; + PRUnichar* rslt = shared_allocator.allocate(len + 1); // add one for the null + // PRUnichar* rslt = new PRUnichar[len + 1]; + + if (rslt == NULL) return NULL; + memcpy(rslt, str, len * sizeof(PRUnichar)); + rslt[len] = 0; + return rslt; +} + + /** + * |nsCRT::HashCode| is identical to |PL_HashString|, which tests + * (http://bugzilla.mozilla.org/showattachment.cgi?attach_id=26596) + * show to be the best hash among several other choices. + * + * We re-implement it here rather than calling it for two reasons: + * (1) in this interface, we also calculate the length of the + * string being hashed; and (2) the narrow and wide and `buffer' versions here + * will hash equivalent strings to the same value, e.g., "Hello" and L"Hello". + */ +PRUint32 nsCRT::HashCode(const char* str, PRUint32* resultingStrLen) +{ + PRUint32 h = 0; + const char* s = str; + + if (!str) return h; + + unsigned char c; + while ( (c = *s++) ) + h = (h>>28) ^ (h<<4) ^ c; + + if ( resultingStrLen ) + *resultingStrLen = (s-str)-1; + return h; +} + +PRUint32 nsCRT::HashCode(const PRUnichar* str, PRUint32* resultingStrLen) +{ + PRUint32 h = 0; + const PRUnichar* s = str; + + if (!str) return h; + + PRUnichar c; + while ( (c = *s++) ) + h = (h>>28) ^ (h<<4) ^ c; + + if ( resultingStrLen ) + *resultingStrLen = (s-str)-1; + return h; +} + +PRUint32 nsCRT::HashCodeAsUTF8(const PRUnichar* str, PRUint32* resultingStrLen) +{ + PRUint32 h = 0; + const PRUnichar* s = str; + + { + PRUint16 W1 = 0; // the first UTF-16 word in a two word tuple + PRUint32 U = 0; // the current char as UCS-4 + int code_length = 0; // the number of bytes in the UTF-8 sequence for the current char + + PRUint16 W; + while ( (W = *s++) ) + { + /* + * On the fly, decoding from UTF-16 (and/or UCS-2) into UTF-8 as per + * http://www.ietf.org/rfc/rfc2781.txt + * http://www.ietf.org/rfc/rfc2279.txt + */ + + if ( !W1 ) + { + if ( W < 0xD800 || 0xDFFF < W ) + { + U = W; + if ( W <= 0x007F ) + code_length = 1; + else if ( W <= 0x07FF ) + code_length = 2; + else + code_length = 3; + } + else if ( /* 0xD800 <= W1 && */ W <= 0xDBFF ) + W1 = W; + } + else + { + // as required by the standard, this code is careful to + // throw out illegal sequences + + if ( 0xDC00 <= W && W <= 0xDFFF ) + { + U = PRUint32( (W1&0x03FF)<<10 | (W&0x3FFF) ); + if ( U <= 0x001FFFFF ) + code_length = 4; + else if ( U <= 0x3FFFFFF ) + code_length = 5; + else + code_length = 6; + } + W1 = 0; + } + + + if ( code_length > 0 ) + { + static const PRUint16 sBytePrefix[7] = { 0x0000, 0x0000, 0x00C0, 0x00E0, 0x00F0, 0x00F8, 0x00FC }; + static const PRUint16 sShift[7] = { 0, 0, 6, 12, 18, 24, 30 }; + + /* + * Unlike the algorithm in http://www.ietf.org/rfc/rfc2279.txt + * we must calculate the bytes in left to right order so that + * our hash result matches what the narrow version would calculate + * on an already UTF-8 string. + */ + + // hash the first (and often, only, byte) + h = (h>>28) ^ (h<<4) ^ (sBytePrefix[code_length] | (U>>sShift[code_length])); + + // an unrolled loop for hashing any remaining bytes in this sequence + switch ( code_length ) + { // falling through in each case + case 6: h = (h>>28) ^ (h<<4) ^ (0x80 | ((U>>24) & 0x003F)); + case 5: h = (h>>28) ^ (h<<4) ^ (0x80 | ((U>>18) & 0x003F)); + case 4: h = (h>>28) ^ (h<<4) ^ (0x80 | ((U>>12) & 0x003F)); + case 3: h = (h>>28) ^ (h<<4) ^ (0x80 | ((U>>6 ) & 0x003F)); + case 2: h = (h>>28) ^ (h<<4) ^ (0x80 | ( U & 0x003F)); + default: code_length = 0; + break; + } + } + } + } + + if ( resultingStrLen ) + *resultingStrLen = (s-str)-1; + return h; +} + +PRUint32 nsCRT::BufferHashCode(const char* s, PRUint32 len) +{ + PRUint32 h = 0; + const char* done = s + len; + + while ( s < done ) + h = (h>>28) ^ (h<<4) ^ PRUint8(*s++); // cast to unsigned to prevent possible sign extension + + return h; +} + +PRUint32 nsCRT::BufferHashCode(const PRUnichar* s, PRUint32 len) +{ + PRUint32 h = 0; + const PRUnichar* done = s + len; + + while ( s < done ) + h = (h>>28) ^ (h<<4) ^ PRUint16(*s++); // cast to unsigned to prevent possible sign extension + + return h; +} + +// This should use NSPR but NSPR isn't exporting its PR_strtoll function +// Until then... +PRInt64 nsCRT::atoll(const char *str) +{ + if (!str) + return LL_Zero(); + + PRInt64 ll = LL_Zero(), digitll = LL_Zero(); + + while (*str && *str >= '0' && *str <= '9') { + LL_MUL(ll, ll, 10); + LL_UI2L(digitll, (*str - '0')); + LL_ADD(ll, ll, digitll); + str++; + } + + return ll; +} + +/** + * Determine if given char in valid ascii range + * + * @update ftang 04.27.2000 + * @param aChar is character to be tested + * @return TRUE if in ASCII range + */ +PRBool nsCRT::IsAscii(PRUnichar aChar) { + return (0x0080 > aChar); +} +/** + * Determine if given char in valid ascii range + * + * @update ftang 10.02.2001 + * @param aString is null terminated to be tested + * @return TRUE if all characters aare in ASCII range + */ +PRBool nsCRT::IsAscii(const PRUnichar *aString) { + while(*aString) { + if( 0x0080 <= *aString) + return PR_FALSE; + aString++; + } + return PR_TRUE; +} +/** + * Determine if given char in valid ascii range + * + * @update ftang 10.02.2001 + * @param aString is null terminated to be tested + * @return TRUE if all characters aare in ASCII range + */ +PRBool nsCRT::IsAscii(const char *aString) { + while(*aString) { + if( 0x80 & *aString) + return PR_FALSE; + aString++; + } + return PR_TRUE; +} +/** + * Determine whether the given string consists of valid ascii chars + * + * @param aString is null terminated + * @param aLength is the number of chars to test. This must be at most + * the number of chars in aString before the null terminator + * @return PR_TRUE if all chars are valid ASCII chars, PR_FALSE otherwise + */ +PRBool nsCRT::IsAscii(const char* aString, PRUint32 aLength) +{ + const char* end = aString + aLength; + while (aString < end) { + NS_ASSERTION(*aString, "Null byte before end of data!"); + if (0x80 & *aString) + return PR_FALSE; + ++aString; + } + return PR_TRUE; +} + +/** + * Determine if given char in valid alpha range + * + * @update rickg 03.10.2000 + * @param aChar is character to be tested + * @return TRUE if in alpha range + */ +PRBool nsCRT::IsAsciiAlpha(PRUnichar aChar) { + // XXX i18n + if (((aChar >= 'A') && (aChar <= 'Z')) || ((aChar >= 'a') && (aChar <= 'z'))) { + return PR_TRUE; + } + return PR_FALSE; +} + +/** + * Determine if given char is a valid space character + * + * @update rickg 03.10.2000 + * @param aChar is character to be tested + * @return TRUE if is valid space char + */ +PRBool nsCRT::IsAsciiSpace(PRUnichar aChar) { + // XXX i18n + if ((aChar == ' ') || (aChar == '\r') || (aChar == '\n') || (aChar == '\t')) { + return PR_TRUE; + } + return PR_FALSE; +} + + + +/** + * Determine if given char is valid digit + * + * @update rickg 03.10.2000 + * @param aChar is character to be tested + * @return TRUE if char is a valid digit + */ +PRBool nsCRT::IsAsciiDigit(PRUnichar aChar) { + // XXX i18n + return PRBool((aChar >= '0') && (aChar <= '9')); +} diff --git a/src/libs/xpcom18a4/xpcom/ds/nsCRT.h b/src/libs/xpcom18a4/xpcom/ds/nsCRT.h new file mode 100644 index 00000000..c168a0a6 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsCRT.h @@ -0,0 +1,301 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ +#ifndef nsCRT_h___ +#define nsCRT_h___ + +#include +#include +#include +#include "plstr.h" +#include "nscore.h" +#include "prtypes.h" +#include "nsCppSharedAllocator.h" + +#ifdef XP_MAC +# define NS_LINEBREAK "\015" +# define NS_LINEBREAK_LEN 1 +#else +# if defined(XP_WIN) || defined(XP_OS2) +# define NS_LINEBREAK "\015\012" +# define NS_LINEBREAK_LEN 2 +# else +# if defined(XP_UNIX) || defined(XP_BEOS) +# define NS_LINEBREAK "\012" +# define NS_LINEBREAK_LEN 1 +# endif /* XP_UNIX */ +# endif /* XP_WIN || XP_OS2 */ +#endif /* XP_MAC */ + +extern const PRUnichar kIsoLatin1ToUCS2[256]; + +// This macro can be used in a class declaration for classes that want +// to ensure that their instance memory is zeroed. +#define NS_DECL_AND_IMPL_ZEROING_OPERATOR_NEW \ + void* operator new(size_t sz) CPP_THROW_NEW { \ + void* rv = ::operator new(sz); \ + if (rv) { \ + memset(rv, 0, sz); \ + } \ + return rv; \ + } \ + void operator delete(void* ptr) { \ + ::operator delete(ptr); \ + } + +// This macro works with the next macro to declare a non-inlined +// version of the above. +#define NS_DECL_ZEROING_OPERATOR_NEW \ + void* operator new(size_t sz) CPP_THROW_NEW; \ + void operator delete(void* ptr); + +#define NS_IMPL_ZEROING_OPERATOR_NEW(_class) \ + void* _class::operator new(size_t sz) CPP_THROW_NEW { \ + void* rv = ::operator new(sz); \ + if (rv) { \ + memset(rv, 0, sz); \ + } \ + return rv; \ + } \ + void _class::operator delete(void* ptr) { \ + ::operator delete(ptr); \ + } + +// Freeing helper +#define CRTFREEIF(x) if (x) { nsCRT::free(x); x = 0; } + +/// This is a wrapper class around all the C runtime functions. + +class NS_COM nsCRT { +public: + enum { + TAB='\t' /* Horizontal Tab */, + LF='\n' /* Line Feed */, + VTAB='\v' /* Vertical Tab */, + FF='\f' /* Form Feed */, + CR='\r' /* Carriage Return */ + }; + + /*** + *** The following nsCRT::mem* functions are no longer + *** supported, please use the corresponding lib C + *** functions instead. + *** + *** nsCRT::memcpy() + *** nsCRT::memcmp() + *** nsCRT::memmove() + *** nsCRT::memset() + *** nsCRT::zero() + *** + *** Additionally, the following char* string utilities + *** are no longer supported, please use the + *** corresponding lib C functions instead. + *** + *** nsCRT::strlen() + *** + ***/ + + /** Compute the string length of s + @param s the string in question + @return the length of s + */ + static PRUint32 strlen(const char* s) { + return PRUint32(::strlen(s)); + } + + /// Compare s1 and s2. + static PRInt32 strcmp(const char* s1, const char* s2) { + return PRInt32(PL_strcmp(s1, s2)); + } + + static PRInt32 strncmp(const char* s1, const char* s2, + PRUint32 aMaxLen) { + return PRInt32(PL_strncmp(s1, s2, aMaxLen)); + } + + /// Case-insensitive string comparison. + static PRInt32 strcasecmp(const char* s1, const char* s2) { + return PRInt32(PL_strcasecmp(s1, s2)); + } + + /// Case-insensitive string comparison with length + static PRInt32 strncasecmp(const char* s1, const char* s2, PRUint32 aMaxLen) { + PRInt32 result=PRInt32(PL_strncasecmp(s1, s2, aMaxLen)); + //Egads. PL_strncasecmp is returning *very* negative numbers. + //Some folks expect -1,0,1, so let's temper its enthusiasm. + if (result<0) + result=-1; + return result; + } + + static PRInt32 strncmp(const char* s1, const char* s2, PRInt32 aMaxLen) { + // inline the first test (assumes strings are not null): + PRInt32 diff = ((const unsigned char*)s1)[0] - ((const unsigned char*)s2)[0]; + if (diff != 0) return diff; + return PRInt32(PL_strncmp(s1,s2,unsigned(aMaxLen))); + } + + static char* strdup(const char* str) { + return PL_strdup(str); + } + + static char* strndup(const char* str, PRUint32 len) { + return PL_strndup(str, len); + } + + static void free(char* str) { + PL_strfree(str); + } + + /** + + How to use this fancy (thread-safe) version of strtok: + + void main(void) { + printf("%s\n\nTokens:\n", string); + // Establish string and get the first token: + char* newStr; + token = nsCRT::strtok(string, seps, &newStr); + while (token != NULL) { + // While there are tokens in "string" + printf(" %s\n", token); + // Get next token: + token = nsCRT::strtok(newStr, seps, &newStr); + } + } + * WARNING - STRTOK WHACKS str THE FIRST TIME IT IS CALLED * + * MAKE A COPY OF str IF YOU NEED TO USE IT AFTER strtok() * + */ + static char* strtok(char* str, const char* delims, char* *newStr); + + /// Like strlen except for ucs2 strings + static PRUint32 strlen(const PRUnichar* s); + + /// Like strcmp except for ucs2 strings + static PRInt32 strcmp(const PRUnichar* s1, const PRUnichar* s2); + /// Like strcmp except for ucs2 strings + static PRInt32 strncmp(const PRUnichar* s1, const PRUnichar* s2, + PRUint32 aMaxLen); + + // You must use nsCRT::free(PRUnichar*) to free memory allocated + // by nsCRT::strdup(PRUnichar*). + static PRUnichar* strdup(const PRUnichar* str); + + // You must use nsCRT::free(PRUnichar*) to free memory allocated + // by strndup(PRUnichar*, PRUint32). + static PRUnichar* strndup(const PRUnichar* str, PRUint32 len); + + static void free(PRUnichar* str) { + nsCppSharedAllocator shared_allocator; + shared_allocator.deallocate(str, 0 /*we never new or kept the size*/); + } + + // Computes the hashcode for a c-string, returns the string length as + // an added bonus. + static PRUint32 HashCode(const char* str, + PRUint32* resultingStrLen = nsnull); + + // Computes the hashcode for a ucs2 string, returns the string length + // as an added bonus. + static PRUint32 HashCode(const PRUnichar* str, + PRUint32* resultingStrLen = nsnull); + + // Computes a hashcode for a ucs2 string that returns the same thing + // as the HashCode method taking a |char*| would if the string were + // converted to UTF8. Returns the string length as an added bonus. + static PRUint32 HashCodeAsUTF8(const PRUnichar* str, + PRUint32* resultingStrLen = nsnull); + + // Computes the hashcode for a buffer with a specified length. + static PRUint32 BufferHashCode(const char* str, PRUint32 strLen); + + // Computes the hashcode for a buffer with a specified length. + static PRUint32 BufferHashCode(const PRUnichar* str, PRUint32 strLen); + + // String to longlong + static PRInt64 atoll(const char *str); + + static char ToUpper(char aChar); + + static char ToLower(char aChar); + + static PRBool IsUpper(char aChar); + + static PRBool IsLower(char aChar); + + static PRBool IsAscii(PRUnichar aChar); + static PRBool IsAscii(const PRUnichar* aString); + static PRBool IsAsciiAlpha(PRUnichar aChar); + static PRBool IsAsciiDigit(PRUnichar aChar); + static PRBool IsAsciiSpace(PRUnichar aChar); + static PRBool IsAscii(const char* aString); + static PRBool IsAscii(const char* aString, PRUint32 aLength); +}; + +#define FF '\014' +#define TAB '\011' + +#define CRSTR "\015" +#define LFSTR "\012" +#define CRLF "\015\012" /* A CR LF equivalent string */ + + +#if defined(XP_MAC) + #define FILE_PATH_SEPARATOR ":" + #define FILE_ILLEGAL_CHARACTERS "" +#elif defined(XP_WIN) || defined(XP_OS2) + #define FILE_PATH_SEPARATOR "\\" + #define FILE_ILLEGAL_CHARACTERS "/:*?\"<>|" +#elif defined(XP_UNIX) || defined(XP_BEOS) + #define FILE_PATH_SEPARATOR "/" + #define FILE_ILLEGAL_CHARACTERS "" +#else + #error need_to_define_your_file_path_separator_and_illegal_characters +#endif + +#define NS_IS_SPACE(VAL) \ + (((((intn)(VAL)) & 0x7f) == ((intn)(VAL))) && isspace((intn)(VAL)) ) + +#define NS_IS_CNTRL(i) ((((unsigned int) (i)) > 0x7f) ? (int) 0 : iscntrl(i)) +#define NS_IS_DIGIT(i) ((((unsigned int) (i)) > 0x7f) ? (int) 0 : isdigit(i)) +#if defined(XP_WIN) || defined(XP_OS2) +#define NS_IS_ALPHA(VAL) (isascii((int)(VAL)) && isalpha((int)(VAL))) +#else +#define NS_IS_ALPHA(VAL) ((((unsigned int) (VAL)) > 0x7f) ? (int) 0 : isalpha((int)(VAL))) +#endif + + +#endif /* nsCRT_h___ */ diff --git a/src/libs/xpcom18a4/xpcom/ds/nsCheapSets.cpp b/src/libs/xpcom18a4/xpcom/ds/nsCheapSets.cpp new file mode 100644 index 00000000..954de2d1 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsCheapSets.cpp @@ -0,0 +1,180 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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 Communicator client code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsCheapSets.h" + +nsCheapStringSet::~nsCheapStringSet() +{ + nsStringHashSet* set = GetHash(); + if (set) { + delete set; + } else { + delete GetStr(); + } +} + +/** + * Put a string into the table + */ +nsresult +nsCheapStringSet::Put(const nsAString& aVal) +{ + // Add the value to the hash if it is there + nsStringHashSet* set = GetHash(); + if (set) { + return set->Put(aVal); + } + + // If a string is already there, create a hashtable and both of these to it + if (GetStr()) { + nsAString* oldStr = GetStr(); + nsresult rv = InitHash(&set); + NS_ENSURE_SUCCESS(rv, rv); + + rv = set->Put(*oldStr); + delete oldStr; + NS_ENSURE_SUCCESS(rv, rv); + + return set->Put(aVal); + } + + // Nothing exists in the hash right now, so just set the single string + return SetStr(aVal); +} + +void +nsCheapStringSet::Remove(const nsAString& aVal) +{ + // Remove from the hash if the hash is there + nsStringHashSet* set = GetHash(); + if (set) { + set->Remove(aVal); + return; + } + + // Remove the string if there is just a string + nsAString* str = GetStr(); + if (str && str->Equals(aVal)) { + delete str; + mValOrHash = nsnull; + } +} + +nsresult +nsCheapStringSet::InitHash(nsStringHashSet** aSet) +{ + nsStringHashSet* newSet = new nsStringHashSet(); + if (!newSet) { + return NS_ERROR_OUT_OF_MEMORY; + } + + nsresult rv = newSet->Init(10); + NS_ENSURE_SUCCESS(rv, rv); + + mValOrHash = newSet; + *aSet = newSet; + return NS_OK; +} + + +nsCheapInt32Set::~nsCheapInt32Set() +{ + delete GetHash(); +} + +nsresult +nsCheapInt32Set::Put(PRInt32 aVal) +{ + // Add the value to the hash or set the pointer as an int + nsInt32HashSet* set = GetHash(); + if (set) { + return set->Put(aVal); + } + + // Create the hash and add the value to it if there is an int already + if (IsInt()) { + PRInt32 oldInt = GetInt(); + + nsresult rv = InitHash(&set); + NS_ENSURE_SUCCESS(rv, rv); + + rv = set->Put(oldInt); + NS_ENSURE_SUCCESS(rv, rv); + + return set->Put(aVal); + } + + // Create the hash anyway if the int is negative (negative numbers cannot + // fit into our PtrBits abstraction) + if (aVal < 0) { + nsresult rv = InitHash(&set); + NS_ENSURE_SUCCESS(rv, rv); + + return set->Put(aVal); + } + + // Finally, just set the int if we can't do anything with hashes + SetInt(aVal); + return NS_OK; +} + +void +nsCheapInt32Set::Remove(PRInt32 aVal) +{ + nsInt32HashSet* set = GetHash(); + if (set) { + set->Remove(aVal); + } else if (IsInt() && GetInt() == aVal) { + mValOrHash = nsnull; + } +} + +nsresult +nsCheapInt32Set::InitHash(nsInt32HashSet** aSet) +{ + nsInt32HashSet* newSet = new nsInt32HashSet(); + if (!newSet) { + return NS_ERROR_OUT_OF_MEMORY; + } + + nsresult rv = newSet->Init(10); + NS_ENSURE_SUCCESS(rv, rv); + + mValOrHash = newSet; + *aSet = newSet; + return NS_OK; +} diff --git a/src/libs/xpcom18a4/xpcom/ds/nsCheapSets.h b/src/libs/xpcom18a4/xpcom/ds/nsCheapSets.h new file mode 100644 index 00000000..7e1c917d --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsCheapSets.h @@ -0,0 +1,194 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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 Communicator client code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +#ifndef __nsCheapSets_h__ +#define __nsCheapSets_h__ + +#include "nsHashSets.h" + +/** + * A string set that takes up minimal size when there are 0 or 1 strings in the + * set. Use for cases where sizes of 0 and 1 are even slightly common. + */ +class NS_COM nsCheapStringSet { +public: + nsCheapStringSet() : mValOrHash(nsnull) + { + } + ~nsCheapStringSet(); + + /** + * Put a string into the set + * @param aVal the value to put in + */ + nsresult Put(const nsAString& aVal); + + /** + * Remove a string from the set + * @param aVal the string to remove + */ + void Remove(const nsAString& aVal); + + /** + * Check if the set contains a particular string + * @param aVal the string to check for + * @return whether the string is in the set + */ + PRBool Contains(const nsAString& aVal) + { + nsStringHashSet* set = GetHash(); + // Check the value from the hash if the hash is there + if (set) { + return set->Contains(aVal); + } + + // Check whether the value is equal to the string if the string is there + nsAString* str = GetStr(); + return str && str->Equals(aVal); + } + +private: + typedef PRUint64 PtrBits; + + /** Get the hash pointer (or null if we're not a hash) */ + nsStringHashSet* GetHash() + { + return (PtrBits(mValOrHash) & 0x1) ? nsnull : (nsStringHashSet*)mValOrHash; + } + /** Find out whether it is a string */ + nsAString* GetStr() + { + return (PtrBits(mValOrHash) & 0x1) + ? (nsAString*)(PtrBits(mValOrHash) & ~0x1) + : nsnull; + } + /** Set the single string */ + nsresult SetStr(const nsAString& aVal) + { + nsString* str = new nsString(aVal); + if (!str) { + return NS_ERROR_OUT_OF_MEMORY; + } + mValOrHash = (nsAString*)(PtrBits(str) | 0x1); + return NS_OK; + } + /** Initialize the hash */ + nsresult InitHash(nsStringHashSet** aSet); + +private: + /** A hash or string ptr, depending on the lower bit (0=hash, 1=string) */ + void* mValOrHash; +}; + + +/** + * An integer set that takes up only 4 bytes when there are 0 or 1 integers + * in the set. Use for cases where sizes of 0 and 1 are even slightly common. + */ +class NS_COM nsCheapInt32Set { +public: + nsCheapInt32Set() : mValOrHash(nsnull) + { + } + ~nsCheapInt32Set(); + + /** + * Put an int into the set + */ + nsresult Put(PRInt32 aVal); + + /** + * Remove a int from the set + * @param aVal the int to remove + */ + void Remove(PRInt32 aVal); + + /** + * Check if the set contains a particular int + * @param aVal the int to check for + * @return whether the int is in the set + */ + PRBool Contains(PRInt32 aVal) + { + nsInt32HashSet* set = GetHash(); + if (set) { + return set->Contains(aVal); + } + if (IsInt()) { + return GetInt() == aVal; + } + return PR_FALSE; + } + +private: + typedef PRUint64 PtrBits; + + /** Get the hash pointer (or null if we're not a hash) */ + nsInt32HashSet* GetHash() + { + return PtrBits(mValOrHash) & 0x1 ? nsnull : (nsInt32HashSet*)mValOrHash; + } + /** Find out whether it is an integer */ + PRBool IsInt() + { + return !!(PtrBits(mValOrHash) & 0x1); + } + /** Get the single integer */ + PRInt32 GetInt() + { + return PtrBits(mValOrHash) >> 1; + } + /** Set the single integer */ + void SetInt(PRInt32 aInt) + { + mValOrHash = (void*)(uintptr_t)((aInt << 1) | 0x1); + } + /** Create the hash and initialize */ + nsresult InitHash(nsInt32HashSet** aSet); + +private: + /** A hash or int, depending on the lower bit (0=hash, 1=int) */ + void* mValOrHash; +}; + + +/** + * XXX We may want an nsCheapVoidSet and nsCheapCStringSet at some point + */ + + +#endif diff --git a/src/libs/xpcom18a4/xpcom/ds/nsClassHashtable.h b/src/libs/xpcom18a4/xpcom/ds/nsClassHashtable.h new file mode 100644 index 00000000..1fd73489 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsClassHashtable.h @@ -0,0 +1,149 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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 C++ hashtable templates. + * + * The Initial Developer of the Original Code is + * Benjamin Smedberg. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * 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 ***** */ + +#ifndef nsClassHashtable_h__ +#define nsClassHashtable_h__ + +#include "nsBaseHashtable.h" +#include "nsHashKeys.h" +#include "nsAutoPtr.h" + +/** + * templated hashtable class maps keys to C++ object pointers. + * See nsBaseHashtable for complete declaration. + * @param KeyClass a wrapper-class for the hashtable key, see nsHashKeys.h + * for a complete specification. + * @param Class the class-type being wrapped + * @see nsInterfaceHashtable, nsClassHashtable + */ +template +class nsClassHashtable : + public nsBaseHashtable< KeyClass, nsAutoPtr, T* > +{ +public: + typedef typename KeyClass::KeyType KeyType; + typedef T* UserDataType; + + /** + * @copydoc nsBaseHashtable::Get + * @param pData if the key doesn't exist, pData will be set to nsnull. + */ + PRBool Get(KeyType aKey, UserDataType* pData) const; +}; + + +/** + * Thread-safe version of nsClassHashtable + * @param KeyClass a wrapper-class for the hashtable key, see nsHashKeys.h + * for a complete specification. + * @param Class the class-type being wrapped + * @see nsInterfaceHashtable, nsClassHashtable + */ +template +class nsClassHashtableMT : + public nsBaseHashtableMT< KeyClass, nsAutoPtr, T* > +{ +public: + typedef typename KeyClass::KeyType KeyType; + typedef T* UserDataType; + + /** + * @copydoc nsBaseHashtable::Get + * @param pData if the key doesn't exist, pData will be set to nsnull. + */ + PRBool Get(KeyType aKey, UserDataType* pData) const; +}; + + +// +// nsClassHashtable definitions +// + +template +PRBool +nsClassHashtable::Get(KeyType aKey, T** retVal) const +{ + typename nsBaseHashtable,T*>::EntryType* ent = + this->GetEntry(aKey); + + if (ent) + { + if (retVal) + *retVal = ent->mData; + + return PR_TRUE; + } + + if (retVal) + *retVal = nsnull; + + return PR_FALSE; +} + + +// +// nsClassHashtableMT definitions +// + +template +PRBool +nsClassHashtableMT::Get(KeyType aKey, T** retVal) const +{ + PR_Lock(this->mLock); + + typename nsBaseHashtableMT,T*>::EntryType* ent = + this->GetEntry(aKey); + + if (ent) + { + if (retVal) + *retVal = ent->mData; + + PR_Unlock(this->mLock); + + return PR_TRUE; + } + + if (retVal) + *retVal = nsnull; + + PR_Unlock(this->mLock); + + return PR_FALSE; +} + +#endif // nsClassHashtable_h__ diff --git a/src/libs/xpcom18a4/xpcom/ds/nsCppSharedAllocator.h b/src/libs/xpcom18a4/xpcom/ds/nsCppSharedAllocator.h new file mode 100644 index 00000000..55f3e19d --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsCppSharedAllocator.h @@ -0,0 +1,127 @@ +#ifndef nsCppSharedAllocator_h__ +#define nsCppSharedAllocator_h__ + +#include "nsMemory.h" // for |nsMemory| +#include "nscore.h" // for |NS_XXX_CAST| +#include NEW_H // to allow placement |new| + + + // under Metrowerks (Mac), we don't have autoconf yet +#ifdef __MWERKS__ + #define HAVE_CPP_MEMBER_TEMPLATES + #define HAVE_CPP_NUMERIC_LIMITS +#endif + + // under MSVC shut off copious warnings about unused in-lines +#ifdef _MSC_VER + #pragma warning( disable: 4514 ) +#endif + +#ifdef HAVE_CPP_NUMERIC_LIMITS +#include +#else +#include +#endif + + +template +class nsCppSharedAllocator + /* + ...allows Standard Library containers, et al, to use our global shared + (XP)COM-aware allocator. + */ + { + public: + typedef T value_type; + typedef size_t size_type; + typedef ptrdiff_t difference_type; + + typedef T* pointer; + typedef const T* const_pointer; + + typedef T& reference; + typedef const T& const_reference; + + + + nsCppSharedAllocator() { } + +#ifdef HAVE_CPP_MEMBER_TEMPLATES + template + nsCppSharedAllocator( const nsCppSharedAllocator& ) { } +#endif + + ~nsCppSharedAllocator() { } + + + pointer + address( reference r ) const + { + return &r; + } + + const_pointer + address( const_reference r ) const + { + return &r; + } + + pointer + allocate( size_type n, const void* /*hint*/=0 ) + { + return NS_REINTERPRET_CAST(pointer, nsMemory::Alloc(NS_STATIC_CAST(PRUint32, n*sizeof(T)))); + } + + void + deallocate( pointer p, size_type /*n*/ ) + { + nsMemory::Free(p); + } + + void + construct( pointer p, const T& val ) + { + new (p) T(val); + } + + void + destroy( pointer p ) + { + p->~T(); + } + + size_type + max_size() const + { +#ifdef HAVE_CPP_NUMERIC_LIMITS + return numeric_limits::max() / sizeof(T); +#else + return ULONG_MAX / sizeof(T); +#endif + } + +#ifdef HAVE_CPP_MEMBER_TEMPLATES + template + struct rebind + { + typedef nsCppSharedAllocator other; + }; +#endif + }; + + +template +PRBool +operator==( const nsCppSharedAllocator&, const nsCppSharedAllocator& ) + { + return PR_TRUE; + } + +template +PRBool +operator!=( const nsCppSharedAllocator&, const nsCppSharedAllocator& ) + { + return PR_FALSE; + } + +#endif /* !defined(nsCppSharedAllocator_h__) */ diff --git a/src/libs/xpcom18a4/xpcom/ds/nsDataHashtable.h b/src/libs/xpcom18a4/xpcom/ds/nsDataHashtable.h new file mode 100644 index 00000000..7a14f826 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsDataHashtable.h @@ -0,0 +1,62 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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 C++ hashtable templates. + * + * The Initial Developer of the Original Code is + * Benjamin Smedberg. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * 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 ***** */ + +#ifndef nsDataHashtable_h__ +#define nsDataHashtable_h__ + +#include "nsHashKeys.h" +#include "nsBaseHashtable.h" + +/** + * templated hashtable class maps keys to simple datatypes. + * See nsBaseHashtable for complete declaration + * @param KeyClass a wrapper-class for the hashtable key, see nsHashKeys.h + * for a complete specification. + * @param DataType the simple datatype being wrapped + * @see nsInterfaceHashtable, nsClassHashtable + */ +template +class nsDataHashtable : + public nsBaseHashtable +{ }; + +template +class nsDataHashtableMT : + public nsBaseHashtableMT +{ }; + +#endif // nsDataHashtable_h__ diff --git a/src/libs/xpcom18a4/xpcom/ds/nsDeque.cpp b/src/libs/xpcom18a4/xpcom/ds/nsDeque.cpp new file mode 100644 index 00000000..d94568bc --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsDeque.cpp @@ -0,0 +1,627 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsDeque.h" +#include "nsCRT.h" +#ifdef DEBUG_rickg +#include +#endif + +/** + * 07/02/2001 09:17p 509,104 clangref.pdf from openwatcom's site + * Watcom C Language Reference Edition 11.0c + * page 118 of 297 + * + * The % symbol yields the remainder from the division of the first operand + * by the second operand. The operands of % must have integral type. + * + * When both operands of % are positive, the result is a positive value + * smaller than the second operand. When one or both operands is negative, + * whether the result is positive or negative is implementation-defined. + * + */ +/* Ok, so first of all, C is underspecified. joy. + * The following functions do not provide a correct implementation of modulus + * They provide functionality for x>-y. + * There are risks of 2*y being greater than max int, which is part of the + * reason no multiplication is used and other operations are avoided. + * + * modasgn + * @param x variable + * @param y expression + * approximately equivalent to x %= y + * + * modulus + * @param x expression + * @param y expression + * approximately equivalent to x % y + */ +#define modasgn(x,y) if (x<0) x+=y; x%=y +#define modulus(x,y) ((x<0)?(x+y)%(y):(x)%(y)) + +MOZ_DECL_CTOR_COUNTER(nsDeque) + +/** + * Standard constructor + * @param deallocator, called by Erase and ~nsDeque + */ +nsDeque::nsDeque(nsDequeFunctor* aDeallocator) { + MOZ_COUNT_CTOR(nsDeque); + mDeallocator=aDeallocator; + mOrigin=mSize=0; + mData=mBuffer; // don't allocate space until you must + mCapacity=sizeof(mBuffer)/sizeof(mBuffer[0]); + memset(mData, 0, mCapacity*sizeof(mBuffer[0])); +} + +/** + * Destructor + */ +nsDeque::~nsDeque() { + MOZ_COUNT_DTOR(nsDeque); + +#ifdef DEBUG_rickg + char buffer[30]; + printf("Capacity: %i\n", mCapacity); + + static int mCaps[15] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + switch(mCapacity) { + case 4: mCaps[0]++; break; + case 8: mCaps[1]++; break; + case 16: mCaps[2]++; break; + case 32: mCaps[3]++; break; + case 64: mCaps[4]++; break; + case 128: mCaps[5]++; break; + case 256: mCaps[6]++; break; + case 512: mCaps[7]++; break; + case 1024: mCaps[8]++; break; + case 2048: mCaps[9]++; break; + case 4096: mCaps[10]++; break; + default: + break; + } +#endif + + Erase(); + if (mData && (mData!=mBuffer)) { + delete [] mData; + } + mData=0; + SetDeallocator(0); +} + +/** + * Set the functor to be called by Erase() + * The deque owns the functor. + * + * @param aDeallocator functor object for use by Erase() + */ +void nsDeque::SetDeallocator(nsDequeFunctor* aDeallocator){ + if (mDeallocator) { + delete mDeallocator; + } + mDeallocator=aDeallocator; +} + +/** + * Remove all items from container without destroying them. + * + * @return *this + */ +nsDeque& nsDeque::Empty() { + if (mSize && mData) { + memset(mData, 0, mCapacity*sizeof(*mData)); + } + mSize=0; + mOrigin=0; + return *this; +} + +/** + * Remove and delete all items from container + * + * @return *this + */ +nsDeque& nsDeque::Erase() { + if (mDeallocator && mSize) { + ForEach(*mDeallocator); + } + return Empty(); +} + +/** + * This method quadruples the size of the deque + * Elements in the deque are resequenced so that elements + * in the deque are stored sequentially + * + * If the deque actually overflows, there's very little we can do. + * Perhaps this function should return PRBool/nsresult indicating success/failure. + * + * @return capacity of the deque + * If the deque did not grow, + * and you knew its capacity beforehand, + * then this would be a way to indicate the failure. + */ +PRInt32 nsDeque::GrowCapacity() { + PRInt32 theNewSize=mCapacity<<2; + NS_ASSERTION(theNewSize>mCapacity, "Overflow"); + if (theNewSize<=mCapacity) + return mCapacity; + void** temp=new void*[theNewSize]; + + //Here's the interesting part: You can't just move the elements + //directly (in situ) from the old buffer to the new one. + //Since capacity has changed, the old origin doesn't make + //sense anymore. It's better to resequence the elements now. + + if (temp) { + PRInt32 tempi=0; + PRInt32 i=0; + PRInt32 j=0; + for (i=mOrigin; i0) { + --mSize; + PRInt32 offset=modulus(mSize + mOrigin, mCapacity); + result=mData[offset]; + mData[offset]=0; + if (!mSize) { + mOrigin=0; + } + } + return result; +} + +/** + * This method gets called you want to remove and return + * the first member in the container. + * + * @return last item in container + */ +void* nsDeque::PopFront() { + void* result=0; + if (mSize>0) { + NS_ASSERTION(mOrigin < mCapacity, "Error: Bad origin"); + result=mData[mOrigin]; + mData[mOrigin++]=0; //zero it out for debugging purposes. + mSize--; + // Cycle around if we pop off the end + // and reset origin if when we pop the last element + if (mCapacity==mOrigin || !mSize) { + mOrigin=0; + } + } + return result; +} + +/** + * This method gets called you want to peek at the bottom + * member without removing it. + * + * @return last item in container + */ +void* nsDeque::Peek() { + void* result=0; + if (mSize>0) { + result = mData[modulus(mSize - 1 + mOrigin, mCapacity)]; + } + return result; +} + +/** + * This method gets called you want to peek at the topmost + * member without removing it. + * + * @return last item in container + */ +void* nsDeque::PeekFront() { + void* result=0; + if (mSize>0) { + result=mData[mOrigin]; + } + return result; +} + +/** + * Call this to retrieve the ith element from this container. + * Keep in mind that accessing the underlying elements is + * done in a relative fashion. Object 0 is not necessarily + * the first element (the first element is at mOrigin). + * + * @param aIndex : 0 relative offset of item you want + * @return void* or null + */ +void* nsDeque::ObjectAt(PRInt32 aIndex) const { + void* result=0; + if ((aIndex>=0) && (aIndexoperator==(aIter)); +} + +/** + * Compare two iterators for increasing order. + * + * @param aIter is the other iterator to be compared to + * @return TRUE if this object points to an element before + * the element pointed to by aIter. + * FALSE if this and aIter are not iterating over the same deque. + */ +PRBool nsDequeIterator::operator<(nsDequeIterator& aIter) { + return PRBool(((mIndex=(nsDequeIterator& aIter) { + return PRBool(((mIndex>=aIter.mIndex) && (&mDeque==&aIter.mDeque))); +} + +/** + * Pre-increment operator + * + * @return object at post-incremented index + */ +void* nsDequeIterator::operator++() { + NS_ASSERTION(mIndex=mDeque.mSize) return 0; +#endif + return mDeque.ObjectAt(++mIndex); +} + +/** + * Post-increment operator + * + * @param param is ignored + * @return object at pre-incremented index + */ +void* nsDequeIterator::operator++(int) { + NS_ASSERTION(mIndex<=mDeque.mSize, + "You have already reached the end of the Internet."\ + "You have seen everything there is to see. Please go back. Now." + ); +#ifndef TIMELESS_LIGHTWEIGHT + if (mIndex>mDeque.mSize) return 0; +#endif + return mDeque.ObjectAt(mIndex++); +} + +/** + * Pre-decrement operator + * + * @return object at pre-decremented index + */ +void* nsDequeIterator::operator--() { + NS_ASSERTION(mIndex>=0, + "You have reached the beginning of the Internet."\ + "You have seen everything there is to see. Please go forward. Now." + ); +#ifndef TIMELESS_LIGHTWEIGHT + if (mIndex<0) return 0; +#endif + return mDeque.ObjectAt(--mIndex); +} + +/** + * Post-decrement operator + * + * @param param is ignored + * @return object at post-decremented index + */ +void* nsDequeIterator::operator--(int) { + NS_ASSERTION(mIndex>=0, + "You have already reached the beginning of the Internet."\ + "You have seen everything there is to see. Please go forward. Now." + ); +#ifndef TIMELESS_LIGHTWEIGHT + if (mIndex<0) return 0; +#endif + return mDeque.ObjectAt(mIndex--); +} + +/** + * Dereference operator + * Note that the iterator floats, so you don't need to do: + * ++iter; aDeque.PopFront(); + * Unless you actually want your iterator to jump 2 spaces. + * + * Picture: [1 2I 3 4] + * PopFront() + * Picture: [2 3I 4] + * Note that I still happily points to object at the second index + * + * @return object at ith index + */ +void* nsDequeIterator::GetCurrent() { + NS_ASSERTION(mIndex=0,"Current is out of bounds"); +#ifndef TIMELESS_LIGHTWEIGHT + if (mIndex>=mDeque.mSize||mIndex<0) return 0; +#endif + return mDeque.ObjectAt(mIndex); +} + +/** + * Call this method when you want to iterate all the + * members of the container, passing a functor along + * to call your code. + * + * @param aFunctor object to call for each member + * @return *this + */ +void nsDequeIterator::ForEach(nsDequeFunctor& aFunctor) const{ + mDeque.ForEach(aFunctor); +} + +/** + * Call this method when you want to iterate all the + * members of the container, calling the functor you + * passed with each member. This process will interrupt + * if your function returns non 0 to this method. + * + * @param aFunctor object to call for each member + * @return first nonzero result of aFunctor or 0. + */ +const void* nsDequeIterator::FirstThat(nsDequeFunctor& aFunctor) const{ + return mDeque.FirstThat(aFunctor); +} diff --git a/src/libs/xpcom18a4/xpcom/ds/nsDeque.h b/src/libs/xpcom18a4/xpcom/ds/nsDeque.h new file mode 100644 index 00000000..7fdf7465 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsDeque.h @@ -0,0 +1,405 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/** + * MODULE NOTES: + * + * The Deque is a very small, very efficient container object + * than can hold elements of type void*, offering the following features: + * Its interface supports pushing and popping of elements. + * It can iterate (via an interator class) its elements. + * When full, it can efficiently resize dynamically. + * + * + * NOTE: The only bit of trickery here is that this deque is + * built upon a ring-buffer. Like all ring buffers, the first + * element may not be at index[0]. The mOrigin member determines + * where the first child is. This point is quietly hidden from + * customers of this class. + * + */ + +#ifndef _NSDEQUE +#define _NSDEQUE + +#include "nscore.h" + +/** + * The nsDequeFunctor class is used when you want to create + * callbacks between the deque and your generic code. + * Use these objects in a call to ForEach(); + * + */ + +class nsDequeFunctor{ +public: + virtual void* operator()(void* anObject)=0; +}; + +/****************************************************** + * Here comes the nsDeque class itself... + ******************************************************/ + +/** + * The deque (double-ended queue) class is a common container type, + * whose behavior mimics a line in your favorite checkout stand. + * Classic CS describes the common behavior of a queue as FIFO. + * A deque allows insertion and removal at both ends of + * the container. + * + * The deque stores pointers to items. + */ + +class nsDequeIterator; + +class NS_COM nsDeque { + friend class nsDequeIterator; + public: + nsDeque(nsDequeFunctor* aDeallocator); + ~nsDeque(); + + /** + * Returns the number of elements currently stored in + * this deque. + * + * @return number of elements currently in the deque + */ + inline PRInt32 GetSize() const {return mSize;} + + /** + * Appends new member at the end of the deque. + * + * @param item to store in deque + * @return *this + */ + nsDeque& Push(void* aItem); + + /** + * Inserts new member at the front of the deque. + * + * @param item to store in deque + * @return *this + */ + nsDeque& PushFront(void* aItem); + + /** + * Remove and return the last item in the container. + * + * @return the item that was the last item in container + */ + void* Pop(); + + /** + * Remove and return the first item in the container. + * + * @return the item that was first item in container + */ + void* PopFront(); + + /** + * Retrieve the bottom item without removing it. + * + * @return the first item in container + */ + + void* Peek(); + /** + * Return topmost item without removing it. + * + * @return the first item in container + */ + void* PeekFront(); + + /** + * Retrieve the i'th member from the deque without removing it. + * + * @param index of desired item + * @return i'th element in list + */ + void* ObjectAt(int aIndex) const; + + /** + * Remove all items from container without destroying them. + * + * @return *this + */ + nsDeque& Empty(); + + /** + * Remove and delete all items from container. + * Deletes are handled by the deallocator nsDequeFunctor + * which is specified at deque construction. + * + * @return *this + */ + nsDeque& Erase(); + + /** + * Creates a new iterator, pointing to the first + * item in the deque. + * + * @return new dequeIterator + */ + nsDequeIterator Begin() const; + + /** + * Creates a new iterator, pointing to the last + * item in the deque. + * + * @return new dequeIterator + */ + nsDequeIterator End() const; + + void* Last() const; + /** + * Call this method when you want to iterate all the + * members of the container, passing a functor along + * to call your code. + * + * @param aFunctor object to call for each member + * @return *this + */ + void ForEach(nsDequeFunctor& aFunctor) const; + + /** + * Call this method when you want to iterate all the + * members of the container, calling the functor you + * passed with each member. This process will interrupt + * if your function returns non 0 to this method. + * + * @param aFunctor object to call for each member + * @return first nonzero result of aFunctor or 0. + */ + const void* FirstThat(nsDequeFunctor& aFunctor) const; + + void SetDeallocator(nsDequeFunctor* aDeallocator); + +protected: + PRInt32 mSize; + PRInt32 mCapacity; + PRInt32 mOrigin; + nsDequeFunctor* mDeallocator; + void* mBuffer[8]; + void** mData; + +private: + + /** + * Simple default constructor (PRIVATE) + */ + nsDeque(); + + /** + * Copy constructor (PRIVATE) + * + * @param another deque + */ + nsDeque(const nsDeque& other); + + /** + * Deque assignment operator (PRIVATE) + * + * @param another deque + * @return *this + */ + nsDeque& operator=(const nsDeque& anOther); + + PRInt32 GrowCapacity(); +}; + +/****************************************************** + * Here comes the nsDequeIterator class... + ******************************************************/ + +class nsDequeIterator { +public: + /** + * DequeIterator is an object that knows how to iterate + * (forward and backward) through a Deque. Normally, + * you don't need to do this, but there are some special + * cases where it is pretty handy. + * + * One warning: the iterator is not bound to an item, + * it is bound to an index, so if you insert or remove + * from the beginning while using an iterator + * (which is not recommended) then the iterator will + * point to a different item. @see GetCurrent() + * + * Here you go. + * + * @param aQueue is the deque object to be iterated + * @param aIndex is the starting position for your iteration + */ + nsDequeIterator(const nsDeque& aQueue, int aIndex=0); + + /** + * Create a copy of a DequeIterator + * + * @param aCopy is another iterator to copy from + */ + nsDequeIterator(const nsDequeIterator& aCopy); + + /** + * Moves iterator to first element in the deque + * @return *this + */ + nsDequeIterator& First(); + + /** + * Standard assignment operator for dequeiterator + * @param aCopy is another iterator to copy from + * @return *this + */ + nsDequeIterator& operator=(const nsDequeIterator& aCopy); + + /** + * preform ! operation against two iterators to test for equivalence + * (or lack thereof)! + * + * @param aIter is the object to be compared to + * @return TRUE if NOT equal. + */ + PRBool operator!=(nsDequeIterator& aIter); + + /** + * Compare two iterators for increasing order. + * + * @param aIter is the other iterator to be compared to + * @return TRUE if this object points to an element before + * the element pointed to by aIter. + * FALSE if this and aIter are not iterating over + * the same deque. + */ + PRBool operator<(nsDequeIterator& aIter); + + /** + * Compare two iterators for equivalence. + * + * @param aIter is the other iterator to be compared to + * @return TRUE if EQUAL + */ + PRBool operator==(nsDequeIterator& aIter); + + /** + * Compare two iterators for non strict decreasing order. + * + * @param aIter is the other iterator to be compared to + * @return TRUE if this object points to the same element, or + * an element after the element pointed to by aIter. + * FALSE if this and aIter are not iterating over + * the same deque. + */ + PRBool operator>=(nsDequeIterator& aIter); + + /** + * Pre-increment operator + * Iterator will advance one index towards the end. + * + * @return object_at(++index) + */ + void* operator++(); + + /** + * Post-increment operator + * Iterator will advance one index towards the end. + * + * @param param is ignored + * @return object_at(mIndex++) + */ + void* operator++(int); + + /** + * Pre-decrement operator + * Iterator will advance one index towards the beginning. + * + * @return object_at(--index) + */ + void* operator--(); + + /** + * Post-decrement operator + * Iterator will advance one index towards the beginning. + * + * @param param is ignored + * @return object_at(index--) + */ + void* operator--(int); + + /** + * Retrieve the the iterator's notion of current node. + * + * Note that the iterator floats, so you don't need to do: + * ++iter; aDeque.PopFront(); + * Unless you actually want your iterator to jump 2 positions + * relative to its origin. + * + * Picture: [1 2i 3 4] + * PopFront() + * Picture: [2 3i 4] + * Note that I still happily points to object at the second index. + * + * @return object at i'th index + */ + void* GetCurrent(); + + /** + * Call this method when you want to iterate all the + * members of the container, passing a functor along + * to call your code. + * + * @param aFunctor object to call for each member + * @return *this + */ + void ForEach(nsDequeFunctor& aFunctor) const; + + /** + * Call this method when you want to iterate all the + * members of the container, calling the functor you + * passed with each member. This process will interrupt + * if your function returns non 0 to this method. + * + * @param aFunctor object to call for each member + * @return first nonzero result of aFunctor or 0. + */ + const void* FirstThat(nsDequeFunctor& aFunctor) const; + + protected: + + PRInt32 mIndex; + const nsDeque& mDeque; +}; +#endif diff --git a/src/libs/xpcom18a4/xpcom/ds/nsDoubleHashtable.h b/src/libs/xpcom18a4/xpcom/ds/nsDoubleHashtable.h new file mode 100644 index 00000000..27bf4ce5 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsDoubleHashtable.h @@ -0,0 +1,505 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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 Communicator client code. + * + * 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): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/** + * nsDoubleHashtable.h is OBSOLETE. Use nsTHashtable or a derivative instead. + */ + +#ifndef __nsDoubleHashtable_h__ +#define __nsDoubleHashtable_h__ + +#include "pldhash.h" +#include "nscore.h" +#include "nsString.h" +#include "nsReadableUtils.h" + +/* + * This file provides several major things to make PLDHashTable easier to use: + * - hash class macros for you to define a hashtable + * - default key classes to use as superclasses for your entries + * - empty maps for string, cstring, int and void + */ + +/* + * USAGE + * + * To use nsDoubleHashtable macros + * (1) Define an entry class + * (2) Create the hash class + * (3) Use the hash class + * + * EXAMPLE + * + * As an example, let's create a dictionary, a mapping from a string (the word) + * to the pronunciation and definition of those words. + * + * (1) Define an entry class + * + * What we want here is an entry class that contains the word, the + * pronunciation string, and the definition string. Since we have a string key + * we can use the standard PLDHashStringEntry class as our base, it will handle + * the key stuff for us automatically. + * + * #include "nsDoubleHashtable.h" + * + * // Do NOT ADD VIRTUAL METHODS INTO YOUR ENTRY. Everything will break. + * // This is because of the 4-byte pointer C++ magically prepends onto your + * // entry class. It interacts very unhappily with PLDHashTable. + * class DictionaryEntry : public PLDHashStringEntry { + * public: + * DictionaryEntry(const void* aKey) : PLDHashStringEntry(aKey) { } + * ~DictionaryEntry() { } + * nsString mPronunciation; + * nsString mDefinition; + * } + * + * (2) Create the hash class + * + * The final hash class you will use in step 3 is defined by 2 macros. + * + * DECL_DHASH_WRAPPER(Dictionary, DictionaryEntry, const nsAString&) + * DHASH_WRAPPER(Dictionary, DictionaryEntry, const nsAString&) + * + * (3) Use the hash class + * + * Here is a simple main() that might look up a string: + * + * int main(void) { + * Dictionary d; + * nsresult rv = d.Init(10); + * if (NS_FAILED(rv)) return 1; + * + * // Put an entry + * DictionaryEntry* a = d.AddEntry(NS_LITERAL_STRING("doomed")); + * if (!a) return 1; + * a->mDefinition.AssignLiteral("The state you get in when a Mozilla release is pending"); + * a->mPronunciation.AssignLiteral("doom-d"); + * + * // Get the entry + * DictionaryEntry* b = d.GetEntry(NS_LITERAL_STRING("doomed")); + * printf("doomed: %s\n", NS_ConvertUCS2toUTF8(b->mDefinition).get()); + * + * // Entries will be automagically cleaned up when the Dictionary object goes away + * return 0; + * } + * + * + * BONUS POINTS + * + * You may wish to extend this class and add helper functions like + * nsDependentString* GetDefinition(nsAString& aWord). For example: + * + * class MyDictionary : public Dictionary { + * public: + * MyDictionary() { } + * // Make SURE you have a virtual destructor + * virtual ~myDictionary() { } + * nsDependentString* GetDefinition(const nsAString& aWord) { + * DictionaryEntry* e = GetEntry(aWord); + * if (e) { + * // We're returning an nsDependentString here, callers need to delete it + * // and it doesn't last long, but at least it doesn't create a copy + * return new nsDependentString(e->mDefinition.get()); + * } else { + * return nsnull; + * } + * } + * nsresult PutDefinition(const nsAString& aWord, + * const nsAString& aDefinition, + * const nsAString& aPronunciation) { + * DictionaryEntry* e = AddEntry(aWord); + * if (!e) { + * return NS_ERROR_OUT_OF_MEMORY; + * } + * e->mDefinition = aDefinition; + * e->mPronunciation = aPronunciation; + * return NS_OK; + * } + * } + */ + +/* + * ENTRY CLASS DEFINITION + * + * The simplifications of PLDHashTable all hinge upon the idea of an entry + * class, which is a class you define, where you store the key and values that + * you will place in each hash entry. You must define six methods for an entry + * (the standard key classes, which you can extend from, define all of these + * for you except the constructor and destructor): + * + * CONSTRUCTOR(const void* aKey) + * When your entry is constructed it will only be given a pointer to the key. + * + * DESTRUCTOR + * Called when the entry is destroyed (of course). + * + * const void* GetKey() + * Must return a pointer to the key + * + * PRBool MatchEntry(const void* aKey) - return true or false depending on + * whether the key pointed to by aKey matches this entry + * + * static PLDHashNumber HashKey(const void* aKey) - get a hashcode based on the + * key (must be the same every time for the same key, but does not have + * to be unique) + * + * For a small hash that just does key->value, you will often just extend a + * standard key class and put a value member into it, and have a destructor and + * constructor--nothing else necessary. + * + * See the default key entry classes as example entry classes. + * + * NOTES: + * - Do NOT ADD VIRTUAL METHODS INTO YOUR ENTRY. Everything will break. + * This is because of the 4-byte pointer C++ magically prepends onto your + * entry class. It interacts very unhappily with PLDHashTable. + */ + +/* + * PRIVATE HASHTABLE MACROS + * + * These internal macros can be used to declare the callbacks for an entry + * class, but the wrapper class macros call these for you so don't call them. + */ + +// +// DHASH_CALLBACKS +// +// Define the hashtable callback functions. Do this in one place only, as you +// will have redundant symbols otherwise. +// +// ENTRY_CLASS: the classname of the entry +// +#define DHASH_CALLBACKS(ENTRY_CLASS) \ +PR_STATIC_CALLBACK(const void *) \ +ENTRY_CLASS##GetKey(PLDHashTable* table, PLDHashEntryHdr* entry) \ +{ \ + ENTRY_CLASS* e = NS_STATIC_CAST(ENTRY_CLASS*, entry); \ + return e->GetKey(); \ +} \ +PR_STATIC_CALLBACK(PLDHashNumber) \ +ENTRY_CLASS##HashKey(PLDHashTable* table, const void* key) \ +{ \ + return ENTRY_CLASS::HashKey(key); \ +} \ +PR_STATIC_CALLBACK(PRBool) \ +ENTRY_CLASS##MatchEntry(PLDHashTable *table, const PLDHashEntryHdr *entry, \ + const void *key) \ +{ \ + const ENTRY_CLASS* e = NS_STATIC_CAST(const ENTRY_CLASS*, entry); \ + return e->MatchEntry(key); \ +} \ +PR_STATIC_CALLBACK(void) \ +ENTRY_CLASS##ClearEntry(PLDHashTable *table, PLDHashEntryHdr *entry) \ +{ \ + ENTRY_CLASS* e = NS_STATIC_CAST(ENTRY_CLASS *, entry); \ + e->~ENTRY_CLASS(); \ +} \ +PR_STATIC_CALLBACK(PRBool) \ +ENTRY_CLASS##InitEntry(PLDHashTable *table, PLDHashEntryHdr *entry, \ + const void *key) \ +{ \ + new (entry) ENTRY_CLASS(key); \ + return PR_TRUE; \ +} + +// +// DHASH_INIT +// +// Initialize hashtable to a certain class. +// +// HASHTABLE: the name of the PLDHashTable variable +// ENTRY_CLASS: the classname of the entry +// NUM_INITIAL_ENTRIES: the number of entry slots the hashtable should start +// with +// RV: an nsresult variable to hold the outcome of the initialization. +// Will be NS_ERROR_OUT_OF_MEMORY if failed, NS_OK otherwise. +// +#define DHASH_INIT(HASHTABLE,ENTRY_CLASS,NUM_INITIAL_ENTRIES,RV) \ +PR_BEGIN_MACRO \ + static PLDHashTableOps hash_table_ops = \ + { \ + PL_DHashAllocTable, \ + PL_DHashFreeTable, \ + ENTRY_CLASS##GetKey, \ + ENTRY_CLASS##HashKey, \ + ENTRY_CLASS##MatchEntry, \ + PL_DHashMoveEntryStub, \ + ENTRY_CLASS##ClearEntry, \ + PL_DHashFinalizeStub, \ + ENTRY_CLASS##InitEntry \ + }; \ + PRBool isLive = PL_DHashTableInit(&(HASHTABLE), \ + &hash_table_ops, nsnull, \ + sizeof(ENTRY_CLASS), \ + (NUM_INITIAL_ENTRIES)); \ + if (!isLive) { \ + (HASHTABLE).ops = nsnull; \ + RV = NS_ERROR_OUT_OF_MEMORY; \ + } else { \ + RV = NS_OK; \ + } \ +PR_END_MACRO + + +/* + * WRAPPER CLASS + * + * This class handles initialization and destruction of the hashtable + * (you must call Init() yourself). It defines these functions: + * + * Init(aNumInitialEntries) + * Initialize the hashtable. This must be called once, it is only separate + * from the constructor so that you can get the return value. You should pass + * in the number of entries you think the hashtable will typically hold (this + * will be the amount of space allocated initially so that it will not have to + * grow). + * + * ENTRY_CLASS* GetEntry(aKey): + * Get the entry referenced by aKey and return a pointer to it. THIS IS A + * TEMPORARY POINTER and is only guaranteed to exist until the next time you do + * an operation on the hashtable. But you can safely use it until then. + * + * Returns nsnull if the entry is not found. + * + * ENTRY_CLASS* AddEntry(aKey): + * Create a new, empty entry and return a pointer to it for you to fill values + * into. THIS IS A TEMPORARY POINTER and is only guaranteed to exist until the + * next time you do an operation on the hashtable. But you can safely fill it + * in. + * + * Returns nsnull if the entry cannot be created (usually a low memory + * constraint). + * + * void Remove(aKey) + * Remove the entry referenced by aKey. If the entry does not exist, nothing + * will happen. + * + * + * DECL_DHASH_WRAPPER(CLASSNAME,ENTRY_CLASS,KEY_TYPE) + * + * Declare the hash class but do not define the functions. + * + * CLASSNAME: the name of the class to declare. + * ENTRY_CLASS: the class of the entry struct. + * KEY_TYPE: the name of the key type for GetEntry and AddEntry. + * + * + * DHASH_WRAPPER(CLASSNAME,ENTRY_CLASS,KEY_TYPE) + * + * Define the functions for the hash class. + * + * CLASSNAME: the name of the class to declare. + * ENTRY_CLASS: the class of the entry struct. + * KEY_TYPE: the name of the key type for GetEntry and AddEntry. + * + * + * CAVEATS: + * - You may have only *one* wrapper class per entry class. + */ + +#define DECL_DHASH_WRAPPER(CLASSNAME,ENTRY_CLASS,KEY_TYPE) \ +class DHASH_EXPORT CLASSNAME { \ +public: \ + CLASSNAME(); \ + ~CLASSNAME(); \ + nsresult Init(PRUint32 aNumInitialEntries); \ + ENTRY_CLASS* GetEntry(const KEY_TYPE aKey); \ + ENTRY_CLASS* AddEntry(const KEY_TYPE aKey); \ + void Remove(const KEY_TYPE aKey); \ + PLDHashTable mHashTable; \ +}; + +#define DHASH_WRAPPER(CLASSNAME,ENTRY_CLASS,KEY_TYPE) \ +DHASH_CALLBACKS(ENTRY_CLASS) \ +CLASSNAME::CLASSNAME() { \ + mHashTable.ops = nsnull; \ +} \ +CLASSNAME::~CLASSNAME() { \ + if (mHashTable.ops) { \ + PL_DHashTableFinish(&mHashTable); \ + } \ +} \ +nsresult CLASSNAME::Init(PRUint32 aNumInitialEntries) { \ + if (!mHashTable.ops) { \ + nsresult rv; \ + DHASH_INIT(mHashTable,ENTRY_CLASS,aNumInitialEntries,rv); \ + return rv; \ + } \ + return NS_OK; \ +} \ +ENTRY_CLASS* CLASSNAME::GetEntry(const KEY_TYPE aKey) { \ + ENTRY_CLASS* e = NS_STATIC_CAST(ENTRY_CLASS*, \ + PL_DHashTableOperate(&mHashTable, &aKey, \ + PL_DHASH_LOOKUP)); \ + return PL_DHASH_ENTRY_IS_BUSY(e) ? e : nsnull; \ +} \ +ENTRY_CLASS* CLASSNAME::AddEntry(const KEY_TYPE aKey) { \ + return NS_STATIC_CAST(ENTRY_CLASS*, \ + PL_DHashTableOperate(&mHashTable, &aKey, \ + PL_DHASH_ADD)); \ +} \ +void CLASSNAME::Remove(const KEY_TYPE aKey) { \ + PL_DHashTableOperate(&mHashTable, &aKey, PL_DHASH_REMOVE); \ +} + +/* + * STANDARD KEY ENTRY CLASSES + * + * We have declared some standard key classes for you to make life a little + * easier. These include string, int and void* keys. You can extend these + * and add value data members to make a working hash entry class with your + * values. + * + * PLDHashStringEntry: nsAString + * PLDHashCStringEntry: nsACString + * PLDHashInt32Entry: PRInt32 + * PLDHashVoidEntry: void* + * + * As a short example, if you want to make a class that maps int to string, + * you could do: + * + * class MyIntStringEntry : public PLDHashInt32Entry + * { + * public: + * MyIntStringEntry(const void* aKey) : PLDHashInt32Entry(aKey) { } + * ~MyIntStringEntry() { }; + * nsString mMyStr; + * }; + * + * XXX It could be advisable (unless COW strings ever happens) to have a + * PLDHashDependentStringEntry + */ + +// +// String-key entry +// +class NS_COM PLDHashStringEntry : public PLDHashEntryHdr +{ +public: + PLDHashStringEntry(const void* aKey) : + mKey(*NS_STATIC_CAST(const nsAString*, aKey)) { } + ~PLDHashStringEntry() { } + + const void* GetKey() const { + return NS_STATIC_CAST(const nsAString*, &mKey); + } + static PLDHashNumber HashKey(const void* key) { + return HashString(*NS_STATIC_CAST(const nsAString*, key)); + } + PRBool MatchEntry(const void* key) const { + return NS_STATIC_CAST(const nsAString*, key)->Equals(mKey); + } + + const nsString mKey; +}; + +// +// CString-key entry +// +class NS_COM PLDHashCStringEntry : public PLDHashEntryHdr +{ +public: + PLDHashCStringEntry(const void* aKey) : + mKey(*NS_STATIC_CAST(const nsACString*, aKey)) { } + ~PLDHashCStringEntry() { } + + const void* GetKey() const { + return NS_STATIC_CAST(const nsACString*, &mKey); + } + static PLDHashNumber HashKey(const void* key) { + return HashString(*NS_STATIC_CAST(const nsACString*, key)); + } + PRBool MatchEntry(const void* key) const { + return NS_STATIC_CAST(const nsACString*, key)->Equals(mKey); + } + + const nsCString mKey; +}; + +// +// Int-key entry +// +class NS_COM PLDHashInt32Entry : public PLDHashEntryHdr +{ +public: + PLDHashInt32Entry(const void* aKey) : + mKey(*(NS_STATIC_CAST(const PRInt32*, aKey))) { } + ~PLDHashInt32Entry() { } + + const void* GetKey() const { + return NS_STATIC_CAST(const PRInt32*, &mKey); + } + static PLDHashNumber HashKey(const void* key) { + return *NS_STATIC_CAST(const PRInt32*, key); + } + PRBool MatchEntry(const void* key) const { + return *(NS_STATIC_CAST(const PRInt32*, key)) == mKey; + } + + const PRInt32 mKey; +}; + + +// +// Void-key entry +// +class NS_COM PLDHashVoidEntry : public PLDHashEntryHdr +{ +public: + PLDHashVoidEntry(const void* aKey) : + mKey(*(const void**)aKey) { } + ~PLDHashVoidEntry() { } + + const void* GetKey() const { + return (const void**)&mKey; + } + static PLDHashNumber HashKey(const void* key) { + return PLDHashNumber(NS_PTR_TO_INT32(*(const void**)key)) >> 2; + } + PRBool MatchEntry(const void* key) const { + return *(const void**)key == mKey; + } + + const void* mKey; +}; + + +#define DHASH_EXPORT + + +#endif diff --git a/src/libs/xpcom18a4/xpcom/ds/nsEmptyEnumerator.cpp b/src/libs/xpcom18a4/xpcom/ds/nsEmptyEnumerator.cpp new file mode 100644 index 00000000..c00d118c --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsEmptyEnumerator.cpp @@ -0,0 +1,108 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * L. David Baron + * Pierre Phaneuf + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* + + An empty enumerator. + + */ + +#include "nsEmptyEnumerator.h" + +//////////////////////////////////////////////////////////////////////// + +MOZ_DECL_CTOR_COUNTER(EmptyEnumeratorImpl) + +EmptyEnumeratorImpl::EmptyEnumeratorImpl(void) +{ + MOZ_COUNT_CTOR(EmptyEnumeratorImpl); +} + +EmptyEnumeratorImpl::~EmptyEnumeratorImpl(void) +{ + MOZ_COUNT_DTOR(EmptyEnumeratorImpl); +} + +// nsISupports interface +NS_IMETHODIMP_(nsrefcnt) EmptyEnumeratorImpl::AddRef(void) +{ + return 2; +} + +NS_IMETHODIMP_(nsrefcnt) EmptyEnumeratorImpl::Release(void) +{ + return 1; +} + +NS_IMPL_QUERY_INTERFACE1(EmptyEnumeratorImpl, nsISimpleEnumerator) + + +// nsISimpleEnumerator interface +NS_IMETHODIMP EmptyEnumeratorImpl::HasMoreElements(PRBool* aResult) +{ + *aResult = PR_FALSE; + return NS_OK; +} + +NS_IMETHODIMP EmptyEnumeratorImpl::GetNext(nsISupports** aResult) +{ + return NS_ERROR_UNEXPECTED; +} + +static EmptyEnumeratorImpl* gEmptyEnumerator = nsnull; + +extern "C" NS_COM nsresult +NS_NewEmptyEnumerator(nsISimpleEnumerator** aResult) +{ + nsresult rv = NS_OK; + if (!gEmptyEnumerator) { + gEmptyEnumerator = new EmptyEnumeratorImpl(); + if (!gEmptyEnumerator) + rv = NS_ERROR_OUT_OF_MEMORY; + } + *aResult = gEmptyEnumerator; + return rv; +} + +/* static */ void +EmptyEnumeratorImpl::Shutdown() +{ + delete gEmptyEnumerator; + gEmptyEnumerator = nsnull; +} diff --git a/src/libs/xpcom18a4/xpcom/ds/nsEmptyEnumerator.h b/src/libs/xpcom18a4/xpcom/ds/nsEmptyEnumerator.h new file mode 100644 index 00000000..4b2feabe --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsEmptyEnumerator.h @@ -0,0 +1,64 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * L. David Baron + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* + + An empty enumerator. + + */ + +#include "nsIEnumerator.h" + +//////////////////////////////////////////////////////////////////////// + +class EmptyEnumeratorImpl : public nsISimpleEnumerator +{ +public: + EmptyEnumeratorImpl(void); + + // nsISupports interface + NS_DECL_ISUPPORTS_INHERITED // not really inherited, but no mRefCnt + + // nsISimpleEnumerator + NS_DECL_NSISIMPLEENUMERATOR + + static void Shutdown(); + +private: + ~EmptyEnumeratorImpl(void); +}; diff --git a/src/libs/xpcom18a4/xpcom/ds/nsEnumeratorUtils.cpp b/src/libs/xpcom18a4/xpcom/ds/nsEnumeratorUtils.cpp new file mode 100644 index 00000000..e91f68e5 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsEnumeratorUtils.cpp @@ -0,0 +1,253 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsEnumeratorUtils.h" + + +nsArrayEnumerator::nsArrayEnumerator(nsISupportsArray* aValueArray) + : mValueArray(aValueArray), + mIndex(0) +{ + NS_IF_ADDREF(mValueArray); +} + +nsArrayEnumerator::~nsArrayEnumerator(void) +{ + NS_IF_RELEASE(mValueArray); +} + +NS_IMPL_ISUPPORTS1(nsArrayEnumerator, nsISimpleEnumerator) + +NS_IMETHODIMP +nsArrayEnumerator::HasMoreElements(PRBool* aResult) +{ + NS_PRECONDITION(aResult != 0, "null ptr"); + if (! aResult) + return NS_ERROR_NULL_POINTER; + + if (!mValueArray) { + *aResult = PR_FALSE; + return NS_OK; + } + + PRUint32 cnt; + nsresult rv = mValueArray->Count(&cnt); + if (NS_FAILED(rv)) return rv; + *aResult = (mIndex < (PRInt32) cnt); + return NS_OK; +} + +NS_IMETHODIMP +nsArrayEnumerator::GetNext(nsISupports** aResult) +{ + NS_PRECONDITION(aResult != 0, "null ptr"); + if (! aResult) + return NS_ERROR_NULL_POINTER; + + if (!mValueArray) { + *aResult = nsnull; + return NS_OK; + } + + PRUint32 cnt; + nsresult rv = mValueArray->Count(&cnt); + if (NS_FAILED(rv)) return rv; + if (mIndex >= (PRInt32) cnt) + return NS_ERROR_UNEXPECTED; + + *aResult = mValueArray->ElementAt(mIndex++); + return NS_OK; +} + +extern NS_COM nsresult +NS_NewArrayEnumerator(nsISimpleEnumerator* *result, + nsISupportsArray* array) +{ + nsArrayEnumerator* enumer = new nsArrayEnumerator(array); + if (enumer == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + *result = enumer; + NS_ADDREF(*result); + return NS_OK; +} + +//////////////////////////////////////////////////////////////////////////////// + +nsSingletonEnumerator::nsSingletonEnumerator(nsISupports* aValue) + : mValue(aValue) +{ + NS_IF_ADDREF(mValue); + mConsumed = (mValue ? PR_FALSE : PR_TRUE); +} + +nsSingletonEnumerator::~nsSingletonEnumerator() +{ + NS_IF_RELEASE(mValue); +} + +NS_IMPL_ISUPPORTS1(nsSingletonEnumerator, nsISimpleEnumerator) + +NS_IMETHODIMP +nsSingletonEnumerator::HasMoreElements(PRBool* aResult) +{ + NS_PRECONDITION(aResult != 0, "null ptr"); + if (! aResult) + return NS_ERROR_NULL_POINTER; + + *aResult = !mConsumed; + return NS_OK; +} + + +NS_IMETHODIMP +nsSingletonEnumerator::GetNext(nsISupports** aResult) +{ + NS_PRECONDITION(aResult != 0, "null ptr"); + if (! aResult) + return NS_ERROR_NULL_POINTER; + + if (mConsumed) + return NS_ERROR_UNEXPECTED; + + mConsumed = PR_TRUE; + + *aResult = mValue; + NS_ADDREF(*aResult); + return NS_OK; +} + +extern "C" NS_COM nsresult +NS_NewSingletonEnumerator(nsISimpleEnumerator* *result, + nsISupports* singleton) +{ + nsSingletonEnumerator* enumer = new nsSingletonEnumerator(singleton); + if (enumer == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + *result = enumer; + NS_ADDREF(*result); + return NS_OK; +} + +//////////////////////////////////////////////////////////////////////////////// + +nsUnionEnumerator::nsUnionEnumerator(nsISimpleEnumerator* firstEnumerator, + nsISimpleEnumerator* secondEnumerator) + : mFirstEnumerator(firstEnumerator), + mSecondEnumerator(secondEnumerator), + mConsumed(PR_FALSE), mAtSecond(PR_FALSE) +{ +} + +nsUnionEnumerator::~nsUnionEnumerator() +{ +} + +NS_IMPL_ISUPPORTS1(nsUnionEnumerator, nsISimpleEnumerator) + +NS_IMETHODIMP +nsUnionEnumerator::HasMoreElements(PRBool* aResult) +{ + NS_PRECONDITION(aResult != 0, "null ptr"); + if (! aResult) + return NS_ERROR_NULL_POINTER; + + nsresult rv; + + if (mConsumed) { + *aResult = PR_FALSE; + return NS_OK; + } + + if (! mAtSecond) { + rv = mFirstEnumerator->HasMoreElements(aResult); + if (NS_FAILED(rv)) return rv; + + if (*aResult) + return NS_OK; + + mAtSecond = PR_TRUE; + } + + rv = mSecondEnumerator->HasMoreElements(aResult); + if (NS_FAILED(rv)) return rv; + + if (*aResult) + return NS_OK; + + *aResult = PR_FALSE; + mConsumed = PR_TRUE; + return NS_OK; +} + +NS_IMETHODIMP +nsUnionEnumerator::GetNext(nsISupports** aResult) +{ + NS_PRECONDITION(aResult != 0, "null ptr"); + if (! aResult) + return NS_ERROR_NULL_POINTER; + + if (mConsumed) + return NS_ERROR_UNEXPECTED; + + if (! mAtSecond) + return mFirstEnumerator->GetNext(aResult); + + return mSecondEnumerator->GetNext(aResult); +} + +extern "C" NS_COM nsresult +NS_NewUnionEnumerator(nsISimpleEnumerator* *result, + nsISimpleEnumerator* firstEnumerator, + nsISimpleEnumerator* secondEnumerator) +{ + *result = nsnull; + if (! firstEnumerator) { + *result = secondEnumerator; + } else if (! secondEnumerator) { + *result = firstEnumerator; + } else { + nsUnionEnumerator* enumer = new nsUnionEnumerator(firstEnumerator, secondEnumerator); + if (enumer == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + *result = enumer; + } + NS_ADDREF(*result); + return NS_OK; +} + + +//////////////////////////////////////////////////////////////////////////////// diff --git a/src/libs/xpcom18a4/xpcom/ds/nsEnumeratorUtils.h b/src/libs/xpcom18a4/xpcom/ds/nsEnumeratorUtils.h new file mode 100644 index 00000000..2d8182b8 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsEnumeratorUtils.h @@ -0,0 +1,129 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +#ifndef nsEnumeratorUtils_h__ +#define nsEnumeratorUtils_h__ + +#include "nsIEnumerator.h" +#include "nsISupportsArray.h" + +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +#define NS_NewSingletonEnumerator VBoxNsxpNS_NewSingletonEnumerator +#define NS_NewUnionEnumerator VBoxNsxpNS_NewUnionEnumerator +#endif /* VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + +class NS_COM nsArrayEnumerator : public nsISimpleEnumerator +{ +public: + // nsISupports interface + NS_DECL_ISUPPORTS + + // nsISimpleEnumerator interface + NS_IMETHOD HasMoreElements(PRBool* aResult); + NS_IMETHOD GetNext(nsISupports** aResult); + + // nsArrayEnumerator methods + nsArrayEnumerator(nsISupportsArray* aValueArray); + +private: + ~nsArrayEnumerator(void); + +protected: + nsISupportsArray* mValueArray; + PRInt32 mIndex; +}; + +extern NS_COM nsresult +NS_NewArrayEnumerator(nsISimpleEnumerator* *result, + nsISupportsArray* array); + +//////////////////////////////////////////////////////////////////////////////// + +class NS_COM nsSingletonEnumerator : public nsISimpleEnumerator +{ +public: + NS_DECL_ISUPPORTS + + // nsISimpleEnumerator methods + NS_IMETHOD HasMoreElements(PRBool* aResult); + NS_IMETHOD GetNext(nsISupports** aResult); + + nsSingletonEnumerator(nsISupports* aValue); + +private: + ~nsSingletonEnumerator(); + +protected: + nsISupports* mValue; + PRBool mConsumed; +}; + +extern "C" NS_COM nsresult +NS_NewSingletonEnumerator(nsISimpleEnumerator* *result, + nsISupports* singleton); + +//////////////////////////////////////////////////////////////////////// + +class NS_COM nsUnionEnumerator : public nsISimpleEnumerator +{ +public: + NS_DECL_ISUPPORTS + + // nsISimpleEnumerator methods + NS_IMETHOD HasMoreElements(PRBool* aResult); + NS_IMETHOD GetNext(nsISupports** aResult); + + nsUnionEnumerator(nsISimpleEnumerator* firstEnumerator, + nsISimpleEnumerator* secondEnumerator); + +private: + ~nsUnionEnumerator(); + +protected: + nsCOMPtr mFirstEnumerator, mSecondEnumerator; + PRBool mConsumed; + PRBool mAtSecond; +}; + +extern "C" NS_COM nsresult +NS_NewUnionEnumerator(nsISimpleEnumerator* *result, + nsISimpleEnumerator* firstEnumerator, + nsISimpleEnumerator* secondEnumerator); + +//////////////////////////////////////////////////////////////////////// + +#endif /* nsEnumeratorUtils_h__ */ diff --git a/src/libs/xpcom18a4/xpcom/ds/nsFixedSizeAllocator.cpp b/src/libs/xpcom18a4/xpcom/ds/nsFixedSizeAllocator.cpp new file mode 100644 index 00000000..1b6232f9 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsFixedSizeAllocator.cpp @@ -0,0 +1,153 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Chris Waterson mSize = aSize; + bucket->mFirst = nsnull; + bucket->mNext = mBuckets; + + mBuckets = bucket; + return bucket; +} + +nsresult +nsFixedSizeAllocator::Init(const char* aName, + const size_t* aBucketSizes, + PRInt32 aNumBuckets, + PRInt32 aInitialSize, + PRInt32 aAlign) +{ + NS_PRECONDITION(aNumBuckets > 0, "no buckets"); + if (aNumBuckets <= 0) + return NS_ERROR_INVALID_ARG; + + // Blow away the old pool if we're being re-initialized. + if (mBuckets) + PL_FinishArenaPool(&mPool); + + PRInt32 bucketspace = aNumBuckets * sizeof(Bucket); + PL_InitArenaPool(&mPool, aName, bucketspace + aInitialSize, aAlign); + + mBuckets = nsnull; + for (PRInt32 i = 0; i < aNumBuckets; ++i) + AddBucket(aBucketSizes[i]); + + return NS_OK; +} + +nsFixedSizeAllocator::Bucket * +nsFixedSizeAllocator::FindBucket(size_t aSize) +{ + Bucket** link = &mBuckets; + Bucket* bucket; + + while ((bucket = *link) != nsnull) { + if (aSize == bucket->mSize) { + // Promote to the head of the list, under the assumption + // that we'll allocate same-sized object contemporaneously. + *link = bucket->mNext; + bucket->mNext = mBuckets; + mBuckets = bucket; + return bucket; + } + + link = &bucket->mNext; + } + return nsnull; +} + +void* +nsFixedSizeAllocator::Alloc(size_t aSize) +{ + Bucket* bucket = FindBucket(aSize); + if (! bucket) { + // Oops, we don't carry that size. Let's fix that. + bucket = AddBucket(aSize); + if (! bucket) + return nsnull; + } + + void* next; + if (bucket->mFirst) { + next = bucket->mFirst; + bucket->mFirst = bucket->mFirst->mNext; + } + else { + PL_ARENA_ALLOCATE(next, &mPool, aSize); + if (!next) + return nsnull; + } + +#ifdef DEBUG + memset(next, 0xc8, aSize); +#endif + + return next; +} + +void +nsFixedSizeAllocator::Free(void* aPtr, size_t aSize) +{ + FreeEntry* entry = NS_REINTERPRET_CAST(FreeEntry*, aPtr); + Bucket* bucket = FindBucket(aSize); + +#ifdef DEBUG + NS_ASSERTION(bucket && bucket->mSize == aSize, "ack! corruption! bucket->mSize != aSize!"); + memset(aPtr, 0xd8, bucket->mSize); +#endif + + entry->mNext = bucket->mFirst; + bucket->mFirst = entry; +} diff --git a/src/libs/xpcom18a4/xpcom/ds/nsFixedSizeAllocator.h b/src/libs/xpcom18a4/xpcom/ds/nsFixedSizeAllocator.h new file mode 100644 index 00000000..16708cdc --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsFixedSizeAllocator.h @@ -0,0 +1,201 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Chris Waterson ~Foo(); + aAllocator.Free(aFoo, sizeof(Foo)); + } + + // ctor & dtor + Foo() {} + ~Foo() {} + }; + + + int main(int argc, char* argv[]) + { + // Somewhere in your code, you'll need to create an + // nsFixedSizeAllocator object and initialize it: + nsFixedSizeAllocator pool; + + // The fixed size allocator will support multiple fixed sizes. + // This array lists an initial set of sizes that the allocator + // should be prepared to support. In our case, there's just one, + // which is Foo. + static const size_t kBucketSizes[] + = { sizeof(Foo) } + + // This is the number of different "buckets" you'll need for + // fixed size objects. In our example, this will be "1". + static const PRInt32 kNumBuckets + = sizeof(kBucketSizes) / sizeof(size_t); + + // This is the intial size of the allocator, in bytes. We'll + // assume that we want to start with space for 1024 Foo objects. + static const PRInt32 kInitialPoolSize = + NS_SIZE_IN_HEAP(sizeof(Foo)) * 1024; + + // Initialize (or re-initialize) the pool + pool.Init("TheFooPool", kBucketSizes, kNumBuckets, kInitialPoolSize); + + // Now we can use the pool. + + // Create a new Foo object using the pool: + Foo* foo = Foo::Create(pool); + if (! foo) { + // uh oh, out of memory! + } + + // Delete the object. The memory used by `foo' is recycled in + // the pool, and placed in a freelist + Foo::Destroy(foo); + + // Create another foo: this one will be allocated from the + // free-list + foo = Foo::Create(pool); + + // When pool is destroyed, all of its memory is automatically + // freed. N.B. it will *not* call your objects' destructors! In + // this case, foo's ~Foo() method would never be called. + } + +*/ + +#ifndef nsFixedSizeAllocator_h__ +#define nsFixedSizeAllocator_h__ + +#include "nscore.h" +#include "nsError.h" +#include "plarena.h" + +#define NS_SIZE_IN_HEAP(_size) (_size) + +class NS_COM nsFixedSizeAllocator +{ +protected: + PLArenaPool mPool; + + struct Bucket; + struct FreeEntry; + + friend struct Bucket; + friend struct FreeEntry; + + struct FreeEntry { + FreeEntry* mNext; + }; + + struct Bucket { + size_t mSize; + FreeEntry* mFirst; + Bucket* mNext; + }; + + Bucket* mBuckets; + + Bucket * + AddBucket(size_t aSize); + + Bucket * + FindBucket(size_t aSize); + +public: + nsFixedSizeAllocator() : mBuckets(nsnull) {} + + ~nsFixedSizeAllocator() { + if (mBuckets) + PL_FinishArenaPool(&mPool); + } + + /** + * Initialize the fixed size allocator. 'aName' is used to tag + * the underlying PLArena object for debugging and measurement + * purposes. 'aNumBuckets' specifies the number of elements in + * 'aBucketSizes', which is an array of integral block sizes + * that this allocator should be prepared to handle. + */ + nsresult + Init(const char* aName, + const size_t* aBucketSizes, + PRInt32 aNumBuckets, + PRInt32 aInitialSize, + PRInt32 aAlign = 0); + + /** + * Allocate a block of memory 'aSize' bytes big. + */ + void* Alloc(size_t aSize); + + /** + * Free a pointer allocated using a fixed-size allocator + */ + void Free(void* aPtr, size_t aSize); +}; + + + +#endif // nsFixedSizeAllocator_h__ diff --git a/src/libs/xpcom18a4/xpcom/ds/nsHashKeys.h b/src/libs/xpcom18a4/xpcom/ds/nsHashKeys.h new file mode 100644 index 00000000..8a6d272e --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsHashKeys.h @@ -0,0 +1,315 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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 C++ hashtable templates. + * + * The Initial Developer of the Original Code is + * Benjamin Smedberg. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * 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 ***** */ + +#ifndef nsTHashKeys_h__ +#define nsTHashKeys_h__ + +#include "nsAString.h" +#include "nsString.h" +#include "nsID.h" +#include "nsCRT.h" +#include "nsReadableUtils.h" +#include "nsISupports.h" +#include "nsCOMPtr.h" +#include "pldhash.h" +#include NEW_H + +/** @file nsHashKeys.h + * standard HashKey classes for nsBaseHashtable and relatives. Each of these + * classes follows the nsTHashtable::EntryType specification + * + * Lightweight keytypes provided here: + * nsStringHashKey + * nsCStringHashKey + * nsUint32HashKey + * nsISupportsHashKey + * nsIDHashKey + * nsDepCharHashKey + */ + +/** + * hashkey wrapper using nsAString KeyType + * + * @see nsTHashtable::EntryType for specification + */ +class NS_COM nsStringHashKey : public PLDHashEntryHdr +{ +public: + typedef const nsAString& KeyType; + typedef const nsAString* KeyTypePointer; + + nsStringHashKey(KeyTypePointer aStr) : mStr(*aStr) { } + nsStringHashKey(const nsStringHashKey& toCopy) : mStr(toCopy.mStr) { } + ~nsStringHashKey() { } + + KeyType GetKey() const { return mStr; } + KeyTypePointer GetKeyPointer() const { return &mStr; } + PRBool KeyEquals(const KeyTypePointer aKey) const + { + return mStr.Equals(*aKey); + } + + static KeyTypePointer KeyToPointer(KeyType aKey) { return &aKey; } + static PLDHashNumber HashKey(const KeyTypePointer aKey) + { + return HashString(*aKey); + } + enum { ALLOW_MEMMOVE = PR_TRUE }; + +private: + const nsString mStr; +}; + +/** + * hashkey wrapper using nsACString KeyType + * + * @see nsTHashtable::EntryType for specification + */ +class NS_COM nsCStringHashKey : public PLDHashEntryHdr +{ +public: + typedef const nsACString& KeyType; + typedef const nsACString* KeyTypePointer; + + nsCStringHashKey(const nsACString* aStr) : mStr(*aStr) { } + nsCStringHashKey(const nsCStringHashKey& toCopy) : mStr(toCopy.mStr) { } + ~nsCStringHashKey() { } + + KeyType GetKey() const { return mStr; } + KeyTypePointer GetKeyPointer() const { return &mStr; } + + PRBool KeyEquals(KeyTypePointer aKey) const { return mStr.Equals(*aKey); } + + static KeyTypePointer KeyToPointer(KeyType aKey) { return &aKey; } + static PLDHashNumber HashKey(KeyTypePointer aKey) + { + return HashString(*aKey); + } + enum { ALLOW_MEMMOVE = PR_TRUE }; + +private: + const nsCString mStr; +}; + +/** + * hashkey wrapper using PRUint32 KeyType + * + * @see nsTHashtable::EntryType for specification + */ +class NS_COM nsUint32HashKey : public PLDHashEntryHdr +{ +public: + typedef const PRUint32& KeyType; + typedef const PRUint32* KeyTypePointer; + + nsUint32HashKey(KeyTypePointer aKey) : mValue(*aKey) { } + nsUint32HashKey(const nsUint32HashKey& toCopy) : mValue(toCopy.mValue) { } + ~nsUint32HashKey() { } + + KeyType GetKey() const { return mValue; } + KeyTypePointer GetKeyPointer() const { return &mValue; } + PRBool KeyEquals(KeyTypePointer aKey) const { return *aKey == mValue; } + + static KeyTypePointer KeyToPointer(KeyType aKey) { return &aKey; } + static PLDHashNumber HashKey(KeyTypePointer aKey) { return *aKey; } + enum { ALLOW_MEMMOVE = PR_TRUE }; + +private: + const PRUint32 mValue; +}; + +/** + * hashkey wrapper using nsISupports* KeyType + * + * @see nsTHashtable::EntryType for specification + */ +class NS_COM nsISupportsHashKey : public PLDHashEntryHdr +{ +public: + typedef nsISupports* KeyType; + typedef const nsISupports* KeyTypePointer; + + nsISupportsHashKey(const nsISupports* key) : + mSupports(NS_CONST_CAST(nsISupports*,key)) { } + nsISupportsHashKey(const nsISupportsHashKey& toCopy) : + mSupports(toCopy.mSupports) { } + ~nsISupportsHashKey() { } + + KeyType GetKey() const { return mSupports; } + KeyTypePointer GetKeyPointer() const { return mSupports; } + + PRBool KeyEquals(KeyTypePointer aKey) const { return aKey == mSupports; } + + static KeyTypePointer KeyToPointer(KeyType aKey) { return aKey; } + static PLDHashNumber HashKey(KeyTypePointer aKey) + { + return NS_PTR_TO_INT32(aKey) >>2; + } + enum { ALLOW_MEMMOVE = PR_TRUE }; + +private: + nsCOMPtr mSupports; +}; + +/** + * hashkey wrapper using void* KeyType + * + * @see nsTHashtable::EntryType for specification + */ +class NS_COM nsVoidPtrHashKey : public PLDHashEntryHdr +{ +public: + typedef const void* KeyType; + typedef const void* KeyTypePointer; + + nsVoidPtrHashKey(const void* key) : + mKey(key) { } + nsVoidPtrHashKey(const nsVoidPtrHashKey& toCopy) : + mKey(toCopy.mKey) { } + ~nsVoidPtrHashKey() { } + + KeyType GetKey() const { return mKey; } + KeyTypePointer GetKeyPointer() const { return mKey; } + + PRBool KeyEquals(KeyTypePointer aKey) const { return aKey == mKey; } + + static KeyTypePointer KeyToPointer(KeyType aKey) { return aKey; } + static PLDHashNumber HashKey(KeyTypePointer aKey) + { + return NS_PTR_TO_INT32(aKey) >>2; + } + enum { ALLOW_MEMMOVE = PR_TRUE }; + +private: + const void* mKey; +}; + +/** + * hashkey wrapper using nsID KeyType + * + * @see nsTHashtable::EntryType for specification + */ +class NS_COM nsIDHashKey : public PLDHashEntryHdr +{ +public: + typedef const nsID& KeyType; + typedef const nsID* KeyTypePointer; + + nsIDHashKey(const nsID* id) : mID(*id) { } + nsIDHashKey(const nsIDHashKey& toCopy) : mID(toCopy.mID) { } + ~nsIDHashKey() { } + + KeyType GetKey() const { return mID; } + KeyTypePointer GetKeyPointer() const { return &mID; } + + PRBool KeyEquals(KeyTypePointer aKey) const { return aKey->Equals(mID); } + + static KeyTypePointer KeyToPointer(KeyType aKey) { return &aKey; } + static PLDHashNumber HashKey(KeyTypePointer aKey); + enum { ALLOW_MEMMOVE = PR_TRUE }; + +private: + const nsID mID; +}; + +/** + * hashkey wrapper for "dependent" const char*; this class does not "own" + * its string pointer. + * + * This class must only be used if the strings have a lifetime longer than + * the hashtable they occupy. This normally occurs only for static + * strings or strings that have been arena-allocated. + * + * @see nsTHashtable::EntryType for specification + */ +class NS_COM nsDepCharHashKey : public PLDHashEntryHdr +{ +public: + typedef const char* KeyType; + typedef const char* KeyTypePointer; + + nsDepCharHashKey(const char* aKey) { mKey = aKey; } + nsDepCharHashKey(const nsDepCharHashKey& toCopy) { mKey = toCopy.mKey; } + ~nsDepCharHashKey() { } + + const char* GetKey() const { return mKey; } + const char* GetKeyPointer() const { return mKey; } + PRBool KeyEquals(const char* aKey) const + { + return !strcmp(mKey, aKey); + } + + static const char* KeyToPointer(const char* aKey) { return aKey; } + static PLDHashNumber HashKey(const char* aKey) { return nsCRT::HashCode(aKey); } + enum { ALLOW_MEMMOVE = PR_TRUE }; + +private: + const char* mKey; +}; + +/** + * hashkey wrapper for const char*; at construction, this class duplicates + * a string pointed to by the pointer so that it doesn't matter whether or not + * the string lives longer than the hash table. + */ +class NS_COM nsCharPtrHashKey : public PLDHashEntryHdr +{ +public: + typedef const char* KeyType; + typedef const char* KeyTypePointer; + + nsCharPtrHashKey(const char* aKey) : mKey(strdup(aKey)) { } + nsCharPtrHashKey(const nsCharPtrHashKey& toCopy) : mKey(strdup(toCopy.mKey)) { } + ~nsCharPtrHashKey() { if (mKey) free(NS_CONST_CAST(char *, mKey)); } + + const char* GetKey() const { return mKey; } + const char* GetKeyPointer() const { return mKey; } + PRBool KeyEquals(KeyTypePointer aKey) const + { + return !strcmp(mKey, aKey); + } + + static KeyTypePointer KeyToPointer(KeyType aKey) { return aKey; } + static PLDHashNumber HashKey(KeyTypePointer aKey) { return nsCRT::HashCode(aKey); } + + enum { ALLOW_MEMMOVE = PR_TRUE }; + +private: + const char* mKey; +}; + +#endif // nsTHashKeys_h__ diff --git a/src/libs/xpcom18a4/xpcom/ds/nsHashSets.cpp b/src/libs/xpcom18a4/xpcom/ds/nsHashSets.cpp new file mode 100644 index 00000000..3f11ba55 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsHashSets.cpp @@ -0,0 +1,46 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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 Communicator client code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nscore.h" +#include NEW_H + +#include "nsHashSets.h" + +DHASH_SET(nsStringHashSet, PLDHashStringEntry, nsAString&) +DHASH_SET(nsCStringHashSet,PLDHashCStringEntry,nsACString&) +DHASH_SET(nsInt32HashSet, PLDHashInt32Entry, PRInt32) +DHASH_SET(nsVoidHashSet, PLDHashVoidEntry, void*) diff --git a/src/libs/xpcom18a4/xpcom/ds/nsHashSets.h b/src/libs/xpcom18a4/xpcom/ds/nsHashSets.h new file mode 100644 index 00000000..627a6a06 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsHashSets.h @@ -0,0 +1,107 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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 Communicator client code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +#ifndef __nsHashSets_h__ +#define __nsHashSets_h__ + +#include "nsDoubleHashtable.h" + +/* + * HASH SETS + * + * These hash classes describe hashtables that contain keys without values. + * This is useful when you want to store things and then just test for their + * existence later. We have defined standard ones for string, int and void. + * + * nsStringHashSet: nsAString& + * nsCStringHashSet: nsACString& + * nsInt32HashSet: PRInt32 + * nsVoidHashSet: void* + * + * USAGE: + * Put(): put a thing of the given type into the set + * Contains(): whether it contains a thing of the given type + * To use, you just do: (for example) + * + * #include "nsDoubleHashtable.h" + * nsInt32HashSet mySet; + * mySet.Init(1); + * mySet.Put(5); + * if (mySet.Contains(5)) { + * printf("yay\n"); + * } + * + * There is a nice convenient macro for declaring empty map classes: + * DECL_DHASH_SET(CLASSNAME, ENTRY_CLASS, KEY_TYPE) + * - CLASSNAME: the name of the class + * - ENTRY_CLASS: the name of the entry class with the key in it + * - KEY_TYPE: the type of key for Put() and Contains() + * + * DHASH_SET(CLASSNAME, ENTRY_CLASS, KEY_TYPE) is the companion macro + * you must put in the .cpp (implementation) code. + */ + +#define DECL_DHASH_SET(CLASSNAME,ENTRY_CLASS,KEY_TYPE) \ +DECL_DHASH_WRAPPER(CLASSNAME##Super,ENTRY_CLASS,KEY_TYPE) \ +class DHASH_EXPORT CLASSNAME : public CLASSNAME##Super { \ +public: \ + CLASSNAME() : CLASSNAME##Super() { } \ + ~CLASSNAME() { } \ + nsresult Put(const KEY_TYPE aKey) { \ + return AddEntry(aKey) ? NS_OK : NS_ERROR_OUT_OF_MEMORY; \ + } \ + PRBool Contains(const KEY_TYPE aKey) { \ + return GetEntry(aKey) ? PR_TRUE : PR_FALSE; \ + } \ +}; + +#define DHASH_SET(CLASSNAME,ENTRY_CLASS,KEY_TYPE) \ +DHASH_WRAPPER(CLASSNAME##Super,ENTRY_CLASS,KEY_TYPE) + +#undef DHASH_EXPORT +#define DHASH_EXPORT NS_COM + +DECL_DHASH_SET(nsStringHashSet, PLDHashStringEntry, nsAString&) +DECL_DHASH_SET(nsCStringHashSet,PLDHashCStringEntry,nsACString&) +DECL_DHASH_SET(nsInt32HashSet, PLDHashInt32Entry, PRInt32) +DECL_DHASH_SET(nsVoidHashSet, PLDHashVoidEntry, void*) + +#undef DHASH_EXPORT +#define DHASH_EXPORT + + +#endif diff --git a/src/libs/xpcom18a4/xpcom/ds/nsHashtable.cpp b/src/libs/xpcom18a4/xpcom/ds/nsHashtable.cpp new file mode 100644 index 00000000..ce74fb28 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsHashtable.cpp @@ -0,0 +1,896 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** + * This Original Code has been modified by IBM Corporation. + * Modifications made by IBM described herein are + * Copyright (c) International Business Machines + * Corporation, 2000 + * + * Modifications to Mozilla code or documentation + * identified per MPL Section 3.3 + * + * Date Modified by Description of modification + * 04/20/2000 IBM Corp. Added PR_CALLBACK for Optlink use in OS2 + */ + +#include +#include "prmem.h" +#include "prlog.h" +#include "nsHashtable.h" +#include "nsReadableUtils.h" +#include "nsIObjectInputStream.h" +#include "nsIObjectOutputStream.h" +#include "nsCRT.h" + +struct HTEntry : PLDHashEntryHdr +{ + nsHashKey* key; + void* value; +}; + +// +// Key operations +// + +PR_STATIC_CALLBACK(PRBool) +matchKeyEntry(PLDHashTable*, const PLDHashEntryHdr* entry, + const void* key) +{ + const HTEntry* hashEntry = + NS_STATIC_CAST(const HTEntry*, entry); + + if (hashEntry->key == key) + return PR_TRUE; + + const nsHashKey* otherKey = NS_REINTERPRET_CAST(const nsHashKey*, key); + return otherKey->Equals(hashEntry->key); +} + +PR_STATIC_CALLBACK(PLDHashNumber) +hashKey(PLDHashTable* table, const void* key) +{ + const nsHashKey* hashKey = NS_STATIC_CAST(const nsHashKey*, key); + + return hashKey->HashCode(); +} + +PR_STATIC_CALLBACK(void) +clearHashEntry(PLDHashTable* table, PLDHashEntryHdr* entry) +{ + HTEntry* hashEntry = NS_STATIC_CAST(HTEntry*, entry); + + // leave it up to the nsHashKey destructor to free the "value" + delete hashEntry->key; + hashEntry->key = nsnull; + hashEntry->value = nsnull; // probably not necessary, but for + // sanity's sake +} + + +static const PLDHashTableOps hashtableOps = { + PL_DHashAllocTable, + PL_DHashFreeTable, + PL_DHashGetKeyStub, + hashKey, + matchKeyEntry, + PL_DHashMoveEntryStub, + clearHashEntry, + PL_DHashFinalizeStub, + nsnull, +}; + + +// +// Enumerator callback +// + +struct _HashEnumerateArgs { + nsHashtableEnumFunc fn; + void* arg; +}; + +PR_STATIC_CALLBACK(PLDHashOperator) +hashEnumerate(PLDHashTable* table, PLDHashEntryHdr* hdr, PRUint32 i, void *arg) +{ + _HashEnumerateArgs* thunk = (_HashEnumerateArgs*)arg; + HTEntry* entry = NS_STATIC_CAST(HTEntry*, hdr); + + switch (thunk->fn(entry->key, entry->value, thunk->arg)) { + case kHashEnumerateNext: + return PL_DHASH_NEXT; + case kHashEnumerateRemove: + return PL_DHASH_REMOVE; + } + return PL_DHASH_STOP; +} + +// +// HashKey +// + +nsHashKey::~nsHashKey(void) +{ + MOZ_COUNT_DTOR(nsHashKey); +} + +nsresult +nsHashKey::Write(nsIObjectOutputStream* aStream) const +{ + NS_NOTREACHED("oops"); + return NS_ERROR_NOT_IMPLEMENTED; +} + +MOZ_DECL_CTOR_COUNTER(nsHashtable) + +nsHashtable::nsHashtable(PRUint32 aInitSize, PRBool threadSafe) + : mLock(NULL), mEnumerating(PR_FALSE) +{ + MOZ_COUNT_CTOR(nsHashtable); + + PRBool result = PL_DHashTableInit(&mHashtable, &hashtableOps, nsnull, + sizeof(HTEntry), aInitSize); + + NS_ASSERTION(result, "Hashtable failed to initialize"); + + // make sure we detect this later + if (!result) + mHashtable.ops = nsnull; + + if (threadSafe) { + mLock = PR_NewLock(); + if (mLock == NULL) { + // Cannot create a lock. If running on a multiprocessing system + // we are sure to die. + PR_ASSERT(mLock != NULL); + } + } +} + + +nsHashtable::~nsHashtable() { + MOZ_COUNT_DTOR(nsHashtable); + if (mHashtable.ops) + PL_DHashTableFinish(&mHashtable); + if (mLock) PR_DestroyLock(mLock); +} + +PRBool nsHashtable::Exists(nsHashKey *aKey) +{ + if (mLock) PR_Lock(mLock); + + if (!mHashtable.ops) + return PR_FALSE; + + PLDHashEntryHdr *entry = + PL_DHashTableOperate(&mHashtable, aKey, PL_DHASH_LOOKUP); + + PRBool exists = PL_DHASH_ENTRY_IS_BUSY(entry); + + if (mLock) PR_Unlock(mLock); + + return exists; +} + +void *nsHashtable::Put(nsHashKey *aKey, void *aData) +{ + void *res = NULL; + + if (!mHashtable.ops) return nsnull; + + if (mLock) PR_Lock(mLock); + + // shouldn't be adding an item during enumeration + PR_ASSERT(!mEnumerating); + + HTEntry* entry = + NS_STATIC_CAST(HTEntry*, + PL_DHashTableOperate(&mHashtable, aKey, PL_DHASH_ADD)); + + if (entry) { // don't return early, or you'll be locked! + if (entry->key) { + // existing entry, need to boot the old value + res = entry->value; + entry->value = aData; + } else { + // new entry (leave res == null) + entry->key = aKey->Clone(); + entry->value = aData; + } + } + + if (mLock) PR_Unlock(mLock); + + return res; +} + +void *nsHashtable::Get(nsHashKey *aKey) +{ + if (!mHashtable.ops) return nsnull; + + if (mLock) PR_Lock(mLock); + + HTEntry* entry = + NS_STATIC_CAST(HTEntry*, + PL_DHashTableOperate(&mHashtable, aKey, PL_DHASH_LOOKUP)); + void *ret = PL_DHASH_ENTRY_IS_BUSY(entry) ? entry->value : nsnull; + + if (mLock) PR_Unlock(mLock); + + return ret; +} + +void *nsHashtable::Remove(nsHashKey *aKey) +{ + if (!mHashtable.ops) return nsnull; + + if (mLock) PR_Lock(mLock); + + // shouldn't be adding an item during enumeration + PR_ASSERT(!mEnumerating); + + + // need to see if the entry is actually there, in order to get the + // old value for the result + HTEntry* entry = + NS_STATIC_CAST(HTEntry*, + PL_DHashTableOperate(&mHashtable, aKey, PL_DHASH_LOOKUP)); + void *res; + + if (PL_DHASH_ENTRY_IS_FREE(entry)) { + // value wasn't in the table anyway + res = nsnull; + } else { + res = entry->value; + PL_DHashTableRawRemove(&mHashtable, entry); + } + + if (mLock) PR_Unlock(mLock); + + return res; +} + +// XXX This method was called _hashEnumerateCopy, but it didn't copy the element! +// I don't know how this was supposed to work since the elements are neither copied +// nor refcounted. +PR_STATIC_CALLBACK(PLDHashOperator) +hashEnumerateShare(PLDHashTable *table, PLDHashEntryHdr *hdr, + PRUint32 i, void *arg) +{ + nsHashtable *newHashtable = (nsHashtable *)arg; + HTEntry * entry = NS_STATIC_CAST(HTEntry*, hdr); + + newHashtable->Put(entry->key, entry->value); + return PL_DHASH_NEXT; +} + +nsHashtable * nsHashtable::Clone() +{ + if (!mHashtable.ops) return nsnull; + + PRBool threadSafe = (mLock != nsnull); + nsHashtable *newHashTable = new nsHashtable(mHashtable.entryCount, threadSafe); + + PL_DHashTableEnumerate(&mHashtable, hashEnumerateShare, newHashTable); + return newHashTable; +} + +void nsHashtable::Enumerate(nsHashtableEnumFunc aEnumFunc, void* aClosure) +{ + if (!mHashtable.ops) return; + + PRBool wasEnumerating = mEnumerating; + mEnumerating = PR_TRUE; + _HashEnumerateArgs thunk; + thunk.fn = aEnumFunc; + thunk.arg = aClosure; + PL_DHashTableEnumerate(&mHashtable, hashEnumerate, &thunk); + mEnumerating = wasEnumerating; +} + +PR_STATIC_CALLBACK(PLDHashOperator) +hashEnumerateRemove(PLDHashTable*, PLDHashEntryHdr* hdr, PRUint32 i, void *arg) +{ + HTEntry* entry = NS_STATIC_CAST(HTEntry*, hdr); + _HashEnumerateArgs* thunk = (_HashEnumerateArgs*)arg; + if (thunk) { + return thunk->fn(entry->key, entry->value, thunk->arg) + ? PL_DHASH_REMOVE + : PL_DHASH_STOP; + } + return PL_DHASH_REMOVE; +} + +void nsHashtable::Reset() { + Reset(NULL); +} + +void nsHashtable::Reset(nsHashtableEnumFunc destroyFunc, void* aClosure) +{ + if (!mHashtable.ops) return; + + _HashEnumerateArgs thunk, *thunkp; + if (!destroyFunc) { + thunkp = nsnull; + } else { + thunkp = &thunk; + thunk.fn = destroyFunc; + thunk.arg = aClosure; + } + PL_DHashTableEnumerate(&mHashtable, hashEnumerateRemove, thunkp); +} + +// nsISerializable helpers + +nsHashtable::nsHashtable(nsIObjectInputStream* aStream, + nsHashtableReadEntryFunc aReadEntryFunc, + nsHashtableFreeEntryFunc aFreeEntryFunc, + nsresult *aRetVal) + : mLock(nsnull), + mEnumerating(PR_FALSE) +{ + MOZ_COUNT_CTOR(nsHashtable); + + PRBool threadSafe; + nsresult rv = aStream->ReadBoolean(&threadSafe); + if (NS_SUCCEEDED(rv)) { + if (threadSafe) { + mLock = PR_NewLock(); + if (!mLock) + rv = NS_ERROR_OUT_OF_MEMORY; + } + + if (NS_SUCCEEDED(rv)) { + PRUint32 count; + rv = aStream->Read32(&count); + + if (NS_SUCCEEDED(rv)) { + PRBool status = + PL_DHashTableInit(&mHashtable, &hashtableOps, + nsnull, sizeof(HTEntry), count); + if (!status) { + mHashtable.ops = nsnull; + rv = NS_ERROR_OUT_OF_MEMORY; + } else { + for (PRUint32 i = 0; i < count; i++) { + nsHashKey* key; + void *data; + + rv = aReadEntryFunc(aStream, &key, &data); + if (NS_SUCCEEDED(rv)) { + if (!Put(key, data)) { + rv = NS_ERROR_OUT_OF_MEMORY; + aFreeEntryFunc(aStream, key, data); + } else { + // XXXbe must we clone key? can't we hand off + aFreeEntryFunc(aStream, key, nsnull); + } + if (NS_FAILED(rv)) + break; + } + } + } + } + } + } + *aRetVal = rv; +} + +struct WriteEntryArgs { + nsIObjectOutputStream* mStream; + nsHashtableWriteDataFunc mWriteDataFunc; + nsresult mRetVal; +}; + +PR_STATIC_CALLBACK(PRBool) +WriteEntry(nsHashKey *aKey, void *aData, void* aClosure) +{ + WriteEntryArgs* args = (WriteEntryArgs*) aClosure; + nsIObjectOutputStream* stream = args->mStream; + + nsresult rv = aKey->Write(stream); + if (NS_SUCCEEDED(rv)) + rv = args->mWriteDataFunc(stream, aData); + + args->mRetVal = rv; + return PR_TRUE; +} + +nsresult +nsHashtable::Write(nsIObjectOutputStream* aStream, + nsHashtableWriteDataFunc aWriteDataFunc) const +{ + if (!mHashtable.ops) + return NS_ERROR_OUT_OF_MEMORY; + PRBool threadSafe = (mLock != nsnull); + nsresult rv = aStream->WriteBoolean(threadSafe); + if (NS_FAILED(rv)) return rv; + + // Write the entry count first, so we know how many key/value pairs to read. + PRUint32 count = mHashtable.entryCount; + rv = aStream->Write32(count); + if (NS_FAILED(rv)) return rv; + + // Write all key/value pairs in the table. + WriteEntryArgs args = {aStream, aWriteDataFunc}; + NS_CONST_CAST(nsHashtable*, this)->Enumerate(WriteEntry, (void*) &args); + return args.mRetVal; +} + +//////////////////////////////////////////////////////////////////////////////// + +nsISupportsKey::nsISupportsKey(nsIObjectInputStream* aStream, nsresult *aResult) + : mKey(nsnull) +{ + PRBool nonnull; + nsresult rv = aStream->ReadBoolean(&nonnull); + if (NS_SUCCEEDED(rv) && nonnull) + rv = aStream->ReadObject(PR_TRUE, &mKey); + *aResult = rv; +} + +nsresult +nsISupportsKey::Write(nsIObjectOutputStream* aStream) const +{ + PRBool nonnull = (mKey != nsnull); + nsresult rv = aStream->WriteBoolean(nonnull); + if (NS_SUCCEEDED(rv) && nonnull) + rv = aStream->WriteObject(mKey, PR_TRUE); + return rv; +} + +nsIDKey::nsIDKey(nsIObjectInputStream* aStream, nsresult *aResult) +{ + *aResult = aStream->ReadID(&mID); +} + +nsresult nsIDKey::Write(nsIObjectOutputStream* aStream) const +{ + return aStream->WriteID(mID); +} + +//////////////////////////////////////////////////////////////////////////////// + +// Copy Constructor +// We need to free mStr if the object is passed with mOwnership as OWN. As the +// destructor here is freeing mStr in that case, mStr is NOT getting leaked here. + +nsCStringKey::nsCStringKey(const nsCStringKey& aKey) + : mStr(aKey.mStr), mStrLen(aKey.mStrLen), mOwnership(aKey.mOwnership) +{ + if (mOwnership != NEVER_OWN) { + PRUint32 len = mStrLen * sizeof(char); + char* str = NS_REINTERPRET_CAST(char*, nsMemory::Alloc(len + sizeof(char))); + if (!str) { + // Pray we don't dangle! + mOwnership = NEVER_OWN; + } else { + // Use memcpy in case there are embedded NULs. + memcpy(str, mStr, len); + str[mStrLen] = '\0'; + mStr = str; + mOwnership = OWN; + } + } +#ifdef DEBUG + mKeyType = CStringKey; +#endif + MOZ_COUNT_CTOR(nsCStringKey); +} + +nsCStringKey::nsCStringKey(const nsAFlatCString& str) + : mStr(NS_CONST_CAST(char*, str.get())), + mStrLen(str.Length()), + mOwnership(OWN_CLONE) +{ + NS_ASSERTION(mStr, "null string key"); +#ifdef DEBUG + mKeyType = CStringKey; +#endif + MOZ_COUNT_CTOR(nsCStringKey); +} + +nsCStringKey::nsCStringKey(const nsACString& str) + : mStr(ToNewCString(str)), + mStrLen(str.Length()), + mOwnership(OWN) +{ + NS_ASSERTION(mStr, "null string key"); +#ifdef DEBUG + mKeyType = CStringKey; +#endif + MOZ_COUNT_CTOR(nsCStringKey); +} + +nsCStringKey::nsCStringKey(const char* str, PRInt32 strLen, Ownership own) + : mStr((char*)str), mStrLen(strLen), mOwnership(own) +{ + NS_ASSERTION(mStr, "null string key"); + if (mStrLen == PRUint32(-1)) + mStrLen = strlen(str); +#ifdef DEBUG + mKeyType = CStringKey; +#endif + MOZ_COUNT_CTOR(nsCStringKey); +} + +nsCStringKey::~nsCStringKey(void) +{ + if (mOwnership == OWN) + nsMemory::Free(mStr); + MOZ_COUNT_DTOR(nsCStringKey); +} + +PRUint32 +nsCStringKey::HashCode(void) const +{ + return nsCRT::HashCode(mStr, (PRUint32*)&mStrLen); +} + +PRBool +nsCStringKey::Equals(const nsHashKey* aKey) const +{ + NS_ASSERTION(aKey->GetKeyType() == CStringKey, "mismatched key types"); + nsCStringKey* other = (nsCStringKey*)aKey; + NS_ASSERTION(mStrLen != PRUint32(-1), "never called HashCode"); + NS_ASSERTION(other->mStrLen != PRUint32(-1), "never called HashCode"); + if (mStrLen != other->mStrLen) + return PR_FALSE; + return memcmp(mStr, other->mStr, mStrLen * sizeof(char)) == 0; +} + +nsHashKey* +nsCStringKey::Clone() const +{ + if (mOwnership == NEVER_OWN) + return new nsCStringKey(mStr, mStrLen, NEVER_OWN); + + // Since this might hold binary data OR a string, we ensure that the + // clone string is zero terminated, but don't assume that the source + // string was so terminated. + + PRUint32 len = mStrLen * sizeof(char); + char* str = (char*)nsMemory::Alloc(len + sizeof(char)); + if (str == NULL) + return NULL; + memcpy(str, mStr, len); + str[len] = 0; + return new nsCStringKey(str, mStrLen, OWN); +} + +nsCStringKey::nsCStringKey(nsIObjectInputStream* aStream, nsresult *aResult) + : mStr(nsnull), mStrLen(0), mOwnership(OWN) +{ + nsCAutoString str; + nsresult rv = aStream->ReadCString(str); + mStr = ToNewCString(str); + if (NS_SUCCEEDED(rv)) + mStrLen = str.Length(); + *aResult = rv; + MOZ_COUNT_CTOR(nsCStringKey); +} + +nsresult +nsCStringKey::Write(nsIObjectOutputStream* aStream) const +{ + return aStream->WriteStringZ(mStr); +} + +//////////////////////////////////////////////////////////////////////////////// + +// Copy Constructor +// We need to free mStr if the object is passed with mOwnership as OWN. As the +// destructor here is freeing mStr in that case, mStr is NOT getting leaked here. + +nsStringKey::nsStringKey(const nsStringKey& aKey) + : mStr(aKey.mStr), mStrLen(aKey.mStrLen), mOwnership(aKey.mOwnership) +{ + if (mOwnership != NEVER_OWN) { + PRUint32 len = mStrLen * sizeof(PRUnichar); + PRUnichar* str = NS_REINTERPRET_CAST(PRUnichar*, nsMemory::Alloc(len + sizeof(PRUnichar))); + if (!str) { + // Pray we don't dangle! + mOwnership = NEVER_OWN; + } else { + // Use memcpy in case there are embedded NULs. + memcpy(str, mStr, len); + str[mStrLen] = 0; + mStr = str; + mOwnership = OWN; + } + } +#ifdef DEBUG + mKeyType = StringKey; +#endif + MOZ_COUNT_CTOR(nsStringKey); +} + +nsStringKey::nsStringKey(const nsAFlatString& str) + : mStr(NS_CONST_CAST(PRUnichar*, str.get())), + mStrLen(str.Length()), + mOwnership(OWN_CLONE) +{ + NS_ASSERTION(mStr, "null string key"); +#ifdef DEBUG + mKeyType = StringKey; +#endif + MOZ_COUNT_CTOR(nsStringKey); +} + +nsStringKey::nsStringKey(const nsAString& str) + : mStr(ToNewUnicode(str)), + mStrLen(str.Length()), + mOwnership(OWN) +{ + NS_ASSERTION(mStr, "null string key"); +#ifdef DEBUG + mKeyType = StringKey; +#endif + MOZ_COUNT_CTOR(nsStringKey); +} + +nsStringKey::nsStringKey(const PRUnichar* str, PRInt32 strLen, Ownership own) + : mStr((PRUnichar*)str), mStrLen(strLen), mOwnership(own) +{ + NS_ASSERTION(mStr, "null string key"); + if (mStrLen == PRUint32(-1)) + mStrLen = nsCRT::strlen(str); +#ifdef DEBUG + mKeyType = StringKey; +#endif + MOZ_COUNT_CTOR(nsStringKey); +} + +nsStringKey::~nsStringKey(void) +{ + if (mOwnership == OWN) + nsMemory::Free(mStr); + MOZ_COUNT_DTOR(nsStringKey); +} + +PRUint32 +nsStringKey::HashCode(void) const +{ + return nsCRT::HashCode(mStr, (PRUint32*)&mStrLen); +} + +PRBool +nsStringKey::Equals(const nsHashKey* aKey) const +{ + NS_ASSERTION(aKey->GetKeyType() == StringKey, "mismatched key types"); + nsStringKey* other = (nsStringKey*)aKey; + NS_ASSERTION(mStrLen != PRUint32(-1), "never called HashCode"); + NS_ASSERTION(other->mStrLen != PRUint32(-1), "never called HashCode"); + if (mStrLen != other->mStrLen) + return PR_FALSE; + return memcmp(mStr, other->mStr, mStrLen * sizeof(PRUnichar)) == 0; +} + +nsHashKey* +nsStringKey::Clone() const +{ + if (mOwnership == NEVER_OWN) + return new nsStringKey(mStr, mStrLen, NEVER_OWN); + + PRUint32 len = (mStrLen+1) * sizeof(PRUnichar); + PRUnichar* str = (PRUnichar*)nsMemory::Alloc(len); + if (str == NULL) + return NULL; + memcpy(str, mStr, len); + return new nsStringKey(str, mStrLen, OWN); +} + +nsStringKey::nsStringKey(nsIObjectInputStream* aStream, nsresult *aResult) + : mStr(nsnull), mStrLen(0), mOwnership(OWN) +{ + nsAutoString str; + nsresult rv = aStream->ReadString(str); + mStr = ToNewUnicode(str); + if (NS_SUCCEEDED(rv)) + mStrLen = str.Length(); + *aResult = rv; + MOZ_COUNT_CTOR(nsStringKey); +} + +nsresult +nsStringKey::Write(nsIObjectOutputStream* aStream) const +{ + return aStream->WriteWStringZ(mStr); +} + +//////////////////////////////////////////////////////////////////////////////// +// nsObjectHashtable: an nsHashtable where the elements are C++ objects to be +// deleted + +nsObjectHashtable::nsObjectHashtable(nsHashtableCloneElementFunc cloneElementFun, + void* cloneElementClosure, + nsHashtableEnumFunc destroyElementFun, + void* destroyElementClosure, + PRUint32 aSize, PRBool threadSafe) + : nsHashtable(aSize, threadSafe), + mCloneElementFun(cloneElementFun), + mCloneElementClosure(cloneElementClosure), + mDestroyElementFun(destroyElementFun), + mDestroyElementClosure(destroyElementClosure) +{ +} + +nsObjectHashtable::~nsObjectHashtable() +{ + Reset(); +} + + +PLDHashOperator PR_CALLBACK +nsObjectHashtable::CopyElement(PLDHashTable* table, + PLDHashEntryHdr* hdr, + PRUint32 i, void *arg) +{ + nsObjectHashtable *newHashtable = (nsObjectHashtable *)arg; + HTEntry *entry = NS_STATIC_CAST(HTEntry*, hdr); + + void* newElement = + newHashtable->mCloneElementFun(entry->key, entry->value, + newHashtable->mCloneElementClosure); + if (newElement == nsnull) + return PL_DHASH_STOP; + newHashtable->Put(entry->key, newElement); + return PL_DHASH_NEXT; +} + +nsHashtable* +nsObjectHashtable::Clone() +{ + if (!mHashtable.ops) return nsnull; + + PRBool threadSafe = PR_FALSE; + if (mLock) + threadSafe = PR_TRUE; + nsObjectHashtable* newHashTable = + new nsObjectHashtable(mCloneElementFun, mCloneElementClosure, + mDestroyElementFun, mDestroyElementClosure, + mHashtable.entryCount, threadSafe); + + PL_DHashTableEnumerate(&mHashtable, CopyElement, newHashTable); + return newHashTable; +} + +void +nsObjectHashtable::Reset() +{ + nsHashtable::Reset(mDestroyElementFun, mDestroyElementClosure); +} + +PRBool +nsObjectHashtable::RemoveAndDelete(nsHashKey *aKey) +{ + void *value = Remove(aKey); + if (value && mDestroyElementFun) + return (*mDestroyElementFun)(aKey, value, mDestroyElementClosure); + return PR_FALSE; +} + +//////////////////////////////////////////////////////////////////////////////// +// nsSupportsHashtable: an nsHashtable where the elements are nsISupports* + +PRBool PR_CALLBACK +nsSupportsHashtable::ReleaseElement(nsHashKey *aKey, void *aData, void* aClosure) +{ + nsISupports* element = NS_STATIC_CAST(nsISupports*, aData); + NS_IF_RELEASE(element); + return PR_TRUE; +} + +nsSupportsHashtable::~nsSupportsHashtable() +{ + Enumerate(ReleaseElement, nsnull); +} + +// Return true if we overwrote something + +PRBool +nsSupportsHashtable::Put(nsHashKey *aKey, nsISupports* aData, nsISupports **value) +{ + NS_IF_ADDREF(aData); + void *prev = nsHashtable::Put(aKey, aData); + nsISupports *old = NS_REINTERPRET_CAST(nsISupports *, prev); + if (value) // pass own the ownership to the caller + *value = old; + else // the caller doesn't care, we do + NS_IF_RELEASE(old); + return prev != nsnull; +} + +nsISupports * +nsSupportsHashtable::Get(nsHashKey *aKey) +{ + void* data = nsHashtable::Get(aKey); + if (!data) + return nsnull; + nsISupports* element = NS_REINTERPRET_CAST(nsISupports*, data); + NS_IF_ADDREF(element); + return element; +} + +// Return true if we found something (useful for checks) + +PRBool +nsSupportsHashtable::Remove(nsHashKey *aKey, nsISupports **value) +{ + void* data = nsHashtable::Remove(aKey); + nsISupports* element = NS_STATIC_CAST(nsISupports*, data); + if (value) // caller wants it + *value = element; + else // caller doesn't care, we do + NS_IF_RELEASE(element); + return data != nsnull; +} + +PLDHashOperator PR_CALLBACK +nsSupportsHashtable::EnumerateCopy(PLDHashTable*, + PLDHashEntryHdr* hdr, + PRUint32 i, void *arg) +{ + nsHashtable *newHashtable = (nsHashtable *)arg; + HTEntry* entry = NS_STATIC_CAST(HTEntry*, hdr); + + nsISupports* element = NS_STATIC_CAST(nsISupports*, entry->value); + NS_IF_ADDREF(element); + newHashtable->Put(entry->key, entry->value); + return PL_DHASH_NEXT; +} + +nsHashtable* +nsSupportsHashtable::Clone() +{ + if (!mHashtable.ops) return nsnull; + + PRBool threadSafe = (mLock != nsnull); + nsSupportsHashtable* newHashTable = + new nsSupportsHashtable(mHashtable.entryCount, threadSafe); + + PL_DHashTableEnumerate(&mHashtable, EnumerateCopy, newHashTable); + return newHashTable; +} + +void +nsSupportsHashtable::Reset() +{ + Enumerate(ReleaseElement, nsnull); + nsHashtable::Reset(); +} + +//////////////////////////////////////////////////////////////////////////////// + diff --git a/src/libs/xpcom18a4/xpcom/ds/nsHashtable.h b/src/libs/xpcom18a4/xpcom/ds/nsHashtable.h new file mode 100644 index 00000000..21ce9028 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsHashtable.h @@ -0,0 +1,454 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** + * This Original Code has been modified by IBM Corporation. + * Modifications made by IBM described herein are + * Copyright (c) International Business Machines + * Corporation, 2000 + * + * Modifications to Mozilla code or documentation + * identified per MPL Section 3.3 + * + * Date Modified by Description of modification + * 04/20/2000 IBM Corp. Added PR_CALLBACK for Optlink use in OS2 + */ + +/** + * nsHashtable is OBSOLETE. Use nsTHashtable or a derivative instead. + */ + +#ifndef nsHashtable_h__ +#define nsHashtable_h__ + +#include "pldhash.h" +#include "prlock.h" +#include "nscore.h" +#include "nsString.h" +#include "nsISupportsBase.h" +#include "nsTraceRefcnt.h" + +class nsIObjectInputStream; +class nsIObjectOutputStream; + +class nsHashtable; +class nsStringKey; + +class NS_COM nsHashKey { + protected: + nsHashKey(void) { +#ifdef DEBUG + mKeyType = UnknownKey; +#endif + MOZ_COUNT_CTOR(nsHashKey); + } + + + public: + // Virtual destructor because all hash keys are |delete|d via a + // nsHashKey pointer. + + virtual ~nsHashKey(void); + virtual PRUint32 HashCode(void) const = 0; + virtual PRBool Equals(const nsHashKey *aKey) const = 0; + virtual nsHashKey *Clone() const = 0; + virtual nsresult Write(nsIObjectOutputStream* aStream) const; + +#ifdef DEBUG + public: + // used for verification that we're casting to the correct key type + enum nsHashKeyType { + UnknownKey, + SupportsKey, + PRUint32Key, + VoidKey, + IDKey, + CStringKey, + StringKey + }; + nsHashKeyType GetKeyType() const { return mKeyType; } + protected: + nsHashKeyType mKeyType; +#endif +}; + +// Enumerator and Read/Write callback functions. + +// Return values for nsHashtableEnumFunc +enum { + kHashEnumerateStop = PR_FALSE, + kHashEnumerateNext = PR_TRUE, + kHashEnumerateRemove = 2 +}; + +typedef PRIntn +(*PR_CALLBACK nsHashtableEnumFunc)(nsHashKey *aKey, void *aData, void* aClosure); + +typedef nsresult +(*PR_CALLBACK nsHashtableReadEntryFunc)(nsIObjectInputStream *aStream, + nsHashKey **aKey, + void **aData); + +// NB: may be called with null aKey or aData, to free just one of the two. +typedef void +(*PR_CALLBACK nsHashtableFreeEntryFunc)(nsIObjectInputStream *aStream, + nsHashKey *aKey, + void *aData); + +typedef nsresult +(*PR_CALLBACK nsHashtableWriteDataFunc)(nsIObjectOutputStream *aStream, + void *aData); + +class NS_COM nsHashtable { + protected: + // members + PRLock* mLock; + PLDHashTable mHashtable; + PRBool mEnumerating; + + public: + nsHashtable(PRUint32 aSize = 16, PRBool threadSafe = PR_FALSE); + virtual ~nsHashtable(); + + PRInt32 Count(void) { return mHashtable.entryCount; } + PRBool Exists(nsHashKey *aKey); + void *Put(nsHashKey *aKey, void *aData); + void *Get(nsHashKey *aKey); + void *Remove(nsHashKey *aKey); + nsHashtable *Clone(); + void Enumerate(nsHashtableEnumFunc aEnumFunc, void* aClosure = NULL); + void Reset(); + void Reset(nsHashtableEnumFunc destroyFunc, void* aClosure = NULL); + + nsHashtable(nsIObjectInputStream* aStream, + nsHashtableReadEntryFunc aReadEntryFunc, + nsHashtableFreeEntryFunc aFreeEntryFunc, + nsresult *aRetVal); + nsresult Write(nsIObjectOutputStream* aStream, + nsHashtableWriteDataFunc aWriteDataFunc) const; +}; + +//////////////////////////////////////////////////////////////////////////////// +// nsObjectHashtable: an nsHashtable where the elements are C++ objects to be +// deleted + +typedef void* (*PR_CALLBACK nsHashtableCloneElementFunc)(nsHashKey *aKey, void *aData, void* aClosure); + +class NS_COM nsObjectHashtable : public nsHashtable { + public: + nsObjectHashtable(nsHashtableCloneElementFunc cloneElementFun, + void* cloneElementClosure, + nsHashtableEnumFunc destroyElementFun, + void* destroyElementClosure, + PRUint32 aSize = 16, PRBool threadSafe = PR_FALSE); + ~nsObjectHashtable(); + + nsHashtable *Clone(); + void Reset(); + PRBool RemoveAndDelete(nsHashKey *aKey); + + protected: + static PLDHashOperator PR_CALLBACK CopyElement(PLDHashTable* table, + PLDHashEntryHdr* hdr, + PRUint32 i, void *arg); + + nsHashtableCloneElementFunc mCloneElementFun; + void* mCloneElementClosure; + nsHashtableEnumFunc mDestroyElementFun; + void* mDestroyElementClosure; +}; + +//////////////////////////////////////////////////////////////////////////////// +// nsSupportsHashtable: an nsHashtable where the elements are nsISupports* + +class nsISupports; + +class NS_COM nsSupportsHashtable + : private nsHashtable +{ + public: + typedef PRBool (* PR_CALLBACK EnumFunc) (nsHashKey *aKey, void *aData, void* aClosure); + + nsSupportsHashtable(PRUint32 aSize = 16, PRBool threadSafe = PR_FALSE) + : nsHashtable(aSize, threadSafe) {} + ~nsSupportsHashtable(); + + PRInt32 Count(void) { + return nsHashtable::Count(); + } + PRBool Exists(nsHashKey *aKey) { + return nsHashtable::Exists (aKey); + } + PRBool Put(nsHashKey *aKey, + nsISupports *aData, + nsISupports **value = nsnull); + nsISupports* Get(nsHashKey *aKey); + PRBool Remove(nsHashKey *aKey, nsISupports **value = nsnull); + nsHashtable *Clone(); + void Enumerate(EnumFunc aEnumFunc, void* aClosure = NULL) { + nsHashtable::Enumerate(aEnumFunc, aClosure); + } + void Reset(); + + private: + static PRBool PR_CALLBACK ReleaseElement(nsHashKey *, void *, void *); + static PLDHashOperator PR_CALLBACK EnumerateCopy(PLDHashTable*, + PLDHashEntryHdr* hdr, + PRUint32 i, void *arg); +}; + +//////////////////////////////////////////////////////////////////////////////// +// nsISupportsKey: Where keys are nsISupports objects that get refcounted. + +#include "nsISupports.h" + +class NS_COM nsISupportsKey : public nsHashKey { + protected: + nsISupports* mKey; + + public: + nsISupportsKey(const nsISupportsKey& aKey) : mKey(aKey.mKey) { +#ifdef DEBUG + mKeyType = SupportsKey; +#endif + NS_IF_ADDREF(mKey); + } + + nsISupportsKey(nsISupports* key) { +#ifdef DEBUG + mKeyType = SupportsKey; +#endif + mKey = key; + NS_IF_ADDREF(mKey); + } + + ~nsISupportsKey(void) { + NS_IF_RELEASE(mKey); + } + + PRUint32 HashCode(void) const { + return NS_PTR_TO_INT32(mKey); + } + + PRBool Equals(const nsHashKey *aKey) const { + NS_ASSERTION(aKey->GetKeyType() == SupportsKey, "mismatched key types"); + return (mKey == ((nsISupportsKey *) aKey)->mKey); + } + + nsHashKey *Clone() const { + return new nsISupportsKey(mKey); + } + + nsISupportsKey(nsIObjectInputStream* aStream, nsresult *aResult); + nsresult Write(nsIObjectOutputStream* aStream) const; +}; + + +class nsPRUint32Key : public nsHashKey { +protected: + PRUint32 mKey; +public: + nsPRUint32Key(PRUint32 key) { +#ifdef DEBUG + mKeyType = PRUint32Key; +#endif + mKey = key; + } + + PRUint32 HashCode(void) const { + return mKey; + } + + PRBool Equals(const nsHashKey *aKey) const { + return mKey == ((const nsPRUint32Key *) aKey)->mKey; + } + nsHashKey *Clone() const { + return new nsPRUint32Key(mKey); + } + PRUint32 GetValue() { return mKey; } +}; + +//////////////////////////////////////////////////////////////////////////////// +// nsVoidKey: Where keys are void* objects that don't get refcounted. + +class nsVoidKey : public nsHashKey { + protected: + void* mKey; + + public: + nsVoidKey(const nsVoidKey& aKey) : mKey(aKey.mKey) { +#ifdef DEBUG + mKeyType = aKey.mKeyType; +#endif + } + + nsVoidKey(void* key) { +#ifdef DEBUG + mKeyType = VoidKey; +#endif + mKey = key; + } + + PRUint32 HashCode(void) const { + return NS_PTR_TO_INT32(mKey); + } + + PRBool Equals(const nsHashKey *aKey) const { + NS_ASSERTION(aKey->GetKeyType() == VoidKey, "mismatched key types"); + return (mKey == ((const nsVoidKey *) aKey)->mKey); + } + + nsHashKey *Clone() const { + return new nsVoidKey(mKey); + } + + void* GetValue() { return mKey; } +}; + +//////////////////////////////////////////////////////////////////////////////// +// nsIDKey: Where keys are nsIDs (e.g. nsIID, nsCID). + +#include "nsID.h" + +class NS_COM nsIDKey : public nsHashKey { + protected: + nsID mID; + + public: + nsIDKey(const nsIDKey& aKey) : mID(aKey.mID) { +#ifdef DEBUG + mKeyType = IDKey; +#endif + } + + nsIDKey(const nsID &aID) { +#ifdef DEBUG + mKeyType = IDKey; +#endif + mID = aID; + } + + PRUint32 HashCode(void) const { + return mID.m0; + } + + PRBool Equals(const nsHashKey *aKey) const { + NS_ASSERTION(aKey->GetKeyType() == IDKey, "mismatched key types"); + return (mID.Equals(((const nsIDKey *) aKey)->mID)); + } + + nsHashKey *Clone() const { + return new nsIDKey(mID); + } + + nsIDKey(nsIObjectInputStream* aStream, nsresult *aResult); + nsresult Write(nsIObjectOutputStream* aStream) const; +}; + +//////////////////////////////////////////////////////////////////////////////// + +#include "nsString.h" + +// for null-terminated c-strings +class NS_COM nsCStringKey : public nsHashKey { + public: + + // NB: when serializing, NEVER_OWN keys are deserialized as OWN. + enum Ownership { + NEVER_OWN, // very long lived, even clones don't need to copy it. + OWN_CLONE, // as long lived as this key. But clones make a copy. + OWN // to be free'd in key dtor. Clones make their own copy. + }; + + nsCStringKey(const nsCStringKey& aStrKey); + nsCStringKey(const char* str, PRInt32 strLen = -1, Ownership own = OWN_CLONE); + nsCStringKey(const nsAFlatCString& str); + nsCStringKey(const nsACString& str); + ~nsCStringKey(void); + + PRUint32 HashCode(void) const; + PRBool Equals(const nsHashKey* aKey) const; + nsHashKey* Clone() const; + nsCStringKey(nsIObjectInputStream* aStream, nsresult *aResult); + nsresult Write(nsIObjectOutputStream* aStream) const; + + // For when the owner of the hashtable wants to peek at the actual + // string in the key. No copy is made, so be careful. + const char* GetString() const { return mStr; } + PRUint32 GetStringLength() const { return mStrLen; } + + protected: + char* mStr; + PRUint32 mStrLen; + Ownership mOwnership; +}; + +// for null-terminated unicode strings +class NS_COM nsStringKey : public nsHashKey { + public: + + // NB: when serializing, NEVER_OWN keys are deserialized as OWN. + enum Ownership { + NEVER_OWN, // very long lived, even clones don't need to copy it. + OWN_CLONE, // as long lived as this key. But clones make a copy. + OWN // to be free'd in key dtor. Clones make their own copy. + }; + + nsStringKey(const nsStringKey& aKey); + nsStringKey(const PRUnichar* str, PRInt32 strLen = -1, Ownership own = OWN_CLONE); + nsStringKey(const nsAFlatString& str); + nsStringKey(const nsAString& str); + ~nsStringKey(void); + + PRUint32 HashCode(void) const; + PRBool Equals(const nsHashKey* aKey) const; + nsHashKey* Clone() const; + nsStringKey(nsIObjectInputStream* aStream, nsresult *aResult); + nsresult Write(nsIObjectOutputStream* aStream) const; + + // For when the owner of the hashtable wants to peek at the actual + // string in the key. No copy is made, so be careful. + const PRUnichar* GetString() const { return mStr; } + PRUint32 GetStringLength() const { return mStrLen; } + + protected: + PRUnichar* mStr; + PRUint32 mStrLen; + Ownership mOwnership; +}; + +//////////////////////////////////////////////////////////////////////////////// + +#endif // nsHashtable_h__ diff --git a/src/libs/xpcom18a4/xpcom/ds/nsIArray.idl b/src/libs/xpcom18a4/xpcom/ds/nsIArray.idl new file mode 100644 index 00000000..c937ec4b --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsIArray.idl @@ -0,0 +1,202 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 XPCOM Array interface. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corp. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Alec Flett + * + * 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 "nsISupports.idl" + +interface nsISimpleEnumerator; + +/** + * nsIArray + * + * An indexed collection of elements. Provides basic functionality for + * retrieving elements at a specific position, searching for + * elements. Indexes are zero-based, such that the last element in the + * array is stored at the index length-1. + * + * For an array which can be modified, see nsIMutableArray below. + * + * Neither interface makes any attempt to protect the individual + * elements from modification. The convention is that the elements of + * the array should not be modified. Documentation within a specific + * interface should describe variations from this convention. + * + * It is also convention that if an interface provides access to an + * nsIArray, that the array should not be QueryInterfaced to an + * nsIMutableArray for modification. If the interface in question had + * intended the array to be modified, it would have returned an + * nsIMutableArray! + * + * null is a valid entry in the array, and as such any nsISupports + * parameters may be null, except where noted. + * + * @status UNDER_REVIEW + */ +[scriptable, uuid(114744d9-c369-456e-b55a-52fe52880d2d)] +interface nsIArray : nsISupports +{ + /** + * length + * + * number of elements in the array. + */ + readonly attribute unsigned long length; + + /** + * queryElementAt() + * + * Retrieve a specific element of the array, and QueryInterface it + * to the specified interface. null is a valid result for + * this method, but exceptions are thrown in other circumstances + * + * @param index position of element + * @param uuid the IID of the requested interface + * @param result the object, QI'd to the requested interface + * + * @throws NS_ERROR_NO_INTERFACE when an entry exists at the + * specified index, but the requested interface is not + * available. + * @throws NS_ERROR_ILLEGAL_VALUE when index > length-1 + * + */ + void queryElementAt(in unsigned long index, + in nsIIDRef uuid, + [iid_is(uuid), retval] out nsQIResult result); + + /** + * indexOf() + * + * Get the position of a specific element. Note that since null is + * a valid input, exceptions are used to indicate that an element + * is not found. + * + * @param startIndex The initial element to search in the array + * To start at the beginning, use 0 as the + * startIndex + * @param element The element you are looking for + * @returns a number >= startIndex which is the position of the + * element in the array. + * @throws NS_ERROR_NOT_FOUND if the element was not in the array. + */ + unsigned long indexOf(in unsigned long startIndex, + in nsISupports element); + + /** + * enumerate the array + * + * @returns a new enumerator positioned at the start of the array + * @throws NS_ERROR_FAILURE if the array is empty (to make it easy + * to detect errors) + */ + nsISimpleEnumerator enumerate(); + +}; + +/** + * nsIMutableArray + * A separate set of methods that will act on the array. Consumers of + * nsIArray should not QueryInterface to nsIMutableArray unless they + * own the array. + * + * As above, it is legal to add null elements to the array. Note also + * that null elements can be created as a side effect of + * insertElementAt(). Conversely, if insertElementAt() is never used, + * and null elements are never explicitly added to the array, then it + * is guaranteed that queryElementAt() will never return a null value. + * + * Any of these methods may throw NS_ERROR_OUT_OF_MEMORY when the + * array must grow to complete the call, but the allocation fails. + * + * @status UNDER_REVIEW + */ + +[scriptable, uuid(2cd0b2f8-d4dd-48b8-87ba-b0200501f079)] +interface nsIMutableArray : nsIArray +{ + /** + * appendElement() + * + * Append an element at the end of the array. + * + * @param element The element to append. + * @param element Whether or not to store the element using a weak + * reference. + * @throws NS_ERROR_UNEXPECTED when a weak reference is requested, + * but the element does not support + * nsIWeakReference. + */ + void appendElement(in nsISupports element, in boolean weak); + + /** + * removeElementAt() + * + * Remove an element at a specific position. + * To remove a specific element, use indexOf() to find the index + * first, then call removeElementAt(). + * + * @param index the position of the item + * + */ + void removeElementAt(in unsigned long index); + + /** + * insertElementAt() + * + * Insert an element at the given position, and move all elements + * stored at a higher position up one. + * + * @param element The element to insert + * @param index The position in the array. If the position is + * greater than or equal to the length of the array + * (@see nsIArray) then the array will grow to + * exactly accomadate the index, and the new length + * will be index+1. The newly created entries will + * be null. + * + * @throws NS_ERROR_FAILURE when a weak reference is requested, + * but the element does not support + * nsIWeakReference. + */ + void insertElementAt(in nsISupports element, in unsigned long index, in boolean weak); + + /** + * clear() + * + * clear the entire array, releasing all stored objects + */ + void clear(); +}; diff --git a/src/libs/xpcom18a4/xpcom/ds/nsIAtom.idl b/src/libs/xpcom18a4/xpcom/ds/nsIAtom.idl new file mode 100644 index 00000000..45eecb4d --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsIAtom.idl @@ -0,0 +1,161 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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 Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsISupports.idl" + +%{C++ +#include "nsAString.h" +#include "nsCOMPtr.h" +%} + +/* + * Should this really be scriptable? Using atoms from script or proxies + * could be dangerous since double-wrapping could lead to loss of + * pointer identity. + */ + +[scriptable, uuid(3d1b15b0-93b4-11d1-895b-006008911b81)] +interface nsIAtom : nsISupports +{ + /** + * Get the Unicode or UTF8 value for the string + */ + AString toString(); + AUTF8String toUTF8String(); + + /** + * Return a pointer to a zero terminated UTF8 string. + */ + [noscript] void getUTF8String([shared, retval] out string aResult); + + /** + * Compare the atom to a specific string value + * Note that this will NEVER return/throw an error condition. + */ + boolean equals(in AString aString); + + boolean equalsUTF8(in AUTF8String aString); + +%{C++ + // note this is NOT virtual so this won't muck with the vtable! + inline PRBool Equals(const nsAString& s) { + PRBool result; + Equals(s, &result); + return result; + } + + inline PRBool EqualsUTF8(const nsACString& s) { + PRBool result; + EqualsUTF8(s, &result); + return result; + } +%} + +}; + + +%{C++ +/* + * The three forms of NS_NewAtom and do_GetAtom (for use with + * |nsCOMPtr|) return the atom for the string given. At any + * given time there will always be one atom representing a given string. + * Atoms are intended to make string comparison cheaper by simplifying + * it to pointer equality. A pointer to the atom that does not own a + * reference is not guaranteed to be valid. + * + * The three forms of NS_NewPermanentAtom and do_GetPermanentAtom return + * the atom for the given string and ensure that the atom is permanent. + * An atom that is permanent will exist (occupy space at a specific + * location in memory) until XPCOM is shut down. The advantage of + * permanent atoms is that they do not need to maintain a reference + * count, which requires locking and hurts performance. + */ + + +/** + * Find an atom that matches the given UTF-8 string. + * The string is assumed to be zero terminated. + */ +extern NS_COM nsIAtom* NS_NewAtom(const char* aUTF8String); +extern NS_COM nsIAtom* NS_NewPermanentAtom(const char* aUTF8String); + +inline already_AddRefed do_GetAtom(const char* aUTF8String) + { return NS_NewAtom(aUTF8String); } +inline already_AddRefed do_GetPermanentAtom(const char* aUTF8String) + { return NS_NewPermanentAtom(aUTF8String); } + +/** + * Find an atom that matches the given UTF-8 string. + */ +extern NS_COM nsIAtom* NS_NewAtom(const nsACString& aUTF8String); +extern NS_COM nsIAtom* NS_NewPermanentAtom(const nsACString& aUTF8String); + +inline already_AddRefed do_GetAtom(const nsACString& aUTF8String) + { return NS_NewAtom(aUTF8String); } +inline already_AddRefed do_GetPermanentAtom(const nsACString& aUTF8String) + { return NS_NewPermanentAtom(aUTF8String); } + +/** + * Find an atom that matches the given UTF-16 string. + * The string is assumed to be zero terminated. + */ +extern NS_COM nsIAtom* NS_NewAtom(const PRUnichar* aUTF16String); +extern NS_COM nsIAtom* NS_NewPermanentAtom(const PRUnichar* aUTF16String); + +inline already_AddRefed do_GetAtom(const PRUnichar* aUTF16String) + { return NS_NewAtom(aUTF16String); } +inline already_AddRefed do_GetPermanentAtom(const PRUnichar* aUTF16String) + { return NS_NewPermanentAtom(aUTF16String); } + +/** + * Find an atom that matches the given UTF-16 string. + */ +extern NS_COM nsIAtom* NS_NewAtom(const nsAString& aUTF16String); +extern NS_COM nsIAtom* NS_NewPermanentAtom(const nsAString& aUTF16String); + +inline already_AddRefed do_GetAtom(const nsAString& aUTF16String) + { return NS_NewAtom(aUTF16String); } +inline already_AddRefed do_GetPermanentAtom(const nsAString& aUTF16String) + { return NS_NewPermanentAtom(aUTF16String); } + +/** + * Return a count of the total number of atoms currently + * alive in the system. + */ +extern NS_COM nsrefcnt NS_GetNumberOfAtoms(void); + +%} diff --git a/src/libs/xpcom18a4/xpcom/ds/nsIAtomService.idl b/src/libs/xpcom18a4/xpcom/ds/nsIAtomService.idl new file mode 100644 index 00000000..b3a30358 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsIAtomService.idl @@ -0,0 +1,73 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Alec Flett + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsIAtom.idl" + +%{C++ +#define NS_ATOMSERVICE_CID \ +{ /* ed3db3fc-0168-4cab-8818-98f5475a490c */ \ + 0xed3db3fc, \ + 0x0168, \ + 0x4cab, \ + {0x88, 0x18, 0x98, 0xf5, 0x47, 0x5a, 0x49, 0x0c} } + +#define NS_ATOMSERVICE_CONTRACTID "@mozilla.org/atom-service;1" +#define NS_ATOMSERVICE_CLASSNAME "Atom Service" +%} + +/* + * Should this really be scriptable? Using atoms from script or proxies + * could be dangerous since double-wrapping could lead to loss of + * pointer identity. + */ + +[scriptable, uuid(e5d0d92b-ea45-4622-ab48-302baf2094ee)] +interface nsIAtomService : nsISupports { + + /** + * Version of NS_NewAtom that doesn't require linking against the + * XPCOM library. See nsIAtom.idl. + */ + nsIAtom getAtom(in wstring value); + + /** + * Version of NS_NewPermanentAtom that doesn't require linking against + * the XPCOM library. See nsIAtom.idl. + */ + nsIAtom getPermanentAtom(in wstring value); +}; diff --git a/src/libs/xpcom18a4/xpcom/ds/nsIByteBuffer.h b/src/libs/xpcom18a4/xpcom/ds/nsIByteBuffer.h new file mode 100644 index 00000000..5d02c9cb --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsIByteBuffer.h @@ -0,0 +1,95 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +#ifndef nsIByteBuffer_h___ +#define nsIByteBuffer_h___ + +#include "nscore.h" +#include "nsISupports.h" + +class nsIInputStream; + +#define NS_IBYTE_BUFFER_IID \ +{ 0xe4a6e4b0, 0x93b4, 0x11d1, \ + {0x89, 0x5b, 0x00, 0x60, 0x08, 0x91, 0x1b, 0x81} } +#define NS_IBYTEBUFFER_IID \ +{ 0xe4a6e4b0, 0x93b4, 0x11d1, \ + {0x89, 0x5b, 0x00, 0x60, 0x08, 0x91, 0x1b, 0x81} } +#define NS_BYTEBUFFER_CONTRACTID "@mozilla.org/byte-buffer;1" +#define NS_BYTEBUFFER_CLASSNAME "Byte Buffer" + +/** Interface to a buffer that holds bytes */ +class nsIByteBuffer : public nsISupports { +public: + NS_DEFINE_STATIC_IID_ACCESSOR(NS_IBYTEBUFFER_IID) + + NS_IMETHOD Init(PRUint32 aBufferSize) = 0; + + /** @return length of buffer, i.e. how many bytes are currently in it. */ + NS_IMETHOD_(PRUint32) GetLength(void) const = 0; + + /** @return number of bytes allocated in the buffer */ + NS_IMETHOD_(PRUint32) GetBufferSize(void) const = 0; + + /** @return the buffer */ + NS_IMETHOD_(char*) GetBuffer(void) const = 0; + + /** Grow buffer to aNewSize bytes. */ + NS_IMETHOD_(PRBool) Grow(PRUint32 aNewSize) = 0; + + /** Fill the buffer with data from aStream. Don't grow the buffer, only + * read until length of buffer equals buffer size. */ + NS_IMETHOD_(PRInt32) Fill(nsresult* aErrorCode, nsIInputStream* aStream, + PRUint32 aKeep) = 0; +}; + +#define NS_BYTEBUFFER_CID \ +{ /* a49d5280-0d6b-11d3-9331-00104ba0fd40 */ \ + 0xa49d5280, \ + 0x0d6b, \ + 0x11d3, \ + {0x93, 0x31, 0x00, 0x10, 0x4b, 0xa0, 0xfd, 0x40} \ +} + +/** Create a new byte buffer using the given buffer size. */ +extern NS_COM nsresult +NS_NewByteBuffer(nsIByteBuffer** aInstancePtrResult, + nsISupports* aOuter, + PRUint32 aBufferSize = 0); + +#endif /* nsIByteBuffer_h___ */ + diff --git a/src/libs/xpcom18a4/xpcom/ds/nsICollection.idl b/src/libs/xpcom18a4/xpcom/ds/nsICollection.idl new file mode 100644 index 00000000..f97bf970 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsICollection.idl @@ -0,0 +1,92 @@ +/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Scott Collins : |do_QueryElementAt| + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsISerializable.idl" +#include "nsIEnumerator.idl" + +[scriptable, uuid(83b6019c-cbc4-11d2-8cca-0060b0fc14a3)] +interface nsICollection : nsISerializable +{ + + PRUint32 Count(); + nsISupports GetElementAt(in PRUint32 index); + void QueryElementAt(in PRUint32 index, in nsIIDRef uuid, + [iid_is(uuid),retval] out nsQIResult result); + void SetElementAt(in PRUint32 index, in nsISupports item); + void AppendElement(in nsISupports item); + void RemoveElement(in nsISupports item); + + nsIEnumerator Enumerate(); + + void Clear(); + +}; + +%{C++ + +#ifndef nsCOMPtr_h__ +#include "nsCOMPtr.h" +#endif + +class NS_COM nsQueryElementAt : public nsCOMPtr_helper + { + public: + nsQueryElementAt( nsICollection* aCollection, PRUint32 aIndex, nsresult* aErrorPtr ) + : mCollection(aCollection), + mIndex(aIndex), + mErrorPtr(aErrorPtr) + { + // nothing else to do here + } + + virtual nsresult NS_FASTCALL operator()( const nsIID& aIID, void** ) const; + + private: + nsICollection* mCollection; + PRUint32 mIndex; + nsresult* mErrorPtr; + }; + +inline +const nsQueryElementAt +do_QueryElementAt( nsICollection* aCollection, PRUint32 aIndex, nsresult* aErrorPtr = 0 ) + { + return nsQueryElementAt(aCollection, aIndex, aErrorPtr); + } + +%} diff --git a/src/libs/xpcom18a4/xpcom/ds/nsIEnumerator.idl b/src/libs/xpcom18a4/xpcom/ds/nsIEnumerator.idl new file mode 100644 index 00000000..7f8824b2 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsIEnumerator.idl @@ -0,0 +1,89 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsISimpleEnumerator.idl" + +%{C++ +#define NS_ENUMERATOR_FALSE 1 + +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +#define NS_NewEmptyEnumerator VBoxNsxpNS_NewEmptyEnumerator +#endif /* VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + +extern "C" NS_COM nsresult +NS_NewEmptyEnumerator(nsISimpleEnumerator** aResult); +%} +/* + * DO NOT USE THIS INTERFACE. IT IS HORRIBLY BROKEN, USES NS_COMFALSE + * AND IS BASICALLY IMPOSSIBLE TO USE CORRECTLY THROUGH PROXIES OR + * XPCONNECT. IF YOU SEE NEW USES OF THIS INTERFACE IN CODE YOU ARE + * REVIEWING, YOU SHOULD INSIST ON nsISimpleEnumerator. + * + * DON'T MAKE ME COME OVER THERE. + */ +[scriptable, uuid(ad385286-cbc4-11d2-8cca-0060b0fc14a3)] +interface nsIEnumerator : nsISupports { + /** First will reset the list. will return NS_FAILED if no items + */ + void first(); + + /** Next will advance the list. will return failed if already at end + */ + void next(); + + /** CurrentItem will return the CurrentItem item it will fail if the + * list is empty + */ + nsISupports currentItem(); + + /** return if the collection is at the end. that is the beginning following + * a call to Prev and it is the end of the list following a call to next + */ + void isDone(); +}; + +[uuid(75f158a0-cadd-11d2-8cca-0060b0fc14a3)] +interface nsIBidirectionalEnumerator : nsIEnumerator { + + /** Last will reset the list to the end. will return NS_FAILED if no items + */ + void last(); + + /** Prev will decrement the list. will return failed if already at beginning + */ + void prev(); +}; diff --git a/src/libs/xpcom18a4/xpcom/ds/nsIHashable.idl b/src/libs/xpcom18a4/xpcom/ds/nsIHashable.idl new file mode 100644 index 00000000..ca3c6598 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsIHashable.idl @@ -0,0 +1,58 @@ +/* ***** 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 XPCOM. + * + * The Initial Developer of the Original Code is + * Benjamin Smedberg . + * + * Portions created by the Initial Developer are Copyright (C) 2005 + * the Mozilla Foundation . All Rights Reserved. + * + * Contributor(s): + * + * 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 "nsISupports.idl" + +/** + * Represents an object that can be stored in a hashtable. + */ + +[scriptable, uuid(17e595fa-b57a-4933-bd0f-b1812e8ab188)] +interface nsIHashable : nsISupports +{ + /** + * Is this object the equivalent of the other object? + */ + boolean equals(in nsIHashable aOther); + + /** + * A generated hashcode for this object. Objects that are equivalent + * must have the same hash code. Getting this property should never + * throw an exception! + */ + readonly attribute unsigned long hashCode; +}; diff --git a/src/libs/xpcom18a4/xpcom/ds/nsIObserver.idl b/src/libs/xpcom18a4/xpcom/ds/nsIObserver.idl new file mode 100644 index 00000000..d2240f2e --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsIObserver.idl @@ -0,0 +1,72 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsISupports.idl" + +/** + * This interface is implemented by an object that wants + * to observe an event corresponding to a topic. + * + * @status FROZEN + */ + +[scriptable, uuid(DB242E01-E4D9-11d2-9DDE-000064657374)] +interface nsIObserver : nsISupports { + + /** + * Observe will be called when there is a notification for the + * topic |aTopic|. This assumes that the object implementing + * this interface has been registered with an observer service + * such as the nsIObserverService. + * + * If you expect multiple topics/subjects, the impl is + * responsible for filtering. + * + * You should not modify, add, remove, or enumerate + * notifications in the implemention of observe. + * + * @param aSubject : Notification specific interface pointer. + * @param aTopic : The notification topic or subject. + * @param aData : Notification specific wide string. + * subject event. + */ + void observe( in nsISupports aSubject, + in string aTopic, + in wstring aData ); + +}; + diff --git a/src/libs/xpcom18a4/xpcom/ds/nsIObserverService.idl b/src/libs/xpcom18a4/xpcom/ds/nsIObserverService.idl new file mode 100644 index 00000000..059a903a --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsIObserverService.idl @@ -0,0 +1,111 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsISupports.idl" + +interface nsIObserver; +interface nsISimpleEnumerator; + +/** + * nsIObserverService + * + * Service allows a client listener (nsIObserver) to register and unregister for + * notifications of specific string referenced topic. Service also provides a + * way to notify registered listeners and a way to enumerate registered client + * listeners. + * + * @status FROZEN + */ + +[scriptable, uuid(D07F5192-E3D1-11d2-8ACD-00105A1B8860)] +interface nsIObserverService : nsISupports +{ + + /** + * AddObserver + * + * Registers a given listener for a notifications regarding the specified + * topic. + * + * @param anObserve : The interface pointer which will receive notifications. + * @param aTopic : The notification topic or subject. + * @param ownsWeak : If set to false, the nsIObserverService will hold a + * strong reference to |anObserver|. If set to true and + * |anObserver| supports the nsIWeakReference interface, + * a weak reference will be held. Otherwise an error will be + * returned. + */ + void addObserver( in nsIObserver anObserver, in string aTopic, in boolean ownsWeak); + + /** + * removeObserver + * + * Unregisters a given listener from notifications regarding the specified + * topic. + * + * @param anObserver : The interface pointer which will stop recieving + * notifications. + * @param aTopic : The notification topic or subject. + */ + void removeObserver( in nsIObserver anObserver, in string aTopic ); + + /** + * notifyObservers + * + * Notifies all registered listeners of the given topic. + * + * @param aSubject : Notification specific interface pointer. + * @param aTopic : The notification topic or subject. + * @param someData : Notification specific wide string. + */ + void notifyObservers( in nsISupports aSubject, + in string aTopic, + in wstring someData ); + + /** + * enumerateObservers + * + * Returns an enumeration of all registered listeners. + * + * @param aTopic : The notification topic or subject. + */ + nsISimpleEnumerator enumerateObservers( in string aTopic ); + + +}; + + diff --git a/src/libs/xpcom18a4/xpcom/ds/nsIPersistentProperties.h b/src/libs/xpcom18a4/xpcom/ds/nsIPersistentProperties.h new file mode 100644 index 00000000..773a52ad --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsIPersistentProperties.h @@ -0,0 +1,8 @@ + +#ifndef __gen_nsIPersistentProperties_h__ +#define __gen_nsIPersistentProperties_h__ + +// "soft" switch over to an IDL generated header file +#include "nsIPersistentProperties2.h" + +#endif /* __gen_nsIPersistentProperties_h__ */ diff --git a/src/libs/xpcom18a4/xpcom/ds/nsIPersistentProperties2.idl b/src/libs/xpcom18a4/xpcom/ds/nsIPersistentProperties2.idl new file mode 100644 index 00000000..3d935621 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsIPersistentProperties2.idl @@ -0,0 +1,107 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsISupports.idl" +#include "nsIProperties.idl" +#include "nsISimpleEnumerator.idl" + +interface nsIInputStream; +interface nsIOutputStream; + +[scriptable, uuid(283EE646-1AEF-11D4-98B3-00C04fA0CE9A)] +interface nsIPropertyElement : nsISupports { + attribute AUTF8String key; + attribute AString value; +}; + +[scriptable, uuid(1A180F60-93B2-11d2-9B8B-00805F8A16D9)] +interface nsIPersistentProperties : nsIProperties +{ + /** + * load a set of name/value pairs from the input stream + * names and values should be in UTF8 + */ + void load(in nsIInputStream input); + + /** + * output the values to the stream - results will be in UTF8 + */ + void save(in nsIOutputStream output, in AUTF8String header); + + /** + * call subclass() to make future calls to load() set the properties + * in this "superclass" instead + */ + void subclass(in nsIPersistentProperties superclass); + + /** + * get an enumeration of nsIPropertyElement objects, + * which are read-only (i.e. setting properties on the element will + * not make changes back into the source nsIPersistentProperties + */ + nsISimpleEnumerator enumerate(); + + /** + * shortcut to nsIProperty's get() which retrieves a string value + * directly (and thus faster) + */ + AString getStringProperty(in AUTF8String key); + + /** + * shortcut to nsIProperty's set() which sets a string value + * directly (and thus faster) + */ + AString setStringProperty(in AUTF8String key, in AString value); +}; + + +%{C++ + +//{283EE645-1AEF-11D4-98B3-00C04fA0CE9A} +#define NS_IPROPERTYELEMENT_CID \ +{ 0x283ee645, 0x1aef, 0x11d4, \ + { 0x98, 0xb3, 0x0, 0xc0, 0x4f, 0xa0, 0xce, 0x9a } } + +#define NS_IPERSISTENTPROPERTIES_CID \ +{ 0x2245e573, 0x9464, 0x11d2, \ + { 0x9b, 0x8b, 0x0, 0x80, 0x5f, 0x8a, 0x16, 0xd9 } } + +#define NS_PERSISTENTPROPERTIES_CONTRACTID "@mozilla.org/persistent-properties;1" +#define NS_PERSISTENTPROPERTIES_CLASSNAME "Persistent Properties" + +%} + diff --git a/src/libs/xpcom18a4/xpcom/ds/nsIProperties.idl b/src/libs/xpcom18a4/xpcom/ds/nsIProperties.idl new file mode 100644 index 00000000..32a2a057 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsIProperties.idl @@ -0,0 +1,79 @@ +/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsISupports.idl" + +/* + * Simple mapping service interface. + * @status FROZEN + */ + +[scriptable, uuid(78650582-4e93-4b60-8e85-26ebd3eb14ca)] +interface nsIProperties : nsISupports +{ + /** + * Gets a property with a given name. + * + * @return NS_ERROR_FAILURE if a property with that name doesn't exist. + * @return NS_ERROR_NO_INTERFACE if the found property fails to QI to the + * given iid. + */ + void get(in string prop, in nsIIDRef iid, + [iid_is(iid),retval] out nsQIResult result); + + /** + * Sets a property with a given name to a given value. + */ + void set(in string prop, in nsISupports value); + + /** + * Returns true if the property with the given name exists. + */ + boolean has(in string prop); + + /** + * Undefines a property. + * @return NS_ERROR_FAILURE if a property with that name doesn't + * already exist. + */ + void undefine(in string prop); + + /** + * Returns an array of the keys. + */ + void getKeys(out PRUint32 count, [array, size_is(count), retval] out string keys); +}; diff --git a/src/libs/xpcom18a4/xpcom/ds/nsIPropertyBag.idl b/src/libs/xpcom18a4/xpcom/ds/nsIPropertyBag.idl new file mode 100644 index 00000000..b54577ff --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsIPropertyBag.idl @@ -0,0 +1,77 @@ +/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * John Bandhauer + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* nsIVariant based Property Bag support. */ + +#include "nsISupports.idl" +#include "nsIVariant.idl" +#include "nsISimpleEnumerator.idl" + +[scriptable, uuid(6dcf9030-a49f-11d5-910d-0010a4e73d9a)] +interface nsIProperty : nsISupports +{ + /** + * Get the name of the property. + */ + readonly attribute AString name; + + /** + * Get the value of the property. + */ + readonly attribute nsIVariant value; +}; + +[scriptable, uuid(bfcd37b0-a49f-11d5-910d-0010a4e73d9a)] +interface nsIPropertyBag : nsISupports +{ + /** + * Get a nsISimpleEnumerator whose elements are nsIProperty objects. + */ + readonly attribute nsISimpleEnumerator enumerator; + + /** + * Get a property value for the given name. + * @return NS_ERROR_FAILURE if a property with that name doesn't + * exist. + */ + nsIVariant getProperty(in AString name); +}; + +// We can add nsIWritableProperty and nsIWritablePropertyBag when we need them. + diff --git a/src/libs/xpcom18a4/xpcom/ds/nsIRecyclingAllocator.idl b/src/libs/xpcom18a4/xpcom/ds/nsIRecyclingAllocator.idl new file mode 100644 index 00000000..5402890e --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsIRecyclingAllocator.idl @@ -0,0 +1,68 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * 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): + * Suresh Duddi + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsIMemory.idl" + +/** + * + * nsIRecyclingAllocator: A wrapper for the nsRecyclingAllocator + * + * Holds allocations and reuses them for subsequent allocs. + * Thread safe and uses a timer to release freelist. + * + * @status UNDER-DEVELOPMENT + */ + +[scriptable, uuid(d064a04c-9cee-4319-be31-64d565bccba9)] +interface nsIRecyclingAllocator : nsIMemory +{ + void init(in size_t nblocks, in size_t recycleAfter, in string id); +}; + +%{C++ +#define NS_RECYCLINGALLOCATOR_CID \ +{ /* ac07ed4c-bf17-4976-a15c-d2194db3b1bf */ \ + 0xac07ed4c, \ + 0xbf17, \ + 0x4976, \ + {0xa1, 0x5c, 0xd2, 0x19, 0x4d, 0xb3, 0xb1, 0xbf} } + +#define NS_RECYCLINGALLOCATOR_CLASSNAME "Recycling Allocator" + +#define NS_RECYCLINGALLOCATOR_CONTRACTID "@mozilla.org/recycling-allocator;1" +%} diff --git a/src/libs/xpcom18a4/xpcom/ds/nsISerializable.idl b/src/libs/xpcom18a4/xpcom/ds/nsISerializable.idl new file mode 100644 index 00000000..907c4824 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsISerializable.idl @@ -0,0 +1,65 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 FastLoad code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Brendan Eich (original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsISupports.idl" + +interface nsIObjectInputStream; +interface nsIObjectOutputStream; + +[scriptable, uuid(91cca981-c26d-44a8-bebe-d9ed4891503a)] +interface nsISerializable : nsISupports +{ + /** + * Initialize the object implementing nsISerializable, which must have + * been freshly constructed via CreateInstance. All data members that + * can't be set to default values must have been serialized by write, + * and should be read from aInputStream in the same order by this method. + */ + void read(in nsIObjectInputStream aInputStream); + + /** + * Serialize the object implementing nsISerializable to aOutputStream, by + * writing each data member that must be recovered later to reconstitute + * a working replica of this object, in a canonical member and byte order, + * to aOutputStream. + * + * NB: a class that implements nsISerializable *must* also implement + * nsIClassInfo, in particular nsIClassInfo::GetClassID. + */ + void write(in nsIObjectOutputStream aOutputStream); +}; diff --git a/src/libs/xpcom18a4/xpcom/ds/nsISimpleEnumerator.idl b/src/libs/xpcom18a4/xpcom/ds/nsISimpleEnumerator.idl new file mode 100644 index 00000000..3f0efbf5 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsISimpleEnumerator.idl @@ -0,0 +1,81 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsISupports.idl" + +/** + * Used to enumerate over elements defined by its implementor. + * Although hasMoreElements() can be called independently of getNext(), + * getNext() must be pre-ceeded by a call to hasMoreElements(). There is + * no way to "reset" an enumerator, once you obtain one. + * + * @status FROZEN + * @version 1.0 + */ + +[scriptable, uuid(D1899240-F9D2-11D2-BDD6-000064657374)] +interface nsISimpleEnumerator : nsISupports { + /** + * Called to determine whether or not the enumerator has + * any elements that can be returned via getNext(). This method + * is generally used to determine whether or not to initiate or + * continue iteration over the enumerator, though it can be + * called without subsequent getNext() calls. Does not affect + * internal state of enumerator. + * + * @see getNext() + * @return PR_TRUE if there are remaining elements in the enumerator. + * PR_FALSE if there are no more elements in the enumerator. + */ + boolean hasMoreElements(); + + /** + * Called to retrieve the next element in the enumerator. The "next" + * element is the first element upon the first call. Must be + * pre-ceeded by a call to hasMoreElements() which returns PR_TRUE. + * This method is generally called within a loop to iterate over + * the elements in the enumerator. + * + * @see hasMoreElements() + * @return NS_OK if the call succeeded in returning a non-null + * value through the out parameter. + * NS_ERROR_FAILURE if there are no more elements + * to enumerate. + * @return the next element in the enumeration. + */ + nsISupports getNext(); +}; diff --git a/src/libs/xpcom18a4/xpcom/ds/nsIStringEnumerator.idl b/src/libs/xpcom18a4/xpcom/ds/nsIStringEnumerator.idl new file mode 100644 index 00000000..a7ac9131 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsIStringEnumerator.idl @@ -0,0 +1,58 @@ +/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 String Enumerator. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corp. + * Portions created by the Initial Developer are Copyright (C) 2003 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Alec Flett + * + * 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 "nsISupports.idl" + +/** + * Used to enumerate over an ordered list of strings. + */ + +[scriptable, uuid(50d3ef6c-9380-4f06-9fb2-95488f7d141c)] +interface nsIStringEnumerator : nsISupports +{ + boolean hasMore(); + AString getNext(); +}; + +[scriptable, uuid(9bdf1010-3695-4907-95ed-83d0410ec307)] +interface nsIUTF8StringEnumerator : nsISupports +{ + boolean hasMore(); + AUTF8String getNext(); +}; + diff --git a/src/libs/xpcom18a4/xpcom/ds/nsISupportsArray.idl b/src/libs/xpcom18a4/xpcom/ds/nsISupportsArray.idl new file mode 100644 index 00000000..bce9f4bf --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsISupportsArray.idl @@ -0,0 +1,139 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsISupports.idl" +#include "nsICollection.idl" + +/* + * This entire interface is deprecated and should not be used. + * See nsIArray and nsIMutableArray for the new implementations. + * + * http://groups.google.com/groups?q=nsisupportsarray+group:netscape.public.mozilla.xpcom&hl=en&lr=&ie=UTF-8&oe=UTF-8&selm=3D779491.3050506%40netscape.com&rnum=2 + * http://groups.google.com/groups?q=nsisupportsarray+group:netscape.public.mozilla.xpcom&hl=en&lr=&ie=UTF-8&oe=UTF-8&selm=al8412%245ab2%40ripley.netscape.com&rnum=8 + */ + +native nsISupportsArrayEnumFunc(nsISupportsArrayEnumFunc); + +%{C++ + +class nsIBidirectionalEnumerator; + +#define NS_SUPPORTSARRAY_CID \ +{ /* bda17d50-0d6b-11d3-9331-00104ba0fd40 */ \ + 0xbda17d50, \ + 0x0d6b, \ + 0x11d3, \ + {0x93, 0x31, 0x00, 0x10, 0x4b, 0xa0, 0xfd, 0x40} \ +} +#define NS_SUPPORTSARRAY_CONTRACTID "@mozilla.org/supports-array;1" +#define NS_SUPPORTSARRAY_CLASSNAME "Supports Array" + +// Enumerator callback function. Return PR_FALSE to stop +typedef PRBool (*nsISupportsArrayEnumFunc)(nsISupports* aElement, void *aData); + +%} + +[scriptable, uuid(791eafa0-b9e6-11d1-8031-006008159b5a)] +interface nsISupportsArray : nsICollection { + + [notxpcom] boolean Equals([const] in nsISupportsArray other); + + [notxpcom] nsISupports ElementAt(in unsigned long aIndex); + + [notxpcom] long IndexOf([const] in nsISupports aPossibleElement); + [notxpcom] long IndexOfStartingAt([const] in nsISupports aPossibleElement, + in unsigned long aStartIndex); + [notxpcom] long LastIndexOf([const] in nsISupports aPossibleElement); + + // xpcom-compatible versions + long GetIndexOf(in nsISupports aPossibleElement); + long GetIndexOfStartingAt(in nsISupports aPossibleElement, + in unsigned long aStartIndex); + long GetLastIndexOf(in nsISupports aPossibleElement); + + [notxpcom] boolean InsertElementAt(in nsISupports aElement, + in unsigned long aIndex); + [notxpcom] boolean ReplaceElementAt(in nsISupports aElement, + in unsigned long aIndex); + + [notxpcom] boolean RemoveElementAt(in unsigned long aIndex); + [notxpcom] boolean RemoveLastElement([const] in nsISupports aElement); + + // xpcom-compatible versions + void DeleteLastElement(in nsISupports aElement); + void DeleteElementAt(in unsigned long aIndex); + + [notxpcom] boolean AppendElements(in nsISupportsArray aElements); + + void Compact(); + + [notxpcom, noscript] + boolean EnumerateForwards(in nsISupportsArrayEnumFunc aFunc, + in voidPtr aData); + [notxpcom, noscript] + boolean EnumerateBackwards(in nsISupportsArrayEnumFunc aFunc, + in voidPtr aData); + + nsISupportsArray clone(); + + [notxpcom] boolean MoveElement(in long aFrom, + in long aTo); + + [notxpcom] boolean InsertElementsAt(in nsISupportsArray aOther, + in unsigned long aIndex); + + [notxpcom] boolean RemoveElementsAt(in unsigned long aIndex, + in unsigned long aCount); + + [notxpcom] boolean SizeTo(in long aSize); + +}; + +%{C++ + +// Construct and return a default implementation of nsISupportsArray: +extern NS_COM nsresult +NS_NewISupportsArray(nsISupportsArray** aInstancePtrResult); + +// Construct and return a default implementation of an enumerator for nsISupportsArrays: +extern NS_COM nsresult +NS_NewISupportsArrayEnumerator(nsISupportsArray* array, + nsIBidirectionalEnumerator* *aInstancePtrResult); + + +%} diff --git a/src/libs/xpcom18a4/xpcom/ds/nsISupportsIterators.idl b/src/libs/xpcom18a4/xpcom/ds/nsISupportsIterators.idl new file mode 100644 index 00000000..f1d8bce1 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsISupportsIterators.idl @@ -0,0 +1,325 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Scott Collins + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* nsISupportsIterators.idl --- IDL defining general purpose iterators */ + + +#include "nsISupports.idl" + + + /* + ... + */ + + + /** + * ... + */ +[scriptable, uuid(7330650e-1dd2-11b2-a0c2-9ff86ee97bed)] +interface nsIOutputIterator : nsISupports + { + /** + * Put |anElementToPut| into the underlying container or sequence at the position currently pointed to by this iterator. + * The iterator and the underlying container or sequence cooperate to |Release()| + * the replaced element, if any and if necessary, and to |AddRef()| the new element. + * + * The result is undefined if this iterator currently points outside the + * useful range of the underlying container or sequence. + * + * @param anElementToPut the element to place into the underlying container or sequence + */ + void putElement( in nsISupports anElementToPut ); + + /** + * Advance this iterator to the next position in the underlying container or sequence. + */ + void stepForward(); + }; + + /** + * ... + */ +[scriptable, uuid(85585e12-1dd2-11b2-a930-f6929058269a)] +interface nsIInputIterator : nsISupports + { + /** + * Retrieve (and |AddRef()|) the element this iterator currently points to. + * + * The result is undefined if this iterator currently points outside the + * useful range of the underlying container or sequence. + * + * @result a new reference to the element this iterator currently points to (if any) + */ + nsISupports getElement(); + + /** + * Advance this iterator to the next position in the underlying container or sequence. + */ + void stepForward(); + + /** + * Test if |anotherIterator| points to the same position in the underlying container or sequence. + * + * The result is undefined if |anotherIterator| was not created by or for the same underlying container or sequence. + * + * @param anotherIterator another iterator to compare against, created by or for the same underlying container or sequence + * @result true if |anotherIterator| points to the same position in the underlying container or sequence + */ + boolean isEqualTo( in nsISupports anotherIterator ); + + /** + * Create a new iterator pointing to the same position in the underlying container or sequence to which this iterator currently points. + * The returned iterator is suitable for use in a subsequent call to |isEqualTo()| against this iterator. + * + * @result a new iterator pointing at the same position in the same underlying container or sequence as this iterator + */ + nsISupports clone(); + }; + + /** + * ... + */ +[scriptable, uuid(8da01646-1dd2-11b2-98a7-c7009045be7e)] +interface nsIForwardIterator : nsISupports + { + /** + * Retrieve (and |AddRef()|) the element this iterator currently points to. + * + * The result is undefined if this iterator currently points outside the + * useful range of the underlying container or sequence. + * + * @result a new reference to the element this iterator currently points to (if any) + */ + nsISupports getElement(); + + /** + * Put |anElementToPut| into the underlying container or sequence at the position currently pointed to by this iterator. + * The iterator and the underlying container or sequence cooperate to |Release()| + * the replaced element, if any and if necessary, and to |AddRef()| the new element. + * + * The result is undefined if this iterator currently points outside the + * useful range of the underlying container or sequence. + * + * @param anElementToPut the element to place into the underlying container or sequence + */ + void putElement( in nsISupports anElementToPut ); + + /** + * Advance this iterator to the next position in the underlying container or sequence. + */ + void stepForward(); + + /** + * Test if |anotherIterator| points to the same position in the underlying container or sequence. + * + * The result is undefined if |anotherIterator| was not created by or for the same underlying container or sequence. + * + * @param anotherIterator another iterator to compare against, created by or for the same underlying container or sequence + * @result true if |anotherIterator| points to the same position in the underlying container or sequence + */ + boolean isEqualTo( in nsISupports anotherIterator ); + + /** + * Create a new iterator pointing to the same position in the underlying container or sequence to which this iterator currently points. + * The returned iterator is suitable for use in a subsequent call to |isEqualTo()| against this iterator. + * + * @result a new iterator pointing at the same position in the same underlying container or sequence as this iterator + */ + nsISupports clone(); + }; + + /** + * ... + */ +[scriptable, uuid(948defaa-1dd1-11b2-89f6-8ce81f5ebda9)] +interface nsIBidirectionalIterator : nsISupports + { + /** + * Retrieve (and |AddRef()|) the element this iterator currently points to. + * + * The result is undefined if this iterator currently points outside the + * useful range of the underlying container or sequence. + * + * @result a new reference to the element this iterator currently points to (if any) + */ + nsISupports getElement(); + + /** + * Put |anElementToPut| into the underlying container or sequence at the position currently pointed to by this iterator. + * The iterator and the underlying container or sequence cooperate to |Release()| + * the replaced element, if any and if necessary, and to |AddRef()| the new element. + * + * The result is undefined if this iterator currently points outside the + * useful range of the underlying container or sequence. + * + * @param anElementToPut the element to place into the underlying container or sequence + */ + void putElement( in nsISupports anElementToPut ); + + /** + * Advance this iterator to the next position in the underlying container or sequence. + */ + void stepForward(); + + /** + * Move this iterator to the previous position in the underlying container or sequence. + */ + void stepBackward(); + + /** + * Test if |anotherIterator| points to the same position in the underlying container or sequence. + * + * The result is undefined if |anotherIterator| was not created by or for the same underlying container or sequence. + * + * @param anotherIterator another iterator to compare against, created by or for the same underlying container or sequence + * @result true if |anotherIterator| points to the same position in the underlying container or sequence + */ + boolean isEqualTo( in nsISupports anotherIterator ); + + /** + * Create a new iterator pointing to the same position in the underlying container or sequence to which this iterator currently points. + * The returned iterator is suitable for use in a subsequent call to |isEqualTo()| against this iterator. + * + * @result a new iterator pointing at the same position in the same underlying container or sequence as this iterator + */ + nsISupports clone(); + }; + + /** + * ... + */ +[scriptable, uuid(9bd6fdb0-1dd1-11b2-9101-d15375968230)] +interface nsIRandomAccessIterator : nsISupports + { + /** + * Retrieve (and |AddRef()|) the element this iterator currently points to. + * + * The result is undefined if this iterator currently points outside the + * useful range of the underlying container or sequence. + * + * @result a new reference to the element this iterator currently points to (if any) + */ + nsISupports getElement(); + + /** + * Retrieve (and |AddRef()|) an element at some offset from where this iterator currently points. + * The offset may be negative. |getElementAt(0)| is equivalent to |getElement()|. + * + * The result is undefined if this iterator currently points outside the + * useful range of the underlying container or sequence. + * + * @param anOffset a |0|-based offset from the position to which this iterator currently points + * @result a new reference to the indicated element (if any) + */ + nsISupports getElementAt( in PRInt32 anOffset ); + + /** + * Put |anElementToPut| into the underlying container or sequence at the position currently pointed to by this iterator. + * The iterator and the underlying container or sequence cooperate to |Release()| + * the replaced element, if any and if necessary, and to |AddRef()| the new element. + * + * The result is undefined if this iterator currently points outside the + * useful range of the underlying container or sequence. + * + * @param anElementToPut the element to place into the underlying container or sequence + */ + void putElement( in nsISupports anElementToPut ); + + /** + * Put |anElementToPut| into the underlying container or sequence at the position |anOffset| away from that currently pointed to by this iterator. + * The iterator and the underlying container or sequence cooperate to |Release()| + * the replaced element, if any and if necessary, and to |AddRef()| the new element. + * |putElementAt(0, obj)| is equivalent to |putElement(obj)|. + * + * The result is undefined if this iterator currently points outside the + * useful range of the underlying container or sequence. + * + * @param anOffset a |0|-based offset from the position to which this iterator currently points + * @param anElementToPut the element to place into the underlying container or sequence + */ + void putElementAt( in PRInt32 anOffset, in nsISupports anElementToPut ); + + /** + * Advance this iterator to the next position in the underlying container or sequence. + */ + void stepForward(); + + /** + * Move this iterator by |anOffset| positions in the underlying container or sequence. + * |anOffset| may be negative. |stepForwardBy(1)| is equivalent to |stepForward()|. + * |stepForwardBy(0)| is a no-op. + * + * @param anOffset a |0|-based offset from the position to which this iterator currently points + */ + void stepForwardBy( in PRInt32 anOffset ); + + /** + * Move this iterator to the previous position in the underlying container or sequence. + */ + void stepBackward(); + + /** + * Move this iterator backwards by |anOffset| positions in the underlying container or sequence. + * |anOffset| may be negative. |stepBackwardBy(1)| is equivalent to |stepBackward()|. + * |stepBackwardBy(n)| is equivalent to |stepForwardBy(-n)|. |stepBackwardBy(0)| is a no-op. + * + * @param anOffset a |0|-based offset from the position to which this iterator currently points + */ + void stepBackwardBy( in PRInt32 anOffset ); + + /** + * Test if |anotherIterator| points to the same position in the underlying container or sequence. + * + * The result is undefined if |anotherIterator| was not created by or for the same underlying container or sequence. + * + * @param anotherIterator another iterator to compare against, created by or for the same underlying container or sequence + * @result true if |anotherIterator| points to the same position in the underlying container or sequence + */ + boolean isEqualTo( in nsISupports anotherIterator ); + + /** + * Create a new iterator pointing to the same position in the underlying container or sequence to which this iterator currently points. + * The returned iterator is suitable for use in a subsequent call to |isEqualTo()| against this iterator. + * + * @result a new iterator pointing at the same position in the same underlying container or sequence as this iterator + */ + nsISupports clone(); + }; + +%{C++ +%} diff --git a/src/libs/xpcom18a4/xpcom/ds/nsISupportsPrimitives.idl b/src/libs/xpcom18a4/xpcom/ds/nsISupportsPrimitives.idl new file mode 100644 index 00000000..680e5599 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsISupportsPrimitives.idl @@ -0,0 +1,304 @@ +/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Dan Rosen + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* nsISupports wrappers for single primitive pieces of data. */ + +#include "nsISupports.idl" + +/** + * Primitive base interface. + * + * These first three are pointer types and do data copying + * using the nsIMemory. Be careful! + * + * @status FROZEN + */ + +[scriptable, uuid(d0d4b136-1dd1-11b2-9371-f0727ef827c0)] +interface nsISupportsPrimitive : nsISupports +{ + const unsigned short TYPE_ID = 1; + const unsigned short TYPE_CSTRING = 2; + const unsigned short TYPE_STRING = 3; + const unsigned short TYPE_PRBOOL = 4; + const unsigned short TYPE_PRUINT8 = 5; + const unsigned short TYPE_PRUINT16 = 6; + const unsigned short TYPE_PRUINT32 = 7; + const unsigned short TYPE_PRUINT64 = 8; + const unsigned short TYPE_PRTIME = 9; + const unsigned short TYPE_CHAR = 10; + const unsigned short TYPE_PRINT16 = 11; + const unsigned short TYPE_PRINT32 = 12; + const unsigned short TYPE_PRINT64 = 13; + const unsigned short TYPE_FLOAT = 14; + const unsigned short TYPE_DOUBLE = 15; + const unsigned short TYPE_VOID = 16; + const unsigned short TYPE_INTERFACE_POINTER = 17; + + readonly attribute unsigned short type; +}; + +/** + * Scriptable storage for nsID structures + * + * @status FROZEN + */ + +[scriptable, uuid(d18290a0-4a1c-11d3-9890-006008962422)] +interface nsISupportsID : nsISupportsPrimitive +{ + attribute nsIDPtr data; + string toString(); +}; + +/** + * Scriptable storage for ASCII strings + * + * @status FROZEN + */ + +[scriptable, uuid(d65ff270-4a1c-11d3-9890-006008962422)] +interface nsISupportsCString : nsISupportsPrimitive +{ + attribute ACString data; + string toString(); +}; + +/** + * Scriptable storage for Unicode strings + * + * @status FROZEN + */ + +[scriptable, uuid(d79dc970-4a1c-11d3-9890-006008962422)] +interface nsISupportsString : nsISupportsPrimitive +{ + attribute AString data; + wstring toString(); +}; + +/** + * The rest are truly primitive and are passed by value + */ + +/** + * Scriptable storage for booleans + * + * @status FROZEN + */ + +[scriptable, uuid(ddc3b490-4a1c-11d3-9890-006008962422)] +interface nsISupportsPRBool : nsISupportsPrimitive +{ + attribute PRBool data; + string toString(); +}; + +/** + * Scriptable storage for 8-bit integers + * + * @status FROZEN + */ + +[scriptable, uuid(dec2e4e0-4a1c-11d3-9890-006008962422)] +interface nsISupportsPRUint8 : nsISupportsPrimitive +{ + attribute PRUint8 data; + string toString(); +}; + +/** + * Scriptable storage for unsigned 16-bit integers + * + * @status FROZEN + */ + +[scriptable, uuid(dfacb090-4a1c-11d3-9890-006008962422)] +interface nsISupportsPRUint16 : nsISupportsPrimitive +{ + attribute PRUint16 data; + string toString(); +}; + +/** + * Scriptable storage for unsigned 32-bit integers + * + * @status FROZEN + */ + +[scriptable, uuid(e01dc470-4a1c-11d3-9890-006008962422)] +interface nsISupportsPRUint32 : nsISupportsPrimitive +{ + attribute PRUint32 data; + string toString(); +}; + +/** + * Scriptable storage for 64-bit integers + * + * @status FROZEN + */ + +[scriptable, uuid(e13567c0-4a1c-11d3-9890-006008962422)] +interface nsISupportsPRUint64 : nsISupportsPrimitive +{ + attribute PRUint64 data; + string toString(); +}; + +/** + * Scriptable storage for NSPR date/time values + * + * @status FROZEN + */ + +[scriptable, uuid(e2563630-4a1c-11d3-9890-006008962422)] +interface nsISupportsPRTime : nsISupportsPrimitive +{ + attribute PRTime data; + string toString(); +}; + +/** + * Scriptable storage for single character values + * (often used to store an ASCII character) + * + * @status FROZEN + */ + +[scriptable, uuid(e2b05e40-4a1c-11d3-9890-006008962422)] +interface nsISupportsChar : nsISupportsPrimitive +{ + attribute char data; + string toString(); +}; + +/** + * Scriptable storage for 16-bit integers + * + * @status FROZEN + */ + +[scriptable, uuid(e30d94b0-4a1c-11d3-9890-006008962422)] +interface nsISupportsPRInt16 : nsISupportsPrimitive +{ + attribute PRInt16 data; + string toString(); +}; + +/** + * Scriptable storage for 32-bit integers + * + * @status FROZEN + */ + +[scriptable, uuid(e36c5250-4a1c-11d3-9890-006008962422)] +interface nsISupportsPRInt32 : nsISupportsPrimitive +{ + attribute PRInt32 data; + string toString(); +}; + +/** + * Scriptable storage for 64-bit integers + * + * @status FROZEN + */ + +[scriptable, uuid(e3cb0ff0-4a1c-11d3-9890-006008962422)] +interface nsISupportsPRInt64 : nsISupportsPrimitive +{ + attribute PRInt64 data; + string toString(); +}; + +/** + * Scriptable storage for floating point numbers + * + * @status FROZEN + */ + +[scriptable, uuid(abeaa390-4ac0-11d3-baea-00805f8a5dd7)] +interface nsISupportsFloat : nsISupportsPrimitive +{ + attribute float data; + string toString(); +}; + +/** + * Scriptable storage for doubles + * + * @status FROZEN + */ + +[scriptable, uuid(b32523a0-4ac0-11d3-baea-00805f8a5dd7)] +interface nsISupportsDouble : nsISupportsPrimitive +{ + attribute double data; + string toString(); +}; + +/** + * Scriptable storage for generic pointers + * + * @status FROZEN + */ + +[scriptable, uuid(464484f0-568d-11d3-baf8-00805f8a5dd7)] +interface nsISupportsVoid : nsISupportsPrimitive +{ + [noscript] attribute voidPtr data; + string toString(); +}; + +/** + * Scriptable storage for other XPCOM objects + * + * @status FROZEN + */ + +[scriptable, uuid(995ea724-1dd1-11b2-9211-c21bdd3e7ed0)] +interface nsISupportsInterfacePointer : nsISupportsPrimitive +{ + attribute nsISupports data; + attribute nsIDPtr dataIID; + + string toString(); +}; + + diff --git a/src/libs/xpcom18a4/xpcom/ds/nsITimelineService.idl b/src/libs/xpcom18a4/xpcom/ds/nsITimelineService.idl new file mode 100644 index 00000000..f0495a35 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsITimelineService.idl @@ -0,0 +1,242 @@ +/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsISupports.idl" + +%{C++ +#ifdef MOZ_TIMELINE +%} + +/** + * nsITimelineService is used to constuct a timeline of program + * execution. The timeline is output to a file, either stderr or the + * value of the environment variable NS_TIMELINE_LOG_FILE. On the + * Mac, the timeline is output to the file named "timeline.txt". The + * reason it's different on the Mac is that the Mac environment + * initialization code happens after timeline initialization code. + * + * If NS_TIMELINE_INIT_TIME is set in the environment, that will be + * used as the time of startup; otherwise the current time when mark() + * is first called will be used. + * + * mark() is used to put marks on the timeline. + * + * indent() and outdent() are used to format the timeline a bit to + * show nesting. This doesn't produce perfect results in the face of + * asychrony and multiple threads. + * + * enter() and leave() are convenience functions that add marks to the + * timeline and do indentation. + * + * startTimer() and stopTimer() control named stop watches. If + * startTimer() is called more than once, an equal number of + * stopTimer() calls are needed to actually stop the timer. This + * makes these timers slightly useful in a threaded environment. + * + * markTimer() puts a mark on the timeline containing the total for + * the named timer. + * + * Don't use nsITimelineService in C++ code; use the NS_TIMELINE + * macros instead. nsITimelineService exists so that JavaScript code + * can mark the timeline. + */ +[scriptable, uuid(93276790-3daf-11d5-b67d-000064657374)] +interface nsITimelineService : nsISupports +{ + /** + * mark() + * Print ": \n" in the timeline log file. + */ + void mark(in string text); + + /** + * causes subsequent marks to be indented for a more readable + * report. + */ + void indent(); + + /** + * Causes subsequent marks to be outdented. + */ + void outdent(); + + /** + * enter/leave bracket code with "..." and "..." as + * well as indentation. + */ + void enter(in string text); + void leave(in string text); + + void startTimer(in string timerName); + + void stopTimer(in string timerName); + + void markTimer(in string timerName); + + void resetTimer(in string timerName); + + // Mark a timer, plus an additional comment + void markTimerWithComment(in string timerName, in string comment); +}; + +%{C++ +#endif /* MOZ_TIMELINE */ +%} + + +%{C++ + +#ifdef MOZ_TIMELINE + +/* + * These are equivalent to the corresponding nsITimelineService + * methods, and can be called before XPCOM is initialized. + */ +extern "C" NS_COM nsresult NS_TimelineMark(const char *text, ...); +extern "C" NS_COM nsresult NS_TimelineForceMark(const char *text, ...); +extern "C" NS_COM nsresult NS_TimelineStartTimer(const char *timerName); +extern "C" NS_COM nsresult NS_TimelineStopTimer(const char *timerName); +extern "C" NS_COM nsresult NS_TimelineResetTimer(const char *timerName); +extern "C" NS_COM nsresult NS_TimelineMarkTimer(const char *timerName, const char *str=nsnull); +extern "C" NS_COM nsresult NS_TimelineIndent(); +extern "C" NS_COM nsresult NS_TimelineOutdent(); +extern "C" NS_COM nsresult NS_TimelineEnter(const char *text); +extern "C" NS_COM nsresult NS_TimelineLeave(const char *text); + +/* + * Use these macros for the above calls so we can easily compile them + * out. + */ +#define NS_TIMELINE_MARK(text) NS_TimelineMark(text) +#define NS_TIMELINE_MARKV(args) NS_TimelineMark args +#define NS_TIMELINE_INDENT() NS_TimelineIndent() +#define NS_TIMELINE_OUTDENT() NS_TimelineOutdent() +#define NS_TIMELINE_ENTER(text) NS_TimelineEnter(text) +#define NS_TIMELINE_LEAVE(text) NS_TimelineLeave(text) +#define NS_TIMELINE_START_TIMER(timerName) NS_TimelineStartTimer(timerName) +#define NS_TIMELINE_STOP_TIMER(timerName) NS_TimelineStopTimer(timerName) +#define NS_TIMELINE_MARK_TIMER(timerName) NS_TimelineMarkTimer(timerName) +#define NS_TIMELINE_RESET_TIMER(timerName) NS_TimelineResetTimer(timerName) +#define NS_TIMELINE_MARK_TIMER1(timerName, str) NS_TimelineMarkTimer(timerName, str) + +/* + * Helper class to time functions. Use only static strings. + */ +class nsFunctionTimer { +public: + const char *mTimer; + PRBool mMark; + const char *mMarkStr; + nsFunctionTimer(const char *timer, PRBool mark = PR_TRUE, const char *markStr = nsnull) + : mTimer(timer), mMark(mark), mMarkStr(markStr) + { + NS_TIMELINE_START_TIMER(mTimer); + } + + ~nsFunctionTimer() + { + NS_TIMELINE_STOP_TIMER(mTimer); + if (mMark) + if (mMarkStr) + NS_TIMELINE_MARK_TIMER1(mTimer, mMarkStr); + else + NS_TIMELINE_MARK_TIMER(mTimer); + } +}; + +/* + * NS_TIMELINE_MARK_ macros for various data types. Each of these + * macros replaces "%s" in its "text" argument with a string + * representation of its last argument. + * + * Please feel free to add more NS_TIMELINE_MARK_ macros for + * various data types so that code using NS_TIMELINE is uncluttered. + * Don't forget the empty versions in the #else section below for + * non-timeline builds. + */ +#define NS_TIMELINE_MARK_URI(text, uri) \ + { \ + nsCAutoString spec; \ + if (uri) { \ + uri->GetSpec(spec); \ + } \ + if (!spec.IsEmpty()) { \ + NS_TimelineMark(text, spec.get()); \ + } else { \ + NS_TimelineMark(text, "??"); \ + } \ + } + +#define NS_TIMELINE_MARK_CHANNEL(text, channel) \ + { \ + nsCOMPtr uri; \ + if (channel) { \ + channel->GetURI(getter_AddRefs(uri)); \ + } \ + NS_TIMELINE_MARK_URI(text, uri); \ + } + +#define NS_TIMELINE_MARK_LOADER(text, loader) \ + { \ + nsCOMPtr request; \ + loader->GetRequest(getter_AddRefs(request)); \ + nsCOMPtr channel(do_QueryInterface(request)); \ + NS_TIMELINE_MARK_CHANNEL(text, channel); \ + } +#define NS_TIMELINE_MARK_FUNCTION(timer) nsFunctionTimer functionTimer(timer) +#define NS_TIMELINE_MARK_FUNCTION1(timer, str) nsFunctionTimer functionTimer(timer, PR_TRUE, str) +#define NS_TIMELINE_TIME_FUNCTION(timer) nsFunctionTimer functionTimer(timer, PR_FALSE) /* no mark, only time */ + +#else /* !defined(MOZ_TIMELINE) */ +#define NS_TIMELINE_MARK(text) +#define NS_TIMELINE_MARKV(args) +#define NS_TIMELINE_INDENT() +#define NS_TIMELINE_OUTDENT() +#define NS_TIMELINE_START_TIMER(timerName) +#define NS_TIMELINE_STOP_TIMER(timerName) +#define NS_TIMELINE_MARK_TIMER(timerName) +#define NS_TIMELINE_RESET_TIMER(timerName) +#define NS_TIMELINE_MARK_TIMER1(timerName, str) +#define NS_TIMELINE_ENTER(text) +#define NS_TIMELINE_LEAVE(text) +#define NS_TIMELINE_MARK_URI(text, uri) +#define NS_TIMELINE_MARK_FUNCTION(timer) +#define NS_TIMELINE_TIME_FUNCTION(timer) +#define NS_TIMELINE_MARK_CHANNEL(text, channel) +#define NS_TIMELINE_MARK_LOADER(text, loader); +#endif /* defined(MOZ_TIMELINE) */ +%} diff --git a/src/libs/xpcom18a4/xpcom/ds/nsIUnicharBuffer.h b/src/libs/xpcom18a4/xpcom/ds/nsIUnicharBuffer.h new file mode 100644 index 00000000..dae89021 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsIUnicharBuffer.h @@ -0,0 +1,73 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ +#ifndef nsIUnicharBuffer_h___ +#define nsIUnicharBuffer_h___ + +#include "nscore.h" +#include "nsISupports.h" + +#define NS_IUNICHARBUFFER_IID \ +{ 0x14cf6970, 0x93b5, 0x11d1, \ + {0x89, 0x5b, 0x00, 0x60, 0x08, 0x91, 0x1b, 0x81} } + +/// Interface to a buffer that holds unicode characters +class nsIUnicharBuffer : public nsISupports { +public: + NS_DEFINE_STATIC_IID_ACCESSOR(NS_IUNICHARBUFFER_IID); + + NS_IMETHOD Init(PRUint32 aBufferSize) = 0; + NS_IMETHOD_(PRInt32) GetLength() const = 0; + NS_IMETHOD_(PRInt32) GetBufferSize() const = 0; + NS_IMETHOD_(PRUnichar*) GetBuffer() const = 0; + NS_IMETHOD_(PRBool) Grow(PRInt32 aNewSize) = 0; +}; + +/// Factory method for nsIUnicharBuffer. +extern NS_COM nsresult +NS_NewUnicharBuffer(nsIUnicharBuffer** aInstancePtrResult, + nsISupports* aOuter, + PRUint32 aBufferSize = 0); + +#define NS_UNICHARBUFFER_CID \ +{ /* c81fd8f0-0d6b-11d3-9331-00104ba0fd40 */ \ + 0xc81fd8f0, \ + 0x0d6b, \ + 0x11d3, \ + {0x93, 0x31, 0x00, 0x10, 0x4b, 0xa0, 0xfd, 0x40} \ +} + +#endif /* nsIUnicharBuffer_h___ */ diff --git a/src/libs/xpcom18a4/xpcom/ds/nsIVariant.idl b/src/libs/xpcom18a4/xpcom/ds/nsIVariant.idl new file mode 100644 index 00000000..2c9d9e96 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsIVariant.idl @@ -0,0 +1,188 @@ +/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * John Bandhauer + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* The long avoided variant support for xpcom. */ + +#include "nsISupports.idl" + +[scriptable,uuid(4d12e540-83d7-11d5-90ed-0010a4e73d9a)] +interface nsIDataType : nsISupports +{ + // These MUST match the declarations in xpt_struct.h. + // Otherwise the world is likely to explode. + // From xpt_struct.h ... + const PRUint16 VTYPE_INT8 = 0; // TD_INT8 = 0, + const PRUint16 VTYPE_INT16 = 1; // TD_INT16 = 1, + const PRUint16 VTYPE_INT32 = 2; // TD_INT32 = 2, + const PRUint16 VTYPE_INT64 = 3; // TD_INT64 = 3, + const PRUint16 VTYPE_UINT8 = 4; // TD_UINT8 = 4, + const PRUint16 VTYPE_UINT16 = 5; // TD_UINT16 = 5, + const PRUint16 VTYPE_UINT32 = 6; // TD_UINT32 = 6, + const PRUint16 VTYPE_UINT64 = 7; // TD_UINT64 = 7, + const PRUint16 VTYPE_FLOAT = 8; // TD_FLOAT = 8, + const PRUint16 VTYPE_DOUBLE = 9; // TD_DOUBLE = 9, + const PRUint16 VTYPE_BOOL = 10; // TD_BOOL = 10, + const PRUint16 VTYPE_CHAR = 11; // TD_CHAR = 11, + const PRUint16 VTYPE_WCHAR = 12; // TD_WCHAR = 12, + const PRUint16 VTYPE_VOID = 13; // TD_VOID = 13, + const PRUint16 VTYPE_ID = 14; // TD_PNSIID = 14, + const PRUint16 VTYPE_DOMSTRING = 15; // TD_DOMSTRING = 15, + const PRUint16 VTYPE_CHAR_STR = 16; // TD_PSTRING = 16, + const PRUint16 VTYPE_WCHAR_STR = 17; // TD_PWSTRING = 17, + const PRUint16 VTYPE_INTERFACE = 18; // TD_INTERFACE_TYPE = 18, + const PRUint16 VTYPE_INTERFACE_IS = 19; // TD_INTERFACE_IS_TYPE = 19, + const PRUint16 VTYPE_ARRAY = 20; // TD_ARRAY = 20, + const PRUint16 VTYPE_STRING_SIZE_IS = 21; // TD_PSTRING_SIZE_IS = 21, + const PRUint16 VTYPE_WSTRING_SIZE_IS = 22; // TD_PWSTRING_SIZE_IS = 22, + const PRUint16 VTYPE_UTF8STRING = 23; // TD_UTF8STRING = 23, + const PRUint16 VTYPE_CSTRING = 24; // TD_CSTRING = 24, + const PRUint16 VTYPE_ASTRING = 25; // TD_ASTRING = 25, + const PRUint16 VTYPE_EMPTY_ARRAY = 254; + const PRUint16 VTYPE_EMPTY = 255; +}; + + +/** + * XPConnect has magic to transparently convert between nsIVariant and JS types. + * We mark the interface [scriptable] so that JS can use methods + * that refer to this interface. But we mark all the methods and attributes + * [noscript] since any nsIVariant object will be automatically converted to a + * JS type anyway. + */ + +[scriptable, uuid(6c9eb060-8c6a-11d5-90f3-0010a4e73d9a)] +interface nsIVariant : nsISupports +{ + [noscript] readonly attribute PRUint16 dataType; + + [noscript] PRUint8 getAsInt8(); + [noscript] PRInt16 getAsInt16(); + [noscript] PRInt32 getAsInt32(); + [noscript] PRInt64 getAsInt64(); + [noscript] PRUint8 getAsUint8(); + [noscript] PRUint16 getAsUint16(); + [noscript] PRUint32 getAsUint32(); + [noscript] PRUint64 getAsUint64(); + [noscript] float getAsFloat(); + [noscript] double getAsDouble(); + [noscript] PRBool getAsBool(); + [noscript] char getAsChar(); + [noscript] wchar getAsWChar(); + [notxpcom] nsresult getAsID(out nsID retval); + [noscript] AString getAsAString(); + [noscript] DOMString getAsDOMString(); + [noscript] ACString getAsACString(); + [noscript] AUTF8String getAsAUTF8String(); + [noscript] string getAsString(); + [noscript] wstring getAsWString(); + [noscript] nsISupports getAsISupports(); + + [noscript] void getAsInterface(out nsIIDPtr iid, + [iid_is(iid), retval] out nsQIResult iface); + + [notxpcom] nsresult getAsArray(out PRUint16 type, out nsIID iid, + out PRUint32 count, out voidPtr ptr); + + [noscript] void getAsStringWithSize(out PRUint32 size, + [size_is(size), retval] out string str); + + [noscript] void getAsWStringWithSize(out PRUint32 size, + [size_is(size), retval] out wstring str); +}; + +/** + * An object that implements nsIVariant may or may NOT also implement this + * nsIWritableVariant. + * + * If the 'writable' attribute is false then attempts to call any of the 'set' + * methods can be expected to fail. Setting the 'writable' attribute may or + * may not succeed. + * + */ + +[scriptable, uuid(5586a590-8c82-11d5-90f3-0010a4e73d9a)] +interface nsIWritableVariant : nsIVariant +{ + attribute PRBool writable; + + void setAsInt8(in PRUint8 aValue); + void setAsInt16(in PRInt16 aValue); + void setAsInt32(in PRInt32 aValue); + void setAsInt64(in PRInt64 aValue); + void setAsUint8(in PRUint8 aValue); + void setAsUint16(in PRUint16 aValue); + void setAsUint32(in PRUint32 aValue); + void setAsUint64(in PRUint64 aValue); + void setAsFloat(in float aValue); + void setAsDouble(in double aValue); + void setAsBool(in PRBool aValue); + void setAsChar(in char aValue); + void setAsWChar(in wchar aValue); + void setAsID(in nsIDRef aValue); + void setAsAString(in AString aValue); + void setAsDOMString(in DOMString aValue); + void setAsACString(in ACString aValue); + void setAsAUTF8String(in AUTF8String aValue); + void setAsString(in string aValue); + void setAsWString(in wstring aValue); + void setAsISupports(in nsISupports aValue); + + void setAsInterface(in nsIIDRef iid, + [iid_is(iid)] in nsQIResult iface); + + [noscript] void setAsArray(in PRUint16 type, in nsIIDPtr iid, + in PRUint32 count, in voidPtr ptr); + + void setAsStringWithSize(in PRUint32 size, + [size_is(size)] in string str); + + void setAsWStringWithSize(in PRUint32 size, + [size_is(size)] in wstring str); + + void setAsVoid(); + void setAsEmpty(); + void setAsEmptyArray(); + + void setFromVariant(in nsIVariant aValue); +}; + +%{C++ +// The contractID for the generic implementation built in to xpcom. +#define NS_VARIANT_CONTRACTID "@mozilla.org/variant;1" +%} diff --git a/src/libs/xpcom18a4/xpcom/ds/nsInt64.h b/src/libs/xpcom18a4/xpcom/ds/nsInt64.h new file mode 100644 index 00000000..c7421548 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsInt64.h @@ -0,0 +1,399 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +#ifndef nsInt64_h__ +#define nsInt64_h__ + +#include "prlong.h" +#include "nscore.h" + +/** + * This class encapsulates full 64-bit integer functionality and + * provides simple arithmetic and conversion operations. + */ + +// If you ever decide that you need to add a non-inline method to this +// class, be sure to change the class declaration to "class NS_BASE +// nsInt64". + +template +class nsTInt64 +{ +public: //XXX should be private + T mValue; + +public: + /** + * Construct a new 64-bit integer. + */ + nsTInt64(void) : mValue(LL_ZERO) { + } + + /** + * Construct a new 64-bit integer from a 32-bit signed integer + */ + nsTInt64(const PRInt32 aInt32) { + LL_I2L(mValue, aInt32); + } + + /** + * Construct a new 64-bit integer from a 32-bit unsigned integer + */ + nsTInt64(const PRUint32 aUint32) { + LL_UI2L(mValue, aUint32); + } + + /** + * Construct a new 64-bit integer from a floating point value. + */ + nsTInt64(const PRFloat64 aFloat64) { + LL_D2L(mValue, aFloat64); + } + + /** + * Construct a new 64-bit integer from a native 64-bit integer + */ + nsTInt64(const T aInt64) : mValue(aInt64) { + } + + /** + * Construct a new 64-bit integer from another 64-bit integer + */ + nsTInt64(const nsTInt64& aObject) : mValue(aObject.mValue) { + } + + // ~nsTInt64(void) -- XXX destructor unnecessary + + /** + * Assign a 64-bit integer to another 64-bit integer + */ + const nsTInt64& operator =(const nsTInt64& aObject) { + mValue = aObject.mValue; + return *this; + } + + /** + * Convert a 64-bit integer to a signed 32-bit value + */ + operator PRInt32(void) const { + PRInt32 result; + LL_L2I(result, mValue); + return result; + } + + /** + * Convert a 64-bit integer to an unsigned 32-bit value + */ + operator PRUint32(void) const { + PRUint32 result; + LL_L2UI(result, mValue); + return result; + } + + /** + * Convert a 64-bit integer to a floating point value + */ + operator PRFloat64(void) const { + PRFloat64 result; + LL_L2D(result, mValue); + return result; + } + + /** + * Convert a 64-bit integer to a native 64-bit integer. + */ + operator T() const { + return mValue; + } + + /** + * Perform unary negation on a 64-bit integer. + */ + const nsTInt64 operator -(void) { + nsTInt64 result; + LL_NEG(result.mValue, mValue); + return result; + } + + // Arithmetic operators + + /** + * Increment a 64-bit integer by a 64-bit integer amount. + */ + nsTInt64& operator +=(const nsTInt64& aObject) { + LL_ADD(mValue, mValue, aObject.mValue); + return *this; + } + + /** + * Decrement a 64-bit integer by a 64-bit integer amount. + */ + nsTInt64& operator -=(const nsTInt64& aObject) { + LL_SUB(mValue, mValue, aObject.mValue); + return *this; + } + + /** + * Multiply a 64-bit integer by a 64-bit integer amount. + */ + nsTInt64& operator *=(const nsTInt64& aObject) { + LL_MUL(mValue, mValue, aObject.mValue); + return *this; + } + + /** + * Divide a 64-bit integer by a 64-bit integer amount. + */ + nsTInt64& operator /=(const nsTInt64& aObject) { + LL_DIV(mValue, mValue, aObject.mValue); + return *this; + } + + /** + * Compute the modulus of a 64-bit integer to a 64-bit value. + */ + nsTInt64& operator %=(const nsTInt64& aObject) { + LL_MOD(mValue, mValue, aObject.mValue); + return *this; + } + + /** + * Shift a 64-bit integer left. + */ + nsTInt64& operator <<=(int aCount) { + LL_SHL(mValue, mValue, aCount); + return *this; + } + + /** + * Shift a 64-bit signed integer right. + */ + nsTInt64& operator >>=(int aCount) { + LL_SHR(mValue, mValue, aCount); + return *this; + } + + // Comparison operators + /** + * Add two 64-bit integers. + */ + inline const nsTInt64 + operator +(const nsTInt64& aObject2) const { + return nsTInt64(*this) += aObject2; + } + + /** + * Subtract one 64-bit integer from another. + */ + inline const nsTInt64 + operator -(const nsTInt64& aObject2) const { + return nsTInt64(*this) -= aObject2; + } + + /** + * Multiply two 64-bit integers + */ + inline const nsTInt64 + operator *(const nsTInt64& aObject2) const { + return nsTInt64(*this) *= aObject2; + } + + /** + * Divide one 64-bit integer by another + */ + inline const nsTInt64 + operator /(const nsTInt64& aObject2) const { + return nsTInt64(*this) /= aObject2; + } + + /** + * Compute the modulus of two 64-bit integers + */ + inline const nsTInt64 + operator %(const nsTInt64& aObject2) const { + return nsTInt64(*this) %= aObject2; + } + + /** + * Shift left a 64-bit integer + */ + inline const nsTInt64 + operator <<(int aCount) const { + return nsTInt64(*this) <<= aCount; + } + + /** + * Shift right a signed 64-bit integer + */ + inline const nsTInt64 + operator >>(int aCount) const { + return nsTInt64(*this) >>= aCount; + } + + /** + * Determine if two 64-bit integers are equal + */ + inline PRBool + operator ==(const nsTInt64& aObject2) const { + return LL_EQ(mValue, aObject2.mValue); + } + + /** + * Determine if two 64-bit integers are not equal + */ + inline PRBool + operator !=(const nsTInt64& aObject2) const { + return LL_NE(mValue, aObject2.mValue); + } + + + /** + * Perform a bitwise AND of two 64-bit integers + */ + inline const nsTInt64 + operator &(const nsTInt64& aObject2) const { + return nsTInt64(*this) &= aObject2; + } + + /** + * Perform a bitwise OR of two 64-bit integers + */ + inline const nsTInt64 + operator |(const nsTInt64& aObject2) const { + return nsTInt64(*this) |= aObject2; + } + + /** + * Perform a bitwise XOR of two 64-bit integers + */ + inline const nsTInt64 + operator ^(const nsTInt64& aObject2) const { + return nsTInt64(*this) ^= aObject2; + } + + // Bitwise operators + + /** + * Compute the bitwise NOT of a 64-bit integer + */ + const nsTInt64 operator ~(void) const { + nsTInt64 result; + LL_NOT(result.mValue, mValue); + return result; + } + + /** + * Compute the bitwise AND with another 64-bit integer + */ + nsTInt64& operator &=(const nsTInt64& aObject) { + LL_AND(mValue, mValue, aObject.mValue); + return *this; + } + + /** + * Compute the bitwise OR with another 64-bit integer + */ + nsTInt64& operator |=(const nsTInt64& aObject) { + LL_OR(mValue, mValue, aObject.mValue); + return *this; + } + + /** + * Compute the bitwise XOR with another 64-bit integer + */ + nsTInt64& operator ^=(const nsTInt64& aObject) { + LL_XOR(mValue, mValue, aObject.mValue); + return *this; + } +}; + +typedef nsTInt64 nsInt64; +typedef nsTInt64 nsUint64; + +/** + * Determine if one 64-bit integer is strictly greater than another, using signed values + */ +inline PRBool +operator >(const nsInt64& aObject1, const nsInt64& aObject2) { + return LL_CMP(aObject1.mValue, >, aObject2.mValue); +} + +inline PRBool +operator >(const nsUint64& aObject1, const nsUint64& aObject2) { + return LL_UCMP(aObject1.mValue, >, aObject2.mValue); +} + +/** + * Determine if one 64-bit integer is greater than or equal to another, using signed values + */ +inline PRBool +operator >=(const nsInt64& aObject1, const nsInt64& aObject2) { + return ! LL_CMP(aObject1.mValue, <, aObject2.mValue); +} + +inline PRBool +operator >=(const nsUint64& aObject1, const nsUint64& aObject2) { + return ! LL_UCMP(aObject1.mValue, <, aObject2.mValue); +} + +/** + * Determine if one 64-bit integer is strictly less than another, using signed values + */ +inline PRBool +operator <(const nsInt64& aObject1, const nsInt64& aObject2) { + return LL_CMP(aObject1.mValue, <, aObject2.mValue); +} + +inline PRBool +operator <(const nsUint64& aObject1, const nsUint64& aObject2) { + return LL_UCMP(aObject1.mValue, <, aObject2.mValue); +} + +/** + * Determine if one 64-bit integers is less than or equal to another, using signed values + */ +inline PRBool +operator <=(const nsInt64& aObject1, const nsInt64& aObject2) { + return ! LL_CMP(aObject1.mValue, >, aObject2.mValue); +} + +inline PRBool +operator <=(const nsUint64& aObject1, const nsUint64& aObject2) { + return ! LL_UCMP(aObject1.mValue, >, aObject2.mValue); +} + +#endif // nsInt64_h__ diff --git a/src/libs/xpcom18a4/xpcom/ds/nsInterfaceHashtable.h b/src/libs/xpcom18a4/xpcom/ds/nsInterfaceHashtable.h new file mode 100644 index 00000000..68b06d66 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsInterfaceHashtable.h @@ -0,0 +1,196 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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 C++ hashtable templates. + * + * The Initial Developer of the Original Code is + * Benjamin Smedberg. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * 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 ***** */ + +#ifndef nsInterfaceHashtable_h__ +#define nsInterfaceHashtable_h__ + +#include "nsBaseHashtable.h" +#include "nsHashKeys.h" +#include "nsCOMPtr.h" + +/** + * templated hashtable class maps keys to interface pointers. + * See nsBaseHashtable for complete declaration. + * @param KeyClass a wrapper-class for the hashtable key, see nsHashKeys.h + * for a complete specification. + * @param Interface the interface-type being wrapped + * @see nsDataHashtable, nsClassHashtable + */ +template +class nsInterfaceHashtable : + public nsBaseHashtable< KeyClass, nsCOMPtr , Interface* > +{ +public: + typedef typename KeyClass::KeyType KeyType; + typedef Interface* UserDataType; + + /** + * @copydoc nsBaseHashtable::Get + * @param pData This is an XPCOM getter, so pData is already_addrefed. + * If the key doesn't exist, pData will be set to nsnull. + */ + PRBool Get(KeyType aKey, UserDataType* pData) const; + + /** + * Gets a weak reference to the hashtable entry. + * @param aFound If not nsnull, will be set to PR_TRUE if the entry is found, + * to PR_FALSE otherwise. + * @return The entry, or nsnull if not found. Do not release this pointer! + */ + Interface* GetWeak(KeyType aKey, PRBool* aFound = nsnull) const; +}; + +/** + * Thread-safe version of nsInterfaceHashtable + * @param KeyClass a wrapper-class for the hashtable key, see nsHashKeys.h + * for a complete specification. + * @param Interface the interface-type being wrapped + */ +template +class nsInterfaceHashtableMT : + public nsBaseHashtableMT< KeyClass, nsCOMPtr , Interface* > +{ +public: + typedef typename KeyClass::KeyType KeyType; + typedef Interface* UserDataType; + + /** + * @copydoc nsBaseHashtable::Get + * @param pData This is an XPCOM getter, so pData is already_addrefed. + * If the key doesn't exist, pData will be set to nsnull. + */ + PRBool Get(KeyType aKey, UserDataType* pData) const; + + // GetWeak does not make sense on a multi-threaded hashtable, where another + // thread may remove the entry (and hence release it) as soon as GetWeak + // returns +}; + + +// +// nsInterfaceHashtable definitions +// + +template +PRBool +nsInterfaceHashtable::Get + (KeyType aKey, UserDataType* pInterface) const +{ + typename nsBaseHashtable, Interface*>::EntryType* ent = + this->GetEntry(aKey); + + if (ent) + { + if (pInterface) + { + *pInterface = ent->mData; + + NS_IF_ADDREF(*pInterface); + } + + return PR_TRUE; + } + + // if the key doesn't exist, set *pInterface to null + // so that it is a valid XPCOM getter + if (pInterface) + *pInterface = nsnull; + + return PR_FALSE; +} + +template +Interface* +nsInterfaceHashtable::GetWeak + (KeyType aKey, PRBool* aFound) const +{ + typename nsBaseHashtable, Interface*>::EntryType* ent = + this->GetEntry(aKey); + + if (ent) + { + if (aFound) + *aFound = PR_TRUE; + + return ent->mData; + } + + // Key does not exist, return nsnull and set aFound to PR_FALSE + if (aFound) + *aFound = PR_FALSE; + return nsnull; +} + +// +// nsInterfaceHashtableMT definitions +// + +template +PRBool +nsInterfaceHashtableMT::Get + (KeyType aKey, UserDataType* pInterface) const +{ + PR_Lock(this->mLock); + + typename nsBaseHashtableMT, Interface*>::EntryType* ent = + this->GetEntry(aKey); + + if (ent) + { + if (pInterface) + { + *pInterface = ent->mData; + + NS_IF_ADDREF(*pInterface); + } + + PR_Unlock(this->mLock); + + return PR_TRUE; + } + + // if the key doesn't exist, set *pInterface to null + // so that it is a valid XPCOM getter + if (pInterface) + *pInterface = nsnull; + + PR_Unlock(this->mLock); + + return PR_FALSE; +} + +#endif // nsInterfaceHashtable_h__ diff --git a/src/libs/xpcom18a4/xpcom/ds/nsManifestLineReader.h b/src/libs/xpcom18a4/xpcom/ds/nsManifestLineReader.h new file mode 100644 index 00000000..761c28c8 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsManifestLineReader.h @@ -0,0 +1,121 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +#ifndef nsManifestLineReader_h__ +#define nsManifestLineReader_h__ + +#include "nspr.h" +#include "nsDebug.h" + +class nsManifestLineReader +{ +public: + nsManifestLineReader() : mBase(nsnull) {} + ~nsManifestLineReader() {} + + void Init(char* base, PRUint32 flen) + { + mBase = mCur = mNext = base; + mLength = 0; + mLimit = base + flen; + } + + PRBool NextLine() + { + if(mNext >= mLimit) + return PR_FALSE; + + mCur = mNext; + mLength = 0; + + while(mNext < mLimit) + { + if(IsEOL(*mNext)) + { + *mNext = '\0'; + for(++mNext; mNext < mLimit; ++mNext) + if(!IsEOL(*mNext)) + break; + return PR_TRUE; + } + ++mNext; + ++mLength; + } + return PR_FALSE; + } + + int ParseLine(char** chunks, int* lengths, int maxChunks) + { + NS_ASSERTION(mCur && maxChunks && chunks, "bad call to ParseLine"); + int found = 0; + chunks[found++] = mCur; + + if(found < maxChunks) + { + char *lastchunk = mCur; + int *lastlength = lengths; + for(char* cur = mCur; *cur; cur++) + { + if(*cur == ',') + { + *cur = 0; + // always fill in the previous chunk's length + *lastlength++ = cur - lastchunk; + chunks[found++] = lastchunk = cur+1; + if(found == maxChunks) + break; + } + } + // crazy pointer math - calculate the length of the final chunk + *lastlength = (mCur + mLength) - lastchunk; + } + return found; + } + + char* LinePtr() {return mCur;} + PRUint32 LineLength() {return mLength;} + + PRBool IsEOL(char c) {return c == '\n' || c == '\r';} +private: + char* mCur; + PRUint32 mLength; + char* mNext; + char* mBase; + char* mLimit; +}; + +#endif diff --git a/src/libs/xpcom18a4/xpcom/ds/nsObserverList.cpp b/src/libs/xpcom18a4/xpcom/ds/nsObserverList.cpp new file mode 100644 index 00000000..51fb04b5 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsObserverList.cpp @@ -0,0 +1,211 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +#define NS_WEAK_OBSERVERS + +#include "pratom.h" +#include "nsString.h" +#include "nsAutoLock.h" +#include "nsCOMPtr.h" +#include "nsIWeakReference.h" +#include "nsEnumeratorUtils.h" +#include "nsObserverList.h" + +nsObserverList::nsObserverList() +{ + MOZ_COUNT_CTOR(nsObserverList); + mLock = PR_NewLock(); +} + +nsObserverList::~nsObserverList(void) +{ + MOZ_COUNT_DTOR(nsObserverList); + PR_DestroyLock(mLock); +} + +nsresult +nsObserverList::AddObserver(nsIObserver* anObserver, PRBool ownsWeak) +{ + nsresult rv; + PRBool inserted; + + NS_ENSURE_ARG(anObserver); + + nsAutoLock lock(mLock); + + if (!mObserverList) { + rv = NS_NewISupportsArray(getter_AddRefs(mObserverList)); + if (NS_FAILED(rv)) return rv; + } + +#ifdef NS_WEAK_OBSERVERS + nsCOMPtr observerRef; + if (ownsWeak) { + nsCOMPtr weakRefFactory = do_QueryInterface(anObserver); + NS_ASSERTION(weakRefFactory, "AddObserver: trying weak object that doesnt support nsIWeakReference"); + if ( weakRefFactory ) + observerRef = getter_AddRefs(NS_STATIC_CAST(nsISupports*, NS_GetWeakReference(weakRefFactory))); + } else { +#if DEBUG_dougt_xxx + // if you are hitting this assertion, contact dougt@netscape.com. There may be a ownership problem caused by his checkin to freeze nsIObserver + nsCOMPtr weakRefFactory = do_QueryInterface(anObserver); + NS_ASSERTION(!weakRefFactory, "Your object supports weak references, but is being added with a strong reference"); +#endif + observerRef = anObserver; + } + if (!observerRef) + return NS_ERROR_FAILURE; + + inserted = mObserverList->AppendElement(observerRef); +#else + if (*anObserver) + inserted = mObserverList->AppendElement(*anObserver); +#endif + return inserted ? NS_OK : NS_ERROR_FAILURE; +} + +nsresult +nsObserverList::RemoveObserver(nsIObserver* anObserver) +{ + PRBool removed = PR_FALSE; + + NS_ENSURE_ARG(anObserver); + + nsAutoLock lock(mLock); + + if (!mObserverList) + return NS_ERROR_FAILURE; + +#ifdef NS_WEAK_OBSERVERS + nsCOMPtr weakRefFactory = do_QueryInterface(anObserver); + nsCOMPtr observerRef; + if (weakRefFactory) { + observerRef = getter_AddRefs(NS_STATIC_CAST(nsISupports*, NS_GetWeakReference(weakRefFactory))); + if (observerRef) + removed = mObserverList->RemoveElement(observerRef); + if (!removed) + observerRef = anObserver; + } else + observerRef = anObserver; + + if (!removed && observerRef) + removed = mObserverList->RemoveElement(observerRef); +#else + if (*anObserver) + removed = mObserverList->RemoveElement(*anObserver); +#endif + return removed ? NS_OK : NS_ERROR_FAILURE; +} + +nsresult +nsObserverList::GetObserverList(nsISimpleEnumerator** anEnumerator) +{ + nsAutoLock lock(mLock); + + ObserverListEnumerator * enumerator= new ObserverListEnumerator(mObserverList); + *anEnumerator = enumerator; + if (!enumerator) + return NS_ERROR_OUT_OF_MEMORY; + + NS_ADDREF(enumerator); + return NS_OK; +} + + +ObserverListEnumerator::ObserverListEnumerator(nsISupportsArray* aValueArray) + : mValueArray(aValueArray), mIndex(0) +{ + if (mValueArray) { + NS_ADDREF(mValueArray); + PRUint32 total; + mValueArray->Count(&total); + mIndex = PRInt32(total); + } +} + +ObserverListEnumerator::~ObserverListEnumerator(void) +{ + NS_IF_RELEASE(mValueArray); +} + +NS_IMPL_ISUPPORTS1(ObserverListEnumerator, nsISimpleEnumerator) + +NS_IMETHODIMP +ObserverListEnumerator::HasMoreElements(PRBool* aResult) +{ + NS_PRECONDITION(aResult != 0, "null ptr"); + if (! aResult) + return NS_ERROR_NULL_POINTER; + + if (!mValueArray) { + *aResult = PR_FALSE; + return NS_OK; + } + + *aResult = (mIndex > 0); + return NS_OK; +} + +NS_IMETHODIMP +ObserverListEnumerator::GetNext(nsISupports** aResult) +{ + NS_PRECONDITION(aResult != 0, "null ptr"); + if (! aResult) + return NS_ERROR_NULL_POINTER; + + if (!mValueArray) { + *aResult = nsnull; + return NS_OK; + } + + if (mIndex <= 0 ) + return NS_ERROR_UNEXPECTED; + + mValueArray->GetElementAt(--mIndex, aResult); + if (*aResult) { + nsCOMPtr weakRefFactory = do_QueryInterface(*aResult); + if ( weakRefFactory ) { + nsCOMPtr weakref = do_QueryReferent(weakRefFactory); + NS_RELEASE(*aResult); + NS_IF_ADDREF(*aResult = weakref); + + return NS_OK; + } + } + + return NS_OK; +} diff --git a/src/libs/xpcom18a4/xpcom/ds/nsObserverList.h b/src/libs/xpcom18a4/xpcom/ds/nsObserverList.h new file mode 100644 index 00000000..521ce1c8 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsObserverList.h @@ -0,0 +1,79 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +#ifndef nsObserverList_h___ +#define nsObserverList_h___ + +#include "nsIObserver.h" +#include "nsIEnumerator.h" +#include "nsISupportsArray.h" +#include "nsISimpleEnumerator.h" + +class ObserverListEnumerator : public nsISimpleEnumerator +{ +public: + // nsISupports interface + NS_DECL_ISUPPORTS + NS_DECL_NSISIMPLEENUMERATOR + + ObserverListEnumerator(nsISupportsArray* aValueArray); + +private: + ~ObserverListEnumerator(void); + +protected: + nsISupportsArray* mValueArray; + PRInt32 mIndex; +}; + +class nsObserverList +{ +public: + nsObserverList(); + ~nsObserverList(); + + nsresult AddObserver(nsIObserver* anObserver, PRBool ownsWeak); + nsresult RemoveObserver(nsIObserver* anObserver); + nsresult GetObserverList(nsISimpleEnumerator** anEnumerator); + +protected: + PRLock* mLock; + nsCOMPtr mObserverList; +}; + + +#endif /* nsObserverList_h___ */ diff --git a/src/libs/xpcom18a4/xpcom/ds/nsObserverService.cpp b/src/libs/xpcom18a4/xpcom/ds/nsObserverService.cpp new file mode 100644 index 00000000..f4c66bcc --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsObserverService.cpp @@ -0,0 +1,227 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Pierre Phaneuf + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "prlog.h" +#include "prlock.h" +#include "nsIFactory.h" +#include "nsIServiceManager.h" +#include "nsIComponentManager.h" +#include "nsIObserverService.h" +#include "nsObserverService.h" +#include "nsObserverList.h" +#include "nsHashtable.h" +#include "nsIWeakReference.h" + +#define NS_WEAK_OBSERVERS + + + +#if defined(PR_LOGGING) +// Log module for nsObserverService logging... +// +// To enable logging (see prlog.h for full details): +// +// set NSPR_LOG_MODULES=ObserverService:5 +// set NSPR_LOG_FILE=nspr.log +// +// this enables PR_LOG_DEBUG level information and places all output in +// the file nspr.log +PRLogModuleInfo* observerServiceLog = nsnull; +#endif /* PR_LOGGING */ + +//////////////////////////////////////////////////////////////////////////////// +// nsObserverService Implementation + + +NS_IMPL_THREADSAFE_ISUPPORTS1(nsObserverService, nsIObserverService) + +nsObserverService::nsObserverService() + : mObserverTopicTable(nsnull) +{ +} + +nsObserverService::~nsObserverService(void) +{ + if(mObserverTopicTable) + delete mObserverTopicTable; +} + +NS_METHOD +nsObserverService::Create(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr) +{ +#if defined(PR_LOGGING) + if (!observerServiceLog) + observerServiceLog = PR_NewLogModule("ObserverService"); +#endif + + nsresult rv; + nsObserverService* os = new nsObserverService(); + if (os == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + NS_ADDREF(os); + rv = os->QueryInterface(aIID, aInstancePtr); + NS_RELEASE(os); + return rv; +} + +static PRBool PR_CALLBACK +ReleaseObserverList(nsHashKey *aKey, void *aData, void* closure) +{ + nsObserverList* observerList = NS_STATIC_CAST(nsObserverList*, aData); + delete(observerList); + return PR_TRUE; +} + +nsresult nsObserverService::GetObserverList(const char* aTopic, nsObserverList** anObserverList) +{ + if (anObserverList == nsnull) + return NS_ERROR_NULL_POINTER; + + if(mObserverTopicTable == nsnull) + { + mObserverTopicTable = new nsObjectHashtable(nsnull, + nsnull, // should never be cloned + ReleaseObserverList, + nsnull, + 256, + PR_TRUE); + if (mObserverTopicTable == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + } + + + nsCStringKey key(aTopic); + + nsObserverList *topicObservers; + topicObservers = (nsObserverList *) mObserverTopicTable->Get(&key); + + if (topicObservers) + { + *anObserverList = topicObservers; + return NS_OK; + } + + topicObservers = new nsObserverList(); + if (!topicObservers) + return NS_ERROR_OUT_OF_MEMORY; + + *anObserverList = topicObservers; + mObserverTopicTable->Put(&key, topicObservers); + + return NS_OK; +} + +NS_IMETHODIMP nsObserverService::AddObserver(nsIObserver* anObserver, const char* aTopic, PRBool ownsWeak) +{ + nsObserverList* anObserverList; + nsresult rv; + + if (anObserver == nsnull || aTopic == nsnull) + return NS_ERROR_NULL_POINTER; + + rv = GetObserverList(aTopic, &anObserverList); + if (NS_FAILED(rv)) return rv; + + return anObserverList->AddObserver(anObserver, ownsWeak); +} + +NS_IMETHODIMP nsObserverService::RemoveObserver(nsIObserver* anObserver, const char* aTopic) +{ + nsObserverList* anObserverList; + nsresult rv; + + if (anObserver == nsnull || aTopic == nsnull) + return NS_ERROR_NULL_POINTER; + + rv = GetObserverList(aTopic, &anObserverList); + if (NS_FAILED(rv)) return rv; + + return anObserverList->RemoveObserver(anObserver); +} + +NS_IMETHODIMP nsObserverService::EnumerateObservers(const char* aTopic, nsISimpleEnumerator** anEnumerator) +{ + nsObserverList* anObserverList; + nsresult rv; + + if (anEnumerator == nsnull || aTopic == nsnull) + return NS_ERROR_NULL_POINTER; + + rv = GetObserverList(aTopic, &anObserverList); + if (NS_FAILED(rv)) return rv; + + return anObserverList->GetObserverList(anEnumerator); +} + +// Enumerate observers of aTopic and call Observe on each. +NS_IMETHODIMP nsObserverService::NotifyObservers( nsISupports *aSubject, + const char *aTopic, + const PRUnichar *someData ) { + nsresult rv = NS_OK; + nsCOMPtr observers; + nsCOMPtr observerRef; + + rv = EnumerateObservers( aTopic, getter_AddRefs(observers) ); + if ( NS_FAILED( rv ) ) + return rv; + PRBool loop = PR_TRUE; + while( NS_SUCCEEDED(observers->HasMoreElements(&loop)) && loop) + { + observers->GetNext(getter_AddRefs(observerRef)); + nsCOMPtr observer = do_QueryInterface(observerRef); + if ( observer ) + observer->Observe( aSubject, aTopic, someData ); +#ifdef NS_WEAK_OBSERVERS + else + { // check for weak reference. + nsCOMPtr weakRef = do_QueryInterface(observerRef); + if ( weakRef ) + weakRef->QueryReferent(NS_GET_IID(nsIObserver), getter_AddRefs(observer)); + + if ( observer ) + observer->Observe( aSubject, aTopic, someData ); + + PR_LOG(observerServiceLog, PR_LOG_DEBUG, ("Notification - %s\n", aTopic ? aTopic : "undefined")); + + } +#endif + } + return NS_OK; +} +//////////////////////////////////////////////////////////////////////////////// + diff --git a/src/libs/xpcom18a4/xpcom/ds/nsObserverService.h b/src/libs/xpcom18a4/xpcom/ds/nsObserverService.h new file mode 100644 index 00000000..0a08f2ae --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsObserverService.h @@ -0,0 +1,75 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +#ifndef nsObserverService_h___ +#define nsObserverService_h___ + +#include "nsIObserverService.h" + +#define NS_OBSERVERSERVICE_CONTRACTID "@mozilla.org/observer-service;1" +#define NS_OBSERVERSERVICE_CLASSNAME "Observer Service" + +class nsObserverList; +class nsObjectHashtable; + +// {D07F5195-E3D1-11d2-8ACD-00105A1B8860} +#define NS_OBSERVERSERVICE_CID \ + { 0xd07f5195, 0xe3d1, 0x11d2, { 0x8a, 0xcd, 0x0, 0x10, 0x5a, 0x1b, 0x88, 0x60 } } + +class nsObserverService : public nsIObserverService { +public: + NS_DEFINE_STATIC_CID_ACCESSOR( NS_OBSERVERSERVICE_CID ) + + nsObserverService(); + + NS_DECL_ISUPPORTS + NS_DECL_NSIOBSERVERSERVICE + + static NS_METHOD + Create(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr); + +private: + ~nsObserverService(void); + + nsObjectHashtable* mObserverTopicTable; + + nsresult GetObserverList(const char* aTopic, nsObserverList** anObserverList); + + +}; + +#endif /* nsObserverService_h___ */ diff --git a/src/libs/xpcom18a4/xpcom/ds/nsPersistentProperties.cpp b/src/libs/xpcom18a4/xpcom/ds/nsPersistentProperties.cpp new file mode 100644 index 00000000..0bdef252 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsPersistentProperties.cpp @@ -0,0 +1,492 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Pierre Phaneuf + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsID.h" +#include "nsCRT.h" +#include "nsReadableUtils.h" +#include "nsIInputStream.h" +#include "nsIUnicharInputStream.h" +#include "pratom.h" +#include "nsEnumeratorUtils.h" +#include "nsReadableUtils.h" +#include "nsPrintfCString.h" + +#define PL_ARENA_CONST_ALIGN_MASK 3 +#include "nsPersistentProperties.h" +#include "nsIProperties.h" +#include "nsProperties.h" + +struct PropertyTableEntry : public PLDHashEntryHdr +{ + // both of these are arena-allocated + const char *mKey; + const PRUnichar *mValue; +}; + +static PRUnichar* +ArenaStrdup(const nsAFlatString& aString, PLArenaPool* aArena) +{ + void *mem; + // add one to include the null terminator + PRInt32 len = (aString.Length()+1) * sizeof(PRUnichar); + PL_ARENA_ALLOCATE(mem, aArena, len); + NS_ASSERTION(mem, "Couldn't allocate space!\n"); + if (mem) { + memcpy(mem, aString.get(), len); + } + return NS_STATIC_CAST(PRUnichar*, mem); +} + +static char* +ArenaStrdup(const nsAFlatCString& aString, PLArenaPool* aArena) +{ + void *mem; + // add one to include the null terminator + PRInt32 len = (aString.Length()+1) * sizeof(char); + PL_ARENA_ALLOCATE(mem, aArena, len); + NS_ASSERTION(mem, "Couldn't allocate space!\n"); + if (mem) + memcpy(mem, aString.get(), len); + return NS_STATIC_CAST(char*, mem); +} + +static const struct PLDHashTableOps property_HashTableOps = { + PL_DHashAllocTable, + PL_DHashFreeTable, + PL_DHashGetKeyStub, + PL_DHashStringKey, + PL_DHashMatchStringKey, + PL_DHashMoveEntryStub, + PL_DHashClearEntryStub, + PL_DHashFinalizeStub, + nsnull, +}; + +nsPersistentProperties::nsPersistentProperties() +: mIn(nsnull) +{ + mSubclass = NS_STATIC_CAST(nsIPersistentProperties*, this); + mTable.ops = nsnull; + PL_INIT_ARENA_POOL(&mArena, "PersistentPropertyArena", 2048); +} + +nsPersistentProperties::~nsPersistentProperties() +{ + PL_FinishArenaPool(&mArena); + if (mTable.ops) + PL_DHashTableFinish(&mTable); +} + +nsresult +nsPersistentProperties::Init() +{ + if (!PL_DHashTableInit(&mTable, &property_HashTableOps, nsnull, + sizeof(PropertyTableEntry), 20)) { + mTable.ops = nsnull; + return NS_ERROR_OUT_OF_MEMORY; + } + return NS_OK; +} + +NS_METHOD +nsPersistentProperties::Create(nsISupports *aOuter, REFNSIID aIID, void **aResult) +{ + if (aOuter) + return NS_ERROR_NO_AGGREGATION; + nsPersistentProperties* props = new nsPersistentProperties(); + if (props == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + + NS_ADDREF(props); + nsresult rv = props->Init(); + if (NS_SUCCEEDED(rv)) + rv = props->QueryInterface(aIID, aResult); + + NS_RELEASE(props); + return rv; +} + +NS_IMPL_THREADSAFE_ISUPPORTS2(nsPersistentProperties, nsIPersistentProperties, nsIProperties) + +NS_IMETHODIMP +nsPersistentProperties::Load(nsIInputStream *aIn) +{ + PRInt32 c; + nsresult ret = NS_NewUTF8ConverterStream(&mIn, aIn, 0); + + if (ret != NS_OK) { + NS_WARNING("NS_NewUTF8ConverterStream failed"); + return NS_ERROR_FAILURE; + } + c = Read(); + while (1) { + c = SkipWhiteSpace(c); + if (c < 0) { + break; + } + else if ((c == '#') || (c == '!')) { + c = SkipLine(c); + continue; + } + else { + nsAutoString key; + while ((c >= 0) && (c != '=') && (c != ':')) { + key.Append(PRUnichar(c)); + c = Read(); + } + if (c < 0) { + break; + } + static const char trimThese[] = " \t"; + key.Trim(trimThese, PR_FALSE, PR_TRUE); + c = Read(); + nsAutoString value; + PRUint32 state = 0; + PRUnichar uchar = 0; + while ((c >= 0) && (c != '\r') && (c != '\n')) { + switch(state) { + case 0: + if (c == '\\') { + c = Read(); + switch(c) { + case '\r': + case '\n': + // Only skip first EOL characters and then next line's + // whitespace characters. Skipping all EOL characters + // and all upcoming whitespace is too agressive. + if (c == '\r') + c = Read(); + if (c == '\n') + c = Read(); + while (c == ' ' || c == '\t') + c = Read(); + continue; + case 'u': + case 'U': + state = 1; + uchar=0; + break; + case 't': + value.Append(PRUnichar('\t')); + break; + case 'n': + value.Append(PRUnichar('\n')); + break; + case 'r': + value.Append(PRUnichar('\r')); + break; + default: + value.Append((PRUnichar) c); + } // switch(c) + } else { + value.Append((PRUnichar) c); + } + c = Read(); + break; + case 1: + case 2: + case 3: + case 4: + if (('0' <= c) && (c <= '9')) { + uchar = (uchar << 4) | (c - '0'); + state++; + c = Read(); + } else if (('a' <= c) && (c <= 'f')) { + uchar = (uchar << 4) | (c - 'a' + 0x0a); + state++; + c = Read(); + } else if (('A' <= c) && (c <= 'F')) { + uchar = (uchar << 4) | (c - 'A' + 0x0a); + state++; + c = Read(); + } else { + value.Append((PRUnichar) uchar); + state = 0; + } + break; + case 5: + value.Append((PRUnichar) uchar); + state = 0; + } + } + if (state != 0) { + value.Append((PRUnichar) uchar); + state = 0; + } + + value.Trim(trimThese, PR_TRUE, PR_TRUE); + nsAutoString oldValue; + mSubclass->SetStringProperty(NS_ConvertUCS2toUTF8(key), value, oldValue); + } + } + mIn->Close(); + NS_RELEASE(mIn); + + return NS_OK; +} + +NS_IMETHODIMP +nsPersistentProperties::SetStringProperty(const nsACString& aKey, + const nsAString& aNewValue, + nsAString& aOldValue) +{ +#if 0 + cout << "will add " << aKey.get() << "=" << + NS_LossyConvertUCS2ToASCII(aNewValue).get() << endl; +#endif + + const nsAFlatCString& flatKey = PromiseFlatCString(aKey); + PropertyTableEntry *entry = + NS_STATIC_CAST(PropertyTableEntry*, + PL_DHashTableOperate(&mTable, flatKey.get(), PL_DHASH_ADD)); + + if (entry->mKey) { + aOldValue = entry->mValue; + NS_WARNING(nsPrintfCString(aKey.Length() + 30, + "the property %s already exists\n", + flatKey.get()).get()); + } + + entry->mKey = ArenaStrdup(flatKey, &mArena); + entry->mValue = ArenaStrdup(PromiseFlatString(aNewValue), &mArena); + + return NS_OK; +} + +NS_IMETHODIMP +nsPersistentProperties::Save(nsIOutputStream* aOut, const nsACString& aHeader) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsPersistentProperties::Subclass(nsIPersistentProperties* aSubclass) +{ + if (aSubclass) { + mSubclass = aSubclass; + } + + return NS_OK; +} + +NS_IMETHODIMP +nsPersistentProperties::GetStringProperty(const nsACString& aKey, + nsAString& aValue) +{ + const nsAFlatCString& flatKey = PromiseFlatCString(aKey); + + PropertyTableEntry *entry = + NS_STATIC_CAST(PropertyTableEntry*, + PL_DHashTableOperate(&mTable, flatKey.get(), PL_DHASH_LOOKUP)); + + if (PL_DHASH_ENTRY_IS_FREE(entry)) + return NS_ERROR_FAILURE; + + aValue = entry->mValue; + return NS_OK; +} + +PR_STATIC_CALLBACK(PLDHashOperator) +AddElemToArray(PLDHashTable* table, PLDHashEntryHdr *hdr, + PRUint32 i, void *arg) +{ + nsISupportsArray *propArray = (nsISupportsArray *) arg; + PropertyTableEntry* entry = + NS_STATIC_CAST(PropertyTableEntry*, hdr); + + nsPropertyElement *element = + new nsPropertyElement(nsDependentCString(entry->mKey), + nsDependentString(entry->mValue)); + if (!element) + return PL_DHASH_STOP; + + NS_ADDREF(element); + propArray->InsertElementAt(element, i); + + return PL_DHASH_NEXT; +} + + +NS_IMETHODIMP +nsPersistentProperties::Enumerate(nsISimpleEnumerator** aResult) +{ + nsCOMPtr iterator; + + nsISupportsArray* propArray; + nsresult rv = NS_NewISupportsArray(&propArray); + if (rv != NS_OK) + return rv; + + // Step through hash entries populating a transient array + PRUint32 n = + PL_DHashTableEnumerate(&mTable, AddElemToArray, (void *)propArray); + if (n < mTable.entryCount) + return NS_ERROR_OUT_OF_MEMORY; + + return NS_NewArrayEnumerator(aResult, propArray); +} + + +PRInt32 +nsPersistentProperties::Read() +{ + PRUnichar c; + PRUint32 nRead; + nsresult ret; + + ret = mIn->Read(&c, 1, &nRead); + if (ret == NS_OK && nRead == 1) { + return c; + } + + return -1; +} + +#define IS_WHITE_SPACE(c) \ + (((c) == ' ') || ((c) == '\t') || ((c) == '\r') || ((c) == '\n')) + +PRInt32 +nsPersistentProperties::SkipWhiteSpace(PRInt32 c) +{ + while (IS_WHITE_SPACE(c)) { + c = Read(); + } + + return c; +} + +PRInt32 +nsPersistentProperties::SkipLine(PRInt32 c) +{ + while ((c >= 0) && (c != '\r') && (c != '\n')) { + c = Read(); + } + if (c == '\r') { + c = Read(); + } + if (c == '\n') { + c = Read(); + } + + return c; +} + +//////////////////////////////////////////////////////////////////////////////// +// XXX Some day we'll unify the nsIPersistentProperties interface with +// nsIProperties, but until now... + +NS_IMETHODIMP +nsPersistentProperties::Get(const char* prop, const nsIID & uuid, void* *result) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsPersistentProperties::Set(const char* prop, nsISupports* value) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} +NS_IMETHODIMP +nsPersistentProperties::Undefine(const char* prop) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsPersistentProperties::Has(const char* prop, PRBool *result) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsPersistentProperties::GetKeys(PRUint32 *count, char ***keys) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +//////////////////////////////////////////////////////////////////////////////// +// PropertyElement +//////////////////////////////////////////////////////////////////////////////// + + +NS_METHOD +nsPropertyElement::Create(nsISupports *aOuter, REFNSIID aIID, void **aResult) +{ + if (aOuter) + return NS_ERROR_NO_AGGREGATION; + nsPropertyElement* propElem = new nsPropertyElement(); + if (propElem == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + NS_ADDREF(propElem); + nsresult rv = propElem->QueryInterface(aIID, aResult); + NS_RELEASE(propElem); + return rv; +} + +NS_IMPL_ISUPPORTS1(nsPropertyElement, nsIPropertyElement) + +NS_IMETHODIMP +nsPropertyElement::GetKey(nsACString& aReturnKey) +{ + aReturnKey = mKey; + return NS_OK; +} + +NS_IMETHODIMP +nsPropertyElement::GetValue(nsAString& aReturnValue) +{ + aReturnValue = mValue; + return NS_OK; +} + +NS_IMETHODIMP +nsPropertyElement::SetKey(const nsACString& aKey) +{ + mKey = aKey; + return NS_OK; +} + +NS_IMETHODIMP +nsPropertyElement::SetValue(const nsAString& aValue) +{ + mValue = aValue; + return NS_OK; +} + +//////////////////////////////////////////////////////////////////////////////// + diff --git a/src/libs/xpcom18a4/xpcom/ds/nsPersistentProperties.h b/src/libs/xpcom18a4/xpcom/ds/nsPersistentProperties.h new file mode 100644 index 00000000..020ff82d --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsPersistentProperties.h @@ -0,0 +1,106 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +#ifndef nsPersistentProperties_h___ +#define nsPersistentProperties_h___ + +#include "nsIPersistentProperties2.h" +#include "pldhash.h" +#include "plarena.h" +#include "nsString.h" + +class nsIUnicharInputStream; + + +class nsPersistentProperties : public nsIPersistentProperties +{ +public: + nsPersistentProperties(); + nsresult Init(); + + NS_DECL_ISUPPORTS + NS_DECL_NSIPROPERTIES + NS_DECL_NSIPERSISTENTPROPERTIES + + + // nsPersistentProperties methods: + PRInt32 Read(); + PRInt32 SkipLine(PRInt32 c); + PRInt32 SkipWhiteSpace(PRInt32 c); + + static NS_METHOD + Create(nsISupports *aOuter, REFNSIID aIID, void **aResult); + +private: + ~nsPersistentProperties(); + +protected: + nsIUnicharInputStream* mIn; + PRUint32 mBufferPos; + PRUint32 mBufferLength; + nsIPersistentProperties* mSubclass; + struct PLDHashTable mTable; + PLArenaPool mArena; +}; + +class nsPropertyElement : public nsIPropertyElement +{ +public: + nsPropertyElement() + { + } + + nsPropertyElement(const nsACString& aKey, const nsAString& aValue) + : mKey(aKey), mValue(aValue) + { + } + + NS_DECL_ISUPPORTS + NS_DECL_NSIPROPERTYELEMENT + + static NS_METHOD + Create(nsISupports *aOuter, REFNSIID aIID, void **aResult); + +private: + ~nsPropertyElement() {} + +protected: + nsCString mKey; + nsString mValue; +}; + +#endif /* nsPersistentProperties_h___ */ diff --git a/src/libs/xpcom18a4/xpcom/ds/nsProperties.cpp b/src/libs/xpcom18a4/xpcom/ds/nsProperties.cpp new file mode 100644 index 00000000..8276e4a5 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsProperties.cpp @@ -0,0 +1,150 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsProperties.h" + +//#include + +//////////////////////////////////////////////////////////////////////////////// + +nsProperties::nsProperties(nsISupports* outer) +{ + NS_INIT_AGGREGATED(outer); +} + +NS_METHOD +nsProperties::Create(nsISupports *outer, REFNSIID aIID, void **aResult) +{ + NS_ENSURE_ARG_POINTER(aResult); + NS_ENSURE_PROPER_AGGREGATION(outer, aIID); + + nsProperties* props = new nsProperties(outer); + if (props == NULL) + return NS_ERROR_OUT_OF_MEMORY; + + nsresult rv = props->AggregatedQueryInterface(aIID, aResult); + if (NS_FAILED(rv)) + delete props; + return rv; +} + +PRBool PR_CALLBACK +nsProperties::ReleaseValues(nsHashKey* key, void* data, void* closure) +{ + nsISupports* value = (nsISupports*)data; + NS_IF_RELEASE(value); + return PR_TRUE; +} + +nsProperties::~nsProperties() +{ + Enumerate(ReleaseValues); +} + +NS_IMPL_AGGREGATED(nsProperties) + +NS_METHOD +nsProperties::AggregatedQueryInterface(const nsIID& aIID, void** aInstancePtr) +{ + NS_ENSURE_ARG_POINTER(aInstancePtr); + + if (aIID.Equals(NS_GET_IID(nsISupports))) + *aInstancePtr = GetInner(); + else if (aIID.Equals(NS_GET_IID(nsIProperties))) + *aInstancePtr = NS_STATIC_CAST(nsIProperties*, this); + else { + *aInstancePtr = nsnull; + return NS_NOINTERFACE; + } + + NS_ADDREF((nsISupports*)*aInstancePtr); + return NS_OK; +} + +NS_IMETHODIMP +nsProperties::Get(const char* prop, const nsIID & uuid, void* *result) +{ + nsresult rv; + nsCStringKey key(prop); + nsISupports* value = (nsISupports*)nsHashtable::Get(&key); + if (value) { + rv = value->QueryInterface(uuid, result); + } + else { + rv = NS_ERROR_FAILURE; + } + return rv; +} + +NS_IMETHODIMP +nsProperties::Set(const char* prop, nsISupports* value) +{ + nsCStringKey key(prop); + + nsISupports* prevValue = (nsISupports*)Put(&key, value); + NS_IF_RELEASE(prevValue); + NS_IF_ADDREF(value); + return NS_OK; +} + +NS_IMETHODIMP +nsProperties::Undefine(const char* prop) +{ + nsCStringKey key(prop); + if (!Exists(&key)) + return NS_ERROR_FAILURE; + + nsISupports* prevValue = (nsISupports*)Remove(&key); + NS_IF_RELEASE(prevValue); + return NS_OK; +} + +NS_IMETHODIMP +nsProperties::Has(const char* prop, PRBool *result) +{ + nsCStringKey key(prop); + *result = nsHashtable::Exists(&key); + return NS_OK; +} + +NS_IMETHODIMP +nsProperties::GetKeys(PRUint32 *count, char ***keys) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +//////////////////////////////////////////////////////////////////////////////// diff --git a/src/libs/xpcom18a4/xpcom/ds/nsProperties.h b/src/libs/xpcom18a4/xpcom/ds/nsProperties.h new file mode 100644 index 00000000..ee225547 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsProperties.h @@ -0,0 +1,72 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +#ifndef nsProperties_h___ +#define nsProperties_h___ + +#include "nsIProperties.h" +#include "nsHashtable.h" +#include "nsAgg.h" + +#define NS_PROPERTIES_CID \ +{ /* 4de2bc90-b1bf-11d3-93b6-00104ba0fd40 */ \ + 0x4de2bc90, \ + 0xb1bf, \ + 0x11d3, \ + {0x93, 0xb6, 0x00, 0x10, 0x4b, 0xa0, 0xfd, 0x40} \ +} + +class nsIUnicharInputStream; + +class nsProperties : public nsIProperties, public nsHashtable { +public: + + NS_DECL_AGGREGATED + NS_DECL_NSIPROPERTIES + + nsProperties(nsISupports* outer); + + static NS_METHOD + Create(nsISupports *aOuter, REFNSIID aIID, void **aResult); + + static PRBool PR_CALLBACK ReleaseValues(nsHashKey* key, void* data, void* closure); + +private: + ~nsProperties(); +}; + +#endif /* nsProperties_h___ */ diff --git a/src/libs/xpcom18a4/xpcom/ds/nsQuickSort.cpp b/src/libs/xpcom18a4/xpcom/ds/nsQuickSort.cpp new file mode 100644 index 00000000..0a71d25d --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsQuickSort.cpp @@ -0,0 +1,182 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ + +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* We need this because Solaris' version of qsort is broken and + * causes array bounds reads. + */ + +#include +#include "prtypes.h" +#include "nsQuickSort.h" + +PR_BEGIN_EXTERN_C + +#if !defined(DEBUG) && (defined(__cplusplus) || defined(__gcc)) +# ifndef INLINE +# define INLINE inline +# endif +#else +# define INLINE +#endif + +typedef int cmp_t(const void *, const void *, void *); +static INLINE char *med3(char *, char *, char *, cmp_t *, void *); +static INLINE void swapfunc(char *, char *, int, int); + +/* + * Qsort routine from Bentley & McIlroy's "Engineering a Sort Function". + */ +#define swapcode(TYPE, parmi, parmj, n) { \ + long i = (n) / sizeof (TYPE); \ + register TYPE *pi = (TYPE *) (parmi); \ + register TYPE *pj = (TYPE *) (parmj); \ + do { \ + register TYPE t = *pi; \ + *pi++ = *pj; \ + *pj++ = t; \ + } while (--i > 0); \ +} + +#define SWAPINIT(a, es) swaptype = ((char *)a - (char *)0) % sizeof(long) || \ + es % sizeof(long) ? 2 : es == sizeof(long)? 0 : 1; + +static INLINE void +swapfunc(char *a, char *b, int n, int swaptype) +{ + if(swaptype <= 1) + swapcode(long, a, b, n) + else + swapcode(char, a, b, n) +} + +#define swap(a, b) \ + if (swaptype == 0) { \ + long t = *(long *)(a); \ + *(long *)(a) = *(long *)(b); \ + *(long *)(b) = t; \ + } else \ + swapfunc((char *)a, (char*)b, (int)es, swaptype) + +#define vecswap(a, b, n) if ((n) > 0) swapfunc((char *)a, (char *)b, (int)n, swaptype) + +static INLINE char * +med3(char *a, char *b, char *c, cmp_t* cmp, void *data) +{ + return cmp(a, b, data) < 0 ? + (cmp(b, c, data) < 0 ? b : (cmp(a, c, data) < 0 ? c : a )) + :(cmp(b, c, data) > 0 ? b : (cmp(a, c, data) < 0 ? a : c )); +} + +void NS_QuickSort ( + void *a, + unsigned int n, + unsigned int es, + cmp_t *cmp, + void *data + ) +{ + char *pa, *pb, *pc, *pd, *pl, *pm, *pn; + int d, r, swaptype, swap_cnt; + +loop: SWAPINIT(a, es); + swap_cnt = 0; + if (n < 7) { + for (pm = (char *)a + es; pm < (char *)a + n * es; pm += es) + for (pl = pm; pl > (char *)a && cmp(pl - es, pl, data) > 0; + pl -= es) + swap(pl, pl - es); + return; + } + pm = (char *)a + (n / 2) * es; + if (n > 7) { + pl = (char *)a; + pn = (char *)a + (n - 1) * es; + if (n > 40) { + d = (n / 8) * es; + pl = med3(pl, pl + d, pl + 2 * d, cmp, data); + pm = med3(pm - d, pm, pm + d, cmp, data); + pn = med3(pn - 2 * d, pn - d, pn, cmp, data); + } + pm = med3(pl, pm, pn, cmp, data); + } + swap(a, pm); + pa = pb = (char *)a + es; + + pc = pd = (char *)a + (n - 1) * es; + for (;;) { + while (pb <= pc && (r = cmp(pb, a, data)) <= 0) { + if (r == 0) { + swap_cnt = 1; + swap(pa, pb); + pa += es; + } + pb += es; + } + while (pb <= pc && (r = cmp(pc, a, data)) >= 0) { + if (r == 0) { + swap_cnt = 1; + swap(pc, pd); + pd -= es; + } + pc -= es; + } + if (pb > pc) + break; + swap(pb, pc); + swap_cnt = 1; + pb += es; + pc -= es; + } + if (swap_cnt == 0) { /* Switch to insertion sort */ + for (pm = (char *)a + es; pm < (char *)a + n * es; pm += es) + for (pl = pm; pl > (char *)a && cmp(pl - es, pl, data) > 0; + pl -= es) + swap(pl, pl - es); + return; + } + + pn = (char *)a + n * es; + r = PR_MIN(pa - (char *)a, pb - pa); + vecswap(a, pb - r, r); + r = PR_MIN(pd - pc, (int)(pn - pd - es)); + vecswap(pb, pn - r, r); + if ((r = pb - pa) > (int)es) + NS_QuickSort(a, r / es, es, cmp, data); + if ((r = pd - pc) > (int)es) { + /* Iterate rather than recurse to save stack space */ + a = pn - r; + n = r / es; + goto loop; + } +/* NS_QuickSort(pn - r, r / es, es, cmp, data);*/ +} + +PR_END_EXTERN_C diff --git a/src/libs/xpcom18a4/xpcom/ds/nsQuickSort.h b/src/libs/xpcom18a4/xpcom/ds/nsQuickSort.h new file mode 100644 index 00000000..0dd16385 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsQuickSort.h @@ -0,0 +1,72 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + + +/* We need this because Solaris' version of qsort is broken and + * causes array bounds reads. + */ + +#ifndef nsQuickSort_h___ +#define nsQuickSort_h___ + +#include "prtypes.h" + +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +#define NS_QuickSort VBoxNsxpNS_QuickSort +#endif /* VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + +PR_BEGIN_EXTERN_C + +/** + * Parameters: + * 1. the array to sort + * 2. the number of elements in the array + * 3. the size of each array element + * 4. comparison function taking two elements and parameter #5 and + * returning an integer: + * + less than zero if the first element should be before the second + * + 0 if the order of the elements does not matter + * + greater than zero if the second element should be before the first + * 5. extra data to pass to comparison function + */ +PR_EXTERN(void) NS_QuickSort(void *, unsigned int, unsigned int, + int (*)(const void *, const void *, void *), + void *); + +PR_END_EXTERN_C + +#endif /* nsQuickSort_h___ */ diff --git a/src/libs/xpcom18a4/xpcom/ds/nsRecyclingAllocator.cpp b/src/libs/xpcom18a4/xpcom/ds/nsRecyclingAllocator.cpp new file mode 100644 index 00000000..241f795c --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsRecyclingAllocator.cpp @@ -0,0 +1,443 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2001, 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Suresh Duddi + * + * 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 ***** */ + +/* + * nsRecyclingAllocator + */ + +#include +#include +#include +#include "nsRecyclingAllocator.h" +#include "nsIMemory.h" +#include "nsAutoLock.h" +#include "prprf.h" +#include "nsITimer.h" +#ifdef VBOX_USE_IPRT_IN_XPCOM +# include +#endif + +#define NS_SEC_TO_MS(s) ((s) * 1000) + +void +nsRecyclingAllocator::nsRecycleTimerCallback(nsITimer *aTimer, void *aClosure) +{ + nsRecyclingAllocator *obj = (nsRecyclingAllocator *) aClosure; + if (!obj->mTouched) + { + if (obj->mFreeList) + obj->FreeUnusedBuckets(); + + // If we are holding no more memory, there is no need for the timer. + // We will revive the timer on the next allocation. + // XXX Unfortunately there is no way to Cancel and restart the same timer. + // XXX So we pretty much kill it and create a new one later. + if (!obj->mFreeList && obj->mRecycleTimer) + { + obj->mRecycleTimer->Cancel(); + NS_RELEASE(obj->mRecycleTimer); + } + } + else + { + // Clear touched so the next time the timer fires we can test whether + // the allocator was used or not. + obj->Untouch(); + } +} + + +nsRecyclingAllocator::nsRecyclingAllocator(PRUint32 nbucket, PRUint32 recycleAfter, const char *id) : + mMaxBlocks(nbucket), mBlocks(nsnull), mFreeList(nsnull), mNotUsedList(nsnull), + mRecycleTimer(nsnull), mRecycleAfter(recycleAfter), mTouched(0), mId(id) +#ifdef DEBUG + ,mNAllocated(0) +#endif +{ + NS_ASSERTION(mMaxBlocks <= NS_MAX_BLOCKS, "Too many blocks. This will affect the allocator's performance."); + + mLock = PR_NewLock(); + NS_ASSERTION(mLock, "Recycling allocator cannot get lock"); + + Init(nbucket, recycleAfter, id); +} + +nsresult +nsRecyclingAllocator::Init(PRUint32 nbucket, PRUint32 recycleAfter, const char *id) +{ + nsAutoLock lock(mLock); + + // Free all memory held, if any + while(mFreeList) + { +#ifdef VBOX_USE_IPRT_IN_XPCOM + RTMemFree(mFreeList->block); +#else + free(mFreeList->block); +#endif + mFreeList = mFreeList->next; + } + mFreeList = nsnull; + + if (mBlocks) + delete [] mBlocks; + + // Reinitialize everything + mMaxBlocks = nbucket; + if (nbucket) + { + // Create memory for our bookkeeping + mBlocks = new BlockStoreNode[mMaxBlocks]; + if (!mBlocks) + return NS_ERROR_OUT_OF_MEMORY; + // Link them together + mNotUsedList = mBlocks; + for (PRUint32 i=0; i < mMaxBlocks-1; i++) + mBlocks[i].next = &(mBlocks[i+1]); + } + + mRecycleAfter = recycleAfter; + mId = id; + + return NS_OK; +} + +nsRecyclingAllocator::~nsRecyclingAllocator() +{ + // Cancel and destroy recycle timer + if (mRecycleTimer) + { + mRecycleTimer->Cancel(); + NS_RELEASE(mRecycleTimer); + } + + // Free all memory held, if any + while(mFreeList) + { +#ifdef VBOX_USE_IPRT_IN_XPCOM + RTMemFree(mFreeList->block); +#else + free(mFreeList->block); +#endif + mFreeList = mFreeList->next; + } + mFreeList = nsnull; + + if (mBlocks) + delete [] mBlocks; + + if (mLock) + { + PR_DestroyLock(mLock); + mLock = nsnull; + } +} + +// Allocation and free routines +void* +nsRecyclingAllocator::Malloc(PRSize bytes, PRBool zeroit) +{ + // Mark that we are using. This will prevent any + // timer based release of unused memory. + Touch(); + + Block* freeBlock = FindFreeBlock(bytes); + if (freeBlock) + { + void *data = DATA(freeBlock); + + if (zeroit) + memset(data, 0, bytes); + return data; + } + + // We need to do an allocation + // Add 4 bytes to what we allocate to hold the bucket index + PRSize allocBytes = bytes + NS_ALLOCATOR_OVERHEAD_BYTES; + + // We dont have that memory already. Allocate. +#ifdef VBOX_USE_IPRT_IN_XPCOM + Block *ptr = (Block *) (zeroit ? RTMemAllocZ(allocBytes) : RTMemAlloc(allocBytes)); +#else + Block *ptr = (Block *) (zeroit ? calloc(1, allocBytes) : malloc(allocBytes)); +#endif + + // Deal with no memory situation + if (!ptr) + return ptr; + + // This is the first allocation we are holding. + // Setup timer for releasing memory + // If this fails, then we wont have a timer to release unused + // memory. We can live with that. Also, the next allocation + // will try again to set the timer. + if (mRecycleAfter && !mRecycleTimer) + { + // known only to stuff in xpcom. + extern nsresult NS_NewTimer(nsITimer* *aResult, nsTimerCallbackFunc aCallback, void *aClosure, + PRUint32 aDelay, PRUint32 aType); + + (void) NS_NewTimer(&mRecycleTimer, nsRecycleTimerCallback, this, + NS_SEC_TO_MS(mRecycleAfter), + nsITimer::TYPE_REPEATING_SLACK); + NS_ASSERTION(mRecycleTimer, "nsRecyclingAllocator: Creating timer failed.\n"); + } + +#ifdef DEBUG + mNAllocated++; +#endif + + // Store size and return data portion + ptr->bytes = bytes; + return DATA(ptr); +} + +void +nsRecyclingAllocator::Free(void *ptr) +{ + // Mark that we are using the allocator. This will prevent any + // timer based release of unused memory. + Touch(); + + Block* block = DATA_TO_BLOCK(ptr); + + if (!AddToFreeList(block)) + { + // We are holding more than max. Failover to free +#ifdef DEBUG_dp + char buf[1024]; + // Warn if we are failing over to malloc/free and not storing it + // This says we have a misdesigned memory pool. The intent was + // once the pool was full, we would never fail over to calloc. + PR_snprintf(buf, sizeof(buf), "nsRecyclingAllocator(%s) FAILOVER 0x%p (%d) - %d allocations, %d max\n", + mId, (char *)ptr, block->bytes, mNAllocated, mMaxBlocks); + NS_WARNING(buf); + mNAllocated--; +#endif +#ifdef VBOX_USE_IPRT_IN_XPCOM + RTMemFree(block); +#else + free(block); +#endif + } +} + +/* FreeUnusedBuckets + * + * Frees any bucket memory that isn't in use + */ + +void +nsRecyclingAllocator::FreeUnusedBuckets() +{ +#ifdef DEBUG_dp + printf("DEBUG: nsRecyclingAllocator(%s) FreeUnusedBuckets: ", mId); +#endif + nsAutoLock lock(mLock); + + // We will run through the freelist and free all blocks + BlockStoreNode* node = mFreeList; + while (node) + { + // Free the allocated block +#ifdef VBOX_USE_IPRT_IN_XPCOM + RTMemFree(node->block); +#else + free(node->block); +#endif + +#ifdef DEBUG_dp + printf("%d ", node->bytes); +#endif + // Clear Node + node->block = nsnull; + node->bytes = 0; + node = node->next; + } + + // remake the lists + mNotUsedList = mBlocks; + for (PRUint32 i=0; i < mMaxBlocks-1; i++) + mBlocks[i].next = &(mBlocks[i+1]); + mBlocks[mMaxBlocks-1].next = nsnull; + mFreeList = nsnull; + +#ifdef DEBUG + mNAllocated = 0; +#endif +#ifdef DEBUG_dp + printf("\n"); +#endif +} + +nsRecyclingAllocator::Block* +nsRecyclingAllocator::FindFreeBlock(PRSize bytes) +{ + // We dont enter lock for this check. This is intentional. + // Here is my logic: we are checking if (!mFreeList). Doing this check + // without locking can lead to unpredictable results. YES. But the effect + // of the unpredictedness are ok. here is why: + // + // a) if the check returned NULL when there is stuff in freelist + // We would just end up reallocating. + // + // b) if the check returned nonNULL when our freelist is empty + // This is the more likely and dangerous case. The code for + // FindFreeBlock() will enter lock, while (null) and return null. + // + // The reason why I chose to not enter lock for this check was that when + // the allocator is full, we dont want to impose any more overhead than + // we already are for failing over to malloc/free. + + if (!mFreeList) + return NULL; + + Block *block = nsnull; + + nsAutoLock lock(mLock); + BlockStoreNode* freeNode = mFreeList; + BlockStoreNode** prevp = &mFreeList; + + while (freeNode) + { + if (freeNode->bytes >= bytes) + { + // Found the best fit free block + block = freeNode->block; + + // Clear the free node + freeNode->block = nsnull; + freeNode->bytes = 0; + + // Remove free node from free list + *prevp = freeNode->next; + + // Add removed BlockStoreNode to not used list + freeNode->next = mNotUsedList; + mNotUsedList = freeNode; + + break; + } + + prevp = &(freeNode->next); + freeNode = freeNode->next; + } + return block; +} + +PRInt32 +nsRecyclingAllocator::AddToFreeList(Block* block) +{ + nsAutoLock lock(mLock); + + if (!mNotUsedList) + return PR_FALSE; + + // Pick a node from the not used list + BlockStoreNode *node = mNotUsedList; + mNotUsedList = mNotUsedList->next; + + // Initialize the node + node->bytes = block->bytes; + node->block = block; + + // Find the right spot in the sorted list. + BlockStoreNode* freeNode = mFreeList; + BlockStoreNode** prevp = &mFreeList; + while (freeNode) + { + if (freeNode->bytes >= block->bytes) + break; + prevp = &(freeNode->next); + freeNode = freeNode->next; + } + + // Needs to be inserted between *prevp and freeNode + *prevp = node; + node->next = freeNode; + + return PR_TRUE; +} + + +// ---------------------------------------------------------------------- +// Wrapping the recyling allocator with nsIMemory +// ---------------------------------------------------------------------- + +// nsIMemory methods +NS_IMPL_THREADSAFE_ISUPPORTS2(nsRecyclingAllocatorImpl, nsIMemory, nsIRecyclingAllocator) + +NS_IMETHODIMP_(void *) +nsRecyclingAllocatorImpl::Alloc(PRSize size) +{ + return nsRecyclingAllocatorImpl::Malloc(size, PR_FALSE); +} + +NS_IMETHODIMP_(void *) +nsRecyclingAllocatorImpl::Realloc(void *ptr, PRSize size) +{ + // XXX Not yet implemented + return NULL; +} + +NS_IMETHODIMP_(void) +nsRecyclingAllocatorImpl::Free(void *ptr) +{ + nsRecyclingAllocator::Free(ptr); +} + +NS_IMETHODIMP +nsRecyclingAllocatorImpl::Init(size_t nbuckets, size_t recycleAfter, const char *id) +{ + return nsRecyclingAllocator::Init((PRUint32) nbuckets, (PRUint32) recycleAfter, id); +} + +NS_IMETHODIMP +nsRecyclingAllocatorImpl::HeapMinimize(PRBool immediate) +{ + // XXX Not yet implemented + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsRecyclingAllocatorImpl::IsLowMemory(PRBool *lowmemoryb_ptr) +{ + // XXX Not yet implemented + return NS_ERROR_NOT_IMPLEMENTED; +} + diff --git a/src/libs/xpcom18a4/xpcom/ds/nsRecyclingAllocator.h b/src/libs/xpcom18a4/xpcom/ds/nsRecyclingAllocator.h new file mode 100644 index 00000000..4266b1b8 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsRecyclingAllocator.h @@ -0,0 +1,208 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2001, 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Suresh Duddi + * + * 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 ***** */ + +/* + * nsRecyclingAllocator + * + * This allocator is useful when we cycle through a small set of allocations + * repeatedly with minimal overlap. For eg. something we do for every gif + * file read (or) buffers required for decompression of every file from jar. + * + * What this does is keeps around the first set of memory allocated and + * reuses it subsequently. If all buckets are full, this falls back to + * malloc/free + * + * Uses a timer to release all memory allocated if not used for more than + * 10 secs automatically. + * + * Also there is a 4 byte maintenance overhead on every allocation. + * + * This allocator is thread safe. + * + * CAVEATS: As the number of buckets increases, this allocators performance + * will drop. As a general guideline, dont use this for more + * than NS_MAX_BLOCKS + */ + +#ifndef nsRecyclingAllocator_h__ +#define nsRecyclingAllocator_h__ + +#include "nscore.h" +#include "pratom.h" +#include "prlock.h" +#include "nsIRecyclingAllocator.h" +#include "nsIGenericFactory.h" + +#define NS_DEFAULT_RECYCLE_TIMEOUT 10 // secs +#define NS_MAX_BLOCKS 24 +#define NS_ALLOCATOR_OVERHEAD_BYTES (sizeof(Block)) // bytes + +class nsITimer; +class nsIMemory; + +class NS_COM nsRecyclingAllocator { + protected: + struct Block { + PRSize bytes; + }; + + // Make |BlockStoreNode| a |friend| so it can access |Block|. + struct BlockStoreNode; + friend struct BlockStoreNode; + + struct BlockStoreNode { + BlockStoreNode() : bytes(0), block(nsnull), next(nsnull) {}; + PRSize bytes; + Block *block; + BlockStoreNode *next; + }; + +#define DATA(block) ((void *)(((char *)block) + NS_ALLOCATOR_OVERHEAD_BYTES)) +#define DATA_TO_BLOCK(data) ((Block *)((char *)(data) - NS_ALLOCATOR_OVERHEAD_BYTES)) + + // mMaxBlocks: Maximum number of blocks that can be allocated + PRUint32 mMaxBlocks; + + // mBlocks: + // All blocks used or not. + BlockStoreNode *mBlocks; + + // mFreeList + // A linked list of free blocks sorted by increasing order of size + BlockStoreNode* mFreeList; + + // mNotUsedList + // A linked list of BlockStoreNodes that are not used to store + // any block information. When we add blocks into mFreeList, we + // take BlockStoreNode from here. + BlockStoreNode* mNotUsedList; + + // mLock: Thread safety of mFreeList and mNotUsedList + PRLock *mLock; + + // Timer for freeing unused memory + nsITimer *mRecycleTimer; + + // mRecycleAfter: + // Allocator should be untouched for this many seconds for freeing + // unused Blocks. + PRUint32 mRecycleAfter; + + // mTouched: + // says if the allocator touched any bucket. If allocator didn't touch + // any bucket over a time time interval, timer will call FreeUnusedBuckets() + PRInt32 mTouched; + + // mId: + // a string for identifying the user of nsRecyclingAllocator + // User mainly for debug prints + const char *mId; + +#ifdef DEBUG + // mNAllocated: Number of blocks allocated + PRInt32 mNAllocated; +#endif + + public: + + // nbucket : number of buckets to hold. Capped at NS_MAX_BUCKET + // recycleAfter : Try recycling allocated buckets after this many seconds + // id : a string used to identify debug prints. Will not be released. + nsRecyclingAllocator(PRUint32 nbucket = 0, PRUint32 recycleAfter = NS_DEFAULT_RECYCLE_TIMEOUT, + const char *id = NULL); + ~nsRecyclingAllocator(); + + nsresult Init(PRUint32 nbucket, PRUint32 recycleAfter, const char *id); + + // Allocation and free routines + void* Malloc(PRSize size, PRBool zeroit = PR_FALSE); + void Free(void *ptr); + + void* Calloc(PRUint32 items, PRSize size) + { + return Malloc(items * size, PR_TRUE); + } + + // FreeUnusedBuckets - Frees any bucket memory that isn't in use + void FreeUnusedBuckets(); + + protected: + + // Timer callback to trigger unused memory + static void nsRecycleTimerCallback(nsITimer *aTimer, void *aClosure); + + // Freelist management + // FindFreeBlock: return a free block that can hold bytes (best fit) + Block* FindFreeBlock(PRSize bytes); + // AddToFreeList: adds block into our freelist for future retrieval. + // Returns PR_TRUE is addition was successful. PR_FALSE otherewise. + PRBool AddToFreeList(Block* block); + + // Touch will mark that someone used this allocator + // Timer based release will free unused memory only if allocator + // was not touched for mRecycleAfter seconds. + void Touch() { + if (!mTouched) + PR_AtomicSet(&mTouched, 1); + } + void Untouch() { + PR_AtomicSet(&mTouched, 0); + } + + friend void nsRecycleTimerCallback(nsITimer *aTimer, void *aClosure); +}; + +// ---------------------------------------------------------------------- +// Wrapping the recyling allocator with nsIMemory +// ---------------------------------------------------------------------- + +// Wrapping the nsRecyclingAllocator with nsIMemory +class nsRecyclingAllocatorImpl : public nsRecyclingAllocator, public nsIRecyclingAllocator { +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIMEMORY + NS_DECL_NSIRECYCLINGALLOCATOR + + nsRecyclingAllocatorImpl() + { + } + +private: + ~nsRecyclingAllocatorImpl() {} +}; +#endif // nsRecyclingAllocator_h__ diff --git a/src/libs/xpcom18a4/xpcom/ds/nsRefPtrHashtable.h b/src/libs/xpcom18a4/xpcom/ds/nsRefPtrHashtable.h new file mode 100644 index 00000000..69cdbe88 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsRefPtrHashtable.h @@ -0,0 +1,197 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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 C++ hashtable templates. + * + * The Initial Developer of the Original Code is + * Benjamin Smedberg. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Neil Rashbrook + * + * 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 ***** */ + +#ifndef nsRefPtrHashtable_h__ +#define nsRefPtrHashtable_h__ + +#include "nsBaseHashtable.h" +#include "nsHashKeys.h" +#include "nsAutoPtr.h" + +/** + * templated hashtable class maps keys to reference pointers. + * See nsBaseHashtable for complete declaration. + * @param KeyClass a wrapper-class for the hashtable key, see nsHashKeys.h + * for a complete specification. + * @param RefPtr the reference-type being wrapped + * @see nsDataHashtable, nsClassHashtable + */ +template +class nsRefPtrHashtable : + public nsBaseHashtable< KeyClass, nsRefPtr , RefPtr* > +{ +public: + typedef typename KeyClass::KeyType KeyType; + typedef RefPtr* UserDataType; + + /** + * @copydoc nsBaseHashtable::Get + * @param pData This is an XPCOM getter, so pData is already_addrefed. + * If the key doesn't exist, pData will be set to nsnull. + */ + PRBool Get(KeyType aKey, UserDataType* pData) const; + + /** + * Gets a weak reference to the hashtable entry. + * @param aFound If not nsnull, will be set to PR_TRUE if the entry is found, + * to PR_FALSE otherwise. + * @return The entry, or nsnull if not found. Do not release this pointer! + */ + RefPtr* GetWeak(KeyType aKey, PRBool* aFound = nsnull) const; +}; + +/** + * Thread-safe version of nsRefPtrHashtable + * @param KeyClass a wrapper-class for the hashtable key, see nsHashKeys.h + * for a complete specification. + * @param RefPtr the reference-type being wrapped + */ +template +class nsRefPtrHashtableMT : + public nsBaseHashtableMT< KeyClass, nsRefPtr , RefPtr* > +{ +public: + typedef typename KeyClass::KeyType KeyType; + typedef RefPtr* UserDataType; + + /** + * @copydoc nsBaseHashtable::Get + * @param pData This is an XPCOM getter, so pData is already_addrefed. + * If the key doesn't exist, pData will be set to nsnull. + */ + PRBool Get(KeyType aKey, UserDataType* pData) const; + + // GetWeak does not make sense on a multi-threaded hashtable, where another + // thread may remove the entry (and hence release it) as soon as GetWeak + // returns +}; + + +// +// nsRefPtrHashtable definitions +// + +template +PRBool +nsRefPtrHashtable::Get + (KeyType aKey, UserDataType* pRefPtr) const +{ + typename nsBaseHashtable, RefPtr*>::EntryType* ent = + this->GetEntry(aKey); + + if (ent) + { + if (pRefPtr) + { + *pRefPtr = ent->mData; + + NS_IF_ADDREF(*pRefPtr); + } + + return PR_TRUE; + } + + // if the key doesn't exist, set *pRefPtr to null + // so that it is a valid XPCOM getter + if (pRefPtr) + *pRefPtr = nsnull; + + return PR_FALSE; +} + +template +RefPtr* +nsRefPtrHashtable::GetWeak + (KeyType aKey, PRBool* aFound) const +{ + typename nsBaseHashtable, RefPtr*>::EntryType* ent = + this->GetEntry(aKey); + + if (ent) + { + if (aFound) + *aFound = PR_TRUE; + + return ent->mData; + } + + // Key does not exist, return nsnull and set aFound to PR_FALSE + if (aFound) + *aFound = PR_FALSE; + return nsnull; +} + +// +// nsRefPtrHashtableMT definitions +// + +template +PRBool +nsRefPtrHashtableMT::Get + (KeyType aKey, UserDataType* pRefPtr) const +{ + PR_Lock(this->mLock); + + typename nsBaseHashtableMT, RefPtr*>::EntryType* ent = + this->GetEntry(aKey); + + if (ent) + { + if (pRefPtr) + { + *pRefPtr = ent->mData; + + NS_IF_ADDREF(*pRefPtr); + } + + PR_Unlock(this->mLock); + + return PR_TRUE; + } + + // if the key doesn't exist, set *pRefPtr to null + // so that it is a valid XPCOM getter + if (pRefPtr) + *pRefPtr = nsnull; + + PR_Unlock(this->mLock); + + return PR_FALSE; +} + +#endif // nsRefPtrHashtable_h__ diff --git a/src/libs/xpcom18a4/xpcom/ds/nsStaticAtom.h b/src/libs/xpcom18a4/xpcom/ds/nsStaticAtom.h new file mode 100644 index 00000000..6c76d016 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsStaticAtom.h @@ -0,0 +1,65 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 Static Atom classes. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corp. + * Portions created by the Initial Developer are Copyright (C) 2003 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Alec Flett + * + * 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 ***** */ + +#ifndef nsStaticAtom_h__ +#define nsStaticAtom_h__ + +#include "nsIAtom.h" + +// see http://www.mozilla.org/projects/xpcom/atoms.html to use this stuff + +// class for declaring a static list of atoms, for use with gperf +// Keep this VERY simple +// mString: the value of the atom - the policy is that this is only +// ASCII, in order to avoid unnecessary conversions if +// someone asks for this in unicode +// mAtom: a convienience pointer - if you want to store the value of +// the atom created by this structure somewhere, put its +// address here +struct nsStaticAtom { + const char* mString; + nsIAtom ** mAtom; +}; + + +// register your lookup function with the atom table. Your function +// will be called when at atom is not found in the main atom table. +NS_COM nsresult +NS_RegisterStaticAtoms(const nsStaticAtom*, PRUint32 aAtomCount); + +#endif diff --git a/src/libs/xpcom18a4/xpcom/ds/nsStaticNameTable.cpp b/src/libs/xpcom18a4/xpcom/ds/nsStaticNameTable.cpp new file mode 100644 index 00000000..35489c6a --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsStaticNameTable.cpp @@ -0,0 +1,217 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** 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 Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Class to manage lookup of static names in a table. */ + +#include "nsCRT.h" + +#include "nscore.h" +#include "nsString.h" +#include "nsReadableUtils.h" + +#define PL_ARENA_CONST_ALIGN_MASK 3 +#include "nsStaticNameTable.h" + +struct NameTableEntry : public PLDHashEntryHdr +{ + // no ownership here! + const char *mKey; + PRInt32 mIndex; +}; + +PR_STATIC_CALLBACK(PRBool) +matchNameKeysCaseInsensitive(PLDHashTable*, const PLDHashEntryHdr* aHdr, + const void* key) +{ + const NameTableEntry* entry = + NS_STATIC_CAST(const NameTableEntry *, aHdr); + const char *keyValue = NS_STATIC_CAST(const char*, key); + + return (nsCRT::strcasecmp(entry->mKey, keyValue)==0); +} + +/* + * caseInsensitiveHashKey is just like PL_DHashStringKey except it + * uses (*s & ~0x20) instead of simply *s. This means that "aFOO" and + * "afoo" and "aFoo" will all hash to the same thing. It also means + * that some strings that aren't case-insensensitively equal will hash + * to the same value, but it's just a hash function so it doesn't + * matter. + */ +PR_STATIC_CALLBACK(PLDHashNumber) +caseInsensitiveStringHashKey(PLDHashTable *table, const void *key) +{ + PLDHashNumber h = 0; + for (const unsigned char* s = + NS_STATIC_CAST(const unsigned char*, key); + *s != '\0'; + s++) + h = (h >> (PL_DHASH_BITS - 4)) ^ (h << 4) ^ (*s & ~0x20); + return h; +} + +static const struct PLDHashTableOps nametable_CaseInsensitiveHashTableOps = { + PL_DHashAllocTable, + PL_DHashFreeTable, + PL_DHashGetKeyStub, + caseInsensitiveStringHashKey, + matchNameKeysCaseInsensitive, + PL_DHashMoveEntryStub, + PL_DHashClearEntryStub, + PL_DHashFinalizeStub, + nsnull, +}; + +nsStaticCaseInsensitiveNameTable::nsStaticCaseInsensitiveNameTable() + : mNameArray(nsnull), mNullStr("") +{ + MOZ_COUNT_CTOR(nsStaticCaseInsensitiveNameTable); + mNameTable.ops = nsnull; +} + +nsStaticCaseInsensitiveNameTable::~nsStaticCaseInsensitiveNameTable() +{ + if (mNameArray) { + // manually call the destructor on placement-new'ed objects + for (PRUint32 index = 0; index < mNameTable.entryCount; index++) { + mNameArray[index].~nsDependentCString(); + } + nsMemory::Free((void*)mNameArray); + } + if (mNameTable.ops) + PL_DHashTableFinish(&mNameTable); + MOZ_COUNT_DTOR(nsStaticCaseInsensitiveNameTable); +} + +PRBool +nsStaticCaseInsensitiveNameTable::Init(const char* const aNames[], PRInt32 Count) +{ + NS_ASSERTION(!mNameArray, "double Init"); + NS_ASSERTION(!mNameTable.ops, "double Init"); + NS_ASSERTION(aNames, "null name table"); + NS_ASSERTION(Count, "0 count"); + + mNameArray = (nsDependentCString*) + nsMemory::Alloc(Count * sizeof(nsDependentCString)); + if (!mNameArray) + return PR_FALSE; + + if (!PL_DHashTableInit(&mNameTable, + &nametable_CaseInsensitiveHashTableOps, + nsnull, sizeof(NameTableEntry), Count)) { + mNameTable.ops = nsnull; + return PR_FALSE; + } + + for (PRInt32 index = 0; index < Count; ++index) { + const char* raw = aNames[index]; +#ifdef DEBUG + { + // verify invariants of contents + nsCAutoString temp1(raw); + nsDependentCString temp2(raw); + ToLowerCase(temp1); + NS_ASSERTION(temp1.Equals(temp2), "upper case char in table"); + NS_ASSERTION(nsCRT::IsAscii(raw), + "non-ascii string in table -- " + "case-insensitive matching won't work right"); + } +#endif + // use placement-new to initialize the string object + new (&mNameArray[index]) nsDependentCString(raw); + + NameTableEntry *entry = + NS_STATIC_CAST(NameTableEntry*, + PL_DHashTableOperate(&mNameTable, raw, PL_DHASH_ADD)); + + if (!entry) continue; + + NS_ASSERTION(entry->mKey == 0, "Entry already exists!"); + + entry->mKey = raw; // not owned! + entry->mIndex = index; + } + return PR_TRUE; +} + +inline PRInt32 +LookupFlatKeyword(const nsAFlatCString& aKeyword, + PLDHashTable& aTable) +{ + NameTableEntry *entry = + NS_STATIC_CAST(NameTableEntry*, + PL_DHashTableOperate(&aTable, aKeyword.get(), PL_DHASH_LOOKUP)); + + if (PL_DHASH_ENTRY_IS_FREE(entry)) + return nsStaticCaseInsensitiveNameTable::NOT_FOUND; + + return entry->mIndex; +} + +PRInt32 +nsStaticCaseInsensitiveNameTable::Lookup(const nsACString& aName) +{ + NS_ASSERTION(mNameArray, "not inited"); + NS_ASSERTION(mNameTable.ops, "not inited"); + + return LookupFlatKeyword(PromiseFlatCString(aName), mNameTable); +} + +PRInt32 +nsStaticCaseInsensitiveNameTable::Lookup(const nsAString& aName) +{ + NS_ASSERTION(mNameArray, "not inited"); + NS_ASSERTION(mNameTable.ops, "not inited"); + + nsCAutoString cstring; + cstring.AssignWithConversion(aName); + return LookupFlatKeyword(cstring, mNameTable); +} + +const nsAFlatCString& +nsStaticCaseInsensitiveNameTable::GetStringValue(PRInt32 index) +{ + NS_ASSERTION(mNameArray, "not inited"); + NS_ASSERTION(mNameTable.ops, "not inited"); + + if ((NOT_FOUND < index) && ((PRUint32)index < mNameTable.entryCount)) { + return mNameArray[index]; + } + return mNullStr; +} diff --git a/src/libs/xpcom18a4/xpcom/ds/nsStaticNameTable.h b/src/libs/xpcom18a4/xpcom/ds/nsStaticNameTable.h new file mode 100644 index 00000000..154a1c9d --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsStaticNameTable.h @@ -0,0 +1,81 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * ***** 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 Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Classes to manage lookup of static names in a table. */ + +#ifndef nsStaticNameTable_h___ +#define nsStaticNameTable_h___ + +#include "pldhash.h" +/* This class supports case insensitive lookup. + * + * It differs from atom tables: + * - It supports case insensitive lookup. + * - It has minimal footprint by not copying the string table. + * - It does no locking. + * - It returns zero based indexes and const nsCString& as required by its + * callers in the parser. + * - It is not an xpcom interface - meant for fast lookup in static tables. + * + * ***REQUIREMENTS*** + * - It *requires* that all entries in the table be lowercase only. + * - It *requires* that the table of strings be in memory that lives at least + * as long as this table object - typically a static string array. + */ + +class NS_COM nsStaticCaseInsensitiveNameTable +{ +public: + enum { NOT_FOUND = -1 }; + + PRBool Init(const char* const aNames[], PRInt32 Count); + PRInt32 Lookup(const nsACString& aName); + PRInt32 Lookup(const nsAString& aName); + const nsAFlatCString& GetStringValue(PRInt32 index); + + nsStaticCaseInsensitiveNameTable(); + ~nsStaticCaseInsensitiveNameTable(); + +private: + nsDependentCString* mNameArray; + PLDHashTable mNameTable; + nsDependentCString mNullStr; +}; + +#endif /* nsStaticNameTable_h___ */ diff --git a/src/libs/xpcom18a4/xpcom/ds/nsStringEnumerator.cpp b/src/libs/xpcom18a4/xpcom/ds/nsStringEnumerator.cpp new file mode 100644 index 00000000..8a10b18c --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsStringEnumerator.cpp @@ -0,0 +1,261 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 String Enumerator. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corp. + * Portions created by the Initial Developer are Copyright (C) 2003 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Alec Flett + * + * 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 "nsStringEnumerator.h" +#include "prtypes.h" +#include "nsCRT.h" +#include "nsString.h" +#include "nsReadableUtils.h" +#include "nsISimpleEnumerator.h" +#include "nsSupportsPrimitives.h" + +// +// nsStringEnumerator +// + +class nsStringEnumerator : public nsIStringEnumerator, + public nsIUTF8StringEnumerator, + public nsISimpleEnumerator +{ +public: + nsStringEnumerator(const nsStringArray* aArray, PRBool aOwnsArray) : + mArray(aArray), mIndex(0), mOwnsArray(aOwnsArray), mIsUnicode(PR_TRUE) + {} + + nsStringEnumerator(const nsCStringArray* aArray, PRBool aOwnsArray) : + mCArray(aArray), mIndex(0), mOwnsArray(aOwnsArray), mIsUnicode(PR_FALSE) + {} + + nsStringEnumerator(const nsStringArray* aArray, nsISupports* aOwner) : + mArray(aArray), mIndex(0), mOwner(aOwner), mOwnsArray(PR_FALSE), mIsUnicode(PR_TRUE) + {} + + nsStringEnumerator(const nsCStringArray* aArray, nsISupports* aOwner) : + mCArray(aArray), mIndex(0), mOwner(aOwner), mOwnsArray(PR_FALSE), mIsUnicode(PR_FALSE) + {} + + NS_DECL_ISUPPORTS + NS_DECL_NSIUTF8STRINGENUMERATOR + + // have to declare nsIStringEnumerator manually, because of + // overlapping method names + NS_IMETHOD GetNext(nsAString& aResult); + NS_DECL_NSISIMPLEENUMERATOR + +private: + ~nsStringEnumerator() { + if (mOwnsArray) { + // const-casting is safe here, because the NS_New* + // constructors make sure mOwnsArray is consistent with + // the constness of the objects + if (mIsUnicode) + delete NS_CONST_CAST(nsStringArray*,mArray); + else + delete NS_CONST_CAST(nsCStringArray*,mCArray); + } + } + + union { + const nsStringArray* mArray; + const nsCStringArray* mCArray; + }; + + inline PRUint32 Count() { + return mIsUnicode ? mArray->Count() : mCArray->Count(); + } + + PRUint32 mIndex; + + // the owner allows us to hold a strong reference to the object + // that owns the array. Having a non-null value in mOwner implies + // that mOwnsArray is PR_FALSE, because we rely on the real owner + // to release the array + nsCOMPtr mOwner; + PRPackedBool mOwnsArray; + PRPackedBool mIsUnicode; +}; + +NS_IMPL_ISUPPORTS3(nsStringEnumerator, + nsIStringEnumerator, + nsIUTF8StringEnumerator, + nsISimpleEnumerator) + +NS_IMETHODIMP +nsStringEnumerator::HasMore(PRBool* aResult) +{ + NS_ENSURE_ARG_POINTER(aResult); + *aResult = mIndex < Count(); + return NS_OK; +} + +NS_IMETHODIMP +nsStringEnumerator::HasMoreElements(PRBool* aResult) +{ + return HasMore(aResult); +} + +NS_IMETHODIMP +nsStringEnumerator::GetNext(nsISupports** aResult) +{ + if (mIsUnicode) { + nsSupportsStringImpl* stringImpl = new nsSupportsStringImpl(); + if (!stringImpl) return NS_ERROR_OUT_OF_MEMORY; + + stringImpl->SetData(*mArray->StringAt(mIndex++)); + *aResult = stringImpl; + } + else { + nsSupportsCStringImpl* cstringImpl = new nsSupportsCStringImpl(); + if (!cstringImpl) return NS_ERROR_OUT_OF_MEMORY; + + cstringImpl->SetData(*mCArray->CStringAt(mIndex++)); + *aResult = cstringImpl; + } + NS_ADDREF(*aResult); + return NS_OK; +} + +NS_IMETHODIMP +nsStringEnumerator::GetNext(nsAString& aResult) +{ + NS_ENSURE_TRUE(mIndex < Count(), NS_ERROR_UNEXPECTED); + + if (mIsUnicode) + aResult = *mArray->StringAt(mIndex++); + else + CopyUTF8toUTF16(*mCArray->CStringAt(mIndex++), aResult); + + return NS_OK; +} + +NS_IMETHODIMP +nsStringEnumerator::GetNext(nsACString& aResult) +{ + NS_ENSURE_TRUE(mIndex < Count(), NS_ERROR_UNEXPECTED); + + if (mIsUnicode) + CopyUTF16toUTF8(*mArray->StringAt(mIndex++), aResult); + else + aResult = *mCArray->CStringAt(mIndex++); + + return NS_OK; +} + +template +static inline nsresult +StringEnumeratorTail(T** aResult) +{ + if (!*aResult) + return NS_ERROR_OUT_OF_MEMORY; + NS_ADDREF(*aResult); + return NS_OK; +} + +// +// constructors +// + +NS_COM nsresult +NS_NewStringEnumerator(nsIStringEnumerator** aResult, + const nsStringArray* aArray, nsISupports* aOwner) +{ + NS_ENSURE_ARG_POINTER(aResult); + NS_ENSURE_ARG_POINTER(aArray); + + *aResult = new nsStringEnumerator(aArray, aOwner); + return StringEnumeratorTail(aResult); +} + + +NS_COM nsresult +NS_NewUTF8StringEnumerator(nsIUTF8StringEnumerator** aResult, + const nsCStringArray* aArray, nsISupports* aOwner) +{ + NS_ENSURE_ARG_POINTER(aResult); + NS_ENSURE_ARG_POINTER(aArray); + + *aResult = new nsStringEnumerator(aArray, aOwner); + return StringEnumeratorTail(aResult); +} + +NS_COM nsresult +NS_NewAdoptingStringEnumerator(nsIStringEnumerator** aResult, + nsStringArray* aArray) +{ + NS_ENSURE_ARG_POINTER(aResult); + NS_ENSURE_ARG_POINTER(aArray); + + *aResult = new nsStringEnumerator(aArray, PR_TRUE); + return StringEnumeratorTail(aResult); +} + +NS_COM nsresult +NS_NewAdoptingUTF8StringEnumerator(nsIUTF8StringEnumerator** aResult, + nsCStringArray* aArray) +{ + NS_ENSURE_ARG_POINTER(aResult); + NS_ENSURE_ARG_POINTER(aArray); + + *aResult = new nsStringEnumerator(aArray, PR_TRUE); + return StringEnumeratorTail(aResult); +} + +// const ones internally just forward to the non-const equivalents +NS_COM nsresult +NS_NewStringEnumerator(nsIStringEnumerator** aResult, + const nsStringArray* aArray) +{ + NS_ENSURE_ARG_POINTER(aResult); + NS_ENSURE_ARG_POINTER(aArray); + + *aResult = new nsStringEnumerator(aArray, PR_FALSE); + return StringEnumeratorTail(aResult); +} + +NS_COM nsresult +NS_NewUTF8StringEnumerator(nsIUTF8StringEnumerator** aResult, + const nsCStringArray* aArray) +{ + NS_ENSURE_ARG_POINTER(aResult); + NS_ENSURE_ARG_POINTER(aArray); + + *aResult = new nsStringEnumerator(aArray, PR_FALSE); + return StringEnumeratorTail(aResult); +} + diff --git a/src/libs/xpcom18a4/xpcom/ds/nsStringEnumerator.h b/src/libs/xpcom18a4/xpcom/ds/nsStringEnumerator.h new file mode 100644 index 00000000..d0080005 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsStringEnumerator.h @@ -0,0 +1,122 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 String Enumerator. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corp. + * Portions created by the Initial Developer are Copyright (C) 2003 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Alec Flett + * + * 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 "nsIStringEnumerator.h" +#include "nsVoidArray.h" + +// nsIStringEnumerator/nsIUTF8StringEnumerator implementations +// +// Currently all implementations support both interfaces. The +// constructors below provide the most common interface for the given +// type (i.e. nsIStringEnumerator for PRUnichar* strings, and so +// forth) but any resulting enumerators can be queried to the other +// type. Internally, the enumerators will hold onto the type that was +// passed in and do conversion if GetNext() for the other type of +// string is called. + +// There are a few different types of enumerators: + +// +// These enumerators hold a pointer to the array. Be careful +// because modifying the array may confuse the iterator, especially if +// you insert or remove elements in the middle of the array. +// + +// The non-adopting enumerator requires that the array sticks around +// at least as long as the enumerator does. These are for constant +// string arrays that the enumerator does not own, this could be used +// in VERY specialized cases such as when the provider KNOWS that the +// string enumerator will be consumed immediately, or will at least +// outlast the array. +// For example: +// +// nsCStringArray array; +// array.AppendCString("abc"); +// array.AppendCString("def"); +// NS_NewStringEnumerator(&enumerator, &array, PR_TRUE); +// +// // call some internal method which iterates the enumerator +// InternalMethod(enumerator); +// NS_RELEASE(enumerator); +// +NS_COM nsresult +NS_NewUTF8StringEnumerator(nsIUTF8StringEnumerator** aResult, + const nsCStringArray* aArray); + +NS_COM nsresult +NS_NewStringEnumerator(nsIStringEnumerator** aResult, + const nsStringArray* aArray); + +// Adopting string enumerators assume ownership of the array and will +// call |operator delete| on the array when the enumerator is destroyed +// this is useful when the provider creates an array soley for the +// purpose of creating the enumerator. +// For example: +// +// nsCStringArray* array = new nsCStringArray; +// array->AppendString("abcd"); +// NS_NewAdoptingStringEnumerator(&result, array); +NS_COM nsresult +NS_NewAdoptingStringEnumerator(nsIStringEnumerator** aResult, + nsStringArray* aArray); + +NS_COM nsresult +NS_NewAdoptingUTF8StringEnumerator(nsIUTF8StringEnumerator** aResult, + nsCStringArray* aArray); + + +// these versions take a refcounted "owner" which will be addreffed +// when the enumerator is created, and destroyed when the enumerator +// is released. This allows providers to give non-owning pointers to +// ns*StringArray member variables without worrying about lifetime +// issues +// For example: +// +// nsresult MyClass::Enumerate(nsIUTF8StringEnumerator** aResult) { +// mCategoryList->AppendString("abcd"); +// return NS_NewStringEnumerator(aResult, mCategoryList, this); +// } +// +NS_COM nsresult +NS_NewStringEnumerator(nsIStringEnumerator** aResult, + const nsStringArray* aArray, + nsISupports* aOwner); +NS_COM nsresult +NS_NewUTF8StringEnumerator(nsIUTF8StringEnumerator** aResult, + const nsCStringArray* aArray, + nsISupports* aOwner); diff --git a/src/libs/xpcom18a4/xpcom/ds/nsSupportsArray.cpp b/src/libs/xpcom18a4/xpcom/ds/nsSupportsArray.cpp new file mode 100644 index 00000000..e0774083 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsSupportsArray.cpp @@ -0,0 +1,684 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Scott Collins : |do_QueryElementAt| + * Pierre Phaneuf + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 +#include "prbit.h" +#include "nsSupportsArray.h" +#include "nsSupportsArrayEnumerator.h" +#include "nsAString.h" +#include "nsIObjectInputStream.h" +#include "nsIObjectOutputStream.h" + +#if DEBUG_SUPPORTSARRAY +#define MAXSUPPORTS 20 + +class SupportsStats { +public: + SupportsStats(); + ~SupportsStats(); + +}; + +static int sizesUsed; // number of the elements of the arrays used +static int sizesAlloced[MAXSUPPORTS]; // sizes of the allocations. sorted +static int NumberOfSize[MAXSUPPORTS]; // number of this allocation size (1 per array) +static int AllocedOfSize[MAXSUPPORTS]; // number of this allocation size (each size for array used) +static int GrowInPlace[MAXSUPPORTS]; + +// these are per-allocation +static int MaxElements[3000]; + +// very evil +#define ADD_TO_STATS(x,size) do {int i; for (i = 0; i < sizesUsed; i++) \ + { \ + if (sizesAlloced[i] == (int)(size)) \ + { ((x)[i])++; break; } \ + } \ + if (i >= sizesUsed && sizesUsed < MAXSUPPORTS) \ + { sizesAlloced[sizesUsed] = (size); \ + ((x)[sizesUsed++])++; break; \ + } \ + } while (0); + +#define SUB_FROM_STATS(x,size) do {int i; for (i = 0; i < sizesUsed; i++) \ + { \ + if (sizesAlloced[i] == (int)(size)) \ + { ((x)[i])--; break; } \ + } \ + } while (0); + + +SupportsStats::SupportsStats() +{ + sizesUsed = 1; + sizesAlloced[0] = 0; +} + +SupportsStats::~SupportsStats() +{ + int i; + for (i = 0; i < sizesUsed; i++) + { + printf("Size %d:\n",sizesAlloced[i]); + printf("\tNumber of SupportsArrays this size (max): %d\n",NumberOfSize[i]); + printf("\tNumber of allocations this size (total): %d\n",AllocedOfSize[i]); + printf("\tNumber of GrowsInPlace this size (total): %d\n",GrowInPlace[i]); + } + printf("Max Size of SupportsArray:\n"); + for (i = 0; i < (int)(sizeof(MaxElements)/sizeof(MaxElements[0])); i++) + { + if (MaxElements[i]) + printf("\t%d: %d\n",i,MaxElements[i]); + } +} + +// Just so constructor/destructor get called +SupportsStats gSupportsStats; +#endif + +nsresult +nsQueryElementAt::operator()( const nsIID& aIID, void** aResult ) const + { + nsresult status = mCollection + ? mCollection->QueryElementAt(mIndex, aIID, aResult) + : NS_ERROR_NULL_POINTER; + + if ( mErrorPtr ) + *mErrorPtr = status; + + return status; + } + +static const PRInt32 kGrowArrayBy = 8; +static const PRInt32 kLinearThreshold = 16 * sizeof(nsISupports *); + +nsSupportsArray::nsSupportsArray() +{ + mArray = mAutoArray; + mArraySize = kAutoArraySize; + mCount = 0; +#if DEBUG_SUPPORTSARRAY + mMaxCount = 0; + mMaxSize = 0; + ADD_TO_STATS(NumberOfSize,kAutoArraySize*sizeof(mArray[0])); + MaxElements[0]++; +#endif +} + +nsSupportsArray::~nsSupportsArray() +{ + DeleteArray(); +} + +PRBool nsSupportsArray::GrowArrayBy(PRInt32 aGrowBy) +{ + // We have to grow the array. Grow by kGrowArrayBy slots if we're smaller + // than kLinearThreshold bytes, or a power of two if we're larger. + // This is much more efficient with most memory allocators, especially + // if it's very large, or of the allocator is binned. + if (aGrowBy < kGrowArrayBy) + aGrowBy = kGrowArrayBy; + + PRUint32 newCount = mArraySize + aGrowBy; // Minimum increase + PRUint32 newSize = sizeof(mArray[0]) * newCount; + + if (newSize >= (PRUint32) kLinearThreshold) + { + // newCount includes enough space for at least kGrowArrayBy new slots. + // Select the next power-of-two size in bytes above that if newSize is + // not a power of two. + if (newSize & (newSize - 1)) + newSize = PR_BIT(PR_CeilingLog2(newSize)); + + newCount = newSize / sizeof(mArray[0]); + } + // XXX This would be far more efficient in many allocators if we used + // XXX PR_Realloc(), etc + nsISupports** oldArray = mArray; + + mArray = new nsISupports*[newCount]; + if (!mArray) { // ran out of memory + mArray = oldArray; + return PR_FALSE; + } + mArraySize = newCount; + +#if DEBUG_SUPPORTSARRAY + if (oldArray == mArray) // can't happen without use of realloc + ADD_TO_STATS(GrowInPlace,mCount); + ADD_TO_STATS(AllocedOfSize,mArraySize*sizeof(mArray[0])); + if (mArraySize > mMaxSize) + { + ADD_TO_STATS(NumberOfSize,mArraySize*sizeof(mArray[0])); + if (oldArray != &(mAutoArray[0])) + SUB_FROM_STATS(NumberOfSize,mCount*sizeof(mArray[0])); + mMaxSize = mArraySize; + } +#endif + if (oldArray) { // need to move old data + if (0 < mCount) { + ::memcpy(mArray, oldArray, mCount * sizeof(nsISupports*)); + } + if (oldArray != &(mAutoArray[0])) { + delete[] oldArray; + } + } + + return PR_TRUE; +} + +NS_METHOD +nsSupportsArray::Create(nsISupports *aOuter, REFNSIID aIID, void **aResult) +{ + if (aOuter) + return NS_ERROR_NO_AGGREGATION; + + nsCOMPtr it = new nsSupportsArray(); + if (!it) + return NS_ERROR_OUT_OF_MEMORY; + + return it->QueryInterface(aIID, aResult); +} + +NS_IMPL_THREADSAFE_ISUPPORTS3(nsSupportsArray, nsISupportsArray, nsICollection, nsISerializable) + +NS_IMETHODIMP +nsSupportsArray::Read(nsIObjectInputStream *aStream) +{ + nsresult rv; + + PRUint32 newArraySize; + rv = aStream->Read32(&newArraySize); + + if (newArraySize <= kAutoArraySize) { + if (mArray != mAutoArray) { + delete[] mArray; + mArray = mAutoArray; + } + newArraySize = kAutoArraySize; + } + else { + if (newArraySize <= mArraySize) { + // Keep non-default-size mArray, it's more than big enough. + newArraySize = mArraySize; + } + else { + nsISupports** array = new nsISupports*[newArraySize]; + if (!array) + return NS_ERROR_OUT_OF_MEMORY; + if (mArray != mAutoArray) + delete[] mArray; + mArray = array; + } + } + mArraySize = newArraySize; + + rv = aStream->Read32(&mCount); + if (NS_FAILED(rv)) return rv; + + NS_ASSERTION(mCount <= mArraySize, "overlarge mCount!"); + if (mCount > mArraySize) + mCount = mArraySize; + + for (PRUint32 i = 0; i < mCount; i++) { + rv = aStream->ReadObject(PR_TRUE, &mArray[i]); + if (NS_FAILED(rv)) return rv; + } + + return NS_OK; +} + +NS_IMETHODIMP +nsSupportsArray::Write(nsIObjectOutputStream *aStream) +{ + nsresult rv; + + rv = aStream->Write32(mArraySize); + if (NS_FAILED(rv)) return rv; + + rv = aStream->Write32(mCount); + if (NS_FAILED(rv)) return rv; + + for (PRUint32 i = 0; i < mCount; i++) { + rv = aStream->WriteObject(mArray[i], PR_TRUE); + if (NS_FAILED(rv)) return rv; + } + + return NS_OK; +} + +void nsSupportsArray::DeleteArray(void) +{ + Clear(); + if (mArray != &(mAutoArray[0])) { + delete[] mArray; + mArray = mAutoArray; + mArraySize = kAutoArraySize; + } +} + + +NS_IMETHODIMP_(PRBool) +nsSupportsArray::Equals(const nsISupportsArray* aOther) +{ + if (aOther) { + PRUint32 countOther; + nsISupportsArray* other = NS_CONST_CAST(nsISupportsArray*, aOther); + nsresult rv = other->Count(&countOther); + if (NS_FAILED( rv )) + return PR_FALSE; + + if (mCount == countOther) { + PRUint32 index = mCount; + nsCOMPtr otherElem; + while (index--) { + if (NS_FAILED(other->GetElementAt(index, getter_AddRefs(otherElem)))) + return PR_FALSE; + if (mArray[index] != otherElem) + return PR_FALSE; + } + return PR_TRUE; + } + } + return PR_FALSE; +} + +NS_IMETHODIMP_(nsISupports*) +nsSupportsArray::ElementAt(PRUint32 aIndex) +{ + if (aIndex < mCount) { + nsISupports* element = mArray[aIndex]; + NS_IF_ADDREF(element); + return element; + } + return 0; +} + +NS_IMETHODIMP_(PRInt32) +nsSupportsArray::IndexOf(const nsISupports* aPossibleElement) +{ + return IndexOfStartingAt(aPossibleElement, 0); +} + +NS_IMETHODIMP_(PRInt32) +nsSupportsArray::IndexOfStartingAt(const nsISupports* aPossibleElement, + PRUint32 aStartIndex) +{ + if (aStartIndex < mCount) { + const nsISupports** start = (const nsISupports**)mArray; // work around goofy compiler behavior + const nsISupports** ep = (start + aStartIndex); + const nsISupports** end = (start + mCount); + while (ep < end) { + if (aPossibleElement == *ep) { + return (ep - start); + } + ep++; + } + } + return -1; +} + +NS_IMETHODIMP_(PRInt32) +nsSupportsArray::LastIndexOf(const nsISupports* aPossibleElement) +{ + if (0 < mCount) { + const nsISupports** start = (const nsISupports**)mArray; // work around goofy compiler behavior + const nsISupports** ep = (start + mCount); + while (start <= --ep) { + if (aPossibleElement == *ep) { + return (ep - start); + } + } + } + return -1; +} + +NS_IMETHODIMP_(PRBool) +nsSupportsArray::InsertElementAt(nsISupports* aElement, PRUint32 aIndex) +{ + if (aIndex <= mCount) { + if (mArraySize < (mCount + 1)) { + // need to grow the array + if (!GrowArrayBy(1)) + return PR_FALSE; + } + + // Could be slightly more efficient if GrowArrayBy knew about the + // split, but the difference is trivial. + PRUint32 slide = (mCount - aIndex); + if (0 < slide) { + ::memmove(mArray + aIndex + 1, mArray + aIndex, slide * sizeof(nsISupports*)); + } + + mArray[aIndex] = aElement; + NS_IF_ADDREF(aElement); + mCount++; + +#if DEBUG_SUPPORTSARRAY + if (mCount > mMaxCount && + mCount < (PRInt32)(sizeof(MaxElements)/sizeof(MaxElements[0]))) + { + MaxElements[mCount]++; + MaxElements[mMaxCount]--; + mMaxCount = mCount; + } +#endif + return PR_TRUE; + } + return PR_FALSE; +} + +NS_IMETHODIMP_(PRBool) +nsSupportsArray::InsertElementsAt(nsISupportsArray* aElements, PRUint32 aIndex) +{ + if (!aElements) { + return PR_FALSE; + } + PRUint32 countElements; + if (NS_FAILED( aElements->Count( &countElements ) )) + return PR_FALSE; + + if (aIndex <= mCount) { + if (mArraySize < (mCount + countElements)) { + // need to grow the array + if (!GrowArrayBy(countElements)) + return PR_FALSE; + } + + // Could be slightly more efficient if GrowArrayBy knew about the + // split, but the difference is trivial. + PRUint32 slide = (mCount - aIndex); + if (0 < slide) { + ::memmove(mArray + aIndex + countElements, mArray + aIndex, + slide * sizeof(nsISupports*)); + } + + for (PRUint32 i = 0; i < countElements; ++i, ++mCount) { + // use GetElementAt to copy and do AddRef for us + if (NS_FAILED( aElements->GetElementAt( i, mArray + aIndex + i) )) + return PR_FALSE; + } + +#if DEBUG_SUPPORTSARRAY + if (mCount > mMaxCount && + mCount < (PRInt32)(sizeof(MaxElements)/sizeof(MaxElements[0]))) + { + MaxElements[mCount]++; + MaxElements[mMaxCount]--; + mMaxCount = mCount; + } +#endif + return PR_TRUE; + } + return PR_FALSE; +} + +NS_IMETHODIMP_(PRBool) +nsSupportsArray::ReplaceElementAt(nsISupports* aElement, PRUint32 aIndex) +{ + if (aIndex < mCount) { + NS_IF_ADDREF(aElement); // addref first in case it's the same object! + NS_IF_RELEASE(mArray[aIndex]); + mArray[aIndex] = aElement; + return PR_TRUE; + } + return PR_FALSE; +} + +NS_IMETHODIMP_(PRBool) +nsSupportsArray::RemoveElementsAt(PRUint32 aIndex, PRUint32 aCount) +{ + if (aIndex + aCount <= mCount) { + for (PRUint32 i = 0; i < aCount; i++) + NS_IF_RELEASE(mArray[aIndex+i]); + mCount -= aCount; + PRInt32 slide = (mCount - aIndex); + if (0 < slide) { + ::memmove(mArray + aIndex, mArray + aIndex + aCount, + slide * sizeof(nsISupports*)); + } + return PR_TRUE; + } + return PR_FALSE; +} + +NS_IMETHODIMP_(PRBool) +nsSupportsArray::RemoveElement(const nsISupports* aElement, PRUint32 aStartIndex) +{ + PRInt32 theIndex = IndexOfStartingAt(aElement,aStartIndex); + if (theIndex >= 0) + return RemoveElementAt(theIndex); + + return PR_FALSE; +} + +NS_IMETHODIMP_(PRBool) +nsSupportsArray::RemoveLastElement(const nsISupports* aElement) +{ + PRInt32 theIndex = LastIndexOf(aElement); + if (theIndex >= 0) + return RemoveElementAt(theIndex); + + return PR_FALSE; +} + +NS_IMETHODIMP_(PRBool) +nsSupportsArray::MoveElement(PRInt32 aFrom, PRInt32 aTo) +{ + nsISupports *tempElement; + + if (aTo == aFrom) + return PR_TRUE; + + if (aTo < 0 || aFrom < 0 || + (PRUint32) aTo >= mCount || (PRUint32) aFrom >= mCount) + { + // can't extend the array when moving an element. Also catches mImpl = null + return PR_FALSE; + } + tempElement = mArray[aFrom]; + + if (aTo < aFrom) + { + // Moving one element closer to the head; the elements inbetween move down + ::memmove(mArray + aTo + 1, mArray + aTo, + (aFrom-aTo) * sizeof(mArray[0])); + mArray[aTo] = tempElement; + } + else // already handled aFrom == aTo + { + // Moving one element closer to the tail; the elements inbetween move up + ::memmove(mArray + aFrom, mArray + aFrom + 1, + (aTo-aFrom) * sizeof(mArray[0])); + mArray[aTo] = tempElement; + } + + return PR_TRUE; +} + +NS_IMETHODIMP +nsSupportsArray::Clear(void) +{ + if (0 < mCount) { + do { + --mCount; + NS_IF_RELEASE(mArray[mCount]); + } while (0 != mCount); + } + return NS_OK; +} + +NS_IMETHODIMP +nsSupportsArray::Compact(void) +{ +#if DEBUG_SUPPORTSARRAY + PRUint32 oldArraySize = mArraySize; +#endif + if ((mArraySize != mCount) && (kAutoArraySize < mArraySize)) { + nsISupports** oldArray = mArray; + if (mCount <= kAutoArraySize) { + mArray = mAutoArray; + mArraySize = kAutoArraySize; + } + else { + mArray = new nsISupports*[mCount]; + if (!mArray) { + mArray = oldArray; + return NS_OK; + } + mArraySize = mCount; + } +#if DEBUG_SUPPORTSARRAY + if (oldArray == mArray && + oldArray != &(mAutoArray[0])) // can't happen without use of realloc + ADD_TO_STATS(GrowInPlace,oldArraySize); + if (oldArray != &(mAutoArray[0])) + ADD_TO_STATS(AllocedOfSize,mArraySize*sizeof(mArray[0])); +#endif + ::memcpy(mArray, oldArray, mCount * sizeof(nsISupports*)); + delete[] oldArray; + } + return NS_OK; +} + +NS_IMETHODIMP_(PRBool) +nsSupportsArray::SizeTo(PRInt32 aSize) +{ +#if DEBUG_SUPPORTSARRAY + PRUint32 oldArraySize = mArraySize; +#endif + NS_ASSERTION(aSize >= 0, "negative aSize!"); + + // XXX for aSize < mCount we could resize to mCount + if (mArraySize == (PRUint32) aSize || (PRUint32) aSize < mCount) + return PR_TRUE; // nothing to do + + // switch back to autoarray if possible + nsISupports** oldArray = mArray; + if ((PRUint32) aSize <= kAutoArraySize) { + mArray = mAutoArray; + mArraySize = kAutoArraySize; + } + else { + mArray = new nsISupports*[aSize]; + if (!mArray) { + mArray = oldArray; + return PR_FALSE; + } + mArraySize = aSize; + } +#if DEBUG_SUPPORTSARRAY + if (oldArray == mArray && + oldArray != &(mAutoArray[0])) // can't happen without use of realloc + ADD_TO_STATS(GrowInPlace,oldArraySize); + if (oldArray != &(mAutoArray[0])) + ADD_TO_STATS(AllocedOfSize,mArraySize*sizeof(mArray[0])); +#endif + ::memcpy(mArray, oldArray, mCount * sizeof(nsISupports*)); + if (oldArray != mAutoArray) + delete[] oldArray; + + return PR_TRUE; +} + +NS_IMETHODIMP_(PRBool) +nsSupportsArray::EnumerateForwards(nsISupportsArrayEnumFunc aFunc, void* aData) +{ + PRInt32 aIndex = -1; + PRBool running = PR_TRUE; + + while (running && (++aIndex < (PRInt32)mCount)) { + running = (*aFunc)(mArray[aIndex], aData); + } + return running; +} + +NS_IMETHODIMP_(PRBool) +nsSupportsArray::EnumerateBackwards(nsISupportsArrayEnumFunc aFunc, void* aData) +{ + PRUint32 aIndex = mCount; + PRBool running = PR_TRUE; + + while (running && (0 < aIndex--)) { + running = (*aFunc)(mArray[aIndex], aData); + } + return running; +} + +NS_IMETHODIMP +nsSupportsArray::Enumerate(nsIEnumerator* *result) +{ + nsSupportsArrayEnumerator* e = new nsSupportsArrayEnumerator(this); + if (!e) + return NS_ERROR_OUT_OF_MEMORY; + *result = e; + NS_ADDREF(e); + return NS_OK; +} + +static PRBool +CopyElement(nsISupports* aElement, void *aData) +{ + nsresult rv; + nsISupportsArray* newArray = (nsISupportsArray*)aData; + rv = newArray->AppendElement(aElement); + return NS_SUCCEEDED(rv); +} + +NS_IMETHODIMP +nsSupportsArray::Clone(nsISupportsArray* *result) +{ + nsresult rv; + nsISupportsArray* newArray; + rv = NS_NewISupportsArray(&newArray); + PRBool ok = EnumerateForwards(CopyElement, newArray); + if (!ok) return NS_ERROR_OUT_OF_MEMORY; + *result = newArray; + return NS_OK; +} + +NS_COM nsresult +NS_NewISupportsArray(nsISupportsArray** aInstancePtrResult) +{ + nsresult rv; + rv = nsSupportsArray::Create(NULL, NS_GET_IID(nsISupportsArray), + (void**)aInstancePtrResult); + return rv; +} + diff --git a/src/libs/xpcom18a4/xpcom/ds/nsSupportsArray.h b/src/libs/xpcom18a4/xpcom/ds/nsSupportsArray.h new file mode 100644 index 00000000..0f9c9601 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsSupportsArray.h @@ -0,0 +1,172 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +#ifndef nsSupportsArray_h__ +#define nsSupportsArray_h__ + +//#define DEBUG_SUPPORTSARRAY 1 + +#include "nsISupportsArray.h" + +static const PRUint32 kAutoArraySize = 8; + +#undef IMETHOD_VISIBILITY +#define IMETHOD_VISIBILITY NS_VISIBILITY_DEFAULT + +class NS_COM nsSupportsArray : public nsISupportsArray { +public: + nsSupportsArray(void); + ~nsSupportsArray(void); // nonvirtual since we're not subclassed + + static NS_METHOD + Create(nsISupports *aOuter, REFNSIID aIID, void **aResult); + + NS_DECL_ISUPPORTS + + NS_DECL_NSISERIALIZABLE + + // nsICollection methods: + NS_IMETHOD Count(PRUint32 *result) { *result = mCount; return NS_OK; } + NS_IMETHOD GetElementAt(PRUint32 aIndex, nsISupports* *result) { + *result = ElementAt(aIndex); + return NS_OK; + } + NS_IMETHOD QueryElementAt(PRUint32 aIndex, const nsIID & aIID, void * *aResult) { + if (aIndex < mCount) { + nsISupports* element = mArray[aIndex]; + if (nsnull != element) + return element->QueryInterface(aIID, aResult); + } + return NS_ERROR_FAILURE; + } + NS_IMETHOD SetElementAt(PRUint32 aIndex, nsISupports* value) { + return ReplaceElementAt(value, aIndex) ? NS_OK : NS_ERROR_FAILURE; + } + NS_IMETHOD AppendElement(nsISupports *aElement) { + return InsertElementAt(aElement, mCount)/* ? NS_OK : NS_ERROR_FAILURE*/; + } + // XXX this is badly named - should be RemoveFirstElement + NS_IMETHOD RemoveElement(nsISupports *aElement) { + return RemoveElement(aElement, 0)/* ? NS_OK : NS_ERROR_FAILURE*/; + } + NS_IMETHOD_(PRBool) MoveElement(PRInt32 aFrom, PRInt32 aTo); + NS_IMETHOD Enumerate(nsIEnumerator* *result); + NS_IMETHOD Clear(void); + + // nsISupportsArray methods: + NS_IMETHOD_(PRBool) Equals(const nsISupportsArray* aOther); + + NS_IMETHOD_(nsISupports*) ElementAt(PRUint32 aIndex); + + NS_IMETHOD_(PRInt32) IndexOf(const nsISupports* aPossibleElement); + NS_IMETHOD_(PRInt32) IndexOfStartingAt(const nsISupports* aPossibleElement, + PRUint32 aStartIndex = 0); + NS_IMETHOD_(PRInt32) LastIndexOf(const nsISupports* aPossibleElement); + + NS_IMETHOD GetIndexOf(nsISupports *aPossibleElement, PRInt32 *_retval) { + *_retval = IndexOf(aPossibleElement); + return NS_OK; + } + + NS_IMETHOD GetIndexOfStartingAt(nsISupports *aPossibleElement, + PRUint32 aStartIndex, PRInt32 *_retval) { + *_retval = IndexOfStartingAt(aPossibleElement, aStartIndex); + return NS_OK; + } + + NS_IMETHOD GetLastIndexOf(nsISupports *aPossibleElement, PRInt32 *_retval) { + *_retval = LastIndexOf(aPossibleElement); + return NS_OK; + } + + NS_IMETHOD_(PRBool) InsertElementAt(nsISupports* aElement, PRUint32 aIndex); + + NS_IMETHOD_(PRBool) ReplaceElementAt(nsISupports* aElement, PRUint32 aIndex); + + NS_IMETHOD_(PRBool) RemoveElementAt(PRUint32 aIndex) { + return RemoveElementsAt(aIndex,1); + } + NS_IMETHOD_(PRBool) RemoveElement(const nsISupports* aElement, PRUint32 aStartIndex = 0); + NS_IMETHOD_(PRBool) RemoveLastElement(const nsISupports* aElement); + + NS_IMETHOD DeleteLastElement(nsISupports *aElement) { + return (RemoveLastElement(aElement) ? NS_OK : NS_ERROR_FAILURE); + } + + NS_IMETHOD DeleteElementAt(PRUint32 aIndex) { + return (RemoveElementAt(aIndex) ? NS_OK : NS_ERROR_FAILURE); + } + + NS_IMETHOD_(PRBool) AppendElements(nsISupportsArray* aElements) { + return InsertElementsAt(aElements,mCount); + } + + NS_IMETHOD Compact(void); + + NS_IMETHOD_(PRBool) EnumerateForwards(nsISupportsArrayEnumFunc aFunc, void* aData); + NS_IMETHOD_(PRBool) EnumerateBackwards(nsISupportsArrayEnumFunc aFunc, void* aData); + + NS_IMETHOD Clone(nsISupportsArray **_retval); + + NS_IMETHOD_(PRBool) InsertElementsAt(nsISupportsArray *aOther, PRUint32 aIndex); + + NS_IMETHOD_(PRBool) RemoveElementsAt(PRUint32 aIndex, PRUint32 aCount); + + NS_IMETHOD_(PRBool) SizeTo(PRInt32 aSize); +protected: + void DeleteArray(void); + + NS_IMETHOD_(PRBool) GrowArrayBy(PRInt32 aGrowBy); + + nsISupports** mArray; + PRUint32 mArraySize; + PRUint32 mCount; + nsISupports* mAutoArray[kAutoArraySize]; +#if DEBUG_SUPPORTSARRAY + PRUint32 mMaxCount; + PRUint32 mMaxSize; +#endif + +private: + // Copy constructors are not allowed + nsSupportsArray(const nsISupportsArray& other); +}; + +#undef IMETHOD_VISIBILITY +#define IMETHOD_VISIBILITY NS_VISIBILITY_HIDDEN + +#endif // nsSupportsArray_h__ diff --git a/src/libs/xpcom18a4/xpcom/ds/nsSupportsArrayEnumerator.cpp b/src/libs/xpcom18a4/xpcom/ds/nsSupportsArrayEnumerator.cpp new file mode 100644 index 00000000..38d7d728 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsSupportsArrayEnumerator.cpp @@ -0,0 +1,148 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsSupportsArrayEnumerator.h" +#include "nsISupportsArray.h" + +nsSupportsArrayEnumerator::nsSupportsArrayEnumerator(nsISupportsArray* array) + : mArray(array), mCursor(0) +{ + NS_ASSERTION(array, "null array"); + NS_ADDREF(mArray); +} + +nsSupportsArrayEnumerator::~nsSupportsArrayEnumerator() +{ + NS_RELEASE(mArray); +} + +NS_IMPL_ISUPPORTS2(nsSupportsArrayEnumerator, nsIBidirectionalEnumerator, nsIEnumerator) + +NS_IMETHODIMP +nsSupportsArrayEnumerator::First() +{ + mCursor = 0; + PRUint32 cnt; + nsresult rv = mArray->Count(&cnt); + if (NS_FAILED(rv)) return rv; + PRInt32 end = (PRInt32)cnt; + if (mCursor < end) + return NS_OK; + else + return NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +nsSupportsArrayEnumerator::Next() +{ + PRUint32 cnt; + nsresult rv = mArray->Count(&cnt); + if (NS_FAILED(rv)) return rv; + PRInt32 end = (PRInt32)cnt; + if (mCursor < end) // don't count upward forever + mCursor++; + if (mCursor < end) + return NS_OK; + else + return NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +nsSupportsArrayEnumerator::CurrentItem(nsISupports **aItem) +{ + NS_ASSERTION(aItem, "null out parameter"); + PRUint32 cnt; + nsresult rv = mArray->Count(&cnt); + if (NS_FAILED(rv)) return rv; + if (mCursor >= 0 && mCursor < (PRInt32)cnt) { + *aItem = mArray->ElementAt(mCursor); + return NS_OK; + } + return NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +nsSupportsArrayEnumerator::IsDone() +{ + PRUint32 cnt; + nsresult rv = mArray->Count(&cnt); + if (NS_FAILED(rv)) return rv; + return (mCursor >= 0 && mCursor < (PRInt32)cnt) + ? NS_ENUMERATOR_FALSE : NS_OK; +} + +//////////////////////////////////////////////////////////////////////////////// + +NS_IMETHODIMP +nsSupportsArrayEnumerator::Last() +{ + PRUint32 cnt; + nsresult rv = mArray->Count(&cnt); + if (NS_FAILED(rv)) return rv; + mCursor = cnt - 1; + return NS_OK; +} + +NS_IMETHODIMP +nsSupportsArrayEnumerator::Prev() +{ + if (mCursor >= 0) + --mCursor; + if (mCursor >= 0) + return NS_OK; + else + return NS_ERROR_FAILURE; +} + +//////////////////////////////////////////////////////////////////////////////// + +NS_COM nsresult +NS_NewISupportsArrayEnumerator(nsISupportsArray* array, + nsIBidirectionalEnumerator* *aInstancePtrResult) +{ + if (aInstancePtrResult == 0) + return NS_ERROR_NULL_POINTER; + nsSupportsArrayEnumerator* e = new nsSupportsArrayEnumerator(array); + if (e == 0) + return NS_ERROR_OUT_OF_MEMORY; + NS_ADDREF(e); + *aInstancePtrResult = e; + return NS_OK; +} + +//////////////////////////////////////////////////////////////////////////////// + diff --git a/src/libs/xpcom18a4/xpcom/ds/nsSupportsArrayEnumerator.h b/src/libs/xpcom18a4/xpcom/ds/nsSupportsArrayEnumerator.h new file mode 100644 index 00000000..e987709f --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsSupportsArrayEnumerator.h @@ -0,0 +1,67 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +#ifndef nsSupportsArrayEnumerator_h___ +#define nsSupportsArrayEnumerator_h___ + +#include "nsIEnumerator.h" + +class nsISupportsArray; + +class nsSupportsArrayEnumerator : public nsIBidirectionalEnumerator { +public: + NS_DECL_ISUPPORTS + + nsSupportsArrayEnumerator(nsISupportsArray* array); + + // nsIEnumerator methods: + NS_DECL_NSIENUMERATOR + + // nsIBidirectionalEnumerator methods: + NS_DECL_NSIBIDIRECTIONALENUMERATOR + +private: + ~nsSupportsArrayEnumerator(); + +protected: + nsISupportsArray* mArray; + PRInt32 mCursor; + +}; + +#endif // __nsSupportsArrayEnumerator_h + diff --git a/src/libs/xpcom18a4/xpcom/ds/nsSupportsPrimitives.cpp b/src/libs/xpcom18a4/xpcom/ds/nsSupportsPrimitives.cpp new file mode 100644 index 00000000..7fe5502a --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsSupportsPrimitives.cpp @@ -0,0 +1,880 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Dan Rosen + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsSupportsPrimitives.h" +#include "nsCRT.h" +#include "nsMemory.h" +#include "prprf.h" +#include "nsIInterfaceInfoManager.h" +#include "nsDependentString.h" +#include "nsReadableUtils.h" +#include "nsPromiseFlatString.h" + +/***************************************************************************/ + +NS_IMPL_ISUPPORTS2(nsSupportsIDImpl, nsISupportsID, nsISupportsPrimitive) + +nsSupportsIDImpl::nsSupportsIDImpl() + : mData(nsnull) +{ +} + +NS_IMETHODIMP nsSupportsIDImpl::GetType(PRUint16 *aType) +{ + NS_ASSERTION(aType, "Bad pointer"); + *aType = TYPE_ID; + + return NS_OK; +} + +NS_IMETHODIMP nsSupportsIDImpl::GetData(nsID **aData) +{ + NS_ASSERTION(aData, "Bad pointer"); + if(mData) + { + *aData = (nsID*) nsMemory::Clone(mData, sizeof(nsID)); + return *aData ? NS_OK : NS_ERROR_OUT_OF_MEMORY; + } + *aData = nsnull; + return NS_OK; +} + +NS_IMETHODIMP nsSupportsIDImpl::SetData(const nsID *aData) +{ + if(mData) + nsMemory::Free(mData); + if(aData) + mData = (nsID*) nsMemory::Clone(aData, sizeof(nsID)); + else + mData = nsnull; + return NS_OK; +} + +NS_IMETHODIMP nsSupportsIDImpl::ToString(char **_retval) +{ + char* result; + NS_ASSERTION(_retval, "Bad pointer"); + if(mData) + { + result = mData->ToString(); + } + else + { + static const char nullStr[] = "null"; + result = (char*) nsMemory::Clone(nullStr, sizeof(nullStr)); + } + + *_retval = result; + return result ? NS_OK : NS_ERROR_OUT_OF_MEMORY; +} + +/***************************************************************************** + * nsSupportsCStringImpl + *****************************************************************************/ + +NS_IMPL_ISUPPORTS2(nsSupportsCStringImpl, nsISupportsCString, + nsISupportsPrimitive) + +NS_IMETHODIMP nsSupportsCStringImpl::GetType(PRUint16 *aType) +{ + NS_ASSERTION(aType, "Bad pointer"); + + *aType = TYPE_CSTRING; + return NS_OK; +} + +NS_IMETHODIMP nsSupportsCStringImpl::GetData(nsACString& aData) +{ + aData = mData; + return NS_OK; +} + +NS_IMETHODIMP nsSupportsCStringImpl::ToString(char **_retval) +{ + *_retval = ToNewCString(mData); + + if (!*_retval) + return NS_ERROR_OUT_OF_MEMORY; + + return NS_OK; +} + +NS_IMETHODIMP nsSupportsCStringImpl::SetData(const nsACString& aData) +{ + mData = aData; + return NS_OK; +} + +/***************************************************************************** + * nsSupportsStringImpl + *****************************************************************************/ + +NS_IMPL_ISUPPORTS2(nsSupportsStringImpl, nsISupportsString, + nsISupportsPrimitive) + +NS_IMETHODIMP nsSupportsStringImpl::GetType(PRUint16 *aType) +{ + NS_ASSERTION(aType, "Bad pointer"); + + *aType = TYPE_STRING; + return NS_OK; +} + +NS_IMETHODIMP nsSupportsStringImpl::GetData(nsAString& aData) +{ + aData = mData; + return NS_OK; +} + +NS_IMETHODIMP nsSupportsStringImpl::ToString(PRUnichar **_retval) +{ + *_retval = ToNewUnicode(mData); + + if (!*_retval) + return NS_ERROR_OUT_OF_MEMORY; + + return NS_OK; +} + +NS_IMETHODIMP nsSupportsStringImpl::SetData(const nsAString& aData) +{ + mData = aData; + return NS_OK; +} + +/***************************************************************************/ + +NS_IMPL_THREADSAFE_ISUPPORTS2(nsSupportsPRBoolImpl, nsISupportsPRBool, + nsISupportsPrimitive) + +nsSupportsPRBoolImpl::nsSupportsPRBoolImpl() + : mData(PR_FALSE) +{ +} + +NS_IMETHODIMP nsSupportsPRBoolImpl::GetType(PRUint16 *aType) +{ + NS_ASSERTION(aType, "Bad pointer"); + *aType = TYPE_PRBOOL; + + return NS_OK; +} + +NS_IMETHODIMP nsSupportsPRBoolImpl::GetData(PRBool *aData) +{ + NS_ASSERTION(aData, "Bad pointer"); + *aData = mData; + return NS_OK; +} + +NS_IMETHODIMP nsSupportsPRBoolImpl::SetData(PRBool aData) +{ + mData = aData; + return NS_OK; +} + +NS_IMETHODIMP nsSupportsPRBoolImpl::ToString(char **_retval) +{ + NS_ASSERTION(_retval, "Bad pointer"); + const char * str = mData ? "true" : "false"; + char* result = (char*) nsMemory::Clone(str, + (strlen(str)+1)*sizeof(char)); + *_retval = result; + return result ? NS_OK : NS_ERROR_OUT_OF_MEMORY; +} + +/***************************************************************************/ + +NS_IMPL_ISUPPORTS2(nsSupportsPRUint8Impl, nsISupportsPRUint8, + nsISupportsPrimitive) + +nsSupportsPRUint8Impl::nsSupportsPRUint8Impl() + : mData(0) +{ +} + +NS_IMETHODIMP nsSupportsPRUint8Impl::GetType(PRUint16 *aType) +{ + NS_ASSERTION(aType, "Bad pointer"); + *aType = TYPE_PRUINT8; + + return NS_OK; +} + +NS_IMETHODIMP nsSupportsPRUint8Impl::GetData(PRUint8 *aData) +{ + NS_ASSERTION(aData, "Bad pointer"); + *aData = mData; + return NS_OK; +} + +NS_IMETHODIMP nsSupportsPRUint8Impl::SetData(PRUint8 aData) +{ + mData = aData; + return NS_OK; +} + +NS_IMETHODIMP nsSupportsPRUint8Impl::ToString(char **_retval) +{ + NS_ASSERTION(_retval, "Bad pointer"); + static const int size = 8; + char buf[size]; + + PR_snprintf(buf, size, "%u", (PRUint16) mData); + + char* result = (char*) nsMemory::Clone(buf, + (strlen(buf)+1)*sizeof(char)); + *_retval = result; + return result ? NS_OK : NS_ERROR_OUT_OF_MEMORY; +} + +/***************************************************************************/ + +NS_IMPL_ISUPPORTS2(nsSupportsPRUint16Impl, nsISupportsPRUint16, + nsISupportsPrimitive) + +nsSupportsPRUint16Impl::nsSupportsPRUint16Impl() + : mData(0) +{ +} + +NS_IMETHODIMP nsSupportsPRUint16Impl::GetType(PRUint16 *aType) +{ + NS_ASSERTION(aType, "Bad pointer"); + *aType = TYPE_PRUINT16; + + return NS_OK; +} + +NS_IMETHODIMP nsSupportsPRUint16Impl::GetData(PRUint16 *aData) +{ + NS_ASSERTION(aData, "Bad pointer"); + *aData = mData; + return NS_OK; +} + +NS_IMETHODIMP nsSupportsPRUint16Impl::SetData(PRUint16 aData) +{ + mData = aData; + return NS_OK; +} + +NS_IMETHODIMP nsSupportsPRUint16Impl::ToString(char **_retval) +{ + NS_ASSERTION(_retval, "Bad pointer"); + static const int size = 8; + char buf[size]; + + PR_snprintf(buf, size, "%u", (int) mData); + + char* result = (char*) nsMemory::Clone(buf, + (strlen(buf)+1)*sizeof(char)); + *_retval = result; + return result ? NS_OK : NS_ERROR_OUT_OF_MEMORY; +} + +/***************************************************************************/ + +NS_IMPL_ISUPPORTS2(nsSupportsPRUint32Impl, nsISupportsPRUint32, + nsISupportsPrimitive) + +nsSupportsPRUint32Impl::nsSupportsPRUint32Impl() + : mData(0) +{ +} + +NS_IMETHODIMP nsSupportsPRUint32Impl::GetType(PRUint16 *aType) +{ + NS_ASSERTION(aType, "Bad pointer"); + *aType = TYPE_PRUINT32; + + return NS_OK; +} + +NS_IMETHODIMP nsSupportsPRUint32Impl::GetData(PRUint32 *aData) +{ + NS_ASSERTION(aData, "Bad pointer"); + *aData = mData; + return NS_OK; +} + +NS_IMETHODIMP nsSupportsPRUint32Impl::SetData(PRUint32 aData) +{ + mData = aData; + return NS_OK; +} + +NS_IMETHODIMP nsSupportsPRUint32Impl::ToString(char **_retval) +{ + NS_ASSERTION(_retval, "Bad pointer"); + static const int size = 16; + char buf[size]; + + PR_snprintf(buf, size, "%lu", mData); + + char* result = (char*) nsMemory::Clone(buf, + (strlen(buf)+1)*sizeof(char)); + *_retval = result; + return result ? NS_OK : NS_ERROR_OUT_OF_MEMORY; +} + +/***************************************************************************/ + +NS_IMPL_ISUPPORTS2(nsSupportsPRUint64Impl, nsISupportsPRUint64, + nsISupportsPrimitive) + +nsSupportsPRUint64Impl::nsSupportsPRUint64Impl() + : mData(LL_ZERO) +{ +} + +NS_IMETHODIMP nsSupportsPRUint64Impl::GetType(PRUint16 *aType) +{ + NS_ASSERTION(aType, "Bad pointer"); + *aType = TYPE_PRUINT64; + + return NS_OK; +} + +NS_IMETHODIMP nsSupportsPRUint64Impl::GetData(PRUint64 *aData) +{ + NS_ASSERTION(aData, "Bad pointer"); + *aData = mData; + return NS_OK; +} + +NS_IMETHODIMP nsSupportsPRUint64Impl::SetData(PRUint64 aData) +{ + mData = aData; + return NS_OK; +} + +NS_IMETHODIMP nsSupportsPRUint64Impl::ToString(char **_retval) +{ + NS_ASSERTION(_retval, "Bad pointer"); + static const int size = 32; + char buf[size]; + + PR_snprintf(buf, size, "%llu", mData); + + char* result = (char*) nsMemory::Clone(buf, + (strlen(buf)+1)*sizeof(char)); + *_retval = result; + return result ? NS_OK : NS_ERROR_OUT_OF_MEMORY; +} + +/***************************************************************************/ + +NS_IMPL_ISUPPORTS2(nsSupportsPRTimeImpl, nsISupportsPRTime, + nsISupportsPrimitive) + +nsSupportsPRTimeImpl::nsSupportsPRTimeImpl() + : mData(LL_ZERO) +{ +} + +NS_IMETHODIMP nsSupportsPRTimeImpl::GetType(PRUint16 *aType) +{ + NS_ASSERTION(aType, "Bad pointer"); + *aType = TYPE_PRTIME; + + return NS_OK; +} + +NS_IMETHODIMP nsSupportsPRTimeImpl::GetData(PRTime *aData) +{ + NS_ASSERTION(aData, "Bad pointer"); + *aData = mData; + return NS_OK; +} + +NS_IMETHODIMP nsSupportsPRTimeImpl::SetData(PRTime aData) +{ + mData = aData; + return NS_OK; +} + +NS_IMETHODIMP nsSupportsPRTimeImpl::ToString(char **_retval) +{ + NS_ASSERTION(_retval, "Bad pointer"); + static const int size = 32; + char buf[size]; + + PR_snprintf(buf, size, "%llu", mData); + + char* result = (char*) nsMemory::Clone(buf, + (strlen(buf)+1)*sizeof(char)); + *_retval = result; + return result ? NS_OK : NS_ERROR_OUT_OF_MEMORY; +} + +/***************************************************************************/ + +NS_IMPL_ISUPPORTS2(nsSupportsCharImpl, nsISupportsChar, + nsISupportsPrimitive) + +nsSupportsCharImpl::nsSupportsCharImpl() + : mData(0) +{ +} + +NS_IMETHODIMP nsSupportsCharImpl::GetType(PRUint16 *aType) +{ + NS_ASSERTION(aType, "Bad pointer"); + *aType = TYPE_CHAR; + + return NS_OK; +} + +NS_IMETHODIMP nsSupportsCharImpl::GetData(char *aData) +{ + NS_ASSERTION(aData, "Bad pointer"); + *aData = mData; + return NS_OK; +} + +NS_IMETHODIMP nsSupportsCharImpl::SetData(char aData) +{ + mData = aData; + return NS_OK; +} + +NS_IMETHODIMP nsSupportsCharImpl::ToString(char **_retval) +{ + char* result; + NS_ASSERTION(_retval, "Bad pointer"); + + if(nsnull != (result = (char*) nsMemory::Alloc(2*sizeof(char)))) + { + result[0] = mData; + result[1] = '\0'; + } + *_retval = result; + return result ? NS_OK : NS_ERROR_OUT_OF_MEMORY; +} + +/***************************************************************************/ + +NS_IMPL_ISUPPORTS2(nsSupportsPRInt16Impl, nsISupportsPRInt16, + nsISupportsPrimitive) + +nsSupportsPRInt16Impl::nsSupportsPRInt16Impl() + : mData(0) +{ +} + +NS_IMETHODIMP nsSupportsPRInt16Impl::GetType(PRUint16 *aType) +{ + NS_ASSERTION(aType, "Bad pointer"); + *aType = TYPE_PRINT16; + + return NS_OK; +} + +NS_IMETHODIMP nsSupportsPRInt16Impl::GetData(PRInt16 *aData) +{ + NS_ASSERTION(aData, "Bad pointer"); + *aData = mData; + return NS_OK; +} + +NS_IMETHODIMP nsSupportsPRInt16Impl::SetData(PRInt16 aData) +{ + mData = aData; + return NS_OK; +} + +NS_IMETHODIMP nsSupportsPRInt16Impl::ToString(char **_retval) +{ + NS_ASSERTION(_retval, "Bad pointer"); + static const int size = 8; + char buf[size]; + + PR_snprintf(buf, size, "%d", mData); + + char* result = (char*) nsMemory::Clone(buf, + (strlen(buf)+1)*sizeof(char)); + *_retval = result; + return result ? NS_OK : NS_ERROR_OUT_OF_MEMORY; +} + +/***************************************************************************/ + +NS_IMPL_ISUPPORTS2(nsSupportsPRInt32Impl, nsISupportsPRInt32, + nsISupportsPrimitive) + +nsSupportsPRInt32Impl::nsSupportsPRInt32Impl() + : mData(0) +{ +} + +NS_IMETHODIMP nsSupportsPRInt32Impl::GetType(PRUint16 *aType) +{ + NS_ASSERTION(aType, "Bad pointer"); + *aType = TYPE_PRINT32; + + return NS_OK; +} + +NS_IMETHODIMP nsSupportsPRInt32Impl::GetData(PRInt32 *aData) +{ + NS_ASSERTION(aData, "Bad pointer"); + *aData = mData; + return NS_OK; +} + +NS_IMETHODIMP nsSupportsPRInt32Impl::SetData(PRInt32 aData) +{ + mData = aData; + return NS_OK; +} + +NS_IMETHODIMP nsSupportsPRInt32Impl::ToString(char **_retval) +{ + NS_ASSERTION(_retval, "Bad pointer"); + static const int size = 16; + char buf[size]; + + PR_snprintf(buf, size, "%ld", mData); + + char* result = (char*) nsMemory::Clone(buf, + (strlen(buf)+1)*sizeof(char)); + *_retval = result; + return result ? NS_OK : NS_ERROR_OUT_OF_MEMORY; +} + +/***************************************************************************/ + +NS_IMPL_ISUPPORTS2(nsSupportsPRInt64Impl, nsISupportsPRInt64, + nsISupportsPrimitive) + +nsSupportsPRInt64Impl::nsSupportsPRInt64Impl() + : mData(LL_ZERO) +{ +} + +NS_IMETHODIMP nsSupportsPRInt64Impl::GetType(PRUint16 *aType) +{ + NS_ASSERTION(aType, "Bad pointer"); + *aType = TYPE_PRINT64; + + return NS_OK; +} + +NS_IMETHODIMP nsSupportsPRInt64Impl::GetData(PRInt64 *aData) +{ + NS_ASSERTION(aData, "Bad pointer"); + *aData = mData; + return NS_OK; +} + +NS_IMETHODIMP nsSupportsPRInt64Impl::SetData(PRInt64 aData) +{ + mData = aData; + return NS_OK; +} + +NS_IMETHODIMP nsSupportsPRInt64Impl::ToString(char **_retval) +{ + NS_ASSERTION(_retval, "Bad pointer"); + static const int size = 32; + char buf[size]; + + PR_snprintf(buf, size, "%lld", mData); + + char* result = (char*) nsMemory::Clone(buf, + (strlen(buf)+1)*sizeof(char)); + *_retval = result; + return result ? NS_OK : NS_ERROR_OUT_OF_MEMORY; +} + +/***************************************************************************/ + +NS_IMPL_ISUPPORTS2(nsSupportsFloatImpl, nsISupportsFloat, + nsISupportsPrimitive) + +nsSupportsFloatImpl::nsSupportsFloatImpl() + : mData(float(0.0)) +{ +} + +NS_IMETHODIMP nsSupportsFloatImpl::GetType(PRUint16 *aType) +{ + NS_ASSERTION(aType, "Bad pointer"); + *aType = TYPE_FLOAT; + + return NS_OK; +} + +NS_IMETHODIMP nsSupportsFloatImpl::GetData(float *aData) +{ + NS_ASSERTION(aData, "Bad pointer"); + *aData = mData; + return NS_OK; +} + +NS_IMETHODIMP nsSupportsFloatImpl::SetData(float aData) +{ + mData = aData; + return NS_OK; +} + +NS_IMETHODIMP nsSupportsFloatImpl::ToString(char **_retval) +{ + NS_ASSERTION(_retval, "Bad pointer"); + static const int size = 32; + char buf[size]; + + PR_snprintf(buf, size, "%f", (double) mData); + + char* result = (char*) nsMemory::Clone(buf, + (strlen(buf)+1)*sizeof(char)); + *_retval = result; + return result ? NS_OK : NS_ERROR_OUT_OF_MEMORY; +} + +/***************************************************************************/ + +NS_IMPL_ISUPPORTS2(nsSupportsDoubleImpl, nsISupportsDouble, + nsISupportsPrimitive) + +nsSupportsDoubleImpl::nsSupportsDoubleImpl() + : mData(double(0.0)) +{ +} + +NS_IMETHODIMP nsSupportsDoubleImpl::GetType(PRUint16 *aType) +{ + NS_ASSERTION(aType, "Bad pointer"); + *aType = TYPE_DOUBLE; + + return NS_OK; +} + +NS_IMETHODIMP nsSupportsDoubleImpl::GetData(double *aData) +{ + NS_ASSERTION(aData, "Bad pointer"); + *aData = mData; + return NS_OK; +} + +NS_IMETHODIMP nsSupportsDoubleImpl::SetData(double aData) +{ + mData = aData; + return NS_OK; +} + +NS_IMETHODIMP nsSupportsDoubleImpl::ToString(char **_retval) +{ + NS_ASSERTION(_retval, "Bad pointer"); + static const int size = 32; + char buf[size]; + + PR_snprintf(buf, size, "%f", mData); + + char* result = (char*) nsMemory::Clone(buf, + (strlen(buf)+1)*sizeof(char)); + *_retval = result; + return result ? NS_OK : NS_ERROR_OUT_OF_MEMORY; +} + +/***************************************************************************/ + + +NS_IMPL_THREADSAFE_ISUPPORTS2(nsSupportsVoidImpl, nsISupportsVoid, + nsISupportsPrimitive) + +nsSupportsVoidImpl::nsSupportsVoidImpl() + : mData(nsnull) +{ +} + +NS_IMETHODIMP nsSupportsVoidImpl::GetType(PRUint16 *aType) +{ + NS_ASSERTION(aType, "Bad pointer"); + *aType = TYPE_VOID; + + return NS_OK; +} + +NS_IMETHODIMP nsSupportsVoidImpl::GetData(void * *aData) +{ + NS_ASSERTION(aData, "Bad pointer"); + *aData = mData; + return NS_OK; +} + +NS_IMETHODIMP nsSupportsVoidImpl::SetData(void * aData) +{ + mData = aData; + return NS_OK; +} + +NS_IMETHODIMP nsSupportsVoidImpl::ToString(char **_retval) +{ + NS_ASSERTION(_retval, "Bad pointer"); + + static const char str[] = "[raw data]"; + char* result = (char*) nsMemory::Clone(str, sizeof(str)); + *_retval = result; + return result ? NS_OK : NS_ERROR_OUT_OF_MEMORY; +} + +/***************************************************************************/ + + +NS_IMPL_THREADSAFE_ISUPPORTS2(nsSupportsInterfacePointerImpl, + nsISupportsInterfacePointer, + nsISupportsPrimitive) + +nsSupportsInterfacePointerImpl::nsSupportsInterfacePointerImpl() + : mIID(nsnull) +{ +} + +nsSupportsInterfacePointerImpl::~nsSupportsInterfacePointerImpl() +{ + if (mIID) { + nsMemory::Free(mIID); + } +} + +NS_IMETHODIMP nsSupportsInterfacePointerImpl::GetType(PRUint16 *aType) +{ + NS_ASSERTION(aType, "Bad pointer"); + *aType = TYPE_INTERFACE_POINTER; + + return NS_OK; +} + +NS_IMETHODIMP nsSupportsInterfacePointerImpl::GetData(nsISupports **aData) +{ + NS_ASSERTION(aData,"Bad pointer"); + + *aData = mData; + NS_IF_ADDREF(*aData); + + return NS_OK; +} + +NS_IMETHODIMP nsSupportsInterfacePointerImpl::SetData(nsISupports * aData) +{ + mData = aData; + + return NS_OK; +} + +NS_IMETHODIMP nsSupportsInterfacePointerImpl::GetDataIID(nsID **aIID) +{ + NS_ASSERTION(aIID,"Bad pointer"); + + if(mIID) + { + *aIID = (nsID*) nsMemory::Clone(mIID, sizeof(nsID)); + return *aIID ? NS_OK : NS_ERROR_OUT_OF_MEMORY; + } + *aIID = nsnull; + return NS_OK; +} + +NS_IMETHODIMP nsSupportsInterfacePointerImpl::SetDataIID(const nsID *aIID) +{ + if(mIID) + nsMemory::Free(mIID); + if(aIID) + mIID = (nsID*) nsMemory::Clone(aIID, sizeof(nsID)); + else + mIID = nsnull; + + return NS_OK; +} + +NS_IMETHODIMP nsSupportsInterfacePointerImpl::ToString(char **_retval) +{ + NS_ASSERTION(_retval, "Bad pointer"); + + static const char str[] = "[interface pointer]"; + + // jband sez: think about asking nsIInterfaceInfoManager whether + // the interface has a known human-readable name + char* result = (char*) nsMemory::Clone(str, sizeof(str)); + *_retval = result; + return result ? NS_OK : NS_ERROR_OUT_OF_MEMORY; +} + +/***************************************************************************/ + +NS_IMPL_ISUPPORTS2(nsSupportsDependentCString,nsISupportsCString,nsISupportsPrimitive) + +nsSupportsDependentCString::nsSupportsDependentCString(const char* aStr) + : mData(aStr) +{ } + +NS_IMETHODIMP +nsSupportsDependentCString::GetType(PRUint16 *aType) +{ + NS_ENSURE_ARG_POINTER(aType); + + *aType = TYPE_CSTRING; + return NS_OK; +} + +NS_IMETHODIMP +nsSupportsDependentCString::GetData(nsACString& aData) +{ + aData = mData; + return NS_OK; +} + +NS_IMETHODIMP +nsSupportsDependentCString::ToString(char **_retval) +{ + NS_ENSURE_ARG_POINTER(_retval); + + *_retval = ToNewCString(mData); + if (!*_retval) + return NS_ERROR_OUT_OF_MEMORY; + + return NS_OK; +} + +NS_IMETHODIMP +nsSupportsDependentCString::SetData(const nsACString& aData) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} diff --git a/src/libs/xpcom18a4/xpcom/ds/nsSupportsPrimitives.h b/src/libs/xpcom18a4/xpcom/ds/nsSupportsPrimitives.h new file mode 100644 index 00000000..81e83fa3 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsSupportsPrimitives.h @@ -0,0 +1,358 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Dan Rosen + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +#ifndef nsSupportsPrimitives_h__ +#define nsSupportsPrimitives_h__ + +#include "nsISupportsPrimitives.h" +#include "nsCOMPtr.h" +#include "nsString.h" +#include "nsDependentString.h" + +class nsSupportsIDImpl : public nsISupportsID +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSISUPPORTSPRIMITIVE + NS_DECL_NSISUPPORTSID + + nsSupportsIDImpl(); + +private: + ~nsSupportsIDImpl() { } + + nsID *mData; +}; + +/***************************************************************************/ + +class nsSupportsCStringImpl : public nsISupportsCString +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSISUPPORTSPRIMITIVE + NS_DECL_NSISUPPORTSCSTRING + + nsSupportsCStringImpl() {} + +private: + ~nsSupportsCStringImpl() {} + + nsCString mData; +}; + +/***************************************************************************/ + +class nsSupportsStringImpl : public nsISupportsString +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSISUPPORTSPRIMITIVE + NS_DECL_NSISUPPORTSSTRING + + nsSupportsStringImpl() {} + +private: + ~nsSupportsStringImpl() {} + + nsString mData; +}; + +/***************************************************************************/ + +class nsSupportsPRBoolImpl : public nsISupportsPRBool +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSISUPPORTSPRIMITIVE + NS_DECL_NSISUPPORTSPRBOOL + + nsSupportsPRBoolImpl(); + +private: + ~nsSupportsPRBoolImpl() {} + + PRBool mData; +}; + +/***************************************************************************/ + +class nsSupportsPRUint8Impl : public nsISupportsPRUint8 +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSISUPPORTSPRIMITIVE + NS_DECL_NSISUPPORTSPRUINT8 + + nsSupportsPRUint8Impl(); + +private: + ~nsSupportsPRUint8Impl() {} + + PRUint8 mData; +}; + +/***************************************************************************/ + +class nsSupportsPRUint16Impl : public nsISupportsPRUint16 +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSISUPPORTSPRIMITIVE + NS_DECL_NSISUPPORTSPRUINT16 + + nsSupportsPRUint16Impl(); + +private: + ~nsSupportsPRUint16Impl() {} + + PRUint16 mData; +}; + +/***************************************************************************/ + +class nsSupportsPRUint32Impl : public nsISupportsPRUint32 +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSISUPPORTSPRIMITIVE + NS_DECL_NSISUPPORTSPRUINT32 + + nsSupportsPRUint32Impl(); + +private: + ~nsSupportsPRUint32Impl() {} + + PRUint32 mData; +}; + +/***************************************************************************/ + +class nsSupportsPRUint64Impl : public nsISupportsPRUint64 +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSISUPPORTSPRIMITIVE + NS_DECL_NSISUPPORTSPRUINT64 + + nsSupportsPRUint64Impl(); + +private: + ~nsSupportsPRUint64Impl() {} + + PRUint64 mData; +}; + +/***************************************************************************/ + +class nsSupportsPRTimeImpl : public nsISupportsPRTime +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSISUPPORTSPRIMITIVE + NS_DECL_NSISUPPORTSPRTIME + + nsSupportsPRTimeImpl(); + +private: + ~nsSupportsPRTimeImpl() {} + + PRTime mData; +}; + +/***************************************************************************/ + +class nsSupportsCharImpl : public nsISupportsChar +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSISUPPORTSPRIMITIVE + NS_DECL_NSISUPPORTSCHAR + + nsSupportsCharImpl(); + +private: + ~nsSupportsCharImpl() {} + + char mData; +}; + +/***************************************************************************/ + +class nsSupportsPRInt16Impl : public nsISupportsPRInt16 +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSISUPPORTSPRIMITIVE + NS_DECL_NSISUPPORTSPRINT16 + + nsSupportsPRInt16Impl(); + +private: + ~nsSupportsPRInt16Impl() {} + + PRInt16 mData; +}; + +/***************************************************************************/ + +class nsSupportsPRInt32Impl : public nsISupportsPRInt32 +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSISUPPORTSPRIMITIVE + NS_DECL_NSISUPPORTSPRINT32 + + nsSupportsPRInt32Impl(); + +private: + ~nsSupportsPRInt32Impl() {} + + PRInt32 mData; +}; + +/***************************************************************************/ + +class nsSupportsPRInt64Impl : public nsISupportsPRInt64 +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSISUPPORTSPRIMITIVE + NS_DECL_NSISUPPORTSPRINT64 + + nsSupportsPRInt64Impl(); + +private: + ~nsSupportsPRInt64Impl() {} + + PRInt64 mData; +}; + +/***************************************************************************/ + +class nsSupportsFloatImpl : public nsISupportsFloat +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSISUPPORTSPRIMITIVE + NS_DECL_NSISUPPORTSFLOAT + + nsSupportsFloatImpl(); + +private: + ~nsSupportsFloatImpl() {} + + float mData; +}; + +/***************************************************************************/ + +class nsSupportsDoubleImpl : public nsISupportsDouble +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSISUPPORTSPRIMITIVE + NS_DECL_NSISUPPORTSDOUBLE + + nsSupportsDoubleImpl(); + +private: + ~nsSupportsDoubleImpl() {} + + double mData; +}; + +/***************************************************************************/ + +class nsSupportsVoidImpl : public nsISupportsVoid +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSISUPPORTSPRIMITIVE + NS_DECL_NSISUPPORTSVOID + + nsSupportsVoidImpl(); + +private: + ~nsSupportsVoidImpl() {} + + void* mData; +}; + +/***************************************************************************/ + +class nsSupportsInterfacePointerImpl : public nsISupportsInterfacePointer +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSISUPPORTSPRIMITIVE + NS_DECL_NSISUPPORTSINTERFACEPOINTER + + nsSupportsInterfacePointerImpl(); + +private: + ~nsSupportsInterfacePointerImpl(); + + nsCOMPtr mData; + nsID *mIID; +}; + +/***************************************************************************/ + +/** + * Wraps a static const char* buffer for use with nsISupportsCString + * + * Only use this class with static buffers, or arena-allocated buffers of + * permanent lifetime! + */ +class nsSupportsDependentCString : public nsISupportsCString +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSISUPPORTSPRIMITIVE + NS_DECL_NSISUPPORTSCSTRING + + nsSupportsDependentCString(const char* aStr); + +private: + ~nsSupportsDependentCString() {} + + nsDependentCString mData; +}; + +#endif /* nsSupportsPrimitives_h__ */ diff --git a/src/libs/xpcom18a4/xpcom/ds/nsTHashtable.cpp b/src/libs/xpcom18a4/xpcom/ds/nsTHashtable.cpp new file mode 100644 index 00000000..37fa998f --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsTHashtable.cpp @@ -0,0 +1,62 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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 C++ hashtable templates. + * + * The Initial Developer of the Original Code is + * Benjamin Smedberg. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * 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 "nsTHashtable.h" +#include "nsHashKeys.h" + +PR_IMPLEMENT(PLDHashOperator) +PL_DHashStubEnumRemove(PLDHashTable *table, + PLDHashEntryHdr *entry, + PRUint32 ordinal, + void *userarg) +{ + return PL_DHASH_REMOVE; +} + +PRUint32 nsIDHashKey::HashKey(const nsID* id) +{ + PRUint32 h = id->m0; + PRUint32 i; + + h = (h>>28) ^ (h<<4) ^ id->m1; + h = (h>>28) ^ (h<<4) ^ id->m2; + + for (i = 0; i < 8; i++) + h = (h>>28) ^ (h<<4) ^ id->m3[i]; + + return h; +} diff --git a/src/libs/xpcom18a4/xpcom/ds/nsTHashtable.h b/src/libs/xpcom18a4/xpcom/ds/nsTHashtable.h new file mode 100644 index 00000000..1e55ada6 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsTHashtable.h @@ -0,0 +1,429 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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 C++ hashtable templates. + * + * The Initial Developer of the Original Code is + * Benjamin Smedberg. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * 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 ***** */ + +#ifndef nsTHashtable_h__ +#define nsTHashtable_h__ + +#include "nscore.h" +#include "pldhash.h" +#include "nsDebug.h" +#include NEW_H + +// helper function for nsTHashtable::Clear() +PR_EXTERN(PLDHashOperator) PR_CALLBACK +PL_DHashStubEnumRemove(PLDHashTable *table, + PLDHashEntryHdr *entry, + PRUint32 ordinal, + void *userArg); + + +/** + * a base class for templated hashtables. + * + * Clients will rarely need to use this class directly. Check the derived + * classes first, to see if they will meet your needs. + * + * @param EntryType the templated entry-type class that is managed by the + * hashtable. EntryType must extend the following declaration, + * and must not declare any virtual functions or derive from classes + * with virtual functions. Any vtable pointer would break the + * PLDHashTable code. + *

   class EntryType : public PLDHashEntryHdr
+ *   {
+ *   public: or friend nsTHashtable;
+ *     // KeyType is what we use when Get()ing or Put()ing this entry
+ *     // this should either be a simple datatype (PRUint32, nsISupports*) or
+ *     // a const reference (const nsAString&)
+ *     typedef something KeyType;
+ *     // KeyTypePointer is the pointer-version of KeyType, because pldhash.h
+ *     // requires keys to cast to const void*
+ *     typedef const something* KeyTypePointer;
+ *
+ *     EntryType(KeyTypePointer aKey);
+ *
+ *     // the copy constructor must be defined, even if AllowMemMove() == true
+ *     // or you will cause link errors!
+ *     EntryType(const EntryType& aEnt);
+ *
+ *     // the destructor must be defined... or you will cause link errors!
+ *     ~EntryType();
+ *
+ *     // return the key of this entry
+ *     const KeyTypePointer GetKeyPointer() const;
+ *
+ *     // KeyEquals(): does this entry match this key?
+ *     PRBool KeyEquals(KeyTypePointer aKey) const;
+ *
+ *     // KeyToPointer(): Convert KeyType to KeyTypePointer
+ *     static KeyTypePointer KeyToPointer(KeyType aKey);
+ *
+ *     // HashKey(): calculate the hash number
+ *     static PLDHashNumber HashKey(KeyTypePointer aKey);
+ *
+ *     // ALLOW_MEMMOVE can we move this class with memmove(), or do we have
+ *     // to use the copy constructor?
+ *     enum { ALLOW_MEMMOVE = PR_(TRUE or FALSE) };
+ *   }
+ * + * @see nsInterfaceHashtable + * @see nsDataHashtable + * @see nsClassHashtable + * @author "Benjamin Smedberg " + */ + +template +class nsTHashtable +{ +public: + /** + * A dummy constructor; you must call Init() before using this class. + */ + nsTHashtable(); + + /** + * destructor, cleans up and deallocates + */ + ~nsTHashtable(); + + /** + * Initialize the table. This function must be called before any other + * class operations. This can fail due to OOM conditions. + * @param initSize the initial number of buckets in the hashtable, default 16 + * @return PR_TRUE if the class was initialized properly. + */ + PRBool Init(PRUint32 initSize = PL_DHASH_MIN_SIZE); + + /** + * Check whether the table has been initialized. This can be useful for static hashtables. + * @return the initialization state of the class. + */ + PRBool IsInitialized() const { return mTable.entrySize; } + + /** + * KeyType is typedef'ed for ease of use. + */ + typedef typename EntryType::KeyType KeyType; + + /** + * KeyTypePointer is typedef'ed for ease of use. + */ + typedef typename EntryType::KeyTypePointer KeyTypePointer; + + /** + * Return the number of entries in the table. + * @return number of entries + */ + PRUint32 Count() const { return mTable.entryCount; } + + /** + * Get the entry associated with a key. + * @param aKey the key to retrieve + * @return pointer to the entry class, if the key exists; nsnull if the + * key doesn't exist + */ + EntryType* GetEntry(KeyType aKey) const + { + NS_ASSERTION(mTable.entrySize, "nsTHashtable was not initialized properly."); + + EntryType* entry = + NS_REINTERPRET_CAST(EntryType*, + PL_DHashTableOperate( + NS_CONST_CAST(PLDHashTable*,&mTable), + EntryType::KeyToPointer(aKey), + PL_DHASH_LOOKUP)); + return PL_DHASH_ENTRY_IS_BUSY(entry) ? entry : nsnull; + } + + /** + * Get the entry associated with a key, or create a new entry, + * @param aKey the key to retrieve + * @return pointer to the entry class retreived; nsnull only if memory + can't be allocated + */ + EntryType* PutEntry(KeyType aKey) + { + NS_ASSERTION(mTable.entrySize, "nsTHashtable was not initialized properly."); + + return NS_STATIC_CAST(EntryType*, + PL_DHashTableOperate( + &mTable, + EntryType::KeyToPointer(aKey), + PL_DHASH_ADD)); + } + + /** + * Remove the entry associated with a key. + * @param aKey of the entry to remove + */ + void RemoveEntry(KeyType aKey) + { + NS_ASSERTION(mTable.entrySize, "nsTHashtable was not initialized properly."); + + PL_DHashTableOperate(&mTable, + EntryType::KeyToPointer(aKey), + PL_DHASH_REMOVE); + } + + /** + * Remove the entry associated with a key, but don't resize the hashtable. + * This is a low-level method, and is not recommended unless you know what + * you're doing and you need the extra performance. This method can be used + * during enumeration, while RemoveEntry() cannot. + * @param aEntry the entry-pointer to remove (obtained from GetEntry or + * the enumerator + */ + void RawRemoveEntry(EntryType* aEntry) + { + PL_DHashTableRawRemove(&mTable, aEntry); + } + + /** + * client must provide an Enumerator function for + * EnumerateEntries + * @param aEntry the entry being enumerated + * @param userArg passed unchanged from EnumerateEntries + * @return combination of flags + * @link PLDHashOperator::PL_DHASH_NEXT PL_DHASH_NEXT @endlink , + * @link PLDHashOperator::PL_DHASH_STOP PL_DHASH_STOP @endlink , + * @link PLDHashOperator::PL_DHASH_REMOVE PL_DHASH_REMOVE @endlink + */ + typedef PLDHashOperator (*PR_CALLBACK Enumerator)(EntryType* aEntry, void* userArg); + + /** + * Enumerate all the entries of the function. + * @param enumFunc the Enumerator function to call + * @param userArg a pointer to pass to the + * Enumerator function + * @return the number of entries actually enumerated + */ + PRUint32 EnumerateEntries(Enumerator enumFunc, void* userArg) + { + NS_ASSERTION(mTable.entrySize, "nsTHashtable was not initialized properly."); + + s_EnumArgs args = { enumFunc, userArg }; + return PL_DHashTableEnumerate(&mTable, s_EnumStub, &args); + } + + /** + * remove all entries, return hashtable to "pristine" state ;) + */ + void Clear() + { + NS_ASSERTION(mTable.entrySize, "nsTHashtable was not initialized properly."); + + PL_DHashTableEnumerate(&mTable, PL_DHashStubEnumRemove, nsnull); + } + +protected: + PLDHashTable mTable; + + static const void* PR_CALLBACK s_GetKey(PLDHashTable *table, + PLDHashEntryHdr *entry); + + static PLDHashNumber PR_CALLBACK s_HashKey(PLDHashTable *table, + const void *key); + + static PRBool PR_CALLBACK s_MatchEntry(PLDHashTable *table, + const PLDHashEntryHdr *entry, + const void *key); + + static void PR_CALLBACK s_CopyEntry(PLDHashTable *table, + const PLDHashEntryHdr *from, + PLDHashEntryHdr *to); + + static void PR_CALLBACK s_ClearEntry(PLDHashTable *table, + PLDHashEntryHdr *entry); + + static PRBool PR_CALLBACK s_InitEntry(PLDHashTable *table, + PLDHashEntryHdr *entry, + const void *key); + + /** + * passed internally during enumeration. Allocated on the stack. + * + * @param userFunc the Enumerator function passed to + * EnumerateEntries by the client + * @param userArg the userArg passed unaltered + */ + struct s_EnumArgs + { + Enumerator userFunc; + void* userArg; + }; + + static PLDHashOperator PR_CALLBACK s_EnumStub(PLDHashTable *table, + PLDHashEntryHdr *entry, + PRUint32 number, + void *arg); +private: + // copy constructor, not implemented + nsTHashtable(nsTHashtable& toCopy); + + // assignment operator, not implemented + nsTHashtable& operator= (nsTHashtable& toEqual); +}; + +// +// template definitions +// + +template +nsTHashtable::nsTHashtable() +{ + // entrySize is our "I'm initialized" indicator + mTable.entrySize = 0; +} + +template +nsTHashtable::~nsTHashtable() +{ + if (mTable.entrySize) + PL_DHashTableFinish(&mTable); +} + +template +PRBool +nsTHashtable::Init(PRUint32 initSize) +{ + if (mTable.entrySize) + { + NS_ERROR("nsTHashtable::Init() should not be called twice."); + return PR_TRUE; + } + + static PLDHashTableOps sOps = + { + ::PL_DHashAllocTable, + ::PL_DHashFreeTable, + s_GetKey, + s_HashKey, + s_MatchEntry, + ::PL_DHashMoveEntryStub, + s_ClearEntry, + ::PL_DHashFinalizeStub, + s_InitEntry + }; + + if (!EntryType::ALLOW_MEMMOVE) + { + sOps.moveEntry = s_CopyEntry; + } + + if (!PL_DHashTableInit(&mTable, &sOps, nsnull, sizeof(EntryType), initSize)) + { + // if failed, reset "flag" + mTable.entrySize = 0; + return PR_FALSE; + } + + return PR_TRUE; +} + +// static definitions + +template +const void* +nsTHashtable::s_GetKey(PLDHashTable *table, + PLDHashEntryHdr *entry) +{ + return ((EntryType*) entry)->GetKeyPointer(); +} + +template +PLDHashNumber +nsTHashtable::s_HashKey(PLDHashTable *table, + const void *key) +{ + return EntryType::HashKey(NS_REINTERPRET_CAST(const KeyTypePointer, key)); +} + +template +PRBool +nsTHashtable::s_MatchEntry(PLDHashTable *table, + const PLDHashEntryHdr *entry, + const void *key) +{ + return ((const EntryType*) entry)->KeyEquals( + NS_REINTERPRET_CAST(const KeyTypePointer, key)); +} + +template +void +nsTHashtable::s_CopyEntry(PLDHashTable *table, + const PLDHashEntryHdr *from, + PLDHashEntryHdr *to) +{ + EntryType* fromEntry = + NS_CONST_CAST(EntryType*, NS_REINTERPRET_CAST(const EntryType*, from)); + + new(to) EntryType(*fromEntry); + + fromEntry->~EntryType(); +} + +template +void +nsTHashtable::s_ClearEntry(PLDHashTable *table, + PLDHashEntryHdr *entry) +{ + NS_REINTERPRET_CAST(EntryType*,entry)->~EntryType(); +} + +template +PRBool +nsTHashtable::s_InitEntry(PLDHashTable *table, + PLDHashEntryHdr *entry, + const void *key) +{ + new(entry) EntryType(NS_REINTERPRET_CAST(KeyTypePointer,key)); + return PR_TRUE; +} + +template +PLDHashOperator +nsTHashtable::s_EnumStub(PLDHashTable *table, + PLDHashEntryHdr *entry, + PRUint32 number, + void *arg) +{ + // dereferences the function-pointer to the user's enumeration function + return (* NS_REINTERPRET_CAST(s_EnumArgs*,arg)->userFunc)( + NS_REINTERPRET_CAST(EntryType*,entry), + NS_REINTERPRET_CAST(s_EnumArgs*,arg)->userArg); +} + +#endif // nsTHashtable_h__ diff --git a/src/libs/xpcom18a4/xpcom/ds/nsTextFormatter.cpp b/src/libs/xpcom18a4/xpcom/ds/nsTextFormatter.cpp new file mode 100644 index 00000000..a5f2dde0 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsTextFormatter.cpp @@ -0,0 +1,1557 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org Code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* + * Portable safe sprintf code. + * + * Code based on mozilla/nsprpub/src/io/prprf.c rev 3.7 + * + * Contributor(s): + * Kipp E.B. Hickman (original author) + * Frank Yung-Fong Tang + * Daniele Nicolodi + */ + +#include +#include +#include +#include +#include "prdtoa.h" +#include "prlong.h" +#include "prlog.h" +#include "prmem.h" +#include "prprf.h" +#include "nsCRT.h" +#include "nsTextFormatter.h" +#include "nsString.h" +#include "nsReadableUtils.h" + +/* +** Note: on some platforms va_list is defined as an array, +** and requires array notation. +*/ + +#ifdef HAVE_VA_COPY +#define VARARGS_ASSIGN(foo, bar) VA_COPY(foo,bar) +#elif defined(HAVE_VA_LIST_AS_ARRAY) +#define VARARGS_ASSIGN(foo, bar) foo[0] = bar[0] +#else +#define VARARGS_ASSIGN(foo, bar) (foo) = (bar) +#endif + +typedef struct SprintfStateStr SprintfState; + +struct SprintfStateStr { + int (*stuff)(SprintfState *ss, const PRUnichar *sp, PRUint32 len); + + PRUnichar *base; + PRUnichar *cur; + PRUint32 maxlen; + + void *stuffclosure; +}; + +/* +** Numbered Arguement State +*/ +struct NumArgState{ + int type; /* type of the current ap */ + va_list ap; /* point to the corresponding position on ap */ +}; + +#define NAS_DEFAULT_NUM 20 /* default number of NumberedArgumentState array */ + +#define TYPE_INT16 0 +#define TYPE_UINT16 1 +#define TYPE_INTN 2 +#define TYPE_UINTN 3 +#define TYPE_INT32 4 +#define TYPE_UINT32 5 +#define TYPE_INT64 6 +#define TYPE_UINT64 7 +#define TYPE_STRING 8 +#define TYPE_DOUBLE 9 +#define TYPE_INTSTR 10 +#define TYPE_UNISTRING 11 +#define TYPE_UNKNOWN 20 + +#define _LEFT 0x1 +#define _SIGNED 0x2 +#define _SPACED 0x4 +#define _ZEROS 0x8 +#define _NEG 0x10 + +#define ELEMENTS_OF(array_) (sizeof(array_) / sizeof(array_[0])) + +// Warning: if aDest isn't big enough this function returns the converted +// string in allocated memory which must be freed using PR_FREE(). +// May return nsnull if memory couldn't be allocated. +static PRUnichar* UTF8ToUCS2(const char *aSrc, PRUint32 aSrcLen, + PRUnichar* aDest, PRUint32 aDestLen) +{ + const char *in, *inend; + inend = aSrc + aSrcLen; + PRUnichar *out; + PRUint32 state; + PRUint32 ucs4; + // decide the length of the UCS2 first. + PRUint32 needLen = 0; + + for (in = aSrc, state = 0, ucs4 = 0; in < inend; in++) { + if (0 == state) { + if (0 == (0x80 & (*in))) { + needLen++; + } else if (0xC0 == (0xE0 & (*in))) { + needLen++; + state = 1; + } else if (0xE0 == (0xF0 & (*in))) { + needLen++; + state = 2; + } else if (0xF0 == (0xF8 & (*in))) { + needLen+=2; + state = 3; + } else if (0xF8 == (0xFC & (*in))) { + needLen+=2; + state = 4; + } else if (0xFC == (0xFE & (*in))) { + needLen+=2; + state = 5; + } else { + needLen++; + state = 0; + } + } else { + NS_ASSERTION((0x80 == (0xC0 & (*in))), "The input string is not in utf8"); + if(0x80 == (0xC0 & (*in))) { + state--; + } else { + state = 0; + } + } + } + needLen++; // add null termination. + + // allocates sufficient memory if aDest is not big enough. + if (needLen > aDestLen) { + aDest = (PRUnichar*)PR_MALLOC(sizeof(PRUnichar) * needLen); + } + if (nsnull == aDest) { + return nsnull; + } + out = aDest; + + for (in = aSrc, state = 0, ucs4 = 0; in < inend; in++) { + if (0 == state) { + if (0 == (0x80 & (*in))) { + // ASCII + *out++ = (PRUnichar)*in; + } else if (0xC0 == (0xE0 & (*in))) { + // 2 bytes UTF8 + ucs4 = (PRUint32)(*in); + ucs4 = (ucs4 << 6) & 0x000007C0L; + state=1; + } else if (0xE0 == (0xF0 & (*in))) { + ucs4 = (PRUint32)(*in); + ucs4 = (ucs4 << 12) & 0x0000F000L; + state=2; + } else if (0xF0 == (0xF8 & (*in))) { + ucs4 = (PRUint32)(*in); + ucs4 = (ucs4 << 18) & 0x001F0000L; + state=3; + } else if (0xF8 == (0xFC & (*in))) { + ucs4 = (PRUint32)(*in); + ucs4 = (ucs4 << 24) & 0x03000000L; + state=4; + } else if (0xFC == (0xFE & (*in))) { + ucs4 = (PRUint32)(*in); + ucs4 = (ucs4 << 30) & 0x40000000L; + state=5; + } else { + NS_ASSERTION(0, "The input string is not in utf8"); + state=0; + ucs4=0; + } + } else { + NS_ASSERTION((0x80 == (0xC0 & (*in))), "The input string is not in utf8"); + if (0x80 == (0xC0 & (*in))) { + PRUint32 tmp = (*in); + int shift = --state * 6; + tmp = (tmp << shift) & (0x0000003FL << shift); + ucs4 |= tmp; + if (0 == state) { + if (ucs4 >= 0x00010000) { + if (ucs4 >= 0x00110000) { + *out++ = 0xFFFD; + } else { + ucs4 -= 0x00010000; + *out++ = 0xD800 | (0x000003FF & (ucs4 >> 10)); + *out++ = 0xDC00 | (0x000003FF & ucs4); + } + } else { + *out++ = ucs4; + } + ucs4 = 0; + } + } else { + state = 0; + ucs4 = 0; + } + } + } + *out = 0x0000; + return aDest; +} + +/* +** Fill into the buffer using the data in src +*/ +static int fill2(SprintfState *ss, const PRUnichar *src, int srclen, + int width, int flags) +{ + PRUnichar space = ' '; + int rv; + + width -= srclen; + /* Right adjusting */ + if ((width > 0) && ((flags & _LEFT) == 0)) { + if (flags & _ZEROS) { + space = '0'; + } + while (--width >= 0) { + rv = (*ss->stuff)(ss, &space, 1); + if (rv < 0) { + return rv; + } + } + } + + /* Copy out the source data */ + rv = (*ss->stuff)(ss, src, srclen); + if (rv < 0) { + return rv; + } + + /* Left adjusting */ + if ((width > 0) && ((flags & _LEFT) != 0)) { + while (--width >= 0) { + rv = (*ss->stuff)(ss, &space, 1); + if (rv < 0) { + return rv; + } + } + } + return 0; +} + +/* +** Fill a number. The order is: optional-sign zero-filling conversion-digits +*/ +static int fill_n(SprintfState *ss, const PRUnichar *src, int srclen, + int width, int prec, int type, int flags) +{ + int zerowidth = 0; + int precwidth = 0; + int signwidth = 0; + int leftspaces = 0; + int rightspaces = 0; + int cvtwidth; + int rv; + PRUnichar sign; + PRUnichar space = ' '; + PRUnichar zero = '0'; + + if ((type & 1) == 0) { + if (flags & _NEG) { + sign = '-'; + signwidth = 1; + } else if (flags & _SIGNED) { + sign = '+'; + signwidth = 1; + } else if (flags & _SPACED) { + sign = ' '; + signwidth = 1; + } + } + cvtwidth = signwidth + srclen; + + if (prec > 0) { + if (prec > srclen) { + /* Need zero filling */ + precwidth = prec - srclen; + cvtwidth += precwidth; + } + } + + if ((flags & _ZEROS) && (prec < 0)) { + if (width > cvtwidth) { + /* Zero filling */ + zerowidth = width - cvtwidth; + cvtwidth += zerowidth; + } + } + + if (flags & _LEFT) { + if (width > cvtwidth) { + /* Space filling on the right (i.e. left adjusting) */ + rightspaces = width - cvtwidth; + } + } else { + if (width > cvtwidth) { + /* Space filling on the left (i.e. right adjusting) */ + leftspaces = width - cvtwidth; + } + } + while (--leftspaces >= 0) { + rv = (*ss->stuff)(ss, &space, 1); + if (rv < 0) { + return rv; + } + } + if (signwidth) { + rv = (*ss->stuff)(ss, &sign, 1); + if (rv < 0) { + return rv; + } + } + while (--precwidth >= 0) { + rv = (*ss->stuff)(ss, &space, 1); + if (rv < 0) { + return rv; + } + } + while (--zerowidth >= 0) { + rv = (*ss->stuff)(ss, &zero, 1); + if (rv < 0) { + return rv; + } + } + rv = (*ss->stuff)(ss, src, srclen); + if (rv < 0) { + return rv; + } + while (--rightspaces >= 0) { + rv = (*ss->stuff)(ss, &space, 1); + if (rv < 0) { + return rv; + } + } + return 0; +} + +/* +** Convert a long into its printable form +*/ +static int cvt_l(SprintfState *ss, long num, int width, int prec, + int radix, int type, int flags, const PRUnichar *hexp) +{ + PRUnichar cvtbuf[100]; + PRUnichar *cvt; + int digits; + + /* according to the man page this needs to happen */ + if ((prec == 0) && (num == 0)) { + return 0; + } + + /* + ** Converting decimal is a little tricky. In the unsigned case we + ** need to stop when we hit 10 digits. In the signed case, we can + ** stop when the number is zero. + */ + cvt = &cvtbuf[0] + ELEMENTS_OF(cvtbuf); + digits = 0; + while (num) { + int digit = (((unsigned long)num) % radix) & 0xF; + *--cvt = hexp[digit]; + digits++; + num = (long)(((unsigned long)num) / radix); + } + if (digits == 0) { + *--cvt = '0'; + digits++; + } + + /* + ** Now that we have the number converted without its sign, deal with + ** the sign and zero padding. + */ + return fill_n(ss, cvt, digits, width, prec, type, flags); +} + +/* +** Convert a 64-bit integer into its printable form +*/ +static int cvt_ll(SprintfState *ss, PRInt64 num, int width, int prec, + int radix, int type, int flags, const PRUnichar *hexp) +{ + PRUnichar cvtbuf[100]; + PRUnichar *cvt; + int digits; + PRInt64 rad; + + /* according to the man page this needs to happen */ + if ((prec == 0) && (LL_IS_ZERO(num))) { + return 0; + } + + /* + ** Converting decimal is a little tricky. In the unsigned case we + ** need to stop when we hit 10 digits. In the signed case, we can + ** stop when the number is zero. + */ + LL_I2L(rad, radix); + cvt = &cvtbuf[0] + ELEMENTS_OF(cvtbuf); + digits = 0; + while (!LL_IS_ZERO(num)) { + PRInt32 digit; + PRInt64 quot, rem; + LL_UDIVMOD(", &rem, num, rad); + LL_L2I(digit, rem); + *--cvt = hexp[digit & 0xf]; + digits++; + num = quot; + } + if (digits == 0) { + *--cvt = '0'; + digits++; + } + + /* + ** Now that we have the number converted without its sign, deal with + ** the sign and zero padding. + */ + return fill_n(ss, cvt, digits, width, prec, type, flags); +} + +/* +** Convert a double precision floating point number into its printable +** form. +*/ +static int cvt_f(SprintfState *ss, double d, int width, int prec, + const PRUnichar type, int flags) +{ + int mode = 2; + int decpt; + int sign; + char buf[256]; + char * bufp = buf; + int bufsz = 256; + char num[256]; + char * nump; + char * endnum; + int numdigits = 0; + char exp = 'e'; + + if (prec == -1) { + prec = 6; + } else if (prec > 50) { + // limit precision to avoid PR_dtoa bug 108335 + // and to prevent buffers overflows + prec = 50; + } + + switch (type) { + case 'f': + numdigits = prec; + mode = 3; + break; + case 'E': + exp = 'E'; + // no break + case 'e': + numdigits = prec + 1; + mode = 2; + break; + case 'G': + exp = 'E'; + // no break + case 'g': + if (prec == 0) { + prec = 1; + } + numdigits = prec; + mode = 2; + break; + default: + NS_ERROR("invalid type passed to cvt_f"); + } + + if (PR_dtoa(d, mode, numdigits, &decpt, &sign, &endnum, num, bufsz) == PR_FAILURE) { + buf[0] = '\0'; + return -1; + } + numdigits = endnum - num; + nump = num; + + if (sign) { + *bufp++ = '-'; + } else if (flags & _SIGNED) { + *bufp++ = '+'; + } + + if (decpt == 9999) { + while ((*bufp++ = *nump++)) { } + } else { + + switch (type) { + + case 'E': + case 'e': + + *bufp++ = *nump++; + if (prec > 0) { + *bufp++ = '.'; + while (*nump) { + *bufp++ = *nump++; + prec--; + } + while (prec-- > 0) { + *bufp++ = '0'; + } + } + *bufp++ = exp; + PR_snprintf(bufp, bufsz - (bufp - buf), "%+03d", decpt-1); + break; + + case 'f': + + if (decpt < 1) { + *bufp++ = '0'; + if (prec > 0) { + *bufp++ = '.'; + while (decpt++ && prec-- > 0) { + *bufp++ = '0'; + } + while (*nump && prec-- > 0) { + *bufp++ = *nump++; + } + while (prec-- > 0) { + *bufp++ = '0'; + } + } + } else { + while (*nump && decpt-- > 0) { + *bufp++ = *nump++; + } + while (decpt-- > 0) { + *bufp++ = '0'; + } + if (prec > 0) { + *bufp++ = '.'; + while (*nump && prec-- > 0) { + *bufp++ = *nump++; + } + while (prec-- > 0) { + *bufp++ = '0'; + } + } + } + *bufp = '\0'; + break; + + case 'G': + case 'g': + + if ((decpt < -3) || ((decpt - 1) >= prec)) { + *bufp++ = *nump++; + numdigits--; + if (numdigits > 0) { + *bufp++ = '.'; + while (*nump) { + *bufp++ = *nump++; + } + } + *bufp++ = exp; + PR_snprintf(bufp, bufsz - (bufp - buf), "%+03d", decpt-1); + } else { + if (decpt < 1) { + *bufp++ = '0'; + if (prec > 0) { + *bufp++ = '.'; + while (decpt++) { + *bufp++ = '0'; + } + while (*nump) { + *bufp++ = *nump++; + } + } + } else { + while (*nump && decpt-- > 0) { + *bufp++ = *nump++; + numdigits--; + } + while (decpt-- > 0) { + *bufp++ = '0'; + } + if (numdigits > 0) { + *bufp++ = '.'; + while (*nump) { + *bufp++ = *nump++; + } + } + } + *bufp = '\0'; + } + } + } + + PRUnichar rbuf[256]; + PRUnichar *rbufp = rbuf; + bufp = buf; + // cast to PRUnichar + while ((*rbufp++ = *bufp++)) { } + *rbufp = '\0'; + + return fill2(ss, rbuf, nsCRT::strlen(rbuf), width, flags); +} + +/* +** Convert a string into its printable form. "width" is the output +** width. "prec" is the maximum number of characters of "s" to output, +** where -1 means until NUL. +*/ +static int cvt_S(SprintfState *ss, const PRUnichar *s, int width, + int prec, int flags) +{ + int slen; + + if (prec == 0) { + return 0; + } + + /* Limit string length by precision value */ + slen = s ? nsCRT::strlen(s) : 6; + if (prec > 0) { + if (prec < slen) { + slen = prec; + } + } + + /* and away we go */ + NS_NAMED_LITERAL_STRING(nullstr, "(null)"); + + return fill2(ss, s ? s : nullstr.get(), slen, width, flags); +} + +/* +** Convert a string into its printable form. "width" is the output +** width. "prec" is the maximum number of characters of "s" to output, +** where -1 means until NUL. +*/ +static int cvt_s(SprintfState *ss, const char *s, int width, + int prec, int flags) +{ + // convert s from UTF8 to PRUnichar* + // Fix me !!! + PRUnichar buf[256]; + PRUnichar *retbuf = nsnull; + + if (s) { + retbuf = UTF8ToUCS2(s, strlen(s), buf, 256); + if(nsnull == retbuf) { + return -1; + } + } + int ret = cvt_S(ss, retbuf, width, prec, flags); + + if (retbuf != buf) { + PR_DELETE(retbuf); + } + return ret; +} + +/* +** BiuldArgArray stands for Numbered Argument list Sprintf +** for example, +** fmp = "%4$i, %2$d, %3s, %1d"; +** the number must start from 1, and no gap among them +*/ + +static struct NumArgState* BuildArgArray(const PRUnichar *fmt, + va_list ap, int * rv, + struct NumArgState * nasArray) +{ + int number = 0, cn = 0, i; + const PRUnichar* p; + PRUnichar c; + struct NumArgState* nas; + + /* + ** first pass: + ** detemine how many legal % I have got, then allocate space + */ + p = fmt; + *rv = 0; + i = 0; + while ((c = *p++) != 0) { + if (c != '%') { + continue; + } + /* skip %% case */ + if ((c = *p++) == '%') { + continue; + } + + while( c != 0 ){ + if (c > '9' || c < '0') { + /* numbered argument csae */ + if (c == '$') { + if (i > 0) { + *rv = -1; + return NULL; + } + number++; + break; + + } else { + /* non-numbered argument case */ + if (number > 0) { + *rv = -1; + return NULL; + } + i = 1; + break; + } + } + c = *p++; + } + } + + if (number == 0) { + return NULL; + } + + if (number > NAS_DEFAULT_NUM) { + nas = (struct NumArgState*)PR_MALLOC(number * sizeof(struct NumArgState)); + if (!nas) { + *rv = -1; + return NULL; + } + } else { + nas = nasArray; + } + + for (i = 0; i < number; i++) { + nas[i].type = TYPE_UNKNOWN; + } + + /* + ** second pass: + ** set nas[].type + */ + p = fmt; + while ((c = *p++) != 0) { + if (c != '%') { + continue; + } + c = *p++; + if (c == '%') { + continue; + } + cn = 0; + /* should imporve error check later */ + while (c && c != '$') { + cn = cn*10 + c - '0'; + c = *p++; + } + + if (!c || cn < 1 || cn > number) { + *rv = -1; + break; + } + + /* nas[cn] starts from 0, and make sure + nas[cn].type is not assigned */ + cn--; + if (nas[cn].type != TYPE_UNKNOWN) { + continue; + } + + c = *p++; + + /* width */ + if (c == '*') { + /* not supported feature, for the argument is not numbered */ + *rv = -1; + break; + } else { + while ((c >= '0') && (c <= '9')) { + c = *p++; + } + } + + /* precision */ + if (c == '.') { + c = *p++; + if (c == '*') { + /* not supported feature, for the argument is not numbered */ + *rv = -1; + break; + } else { + while ((c >= '0') && (c <= '9')) { + c = *p++; + } + } + } + + /* size */ + nas[cn].type = TYPE_INTN; + if (c == 'h') { + nas[cn].type = TYPE_INT16; + c = *p++; + } else if (c == 'L') { + /* XXX not quite sure here */ + nas[cn].type = TYPE_INT64; + c = *p++; + } else if (c == 'l') { + nas[cn].type = TYPE_INT32; + c = *p++; + if (c == 'l') { + nas[cn].type = TYPE_INT64; + c = *p++; + } + } + + /* format */ + switch (c) { + case 'd': + case 'c': + case 'i': + case 'o': + case 'u': + case 'x': + case 'X': + break; + + case 'e': + case 'f': + case 'g': + nas[cn].type = TYPE_DOUBLE; + break; + + case 'p': + /* XXX should use cpp */ + if (sizeof(void *) == sizeof(PRInt32)) { + nas[cn].type = TYPE_UINT32; + } else if (sizeof(void *) == sizeof(PRInt64)) { + nas[cn].type = TYPE_UINT64; + } else if (sizeof(void *) == sizeof(PRIntn)) { + nas[cn].type = TYPE_UINTN; + } else { + nas[cn].type = TYPE_UNKNOWN; + } + break; + + case 'C': + /* XXX not supported I suppose */ + PR_ASSERT(0); + nas[cn].type = TYPE_UNKNOWN; + break; + + case 'S': + nas[cn].type = TYPE_UNISTRING; + break; + + case 's': + nas[cn].type = TYPE_STRING; + break; + + case 'n': + nas[cn].type = TYPE_INTSTR; + break; + + default: + PR_ASSERT(0); + nas[cn].type = TYPE_UNKNOWN; + break; + } + + /* get a legal para. */ + if (nas[cn].type == TYPE_UNKNOWN) { + *rv = -1; + break; + } + } + + + /* + ** third pass + ** fill the nas[cn].ap + */ + if (*rv < 0) { + if( nas != nasArray ) { + PR_DELETE(nas); + } + return NULL; + } + + cn = 0; + while (cn < number) { + if (nas[cn].type == TYPE_UNKNOWN) { + cn++; + continue; + } + + VARARGS_ASSIGN(nas[cn].ap, ap); + + switch (nas[cn].type) { + case TYPE_INT16: + case TYPE_UINT16: + case TYPE_INTN: + case TYPE_UINTN: (void)va_arg(ap, PRIntn); break; + + case TYPE_INT32: (void)va_arg(ap, PRInt32); break; + + case TYPE_UINT32: (void)va_arg(ap, PRUint32); break; + + case TYPE_INT64: (void)va_arg(ap, PRInt64); break; + + case TYPE_UINT64: (void)va_arg(ap, PRUint64); break; + + case TYPE_STRING: (void)va_arg(ap, char*); break; + + case TYPE_INTSTR: (void)va_arg(ap, PRIntn*); break; + + case TYPE_DOUBLE: (void)va_arg(ap, double); break; + + case TYPE_UNISTRING: (void)va_arg(ap, PRUnichar*); break; + + default: + if( nas != nasArray ) { + PR_DELETE( nas ); + } + *rv = -1; + return NULL; + } + cn++; + } + return nas; +} + +/* +** The workhorse sprintf code. +*/ +static int dosprintf(SprintfState *ss, const PRUnichar *fmt, va_list ap) +{ + PRUnichar c; + int flags, width, prec, radix, type; + union { + PRUnichar ch; + int i; + long l; + PRInt64 ll; + double d; + const char *s; + const PRUnichar *S; + int *ip; + } u; + PRUnichar space = ' '; + const PRUnichar *fmt0; + + nsAutoString hex; + hex.AssignLiteral("0123456789abcdef"); + + nsAutoString HEX; + HEX.AssignLiteral("0123456789ABCDEF"); + + const PRUnichar *hexp; + int rv, i; + struct NumArgState* nas = NULL; + struct NumArgState nasArray[NAS_DEFAULT_NUM]; + /* in "%4$.2f" dolPt will point to . */ + const PRUnichar* dolPt = NULL; + + + /* + ** build an argument array, IF the fmt is numbered argument + ** list style, to contain the Numbered Argument list pointers + */ + nas = BuildArgArray (fmt, ap, &rv, nasArray); + if (rv < 0) { + /* the fmt contains error Numbered Argument format, jliu@netscape.com */ + PR_ASSERT(0); + return rv; + } + + while ((c = *fmt++) != 0) { + if (c != '%') { + rv = (*ss->stuff)(ss, fmt - 1, 1); + if (rv < 0) { + return rv; + } + continue; + } + fmt0 = fmt - 1; + + /* + ** Gobble up the % format string. Hopefully we have handled all + ** of the strange cases! + */ + flags = 0; + c = *fmt++; + if (c == '%') { + /* quoting a % with %% */ + rv = (*ss->stuff)(ss, fmt - 1, 1); + if (rv < 0) { + return rv; + } + continue; + } + + if (nas != NULL) { + /* the fmt contains the Numbered Arguments feature */ + i = 0; + /* should imporve error check later */ + while (c && c != '$') { + i = (i * 10) + (c - '0'); + c = *fmt++; + } + + if (nas[i-1].type == TYPE_UNKNOWN) { + if (nas && (nas != nasArray)) { + PR_DELETE(nas); + } + return -1; + } + + ap = nas[i-1].ap; + dolPt = fmt; + c = *fmt++; + } + + /* + * Examine optional flags. Note that we do not implement the + * '#' flag of sprintf(). The ANSI C spec. of the '#' flag is + * somewhat ambiguous and not ideal, which is perhaps why + * the various sprintf() implementations are inconsistent + * on this feature. + */ + while ((c == '-') || (c == '+') || (c == ' ') || (c == '0')) { + if (c == '-') flags |= _LEFT; + if (c == '+') flags |= _SIGNED; + if (c == ' ') flags |= _SPACED; + if (c == '0') flags |= _ZEROS; + c = *fmt++; + } + if (flags & _SIGNED) flags &= ~_SPACED; + if (flags & _LEFT) flags &= ~_ZEROS; + + /* width */ + if (c == '*') { + c = *fmt++; + width = va_arg(ap, int); + } else { + width = 0; + while ((c >= '0') && (c <= '9')) { + width = (width * 10) + (c - '0'); + c = *fmt++; + } + } + + /* precision */ + prec = -1; + if (c == '.') { + c = *fmt++; + if (c == '*') { + c = *fmt++; + prec = va_arg(ap, int); + } else { + prec = 0; + while ((c >= '0') && (c <= '9')) { + prec = (prec * 10) + (c - '0'); + c = *fmt++; + } + } + } + + /* size */ + type = TYPE_INTN; + if (c == 'h') { + type = TYPE_INT16; + c = *fmt++; + } else if (c == 'L') { + /* XXX not quite sure here */ + type = TYPE_INT64; + c = *fmt++; + } else if (c == 'l') { + type = TYPE_INT32; + c = *fmt++; + if (c == 'l') { + type = TYPE_INT64; + c = *fmt++; + } + } + + /* format */ + hexp = hex.get(); + switch (c) { + case 'd': + case 'i': /* decimal/integer */ + radix = 10; + goto fetch_and_convert; + + case 'o': /* octal */ + radix = 8; + type |= 1; + goto fetch_and_convert; + + case 'u': /* unsigned decimal */ + radix = 10; + type |= 1; + goto fetch_and_convert; + + case 'x': /* unsigned hex */ + radix = 16; + type |= 1; + goto fetch_and_convert; + + case 'X': /* unsigned HEX */ + radix = 16; + hexp = HEX.get(); + type |= 1; + goto fetch_and_convert; + + fetch_and_convert: + switch (type) { + case TYPE_INT16: + u.l = va_arg(ap, int); + if (u.l < 0) { + u.l = -u.l; + flags |= _NEG; + } + goto do_long; + case TYPE_UINT16: + u.l = va_arg(ap, int) & 0xffff; + goto do_long; + case TYPE_INTN: + u.l = va_arg(ap, int); + if (u.l < 0) { + u.l = -u.l; + flags |= _NEG; + } + goto do_long; + case TYPE_UINTN: + u.l = (long)va_arg(ap, unsigned int); + goto do_long; + + case TYPE_INT32: + u.l = va_arg(ap, PRInt32); + if (u.l < 0) { + u.l = -u.l; + flags |= _NEG; + } + goto do_long; + case TYPE_UINT32: + u.l = (long)va_arg(ap, PRUint32); + do_long: + rv = cvt_l(ss, u.l, width, prec, radix, type, flags, hexp); + if (rv < 0) { + return rv; + } + break; + + case TYPE_INT64: + u.ll = va_arg(ap, PRInt64); + if (!LL_GE_ZERO(u.ll)) { + LL_NEG(u.ll, u.ll); + flags |= _NEG; + } + goto do_longlong; + case TYPE_UINT64: + u.ll = va_arg(ap, PRUint64); + do_longlong: + rv = cvt_ll(ss, u.ll, width, prec, radix, type, flags, hexp); + if (rv < 0) { + return rv; + } + break; + } + break; + + case 'e': + case 'E': + case 'f': + case 'g': + case 'G': + u.d = va_arg(ap, double); + rv = cvt_f(ss, u.d, width, prec, c, flags); + if (rv < 0) { + return rv; + } + break; + + case 'c': + u.ch = va_arg(ap, int); + if ((flags & _LEFT) == 0) { + while (width-- > 1) { + rv = (*ss->stuff)(ss, &space, 1); + if (rv < 0) { + return rv; + } + } + } + rv = (*ss->stuff)(ss, &u.ch, 1); + if (rv < 0) { + return rv; + } + if (flags & _LEFT) { + while (width-- > 1) { + rv = (*ss->stuff)(ss, &space, 1); + if (rv < 0) { + return rv; + } + } + } + break; + + case 'p': + if (sizeof(void *) == sizeof(PRInt32)) { + type = TYPE_UINT32; + } else if (sizeof(void *) == sizeof(PRInt64)) { + type = TYPE_UINT64; + } else if (sizeof(void *) == sizeof(int)) { + type = TYPE_UINTN; + } else { + PR_ASSERT(0); + break; + } + radix = 16; + goto fetch_and_convert; + +#if 0 + case 'C': + /* XXX not supported I suppose */ + PR_ASSERT(0); + break; +#endif + + case 'S': + u.S = va_arg(ap, const PRUnichar*); + rv = cvt_S(ss, u.S, width, prec, flags); + if (rv < 0) { + return rv; + } + break; + + case 's': + u.s = va_arg(ap, const char*); + rv = cvt_s(ss, u.s, width, prec, flags); + if (rv < 0) { + return rv; + } + break; + + case 'n': + u.ip = va_arg(ap, int*); + if (u.ip) { + *u.ip = ss->cur - ss->base; + } + break; + + default: + /* Not a % token after all... skip it */ +#if 0 + PR_ASSERT(0); +#endif + PRUnichar perct = '%'; + rv = (*ss->stuff)(ss, &perct, 1); + if (rv < 0) { + return rv; + } + rv = (*ss->stuff)(ss, fmt - 1, 1); + if (rv < 0) { + return rv; + } + } + } + + /* Stuff trailing NUL */ + PRUnichar null = '\0'; + + rv = (*ss->stuff)(ss, &null, 1); + + if( nas && ( nas != nasArray ) ){ + PR_DELETE( nas ); + } + + return rv; +} + +/************************************************************************/ + +static int +StringStuff(SprintfState* ss, const PRUnichar* sp, PRUint32 len) +{ + ptrdiff_t off = ss->cur - ss->base; + + nsAString* str = NS_STATIC_CAST(nsAString*,ss->stuffclosure); + str->Append(sp, len); + + // we can assume contiguous storage + nsAString::iterator begin; + str->BeginWriting(begin); + ss->base = begin.get(); + ss->cur = ss->base + off; + + return 0; +} + +/* +** Stuff routine that automatically grows the malloc'd output buffer +** before it overflows. +*/ +static int GrowStuff(SprintfState *ss, const PRUnichar *sp, PRUint32 len) +{ + ptrdiff_t off; + PRUnichar *newbase; + PRUint32 newlen; + + off = ss->cur - ss->base; + if (off + len >= ss->maxlen) { + /* Grow the buffer */ + newlen = ss->maxlen + ((len > 32) ? len : 32); + if (ss->base) { + newbase = (PRUnichar*) PR_REALLOC(ss->base, newlen*sizeof(PRUnichar)); + } else { + newbase = (PRUnichar*) PR_MALLOC(newlen*sizeof(PRUnichar)); + } + if (!newbase) { + /* Ran out of memory */ + return -1; + } + ss->base = newbase; + ss->maxlen = newlen; + ss->cur = ss->base + off; + } + + /* Copy data */ + while (len) { + --len; + *ss->cur++ = *sp++; + } + PR_ASSERT((PRUint32)(ss->cur - ss->base) <= ss->maxlen); + return 0; +} + +/* +** sprintf into a malloc'd buffer +*/ +PRUnichar * nsTextFormatter::smprintf(const PRUnichar *fmt, ...) +{ + va_list ap; + PRUnichar *rv; + + va_start(ap, fmt); + rv = nsTextFormatter::vsmprintf(fmt, ap); + va_end(ap); + return rv; +} + +PRUint32 nsTextFormatter::ssprintf(nsAString& out, const PRUnichar* fmt, ...) +{ + va_list ap; + PRUint32 rv; + + va_start(ap, fmt); + rv = nsTextFormatter::vssprintf(out, fmt, ap); + va_end(ap); + return rv; +} + +/* +** Free memory allocated, for the caller, by smprintf +*/ +void nsTextFormatter::smprintf_free(PRUnichar *mem) +{ + PR_DELETE(mem); +} + +PRUint32 nsTextFormatter::vssprintf(nsAString& out, const PRUnichar* fmt, va_list ap) +{ + SprintfState ss; + ss.stuff = StringStuff; + ss.base = 0; + ss.cur = 0; + ss.maxlen = 0; + ss.stuffclosure = &out; + + out.Truncate(); + int n = dosprintf(&ss, fmt, ap); + return n ? n - 1 : n; +} + +PRUnichar * nsTextFormatter::vsmprintf(const PRUnichar *fmt, va_list ap) +{ + SprintfState ss; + int rv; + + ss.stuff = GrowStuff; + ss.base = 0; + ss.cur = 0; + ss.maxlen = 0; + rv = dosprintf(&ss, fmt, ap); + if (rv < 0) { + if (ss.base) { + PR_DELETE(ss.base); + } + return 0; + } + return ss.base; +} + +/* +** Stuff routine that discards overflow data +*/ +static int LimitStuff(SprintfState *ss, const PRUnichar *sp, PRUint32 len) +{ + PRUint32 limit = ss->maxlen - (ss->cur - ss->base); + + if (len > limit) { + len = limit; + } + while (len) { + --len; + *ss->cur++ = *sp++; + } + return 0; +} + +/* +** sprintf into a fixed size buffer. Make sure there is a NUL at the end +** when finished. +*/ +PRUint32 nsTextFormatter::snprintf(PRUnichar *out, PRUint32 outlen, const PRUnichar *fmt, ...) +{ + va_list ap; + PRUint32 rv; + + PR_ASSERT((PRInt32)outlen > 0); + if ((PRInt32)outlen <= 0) { + return 0; + } + + va_start(ap, fmt); + rv = nsTextFormatter::vsnprintf(out, outlen, fmt, ap); + va_end(ap); + return rv; +} + +PRUint32 nsTextFormatter::vsnprintf(PRUnichar *out, PRUint32 outlen,const PRUnichar *fmt, + va_list ap) +{ + SprintfState ss; + PRUint32 n; + + PR_ASSERT((PRInt32)outlen > 0); + if ((PRInt32)outlen <= 0) { + return 0; + } + + ss.stuff = LimitStuff; + ss.base = out; + ss.cur = out; + ss.maxlen = outlen; + (void) dosprintf(&ss, fmt, ap); + + /* If we added chars, and we didn't append a null, do it now. */ + if( (ss.cur != ss.base) && (*(ss.cur - 1) != '\0') ) + *(--ss.cur) = '\0'; + + n = ss.cur - ss.base; + return n ? n - 1 : n; +} + +PRUnichar * nsTextFormatter::sprintf_append(PRUnichar *last, const PRUnichar *fmt, ...) +{ + va_list ap; + PRUnichar *rv; + + va_start(ap, fmt); + rv = nsTextFormatter::vsprintf_append(last, fmt, ap); + va_end(ap); + return rv; +} + +PRUnichar * nsTextFormatter::vsprintf_append(PRUnichar *last, const PRUnichar *fmt, va_list ap) +{ + SprintfState ss; + int rv; + + ss.stuff = GrowStuff; + if (last) { + int lastlen = nsCRT::strlen(last); + ss.base = last; + ss.cur = last + lastlen; + ss.maxlen = lastlen; + } else { + ss.base = 0; + ss.cur = 0; + ss.maxlen = 0; + } + rv = dosprintf(&ss, fmt, ap); + if (rv < 0) { + if (ss.base) { + PR_DELETE(ss.base); + } + return 0; + } + return ss.base; +} +#ifdef DEBUG +PRBool nsTextFormatter::SelfTest() +{ + PRBool passed = PR_TRUE ; + nsAutoString fmt(NS_LITERAL_STRING("%3$s %4$S %1$d %2$d")); + + char utf8[] = "Hello"; + PRUnichar ucs2[]={'W', 'o', 'r', 'l', 'd', 0x4e00, 0xAc00, 0xFF45, 0x0103}; + int d=3; + + + PRUnichar buf[256]; + int ret; + ret = nsTextFormatter::snprintf(buf, 256, fmt.get(), d, 333, utf8, ucs2); + printf("ret = %d\n", ret); + nsAutoString out(buf); + printf("%s \n", NS_LossyConvertUCS2toASCII(out).get()); + const PRUnichar *uout = out.get(); + for(PRUint32 i=0;i +#include +#include "nscore.h" +#include "nsAString.h" + + +class NS_COM nsTextFormatter { + +public: + +/* +** sprintf into a fixed size buffer. Guarantees that a NUL is at the end +** of the buffer. Returns the length of the written output, NOT including +** the NUL, or (PRUint32)-1 if an error occurs. +*/ +static PRUint32 snprintf(PRUnichar *out, PRUint32 outlen, const PRUnichar *fmt, ...); + +/* +** sprintf into a PR_MALLOC'd buffer. Return a pointer to the malloc'd +** buffer on success, NULL on failure. Call "smprintf_free" to release +** the memory returned. +*/ +static PRUnichar* smprintf(const PRUnichar *fmt, ...); + + +static PRUint32 ssprintf(nsAString& out, const PRUnichar* fmt, ...); +/* +** Free the memory allocated, for the caller, by smprintf +*/ +static void smprintf_free(PRUnichar *mem); + +/* +** "append" sprintf into a PR_MALLOC'd buffer. "last" is the last value of +** the PR_MALLOC'd buffer. sprintf will append data to the end of last, +** growing it as necessary using realloc. If last is NULL, PR_sprintf_append +** will allocate the initial string. The return value is the new value of +** last for subsequent calls, or NULL if there is a malloc failure. +*/ +static PRUnichar* sprintf_append(PRUnichar *last, const PRUnichar *fmt, ...); + +/* +** va_list forms of the above. +*/ +static PRUint32 vsnprintf(PRUnichar *out, PRUint32 outlen, const PRUnichar *fmt, va_list ap); +static PRUnichar* vsmprintf(const PRUnichar *fmt, va_list ap); +static PRUint32 vssprintf(nsAString& out, const PRUnichar *fmt, va_list ap); +static PRUnichar* vsprintf_append(PRUnichar *last, const PRUnichar *fmt, va_list ap); + +#ifdef DEBUG +static PRBool SelfTest(); +#endif + + +}; + +#endif /* nsTextFormatter_h___ */ diff --git a/src/libs/xpcom18a4/xpcom/ds/nsTime.h b/src/libs/xpcom18a4/xpcom/ds/nsTime.h new file mode 100644 index 00000000..f5c3a0ab --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsTime.h @@ -0,0 +1,143 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +#ifndef nsTime_h__ +#define nsTime_h__ + +#include "prtime.h" +#include "nsInt64.h" +#include "nscore.h" + +/** + * This class encapsulates full 64-bit time functionality and + * provides simple arithmetic and conversion operations. + */ + +// If you ever decide that you need to add a non-inline method to this +// class, be sure to change the class declaration to "class NS_BASE +// nsTime". + +class nsTime : public nsInt64 +{ +public: + /** + * Construct the current time. + */ + nsTime(void) : nsInt64(PR_Now()) { + } + + /** + * Construct the time from a string. + */ + nsTime(const char* dateStr, PRBool defaultToGMT) { + PRInt64 theTime; + PRStatus status = PR_ParseTimeString(dateStr, defaultToGMT, &theTime); + if (status == PR_SUCCESS) + mValue = theTime; + else + mValue = LL_ZERO; + } + + /** + * Construct a time from a PRTime. + */ + nsTime(const PRTime aTime) : nsInt64(aTime) { + } + + /** + * Construct a time from a 64-bit value. + */ + nsTime(const nsInt64& aTime) : nsInt64(aTime) { + } + + /** + * Construct a time from another time. + */ + nsTime(const nsTime& aTime) : nsInt64(aTime.mValue) { + } + + // ~nsTime(void) -- XXX destructor unnecessary + + /** + * Assign one time to another. + */ + const nsTime& operator =(const nsTime& aTime) { + mValue = aTime.mValue; + return *this; + } + + /** + * Convert a nsTime object to a PRTime + */ + operator PRTime(void) const { + return mValue; + } +}; + +/** + * Determine if one time is strictly less than another + */ +inline const PRBool +operator <(const nsTime& aTime1, const nsTime& aTime2) { + return aTime1.mValue < aTime2.mValue; +} + +/** + * Determine if one time is less than or equal to another + */ +inline const PRBool +operator <=(const nsTime& aTime1, const nsTime& aTime2) { + return aTime1.mValue <= aTime2.mValue; +} + +/** + * Determine if one time is strictly greater than another + */ +inline const PRBool +operator >(const nsTime& aTime1, const nsTime& aTime2) { + return aTime1.mValue > aTime2.mValue; +} + +/** + * Determine if one time is greater than or equal to another + */ +inline const PRBool +operator >=(const nsTime& aTime1, const nsTime& aTime2) { + return aTime1.mValue >= aTime2.mValue; +} + +#endif // nsTime_h__ diff --git a/src/libs/xpcom18a4/xpcom/ds/nsTimelineService.cpp b/src/libs/xpcom18a4/xpcom/ds/nsTimelineService.cpp new file mode 100644 index 00000000..4974f562 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsTimelineService.cpp @@ -0,0 +1,613 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsTimelineService.h" +#include "prlong.h" +#include "prprf.h" +#include "prenv.h" +#include "plhash.h" +#include "prlock.h" +#include "prinit.h" +#include "prinrval.h" +#include "prthread.h" + +#ifdef MOZ_TIMELINE + +#define MAXINDENT 20 + +#ifdef XP_MAC +static PRIntervalTime initInterval = 0; +#endif + +static PRFileDesc *timelineFD = PR_STDERR; +static PRBool gTimelineDisabled = PR_TRUE; + +// Notes about threading: +// We avoid locks as we always use thread-local-storage. +// This means every other thread has its own private copy of +// data, and this thread can't re-enter (as our implemenation +// doesn't call back out anywhere). Thus, we can avoid locks! +// TLS index +static const PRUintn BAD_TLS_INDEX = (PRUintn) -1; +static PRUintn gTLSIndex = BAD_TLS_INDEX; + +class TimelineThreadData { +public: + TimelineThreadData() : initTime(0), indent(0), + disabled(PR_TRUE), timers(nsnull) {} + ~TimelineThreadData() {if (timers) PL_HashTableDestroy(timers);} + PRTime initTime; + PRHashTable *timers; + int indent; + PRBool disabled; +}; + +/* Implementation file */ +NS_IMPL_THREADSAFE_ISUPPORTS1(nsTimelineService, nsITimelineService) + +static PRTime Now(void); + +/* + * Timer structure stored in a hash table to keep track of named + * timers. + */ +class nsTimelineServiceTimer { + public: + nsTimelineServiceTimer(); + ~nsTimelineServiceTimer(); + void start(); + + /* + * Caller passes in "now" rather than having us calculate it so + * that we can avoid including timer overhead in the time being + * measured. + */ + void stop(PRTime now); + void reset(); + PRTime getAccum(); + PRTime getAccum(PRTime now); + + private: + PRTime mAccum; + PRTime mStart; + PRInt32 mRunning; + PRThread *mOwnerThread; // only used for asserts - could be #if MOZ_DEBUG +}; + +#define TIMER_CHECK_OWNER() \ + NS_ABORT_IF_FALSE(PR_GetCurrentThread() == mOwnerThread, \ + "Timer used by non-owning thread") + + +nsTimelineServiceTimer::nsTimelineServiceTimer() +: mAccum(LL_ZERO), mStart(LL_ZERO), mRunning(0), + mOwnerThread(PR_GetCurrentThread()) +{ +} + +nsTimelineServiceTimer::~nsTimelineServiceTimer() +{ +} + +void nsTimelineServiceTimer::start() +{ + TIMER_CHECK_OWNER(); + if (!mRunning) { + mStart = Now(); + } + mRunning++; +} + +void nsTimelineServiceTimer::stop(PRTime now) +{ + TIMER_CHECK_OWNER(); + mRunning--; + if (mRunning == 0) { + PRTime delta, accum; + LL_SUB(delta, now, mStart); + LL_ADD(accum, mAccum, delta); + mAccum = accum; + } +} + +void nsTimelineServiceTimer::reset() +{ + TIMER_CHECK_OWNER(); + mStart = 0; + mAccum = 0; +} + +PRTime nsTimelineServiceTimer::getAccum() +{ + TIMER_CHECK_OWNER(); + PRTime accum; + + if (!mRunning) { + accum = mAccum; + } else { + PRTime delta; + LL_SUB(delta, Now(), mStart); + LL_ADD(accum, mAccum, delta); + } + return accum; +} + +PRTime nsTimelineServiceTimer::getAccum(PRTime now) +{ + TIMER_CHECK_OWNER(); + PRTime accum; + + if (!mRunning) { + accum = mAccum; + } else { + PRTime delta; + LL_SUB(delta, now, mStart); + LL_ADD(accum, mAccum, delta); + } + return accum; +} + +#ifdef XP_MAC +/* + * PR_Now() on the Mac only gives us a resolution of seconds. Using + * PR_IntervalNow() gives us better resolution. with the drawback that + * the timeline is only good for about six hours. + * + * PR_IntervalNow() occasionally exhibits discontinuities on Windows, + * so we only use it on the Mac. Bleah! + */ +static PRTime Now(void) +{ + PRIntervalTime numTicks = PR_IntervalNow() - initInterval; + PRTime now; + LL_ADD(now, initTime, PR_IntervalToMilliseconds(numTicks) * 1000); + return now; +} +#else +static PRTime Now(void) +{ + return PR_Now(); +} +#endif + +static TimelineThreadData *GetThisThreadData() +{ + NS_ABORT_IF_FALSE(gTLSIndex!=BAD_TLS_INDEX, "Our TLS not initialized"); + TimelineThreadData *new_data = nsnull; + TimelineThreadData *data = (TimelineThreadData *)PR_GetThreadPrivate(gTLSIndex); + if (data == nsnull) { + // First request for this thread - allocate it. + new_data = new TimelineThreadData(); + if (!new_data) + goto done; + + // Fill it + new_data->timers = PL_NewHashTable(100, PL_HashString, PL_CompareStrings, + PL_CompareValues, NULL, NULL); + if (new_data->timers==NULL) + goto done; + new_data->initTime = PR_Now(); + NS_WARN_IF_FALSE(!gTimelineDisabled, + "Why are we creating new state when disabled?"); + new_data->disabled = PR_FALSE; + data = new_data; + new_data = nsnull; + PR_SetThreadPrivate(gTLSIndex, data); + } +done: + if (new_data) // eeek - error during creation! + delete new_data; + NS_WARN_IF_FALSE(data, "TimelineService could not get thread-local data"); + return data; +} + +extern "C" { + static void ThreadDestruct (void *data); + static PRStatus TimelineInit(void); +}; + +void ThreadDestruct( void *data ) +{ + if (data) + delete (TimelineThreadData *)data; +} + +/* +* PRCallOnceFN that initializes stuff for the timing service. +*/ +static PRCallOnceType initonce; + +PRStatus TimelineInit(void) +{ + char *timeStr; + char *fileName; + PRInt32 secs, msecs; + PRFileDesc *fd; + PRInt64 tmp1, tmp2; + + PRStatus status = PR_NewThreadPrivateIndex( &gTLSIndex, ThreadDestruct ); + NS_WARN_IF_FALSE(status==0, "TimelineService could not allocate TLS storage."); + + timeStr = PR_GetEnv("NS_TIMELINE_INIT_TIME"); +#ifdef XP_MAC + initInterval = PR_IntervalNow(); +#endif + // NS_TIMELINE_INIT_TIME only makes sense for the main thread, so if it + // exists, set it there. If not, let normal thread management code take + // care of setting the init time. + if (timeStr != NULL && 2 == PR_sscanf(timeStr, "%d.%d", &secs, &msecs)) { + PRTime &initTime = GetThisThreadData()->initTime; + LL_MUL(tmp1, (PRInt64)secs, 1000000); + LL_MUL(tmp2, (PRInt64)msecs, 1000); + LL_ADD(initTime, tmp1, tmp2); +#ifdef XP_MAC + initInterval -= PR_MicrosecondsToInterval( + (PRUint32)(PR_Now() - initTime)); +#endif + } + // Get the log file. +#ifdef XP_MAC + fileName = "timeline.txt"; +#else + fileName = PR_GetEnv("NS_TIMELINE_LOG_FILE"); +#endif + if (fileName != NULL + && (fd = PR_Open(fileName, PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE, + 0666)) != NULL) { + timelineFD = fd; + PR_fprintf(fd, + "NOTE: due to asynchrony, the indentation that you see does" + " not necessarily correspond to nesting in the code.\n\n"); + } + + // Runtime disable of timeline + if (PR_GetEnv("NS_TIMELINE_ENABLE")) + gTimelineDisabled = PR_FALSE; + return PR_SUCCESS; +} + +static void ParseTime(PRTime tm, PRInt32& secs, PRInt32& msecs) +{ + PRTime llsecs, llmsecs, tmp; + + LL_DIV(llsecs, tm, 1000000); + LL_MOD(tmp, tm, 1000000); + LL_DIV(llmsecs, tmp, 1000); + + LL_L2I(secs, llsecs); + LL_L2I(msecs, llmsecs); +} + +static char *Indent(char *buf) +{ + int &indent = GetThisThreadData()->indent; + int amount = indent; + if (amount > MAXINDENT) { + amount = MAXINDENT; + } + if (amount < 0) { + amount = 0; + indent = 0; + PR_Write(timelineFD, "indent underflow!\n", 18); + } + while (amount--) { + *buf++ = ' '; + } + return buf; +} + +static void PrintTime(PRTime tm, const char *text, va_list args) +{ + PRInt32 secs, msecs; + char pbuf[550], *pc, tbuf[550]; + + ParseTime(tm, secs, msecs); + + // snprintf/write rather than fprintf because we don't want + // messages from multiple threads to garble one another. + pc = Indent(pbuf); + PR_vsnprintf(pc, sizeof pbuf - (pc - pbuf), text, args); + PR_snprintf(tbuf, sizeof tbuf, "%05d.%03d (%08p): %s\n", + secs, msecs, PR_GetCurrentThread(), pbuf); + PR_Write(timelineFD, tbuf, strlen(tbuf)); +} + +/* + * Make this public if we need it. + */ +static nsresult NS_TimelineMarkV(const char *text, va_list args) +{ + PRTime elapsed,tmp; + + PR_CallOnce(&initonce, TimelineInit); + + TimelineThreadData *thread = GetThisThreadData(); + + tmp = Now(); + LL_SUB(elapsed, tmp, thread->initTime); + + PrintTime(elapsed, text, args); + + return NS_OK; +} + +PR_IMPLEMENT(nsresult) NS_TimelineForceMark(const char *text, ...) +{ + va_list args; + va_start(args, text); + NS_TimelineMarkV(text, args); + va_end(args); + + return NS_OK; +} + +PR_IMPLEMENT(nsresult) NS_TimelineMark(const char *text, ...) +{ + va_list args; + + PR_CallOnce(&initonce, TimelineInit); + + if (gTimelineDisabled) + return NS_ERROR_NOT_AVAILABLE; + + TimelineThreadData *thread = GetThisThreadData(); + + if (thread->disabled) + return NS_ERROR_NOT_AVAILABLE; + + va_start(args, text); + NS_TimelineMarkV(text, args); + va_end(args); + + return NS_OK; +} + +PR_IMPLEMENT(nsresult) NS_TimelineStartTimer(const char *timerName) +{ + PR_CallOnce(&initonce, TimelineInit); + + if (gTimelineDisabled) + return NS_ERROR_NOT_AVAILABLE; + + TimelineThreadData *thread = GetThisThreadData(); + + if (thread->timers == NULL) + return NS_ERROR_FAILURE; + if (thread->disabled) + return NS_ERROR_NOT_AVAILABLE; + + nsTimelineServiceTimer *timer + = (nsTimelineServiceTimer *)PL_HashTableLookup(thread->timers, timerName); + if (timer == NULL) { + timer = new nsTimelineServiceTimer; + if (!timer) + return NS_ERROR_OUT_OF_MEMORY; + + PL_HashTableAdd(thread->timers, timerName, timer); + } + timer->start(); + return NS_OK; +} + +PR_IMPLEMENT(nsresult) NS_TimelineStopTimer(const char *timerName) +{ + if (gTimelineDisabled) + return NS_ERROR_NOT_AVAILABLE; + /* + * Strange-looking now/timer->stop() interaction is to avoid + * including time spent in TLS and PL_HashTableLookup in the + * timer. + */ + PRTime now = Now(); + + TimelineThreadData *thread = GetThisThreadData(); + if (thread->timers == NULL) + return NS_ERROR_FAILURE; + if (thread->disabled) + return NS_ERROR_NOT_AVAILABLE; + nsTimelineServiceTimer *timer + = (nsTimelineServiceTimer *)PL_HashTableLookup(thread->timers, timerName); + if (timer == NULL) { + return NS_ERROR_FAILURE; + } + + timer->stop(now); + + return NS_OK; +} + +PR_IMPLEMENT(nsresult) NS_TimelineMarkTimer(const char *timerName, const char *str) +{ + PR_CallOnce(&initonce, TimelineInit); + + if (gTimelineDisabled) + return NS_ERROR_NOT_AVAILABLE; + + TimelineThreadData *thread = GetThisThreadData(); + if (thread->timers == NULL) + return NS_ERROR_FAILURE; + if (thread->disabled) + return NS_ERROR_NOT_AVAILABLE; + nsTimelineServiceTimer *timer + = (nsTimelineServiceTimer *)PL_HashTableLookup(thread->timers, timerName); + if (timer == NULL) { + return NS_ERROR_FAILURE; + } + PRTime accum = timer->getAccum(); + + char buf[500]; + PRInt32 sec, msec; + ParseTime(accum, sec, msec); + if (!str) + PR_snprintf(buf, sizeof buf, "%s total: %d.%03d", + timerName, sec, msec); + else + PR_snprintf(buf, sizeof buf, "%s total: %d.%03d (%s)", + timerName, sec, msec, str); + NS_TimelineMark(buf); + + return NS_OK; +} + +PR_IMPLEMENT(nsresult) NS_TimelineResetTimer(const char *timerName) +{ + if (gTimelineDisabled) + return NS_ERROR_NOT_AVAILABLE; + + TimelineThreadData *thread = GetThisThreadData(); + if (thread->timers == NULL) + return NS_ERROR_FAILURE; + if (thread->disabled) + return NS_ERROR_NOT_AVAILABLE; + nsTimelineServiceTimer *timer + = (nsTimelineServiceTimer *)PL_HashTableLookup(thread->timers, timerName); + if (timer == NULL) { + return NS_ERROR_FAILURE; + } + + timer->reset(); + return NS_OK; +} + +PR_IMPLEMENT(nsresult) NS_TimelineIndent() +{ + if (gTimelineDisabled) + return NS_ERROR_NOT_AVAILABLE; + + TimelineThreadData *thread = GetThisThreadData(); + if (thread->disabled) + return NS_ERROR_NOT_AVAILABLE; + thread->indent++; + return NS_OK; +} + +PR_IMPLEMENT(nsresult) NS_TimelineOutdent() +{ + if (gTimelineDisabled) + return NS_ERROR_NOT_AVAILABLE; + + TimelineThreadData *thread = GetThisThreadData(); + if (thread->disabled) + return NS_ERROR_NOT_AVAILABLE; + thread->indent--; + return NS_OK; +} + +PR_IMPLEMENT(nsresult) NS_TimelineEnter(const char *text) +{ + nsresult rv = NS_TimelineMark("%s...", text); + if (NS_FAILED(rv)) { + return rv; + } + return NS_TimelineIndent(); +} + +PR_IMPLEMENT(nsresult) NS_TimelineLeave(const char *text) +{ + nsresult rv = NS_TimelineOutdent(); + if (NS_FAILED(rv)) { + return rv; + } + return NS_TimelineMark("...%s", text); +} + +nsTimelineService::nsTimelineService() +{ + /* member initializers and constructor code */ +} + +/* void mark (in string text); */ +NS_IMETHODIMP nsTimelineService::Mark(const char *text) +{ + return NS_TimelineMark(text); +} + +/* void startTimer (in string timerName); */ +NS_IMETHODIMP nsTimelineService::StartTimer(const char *timerName) +{ + return NS_TimelineStartTimer(timerName); +} + +/* void stopTimer (in string timerName); */ +NS_IMETHODIMP nsTimelineService::StopTimer(const char *timerName) +{ + return NS_TimelineStopTimer(timerName); +} + +/* void markTimer (in string timerName); */ +NS_IMETHODIMP nsTimelineService::MarkTimer(const char *timerName) +{ + return NS_TimelineMarkTimer(timerName); +} + +/* void markTimerWithComment(in string timerName, in string comment); */ +NS_IMETHODIMP nsTimelineService::MarkTimerWithComment(const char *timerName, const char *comment) +{ + return NS_TimelineMarkTimer(timerName, comment); +} + +/* void resetTimer (in string timerName); */ +NS_IMETHODIMP nsTimelineService::ResetTimer(const char *timerName) +{ + return NS_TimelineResetTimer(timerName); +} + +/* void indent (); */ +NS_IMETHODIMP nsTimelineService::Indent() +{ + return NS_TimelineIndent(); +} + +/* void outdent (); */ +NS_IMETHODIMP nsTimelineService::Outdent() +{ + return NS_TimelineOutdent(); +} + +/* void enter (in string text); */ +NS_IMETHODIMP nsTimelineService::Enter(const char *text) +{ + return NS_TimelineEnter(text); +} + +/* void leave (in string text); */ +NS_IMETHODIMP nsTimelineService::Leave(const char *text) +{ + return NS_TimelineLeave(text); +} + +#endif /* MOZ_TIMELINE */ diff --git a/src/libs/xpcom18a4/xpcom/ds/nsTimelineService.h b/src/libs/xpcom18a4/xpcom/ds/nsTimelineService.h new file mode 100644 index 00000000..bb579755 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsTimelineService.h @@ -0,0 +1,64 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsITimelineService.h" + +#ifdef MOZ_TIMELINE + +#define NS_TIMELINESERVICE_CID \ +{ /* a335edf0-3daf-11d5-b67d-000064657374 */ \ + 0xa335edf0, \ + 0x3daf, \ + 0x11d5, \ + {0xb6, 0x7d, 0x00, 0x00, 0x64, 0x65, 0x73, 0x74}} + +#define NS_TIMELINESERVICE_CONTRACTID "@mozilla.org;timeline-service;1" +#define NS_TIMELINESERVICE_CLASSNAME "Timeline Service" + +class nsTimelineService : public nsITimelineService +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSITIMELINESERVICE + + nsTimelineService(); + +private: + ~nsTimelineService() {} +}; + +#endif diff --git a/src/libs/xpcom18a4/xpcom/ds/nsUnicharBuffer.cpp b/src/libs/xpcom18a4/xpcom/ds/nsUnicharBuffer.cpp new file mode 100644 index 00000000..12033da0 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsUnicharBuffer.cpp @@ -0,0 +1,141 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Pierre Phaneuf + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsUnicharBuffer.h" +#include "nsCRT.h" + +#define MIN_BUFFER_SIZE 32 + +UnicharBufferImpl::UnicharBufferImpl() + : mBuffer(NULL), mSpace(0), mLength(0) +{ +} + +NS_METHOD +UnicharBufferImpl::Create(nsISupports *aOuter, REFNSIID aIID, void **aResult) +{ + if (aOuter) + return NS_ERROR_NO_AGGREGATION; + + UnicharBufferImpl* it = new UnicharBufferImpl(); + if (it == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + + NS_ADDREF(it); + nsresult rv = it->QueryInterface(aIID, aResult); + NS_RELEASE(it); + return rv; +} + +NS_IMETHODIMP +UnicharBufferImpl::Init(PRUint32 aBufferSize) +{ + if (aBufferSize < MIN_BUFFER_SIZE) { + aBufferSize = MIN_BUFFER_SIZE; + } + mSpace = aBufferSize; + mLength = 0; + mBuffer = new PRUnichar[aBufferSize]; + return mBuffer ? NS_OK : NS_ERROR_OUT_OF_MEMORY; +} + +NS_IMPL_ISUPPORTS1(UnicharBufferImpl, nsIUnicharBuffer) + +UnicharBufferImpl::~UnicharBufferImpl() +{ + if (nsnull != mBuffer) { + delete[] mBuffer; + mBuffer = nsnull; + } + mLength = 0; +} + +NS_IMETHODIMP_(PRInt32) +UnicharBufferImpl::GetLength() const +{ + return mLength; +} + +NS_IMETHODIMP_(PRInt32) +UnicharBufferImpl::GetBufferSize() const +{ + return mSpace; +} + +NS_IMETHODIMP_(PRUnichar*) +UnicharBufferImpl::GetBuffer() const +{ + return mBuffer; +} + +NS_IMETHODIMP_(PRBool) +UnicharBufferImpl::Grow(PRInt32 aNewSize) +{ + if (PRUint32(aNewSize) < MIN_BUFFER_SIZE) { + aNewSize = MIN_BUFFER_SIZE; + } + PRUnichar* newbuf = new PRUnichar[aNewSize]; + if (nsnull != newbuf) { + if (0 != mLength) { + memcpy(newbuf, mBuffer, mLength * sizeof(PRUnichar)); + } + delete[] mBuffer; + mBuffer = newbuf; + return PR_TRUE; + } + return PR_FALSE; +} + +NS_COM nsresult +NS_NewUnicharBuffer(nsIUnicharBuffer** aInstancePtrResult, + nsISupports* aOuter, + PRUint32 aBufferSize) +{ + nsresult rv; + nsIUnicharBuffer* buf; + rv = UnicharBufferImpl::Create(aOuter, NS_GET_IID(nsIUnicharBuffer), + (void**)&buf); + if (NS_FAILED(rv)) return rv; + rv = buf->Init(aBufferSize); + if (NS_FAILED(rv)) { + NS_RELEASE(buf); + return rv; + } + *aInstancePtrResult = buf; + return rv; +} diff --git a/src/libs/xpcom18a4/xpcom/ds/nsUnicharBuffer.h b/src/libs/xpcom18a4/xpcom/ds/nsUnicharBuffer.h new file mode 100644 index 00000000..d57a48ae --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsUnicharBuffer.h @@ -0,0 +1,65 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +#ifndef nsUnicharBuffer_h__ +#define nsUnicharBuffer_h__ + +#include "nsIUnicharBuffer.h" + +class UnicharBufferImpl : public nsIUnicharBuffer { +public: + UnicharBufferImpl(); + + static NS_METHOD + Create(nsISupports *aOuter, REFNSIID aIID, void **aResult); + + NS_DECL_ISUPPORTS + NS_IMETHOD Init(PRUint32 aBufferSize); + NS_IMETHOD_(PRInt32) GetLength() const; + NS_IMETHOD_(PRInt32) GetBufferSize() const; + NS_IMETHOD_(PRUnichar*) GetBuffer() const; + NS_IMETHOD_(PRBool) Grow(PRInt32 aNewSize); + + PRUnichar* mBuffer; + PRUint32 mSpace; + PRUint32 mLength; + +private: + ~UnicharBufferImpl(); +}; + +#endif // nsUnicharBuffer_h__ diff --git a/src/libs/xpcom18a4/xpcom/ds/nsUnitConversion.h b/src/libs/xpcom18a4/xpcom/ds/nsUnitConversion.h new file mode 100644 index 00000000..07825385 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsUnitConversion.h @@ -0,0 +1,207 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ +#ifndef nsUnitConversion_h__ +#define nsUnitConversion_h__ + +#include "nscore.h" +#include "nsCoord.h" +#include +#include + +#ifndef FLT_EPSILON +// Not an ANSI compiler... oh, well. Use an IEEE value. +#define FLT_EPSILON 1.19209290e-7f +#endif +/// handy constants +#define TWIPS_PER_POINT_INT 20 +#define TWIPS_PER_POINT_FLOAT 20.0f +#define CEIL_CONST_FLOAT (1.0f - 0.5f*FLT_EPSILON) +#define ROUND_EXCLUSIVE_CONST_FLOAT (0.5f*CEIL_CONST_FLOAT) +#define ROUND_CONST_FLOAT 0.5f + + +/* + * Coord Rounding Functions + */ +inline nscoord NSToCoordFloor(float aValue) +{ + return ((0.0f <= aValue) ? nscoord(aValue) : nscoord(aValue - CEIL_CONST_FLOAT)); +} + +inline nscoord NSToCoordCeil(float aValue) +{ + return ((0.0f <= aValue) ? nscoord(aValue + CEIL_CONST_FLOAT) : nscoord(aValue)); +} + +inline nscoord NSToCoordRound(float aValue) +{ + return ((0.0f <= aValue) ? nscoord(aValue + ROUND_CONST_FLOAT) : nscoord(aValue - ROUND_CONST_FLOAT)); +} + +inline nscoord NSToCoordRoundExclusive(float aValue) +{ + return ((0.0f <= aValue) ? nscoord(aValue + ROUND_EXCLUSIVE_CONST_FLOAT) : + nscoord(aValue - ROUND_EXCLUSIVE_CONST_FLOAT)); +} + + +/* + * Int Rounding Functions + */ +inline PRInt32 NSToIntFloor(float aValue) +{ + return ((0.0f <= aValue) ? PRInt32(aValue) : PRInt32(aValue - CEIL_CONST_FLOAT)); +} + +inline PRInt32 NSToIntCeil(float aValue) +{ + return ((0.0f <= aValue) ? PRInt32(aValue + CEIL_CONST_FLOAT) : PRInt32(aValue)); +} + +inline PRInt32 NSToIntRound(float aValue) +{ + return ((0.0f <= aValue) ? PRInt32(aValue + ROUND_CONST_FLOAT) : PRInt32(aValue - ROUND_CONST_FLOAT)); +} + +inline PRInt32 NSToIntRoundExclusive(float aValue) +{ + return ((0.0f <= aValue) ? PRInt32(aValue + ROUND_EXCLUSIVE_CONST_FLOAT) : + PRInt32(aValue - ROUND_EXCLUSIVE_CONST_FLOAT)); +} + + +/* + * Twips/Points conversions + */ +inline nscoord NSFloatPointsToTwips(float aPoints) +{ + return NSToCoordRound(aPoints * TWIPS_PER_POINT_FLOAT); +} + +inline nscoord NSIntPointsToTwips(PRInt32 aPoints) +{ + return nscoord(aPoints * TWIPS_PER_POINT_INT); +} + +inline PRInt32 NSTwipsToIntPoints(nscoord aTwips) +{ + return NSToIntRound(aTwips / TWIPS_PER_POINT_FLOAT); +} + +inline PRInt32 NSTwipsToFloorIntPoints(nscoord aTwips) +{ + return NSToIntFloor(aTwips / TWIPS_PER_POINT_FLOAT); +} + +inline PRInt32 NSTwipsToCeilIntPoints(nscoord aTwips) +{ + return NSToIntCeil(aTwips / TWIPS_PER_POINT_FLOAT); +} + +inline float NSTwipsToFloatPoints(nscoord aTwips) +{ + return (float(aTwips) / TWIPS_PER_POINT_FLOAT); +} + +/* + * Twips/Pixel conversions + */ +inline nscoord NSFloatPixelsToTwips(float aPixels, float aTwipsPerPixel) +{ + return NSToCoordRound(aPixels * aTwipsPerPixel); +} + +inline nscoord NSIntPixelsToTwips(PRInt32 aPixels, float aTwipsPerPixel) +{ + return NSToCoordRound(float(aPixels) * aTwipsPerPixel); +} + +inline float NSTwipsToFloatPixels(nscoord aTwips, float aPixelsPerTwip) +{ + return (float(aTwips) * aPixelsPerTwip); +} + +inline PRInt32 NSTwipsToIntPixels(nscoord aTwips, float aPixelsPerTwip) +{ + return NSToIntRound(float(aTwips) * aPixelsPerTwip); +} + +/* + * Twips/unit conversions + */ +inline nscoord NSUnitsToTwips(float aValue, float aPointsPerUnit) +{ + return NSToCoordRound(aValue * aPointsPerUnit * TWIPS_PER_POINT_FLOAT); +} + +inline float NSTwipsToUnits(nscoord aTwips, float aUnitsPerPoint) +{ + return (aTwips * (aUnitsPerPoint / TWIPS_PER_POINT_FLOAT)); +} + + +/// Unit conversion macros +//@{ +#define NS_INCHES_TO_TWIPS(x) NSUnitsToTwips((x), 72.0f) // 72 points per inch +#define NS_FEET_TO_TWIPS(x) NSUnitsToTwips((x), (72.0f * 12.0f)) // 12 inches per foot +#define NS_MILES_TO_TWIPS(x) NSUnitsToTwips((x), (72.0f * 12.0f * 5280.0f)) // 5280 feet per mile + +#define NS_MILLIMETERS_TO_TWIPS(x) NSUnitsToTwips((x), (72.0f * 0.03937f)) +#define NS_CENTIMETERS_TO_TWIPS(x) NSUnitsToTwips((x), (72.0f * 0.3937f)) +#define NS_METERS_TO_TWIPS(x) NSUnitsToTwips((x), (72.0f * 39.37f)) +#define NS_KILOMETERS_TO_TWIPS(x) NSUnitsToTwips((x), (72.0f * 39370.0f)) + +#define NS_PICAS_TO_TWIPS(x) NSUnitsToTwips((x), 12.0f) // 12 points per pica +#define NS_DIDOTS_TO_TWIPS(x) NSUnitsToTwips((x), (16.0f / 15.0f)) // 15 didots per 16 points +#define NS_CICEROS_TO_TWIPS(x) NSUnitsToTwips((x), (12.0f * (16.0f / 15.0f))) // 12 didots per cicero + + +#define NS_TWIPS_TO_INCHES(x) NSTwipsToUnits((x), 1.0f / 72.0f) +#define NS_TWIPS_TO_FEET(x) NSTwipsToUnits((x), 1.0f / (72.0f * 12.0f)) +#define NS_TWIPS_TO_MILES(x) NSTwipsToUnits((x), 1.0f / (72.0f * 12.0f * 5280.0f)) + +#define NS_TWIPS_TO_MILLIMETERS(x) NSTwipsToUnits((x), 1.0f / (72.0f * 0.03937f)) +#define NS_TWIPS_TO_CENTIMETERS(x) NSTwipsToUnits((x), 1.0f / (72.0f * 0.3937f)) +#define NS_TWIPS_TO_METERS(x) NSTwipsToUnits((x), 1.0f / (72.0f * 39.37f)) +#define NS_TWIPS_TO_KILOMETERS(x) NSTwipsToUnits((x), 1.0f / (72.0f * 39370.0f)) + +#define NS_TWIPS_TO_PICAS(x) NSTwipsToUnits((x), 1.0f / 12.0f) +#define NS_TWIPS_TO_DIDOTS(x) NSTwipsToUnits((x), 1.0f / (16.0f / 15.0f)) +#define NS_TWIPS_TO_CICEROS(x) NSTwipsToUnits((x), 1.0f / (12.0f * (16.0f / 15.0f))) +//@} + +#endif diff --git a/src/libs/xpcom18a4/xpcom/ds/nsValueArray.cpp b/src/libs/xpcom18a4/xpcom/ds/nsValueArray.cpp new file mode 100644 index 00000000..4660ccec --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsValueArray.cpp @@ -0,0 +1,304 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** 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 nsValueArray.h/nsValueArray.cpp code, released + * Dec 28, 2001. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Garrett Arch Blythe, 20-December-2001 + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +// +// nsValueArray.cpp +// +// Implement an array class to store unsigned integer values. +// The maximum value must be known up front. Once known, the +// smallest memory representation will be attempted; i.e. if the +// maximum value was 1275, then 2 bytes (uint16) would represent each value +// in the array instead of 4 bytes (uint32). +// +#include "nsValueArray.h" +#include "nsCRT.h" +#include "prmem.h" +#include "prbit.h" + +#define NSVALUEARRAY_LINEAR_GROWBY 8 +#define NSVALUEARRAY_LINEAR_THRESHOLD 128 + +nsValueArray::nsValueArray(nsValueArrayValue aMaxValue, nsValueArrayCount aInitialCapacity) { + mCount = 0; + mCapacity = 0; + mValueArray = nsnull; + + PRUint8 test8 = (PRUint8)aMaxValue; + PRUint16 test16 = (PRUint16)aMaxValue; + PRUint32 test32 = (PRUint32)aMaxValue; + if ((nsValueArrayValue)test8 == aMaxValue) { + mBytesPerValue = sizeof(test8); + } + else if ((nsValueArrayValue)test16 == aMaxValue) { + mBytesPerValue = sizeof(test16); + } + else if ((nsValueArrayValue)test32 == aMaxValue) { + mBytesPerValue = sizeof(test32); + } + else { + NS_ASSERTION(0, "not supported yet, add it yourself..."); + mBytesPerValue = 0; + } + + if (aInitialCapacity) { + mValueArray = (PRUint8*)PR_Malloc(aInitialCapacity * mBytesPerValue); + if (nsnull != mValueArray) { + mCapacity = aInitialCapacity; + } + } +} + +nsValueArray::~nsValueArray() { + if (nsnull != mValueArray) { + PR_Free(mValueArray); + mValueArray = nsnull; + } +} + +// +// Copy it. +// +nsValueArray& nsValueArray::operator=(const nsValueArray& aOther) { + // + // Free off what you know if not enough space, or units differ. + // + if ((mBytesPerValue != aOther.mBytesPerValue || mCapacity < aOther.mCount) && nsnull != mValueArray) { + PR_Free(mValueArray); + mValueArray = nsnull; + mCount = mCapacity = 0; + } + + // + // Copy some attribs. + // + mBytesPerValue = aOther.mBytesPerValue; + mCount = aOther.mCount; + + // + // Anything to do? + // + if (0 != mCount) { + // + // May need to allocate our buffer. + // + if (0 == mCapacity) { + mValueArray = (PRUint8*)PR_Malloc(mCount * mBytesPerValue); + mCapacity = mCount; + } + + NS_ASSERTION(nsnull != mValueArray, "loss of value array assignment and original data."); + if (nsnull != mValueArray) { + memcpy(mValueArray, aOther.mValueArray, mCount * mBytesPerValue); + } + else { + mCount = mCapacity = 0; + } + } + + return *this; +} + +// +// Insert a value into the array. +// No validity checking other than index is done. +// +PRBool nsValueArray::InsertValueAt(nsValueArrayValue aValue, nsValueArrayIndex aIndex) { + PRBool retval = PR_FALSE; + + nsValueArrayCount count = Count(); + if (aIndex <= count) { + // + // If we're at capacity, then we'll need to grow a little. + // + if (Capacity() == count) { + PRUint8* reallocRes = nsnull; + nsValueArrayCount growBy = NSVALUEARRAY_LINEAR_GROWBY; + + // + // Up to a particular limit we grow in small increments. + // Otherwise, grow exponentially. + // + if (count >= NSVALUEARRAY_LINEAR_THRESHOLD) { + growBy = PR_BIT(PR_CeilingLog2(count + 1)) - count; + } + + if (nsnull == mValueArray) { + reallocRes = (PRUint8*)PR_Malloc((count + growBy) * mBytesPerValue); + } + else { + reallocRes = (PRUint8*)PR_Realloc(mValueArray, (count + growBy) * mBytesPerValue); + } + if (nsnull != reallocRes) { + mValueArray = reallocRes; + mCapacity += growBy; + } + } + + // + // Only if we are below capacity do we continue. + // + if (Capacity() > count) { + // + // All those at and beyond the insertion point need to move. + // + if (aIndex < count) { + memmove(&mValueArray[(aIndex + 1) * mBytesPerValue], &mValueArray[aIndex * mBytesPerValue], (count - aIndex) * mBytesPerValue); + } + + // + // Do the assignment. + // + switch (mBytesPerValue) { + case sizeof(PRUint8): + *((PRUint8*)&mValueArray[aIndex * mBytesPerValue]) = (PRUint8)aValue; + NS_ASSERTION(*((PRUint8*)&mValueArray[aIndex * mBytesPerValue]) == aValue, "Lossy value array detected. Report a higher maximum upon construction!"); + break; + case sizeof(PRUint16): + *((PRUint16*)&mValueArray[aIndex * mBytesPerValue]) = (PRUint16)aValue; + NS_ASSERTION(*((PRUint16*)&mValueArray[aIndex * mBytesPerValue]) == aValue, "Lossy value array detected. Report a higher maximum upon construction!"); + break; + case sizeof(PRUint32): + *((PRUint32*)&mValueArray[aIndex * mBytesPerValue]) = (PRUint32)aValue; + NS_ASSERTION(*((PRUint32*)&mValueArray[aIndex * mBytesPerValue]) == aValue, "Lossy value array detected. Report a higher maximum upon construction!"); + break; + default: + NS_ASSERTION(0, "surely you've been warned prior to this!"); + break; + } + + // + // Up the count by 1. + // + mCount++; + } + } + + return retval; +} + +// +// Remove the index from the value array. +// The array does not shrink until Compact() is invoked. +// +PRBool nsValueArray::RemoveValueAt(nsValueArrayIndex aIndex) { + PRBool retval = PR_FALSE; + + nsValueArrayCount count = Count(); + if (aIndex < count) { + // + // Move memory around if appropriate. + // + if (aIndex != (count - 1)) { + memmove(&mValueArray[aIndex * mBytesPerValue], &mValueArray[(aIndex + 1) * mBytesPerValue], (count - aIndex - 1) * mBytesPerValue); + } + + // + // Update our count. + // + mCount--; + } + + return retval; +} + +// +// Shrink as much as possible. +// +void nsValueArray::Compact() { + nsValueArrayCount count = Count(); + if (Capacity() != count) + { + if (0 == count) { + PR_Free(mValueArray); + mValueArray = nsnull; + mCapacity = 0; + } + else { + PRUint8* reallocRes = (PRUint8*)PR_Realloc(mValueArray, count * mBytesPerValue); + if (nsnull != reallocRes) { + mValueArray = reallocRes; + mCapacity = count; + } + } + } +} + +// +// Return the value at the index. +// +nsValueArrayValue nsValueArray::ValueAt(nsValueArrayIndex aIndex) const { + nsValueArrayValue retval = NSVALUEARRAY_INVALID; + + if (aIndex < Count()) { + switch (mBytesPerValue) { + case sizeof(PRUint8): + retval = (nsValueArrayIndex)*((PRUint8*)&mValueArray[aIndex * mBytesPerValue]); + break; + case sizeof(PRUint16): + retval = (nsValueArrayIndex)*((PRUint16*)&mValueArray[aIndex * mBytesPerValue]); + break; + case sizeof(PRUint32): + retval = (nsValueArrayIndex)*((PRUint32*)&mValueArray[aIndex * mBytesPerValue]); + break; + default: + NS_ASSERTION(0, "unexpected for sure."); + break; + } + } + + return retval; +} + +// +// Return the first encountered index of the value. +// +nsValueArrayIndex nsValueArray::IndexOf(nsValueArrayValue aPossibleValue) const { + nsValueArrayIndex retval = NSVALUEARRAY_INVALID; + nsValueArrayIndex traverse; + + for (traverse = 0; traverse < Count(); traverse++) { + if (aPossibleValue == ValueAt(traverse)) { + retval = traverse; + break; + } + } + + return retval; +} diff --git a/src/libs/xpcom18a4/xpcom/ds/nsValueArray.h b/src/libs/xpcom18a4/xpcom/ds/nsValueArray.h new file mode 100644 index 00000000..6437ca60 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsValueArray.h @@ -0,0 +1,125 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** 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 nsValueArray.h/nsValueArray.cpp code, released + * Dec 28, 2001. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Garrett Arch Blythe, 20-December-2001 + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ +#ifndef nsValueArray_h___ +#define nsValueArray_h___ + +// +// nsValueArray.h +// +// Implement an array class to store unsigned integer values. +// The maximum value must be known up front. Once known, the +// smallest memory representation will be attempted; i.e. if the +// maximum value was 1275, then 2 bytes (uint16) would represent each value +// in the array instead of 4 bytes (uint32). +// +#include "nscore.h" + +typedef PRUint32 nsValueArrayCount; +typedef PRUint32 nsValueArrayIndex; +typedef PRUint32 nsValueArrayValue; +#define NSVALUEARRAY_INVALID ((nsValueArrayValue)-1) + +class NS_COM nsValueArray { + public: + nsValueArray(nsValueArrayValue aMaxValue, + nsValueArrayCount aInitialCapacity = 0); + ~nsValueArray(); + + // + // Assignment. + // + public: + nsValueArray& operator=(const nsValueArray& other); + + // + // Array size information. + // Ability to add more values without growing is Capacity - Count. + // + public: + inline nsValueArrayCount Count() const { + return mCount; + } + + inline nsValueArrayCount Capacity() const { + return mCapacity; + } + + void Compact(); + + // Removes all elements from this array + inline void Clear() { + mCount = 0; + } + + // + // Array access. + // + public: + nsValueArrayValue ValueAt(nsValueArrayIndex aIndex) const; + + inline nsValueArrayValue operator[](nsValueArrayIndex aIndex) const { + return ValueAt(aIndex); + } + + nsValueArrayIndex IndexOf(nsValueArrayValue aPossibleValue) const; + + inline PRBool AppendValue(nsValueArrayValue aValue) { + return InsertValueAt(aValue, Count()); + } + + inline PRBool RemoveValue(nsValueArrayValue aValue) { + return RemoveValueAt(IndexOf(aValue)); + } + + PRBool InsertValueAt(nsValueArrayValue aValue, nsValueArrayIndex aIndex); + + PRBool RemoveValueAt(nsValueArrayIndex aIndex); + + // + // Data members. + // + private: + nsValueArrayCount mCount; + nsValueArrayCount mCapacity; + PRUint8* mValueArray; + PRUint8 mBytesPerValue; +}; + +#endif /* nsValueArray_h___ */ diff --git a/src/libs/xpcom18a4/xpcom/ds/nsVariant.cpp b/src/libs/xpcom18a4/xpcom/ds/nsVariant.cpp new file mode 100644 index 00000000..09a4cda5 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsVariant.cpp @@ -0,0 +1,2092 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * John Bandhauer + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* The long avoided variant support for xpcom. */ + +#include "nsVariant.h" +#include "nsString.h" +#include "prprf.h" +#include "prdtoa.h" +#include +#include "nsCRT.h" + +/***************************************************************************/ +// Helpers for static convert functions... + +static nsresult String2Double(const char* aString, double* retval) +{ + char* next; + double value = PR_strtod(aString, &next); + if(next == aString) + return NS_ERROR_CANNOT_CONVERT_DATA; + *retval = value; + return NS_OK; +} + +static nsresult AString2Double(const nsAString& aString, double* retval) +{ + char* pChars = ToNewCString(aString); + if(!pChars) + return NS_ERROR_OUT_OF_MEMORY; + nsresult rv = String2Double(pChars, retval); + nsMemory::Free(pChars); + return rv; +} + +static nsresult AUTF8String2Double(const nsAUTF8String& aString, double* retval) +{ + return String2Double(PromiseFlatUTF8String(aString).get(), retval); +} + +static nsresult ACString2Double(const nsACString& aString, double* retval) +{ + return String2Double(PromiseFlatCString(aString).get(), retval); +} + +// Fills outVariant with double, PRUint32, or PRInt32. +// Returns NS_OK, an error code, or a non-NS_OK success code +static nsresult ToManageableNumber(const nsDiscriminatedUnion& inData, + nsDiscriminatedUnion* outData) +{ + nsresult rv; + + switch(inData.mType) + { + // This group results in a PRInt32... + +#define CASE__NUMBER_INT32(type_, member_) \ + case nsIDataType :: type_ : \ + outData->u.mInt32Value = inData.u. member_ ; \ + outData->mType = nsIDataType::VTYPE_INT32; \ + return NS_OK; + + CASE__NUMBER_INT32(VTYPE_INT8, mInt8Value) + CASE__NUMBER_INT32(VTYPE_INT16, mInt16Value) + CASE__NUMBER_INT32(VTYPE_INT32, mInt32Value) + CASE__NUMBER_INT32(VTYPE_UINT8, mUint8Value) + CASE__NUMBER_INT32(VTYPE_UINT16, mUint16Value) + CASE__NUMBER_INT32(VTYPE_BOOL, mBoolValue) + CASE__NUMBER_INT32(VTYPE_CHAR, mCharValue) + CASE__NUMBER_INT32(VTYPE_WCHAR, mWCharValue) + +#undef CASE__NUMBER_INT32 + + // This group results in a PRUint32... + + case nsIDataType::VTYPE_UINT32: + outData->u.mInt32Value = inData.u.mUint32Value; + outData->mType = nsIDataType::VTYPE_INT32; + return NS_OK; + + // This group results in a double... + + case nsIDataType::VTYPE_INT64: + case nsIDataType::VTYPE_UINT64: + // XXX Need boundary checking here. + // We may need to return NS_SUCCESS_LOSS_OF_INSIGNIFICANT_DATA + LL_L2D(outData->u.mDoubleValue, inData.u.mInt64Value); + outData->mType = nsIDataType::VTYPE_DOUBLE; + return NS_OK; + case nsIDataType::VTYPE_FLOAT: + outData->u.mDoubleValue = inData.u.mFloatValue; + outData->mType = nsIDataType::VTYPE_DOUBLE; + return NS_OK; + case nsIDataType::VTYPE_DOUBLE: + outData->u.mDoubleValue = inData.u.mDoubleValue; + outData->mType = nsIDataType::VTYPE_DOUBLE; + return NS_OK; + case nsIDataType::VTYPE_CHAR_STR: + case nsIDataType::VTYPE_STRING_SIZE_IS: + rv = String2Double(inData.u.str.mStringValue, &outData->u.mDoubleValue); + if(NS_FAILED(rv)) + return rv; + outData->mType = nsIDataType::VTYPE_DOUBLE; + return NS_OK; + case nsIDataType::VTYPE_DOMSTRING: + case nsIDataType::VTYPE_ASTRING: + rv = AString2Double(*inData.u.mAStringValue, &outData->u.mDoubleValue); + if(NS_FAILED(rv)) + return rv; + outData->mType = nsIDataType::VTYPE_DOUBLE; + return NS_OK; + case nsIDataType::VTYPE_UTF8STRING: + rv = AUTF8String2Double(*inData.u.mUTF8StringValue, + &outData->u.mDoubleValue); + if(NS_FAILED(rv)) + return rv; + outData->mType = nsIDataType::VTYPE_DOUBLE; + return NS_OK; + case nsIDataType::VTYPE_CSTRING: + rv = ACString2Double(*inData.u.mCStringValue, + &outData->u.mDoubleValue); + if(NS_FAILED(rv)) + return rv; + outData->mType = nsIDataType::VTYPE_DOUBLE; + return NS_OK; + case nsIDataType::VTYPE_WCHAR_STR: + case nsIDataType::VTYPE_WSTRING_SIZE_IS: + rv = AString2Double(nsDependentString(inData.u.wstr.mWStringValue), + &outData->u.mDoubleValue); + if(NS_FAILED(rv)) + return rv; + outData->mType = nsIDataType::VTYPE_DOUBLE; + return NS_OK; + + // This group fails... + + case nsIDataType::VTYPE_VOID: + case nsIDataType::VTYPE_ID: + case nsIDataType::VTYPE_INTERFACE: + case nsIDataType::VTYPE_INTERFACE_IS: + case nsIDataType::VTYPE_ARRAY: + case nsIDataType::VTYPE_EMPTY_ARRAY: + case nsIDataType::VTYPE_EMPTY: + default: + return NS_ERROR_CANNOT_CONVERT_DATA; + } +} + +/***************************************************************************/ +// Array helpers... + +static void FreeArray(nsDiscriminatedUnion* data) +{ + NS_ASSERTION(data->mType == nsIDataType::VTYPE_ARRAY, "bad FreeArray call"); + NS_ASSERTION(data->u.array.mArrayValue, "bad array"); + NS_ASSERTION(data->u.array.mArrayCount, "bad array count"); + +#define CASE__FREE_ARRAY_PTR(type_, ctype_) \ + case nsIDataType:: type_ : \ + { \ + ctype_ ** p = (ctype_ **) data->u.array.mArrayValue; \ + for(PRUint32 i = data->u.array.mArrayCount; i > 0; p++, i--) \ + if(*p) \ + nsMemory::Free((char*)*p); \ + break; \ + } + +#define CASE__FREE_ARRAY_IFACE(type_, ctype_) \ + case nsIDataType:: type_ : \ + { \ + ctype_ ** p = (ctype_ **) data->u.array.mArrayValue; \ + for(PRUint32 i = data->u.array.mArrayCount; i > 0; p++, i--) \ + if(*p) \ + (*p)->Release(); \ + break; \ + } + + switch(data->u.array.mArrayType) + { + case nsIDataType::VTYPE_INT8: + case nsIDataType::VTYPE_INT16: + case nsIDataType::VTYPE_INT32: + case nsIDataType::VTYPE_INT64: + case nsIDataType::VTYPE_UINT8: + case nsIDataType::VTYPE_UINT16: + case nsIDataType::VTYPE_UINT32: + case nsIDataType::VTYPE_UINT64: + case nsIDataType::VTYPE_FLOAT: + case nsIDataType::VTYPE_DOUBLE: + case nsIDataType::VTYPE_BOOL: + case nsIDataType::VTYPE_CHAR: + case nsIDataType::VTYPE_WCHAR: + break; + + // XXX We ASSUME that "array of nsID" means "array of pointers to nsID". + CASE__FREE_ARRAY_PTR(VTYPE_ID, nsID) + CASE__FREE_ARRAY_PTR(VTYPE_CHAR_STR, char) + CASE__FREE_ARRAY_PTR(VTYPE_WCHAR_STR, PRUnichar) + CASE__FREE_ARRAY_IFACE(VTYPE_INTERFACE, nsISupports) + CASE__FREE_ARRAY_IFACE(VTYPE_INTERFACE_IS, nsISupports) + + // The rest are illegal. + case nsIDataType::VTYPE_VOID: + case nsIDataType::VTYPE_ASTRING: + case nsIDataType::VTYPE_DOMSTRING: + case nsIDataType::VTYPE_UTF8STRING: + case nsIDataType::VTYPE_CSTRING: + case nsIDataType::VTYPE_WSTRING_SIZE_IS: + case nsIDataType::VTYPE_STRING_SIZE_IS: + case nsIDataType::VTYPE_ARRAY: + case nsIDataType::VTYPE_EMPTY_ARRAY: + case nsIDataType::VTYPE_EMPTY: + default: + NS_ERROR("bad type in array!"); + break; + } + + // Free the array memory. + nsMemory::Free((char*)data->u.array.mArrayValue); + +#undef CASE__FREE_ARRAY_PTR +#undef CASE__FREE_ARRAY_IFACE +} + +static nsresult CloneArray(PRUint16 inType, const nsIID* inIID, + PRUint32 inCount, void* inValue, + PRUint16* outType, nsIID* outIID, + PRUint32* outCount, void** outValue) +{ + NS_ASSERTION(inCount, "bad param"); + NS_ASSERTION(inValue, "bad param"); + NS_ASSERTION(outType, "bad param"); + NS_ASSERTION(outCount, "bad param"); + NS_ASSERTION(outValue, "bad param"); + + PRUint32 allocatedValueCount = 0; + nsresult rv = NS_OK; + PRUint32 i; + + // First we figure out the size of the elements for the new u.array. + + size_t elementSize; + size_t allocSize; + + switch(inType) + { + case nsIDataType::VTYPE_INT8: + elementSize = sizeof(PRInt8); + break; + case nsIDataType::VTYPE_INT16: + elementSize = sizeof(PRInt16); + break; + case nsIDataType::VTYPE_INT32: + elementSize = sizeof(PRInt32); + break; + case nsIDataType::VTYPE_INT64: + elementSize = sizeof(PRInt64); + break; + case nsIDataType::VTYPE_UINT8: + elementSize = sizeof(PRUint8); + break; + case nsIDataType::VTYPE_UINT16: + elementSize = sizeof(PRUint16); + break; + case nsIDataType::VTYPE_UINT32: + elementSize = sizeof(PRUint32); + break; + case nsIDataType::VTYPE_UINT64: + elementSize = sizeof(PRUint64); + break; + case nsIDataType::VTYPE_FLOAT: + elementSize = sizeof(float); + break; + case nsIDataType::VTYPE_DOUBLE: + elementSize = sizeof(double); + break; + case nsIDataType::VTYPE_BOOL: + elementSize = sizeof(PRBool); + break; + case nsIDataType::VTYPE_CHAR: + elementSize = sizeof(char); + break; + case nsIDataType::VTYPE_WCHAR: + elementSize = sizeof(PRUnichar); + break; + + // XXX We ASSUME that "array of nsID" means "array of pointers to nsID". + case nsIDataType::VTYPE_ID: + case nsIDataType::VTYPE_CHAR_STR: + case nsIDataType::VTYPE_WCHAR_STR: + case nsIDataType::VTYPE_INTERFACE: + case nsIDataType::VTYPE_INTERFACE_IS: + elementSize = sizeof(void*); + break; + + // The rest are illegal. + case nsIDataType::VTYPE_ASTRING: + case nsIDataType::VTYPE_DOMSTRING: + case nsIDataType::VTYPE_UTF8STRING: + case nsIDataType::VTYPE_CSTRING: + case nsIDataType::VTYPE_STRING_SIZE_IS: + case nsIDataType::VTYPE_WSTRING_SIZE_IS: + case nsIDataType::VTYPE_VOID: + case nsIDataType::VTYPE_ARRAY: + case nsIDataType::VTYPE_EMPTY_ARRAY: + case nsIDataType::VTYPE_EMPTY: + default: + NS_ERROR("bad type in array!"); + return NS_ERROR_CANNOT_CONVERT_DATA; + } + + + // Alloc the u.array. + + allocSize = inCount * elementSize; + *outValue = nsMemory::Alloc(allocSize); + if(!*outValue) + return NS_ERROR_OUT_OF_MEMORY; + + // Clone the elements. + + switch(inType) + { + case nsIDataType::VTYPE_INT8: + case nsIDataType::VTYPE_INT16: + case nsIDataType::VTYPE_INT32: + case nsIDataType::VTYPE_INT64: + case nsIDataType::VTYPE_UINT8: + case nsIDataType::VTYPE_UINT16: + case nsIDataType::VTYPE_UINT32: + case nsIDataType::VTYPE_UINT64: + case nsIDataType::VTYPE_FLOAT: + case nsIDataType::VTYPE_DOUBLE: + case nsIDataType::VTYPE_BOOL: + case nsIDataType::VTYPE_CHAR: + case nsIDataType::VTYPE_WCHAR: + memcpy(*outValue, inValue, allocSize); + break; + + case nsIDataType::VTYPE_INTERFACE_IS: + if(outIID) + *outIID = *inIID; + // fall through... + case nsIDataType::VTYPE_INTERFACE: + { + memcpy(*outValue, inValue, allocSize); + + nsISupports** p = (nsISupports**) *outValue; + for(i = inCount; i > 0; p++, i--) + if(*p) + (*p)->AddRef(); + break; + } + + // XXX We ASSUME that "array of nsID" means "array of pointers to nsID". + case nsIDataType::VTYPE_ID: + { + nsID** inp = (nsID**) inValue; + nsID** outp = (nsID**) *outValue; + for(i = inCount; i > 0; i--) + { + nsID* idp = *(inp++); + if(idp) + { + if(nsnull == (*(outp++) = (nsID*) + nsMemory::Clone((char*)idp, sizeof(nsID)))) + goto bad; + } + else + *(outp++) = nsnull; + allocatedValueCount++; + } + break; + } + + case nsIDataType::VTYPE_CHAR_STR: + { + char** inp = (char**) inValue; + char** outp = (char**) *outValue; + for(i = inCount; i > 0; i--) + { + char* str = *(inp++); + if(str) + { + if(nsnull == (*(outp++) = (char*) + nsMemory::Clone(str, (strlen(str)+1)*sizeof(char)))) + goto bad; + } + else + *(outp++) = nsnull; + allocatedValueCount++; + } + break; + } + + case nsIDataType::VTYPE_WCHAR_STR: + { + PRUnichar** inp = (PRUnichar**) inValue; + PRUnichar** outp = (PRUnichar**) *outValue; + for(i = inCount; i > 0; i--) + { + PRUnichar* str = *(inp++); + if(str) + { + if(nsnull == (*(outp++) = (PRUnichar*) + nsMemory::Clone(str, + (nsCRT::strlen(str)+1)*sizeof(PRUnichar)))) + goto bad; + } + else + *(outp++) = nsnull; + allocatedValueCount++; + } + break; + } + + // The rest are illegal. + case nsIDataType::VTYPE_VOID: + case nsIDataType::VTYPE_ARRAY: + case nsIDataType::VTYPE_EMPTY_ARRAY: + case nsIDataType::VTYPE_EMPTY: + case nsIDataType::VTYPE_ASTRING: + case nsIDataType::VTYPE_DOMSTRING: + case nsIDataType::VTYPE_UTF8STRING: + case nsIDataType::VTYPE_CSTRING: + case nsIDataType::VTYPE_STRING_SIZE_IS: + case nsIDataType::VTYPE_WSTRING_SIZE_IS: + default: + NS_ERROR("bad type in array!"); + return NS_ERROR_CANNOT_CONVERT_DATA; + } + + *outType = inType; + *outCount = inCount; + return NS_OK; + +bad: + if(*outValue) + { + char** p = (char**) *outValue; + for(i = allocatedValueCount; i > 0; p++, i--) + if(*p) + nsMemory::Free(*p); + nsMemory::Free((char*)*outValue); + *outValue = nsnull; + } + return rv; +} + +/***************************************************************************/ + +#define TRIVIAL_DATA_CONVERTER(type_, data_, member_, retval_) \ + if(data_.mType == nsIDataType :: type_) { \ + *retval_ = data_.u.member_; \ + return NS_OK; \ + } + +#define NUMERIC_CONVERSION_METHOD_BEGIN(type_, Ctype_, name_) \ +/* static */ nsresult \ +nsVariant::ConvertTo##name_ (const nsDiscriminatedUnion& data, \ + Ctype_ *_retval) \ +{ \ + TRIVIAL_DATA_CONVERTER(type_, data, m##name_##Value, _retval) \ + nsDiscriminatedUnion tempData; \ + nsVariant::Initialize(&tempData); \ + nsresult rv = ToManageableNumber(data, &tempData); \ + /* */ \ + /* NOTE: rv may indicate a success code that we want to preserve */ \ + /* For the final return. So all the return cases below should return */ \ + /* this rv when indicating success. */ \ + /* */ \ + if(NS_FAILED(rv)) \ + return rv; \ + switch(tempData.mType) \ + { + +#define CASE__NUMERIC_CONVERSION_INT32_JUST_CAST(Ctype_) \ + case nsIDataType::VTYPE_INT32: \ + *_retval = ( Ctype_ ) tempData.u.mInt32Value; \ + return rv; + +#define CASE__NUMERIC_CONVERSION_INT32_MIN_MAX(Ctype_, min_, max_) \ + case nsIDataType::VTYPE_INT32: \ + { \ + PRInt32 value = tempData.u.mInt32Value; \ + if(value < min_ || value > max_) \ + return NS_ERROR_LOSS_OF_SIGNIFICANT_DATA; \ + *_retval = ( Ctype_ ) value; \ + return rv; \ + } + +#define CASE__NUMERIC_CONVERSION_UINT32_JUST_CAST(Ctype_) \ + case nsIDataType::VTYPE_UINT32: \ + *_retval = ( Ctype_ ) tempData.u.mUint32Value; \ + return rv; + +#define CASE__NUMERIC_CONVERSION_UINT32_MAX(Ctype_, max_) \ + case nsIDataType::VTYPE_UINT32: \ + { \ + PRUint32 value = tempData.u.mUint32Value; \ + if(value > max_) \ + return NS_ERROR_LOSS_OF_SIGNIFICANT_DATA; \ + *_retval = ( Ctype_ ) value; \ + return rv; \ + } + +#define CASE__NUMERIC_CONVERSION_DOUBLE_JUST_CAST(Ctype_) \ + case nsIDataType::VTYPE_DOUBLE: \ + *_retval = ( Ctype_ ) tempData.u.mDoubleValue; \ + return rv; + +#define CASE__NUMERIC_CONVERSION_DOUBLE_MIN_MAX(Ctype_, min_, max_) \ + case nsIDataType::VTYPE_DOUBLE: \ + { \ + double value = tempData.u.mDoubleValue; \ + if(value < min_ || value > max_) \ + return NS_ERROR_LOSS_OF_SIGNIFICANT_DATA; \ + *_retval = ( Ctype_ ) value; \ + return rv; \ + } + +#define CASE__NUMERIC_CONVERSION_DOUBLE_MIN_MAX_INT(Ctype_, min_, max_) \ + case nsIDataType::VTYPE_DOUBLE: \ + { \ + double value = tempData.u.mDoubleValue; \ + if(value < min_ || value > max_) \ + return NS_ERROR_LOSS_OF_SIGNIFICANT_DATA; \ + *_retval = ( Ctype_ ) value; \ + return (0.0 == fmod(value,1.0)) ? \ + rv : NS_SUCCESS_LOSS_OF_INSIGNIFICANT_DATA; \ + } + +#define CASES__NUMERIC_CONVERSION_NORMAL(Ctype_, min_, max_) \ + CASE__NUMERIC_CONVERSION_INT32_MIN_MAX(Ctype_, min_, max_) \ + CASE__NUMERIC_CONVERSION_UINT32_MAX(Ctype_, max_) \ + CASE__NUMERIC_CONVERSION_DOUBLE_MIN_MAX_INT(Ctype_, min_, max_) + +#define NUMERIC_CONVERSION_METHOD_END \ + default: \ + NS_ERROR("bad type returned from ToManageableNumber"); \ + return NS_ERROR_CANNOT_CONVERT_DATA; \ + } \ +} + +#define NUMERIC_CONVERSION_METHOD_NORMAL(type_, Ctype_, name_, min_, max_) \ + NUMERIC_CONVERSION_METHOD_BEGIN(type_, Ctype_, name_) \ + CASES__NUMERIC_CONVERSION_NORMAL(Ctype_, min_, max_) \ + NUMERIC_CONVERSION_METHOD_END + +/***************************************************************************/ +// These expand into full public methods... + +NUMERIC_CONVERSION_METHOD_NORMAL(VTYPE_INT8, PRUint8, Int8, (-127-1), 127) +NUMERIC_CONVERSION_METHOD_NORMAL(VTYPE_INT16, PRInt16, Int16, (-32767-1), 32767) + +NUMERIC_CONVERSION_METHOD_BEGIN(VTYPE_INT32, PRInt32, Int32) + CASE__NUMERIC_CONVERSION_INT32_JUST_CAST(PRInt32) + CASE__NUMERIC_CONVERSION_UINT32_MAX(PRInt32, 2147483647) + CASE__NUMERIC_CONVERSION_DOUBLE_MIN_MAX_INT(PRInt32, (-2147483647-1), 2147483647) +NUMERIC_CONVERSION_METHOD_END + +NUMERIC_CONVERSION_METHOD_NORMAL(VTYPE_UINT8, PRUint8, Uint8, 0, 255) +NUMERIC_CONVERSION_METHOD_NORMAL(VTYPE_UINT16, PRUint16, Uint16, 0, 65535) + +NUMERIC_CONVERSION_METHOD_BEGIN(VTYPE_UINT32, PRUint32, Uint32) + CASE__NUMERIC_CONVERSION_INT32_MIN_MAX(PRUint32, 0, 2147483647) + CASE__NUMERIC_CONVERSION_UINT32_JUST_CAST(PRUint32) + CASE__NUMERIC_CONVERSION_DOUBLE_MIN_MAX_INT(PRUint32, 0, 4294967295U) +NUMERIC_CONVERSION_METHOD_END + +// XXX toFloat convertions need to be fixed! +NUMERIC_CONVERSION_METHOD_BEGIN(VTYPE_FLOAT, float, Float) + CASE__NUMERIC_CONVERSION_INT32_JUST_CAST(float) + CASE__NUMERIC_CONVERSION_UINT32_JUST_CAST(float) + CASE__NUMERIC_CONVERSION_DOUBLE_JUST_CAST(float) +NUMERIC_CONVERSION_METHOD_END + +NUMERIC_CONVERSION_METHOD_BEGIN(VTYPE_DOUBLE, double, Double) + CASE__NUMERIC_CONVERSION_INT32_JUST_CAST(double) + CASE__NUMERIC_CONVERSION_UINT32_JUST_CAST(double) + CASE__NUMERIC_CONVERSION_DOUBLE_JUST_CAST(double) +NUMERIC_CONVERSION_METHOD_END + +// XXX toChar convertions need to be fixed! +NUMERIC_CONVERSION_METHOD_BEGIN(VTYPE_CHAR, char, Char) + CASE__NUMERIC_CONVERSION_INT32_JUST_CAST(char) + CASE__NUMERIC_CONVERSION_UINT32_JUST_CAST(char) + CASE__NUMERIC_CONVERSION_DOUBLE_JUST_CAST(char) +NUMERIC_CONVERSION_METHOD_END + +// XXX toWChar convertions need to be fixed! +NUMERIC_CONVERSION_METHOD_BEGIN(VTYPE_WCHAR, PRUnichar, WChar) + CASE__NUMERIC_CONVERSION_INT32_JUST_CAST(PRUnichar) + CASE__NUMERIC_CONVERSION_UINT32_JUST_CAST(PRUnichar) + CASE__NUMERIC_CONVERSION_DOUBLE_JUST_CAST(PRUnichar) +NUMERIC_CONVERSION_METHOD_END + +#undef NUMERIC_CONVERSION_METHOD_BEGIN +#undef CASE__NUMERIC_CONVERSION_INT32_JUST_CAST +#undef CASE__NUMERIC_CONVERSION_INT32_MIN_MAX +#undef CASE__NUMERIC_CONVERSION_UINT32_JUST_CAST +#undef CASE__NUMERIC_CONVERSION_UINT32_MIN_MAX +#undef CASE__NUMERIC_CONVERSION_DOUBLE_JUST_CAST +#undef CASE__NUMERIC_CONVERSION_DOUBLE_MIN_MAX +#undef CASE__NUMERIC_CONVERSION_DOUBLE_MIN_MAX_INT +#undef CASES__NUMERIC_CONVERSION_NORMAL +#undef NUMERIC_CONVERSION_METHOD_END +#undef NUMERIC_CONVERSION_METHOD_NORMAL + +/***************************************************************************/ + +// Just leverage a numeric converter for bool (but restrict the values). +// XXX Is this really what we want to do? + +/* static */ nsresult +nsVariant::ConvertToBool(const nsDiscriminatedUnion& data, PRBool *_retval) +{ + TRIVIAL_DATA_CONVERTER(VTYPE_BOOL, data, mBoolValue, _retval) + + double val; + nsresult rv = nsVariant::ConvertToDouble(data, &val); + if(NS_FAILED(rv)) + return rv; + *_retval = 0.0 != val; + return rv; +} + +/***************************************************************************/ + +/* static */ nsresult +nsVariant::ConvertToInt64(const nsDiscriminatedUnion& data, PRInt64 *_retval) +{ + TRIVIAL_DATA_CONVERTER(VTYPE_INT64, data, mInt64Value, _retval) + TRIVIAL_DATA_CONVERTER(VTYPE_UINT64, data, mUint64Value, _retval) + + nsDiscriminatedUnion tempData; + nsVariant::Initialize(&tempData); + nsresult rv = ToManageableNumber(data, &tempData); + if(NS_FAILED(rv)) + return rv; + switch(tempData.mType) + { + case nsIDataType::VTYPE_INT32: + LL_I2L(*_retval, tempData.u.mInt32Value); + return rv; + case nsIDataType::VTYPE_UINT32: + LL_UI2L(*_retval, tempData.u.mUint32Value); + return rv; + case nsIDataType::VTYPE_DOUBLE: + // XXX should check for data loss here! + LL_D2L(*_retval, tempData.u.mDoubleValue); + return rv; + default: + NS_ERROR("bad type returned from ToManageableNumber"); + return NS_ERROR_CANNOT_CONVERT_DATA; + } +} + +/* static */ nsresult +nsVariant::ConvertToUint64(const nsDiscriminatedUnion& data, PRUint64 *_retval) +{ + return nsVariant::ConvertToInt64(data, (PRInt64 *)_retval); +} + +/***************************************************************************/ + +static PRBool String2ID(const nsDiscriminatedUnion& data, nsID* pid) +{ + nsAutoString tempString; + nsAString* pString; + + switch(data.mType) + { + case nsIDataType::VTYPE_CHAR_STR: + case nsIDataType::VTYPE_STRING_SIZE_IS: + return pid->Parse(data.u.str.mStringValue); + case nsIDataType::VTYPE_CSTRING: + return pid->Parse(PromiseFlatCString(*data.u.mCStringValue).get()); + case nsIDataType::VTYPE_UTF8STRING: + return pid->Parse(PromiseFlatUTF8String(*data.u.mUTF8StringValue).get()); + case nsIDataType::VTYPE_ASTRING: + case nsIDataType::VTYPE_DOMSTRING: + pString = data.u.mAStringValue; + break; + case nsIDataType::VTYPE_WCHAR_STR: + case nsIDataType::VTYPE_WSTRING_SIZE_IS: + tempString.Assign(data.u.wstr.mWStringValue); + pString = &tempString; + break; + default: + NS_ERROR("bad type in call to String2ID"); + return PR_FALSE; + } + + char* pChars = ToNewCString(*pString); + if(!pChars) + return PR_FALSE; + PRBool result = pid->Parse(pChars); + nsMemory::Free(pChars); + return result; +} + +/* static */ nsresult +nsVariant::ConvertToID(const nsDiscriminatedUnion& data, nsID * _retval) +{ + nsID id; + + switch(data.mType) + { + case nsIDataType::VTYPE_ID: + *_retval = data.u.mIDValue; + return NS_OK; + case nsIDataType::VTYPE_INTERFACE: + *_retval = NS_GET_IID(nsISupports); + return NS_OK; + case nsIDataType::VTYPE_INTERFACE_IS: + *_retval = data.u.iface.mInterfaceID; + return NS_OK; + case nsIDataType::VTYPE_ASTRING: + case nsIDataType::VTYPE_DOMSTRING: + case nsIDataType::VTYPE_UTF8STRING: + case nsIDataType::VTYPE_CSTRING: + case nsIDataType::VTYPE_CHAR_STR: + case nsIDataType::VTYPE_WCHAR_STR: + case nsIDataType::VTYPE_STRING_SIZE_IS: + case nsIDataType::VTYPE_WSTRING_SIZE_IS: + if(!String2ID(data, &id)) + return NS_ERROR_CANNOT_CONVERT_DATA; + *_retval = id; + return NS_OK; + default: + return NS_ERROR_CANNOT_CONVERT_DATA; + } +} + +/***************************************************************************/ + +static nsresult ToString(const nsDiscriminatedUnion& data, + nsACString & outString) +{ + char* ptr; + + switch(data.mType) + { + // all the stuff we don't handle... + case nsIDataType::VTYPE_ASTRING: + case nsIDataType::VTYPE_DOMSTRING: + case nsIDataType::VTYPE_UTF8STRING: + case nsIDataType::VTYPE_CSTRING: + case nsIDataType::VTYPE_CHAR_STR: + case nsIDataType::VTYPE_WCHAR_STR: + case nsIDataType::VTYPE_STRING_SIZE_IS: + case nsIDataType::VTYPE_WSTRING_SIZE_IS: + case nsIDataType::VTYPE_WCHAR: + NS_ERROR("ToString being called for a string type - screwy logic!"); + // fall through... + + // XXX We might want stringified versions of these... ??? + + case nsIDataType::VTYPE_VOID: + case nsIDataType::VTYPE_EMPTY_ARRAY: + case nsIDataType::VTYPE_EMPTY: + case nsIDataType::VTYPE_ARRAY: + case nsIDataType::VTYPE_INTERFACE: + case nsIDataType::VTYPE_INTERFACE_IS: + default: + return NS_ERROR_CANNOT_CONVERT_DATA; + + // nsID has its own text formater. + + case nsIDataType::VTYPE_ID: + ptr = data.u.mIDValue.ToString(); + if(!ptr) + return NS_ERROR_OUT_OF_MEMORY; + outString.Assign(ptr); + nsMemory::Free(ptr); + return NS_OK; + + // the rest can be PR_smprintf'd and use common code. + +#define CASE__SMPRINTF_NUMBER(type_, format_, cast_, member_) \ + case nsIDataType :: type_ : \ + ptr = PR_smprintf( format_ , (cast_) data.u. member_ ); \ + break; + + CASE__SMPRINTF_NUMBER(VTYPE_INT8, "%d", int, mInt8Value) + CASE__SMPRINTF_NUMBER(VTYPE_INT16, "%d", int, mInt16Value) + CASE__SMPRINTF_NUMBER(VTYPE_INT32, "%d", int, mInt32Value) + CASE__SMPRINTF_NUMBER(VTYPE_INT64, "%lld", PRInt64, mInt64Value) + + CASE__SMPRINTF_NUMBER(VTYPE_UINT8, "%u", unsigned, mUint8Value) + CASE__SMPRINTF_NUMBER(VTYPE_UINT16, "%u", unsigned, mUint16Value) + CASE__SMPRINTF_NUMBER(VTYPE_UINT32, "%u", unsigned, mUint32Value) + CASE__SMPRINTF_NUMBER(VTYPE_UINT64, "%llu", PRInt64, mUint64Value) + + CASE__SMPRINTF_NUMBER(VTYPE_FLOAT, "%f", float, mFloatValue) + CASE__SMPRINTF_NUMBER(VTYPE_DOUBLE, "%f", double, mDoubleValue) + + // XXX Would we rather print "true" / "false" ? + CASE__SMPRINTF_NUMBER(VTYPE_BOOL, "%d", int, mBoolValue) + + CASE__SMPRINTF_NUMBER(VTYPE_CHAR, "%c", char, mCharValue) + +#undef CASE__SMPRINTF_NUMBER + } + + if(!ptr) + return NS_ERROR_OUT_OF_MEMORY; + outString.Assign(ptr); + PR_smprintf_free(ptr); + return NS_OK; +} + +/* static */ nsresult +nsVariant::ConvertToAString(const nsDiscriminatedUnion& data, + nsAString & _retval) +{ + switch(data.mType) + { + case nsIDataType::VTYPE_ASTRING: + case nsIDataType::VTYPE_DOMSTRING: + _retval.Assign(*data.u.mAStringValue); + return NS_OK; + case nsIDataType::VTYPE_CSTRING: + CopyASCIItoUCS2(*data.u.mCStringValue, _retval); + return NS_OK; + case nsIDataType::VTYPE_UTF8STRING: + CopyUTF8toUTF16(*data.u.mUTF8StringValue, _retval); + return NS_OK; + case nsIDataType::VTYPE_CHAR_STR: + CopyASCIItoUTF16(data.u.str.mStringValue, _retval); + return NS_OK; + case nsIDataType::VTYPE_WCHAR_STR: + _retval.Assign(data.u.wstr.mWStringValue); + return NS_OK; + case nsIDataType::VTYPE_STRING_SIZE_IS: + CopyASCIItoUCS2(nsDependentCString(data.u.str.mStringValue, + data.u.str.mStringLength), + _retval); + return NS_OK; + case nsIDataType::VTYPE_WSTRING_SIZE_IS: + _retval.Assign(data.u.wstr.mWStringValue, data.u.wstr.mWStringLength); + return NS_OK; + case nsIDataType::VTYPE_WCHAR: + _retval.Assign(data.u.mWCharValue); + return NS_OK; + default: + { + nsCAutoString tempCString; + nsresult rv = ToString(data, tempCString); + if(NS_FAILED(rv)) + return rv; + CopyASCIItoUTF16(tempCString, _retval); + return NS_OK; + } + } +} + +/* static */ nsresult +nsVariant::ConvertToACString(const nsDiscriminatedUnion& data, + nsACString & _retval) +{ + switch(data.mType) + { + case nsIDataType::VTYPE_ASTRING: + case nsIDataType::VTYPE_DOMSTRING: + CopyUCS2toASCII(*data.u.mAStringValue, _retval); + return NS_OK; + case nsIDataType::VTYPE_CSTRING: + _retval.Assign(*data.u.mCStringValue); + return NS_OK; + case nsIDataType::VTYPE_UTF8STRING: + // XXX This is an extra copy that should be avoided + // once Jag lands support for UTF8String and associated + // conversion methods. + CopyUCS2toASCII(NS_ConvertUTF8toUCS2(*data.u.mUTF8StringValue), + _retval); + return NS_OK; + case nsIDataType::VTYPE_CHAR_STR: + _retval.Assign(*data.u.str.mStringValue); + return NS_OK; + case nsIDataType::VTYPE_WCHAR_STR: + CopyUCS2toASCII(nsDependentString(data.u.wstr.mWStringValue), + _retval); + return NS_OK; + case nsIDataType::VTYPE_STRING_SIZE_IS: + _retval.Assign(data.u.str.mStringValue, data.u.str.mStringLength); + return NS_OK; + case nsIDataType::VTYPE_WSTRING_SIZE_IS: + CopyUCS2toASCII(nsDependentString(data.u.wstr.mWStringValue, + data.u.wstr.mWStringLength), _retval); + return NS_OK; + case nsIDataType::VTYPE_WCHAR: + { + const PRUnichar* str = &data.u.mWCharValue; + CopyUCS2toASCII(Substring(str, str + 1), _retval); + return NS_OK; + } + default: + return ToString(data, _retval); + } +} + +/* static */ nsresult +nsVariant::ConvertToAUTF8String(const nsDiscriminatedUnion& data, + nsAUTF8String & _retval) +{ + switch(data.mType) + { + case nsIDataType::VTYPE_ASTRING: + case nsIDataType::VTYPE_DOMSTRING: + CopyUTF16toUTF8(*data.u.mAStringValue, _retval); + return NS_OK; + case nsIDataType::VTYPE_CSTRING: + // XXX Extra copy, can be removed if we're sure CSTRING can + // only contain ASCII. + CopyUTF16toUTF8(NS_ConvertASCIItoUTF16(*data.u.mCStringValue), + _retval); + return NS_OK; + case nsIDataType::VTYPE_UTF8STRING: + _retval.Assign(*data.u.mUTF8StringValue); + return NS_OK; + case nsIDataType::VTYPE_CHAR_STR: + // XXX Extra copy, can be removed if we're sure CHAR_STR can + // only contain ASCII. + CopyUTF16toUTF8(NS_ConvertASCIItoUTF16(data.u.str.mStringValue), + _retval); + return NS_OK; + case nsIDataType::VTYPE_WCHAR_STR: + CopyUTF16toUTF8(data.u.wstr.mWStringValue, _retval); + return NS_OK; + case nsIDataType::VTYPE_STRING_SIZE_IS: + // XXX Extra copy, can be removed if we're sure CHAR_STR can + // only contain ASCII. + CopyUTF16toUTF8(NS_ConvertASCIItoUTF16( + nsDependentCString(data.u.str.mStringValue, + data.u.str.mStringLength)), _retval); + return NS_OK; + case nsIDataType::VTYPE_WSTRING_SIZE_IS: + CopyUTF16toUTF8(nsDependentString(data.u.wstr.mWStringValue, + data.u.wstr.mWStringLength), + _retval); + return NS_OK; + case nsIDataType::VTYPE_WCHAR: + { + const PRUnichar* str = &data.u.mWCharValue; + CopyUTF16toUTF8(Substring(str, str + 1), _retval); + return NS_OK; + } + default: + { + nsCAutoString tempCString; + nsresult rv = ToString(data, tempCString); + if(NS_FAILED(rv)) + return rv; + // XXX Extra copy, can be removed if we're sure tempCString can + // only contain ASCII. + CopyUTF16toUTF8(NS_ConvertASCIItoUTF16(tempCString), _retval); + return NS_OK; + } + } +} + +/* static */ nsresult +nsVariant::ConvertToString(const nsDiscriminatedUnion& data, char **_retval) +{ + PRUint32 ignored; + return nsVariant::ConvertToStringWithSize(data, &ignored, _retval); +} + +/* static */ nsresult +nsVariant::ConvertToWString(const nsDiscriminatedUnion& data, PRUnichar **_retval) +{ + PRUint32 ignored; + return nsVariant::ConvertToWStringWithSize(data, &ignored, _retval); +} + +/* static */ nsresult +nsVariant::ConvertToStringWithSize(const nsDiscriminatedUnion& data, + PRUint32 *size, char **str) +{ + nsAutoString tempString; + nsCAutoString tempCString; + nsresult rv; + + switch(data.mType) + { + case nsIDataType::VTYPE_ASTRING: + case nsIDataType::VTYPE_DOMSTRING: + *size = data.u.mAStringValue->Length(); + *str = ToNewCString(*data.u.mAStringValue); + break; + case nsIDataType::VTYPE_CSTRING: + *size = data.u.mCStringValue->Length(); + *str = ToNewCString(*data.u.mCStringValue); + break; + case nsIDataType::VTYPE_UTF8STRING: + { + // XXX This is doing 1 extra copy. Need to fix this + // when Jag lands UTF8String + // we want: + // *size = *data.mUTF8StringValue->Length(); + // *str = ToNewCString(*data.mUTF8StringValue); + // But this will have to do for now. + NS_ConvertUTF8toUCS2 tempString(*data.u.mUTF8StringValue); + *size = tempString.Length(); + *str = ToNewCString(tempString); + break; + } + case nsIDataType::VTYPE_CHAR_STR: + { + nsDependentCString cString(data.u.str.mStringValue); + *size = cString.Length(); + *str = ToNewCString(cString); + break; + } + case nsIDataType::VTYPE_WCHAR_STR: + { + nsDependentString string(data.u.wstr.mWStringValue); + *size = string.Length(); + *str = ToNewCString(string); + break; + } + case nsIDataType::VTYPE_STRING_SIZE_IS: + { + nsDependentCString cString(data.u.str.mStringValue, + data.u.str.mStringLength); + *size = cString.Length(); + *str = ToNewCString(cString); + break; + } + case nsIDataType::VTYPE_WSTRING_SIZE_IS: + { + nsDependentString string(data.u.wstr.mWStringValue, + data.u.wstr.mWStringLength); + *size = string.Length(); + *str = ToNewCString(string); + break; + } + case nsIDataType::VTYPE_WCHAR: + tempString.Assign(data.u.mWCharValue); + *size = tempString.Length(); + *str = ToNewCString(tempString); + break; + default: + rv = ToString(data, tempCString); + if(NS_FAILED(rv)) + return rv; + *size = tempCString.Length(); + *str = ToNewCString(tempCString); + break; + } + + return *str ? NS_OK : NS_ERROR_OUT_OF_MEMORY; +} +/* static */ nsresult +nsVariant::ConvertToWStringWithSize(const nsDiscriminatedUnion& data, + PRUint32 *size, PRUnichar **str) +{ + nsAutoString tempString; + nsCAutoString tempCString; + nsresult rv; + + switch(data.mType) + { + case nsIDataType::VTYPE_ASTRING: + case nsIDataType::VTYPE_DOMSTRING: + *size = data.u.mAStringValue->Length(); + *str = ToNewUnicode(*data.u.mAStringValue); + break; + case nsIDataType::VTYPE_CSTRING: + *size = data.u.mCStringValue->Length(); + *str = ToNewUnicode(*data.u.mCStringValue); + break; + case nsIDataType::VTYPE_UTF8STRING: + { + *str = UTF8ToNewUnicode(*data.u.mUTF8StringValue, size); + break; + } + case nsIDataType::VTYPE_CHAR_STR: + { + nsDependentCString cString(data.u.str.mStringValue); + *size = cString.Length(); + *str = ToNewUnicode(cString); + break; + } + case nsIDataType::VTYPE_WCHAR_STR: + { + nsDependentString string(data.u.wstr.mWStringValue); + *size = string.Length(); + *str = ToNewUnicode(string); + break; + } + case nsIDataType::VTYPE_STRING_SIZE_IS: + { + nsDependentCString cString(data.u.str.mStringValue, + data.u.str.mStringLength); + *size = cString.Length(); + *str = ToNewUnicode(cString); + break; + } + case nsIDataType::VTYPE_WSTRING_SIZE_IS: + { + nsDependentString string(data.u.wstr.mWStringValue, + data.u.wstr.mWStringLength); + *size = string.Length(); + *str = ToNewUnicode(string); + break; + } + case nsIDataType::VTYPE_WCHAR: + tempString.Assign(data.u.mWCharValue); + *size = tempString.Length(); + *str = ToNewUnicode(tempString); + break; + default: + rv = ToString(data, tempCString); + if(NS_FAILED(rv)) + return rv; + *size = tempCString.Length(); + *str = ToNewUnicode(tempCString); + break; + } + + return *str ? NS_OK : NS_ERROR_OUT_OF_MEMORY; +} + +/* static */ nsresult +nsVariant::ConvertToISupports(const nsDiscriminatedUnion& data, + nsISupports **_retval) +{ + switch(data.mType) + { + case nsIDataType::VTYPE_INTERFACE: + case nsIDataType::VTYPE_INTERFACE_IS: + if (data.u.iface.mInterfaceValue) { + return data.u.iface.mInterfaceValue-> + QueryInterface(NS_GET_IID(nsISupports), (void**)_retval); + } else { + *_retval = nsnull; + return NS_OK; + } + default: + return NS_ERROR_CANNOT_CONVERT_DATA; + } +} + +/* static */ nsresult +nsVariant::ConvertToInterface(const nsDiscriminatedUnion& data, nsIID * *iid, + void * *iface) +{ + const nsIID* piid; + + switch(data.mType) + { + case nsIDataType::VTYPE_INTERFACE: + piid = &NS_GET_IID(nsISupports); + break; + case nsIDataType::VTYPE_INTERFACE_IS: + piid = &data.u.iface.mInterfaceID; + break; + default: + return NS_ERROR_CANNOT_CONVERT_DATA; + } + + *iid = (nsIID*) nsMemory::Clone(piid, sizeof(nsIID)); + if(!*iid) + return NS_ERROR_OUT_OF_MEMORY; + + if (data.u.iface.mInterfaceValue) { + return data.u.iface.mInterfaceValue->QueryInterface(*piid, iface); + } + + *iface = nsnull; + return NS_OK; +} + +/* static */ nsresult +nsVariant::ConvertToArray(const nsDiscriminatedUnion& data, PRUint16 *type, + nsIID* iid, PRUint32 *count, void * *ptr) +{ + // XXX perhaps we'd like to add support for converting each of the various + // types into an array containing one element of that type. We can leverage + // CloneArray to do this if we want to support this. + + if(data.mType == nsIDataType::VTYPE_ARRAY) + return CloneArray(data.u.array.mArrayType, &data.u.array.mArrayInterfaceID, + data.u.array.mArrayCount, data.u.array.mArrayValue, + type, iid, count, ptr); + return NS_ERROR_CANNOT_CONVERT_DATA; +} + +/***************************************************************************/ +// static setter functions... + +#define DATA_SETTER_PROLOGUE(data_) \ + nsVariant::Cleanup(data_); + +#define DATA_SETTER_EPILOGUE(data_, type_) \ + data_->mType = nsIDataType :: type_; \ + return NS_OK; + +#define DATA_SETTER(data_, type_, member_, value_) \ + DATA_SETTER_PROLOGUE(data_) \ + data_->u.member_ = value_; \ + DATA_SETTER_EPILOGUE(data_, type_) + +#define DATA_SETTER_WITH_CAST(data_, type_, member_, cast_, value_) \ + DATA_SETTER_PROLOGUE(data_) \ + data_->u.member_ = cast_ value_; \ + DATA_SETTER_EPILOGUE(data_, type_) + + +/********************************************/ + +#define CASE__SET_FROM_VARIANT_VTYPE_PROLOGUE(type_) \ + { \ + +#define CASE__SET_FROM_VARIANT_VTYPE__GETTER(member_, name_) \ + rv = aValue->GetAs##name_ (&(data->u. member_ )); + +#define CASE__SET_FROM_VARIANT_VTYPE__GETTER_CAST(cast_, member_, name_) \ + rv = aValue->GetAs##name_ ( cast_ &(data->u. member_ )); + +#define CASE__SET_FROM_VARIANT_VTYPE_EPILOGUE(type_) \ + if(NS_SUCCEEDED(rv)) \ + { \ + data->mType = nsIDataType :: type_ ; \ + } \ + break; \ + } + +#define CASE__SET_FROM_VARIANT_TYPE(type_, member_, name_) \ + case nsIDataType :: type_ : \ + CASE__SET_FROM_VARIANT_VTYPE_PROLOGUE(type_) \ + CASE__SET_FROM_VARIANT_VTYPE__GETTER(member_, name_) \ + CASE__SET_FROM_VARIANT_VTYPE_EPILOGUE(type_) + +#define CASE__SET_FROM_VARIANT_VTYPE_CAST(type_, cast_, member_, name_) \ + case nsIDataType :: type_ : \ + CASE__SET_FROM_VARIANT_VTYPE_PROLOGUE(type_) \ + CASE__SET_FROM_VARIANT_VTYPE__GETTER_CAST(cast_, member_, name_) \ + CASE__SET_FROM_VARIANT_VTYPE_EPILOGUE(type_) + + +/* static */ nsresult +nsVariant::SetFromVariant(nsDiscriminatedUnion* data, nsIVariant* aValue) +{ + PRUint16 type; + nsresult rv; + + nsVariant::Cleanup(data); + + rv = aValue->GetDataType(&type); + if(NS_FAILED(rv)) + return rv; + + switch(type) + { + CASE__SET_FROM_VARIANT_VTYPE_CAST(VTYPE_INT8, (PRUint8*), mInt8Value, + Int8) + CASE__SET_FROM_VARIANT_TYPE(VTYPE_INT16, mInt16Value, Int16) + CASE__SET_FROM_VARIANT_TYPE(VTYPE_INT32, mInt32Value, Int32) + CASE__SET_FROM_VARIANT_TYPE(VTYPE_UINT8, mUint8Value, Uint8) + CASE__SET_FROM_VARIANT_TYPE(VTYPE_UINT16, mUint16Value, Uint16) + CASE__SET_FROM_VARIANT_TYPE(VTYPE_UINT32, mUint32Value, Uint32) + CASE__SET_FROM_VARIANT_TYPE(VTYPE_FLOAT, mFloatValue, Float) + CASE__SET_FROM_VARIANT_TYPE(VTYPE_DOUBLE, mDoubleValue, Double) + CASE__SET_FROM_VARIANT_TYPE(VTYPE_BOOL , mBoolValue, Bool) + CASE__SET_FROM_VARIANT_TYPE(VTYPE_CHAR, mCharValue, Char) + CASE__SET_FROM_VARIANT_TYPE(VTYPE_WCHAR, mWCharValue, WChar) + CASE__SET_FROM_VARIANT_TYPE(VTYPE_ID, mIDValue, ID) + + case nsIDataType::VTYPE_ASTRING: + case nsIDataType::VTYPE_DOMSTRING: + case nsIDataType::VTYPE_WCHAR_STR: + case nsIDataType::VTYPE_WSTRING_SIZE_IS: + CASE__SET_FROM_VARIANT_VTYPE_PROLOGUE(VTYPE_ASTRING); + data->u.mAStringValue = new nsString(); + if(!data->u.mAStringValue) + return NS_ERROR_OUT_OF_MEMORY; + rv = aValue->GetAsAString(*data->u.mAStringValue); + if(NS_FAILED(rv)) + delete data->u.mAStringValue; + CASE__SET_FROM_VARIANT_VTYPE_EPILOGUE(VTYPE_ASTRING) + + case nsIDataType::VTYPE_CSTRING: + CASE__SET_FROM_VARIANT_VTYPE_PROLOGUE(VTYPE_CSTRING); + data->u.mCStringValue = new nsCString(); + if(!data->u.mCStringValue) + return NS_ERROR_OUT_OF_MEMORY; + rv = aValue->GetAsACString(*data->u.mCStringValue); + if(NS_FAILED(rv)) + delete data->u.mCStringValue; + CASE__SET_FROM_VARIANT_VTYPE_EPILOGUE(VTYPE_CSTRING) + + case nsIDataType::VTYPE_UTF8STRING: + CASE__SET_FROM_VARIANT_VTYPE_PROLOGUE(VTYPE_UTF8STRING); + data->u.mUTF8StringValue = new nsUTF8String(); + if(!data->u.mUTF8StringValue) + return NS_ERROR_OUT_OF_MEMORY; + rv = aValue->GetAsAUTF8String(*data->u.mUTF8StringValue); + if(NS_FAILED(rv)) + delete data->u.mUTF8StringValue; + CASE__SET_FROM_VARIANT_VTYPE_EPILOGUE(VTYPE_UTF8STRING) + + case nsIDataType::VTYPE_CHAR_STR: + case nsIDataType::VTYPE_STRING_SIZE_IS: + CASE__SET_FROM_VARIANT_VTYPE_PROLOGUE(VTYPE_STRING_SIZE_IS); + rv = aValue->GetAsStringWithSize(&data->u.str.mStringLength, + &data->u.str.mStringValue); + CASE__SET_FROM_VARIANT_VTYPE_EPILOGUE(VTYPE_STRING_SIZE_IS) + + case nsIDataType::VTYPE_INTERFACE: + case nsIDataType::VTYPE_INTERFACE_IS: + CASE__SET_FROM_VARIANT_VTYPE_PROLOGUE(VTYPE_INTERFACE_IS); + // XXX This iid handling is ugly! + nsIID* iid; + rv = aValue->GetAsInterface(&iid, (void**)&data->u.iface.mInterfaceValue); + if(NS_SUCCEEDED(rv)) + { + data->u.iface.mInterfaceID = *iid; + nsMemory::Free((char*)iid); + } + CASE__SET_FROM_VARIANT_VTYPE_EPILOGUE(VTYPE_INTERFACE_IS) + + case nsIDataType::VTYPE_ARRAY: + CASE__SET_FROM_VARIANT_VTYPE_PROLOGUE(VTYPE_ARRAY); + rv = aValue->GetAsArray(&data->u.array.mArrayType, + &data->u.array.mArrayInterfaceID, + &data->u.array.mArrayCount, + &data->u.array.mArrayValue); + CASE__SET_FROM_VARIANT_VTYPE_EPILOGUE(VTYPE_ARRAY) + + case nsIDataType::VTYPE_VOID: + rv = nsVariant::SetToVoid(data); + break; + case nsIDataType::VTYPE_EMPTY_ARRAY: + rv = nsVariant::SetToEmptyArray(data); + break; + case nsIDataType::VTYPE_EMPTY: + rv = nsVariant::SetToEmpty(data); + break; + default: + NS_ERROR("bad type in variant!"); + rv = NS_ERROR_FAILURE; + break; + } + return rv; +} + +/* static */ nsresult +nsVariant::SetFromInt8(nsDiscriminatedUnion* data, PRUint8 aValue) +{ + DATA_SETTER_WITH_CAST(data, VTYPE_INT8, mInt8Value, (PRUint8), aValue) +} +/* static */ nsresult +nsVariant::SetFromInt16(nsDiscriminatedUnion* data, PRInt16 aValue) +{ + DATA_SETTER(data, VTYPE_INT16, mInt16Value, aValue) +} +/* static */ nsresult +nsVariant::SetFromInt32(nsDiscriminatedUnion* data, PRInt32 aValue) +{ + DATA_SETTER(data, VTYPE_INT32, mInt32Value, aValue) +} +/* static */ nsresult +nsVariant::SetFromInt64(nsDiscriminatedUnion* data, PRInt64 aValue) +{ + DATA_SETTER(data, VTYPE_INT64, mInt64Value, aValue) +} +/* static */ nsresult +nsVariant::SetFromUint8(nsDiscriminatedUnion* data, PRUint8 aValue) +{ + DATA_SETTER(data, VTYPE_UINT8, mUint8Value, aValue) +} +/* static */ nsresult +nsVariant::SetFromUint16(nsDiscriminatedUnion* data, PRUint16 aValue) +{ + DATA_SETTER(data, VTYPE_UINT16, mUint16Value, aValue) +} +/* static */ nsresult +nsVariant::SetFromUint32(nsDiscriminatedUnion* data, PRUint32 aValue) +{ + DATA_SETTER(data, VTYPE_UINT32, mUint32Value, aValue) +} +/* static */ nsresult +nsVariant::SetFromUint64(nsDiscriminatedUnion* data, PRUint64 aValue) +{ + DATA_SETTER(data, VTYPE_UINT64, mUint64Value, aValue) +} +/* static */ nsresult +nsVariant::SetFromFloat(nsDiscriminatedUnion* data, float aValue) +{ + DATA_SETTER(data, VTYPE_FLOAT, mFloatValue, aValue) +} +/* static */ nsresult +nsVariant::SetFromDouble(nsDiscriminatedUnion* data, double aValue) +{ + DATA_SETTER(data, VTYPE_DOUBLE, mDoubleValue, aValue) +} +/* static */ nsresult +nsVariant::SetFromBool(nsDiscriminatedUnion* data, PRBool aValue) +{ + DATA_SETTER(data, VTYPE_BOOL, mBoolValue, aValue) +} +/* static */ nsresult +nsVariant::SetFromChar(nsDiscriminatedUnion* data, char aValue) +{ + DATA_SETTER(data, VTYPE_CHAR, mCharValue, aValue) +} +/* static */ nsresult +nsVariant::SetFromWChar(nsDiscriminatedUnion* data, PRUnichar aValue) +{ + DATA_SETTER(data, VTYPE_WCHAR, mWCharValue, aValue) +} +/* static */ nsresult +nsVariant::SetFromID(nsDiscriminatedUnion* data, const nsID & aValue) +{ + DATA_SETTER(data, VTYPE_ID, mIDValue, aValue) +} +/* static */ nsresult +nsVariant::SetFromAString(nsDiscriminatedUnion* data, const nsAString & aValue) +{ + DATA_SETTER_PROLOGUE(data); + if(!(data->u.mAStringValue = new nsString(aValue))) + return NS_ERROR_OUT_OF_MEMORY; + DATA_SETTER_EPILOGUE(data, VTYPE_ASTRING); +} + +/* static */ nsresult +nsVariant::SetFromACString(nsDiscriminatedUnion* data, + const nsACString & aValue) +{ + DATA_SETTER_PROLOGUE(data); + if(!(data->u.mCStringValue = new nsCString(aValue))) + return NS_ERROR_OUT_OF_MEMORY; + DATA_SETTER_EPILOGUE(data, VTYPE_CSTRING); +} + +/* static */ nsresult +nsVariant::SetFromAUTF8String(nsDiscriminatedUnion* data, + const nsAUTF8String & aValue) +{ + DATA_SETTER_PROLOGUE(data); + if(!(data->u.mUTF8StringValue = new nsUTF8String(aValue))) + return NS_ERROR_OUT_OF_MEMORY; + DATA_SETTER_EPILOGUE(data, VTYPE_UTF8STRING); +} + +/* static */ nsresult +nsVariant::SetFromString(nsDiscriminatedUnion* data, const char *aValue) +{ + DATA_SETTER_PROLOGUE(data); + if(!aValue) + return NS_ERROR_NULL_POINTER; + return SetFromStringWithSize(data, strlen(aValue), aValue); +} +/* static */ nsresult +nsVariant::SetFromWString(nsDiscriminatedUnion* data, const PRUnichar *aValue) +{ + DATA_SETTER_PROLOGUE(data); + if(!aValue) + return NS_ERROR_NULL_POINTER; + return SetFromWStringWithSize(data, nsCRT::strlen(aValue), aValue); +} +/* static */ nsresult +nsVariant::SetFromISupports(nsDiscriminatedUnion* data, nsISupports *aValue) +{ + return SetFromInterface(data, NS_GET_IID(nsISupports), aValue); +} +/* static */ nsresult +nsVariant::SetFromInterface(nsDiscriminatedUnion* data, const nsIID& iid, + nsISupports *aValue) +{ + DATA_SETTER_PROLOGUE(data); + NS_IF_ADDREF(aValue); + data->u.iface.mInterfaceValue = aValue; + data->u.iface.mInterfaceID = iid; + DATA_SETTER_EPILOGUE(data, VTYPE_INTERFACE_IS); +} +/* static */ nsresult +nsVariant::SetFromArray(nsDiscriminatedUnion* data, PRUint16 type, + const nsIID* iid, PRUint32 count, void * aValue) +{ + DATA_SETTER_PROLOGUE(data); + if(!aValue || !count) + return NS_ERROR_NULL_POINTER; + + nsresult rv = CloneArray(type, iid, count, aValue, + &data->u.array.mArrayType, + &data->u.array.mArrayInterfaceID, + &data->u.array.mArrayCount, + &data->u.array.mArrayValue); + if(NS_FAILED(rv)) + return rv; + DATA_SETTER_EPILOGUE(data, VTYPE_ARRAY); +} +/* static */ nsresult +nsVariant::SetFromStringWithSize(nsDiscriminatedUnion* data, PRUint32 size, const char *aValue) +{ + DATA_SETTER_PROLOGUE(data); + if(!aValue) + return NS_ERROR_NULL_POINTER; + if(!(data->u.str.mStringValue = + (char*) nsMemory::Clone(aValue, (size+1)*sizeof(char)))) + return NS_ERROR_OUT_OF_MEMORY; + data->u.str.mStringLength = size; + DATA_SETTER_EPILOGUE(data, VTYPE_STRING_SIZE_IS); +} +/* static */ nsresult +nsVariant::SetFromWStringWithSize(nsDiscriminatedUnion* data, PRUint32 size, const PRUnichar *aValue) +{ + DATA_SETTER_PROLOGUE(data); + if(!aValue) + return NS_ERROR_NULL_POINTER; + if(!(data->u.wstr.mWStringValue = + (PRUnichar*) nsMemory::Clone(aValue, (size+1)*sizeof(PRUnichar)))) + return NS_ERROR_OUT_OF_MEMORY; + data->u.wstr.mWStringLength = size; + DATA_SETTER_EPILOGUE(data, VTYPE_WSTRING_SIZE_IS); +} +/* static */ nsresult +nsVariant::SetToVoid(nsDiscriminatedUnion* data) +{ + DATA_SETTER_PROLOGUE(data); + DATA_SETTER_EPILOGUE(data, VTYPE_VOID); +} +/* static */ nsresult +nsVariant::SetToEmpty(nsDiscriminatedUnion* data) +{ + DATA_SETTER_PROLOGUE(data); + DATA_SETTER_EPILOGUE(data, VTYPE_EMPTY); +} +/* static */ nsresult +nsVariant::SetToEmptyArray(nsDiscriminatedUnion* data) +{ + DATA_SETTER_PROLOGUE(data); + DATA_SETTER_EPILOGUE(data, VTYPE_EMPTY_ARRAY); +} + +/***************************************************************************/ + +/* static */ nsresult +nsVariant::Initialize(nsDiscriminatedUnion* data) +{ + data->mType = nsIDataType::VTYPE_EMPTY; + return NS_OK; +} + +/* static */ nsresult +nsVariant::Cleanup(nsDiscriminatedUnion* data) +{ + switch(data->mType) + { + case nsIDataType::VTYPE_INT8: + case nsIDataType::VTYPE_INT16: + case nsIDataType::VTYPE_INT32: + case nsIDataType::VTYPE_INT64: + case nsIDataType::VTYPE_UINT8: + case nsIDataType::VTYPE_UINT16: + case nsIDataType::VTYPE_UINT32: + case nsIDataType::VTYPE_UINT64: + case nsIDataType::VTYPE_FLOAT: + case nsIDataType::VTYPE_DOUBLE: + case nsIDataType::VTYPE_BOOL: + case nsIDataType::VTYPE_CHAR: + case nsIDataType::VTYPE_WCHAR: + case nsIDataType::VTYPE_VOID: + case nsIDataType::VTYPE_ID: + break; + case nsIDataType::VTYPE_ASTRING: + case nsIDataType::VTYPE_DOMSTRING: + delete data->u.mAStringValue; + break; + case nsIDataType::VTYPE_CSTRING: + delete data->u.mCStringValue; + break; + case nsIDataType::VTYPE_UTF8STRING: + delete data->u.mUTF8StringValue; + break; + case nsIDataType::VTYPE_CHAR_STR: + case nsIDataType::VTYPE_STRING_SIZE_IS: + nsMemory::Free((char*)data->u.str.mStringValue); + break; + case nsIDataType::VTYPE_WCHAR_STR: + case nsIDataType::VTYPE_WSTRING_SIZE_IS: + nsMemory::Free((char*)data->u.wstr.mWStringValue); + break; + case nsIDataType::VTYPE_INTERFACE: + case nsIDataType::VTYPE_INTERFACE_IS: + NS_IF_RELEASE(data->u.iface.mInterfaceValue); + break; + case nsIDataType::VTYPE_ARRAY: + FreeArray(data); + break; + case nsIDataType::VTYPE_EMPTY_ARRAY: + case nsIDataType::VTYPE_EMPTY: + break; + default: + NS_ERROR("bad type in variant!"); + break; + } + + data->mType = nsIDataType::VTYPE_EMPTY; + return NS_OK; +} + +/***************************************************************************/ +/***************************************************************************/ +// members... + +NS_IMPL_ISUPPORTS2(nsVariant, nsIVariant, nsIWritableVariant) + +nsVariant::nsVariant() + : mWritable(PR_TRUE) +{ + nsVariant::Initialize(&mData); + +#ifdef DEBUG + { + // Assert that the nsIDataType consts match the values #defined in + // xpt_struct.h. Bad things happen somewhere if they don't. + struct THE_TYPES {PRUint16 a; PRUint16 b;}; + static const THE_TYPES array[] = { + {nsIDataType::VTYPE_INT8 , TD_INT8 }, + {nsIDataType::VTYPE_INT16 , TD_INT16 }, + {nsIDataType::VTYPE_INT32 , TD_INT32 }, + {nsIDataType::VTYPE_INT64 , TD_INT64 }, + {nsIDataType::VTYPE_UINT8 , TD_UINT8 }, + {nsIDataType::VTYPE_UINT16 , TD_UINT16 }, + {nsIDataType::VTYPE_UINT32 , TD_UINT32 }, + {nsIDataType::VTYPE_UINT64 , TD_UINT64 }, + {nsIDataType::VTYPE_FLOAT , TD_FLOAT }, + {nsIDataType::VTYPE_DOUBLE , TD_DOUBLE }, + {nsIDataType::VTYPE_BOOL , TD_BOOL }, + {nsIDataType::VTYPE_CHAR , TD_CHAR }, + {nsIDataType::VTYPE_WCHAR , TD_WCHAR }, + {nsIDataType::VTYPE_VOID , TD_VOID }, + {nsIDataType::VTYPE_ID , TD_PNSIID }, + {nsIDataType::VTYPE_DOMSTRING , TD_DOMSTRING }, + {nsIDataType::VTYPE_CHAR_STR , TD_PSTRING }, + {nsIDataType::VTYPE_WCHAR_STR , TD_PWSTRING }, + {nsIDataType::VTYPE_INTERFACE , TD_INTERFACE_TYPE }, + {nsIDataType::VTYPE_INTERFACE_IS , TD_INTERFACE_IS_TYPE}, + {nsIDataType::VTYPE_ARRAY , TD_ARRAY }, + {nsIDataType::VTYPE_STRING_SIZE_IS , TD_PSTRING_SIZE_IS }, + {nsIDataType::VTYPE_WSTRING_SIZE_IS , TD_PWSTRING_SIZE_IS }, + {nsIDataType::VTYPE_UTF8STRING , TD_UTF8STRING }, + {nsIDataType::VTYPE_CSTRING , TD_CSTRING }, + {nsIDataType::VTYPE_ASTRING , TD_ASTRING } + }; + static const int length = sizeof(array)/sizeof(array[0]); + static PRBool inited = PR_FALSE; + if(!inited) + { + for(int i = 0; i < length; i++) + NS_ASSERTION(array[i].a == array[i].b, "bad const declaration"); + inited = PR_TRUE; + } + } +#endif +} + +nsVariant::~nsVariant() +{ + nsVariant::Cleanup(&mData); +} + +// For all the data getters we just forward to the static (and sharable) +// 'ConvertTo' functions. + +/* readonly attribute PRUint16 dataType; */ +NS_IMETHODIMP nsVariant::GetDataType(PRUint16 *aDataType) +{ + *aDataType = mData.mType; + return NS_OK; +} + +/* PRUint8 getAsInt8 (); */ +NS_IMETHODIMP nsVariant::GetAsInt8(PRUint8 *_retval) +{ + return nsVariant::ConvertToInt8(mData, _retval); +} + +/* PRInt16 getAsInt16 (); */ +NS_IMETHODIMP nsVariant::GetAsInt16(PRInt16 *_retval) +{ + return nsVariant::ConvertToInt16(mData, _retval); +} + +/* PRInt32 getAsInt32 (); */ +NS_IMETHODIMP nsVariant::GetAsInt32(PRInt32 *_retval) +{ + return nsVariant::ConvertToInt32(mData, _retval); +} + +/* PRInt64 getAsInt64 (); */ +NS_IMETHODIMP nsVariant::GetAsInt64(PRInt64 *_retval) +{ + return nsVariant::ConvertToInt64(mData, _retval); +} + +/* PRUint8 getAsUint8 (); */ +NS_IMETHODIMP nsVariant::GetAsUint8(PRUint8 *_retval) +{ + return nsVariant::ConvertToUint8(mData, _retval); +} + +/* PRUint16 getAsUint16 (); */ +NS_IMETHODIMP nsVariant::GetAsUint16(PRUint16 *_retval) +{ + return nsVariant::ConvertToUint16(mData, _retval); +} + +/* PRUint32 getAsUint32 (); */ +NS_IMETHODIMP nsVariant::GetAsUint32(PRUint32 *_retval) +{ + return nsVariant::ConvertToUint32(mData, _retval); +} + +/* PRUint64 getAsUint64 (); */ +NS_IMETHODIMP nsVariant::GetAsUint64(PRUint64 *_retval) +{ + return nsVariant::ConvertToUint64(mData, _retval); +} + +/* float getAsFloat (); */ +NS_IMETHODIMP nsVariant::GetAsFloat(float *_retval) +{ + return nsVariant::ConvertToFloat(mData, _retval); +} + +/* double getAsDouble (); */ +NS_IMETHODIMP nsVariant::GetAsDouble(double *_retval) +{ + return nsVariant::ConvertToDouble(mData, _retval); +} + +/* PRBool getAsBool (); */ +NS_IMETHODIMP nsVariant::GetAsBool(PRBool *_retval) +{ + return nsVariant::ConvertToBool(mData, _retval); +} + +/* char getAsChar (); */ +NS_IMETHODIMP nsVariant::GetAsChar(char *_retval) +{ + return nsVariant::ConvertToChar(mData, _retval); +} + +/* wchar getAsWChar (); */ +NS_IMETHODIMP nsVariant::GetAsWChar(PRUnichar *_retval) +{ + return nsVariant::ConvertToWChar(mData, _retval); +} + +/* [notxpcom] nsresult getAsID (out nsID retval); */ +NS_IMETHODIMP_(nsresult) nsVariant::GetAsID(nsID *retval) +{ + return nsVariant::ConvertToID(mData, retval); +} + +/* AString getAsAString (); */ +NS_IMETHODIMP nsVariant::GetAsAString(nsAString & _retval) +{ + return nsVariant::ConvertToAString(mData, _retval); +} + +/* DOMString getAsDOMString (); */ +NS_IMETHODIMP nsVariant::GetAsDOMString(nsAString & _retval) +{ + // A DOMString maps to an AString internally, so we can re-use + // ConvertToAString here. + return nsVariant::ConvertToAString(mData, _retval); +} + +/* ACString getAsACString (); */ +NS_IMETHODIMP nsVariant::GetAsACString(nsACString & _retval) +{ + return nsVariant::ConvertToACString(mData, _retval); +} + +/* AUTF8String getAsAUTF8String (); */ +NS_IMETHODIMP nsVariant::GetAsAUTF8String(nsAUTF8String & _retval) +{ + return nsVariant::ConvertToAUTF8String(mData, _retval); +} + +/* string getAsString (); */ +NS_IMETHODIMP nsVariant::GetAsString(char **_retval) +{ + return nsVariant::ConvertToString(mData, _retval); +} + +/* wstring getAsWString (); */ +NS_IMETHODIMP nsVariant::GetAsWString(PRUnichar **_retval) +{ + return nsVariant::ConvertToWString(mData, _retval); +} + +/* nsISupports getAsISupports (); */ +NS_IMETHODIMP nsVariant::GetAsISupports(nsISupports **_retval) +{ + return nsVariant::ConvertToISupports(mData, _retval); +} + +/* void getAsInterface (out nsIIDPtr iid, [iid_is (iid), retval] out nsQIResult iface); */ +NS_IMETHODIMP nsVariant::GetAsInterface(nsIID * *iid, void * *iface) +{ + return nsVariant::ConvertToInterface(mData, iid, iface); +} + +/* [notxpcom] nsresult getAsArray (out PRUint16 type, out nsIID iid, out PRUint32 count, out voidPtr ptr); */ +NS_IMETHODIMP_(nsresult) nsVariant::GetAsArray(PRUint16 *type, nsIID *iid, PRUint32 *count, void * *ptr) +{ + return nsVariant::ConvertToArray(mData, type, iid, count, ptr); +} + +/* void getAsStringWithSize (out PRUint32 size, [size_is (size), retval] out string str); */ +NS_IMETHODIMP nsVariant::GetAsStringWithSize(PRUint32 *size, char **str) +{ + return nsVariant::ConvertToStringWithSize(mData, size, str); +} + +/* void getAsWStringWithSize (out PRUint32 size, [size_is (size), retval] out wstring str); */ +NS_IMETHODIMP nsVariant::GetAsWStringWithSize(PRUint32 *size, PRUnichar **str) +{ + return nsVariant::ConvertToWStringWithSize(mData, size, str); +} + +/***************************************************************************/ + +/* attribute PRBool writable; */ +NS_IMETHODIMP nsVariant::GetWritable(PRBool *aWritable) +{ + *aWritable = mWritable; + return NS_OK; +} +NS_IMETHODIMP nsVariant::SetWritable(PRBool aWritable) +{ + if(!mWritable && aWritable) + return NS_ERROR_FAILURE; + mWritable = aWritable; + return NS_OK; +} + +/***************************************************************************/ + +// For all the data setters we just forward to the static (and sharable) +// 'SetFrom' functions. + +/* void setAsInt8 (in PRUint8 aValue); */ +NS_IMETHODIMP nsVariant::SetAsInt8(PRUint8 aValue) +{ + if(!mWritable) return NS_ERROR_OBJECT_IS_IMMUTABLE; + return nsVariant::SetFromInt8(&mData, aValue); +} + +/* void setAsInt16 (in PRInt16 aValue); */ +NS_IMETHODIMP nsVariant::SetAsInt16(PRInt16 aValue) +{ + if(!mWritable) return NS_ERROR_OBJECT_IS_IMMUTABLE; + return nsVariant::SetFromInt16(&mData, aValue); +} + +/* void setAsInt32 (in PRInt32 aValue); */ +NS_IMETHODIMP nsVariant::SetAsInt32(PRInt32 aValue) +{ + if(!mWritable) return NS_ERROR_OBJECT_IS_IMMUTABLE; + return nsVariant::SetFromInt32(&mData, aValue); +} + +/* void setAsInt64 (in PRInt64 aValue); */ +NS_IMETHODIMP nsVariant::SetAsInt64(PRInt64 aValue) +{ + if(!mWritable) return NS_ERROR_OBJECT_IS_IMMUTABLE; + return nsVariant::SetFromInt64(&mData, aValue); +} + +/* void setAsUint8 (in PRUint8 aValue); */ +NS_IMETHODIMP nsVariant::SetAsUint8(PRUint8 aValue) +{ + if(!mWritable) return NS_ERROR_OBJECT_IS_IMMUTABLE; + return nsVariant::SetFromUint8(&mData, aValue); +} + +/* void setAsUint16 (in PRUint16 aValue); */ +NS_IMETHODIMP nsVariant::SetAsUint16(PRUint16 aValue) +{ + if(!mWritable) return NS_ERROR_OBJECT_IS_IMMUTABLE; + return nsVariant::SetFromUint16(&mData, aValue); +} + +/* void setAsUint32 (in PRUint32 aValue); */ +NS_IMETHODIMP nsVariant::SetAsUint32(PRUint32 aValue) +{ + if(!mWritable) return NS_ERROR_OBJECT_IS_IMMUTABLE; + return nsVariant::SetFromUint32(&mData, aValue); +} + +/* void setAsUint64 (in PRUint64 aValue); */ +NS_IMETHODIMP nsVariant::SetAsUint64(PRUint64 aValue) +{ + if(!mWritable) return NS_ERROR_OBJECT_IS_IMMUTABLE; + return nsVariant::SetFromUint64(&mData, aValue); +} + +/* void setAsFloat (in float aValue); */ +NS_IMETHODIMP nsVariant::SetAsFloat(float aValue) +{ + if(!mWritable) return NS_ERROR_OBJECT_IS_IMMUTABLE; + return nsVariant::SetFromFloat(&mData, aValue); +} + +/* void setAsDouble (in double aValue); */ +NS_IMETHODIMP nsVariant::SetAsDouble(double aValue) +{ + if(!mWritable) return NS_ERROR_OBJECT_IS_IMMUTABLE; + return nsVariant::SetFromDouble(&mData, aValue); +} + +/* void setAsBool (in PRBool aValue); */ +NS_IMETHODIMP nsVariant::SetAsBool(PRBool aValue) +{ + if(!mWritable) return NS_ERROR_OBJECT_IS_IMMUTABLE; + return nsVariant::SetFromBool(&mData, aValue); +} + +/* void setAsChar (in char aValue); */ +NS_IMETHODIMP nsVariant::SetAsChar(char aValue) +{ + if(!mWritable) return NS_ERROR_OBJECT_IS_IMMUTABLE; + return nsVariant::SetFromChar(&mData, aValue); +} + +/* void setAsWChar (in wchar aValue); */ +NS_IMETHODIMP nsVariant::SetAsWChar(PRUnichar aValue) +{ + if(!mWritable) return NS_ERROR_OBJECT_IS_IMMUTABLE; + return nsVariant::SetFromWChar(&mData, aValue); +} + +/* void setAsID (in nsIDRef aValue); */ +NS_IMETHODIMP nsVariant::SetAsID(const nsID & aValue) +{ + if(!mWritable) return NS_ERROR_OBJECT_IS_IMMUTABLE; + return nsVariant::SetFromID(&mData, aValue); +} + +/* void setAsAString (in AString aValue); */ +NS_IMETHODIMP nsVariant::SetAsAString(const nsAString & aValue) +{ + if(!mWritable) return NS_ERROR_OBJECT_IS_IMMUTABLE; + return nsVariant::SetFromAString(&mData, aValue); +} + +/* void setAsDOMString (in DOMString aValue); */ +NS_IMETHODIMP nsVariant::SetAsDOMString(const nsAString & aValue) +{ + if(!mWritable) return NS_ERROR_OBJECT_IS_IMMUTABLE; + + // A DOMString maps to an AString internally, so we can re-use + // SetFromAString here. + return nsVariant::SetFromAString(&mData, aValue); +} + +/* void setAsACString (in ACString aValue); */ +NS_IMETHODIMP nsVariant::SetAsACString(const nsACString & aValue) +{ + if(!mWritable) return NS_ERROR_OBJECT_IS_IMMUTABLE; + return nsVariant::SetFromACString(&mData, aValue); +} + +/* void setAsAUTF8String (in AUTF8String aValue); */ +NS_IMETHODIMP nsVariant::SetAsAUTF8String(const nsAUTF8String & aValue) +{ + if(!mWritable) return NS_ERROR_OBJECT_IS_IMMUTABLE; + return nsVariant::SetFromAUTF8String(&mData, aValue); +} + +/* void setAsString (in string aValue); */ +NS_IMETHODIMP nsVariant::SetAsString(const char *aValue) +{ + if(!mWritable) return NS_ERROR_OBJECT_IS_IMMUTABLE; + return nsVariant::SetFromString(&mData, aValue); +} + +/* void setAsWString (in wstring aValue); */ +NS_IMETHODIMP nsVariant::SetAsWString(const PRUnichar *aValue) +{ + if(!mWritable) return NS_ERROR_OBJECT_IS_IMMUTABLE; + return nsVariant::SetFromWString(&mData, aValue); +} + +/* void setAsISupports (in nsISupports aValue); */ +NS_IMETHODIMP nsVariant::SetAsISupports(nsISupports *aValue) +{ + if(!mWritable) return NS_ERROR_OBJECT_IS_IMMUTABLE; + return nsVariant::SetFromISupports(&mData, aValue); +} + +/* void setAsInterface (in nsIIDRef iid, [iid_is (iid)] in nsQIResult iface); */ +NS_IMETHODIMP nsVariant::SetAsInterface(const nsIID & iid, void * iface) +{ + if(!mWritable) return NS_ERROR_OBJECT_IS_IMMUTABLE; + return nsVariant::SetFromInterface(&mData, iid, (nsISupports*)iface); +} + +/* [noscript] void setAsArray (in PRUint16 type, in nsIIDPtr iid, in PRUint32 count, in voidPtr ptr); */ +NS_IMETHODIMP nsVariant::SetAsArray(PRUint16 type, const nsIID * iid, PRUint32 count, void * ptr) +{ + if(!mWritable) return NS_ERROR_OBJECT_IS_IMMUTABLE; + return nsVariant::SetFromArray(&mData, type, iid, count, ptr); +} + +/* void setAsStringWithSize (in PRUint32 size, [size_is (size)] in string str); */ +NS_IMETHODIMP nsVariant::SetAsStringWithSize(PRUint32 size, const char *str) +{ + if(!mWritable) return NS_ERROR_OBJECT_IS_IMMUTABLE; + return nsVariant::SetFromStringWithSize(&mData, size, str); +} + +/* void setAsWStringWithSize (in PRUint32 size, [size_is (size)] in wstring str); */ +NS_IMETHODIMP nsVariant::SetAsWStringWithSize(PRUint32 size, const PRUnichar *str) +{ + if(!mWritable) return NS_ERROR_OBJECT_IS_IMMUTABLE; + return nsVariant::SetFromWStringWithSize(&mData, size, str); +} + +/* void setAsVoid (); */ +NS_IMETHODIMP nsVariant::SetAsVoid() +{ + if(!mWritable) return NS_ERROR_OBJECT_IS_IMMUTABLE; + return nsVariant::SetToVoid(&mData); +} + +/* void setAsEmpty (); */ +NS_IMETHODIMP nsVariant::SetAsEmpty() +{ + if(!mWritable) return NS_ERROR_OBJECT_IS_IMMUTABLE; + return nsVariant::SetToEmpty(&mData); +} + +/* void setAsEmptyArray (); */ +NS_IMETHODIMP nsVariant::SetAsEmptyArray() +{ + if(!mWritable) return NS_ERROR_OBJECT_IS_IMMUTABLE; + return nsVariant::SetToEmptyArray(&mData); +} + +/* void setFromVariant (in nsIVariant aValue); */ +NS_IMETHODIMP nsVariant::SetFromVariant(nsIVariant *aValue) +{ + if(!mWritable) return NS_ERROR_OBJECT_IS_IMMUTABLE; + return nsVariant::SetFromVariant(&mData, aValue); +} diff --git a/src/libs/xpcom18a4/xpcom/ds/nsVariant.h b/src/libs/xpcom18a4/xpcom/ds/nsVariant.h new file mode 100644 index 00000000..393e745f --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsVariant.h @@ -0,0 +1,203 @@ +/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * John Bandhauer + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* The long avoided variant support for xpcom. */ + +#include "nsIVariant.h" +#include "nsStringFwd.h" +#include "xpt_struct.h" + +/** + * Map the nsAUTF8String, nsUTF8String classes to the nsACString and + * nsCString classes respectively for now. These defines need to be removed + * once Jag lands his nsUTF8String implementation. + */ +#define nsAUTF8String nsACString +#define nsUTF8String nsCString +#define PromiseFlatUTF8String PromiseFlatCString + +/** + * nsDiscriminatedUnion is a type that nsIVariant implementors *may* use + * to hold underlying data. It has no methods. So, its use requires no linkage + * to the xpcom module. + */ + +struct nsDiscriminatedUnion +{ + union { + PRInt8 mInt8Value; + PRInt16 mInt16Value; + PRInt32 mInt32Value; + PRInt64 mInt64Value; + PRUint8 mUint8Value; + PRUint16 mUint16Value; + PRUint32 mUint32Value; + PRUint64 mUint64Value; + float mFloatValue; + double mDoubleValue; + PRBool mBoolValue; + char mCharValue; + PRUnichar mWCharValue; + nsIID mIDValue; + nsAString* mAStringValue; + nsAUTF8String* mUTF8StringValue; + nsACString* mCStringValue; + struct { + nsISupports* mInterfaceValue; + nsIID mInterfaceID; + } iface; + struct { + nsIID mArrayInterfaceID; + void* mArrayValue; + PRUint32 mArrayCount; + PRUint16 mArrayType; + } array; + struct { + char* mStringValue; + PRUint32 mStringLength; + } str; + struct { + PRUnichar* mWStringValue; + PRUint32 mWStringLength; + } wstr; + } u; + PRUint16 mType; +}; + +/** + * nsVariant implements the generic variant support. The xpcom module registers + * a factory (see NS_VARIANT_CONTRACTID in nsIVariant.idl) that will create + * these objects. They are created 'empty' and 'writable'. + * + * nsIVariant users won't usually need to see this class. + * + * This class also has static helper methods that nsIVariant *implementors* can + * use to help them do all the 'standard' nsIVariant data conversions. + */ + +class NS_COM nsVariant : public nsIWritableVariant +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIVARIANT + NS_DECL_NSIWRITABLEVARIANT + + nsVariant(); + + static nsresult Initialize(nsDiscriminatedUnion* data); + static nsresult Cleanup(nsDiscriminatedUnion* data); + + static nsresult ConvertToInt8(const nsDiscriminatedUnion& data, PRUint8 *_retval); + static nsresult ConvertToInt16(const nsDiscriminatedUnion& data, PRInt16 *_retval); + static nsresult ConvertToInt32(const nsDiscriminatedUnion& data, PRInt32 *_retval); + static nsresult ConvertToInt64(const nsDiscriminatedUnion& data, PRInt64 *_retval); + static nsresult ConvertToUint8(const nsDiscriminatedUnion& data, PRUint8 *_retval); + static nsresult ConvertToUint16(const nsDiscriminatedUnion& data, PRUint16 *_retval); + static nsresult ConvertToUint32(const nsDiscriminatedUnion& data, PRUint32 *_retval); + static nsresult ConvertToUint64(const nsDiscriminatedUnion& data, PRUint64 *_retval); + static nsresult ConvertToFloat(const nsDiscriminatedUnion& data, float *_retval); + static nsresult ConvertToDouble(const nsDiscriminatedUnion& data, double *_retval); + static nsresult ConvertToBool(const nsDiscriminatedUnion& data, PRBool *_retval); + static nsresult ConvertToChar(const nsDiscriminatedUnion& data, char *_retval); + static nsresult ConvertToWChar(const nsDiscriminatedUnion& data, PRUnichar *_retval); + static nsresult ConvertToID(const nsDiscriminatedUnion& data, nsID * _retval); + static nsresult ConvertToAString(const nsDiscriminatedUnion& data, nsAString & _retval); + static nsresult ConvertToAUTF8String(const nsDiscriminatedUnion& data, nsAUTF8String & _retval); + static nsresult ConvertToACString(const nsDiscriminatedUnion& data, nsACString & _retval); + static nsresult ConvertToString(const nsDiscriminatedUnion& data, char **_retval); + static nsresult ConvertToWString(const nsDiscriminatedUnion& data, PRUnichar **_retval); + static nsresult ConvertToISupports(const nsDiscriminatedUnion& data, nsISupports **_retval); + static nsresult ConvertToInterface(const nsDiscriminatedUnion& data, nsIID * *iid, void * *iface); + static nsresult ConvertToArray(const nsDiscriminatedUnion& data, PRUint16 *type, nsIID* iid, PRUint32 *count, void * *ptr); + static nsresult ConvertToStringWithSize(const nsDiscriminatedUnion& data, PRUint32 *size, char **str); + static nsresult ConvertToWStringWithSize(const nsDiscriminatedUnion& data, PRUint32 *size, PRUnichar **str); + + static nsresult SetFromVariant(nsDiscriminatedUnion* data, nsIVariant* aValue); + + static nsresult SetFromInt8(nsDiscriminatedUnion* data, PRUint8 aValue); + static nsresult SetFromInt16(nsDiscriminatedUnion* data, PRInt16 aValue); + static nsresult SetFromInt32(nsDiscriminatedUnion* data, PRInt32 aValue); + static nsresult SetFromInt64(nsDiscriminatedUnion* data, PRInt64 aValue); + static nsresult SetFromUint8(nsDiscriminatedUnion* data, PRUint8 aValue); + static nsresult SetFromUint16(nsDiscriminatedUnion* data, PRUint16 aValue); + static nsresult SetFromUint32(nsDiscriminatedUnion* data, PRUint32 aValue); + static nsresult SetFromUint64(nsDiscriminatedUnion* data, PRUint64 aValue); + static nsresult SetFromFloat(nsDiscriminatedUnion* data, float aValue); + static nsresult SetFromDouble(nsDiscriminatedUnion* data, double aValue); + static nsresult SetFromBool(nsDiscriminatedUnion* data, PRBool aValue); + static nsresult SetFromChar(nsDiscriminatedUnion* data, char aValue); + static nsresult SetFromWChar(nsDiscriminatedUnion* data, PRUnichar aValue); + static nsresult SetFromID(nsDiscriminatedUnion* data, const nsID & aValue); + static nsresult SetFromAString(nsDiscriminatedUnion* data, const nsAString & aValue); + static nsresult SetFromAUTF8String(nsDiscriminatedUnion* data, const nsAUTF8String & aValue); + static nsresult SetFromACString(nsDiscriminatedUnion* data, const nsACString & aValue); + static nsresult SetFromString(nsDiscriminatedUnion* data, const char *aValue); + static nsresult SetFromWString(nsDiscriminatedUnion* data, const PRUnichar *aValue); + static nsresult SetFromISupports(nsDiscriminatedUnion* data, nsISupports *aValue); + static nsresult SetFromInterface(nsDiscriminatedUnion* data, const nsIID& iid, nsISupports *aValue); + static nsresult SetFromArray(nsDiscriminatedUnion* data, PRUint16 type, const nsIID* iid, PRUint32 count, void * aValue); + static nsresult SetFromStringWithSize(nsDiscriminatedUnion* data, PRUint32 size, const char *aValue); + static nsresult SetFromWStringWithSize(nsDiscriminatedUnion* data, PRUint32 size, const PRUnichar *aValue); + + static nsresult SetToVoid(nsDiscriminatedUnion* data); + static nsresult SetToEmpty(nsDiscriminatedUnion* data); + static nsresult SetToEmptyArray(nsDiscriminatedUnion* data); + +private: + ~nsVariant(); + +protected: + nsDiscriminatedUnion mData; + PRBool mWritable; +}; + +/** + * Users of nsIVariant should be using the contractID and not this CID. + * - see NS_VARIANT_CONTRACTID in nsIVariant.idl. + */ + +#define NS_VARIANT_CID \ +{ /* 0D6EA1D0-879C-11d5-90EF-0010A4E73D9A */ \ + 0xd6ea1d0, \ + 0x879c, \ + 0x11d5, \ + {0x90, 0xef, 0x0, 0x10, 0xa4, 0xe7, 0x3d, 0x9a}} + +#define NS_VARIANT_CLASSNAME "Variant" + diff --git a/src/libs/xpcom18a4/xpcom/ds/nsVoidArray.cpp b/src/libs/xpcom18a4/xpcom/ds/nsVoidArray.cpp new file mode 100644 index 00000000..259d0bd3 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsVoidArray.cpp @@ -0,0 +1,1560 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; c-file-offsets: ((substatement-open . 0)) -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsVoidArray.h" +#include "nsQuickSort.h" +#include "prmem.h" +#include "nsCRT.h" +#include "nsString.h" +#include "prbit.h" + +/** + * Grow the array by at least this many elements at a time. + */ +static const PRInt32 kMinGrowArrayBy = 8; +static const PRInt32 kMaxGrowArrayBy = 1024; + +/** + * This is the threshold (in bytes) of the mImpl struct, past which + * we'll force the array to grow geometrically + */ +static const PRInt32 kLinearThreshold = 24 * sizeof(void *); + +/** + * Compute the number of bytes requires for the mImpl struct that will + * hold |n| elements. + */ +#define SIZEOF_IMPL(n_) (sizeof(Impl) + sizeof(void *) * ((n_) - 1)) + + +/** + * Compute the number of elements that an mImpl struct of |n| bytes + * will hold. + */ +#define CAPACITYOF_IMPL(n_) ((((n_) - sizeof(Impl)) / sizeof(void *)) + 1) + +#if DEBUG_VOIDARRAY +#define MAXVOID 10 + +class VoidStats { +public: + VoidStats(); + ~VoidStats(); + +}; + +static int sizesUsed; // number of the elements of the arrays used +static int sizesAlloced[MAXVOID]; // sizes of the allocations. sorted +static int NumberOfSize[MAXVOID]; // number of this allocation size (1 per array) +static int AllocedOfSize[MAXVOID]; // number of this allocation size (each size for array used) +static int MaxAuto[MAXVOID]; // AutoArrays that maxed out at this size +static int GrowInPlace[MAXVOID]; // arrays this size that grew in-place via realloc + +// these are per-allocation +static int MaxElements[2000]; // # of arrays that maxed out at each size. + +// statistics macros +#define ADD_TO_STATS(x,size) do {int i; for (i = 0; i < sizesUsed; i++) \ + { \ + if (sizesAlloced[i] == (int)(size)) \ + { ((x)[i])++; break; } \ + } \ + if (i >= sizesUsed && sizesUsed < MAXVOID) \ + { sizesAlloced[sizesUsed] = (size); \ + ((x)[sizesUsed++])++; break; \ + } \ + } while (0) + +#define SUB_FROM_STATS(x,size) do {int i; for (i = 0; i < sizesUsed; i++) \ + { \ + if (sizesAlloced[i] == (int)(size)) \ + { ((x)[i])--; break; } \ + } \ + } while (0) + + +VoidStats::VoidStats() +{ + sizesUsed = 1; + sizesAlloced[0] = 0; +} + +VoidStats::~VoidStats() +{ + int i; + for (i = 0; i < sizesUsed; i++) + { + printf("Size %d:\n",sizesAlloced[i]); + printf("\tNumber of VoidArrays this size (max): %d\n",NumberOfSize[i]-MaxAuto[i]); + printf("\tNumber of AutoVoidArrays this size (max): %d\n",MaxAuto[i]); + printf("\tNumber of allocations this size (total): %d\n",AllocedOfSize[i]); + printf("\tNumber of GrowsInPlace this size (total): %d\n",GrowInPlace[i]); + } + printf("Max Size of VoidArray:\n"); + for (i = 0; i < (int)(sizeof(MaxElements)/sizeof(MaxElements[0])); i++) + { + if (MaxElements[i]) + printf("\t%d: %d\n",i,MaxElements[i]); + } +} + +// Just so constructor/destructor's get called +VoidStats gVoidStats; +#endif + +inline void +nsVoidArray::SetArray(Impl *newImpl, PRInt32 aSize, PRInt32 aCount, PRBool owner) +{ + // old mImpl has been realloced and so we don't free/delete it + NS_PRECONDITION(newImpl, "can't set size"); + mImpl = newImpl; + mImpl->mCount = aCount; + mImpl->mBits = PRUint32(aSize & kArraySizeMask) | + (owner ? kArrayOwnerMask : 0); +} + +// This does all allocation/reallocation of the array. +// It also will compact down to N - good for things that might grow a lot +// at times, but usually are smaller, like JS deferred GC releases. +PRBool nsVoidArray::SizeTo(PRInt32 aSize) +{ + PRUint32 oldsize = GetArraySize(); + + if (aSize == (PRInt32) oldsize) + return PR_TRUE; // no change + + if (aSize <= 0) + { + // free the array if allocated + if (mImpl) + { + if (IsArrayOwner()) + { + PR_Free(NS_REINTERPRET_CAST(char *, mImpl)); + mImpl = nsnull; + } + else + { + mImpl->mCount = 0; // nsAutoVoidArray + } + } + return PR_TRUE; + } + + if (mImpl && IsArrayOwner()) + { + // We currently own an array impl. Resize it appropriately. + if (aSize < mImpl->mCount) + { + // XXX Note: we could also just resize to mCount + return PR_TRUE; // can't make it that small, ignore request + } + + char* bytes = (char *) PR_Realloc(mImpl,SIZEOF_IMPL(aSize)); + Impl* newImpl = NS_REINTERPRET_CAST(Impl*, bytes); + if (!newImpl) + return PR_FALSE; + +#if DEBUG_VOIDARRAY + if (mImpl == newImpl) + ADD_TO_STATS(GrowInPlace,oldsize); + ADD_TO_STATS(AllocedOfSize,SIZEOF_IMPL(aSize)); + if (aSize > mMaxSize) + { + ADD_TO_STATS(NumberOfSize,SIZEOF_IMPL(aSize)); + if (oldsize) + SUB_FROM_STATS(NumberOfSize,oldsize); + mMaxSize = aSize; + if (mIsAuto) + { + ADD_TO_STATS(MaxAuto,SIZEOF_IMPL(aSize)); + SUB_FROM_STATS(MaxAuto,oldsize); + } + } +#endif + SetArray(newImpl,aSize,newImpl->mCount,PR_TRUE); + return PR_TRUE; + } + + // just allocate an array + // allocate the exact size requested + char* bytes = (char *) PR_Malloc(SIZEOF_IMPL(aSize)); + Impl* newImpl = NS_REINTERPRET_CAST(Impl*, bytes); + if (!newImpl) + return PR_FALSE; + +#if DEBUG_VOIDARRAY + ADD_TO_STATS(AllocedOfSize,SIZEOF_IMPL(aSize)); + if (aSize > mMaxSize) + { + ADD_TO_STATS(NumberOfSize,SIZEOF_IMPL(aSize)); + if (oldsize && !mImpl) + SUB_FROM_STATS(NumberOfSize,oldsize); + mMaxSize = aSize; + } +#endif + if (mImpl) + { +#if DEBUG_VOIDARRAY + ADD_TO_STATS(MaxAuto,SIZEOF_IMPL(aSize)); + SUB_FROM_STATS(MaxAuto,0); + SUB_FROM_STATS(NumberOfSize,0); + mIsAuto = PR_TRUE; +#endif + // We must be growing an nsAutoVoidArray - copy since we didn't + // realloc. + memcpy(newImpl->mArray, mImpl->mArray, + mImpl->mCount * sizeof(mImpl->mArray[0])); + } + + SetArray(newImpl,aSize,mImpl ? mImpl->mCount : 0,PR_TRUE); + // no memset; handled later in ReplaceElementAt if needed + return PR_TRUE; +} + +PRBool nsVoidArray::GrowArrayBy(PRInt32 aGrowBy) +{ + // We have to grow the array. Grow by kMinGrowArrayBy slots if we're + // smaller than kLinearThreshold bytes, or a power of two if we're + // larger. This is much more efficient with most memory allocators, + // especially if it's very large, or of the allocator is binned. + if (aGrowBy < kMinGrowArrayBy) + aGrowBy = kMinGrowArrayBy; + + PRUint32 newCapacity = GetArraySize() + aGrowBy; // Minimum increase + PRUint32 newSize = SIZEOF_IMPL(newCapacity); + + if (newSize >= (PRUint32) kLinearThreshold) + { + // newCount includes enough space for at least kMinGrowArrayBy new + // slots. Select the next power-of-two size in bytes above or + // equal to that. + // Also, limit the increase in size to about a VM page or two. + if (GetArraySize() >= kMaxGrowArrayBy) + { + newCapacity = GetArraySize() + PR_MAX(kMaxGrowArrayBy,aGrowBy); + newSize = SIZEOF_IMPL(newCapacity); + } + else + { + newSize = PR_BIT(PR_CeilingLog2(newSize)); + newCapacity = CAPACITYOF_IMPL(newSize); + } + } + // frees old mImpl IF this succeeds + if (!SizeTo(newCapacity)) + return PR_FALSE; + + return PR_TRUE; +} + +nsVoidArray::nsVoidArray() + : mImpl(nsnull) +{ + MOZ_COUNT_CTOR(nsVoidArray); +#if DEBUG_VOIDARRAY + mMaxCount = 0; + mMaxSize = 0; + mIsAuto = PR_FALSE; + ADD_TO_STATS(NumberOfSize,0); + MaxElements[0]++; +#endif +} + +nsVoidArray::nsVoidArray(PRInt32 aCount) + : mImpl(nsnull) +{ + MOZ_COUNT_CTOR(nsVoidArray); +#if DEBUG_VOIDARRAY + mMaxCount = 0; + mMaxSize = 0; + mIsAuto = PR_FALSE; + MaxElements[0]++; +#endif + SizeTo(aCount); +} + +nsVoidArray& nsVoidArray::operator=(const nsVoidArray& other) +{ + PRInt32 otherCount = other.Count(); + PRInt32 maxCount = GetArraySize(); + if (otherCount) + { + if (otherCount > maxCount) + { + // frees old mImpl IF this succeeds + if (!GrowArrayBy(otherCount-maxCount)) + return *this; // XXX The allocation failed - don't do anything + + memcpy(mImpl->mArray, other.mImpl->mArray, otherCount * sizeof(mImpl->mArray[0])); + mImpl->mCount = otherCount; + } + else + { + // the old array can hold the new array + memcpy(mImpl->mArray, other.mImpl->mArray, otherCount * sizeof(mImpl->mArray[0])); + mImpl->mCount = otherCount; + // if it shrank a lot, compact it anyways + if ((otherCount*2) < maxCount && maxCount > 100) + { + Compact(); // shrank by at least 50 entries + } + } +#if DEBUG_VOIDARRAY + if (mImpl->mCount > mMaxCount && + mImpl->mCount < (PRInt32)(sizeof(MaxElements)/sizeof(MaxElements[0]))) + { + MaxElements[mImpl->mCount]++; + MaxElements[mMaxCount]--; + mMaxCount = mImpl->mCount; + } +#endif + } + else + { + if (mImpl && IsArrayOwner()) + PR_Free(NS_REINTERPRET_CAST(char*, mImpl)); + + mImpl = nsnull; + } + + return *this; +} + +nsVoidArray::~nsVoidArray() +{ + MOZ_COUNT_DTOR(nsVoidArray); + if (mImpl && IsArrayOwner()) + PR_Free(NS_REINTERPRET_CAST(char*, mImpl)); +} + +PRInt32 nsVoidArray::IndexOf(void* aPossibleElement) const +{ + if (mImpl) + { + void** ap = mImpl->mArray; + void** end = ap + mImpl->mCount; + while (ap < end) + { + if (*ap == aPossibleElement) + { + return ap - mImpl->mArray; + } + ap++; + } + } + return -1; +} + +PRBool nsVoidArray::InsertElementAt(void* aElement, PRInt32 aIndex) +{ + PRInt32 oldCount = Count(); + NS_ASSERTION(aIndex >= 0,"InsertElementAt(negative index)"); + if (PRUint32(aIndex) > PRUint32(oldCount)) + { + // An invalid index causes the insertion to fail + // Invalid indexes are ones that add more than one entry to the + // array (i.e., they can append). + return PR_FALSE; + } + + if (oldCount >= GetArraySize()) + { + if (!GrowArrayBy(1)) + return PR_FALSE; + } + // else the array is already large enough + + PRInt32 slide = oldCount - aIndex; + if (0 != slide) + { + // Slide data over to make room for the insertion + memmove(mImpl->mArray + aIndex + 1, mImpl->mArray + aIndex, + slide * sizeof(mImpl->mArray[0])); + } + + mImpl->mArray[aIndex] = aElement; + mImpl->mCount++; + +#if DEBUG_VOIDARRAY + if (mImpl->mCount > mMaxCount && + mImpl->mCount < (PRInt32)(sizeof(MaxElements)/sizeof(MaxElements[0]))) + { + MaxElements[mImpl->mCount]++; + MaxElements[mMaxCount]--; + mMaxCount = mImpl->mCount; + } +#endif + + return PR_TRUE; +} + +PRBool nsVoidArray::InsertElementsAt(const nsVoidArray& other, PRInt32 aIndex) +{ + PRInt32 oldCount = Count(); + PRInt32 otherCount = other.Count(); + + NS_ASSERTION(aIndex >= 0,"InsertElementsAt(negative index)"); + if (PRUint32(aIndex) > PRUint32(oldCount)) + { + // An invalid index causes the insertion to fail + // Invalid indexes are ones that are more than one entry past the end of + // the array (i.e., they can append). + return PR_FALSE; + } + + if (oldCount + otherCount > GetArraySize()) + { + if (!GrowArrayBy(otherCount)) + return PR_FALSE;; + } + // else the array is already large enough + + PRInt32 slide = oldCount - aIndex; + if (0 != slide) + { + // Slide data over to make room for the insertion + memmove(mImpl->mArray + aIndex + otherCount, mImpl->mArray + aIndex, + slide * sizeof(mImpl->mArray[0])); + } + + for (PRInt32 i = 0; i < otherCount; i++) + { + // copy all the elements (destroys aIndex) + mImpl->mArray[aIndex++] = other.mImpl->mArray[i]; + mImpl->mCount++; + } + +#if DEBUG_VOIDARRAY + if (mImpl->mCount > mMaxCount && + mImpl->mCount < (PRInt32)(sizeof(MaxElements)/sizeof(MaxElements[0]))) + { + MaxElements[mImpl->mCount]++; + MaxElements[mMaxCount]--; + mMaxCount = mImpl->mCount; + } +#endif + + return PR_TRUE; +} + +PRBool nsVoidArray::ReplaceElementAt(void* aElement, PRInt32 aIndex) +{ + NS_ASSERTION(aIndex >= 0,"ReplaceElementAt(negative index)"); + if (aIndex < 0) + return PR_FALSE; + + // Unlike InsertElementAt, ReplaceElementAt can implicitly add more + // than just the one element to the array. + if (PRUint32(aIndex) >= PRUint32(GetArraySize())) + { + PRInt32 oldCount = Count(); + PRInt32 requestedCount = aIndex + 1; + PRInt32 growDelta = requestedCount - oldCount; + + // frees old mImpl IF this succeeds + if (!GrowArrayBy(growDelta)) + return PR_FALSE; + } + + mImpl->mArray[aIndex] = aElement; + if (aIndex >= mImpl->mCount) + { + // Make sure that any entries implicitly added to the array by this + // ReplaceElementAt are cleared to 0. Some users of this assume that. + // This code means we don't have to memset when we allocate an array. + if (aIndex > mImpl->mCount) // note: not >= + { + // For example, if mCount is 2, and we do a ReplaceElementAt for + // element[5], then we need to set three entries ([2], [3], and [4]) + // to 0. + memset(&mImpl->mArray[mImpl->mCount], 0, + (aIndex - mImpl->mCount) * sizeof(mImpl->mArray[0])); + } + + mImpl->mCount = aIndex + 1; + +#if DEBUG_VOIDARRAY + if (mImpl->mCount > mMaxCount && + mImpl->mCount < (PRInt32)(sizeof(MaxElements)/sizeof(MaxElements[0]))) + { + MaxElements[mImpl->mCount]++; + MaxElements[mMaxCount]--; + mMaxCount = mImpl->mCount; + } +#endif + } + + return PR_TRUE; +} + +// useful for doing LRU arrays +PRBool nsVoidArray::MoveElement(PRInt32 aFrom, PRInt32 aTo) +{ + void *tempElement; + + if (aTo == aFrom) + return PR_TRUE; + + NS_ASSERTION(aTo >= 0 && aFrom >= 0,"MoveElement(negative index)"); + if (aTo >= Count() || aFrom >= Count()) + { + // can't extend the array when moving an element. Also catches mImpl = null + return PR_FALSE; + } + tempElement = mImpl->mArray[aFrom]; + + if (aTo < aFrom) + { + // Moving one element closer to the head; the elements inbetween move down + memmove(mImpl->mArray + aTo + 1, mImpl->mArray + aTo, + (aFrom-aTo) * sizeof(mImpl->mArray[0])); + mImpl->mArray[aTo] = tempElement; + } + else // already handled aFrom == aTo + { + // Moving one element closer to the tail; the elements inbetween move up + memmove(mImpl->mArray + aFrom, mImpl->mArray + aFrom + 1, + (aTo-aFrom) * sizeof(mImpl->mArray[0])); + mImpl->mArray[aTo] = tempElement; + } + + return PR_TRUE; +} + +PRBool nsVoidArray::RemoveElementsAt(PRInt32 aIndex, PRInt32 aCount) +{ + PRInt32 oldCount = Count(); + NS_ASSERTION(aIndex >= 0,"RemoveElementsAt(negative index)"); + if (PRUint32(aIndex) >= PRUint32(oldCount)) + { + // An invalid index causes the replace to fail + return PR_FALSE; + } + // Limit to available entries starting at aIndex + if (aCount + aIndex > oldCount) + aCount = oldCount - aIndex; + + // We don't need to move any elements if we're removing the + // last element in the array + if (aIndex < (oldCount - aCount)) + { + memmove(mImpl->mArray + aIndex, mImpl->mArray + aIndex + aCount, + (oldCount - (aIndex + aCount)) * sizeof(mImpl->mArray[0])); + } + + mImpl->mCount -= aCount; + return PR_TRUE; +} + +PRBool nsVoidArray::RemoveElement(void* aElement) +{ + PRInt32 theIndex = IndexOf(aElement); + if (theIndex != -1) + return RemoveElementAt(theIndex); + + return PR_FALSE; +} + +void nsVoidArray::Clear() +{ + if (mImpl) + { + mImpl->mCount = 0; + } +} + +void nsVoidArray::Compact() +{ + if (mImpl) + { + // XXX NOTE: this is quite inefficient in many cases if we're only + // compacting by a little, but some callers care more about memory use. + if (GetArraySize() > Count()) + { + SizeTo(Count()); + } + } +} + +// Needed because we want to pass the pointer to the item in the array +// to the comparator function, not a pointer to the pointer in the array. +struct VoidArrayComparatorContext { + nsVoidArrayComparatorFunc mComparatorFunc; + void* mData; +}; + +PR_STATIC_CALLBACK(int) +VoidArrayComparator(const void* aElement1, const void* aElement2, void* aData) +{ + VoidArrayComparatorContext* ctx = NS_STATIC_CAST(VoidArrayComparatorContext*, aData); + return (*ctx->mComparatorFunc)(*NS_STATIC_CAST(void* const*, aElement1), + *NS_STATIC_CAST(void* const*, aElement2), + ctx->mData); +} + +void nsVoidArray::Sort(nsVoidArrayComparatorFunc aFunc, void* aData) +{ + if (mImpl && mImpl->mCount > 1) + { + VoidArrayComparatorContext ctx = {aFunc, aData}; + NS_QuickSort(mImpl->mArray, mImpl->mCount, sizeof(mImpl->mArray[0]), + VoidArrayComparator, &ctx); + } +} + +PRBool nsVoidArray::EnumerateForwards(nsVoidArrayEnumFunc aFunc, void* aData) +{ + PRInt32 index = -1; + PRBool running = PR_TRUE; + + if (mImpl) + { + while (running && (++index < mImpl->mCount)) + { + running = (*aFunc)(mImpl->mArray[index], aData); + } + } + return running; +} + +PRBool nsVoidArray::EnumerateBackwards(nsVoidArrayEnumFunc aFunc, void* aData) +{ + PRBool running = PR_TRUE; + + if (mImpl) + { + PRInt32 index = Count(); + while (running && (0 <= --index)) + { + running = (*aFunc)(mImpl->mArray[index], aData); + } + } + return running; +} + +//---------------------------------------------------------------- +// nsAutoVoidArray + +nsAutoVoidArray::nsAutoVoidArray() + : nsVoidArray() +{ + // Don't need to clear it. Some users just call ReplaceElementAt(), + // but we'll clear it at that time if needed to save CPU cycles. +#if DEBUG_VOIDARRAY + mIsAuto = PR_TRUE; + ADD_TO_STATS(MaxAuto,0); +#endif + SetArray(NS_REINTERPRET_CAST(Impl*, mAutoBuf),kAutoBufSize,0,PR_FALSE); +} + +void nsAutoVoidArray::Clear() +{ + // We don't have to free on Clear, but since we have a built-in buffer, + // it's worth considering. + nsVoidArray::Clear(); + if (IsArrayOwner() && GetArraySize() > 4*kAutoBufSize) + SizeTo(0); // we override CompactTo - delete and repoint at auto array +} + +PRBool nsAutoVoidArray::SizeTo(PRInt32 aSize) +{ + if (!nsVoidArray::SizeTo(aSize)) + return PR_FALSE; + + if (!mImpl) + { + // reset the array to point to our autobuf + SetArray(NS_REINTERPRET_CAST(Impl*, mAutoBuf),kAutoBufSize,0,PR_FALSE); + } + return PR_TRUE; +} + +void nsAutoVoidArray::Compact() +{ + nsVoidArray::Compact(); + if (!mImpl) + { + // reset the array to point to our autobuf + SetArray(NS_REINTERPRET_CAST(Impl*, mAutoBuf),kAutoBufSize,0,PR_FALSE); + } +} + +//---------------------------------------------------------------- +// nsStringArray + +nsStringArray::nsStringArray(void) + : nsVoidArray() +{ +} + +nsStringArray::nsStringArray(PRInt32 aCount) + : nsVoidArray(aCount) +{ +} + +nsStringArray::~nsStringArray(void) +{ + Clear(); +} + +nsStringArray& +nsStringArray::operator=(const nsStringArray& other) +{ + // Copy the pointers + nsVoidArray::operator=(other); + + // Now copy the strings + for (PRInt32 i = Count() - 1; i >= 0; --i) + { + nsString* oldString = NS_STATIC_CAST(nsString*, other.ElementAt(i)); + mImpl->mArray[i] = new nsString(*oldString); + } + + return *this; +} + +void +nsStringArray::StringAt(PRInt32 aIndex, nsAString& aString) const +{ + nsString* string = NS_STATIC_CAST(nsString*, nsVoidArray::ElementAt(aIndex)); + if (nsnull != string) + { + aString.Assign(*string); + } + else + { + aString.Truncate(); + } +} + +nsString* +nsStringArray::StringAt(PRInt32 aIndex) const +{ + return NS_STATIC_CAST(nsString*, nsVoidArray::ElementAt(aIndex)); +} + +PRInt32 +nsStringArray::IndexOf(const nsAString& aPossibleString) const +{ + if (mImpl) + { + void** ap = mImpl->mArray; + void** end = ap + mImpl->mCount; + while (ap < end) + { + nsString* string = NS_STATIC_CAST(nsString*, *ap); + if (string->Equals(aPossibleString)) + { + return ap - mImpl->mArray; + } + ap++; + } + } + return -1; +} + +PRBool +nsStringArray::InsertStringAt(const nsAString& aString, PRInt32 aIndex) +{ + nsString* string = new nsString(aString); + if (nsVoidArray::InsertElementAt(string, aIndex)) + { + return PR_TRUE; + } + delete string; + return PR_FALSE; +} + +PRBool +nsStringArray::ReplaceStringAt(const nsAString& aString, + PRInt32 aIndex) +{ + nsString* string = NS_STATIC_CAST(nsString*, nsVoidArray::ElementAt(aIndex)); + if (nsnull != string) + { + *string = aString; + return PR_TRUE; + } + return PR_FALSE; +} + +PRBool +nsStringArray::RemoveString(const nsAString& aString) +{ + PRInt32 index = IndexOf(aString); + if (-1 < index) + { + return RemoveStringAt(index); + } + return PR_FALSE; +} + +PRBool nsStringArray::RemoveStringAt(PRInt32 aIndex) +{ + nsString* string = StringAt(aIndex); + if (nsnull != string) + { + nsVoidArray::RemoveElementAt(aIndex); + delete string; + return PR_TRUE; + } + return PR_FALSE; +} + +void +nsStringArray::Clear(void) +{ + PRInt32 index = Count(); + while (0 <= --index) + { + nsString* string = NS_STATIC_CAST(nsString*, mImpl->mArray[index]); + delete string; + } + nsVoidArray::Clear(); +} + +PR_STATIC_CALLBACK(int) +CompareString(const nsString* aString1, const nsString* aString2, void*) +{ + return Compare(*aString1, *aString2); +} + +void nsStringArray::Sort(void) +{ + Sort(CompareString, nsnull); +} + +void nsStringArray::Sort(nsStringArrayComparatorFunc aFunc, void* aData) +{ + nsVoidArray::Sort(NS_REINTERPRET_CAST(nsVoidArrayComparatorFunc, aFunc), aData); +} + +PRBool +nsStringArray::EnumerateForwards(nsStringArrayEnumFunc aFunc, void* aData) +{ + PRInt32 index = -1; + PRBool running = PR_TRUE; + + if (mImpl) + { + while (running && (++index < mImpl->mCount)) + { + running = (*aFunc)(*NS_STATIC_CAST(nsString*, mImpl->mArray[index]), aData); + } + } + return running; +} + +PRBool +nsStringArray::EnumerateBackwards(nsStringArrayEnumFunc aFunc, void* aData) +{ + PRInt32 index = Count(); + PRBool running = PR_TRUE; + + if (mImpl) + { + while (running && (0 <= --index)) + { + running = (*aFunc)(*NS_STATIC_CAST(nsString*, mImpl->mArray[index]), aData); + } + } + return running; +} + + + +//---------------------------------------------------------------- +// nsCStringArray + +nsCStringArray::nsCStringArray(void) + : nsVoidArray() +{ +} + +// Parses a given string using the delimiter passed in and appends items +// parsed to the array. +void +nsCStringArray::ParseString(const char* string, const char* delimiter) +{ + if (string && *string && delimiter && *delimiter) { + char *newStr; + char *rest = nsCRT::strdup(string); + char *token = nsCRT::strtok(rest, delimiter, &newStr); + + while (token) { + if (*token) { + /* calling AppendElement(void*) to avoid extra nsCString copy */ + AppendElement(new nsCString(token)); + } + token = nsCRT::strtok(newStr, delimiter, &newStr); + } + PR_FREEIF(rest); + } +} + +nsCStringArray::nsCStringArray(PRInt32 aCount) + : nsVoidArray(aCount) +{ +} + +nsCStringArray::~nsCStringArray(void) +{ + Clear(); +} + +nsCStringArray& +nsCStringArray::operator=(const nsCStringArray& other) +{ + // Copy the pointers + nsVoidArray::operator=(other); + + // Now copy the strings + for (PRInt32 i = Count() - 1; i >= 0; --i) + { + nsCString* oldString = NS_STATIC_CAST(nsCString*, other.ElementAt(i)); + mImpl->mArray[i] = new nsCString(*oldString); + } + + return *this; +} + +void +nsCStringArray::CStringAt(PRInt32 aIndex, nsACString& aCString) const +{ + nsCString* string = NS_STATIC_CAST(nsCString*, nsVoidArray::ElementAt(aIndex)); + if (nsnull != string) + { + aCString = *string; + } + else + { + aCString.Truncate(); + } +} + +nsCString* +nsCStringArray::CStringAt(PRInt32 aIndex) const +{ + return NS_STATIC_CAST(nsCString*, nsVoidArray::ElementAt(aIndex)); +} + +PRInt32 +nsCStringArray::IndexOf(const nsACString& aPossibleString) const +{ + if (mImpl) + { + void** ap = mImpl->mArray; + void** end = ap + mImpl->mCount; + while (ap < end) + { + nsCString* string = NS_STATIC_CAST(nsCString*, *ap); + if (string->Equals(aPossibleString)) + { + return ap - mImpl->mArray; + } + ap++; + } + } + return -1; +} + +PRInt32 +nsCStringArray::IndexOfIgnoreCase(const nsACString& aPossibleString) const +{ + if (mImpl) + { + void** ap = mImpl->mArray; + void** end = ap + mImpl->mCount; + while (ap < end) + { + nsCString* string = NS_STATIC_CAST(nsCString*, *ap); + if (string->Equals(aPossibleString, nsCaseInsensitiveCStringComparator())) + { + return ap - mImpl->mArray; + } + ap++; + } + } + return -1; +} + +PRBool +nsCStringArray::InsertCStringAt(const nsACString& aCString, PRInt32 aIndex) +{ + nsCString* string = new nsCString(aCString); + if (nsVoidArray::InsertElementAt(string, aIndex)) + { + return PR_TRUE; + } + delete string; + return PR_FALSE; +} + +PRBool +nsCStringArray::ReplaceCStringAt(const nsACString& aCString, PRInt32 aIndex) +{ + nsCString* string = NS_STATIC_CAST(nsCString*, nsVoidArray::ElementAt(aIndex)); + if (nsnull != string) + { + *string = aCString; + return PR_TRUE; + } + return PR_FALSE; +} + +PRBool +nsCStringArray::RemoveCString(const nsACString& aCString) +{ + PRInt32 index = IndexOf(aCString); + if (-1 < index) + { + return RemoveCStringAt(index); + } + return PR_FALSE; +} + +PRBool +nsCStringArray::RemoveCStringIgnoreCase(const nsACString& aCString) +{ + PRInt32 index = IndexOfIgnoreCase(aCString); + if (-1 < index) + { + return RemoveCStringAt(index); + } + return PR_FALSE; +} + +PRBool nsCStringArray::RemoveCStringAt(PRInt32 aIndex) +{ + nsCString* string = CStringAt(aIndex); + if (nsnull != string) + { + nsVoidArray::RemoveElementAt(aIndex); + delete string; + return PR_TRUE; + } + return PR_FALSE; +} + +void +nsCStringArray::Clear(void) +{ + PRInt32 index = Count(); + while (0 <= --index) + { + nsCString* string = NS_STATIC_CAST(nsCString*, mImpl->mArray[index]); + delete string; + } + nsVoidArray::Clear(); +} + +PR_STATIC_CALLBACK(int) +CompareCString(const nsCString* aCString1, const nsCString* aCString2, void*) +{ + return Compare(*aCString1, *aCString2); +} + +PR_STATIC_CALLBACK(int) +CompareCStringIgnoreCase(const nsCString* aCString1, const nsCString* aCString2, void*) +{ + return Compare(*aCString1, *aCString2, nsCaseInsensitiveCStringComparator()); +} + +void nsCStringArray::Sort(void) +{ + Sort(CompareCString, nsnull); +} + +void nsCStringArray::SortIgnoreCase(void) +{ + Sort(CompareCStringIgnoreCase, nsnull); +} + +void nsCStringArray::Sort(nsCStringArrayComparatorFunc aFunc, void* aData) +{ + nsVoidArray::Sort(NS_REINTERPRET_CAST(nsVoidArrayComparatorFunc, aFunc), aData); +} + +PRBool +nsCStringArray::EnumerateForwards(nsCStringArrayEnumFunc aFunc, void* aData) +{ + PRBool running = PR_TRUE; + + if (mImpl) + { + PRInt32 index = -1; + while (running && (++index < mImpl->mCount)) + { + running = (*aFunc)(*NS_STATIC_CAST(nsCString*, mImpl->mArray[index]), aData); + } + } + return running; +} + +PRBool +nsCStringArray::EnumerateBackwards(nsCStringArrayEnumFunc aFunc, void* aData) +{ + PRBool running = PR_TRUE; + + if (mImpl) + { + PRInt32 index = Count(); + while (running && (0 <= --index)) + { + running = (*aFunc)(*NS_STATIC_CAST(nsCString*, mImpl->mArray[index]), aData); + } + } + return running; +} + + +//---------------------------------------------------------------------- +// NOTE: nsSmallVoidArray elements MUST all have the low bit as 0. +// This means that normally it's only used for pointers, and in particular +// structures or objects. +nsSmallVoidArray::nsSmallVoidArray() +{ + mChildren = nsnull; +} + +nsSmallVoidArray::~nsSmallVoidArray() +{ + if (HasVector()) + { + nsVoidArray* vector = GetChildVector(); + delete vector; + } +} + +nsSmallVoidArray& +nsSmallVoidArray::operator=(nsSmallVoidArray& other) +{ + nsVoidArray* ourArray = GetChildVector(); + nsVoidArray* otherArray = other.GetChildVector(); + + if (HasVector()) + { + if (other.HasVector()) + { + // if both are real arrays, just use array= */ + *ourArray = *otherArray; + } + else + { + // we have an array, but the other doesn't. + otherArray = other.SwitchToVector(); + if (otherArray) + *ourArray = *otherArray; + } + } + else + { + if (other.HasVector()) + { + // we have no array, but other does + ourArray = SwitchToVector(); + if (ourArray) + *ourArray = *otherArray; + } + else + { + // neither has an array (either may have 0 or 1 items) + SetSingleChild(other.GetSingleChild()); + } + } + return *this; +} + +PRInt32 +nsSmallVoidArray::GetArraySize() const +{ + nsVoidArray* vector = GetChildVector(); + if (vector) + return vector->GetArraySize(); + + return 1; +} + +PRInt32 +nsSmallVoidArray::Count() const +{ + if (HasSingleChild()) + { + return 1; + } + else { + nsVoidArray* vector = GetChildVector(); + if (vector) + return vector->Count(); + } + + return 0; +} + +void* +nsSmallVoidArray::ElementAt(PRInt32 aIndex) const +{ + if (HasSingleChild()) + { + if (0 == aIndex) + return (void*)GetSingleChild(); + } + else + { + nsVoidArray* vector = GetChildVector(); + if (vector) + return vector->ElementAt(aIndex); + } + + return nsnull; +} + +PRInt32 +nsSmallVoidArray::IndexOf(void* aPossibleElement) const +{ + if (HasSingleChild()) + { + if (aPossibleElement == (void*)GetSingleChild()) + return 0; + } + else + { + nsVoidArray* vector = GetChildVector(); + if (vector) + return vector->IndexOf(aPossibleElement); + } + + return -1; +} + +PRBool +nsSmallVoidArray::InsertElementAt(void* aElement, PRInt32 aIndex) +{ + nsVoidArray* vector; + NS_ASSERTION(!(PtrBits(aElement) & 0x1),"Attempt to add element with 0x1 bit set to nsSmallVoidArray"); + NS_ASSERTION(aElement != nsnull,"Attempt to add a NULL element to an nsSmallVoidArray"); + + if (HasSingleChild()) + { + vector = SwitchToVector(); + } + else + { + vector = GetChildVector(); + if (!vector) + { + if (0 == aIndex) + { + SetSingleChild(aElement); + return PR_TRUE; + } + return PR_FALSE; + } + } + + return vector->InsertElementAt(aElement, aIndex); +} + +PRBool nsSmallVoidArray::InsertElementsAt(const nsVoidArray &other, PRInt32 aIndex) +{ + nsVoidArray* vector; + PRInt32 count = other.Count(); + if (count == 0) + return PR_TRUE; + +#ifdef DEBUG + for (int i = 0; i < count; i++) + { + NS_ASSERTION(!(PtrBits(other.ElementAt(i)) & 0x1),"Attempt to add element with 0x1 bit set to nsSmallVoidArray"); + NS_ASSERTION(other.ElementAt(i) != nsnull,"Attempt to add a NULL element to an nsSmallVoidArray"); + } +#endif + + if (!HasVector()) + { + if (HasSingleChild() || count > 1 || aIndex > 0) + { + vector = SwitchToVector(); + } + else + { + // count == 1, aIndex == 0, no elements already + SetSingleChild(other[0]); + return PR_TRUE; + } + } + else + { + vector = GetChildVector(); + } + + if (vector) + { + return vector->InsertElementsAt(other,aIndex); + } + return PR_TRUE; +} + +PRBool +nsSmallVoidArray::ReplaceElementAt(void* aElement, PRInt32 aIndex) +{ + NS_ASSERTION(!(PtrBits(aElement) & 0x1),"Attempt to add element with 0x1 bit set to nsSmallVoidArray"); + NS_ASSERTION(aElement != nsnull,"Attempt to add a NULL element to an nsSmallVoidArray"); + + if (HasSingleChild()) + { + if (aIndex == 0) + { + SetSingleChild(aElement); + return PR_TRUE; + } + return PR_FALSE; + } + else + { + nsVoidArray* vector = GetChildVector(); + if (vector) + return vector->ReplaceElementAt(aElement, aIndex); + + return PR_FALSE; + } +} + +PRBool +nsSmallVoidArray::AppendElement(void* aElement) +{ + NS_ASSERTION(!(PtrBits(aElement) & 0x1),"Attempt to add element with 0x1 bit set to nsSmallVoidArray"); + NS_ASSERTION(aElement != nsnull,"Attempt to add a NULL element to an nsSmallVoidArray"); + + nsVoidArray* vector; + if (HasSingleChild()) + { + vector = SwitchToVector(); + } + else + { + vector = GetChildVector(); + if (!vector) + { + SetSingleChild(aElement); + return PR_TRUE; + } + } + + return vector->AppendElement(aElement); +} + +PRBool +nsSmallVoidArray::RemoveElement(void* aElement) +{ + if (HasSingleChild()) + { + if (aElement == GetSingleChild()) + { + SetSingleChild(nsnull); + return PR_TRUE; + } + } + else + { + nsVoidArray* vector = GetChildVector(); + if (vector) + return vector->RemoveElement(aElement); + } + + return PR_FALSE; +} + +PRBool +nsSmallVoidArray::RemoveElementAt(PRInt32 aIndex) +{ + if (HasSingleChild()) + { + if (0 == aIndex) + { + SetSingleChild(nsnull); + return PR_TRUE; + } + } + else + { + nsVoidArray* vector = GetChildVector(); + if (vector) + { + return vector->RemoveElementAt(aIndex); + } + } + + return PR_FALSE; +} + +PRBool +nsSmallVoidArray::RemoveElementsAt(PRInt32 aIndex, PRInt32 aCount) +{ + nsVoidArray* vector = GetChildVector(); + + if (aCount == 0) + return PR_TRUE; + + if (HasSingleChild()) + { + if (aIndex == 0) + SetSingleChild(nsnull); + return PR_TRUE; + } + + if (!vector) + return PR_TRUE; + + // complex case; remove entries from an array + return vector->RemoveElementsAt(aIndex,aCount); +} + +void +nsSmallVoidArray::Clear() +{ + if (HasVector()) + { + nsVoidArray* vector = GetChildVector(); + vector->Clear(); + } + else + { + SetSingleChild(nsnull); + } +} + +PRBool +nsSmallVoidArray::SizeTo(PRInt32 aMin) +{ + nsVoidArray* vector; + if (!HasVector()) + { + if (aMin <= 1) + return PR_TRUE; + vector = SwitchToVector(); + } + else + { + vector = GetChildVector(); + if (aMin <= 1) + { + void *prev = nsnull; + if (vector->Count() == 1) + { + prev = vector->ElementAt(0); + } + delete vector; + SetSingleChild(prev); + return PR_TRUE; + } + } + return vector->SizeTo(aMin); +} + +void +nsSmallVoidArray::Compact() +{ + if (!HasSingleChild()) + { + nsVoidArray* vector = GetChildVector(); + if (vector) + vector->Compact(); + } +} + +void +nsSmallVoidArray::Sort(nsVoidArrayComparatorFunc aFunc, void* aData) +{ + if (HasVector()) + { + nsVoidArray* vector = GetChildVector(); + vector->Sort(aFunc,aData); + } +} + +PRBool +nsSmallVoidArray::EnumerateForwards(nsVoidArrayEnumFunc aFunc, void* aData) +{ + if (HasVector()) + { + nsVoidArray* vector = GetChildVector(); + return vector->EnumerateForwards(aFunc,aData); + } + if (HasSingleChild()) + { + return (*aFunc)(GetSingleChild(), aData); + } + return PR_TRUE; +} + +PRBool +nsSmallVoidArray::EnumerateBackwards(nsVoidArrayEnumFunc aFunc, void* aData) +{ + if (HasVector()) + { + nsVoidArray* vector = GetChildVector(); + return vector->EnumerateBackwards(aFunc,aData); + } + if (HasSingleChild()) + { + return (*aFunc)(GetSingleChild(), aData); + } + return PR_TRUE; +} + +void +nsSmallVoidArray::SetSingleChild(void* aChild) +{ + if (aChild) + mChildren = (void*)(PtrBits(aChild) | 0x1); + else + mChildren = nsnull; +} + +nsVoidArray* +nsSmallVoidArray::SwitchToVector() +{ + void* child = GetSingleChild(); + + mChildren = (void*)new nsAutoVoidArray(); + nsVoidArray* vector = GetChildVector(); + if (vector && child) + vector->AppendElement(child); + + return vector; +} diff --git a/src/libs/xpcom18a4/xpcom/ds/nsVoidArray.h b/src/libs/xpcom18a4/xpcom/ds/nsVoidArray.h new file mode 100644 index 00000000..28d950e7 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsVoidArray.h @@ -0,0 +1,410 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; c-file-offsets: ((substatement-open . 0)) -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ +#ifndef nsVoidArray_h___ +#define nsVoidArray_h___ + +//#define DEBUG_VOIDARRAY 1 + +#include "nscore.h" +#include "nsAString.h" + +// Comparator callback function for sorting array values. +typedef int (* PR_CALLBACK nsVoidArrayComparatorFunc) + (const void* aElement1, const void* aElement2, void* aData); + +// Enumerator callback function. Return PR_FALSE to stop +typedef PRBool (* PR_CALLBACK nsVoidArrayEnumFunc)(void* aElement, void *aData); + +/// A basic zero-based array of void*'s that manages its own memory +class NS_COM nsVoidArray { +public: + nsVoidArray(); + nsVoidArray(PRInt32 aCount); // initial count of aCount elements set to nsnull + virtual ~nsVoidArray(); + + nsVoidArray& operator=(const nsVoidArray& other); + + inline PRInt32 Count() const { + return mImpl ? mImpl->mCount : 0; + } + // returns the max number that can be held without allocating + inline PRInt32 GetArraySize() const { + return mImpl ? (PRInt32(mImpl->mBits) & kArraySizeMask) : 0; + } + + void* FastElementAt(PRInt32 aIndex) const + { + NS_ASSERTION(0 <= aIndex && aIndex < Count(), "index out of range"); + return mImpl->mArray[aIndex]; + } + + // This both asserts and bounds-checks, because (1) we don't want + // people to write bad code, but (2) we don't want to change it to + // crashing for backwards compatibility. See bug 96108. + void* ElementAt(PRInt32 aIndex) const + { + NS_ASSERTION(0 <= aIndex && aIndex < Count(), "index out of range"); + return SafeElementAt(aIndex); + } + + // bounds-checked version + void* SafeElementAt(PRInt32 aIndex) const + { + if (PRUint32(aIndex) >= PRUint32(Count())) // handles aIndex < 0 too + { + return nsnull; + } + // The bounds check ensures mImpl is non-null. + return mImpl->mArray[aIndex]; + } + + void* operator[](PRInt32 aIndex) const { return ElementAt(aIndex); } + + PRInt32 IndexOf(void* aPossibleElement) const; + + PRBool InsertElementAt(void* aElement, PRInt32 aIndex); + PRBool InsertElementsAt(const nsVoidArray &other, PRInt32 aIndex); + + PRBool ReplaceElementAt(void* aElement, PRInt32 aIndex); + + // useful for doing LRU arrays, sorting, etc + PRBool MoveElement(PRInt32 aFrom, PRInt32 aTo); + + PRBool AppendElement(void* aElement) { + return InsertElementAt(aElement, Count()); + } + + PRBool AppendElements(nsVoidArray& aElements) { + return InsertElementsAt(aElements, Count()); + } + + PRBool RemoveElement(void* aElement); + PRBool RemoveElementsAt(PRInt32 aIndex, PRInt32 aCount); + PRBool RemoveElementAt(PRInt32 aIndex) { return RemoveElementsAt(aIndex,1); } + + virtual void Clear(); + + virtual PRBool SizeTo(PRInt32 aMin); + // Subtly different - Compact() tries to be smart about whether we + // should reallocate the array; SizeTo() just does it. + virtual void Compact(); + + void Sort(nsVoidArrayComparatorFunc aFunc, void* aData); + + PRBool EnumerateForwards(nsVoidArrayEnumFunc aFunc, void* aData); + PRBool EnumerateBackwards(nsVoidArrayEnumFunc aFunc, void* aData); + +protected: + virtual PRBool GrowArrayBy(PRInt32 aGrowBy); + + struct Impl { + /** + * Packed bits. The low 31 bits are the array's size. + * The highest bit is a flag that indicates + * whether or not we "own" mArray, and must free() it when + * destroyed. + */ + PRUint32 mBits; + + /** + * The number of elements in the array + */ + PRInt32 mCount; + + /** + * Array data, padded out to the actual size of the array. + */ + void* mArray[1]; + }; + + Impl* mImpl; +#if DEBUG_VOIDARRAY + PRInt32 mMaxCount; + PRInt32 mMaxSize; + PRBool mIsAuto; +#endif + + enum { + kArrayOwnerMask = 1 << 31, + kArraySizeMask = ~kArrayOwnerMask + }; + + + // bit twiddlers + void SetArray(Impl *newImpl, PRInt32 aSize, PRInt32 aCount, PRBool owner); + inline PRBool IsArrayOwner() const { + return mImpl ? (PRBool(mImpl->mBits) & kArrayOwnerMask) : PR_FALSE; + } + +private: + /// Copy constructors are not allowed + nsVoidArray(const nsVoidArray& other); +}; + + +// A zero-based array with a bit of automatic internal storage +class NS_COM nsAutoVoidArray : public nsVoidArray { +public: + nsAutoVoidArray(); + void Clear(); + + virtual PRBool SizeTo(PRInt32 aMin); + virtual void Compact(); + +protected: + // The internal storage + enum { kAutoBufSize = 8 }; + char mAutoBuf[sizeof(Impl) + (kAutoBufSize - 1) * sizeof(void*)]; +}; + + +class nsString; + +typedef int (* PR_CALLBACK nsStringArrayComparatorFunc) + (const nsString* aElement1, const nsString* aElement2, void* aData); + +typedef PRBool (*nsStringArrayEnumFunc)(nsString& aElement, void *aData); + +class NS_COM nsStringArray: protected nsVoidArray +{ +public: + nsStringArray(void); + nsStringArray(PRInt32 aCount); // Storage for aCount elements will be pre-allocated + virtual ~nsStringArray(void); + + nsStringArray& operator=(const nsStringArray& other); + + PRInt32 Count(void) const { + return nsVoidArray::Count(); + } + + void StringAt(PRInt32 aIndex, nsAString& aString) const; + nsString* StringAt(PRInt32 aIndex) const; + nsString* operator[](PRInt32 aIndex) const { return StringAt(aIndex); } + + PRInt32 IndexOf(const nsAString& aPossibleString) const; + + PRBool InsertStringAt(const nsAString& aString, PRInt32 aIndex); + + PRBool ReplaceStringAt(const nsAString& aString, PRInt32 aIndex); + + PRBool AppendString(const nsAString& aString) { + return InsertStringAt(aString, Count()); + } + + PRBool RemoveString(const nsAString& aString); + PRBool RemoveStringAt(PRInt32 aIndex); + void Clear(void); + + void Compact(void) { + nsVoidArray::Compact(); + } + + void Sort(void); + void Sort(nsStringArrayComparatorFunc aFunc, void* aData); + + PRBool EnumerateForwards(nsStringArrayEnumFunc aFunc, void* aData); + PRBool EnumerateBackwards(nsStringArrayEnumFunc aFunc, void* aData); + +private: + /// Copy constructors are not allowed + nsStringArray(const nsStringArray& other); +}; + + +class nsCString; + +typedef int (* PR_CALLBACK nsCStringArrayComparatorFunc) + (const nsCString* aElement1, const nsCString* aElement2, void* aData); + +typedef PRBool (*nsCStringArrayEnumFunc)(nsCString& aElement, void *aData); + +class NS_COM nsCStringArray: protected nsVoidArray +{ +public: + nsCStringArray(void); + nsCStringArray(PRInt32 aCount); // Storage for aCount elements will be pre-allocated + virtual ~nsCStringArray(void); + + nsCStringArray& operator=(const nsCStringArray& other); + + // Parses a given string using the delimiter passed in. If the array + // already has some elements, items parsed from string will be appended + // to array. For example, array.ParseString("a,b,c", ","); will add strings + // "a", "b" and "c" to the array. Parsing process has the same tokenizing + // behavior as strtok(). + void ParseString(const char* string, const char* delimiter); + + PRInt32 Count(void) const { + return nsVoidArray::Count(); + } + + void CStringAt(PRInt32 aIndex, nsACString& aCString) const; + nsCString* CStringAt(PRInt32 aIndex) const; + nsCString* operator[](PRInt32 aIndex) const { return CStringAt(aIndex); } + + PRInt32 IndexOf(const nsACString& aPossibleString) const; + PRInt32 IndexOfIgnoreCase(const nsACString& aPossibleString) const; + + PRBool InsertCStringAt(const nsACString& aCString, PRInt32 aIndex); + + PRBool ReplaceCStringAt(const nsACString& aCString, PRInt32 aIndex); + + PRBool AppendCString(const nsACString& aCString) { + return InsertCStringAt(aCString, Count()); + } + + PRBool RemoveCString(const nsACString& aCString); + PRBool RemoveCStringIgnoreCase(const nsACString& aCString); + PRBool RemoveCStringAt(PRInt32 aIndex); + void Clear(void); + + void Compact(void) { + nsVoidArray::Compact(); + } + + void Sort(void); + void SortIgnoreCase(void); + void Sort(nsCStringArrayComparatorFunc aFunc, void* aData); + + PRBool EnumerateForwards(nsCStringArrayEnumFunc aFunc, void* aData); + PRBool EnumerateBackwards(nsCStringArrayEnumFunc aFunc, void* aData); + +private: + /// Copy constructors are not allowed + nsCStringArray(const nsCStringArray& other); +}; + + +//=================================================================== +// nsSmallVoidArray is not a general-purpose replacement for +// ns(Auto)VoidArray because there is (some) extra CPU overhead for arrays +// larger than 1 element, though not a lot. It is appropriate for +// space-sensitive uses where sizes of 0 or 1 are moderately common or +// more, and where we're NOT storing arbitrary integers or arbitrary +// pointers. + +// NOTE: nsSmallVoidArray can ONLY be used for holding items that always +// have the low bit as a 0 - i.e. element & 1 == 0. This happens to be +// true for allocated and object pointers for all the architectures we run +// on, but conceivably there might be some architectures/compilers for +// which it is NOT true. We know this works for all existing architectures +// because if it didn't then nsCheapVoidArray would have failed. Also note +// that we will ASSERT if this assumption is violated in DEBUG builds. + +// XXX we're really re-implementing the whole nsVoidArray interface here - +// some form of abstract class would be useful + +// I disagree on the abstraction here. If the point of this class is to be +// as small as possible, and no one will ever derive from it, as I found +// today, there should not be any virtualness to it to avoid the vtable +// ptr overhead. + +class NS_COM nsSmallVoidArray +{ +public: + nsSmallVoidArray(); + ~nsSmallVoidArray(); + + nsSmallVoidArray& operator=(nsSmallVoidArray& other); + void* operator[](PRInt32 aIndex) const { return ElementAt(aIndex); } + + PRInt32 GetArraySize() const; + + PRInt32 Count() const; + void* ElementAt(PRInt32 aIndex) const; + void* SafeElementAt(PRInt32 aIndex) const { + // let compiler inline; it may be able to remove these checks + if (aIndex < 0 || aIndex >= Count()) + return nsnull; + return ElementAt(aIndex); + } + PRInt32 IndexOf(void* aPossibleElement) const; + PRBool InsertElementAt(void* aElement, PRInt32 aIndex); + PRBool InsertElementsAt(const nsVoidArray &other, PRInt32 aIndex); + PRBool ReplaceElementAt(void* aElement, PRInt32 aIndex); + PRBool MoveElement(PRInt32 aFrom, PRInt32 aTo); + PRBool AppendElement(void* aElement); + PRBool AppendElements(nsVoidArray& aElements) { + return InsertElementsAt(aElements, Count()); + } + PRBool RemoveElement(void* aElement); + PRBool RemoveElementsAt(PRInt32 aIndex, PRInt32 aCount); + PRBool RemoveElementAt(PRInt32 aIndex); + + void Clear(); + PRBool SizeTo(PRInt32 aMin); + void Compact(); + void Sort(nsVoidArrayComparatorFunc aFunc, void* aData); + + PRBool EnumerateForwards(nsVoidArrayEnumFunc aFunc, void* aData); + PRBool EnumerateBackwards(nsVoidArrayEnumFunc aFunc, void* aData); + +private: +#ifdef RT_OS_OS2 /* shut up a million warnings */ + typedef PRUint32 PtrBits; +#else + typedef PRUint64 PtrBits; +#endif + + PRBool HasSingleChild() const + { + return (mChildren && (PtrBits(mChildren) & 0x1)); + } + PRBool HasVector() const + { + return (mChildren && !(PtrBits(mChildren) & 0x1)); + } + void* GetSingleChild() const + { + return (mChildren ? ((void*)(PtrBits(mChildren) & ~0x1)) : nsnull); + } + void SetSingleChild(void *aChild); + nsVoidArray* GetChildVector() const + { + return (nsVoidArray*)mChildren; + } + nsVoidArray* SwitchToVector(); + + // A tagged pointer that's either a pointer to a single child + // or a pointer to a vector of multiple children. This is a space + // optimization since a large number of containers have only a + // single child. + void *mChildren; +}; + +#endif /* nsVoidArray_h___ */ diff --git a/src/libs/xpcom18a4/xpcom/ds/pldhash.c b/src/libs/xpcom18a4/xpcom/ds/pldhash.c new file mode 100644 index 00000000..74f8cd0e --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/pldhash.c @@ -0,0 +1,826 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 JavaScript code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999-2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Brendan Eich (Original Author) + * Chris Waterson + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* + * Double hashing implementation. + * GENERATED BY js/src/plify_jsdhash.sed -- DO NOT EDIT!!! + */ +#include +#include +#include +#include "prbit.h" +#include "pldhash.h" +#include "prlog.h" /* for PR_ASSERT */ + +#ifdef PL_DHASHMETER +# if defined MOZILLA_CLIENT && defined DEBUG_XXXbrendan +# include "nsTraceMalloc.h" +# endif +# define METER(x) x +#else +# define METER(x) /* nothing */ +#endif +#ifdef VBOX_USE_IPRT_IN_XPCOM +# include +#endif + +PR_IMPLEMENT(void *) +PL_DHashAllocTable(PLDHashTable *table, PRUint32 nbytes) +{ +#ifdef VBOX_USE_IPRT_IN_XPCOM + return RTMemAlloc(nbytes); +#else + return malloc(nbytes); +#endif +} + +PR_IMPLEMENT(void) +PL_DHashFreeTable(PLDHashTable *table, void *ptr) +{ +#ifdef VBOX_USE_IPRT_IN_XPCOM + RTMemFree(ptr); +#else + free(ptr); +#endif +} + +PR_IMPLEMENT(PLDHashNumber) +PL_DHashStringKey(PLDHashTable *table, const void *key) +{ + PLDHashNumber h; + const unsigned char *s; + + h = 0; + for (s = key; *s != '\0'; s++) + h = (h >> (PL_DHASH_BITS - 4)) ^ (h << 4) ^ *s; + return h; +} + +PR_IMPLEMENT(const void *) +PL_DHashGetKeyStub(PLDHashTable *table, PLDHashEntryHdr *entry) +{ + PLDHashEntryStub *stub = (PLDHashEntryStub *)entry; + + return stub->key; +} + +PR_IMPLEMENT(PLDHashNumber) +PL_DHashVoidPtrKeyStub(PLDHashTable *table, const void *key) +{ + return (PLDHashNumber)(uintptr_t)key >> 2; +} + +PR_IMPLEMENT(PRBool) +PL_DHashMatchEntryStub(PLDHashTable *table, + const PLDHashEntryHdr *entry, + const void *key) +{ + const PLDHashEntryStub *stub = (const PLDHashEntryStub *)entry; + + return stub->key == key; +} + +PR_IMPLEMENT(PRBool) +PL_DHashMatchStringKey(PLDHashTable *table, + const PLDHashEntryHdr *entry, + const void *key) +{ + const PLDHashEntryStub *stub = (const PLDHashEntryStub *)entry; + + /* XXX tolerate null keys on account of sloppy Mozilla callers. */ + return stub->key == key || + (stub->key && key && strcmp(stub->key, key) == 0); +} + +PR_IMPLEMENT(void) +PL_DHashMoveEntryStub(PLDHashTable *table, + const PLDHashEntryHdr *from, + PLDHashEntryHdr *to) +{ + memcpy(to, from, table->entrySize); +} + +PR_IMPLEMENT(void) +PL_DHashClearEntryStub(PLDHashTable *table, PLDHashEntryHdr *entry) +{ + memset(entry, 0, table->entrySize); +} + +PR_IMPLEMENT(void) +PL_DHashFreeStringKey(PLDHashTable *table, PLDHashEntryHdr *entry) +{ + const PLDHashEntryStub *stub = (const PLDHashEntryStub *)entry; + +#ifdef VBOX_USE_IPRT_IN_XPCOM + RTMemFree((void *) stub->key); +#else + free((void *) stub->key); +#endif + memset(entry, 0, table->entrySize); +} + +PR_IMPLEMENT(void) +PL_DHashFinalizeStub(PLDHashTable *table) +{ +} + +static const PLDHashTableOps stub_ops = { + PL_DHashAllocTable, + PL_DHashFreeTable, + PL_DHashGetKeyStub, + PL_DHashVoidPtrKeyStub, + PL_DHashMatchEntryStub, + PL_DHashMoveEntryStub, + PL_DHashClearEntryStub, + PL_DHashFinalizeStub, + NULL +}; + +PR_IMPLEMENT(const PLDHashTableOps *) +PL_DHashGetStubOps(void) +{ + return &stub_ops; +} + +PR_IMPLEMENT(PLDHashTable *) +PL_NewDHashTable(const PLDHashTableOps *ops, void *data, PRUint32 entrySize, + PRUint32 capacity) +{ + PLDHashTable *table; + +#ifdef VBOX_USE_IPRT_IN_XPCOM + table = (PLDHashTable *) RTMemAlloc(sizeof *table); +#else + table = (PLDHashTable *) malloc(sizeof *table); +#endif + if (!table) + return NULL; + if (!PL_DHashTableInit(table, ops, data, entrySize, capacity)) { +#ifdef VBOX_USE_IPRT_IN_XPCOM + RTMemFree(table); +#else + free(table); +#endif + return NULL; + } + return table; +} + +PR_IMPLEMENT(void) +PL_DHashTableDestroy(PLDHashTable *table) +{ + PL_DHashTableFinish(table); +#ifdef VBOX_USE_IPRT_IN_XPCOM + RTMemFree(table); +#else + free(table); +#endif +} + +PR_IMPLEMENT(PRBool) +PL_DHashTableInit(PLDHashTable *table, const PLDHashTableOps *ops, void *data, + PRUint32 entrySize, PRUint32 capacity) +{ + int log2; + PRUint32 nbytes; + +#ifdef DEBUG + if (entrySize > 10 * sizeof(void *)) { + fprintf(stderr, + "pldhash: for the table at address %p, the given entrySize" + " of %lu %s favors chaining over double hashing.\n", + (void *)table, + (unsigned long) entrySize, + (entrySize > 16 * sizeof(void*)) ? "definitely" : "probably"); + } +#endif + + table->ops = ops; + table->data = data; + if (capacity < PL_DHASH_MIN_SIZE) + capacity = PL_DHASH_MIN_SIZE; + log2 = PR_CeilingLog2(capacity); + capacity = PR_BIT(log2); + if (capacity >= PL_DHASH_SIZE_LIMIT) + return PR_FALSE; + table->hashShift = PL_DHASH_BITS - log2; + table->maxAlphaFrac = 0xC0; /* .75 */ + table->minAlphaFrac = 0x40; /* .25 */ + table->entrySize = entrySize; + table->entryCount = table->removedCount = 0; + table->generation = 0; + nbytes = capacity * entrySize; + + table->entryStore = ops->allocTable(table, nbytes); + if (!table->entryStore) + return PR_FALSE; + memset(table->entryStore, 0, nbytes); + METER(memset(&table->stats, 0, sizeof table->stats)); + return PR_TRUE; +} + +/* + * Compute max and min load numbers (entry counts) from table params. + */ +#define MAX_LOAD(table, size) (((table)->maxAlphaFrac * (size)) >> 8) +#define MIN_LOAD(table, size) (((table)->minAlphaFrac * (size)) >> 8) + +PR_IMPLEMENT(void) +PL_DHashTableSetAlphaBounds(PLDHashTable *table, + float maxAlpha, + float minAlpha) +{ + PRUint32 size; + + /* + * Reject obviously insane bounds, rather than trying to guess what the + * buggy caller intended. + */ + PR_ASSERT(0.5 <= maxAlpha && maxAlpha < 1 && 0 <= minAlpha); + if (maxAlpha < 0.5 || 1 <= maxAlpha || minAlpha < 0) + return; + + /* + * Ensure that at least one entry will always be free. If maxAlpha at + * minimum size leaves no entries free, reduce maxAlpha based on minimum + * size and the precision limit of maxAlphaFrac's fixed point format. + */ + PR_ASSERT(PL_DHASH_MIN_SIZE - (maxAlpha * PL_DHASH_MIN_SIZE) >= 1); + if (PL_DHASH_MIN_SIZE - (maxAlpha * PL_DHASH_MIN_SIZE) < 1) { + maxAlpha = (float) + (PL_DHASH_MIN_SIZE - PR_MAX(PL_DHASH_MIN_SIZE / 256, 1)) + / PL_DHASH_MIN_SIZE; + } + + /* + * Ensure that minAlpha is strictly less than half maxAlpha. Take care + * not to truncate an entry's worth of alpha when storing in minAlphaFrac + * (8-bit fixed point format). + */ + PR_ASSERT(minAlpha < maxAlpha / 2); + if (minAlpha >= maxAlpha / 2) { + size = PL_DHASH_TABLE_SIZE(table); + minAlpha = (size * maxAlpha - PR_MAX(size / 256, 1)) / (2 * size); + } + + table->maxAlphaFrac = (uint8)(maxAlpha * 256); + table->minAlphaFrac = (uint8)(minAlpha * 256); +} + +/* + * Double hashing needs the second hash code to be relatively prime to table + * size, so we simply make hash2 odd. + */ +#define HASH1(hash0, shift) ((hash0) >> (shift)) +#define HASH2(hash0,log2,shift) ((((hash0) << (log2)) >> (shift)) | 1) + +/* + * Reserve keyHash 0 for free entries and 1 for removed-entry sentinels. Note + * that a removed-entry sentinel need be stored only if the removed entry had + * a colliding entry added after it. Therefore we can use 1 as the collision + * flag in addition to the removed-entry sentinel value. Multiplicative hash + * uses the high order bits of keyHash, so this least-significant reservation + * should not hurt the hash function's effectiveness much. + * + * If you change any of these magic numbers, also update PL_DHASH_ENTRY_IS_LIVE + * in pldhash.h. It used to be private to pldhash.c, but then became public to + * assist iterator writers who inspect table->entryStore directly. + */ +#define COLLISION_FLAG ((PLDHashNumber) 1) +#define MARK_ENTRY_FREE(entry) ((entry)->keyHash = 0) +#define MARK_ENTRY_REMOVED(entry) ((entry)->keyHash = 1) +#define ENTRY_IS_REMOVED(entry) ((entry)->keyHash == 1) +#define ENTRY_IS_LIVE(entry) PL_DHASH_ENTRY_IS_LIVE(entry) +#define ENSURE_LIVE_KEYHASH(hash0) if (hash0 < 2) hash0 -= 2; else (void)0 + +/* Match an entry's keyHash against an unstored one computed from a key. */ +#define MATCH_ENTRY_KEYHASH(entry,hash0) \ + (((entry)->keyHash & ~COLLISION_FLAG) == (hash0)) + +/* Compute the address of the indexed entry in table. */ +#define ADDRESS_ENTRY(table, index) \ + ((PLDHashEntryHdr *)((table)->entryStore + (index) * (table)->entrySize)) + +PR_IMPLEMENT(void) +PL_DHashTableFinish(PLDHashTable *table) +{ + char *entryAddr, *entryLimit; + PRUint32 entrySize; + PLDHashEntryHdr *entry; + +#ifdef DEBUG_XXXbrendan + static FILE *dumpfp = NULL; + if (!dumpfp) dumpfp = fopen("/tmp/pldhash.bigdump", "w"); + if (dumpfp) { +#ifdef MOZILLA_CLIENT + NS_TraceStack(1, dumpfp); +#endif + PL_DHashTableDumpMeter(table, NULL, dumpfp); + fputc('\n', dumpfp); + } +#endif + + /* Call finalize before clearing entries, so it can enumerate them. */ + table->ops->finalize(table); + + /* Clear any remaining live entries. */ + entryAddr = table->entryStore; + entrySize = table->entrySize; + entryLimit = entryAddr + PL_DHASH_TABLE_SIZE(table) * entrySize; + while (entryAddr < entryLimit) { + entry = (PLDHashEntryHdr *)entryAddr; + if (ENTRY_IS_LIVE(entry)) { + METER(table->stats.removeEnums++); + table->ops->clearEntry(table, entry); + } + entryAddr += entrySize; + } + + /* Free entry storage last. */ + table->ops->freeTable(table, table->entryStore); +} + +static PLDHashEntryHdr * PL_DHASH_FASTCALL +SearchTable(PLDHashTable *table, const void *key, PLDHashNumber keyHash, + PLDHashOperator op) +{ + PLDHashNumber hash1, hash2; + int hashShift, sizeLog2; + PLDHashEntryHdr *entry, *firstRemoved; + PLDHashMatchEntry matchEntry; + PRUint32 sizeMask; + + METER(table->stats.searches++); + PR_ASSERT(!(keyHash & COLLISION_FLAG)); + + /* Compute the primary hash address. */ + hashShift = table->hashShift; + hash1 = HASH1(keyHash, hashShift); + entry = ADDRESS_ENTRY(table, hash1); + + /* Miss: return space for a new entry. */ + if (PL_DHASH_ENTRY_IS_FREE(entry)) { + METER(table->stats.misses++); + return entry; + } + + /* Hit: return entry. */ + matchEntry = table->ops->matchEntry; + if (MATCH_ENTRY_KEYHASH(entry, keyHash) && matchEntry(table, entry, key)) { + METER(table->stats.hits++); + return entry; + } + + /* Collision: double hash. */ + sizeLog2 = PL_DHASH_BITS - table->hashShift; + hash2 = HASH2(keyHash, sizeLog2, hashShift); + sizeMask = PR_BITMASK(sizeLog2); + + /* Save the first removed entry pointer so PL_DHASH_ADD can recycle it. */ + if (ENTRY_IS_REMOVED(entry)) { + firstRemoved = entry; + } else { + firstRemoved = NULL; + if (op == PL_DHASH_ADD) + entry->keyHash |= COLLISION_FLAG; + } + + for (;;) { + METER(table->stats.steps++); + hash1 -= hash2; + hash1 &= sizeMask; + + entry = ADDRESS_ENTRY(table, hash1); + if (PL_DHASH_ENTRY_IS_FREE(entry)) { + METER(table->stats.misses++); + return (firstRemoved && op == PL_DHASH_ADD) ? firstRemoved : entry; + } + + if (MATCH_ENTRY_KEYHASH(entry, keyHash) && + matchEntry(table, entry, key)) { + METER(table->stats.hits++); + return entry; + } + + if (ENTRY_IS_REMOVED(entry)) { + if (!firstRemoved) + firstRemoved = entry; + } else { + if (op == PL_DHASH_ADD) + entry->keyHash |= COLLISION_FLAG; + } + } + + /* NOTREACHED */ + return NULL; +} + +static PRBool +ChangeTable(PLDHashTable *table, int deltaLog2) +{ + int oldLog2, newLog2; + PRUint32 oldCapacity, newCapacity; + char *newEntryStore, *oldEntryStore, *oldEntryAddr; + PRUint32 entrySize, i, nbytes; + PLDHashEntryHdr *oldEntry, *newEntry; + PLDHashGetKey getKey; + PLDHashMoveEntry moveEntry; + +#ifdef VBOX /* HACK ALERT! generation == PR_UINT32_MAX during enumeration. */ + PR_ASSERT(table->generation != PR_UINT32_MAX); + if (table->generation == PR_UINT32_MAX) + return PR_FALSE; +#endif + + /* Look, but don't touch, until we succeed in getting new entry store. */ + oldLog2 = PL_DHASH_BITS - table->hashShift; + newLog2 = oldLog2 + deltaLog2; + oldCapacity = PR_BIT(oldLog2); + newCapacity = PR_BIT(newLog2); + if (newCapacity >= PL_DHASH_SIZE_LIMIT) + return PR_FALSE; + entrySize = table->entrySize; + nbytes = newCapacity * entrySize; + + newEntryStore = table->ops->allocTable(table, nbytes); + if (!newEntryStore) + return PR_FALSE; + + /* We can't fail from here on, so update table parameters. */ + table->hashShift = PL_DHASH_BITS - newLog2; + table->removedCount = 0; + table->generation++; +#ifdef VBOX /* HACK ALERT! generation == PR_UINT32_MAX during enumeration. */ + if (table->generation == PR_UINT32_MAX) + table->generation++; +#endif + + /* Assign the new entry store to table. */ + memset(newEntryStore, 0, nbytes); + oldEntryAddr = oldEntryStore = table->entryStore; + table->entryStore = newEntryStore; + getKey = table->ops->getKey; + moveEntry = table->ops->moveEntry; + + /* Copy only live entries, leaving removed ones behind. */ + for (i = 0; i < oldCapacity; i++) { + oldEntry = (PLDHashEntryHdr *)oldEntryAddr; + if (ENTRY_IS_LIVE(oldEntry)) { + oldEntry->keyHash &= ~COLLISION_FLAG; + newEntry = SearchTable(table, getKey(table, oldEntry), + oldEntry->keyHash, PL_DHASH_ADD); + PR_ASSERT(PL_DHASH_ENTRY_IS_FREE(newEntry)); + moveEntry(table, oldEntry, newEntry); + newEntry->keyHash = oldEntry->keyHash; + } + oldEntryAddr += entrySize; + } + + table->ops->freeTable(table, oldEntryStore); + return PR_TRUE; +} + +PR_IMPLEMENT(PLDHashEntryHdr *) PL_DHASH_FASTCALL +PL_DHashTableOperate(PLDHashTable *table, const void *key, PLDHashOperator op) +{ + PLDHashNumber keyHash; + PLDHashEntryHdr *entry; + PRUint32 size; + int deltaLog2; + + keyHash = table->ops->hashKey(table, key); + keyHash *= PL_DHASH_GOLDEN_RATIO; + + /* Avoid 0 and 1 hash codes, they indicate free and removed entries. */ + ENSURE_LIVE_KEYHASH(keyHash); + keyHash &= ~COLLISION_FLAG; + + switch (op) { + case PL_DHASH_LOOKUP: + METER(table->stats.lookups++); + entry = SearchTable(table, key, keyHash, op); + break; + + case PL_DHASH_ADD: + /* + * If alpha is >= .75, grow or compress the table. If key is already + * in the table, we may grow once more than necessary, but only if we + * are on the edge of being overloaded. + */ + size = PL_DHASH_TABLE_SIZE(table); + if (table->entryCount + table->removedCount >= MAX_LOAD(table, size)) { + /* Compress if a quarter or more of all entries are removed. */ + if (table->removedCount >= size >> 2) { + METER(table->stats.compresses++); + deltaLog2 = 0; + } else { + METER(table->stats.grows++); + deltaLog2 = 1; + } + + /* + * Grow or compress table, returning null if ChangeTable fails and + * falling through might claim the last free entry. + */ + if (!ChangeTable(table, deltaLog2) && + table->entryCount + table->removedCount == size - 1) { + METER(table->stats.addFailures++); + return NULL; + } + } + + /* + * Look for entry after possibly growing, so we don't have to add it, + * then skip it while growing the table and re-add it after. + */ + entry = SearchTable(table, key, keyHash, op); + if (!ENTRY_IS_LIVE(entry)) { + /* Initialize the entry, indicating that it's no longer free. */ + METER(table->stats.addMisses++); + if (ENTRY_IS_REMOVED(entry)) { + METER(table->stats.addOverRemoved++); + table->removedCount--; + keyHash |= COLLISION_FLAG; + } + if (table->ops->initEntry && + !table->ops->initEntry(table, entry, key)) { + /* We haven't claimed entry yet; fail with null return. */ + memset(entry + 1, 0, table->entrySize - sizeof *entry); + return NULL; + } + entry->keyHash = keyHash; + table->entryCount++; + } + METER(else table->stats.addHits++); + break; + + case PL_DHASH_REMOVE: + entry = SearchTable(table, key, keyHash, op); + if (ENTRY_IS_LIVE(entry)) { + /* Clear this entry and mark it as "removed". */ + METER(table->stats.removeHits++); + PL_DHashTableRawRemove(table, entry); + + /* Shrink if alpha is <= .25 and table isn't too small already. */ + size = PL_DHASH_TABLE_SIZE(table); + if (size > PL_DHASH_MIN_SIZE && +#ifdef VBOX /* HACK ALERT! generation == PR_UINT32_MAX during enumeration. */ + /** @todo This is where IPC screws up, avoid the assertion in ChangeTable until it's fixed. */ + table->generation != PR_UINT32_MAX && +#endif + table->entryCount <= MIN_LOAD(table, size)) { + METER(table->stats.shrinks++); + (void) ChangeTable(table, -1); + } + } + METER(else table->stats.removeMisses++); + entry = NULL; + break; + + default: + PR_ASSERT(0); + entry = NULL; + } + + return entry; +} + +PR_IMPLEMENT(void) +PL_DHashTableRawRemove(PLDHashTable *table, PLDHashEntryHdr *entry) +{ + PLDHashNumber keyHash; /* load first in case clearEntry goofs it */ + + PR_ASSERT(PL_DHASH_ENTRY_IS_LIVE(entry)); + keyHash = entry->keyHash; + table->ops->clearEntry(table, entry); + if (keyHash & COLLISION_FLAG) { + MARK_ENTRY_REMOVED(entry); + table->removedCount++; + } else { + METER(table->stats.removeFrees++); + MARK_ENTRY_FREE(entry); + } + table->entryCount--; +} + +PR_IMPLEMENT(PRUint32) +PL_DHashTableEnumerate(PLDHashTable *table, PLDHashEnumerator etor, void *arg) +{ + char *entryAddr, *entryLimit; + PRUint32 i, capacity, entrySize; + PRBool didRemove; + PLDHashEntryHdr *entry; + PLDHashOperator op; +#ifdef VBOX /* HACK ALERT! generation == PR_UINT32_MAX during enumeration. */ + PRUint32 generation; + + /* + * The hack! Set generation to PR_UINT32_MAX during the enumeration so + * we can prevent ChangeTable from being called. + * + * This happens during ipcDConnectService::OnClientStateChange() + * / ipcDConnectService::DeleteInstance() now when running + * java clienttest list hostinfo and vboxwebsrv crashes. It's quite + * likely that the IPC code isn't following the rules here, but it + * looks more difficult to fix that just hacking this hash code. + */ + generation = table->generation; + table->generation = PR_UINT32_MAX; +#endif /* VBOX */ + entryAddr = table->entryStore; + entrySize = table->entrySize; + capacity = PL_DHASH_TABLE_SIZE(table); + entryLimit = entryAddr + capacity * entrySize; + i = 0; + didRemove = PR_FALSE; + while (entryAddr < entryLimit) { + entry = (PLDHashEntryHdr *)entryAddr; + if (ENTRY_IS_LIVE(entry)) { + op = etor(table, entry, i++, arg); +#ifdef VBOX /* HACK ALERT! generation == PR_UINT32_MAX during enumeration. */ + PR_ASSERT(table->generation == PR_UINT32_MAX); +#endif + if (op & PL_DHASH_REMOVE) { + METER(table->stats.removeEnums++); + PL_DHashTableRawRemove(table, entry); + didRemove = PR_TRUE; + } + if (op & PL_DHASH_STOP) + break; + } + entryAddr += entrySize; + } +#ifdef VBOX /* HACK ALERT! generation == PR_UINT32_MAX during enumeration. */ + table->generation = generation; +#endif + + /* + * Shrink or compress if a quarter or more of all entries are removed, or + * if the table is underloaded according to the configured minimum alpha, + * and is not minimal-size already. Do this only if we removed above, so + * non-removing enumerations can count on stable table->entryStore until + * the next non-lookup-Operate or removing-Enumerate. + */ + if (didRemove && + (table->removedCount >= capacity >> 2 || + (capacity > PL_DHASH_MIN_SIZE && + table->entryCount <= MIN_LOAD(table, capacity)))) { + METER(table->stats.enumShrinks++); + capacity = table->entryCount; + capacity += capacity >> 1; + if (capacity < PL_DHASH_MIN_SIZE) + capacity = PL_DHASH_MIN_SIZE; + (void) ChangeTable(table, + PR_CeilingLog2(capacity) + - (PL_DHASH_BITS - table->hashShift)); + } + return i; +} + +#ifdef PL_DHASHMETER +#include + +PR_IMPLEMENT(void) +PL_DHashTableDumpMeter(PLDHashTable *table, PLDHashEnumerator dump, FILE *fp) +{ + char *entryAddr; + PRUint32 entrySize, entryCount; + int hashShift, sizeLog2; + PRUint32 i, tableSize, sizeMask, chainLen, maxChainLen, chainCount; + PLDHashNumber hash1, hash2, saveHash1, maxChainHash1, maxChainHash2; + double sqsum, mean, variance, sigma; + PLDHashEntryHdr *entry, *probe; + + entryAddr = table->entryStore; + entrySize = table->entrySize; + hashShift = table->hashShift; + sizeLog2 = PL_DHASH_BITS - hashShift; + tableSize = PL_DHASH_TABLE_SIZE(table); + sizeMask = PR_BITMASK(sizeLog2); + chainCount = maxChainLen = 0; + hash2 = 0; + sqsum = 0; + + for (i = 0; i < tableSize; i++) { + entry = (PLDHashEntryHdr *)entryAddr; + entryAddr += entrySize; + if (!ENTRY_IS_LIVE(entry)) + continue; + hash1 = HASH1(entry->keyHash & ~COLLISION_FLAG, hashShift); + saveHash1 = hash1; + probe = ADDRESS_ENTRY(table, hash1); + chainLen = 1; + if (probe == entry) { + /* Start of a (possibly unit-length) chain. */ + chainCount++; + } else { + hash2 = HASH2(entry->keyHash & ~COLLISION_FLAG, sizeLog2, + hashShift); + do { + chainLen++; + hash1 -= hash2; + hash1 &= sizeMask; + probe = ADDRESS_ENTRY(table, hash1); + } while (probe != entry); + } + sqsum += chainLen * chainLen; + if (chainLen > maxChainLen) { + maxChainLen = chainLen; + maxChainHash1 = saveHash1; + maxChainHash2 = hash2; + } + } + + entryCount = table->entryCount; + if (entryCount && chainCount) { + mean = (double)entryCount / chainCount; + variance = chainCount * sqsum - entryCount * entryCount; + if (variance < 0 || chainCount == 1) + variance = 0; + else + variance /= chainCount * (chainCount - 1); + sigma = sqrt(variance); + } else { + mean = sigma = 0; + } + + fprintf(fp, "Double hashing statistics:\n"); + fprintf(fp, " table size (in entries): %u\n", tableSize); + fprintf(fp, " number of entries: %u\n", table->entryCount); + fprintf(fp, " number of removed entries: %u\n", table->removedCount); + fprintf(fp, " number of searches: %u\n", table->stats.searches); + fprintf(fp, " number of hits: %u\n", table->stats.hits); + fprintf(fp, " number of misses: %u\n", table->stats.misses); + fprintf(fp, " mean steps per search: %g\n", table->stats.searches ? + (double)table->stats.steps + / table->stats.searches : + 0.); + fprintf(fp, " mean hash chain length: %g\n", mean); + fprintf(fp, " standard deviation: %g\n", sigma); + fprintf(fp, " maximum hash chain length: %u\n", maxChainLen); + fprintf(fp, " number of lookups: %u\n", table->stats.lookups); + fprintf(fp, " adds that made a new entry: %u\n", table->stats.addMisses); + fprintf(fp, "adds that recycled removeds: %u\n", table->stats.addOverRemoved); + fprintf(fp, " adds that found an entry: %u\n", table->stats.addHits); + fprintf(fp, " add failures: %u\n", table->stats.addFailures); + fprintf(fp, " useful removes: %u\n", table->stats.removeHits); + fprintf(fp, " useless removes: %u\n", table->stats.removeMisses); + fprintf(fp, "removes that freed an entry: %u\n", table->stats.removeFrees); + fprintf(fp, " removes while enumerating: %u\n", table->stats.removeEnums); + fprintf(fp, " number of grows: %u\n", table->stats.grows); + fprintf(fp, " number of shrinks: %u\n", table->stats.shrinks); + fprintf(fp, " number of compresses: %u\n", table->stats.compresses); + fprintf(fp, "number of enumerate shrinks: %u\n", table->stats.enumShrinks); + + if (dump && maxChainLen && hash2) { + fputs("Maximum hash chain:\n", fp); + hash1 = maxChainHash1; + hash2 = maxChainHash2; + entry = ADDRESS_ENTRY(table, hash1); + i = 0; + do { + if (dump(table, entry, i++, fp) != PL_DHASH_NEXT) + break; + hash1 -= hash2; + hash1 &= sizeMask; + entry = ADDRESS_ENTRY(table, hash1); + } while (PL_DHASH_ENTRY_IS_BUSY(entry)); + } +} +#endif /* PL_DHASHMETER */ diff --git a/src/libs/xpcom18a4/xpcom/ds/pldhash.h b/src/libs/xpcom18a4/xpcom/ds/pldhash.h new file mode 100644 index 00000000..8c4347c0 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/pldhash.h @@ -0,0 +1,603 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 JavaScript code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999-2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Brendan Eich (Original Author) + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +#ifndef pldhash_h___ +#define pldhash_h___ +/* + * Double hashing, a la Knuth 6. + * GENERATED BY js/src/plify_jsdhash.sed -- DO NOT EDIT!!! + */ +#include "prtypes.h" + +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +#define PL_DHashTableInit VBoxNsplPL_DHashTableInit +#define PL_DHashTableFinish VBoxNsplPL_DHashTableFinish +#define PL_DHashTableOperate VBoxNsplPL_DHashTableOperate +#define PL_DHashTableEnumerate VBoxNsplPL_DHashTableEnumerate +#define PL_DHashAllocTable VBoxNsplPL_DHashAllocTable +#define PL_DHashFreeTable VBoxNsplPL_DHashFreeTable +#define PL_DHashMoveEntryStub VBoxNsplPL_DHashMoveEntryStub +#define PL_DHashFinalizeStub VBoxNsplPL_DHashFinalizeStub +#define PL_DHashClearEntryStub VBoxNsplPL_DHashClearEntryStub +#define PL_DHashFreeStringKey VBoxNsplPL_DHashFreeStringKey +#define PL_DHashGetKeyStub VBoxNsplPL_DHashGetKeyStub +#define PL_DHashGetStubOps VBoxNsplPL_DHashGetStubOps +#define PL_DHashMatchEntryStub VBoxNsplPL_DHashMatchEntryStub +#define PL_DHashMatchStringKey VBoxNsplPL_DHashMatchStringKey +#define PL_DHashStringKey VBoxNsplPL_DHashStringKey +#define PL_DHashTableDestroy VBoxNsplPL_DHashTableDestroy +#define PL_DHashTableRawRemove VBoxNsplPL_DHashTableRawRemove +#define PL_DHashTableSetAlphaBounds VBoxNsplPL_DHashTableSetAlphaBounds +#define PL_DHashVoidPtrKeyStub VBoxNsplPL_DHashVoidPtrKeyStub +#define PL_NewDHashTable VBoxNsplPL_NewDHashTable +#endif /* VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + +PR_BEGIN_EXTERN_C + +#ifdef DEBUG_XXXbrendan +#define PL_DHASHMETER 1 +#endif + +#if defined(__GNUC__) && defined(__i386__) && (__GNUC__ >= 3) && !defined(XP_OS2) +#define PL_DHASH_FASTCALL __attribute__ ((regparm (3),stdcall)) +#else +#define PL_DHASH_FASTCALL +#endif + +/* Table size limit, do not equal or exceed (see min&maxAlphaFrac, below). */ +#undef PL_DHASH_SIZE_LIMIT +#define PL_DHASH_SIZE_LIMIT PR_BIT(24) + +/* Minimum table size, or gross entry count (net is at most .75 loaded). */ +#ifndef PL_DHASH_MIN_SIZE +#define PL_DHASH_MIN_SIZE 16 +#elif (PL_DHASH_MIN_SIZE & (PL_DHASH_MIN_SIZE - 1)) != 0 +#error "PL_DHASH_MIN_SIZE must be a power of two!" +#endif + +/* + * Multiplicative hash uses an unsigned 32 bit integer and the golden ratio, + * expressed as a fixed-point 32-bit fraction. + */ +#define PL_DHASH_BITS 32 +#define PL_DHASH_GOLDEN_RATIO 0x9E3779B9U + +/* Primitive and forward-struct typedefs. */ +typedef PRUint32 PLDHashNumber; +typedef struct PLDHashEntryHdr PLDHashEntryHdr; +typedef struct PLDHashEntryStub PLDHashEntryStub; +typedef struct PLDHashTable PLDHashTable; +typedef struct PLDHashTableOps PLDHashTableOps; + +/* + * Table entry header structure. + * + * In order to allow in-line allocation of key and value, we do not declare + * either here. Instead, the API uses const void *key as a formal parameter, + * and asks each entry for its key when necessary via a getKey callback, used + * when growing or shrinking the table. Other callback types are defined + * below and grouped into the PLDHashTableOps structure, for single static + * initialization per hash table sub-type. + * + * Each hash table sub-type should nest the PLDHashEntryHdr structure at the + * front of its particular entry type. The keyHash member contains the result + * of multiplying the hash code returned from the hashKey callback (see below) + * by PL_DHASH_GOLDEN_RATIO, then constraining the result to avoid the magic 0 + * and 1 values. The stored keyHash value is table size invariant, and it is + * maintained automatically by PL_DHashTableOperate -- users should never set + * it, and its only uses should be via the entry macros below. + * + * The PL_DHASH_ENTRY_IS_LIVE macro tests whether entry is neither free nor + * removed. An entry may be either busy or free; if busy, it may be live or + * removed. Consumers of this API should not access members of entries that + * are not live. + * + * However, use PL_DHASH_ENTRY_IS_BUSY for faster liveness testing of entries + * returned by PL_DHashTableOperate, as PL_DHashTableOperate never returns a + * non-live, busy (i.e., removed) entry pointer to its caller. See below for + * more details on PL_DHashTableOperate's calling rules. + */ +struct PLDHashEntryHdr { + PLDHashNumber keyHash; /* every entry must begin like this */ +}; + +#define PL_DHASH_ENTRY_IS_FREE(entry) ((entry)->keyHash == 0) +#define PL_DHASH_ENTRY_IS_BUSY(entry) (!PL_DHASH_ENTRY_IS_FREE(entry)) +#define PL_DHASH_ENTRY_IS_LIVE(entry) ((entry)->keyHash >= 2) + +/* + * A PLDHashTable is currently 8 words (without the PL_DHASHMETER overhead) + * on most architectures, and may be allocated on the stack or within another + * structure or class (see below for the Init and Finish functions to use). + * + * To decide whether to use double hashing vs. chaining, we need to develop a + * trade-off relation, as follows: + * + * Let alpha be the load factor, esize the entry size in words, count the + * entry count, and pow2 the power-of-two table size in entries. + * + * (PLDHashTable overhead) > (PLHashTable overhead) + * (unused table entry space) > (malloc and .next overhead per entry) + + * (buckets overhead) + * (1 - alpha) * esize * pow2 > 2 * count + pow2 + * + * Notice that alpha is by definition (count / pow2): + * + * (1 - alpha) * esize * pow2 > 2 * alpha * pow2 + pow2 + * (1 - alpha) * esize > 2 * alpha + 1 + * + * esize > (1 + 2 * alpha) / (1 - alpha) + * + * This assumes both tables must keep keyHash, key, and value for each entry, + * where key and value point to separately allocated strings or structures. + * If key and value can be combined into one pointer, then the trade-off is: + * + * esize > (1 + 3 * alpha) / (1 - alpha) + * + * If the entry value can be a subtype of PLDHashEntryHdr, rather than a type + * that must be allocated separately and referenced by an entry.value pointer + * member, and provided key's allocation can be fused with its entry's, then + * k (the words wasted per entry with chaining) is 4. + * + * To see these curves, feed gnuplot input like so: + * + * gnuplot> f(x,k) = (1 + k * x) / (1 - x) + * gnuplot> plot [0:.75] f(x,2), f(x,3), f(x,4) + * + * For k of 2 and a well-loaded table (alpha > .5), esize must be more than 4 + * words for chaining to be more space-efficient than double hashing. + * + * Solving for alpha helps us decide when to shrink an underloaded table: + * + * esize > (1 + k * alpha) / (1 - alpha) + * esize - alpha * esize > 1 + k * alpha + * esize - 1 > (k + esize) * alpha + * (esize - 1) / (k + esize) > alpha + * + * alpha < (esize - 1) / (esize + k) + * + * Therefore double hashing should keep alpha >= (esize - 1) / (esize + k), + * assuming esize is not too large (in which case, chaining should probably be + * used for any alpha). For esize=2 and k=3, we want alpha >= .2; for esize=3 + * and k=2, we want alpha >= .4. For k=4, esize could be 6, and alpha >= .5 + * would still obtain. See the PL_DHASH_MIN_ALPHA macro further below. + * + * The current implementation uses a configurable lower bound on alpha, which + * defaults to .25, when deciding to shrink the table (while still respecting + * PL_DHASH_MIN_SIZE). + * + * Note a qualitative difference between chaining and double hashing: under + * chaining, entry addresses are stable across table shrinks and grows. With + * double hashing, you can't safely hold an entry pointer and use it after an + * ADD or REMOVE operation, unless you sample table->generation before adding + * or removing, and compare the sample after, dereferencing the entry pointer + * only if table->generation has not changed. + * + * The moral of this story: there is no one-size-fits-all hash table scheme, + * but for small table entry size, and assuming entry address stability is not + * required, double hashing wins. + */ +struct PLDHashTable { + const PLDHashTableOps *ops; /* virtual operations, see below */ + void *data; /* ops- and instance-specific data */ + PRInt16 hashShift; /* multiplicative hash shift */ + uint8 maxAlphaFrac; /* 8-bit fixed point max alpha */ + uint8 minAlphaFrac; /* 8-bit fixed point min alpha */ + PRUint32 entrySize; /* number of bytes in an entry */ + PRUint32 entryCount; /* number of entries in table */ + PRUint32 removedCount; /* removed entry sentinels in table */ + PRUint32 generation; /* entry storage generation number */ + char *entryStore; /* entry storage */ +#ifdef PL_DHASHMETER + struct PLDHashStats { + PRUint32 searches; /* total number of table searches */ + PRUint32 steps; /* hash chain links traversed */ + PRUint32 hits; /* searches that found key */ + PRUint32 misses; /* searches that didn't find key */ + PRUint32 lookups; /* number of PL_DHASH_LOOKUPs */ + PRUint32 addMisses; /* adds that miss, and do work */ + PRUint32 addOverRemoved; /* adds that recycled a removed entry */ + PRUint32 addHits; /* adds that hit an existing entry */ + PRUint32 addFailures; /* out-of-memory during add growth */ + PRUint32 removeHits; /* removes that hit, and do work */ + PRUint32 removeMisses; /* useless removes that miss */ + PRUint32 removeFrees; /* removes that freed entry directly */ + PRUint32 removeEnums; /* removes done by Enumerate */ + PRUint32 grows; /* table expansions */ + PRUint32 shrinks; /* table contractions */ + PRUint32 compresses; /* table compressions */ + PRUint32 enumShrinks; /* contractions after Enumerate */ + } stats; +#endif +}; + +/* + * Size in entries (gross, not net of free and removed sentinels) for table. + * We store hashShift rather than sizeLog2 to optimize the collision-free case + * in SearchTable. + */ +#define PL_DHASH_TABLE_SIZE(table) PR_BIT(PL_DHASH_BITS - (table)->hashShift) + +/* + * Table space at entryStore is allocated and freed using these callbacks. + * The allocator should return null on error only (not if called with nbytes + * equal to 0; but note that pldhash.c code will never call with 0 nbytes). + */ +typedef void * +(* PR_CALLBACK PLDHashAllocTable)(PLDHashTable *table, PRUint32 nbytes); + +typedef void +(* PR_CALLBACK PLDHashFreeTable) (PLDHashTable *table, void *ptr); + +/* + * When a table grows or shrinks, each entry is queried for its key using this + * callback. NB: in that event, entry is not in table any longer; it's in the + * old entryStore vector, which is due to be freed once all entries have been + * moved via moveEntry callbacks. + */ +typedef const void * +(* PR_CALLBACK PLDHashGetKey) (PLDHashTable *table, + PLDHashEntryHdr *entry); + +/* + * Compute the hash code for a given key to be looked up, added, or removed + * from table. A hash code may have any PLDHashNumber value. + */ +typedef PLDHashNumber +(* PR_CALLBACK PLDHashHashKey) (PLDHashTable *table, const void *key); + +/* + * Compare the key identifying entry in table with the provided key parameter. + * Return PR_TRUE if keys match, PR_FALSE otherwise. + */ +typedef PRBool +(* PR_CALLBACK PLDHashMatchEntry)(PLDHashTable *table, + const PLDHashEntryHdr *entry, + const void *key); + +/* + * Copy the data starting at from to the new entry storage at to. Do not add + * reference counts for any strong references in the entry, however, as this + * is a "move" operation: the old entry storage at from will be freed without + * any reference-decrementing callback shortly. + */ +typedef void +(* PR_CALLBACK PLDHashMoveEntry)(PLDHashTable *table, + const PLDHashEntryHdr *from, + PLDHashEntryHdr *to); + +/* + * Clear the entry and drop any strong references it holds. This callback is + * invoked during a PL_DHASH_REMOVE operation (see below for operation codes), + * but only if the given key is found in the table. + */ +typedef void +(* PR_CALLBACK PLDHashClearEntry)(PLDHashTable *table, + PLDHashEntryHdr *entry); + +/* + * Called when a table (whether allocated dynamically by itself, or nested in + * a larger structure, or allocated on the stack) is finished. This callback + * allows table->ops-specific code to finalize table->data. + */ +typedef void +(* PR_CALLBACK PLDHashFinalize) (PLDHashTable *table); + +/* + * Initialize a new entry, apart from keyHash. This function is called when + * PL_DHashTableOperate's PL_DHASH_ADD case finds no existing entry for the + * given key, and must add a new one. At that point, entry->keyHash is not + * set yet, to avoid claiming the last free entry in a severely overloaded + * table. + */ +typedef PRBool +(* PR_CALLBACK PLDHashInitEntry)(PLDHashTable *table, + PLDHashEntryHdr *entry, + const void *key); + +/* + * Finally, the "vtable" structure for PLDHashTable. The first eight hooks + * must be provided by implementations; they're called unconditionally by the + * generic pldhash.c code. Hooks after these may be null. + * + * Summary of allocation-related hook usage with C++ placement new emphasis: + * allocTable Allocate raw bytes with malloc, no ctors run. + * freeTable Free raw bytes with free, no dtors run. + * initEntry Call placement new using default key-based ctor. + * Return PR_TRUE on success, PR_FALSE on error. + * moveEntry Call placement new using copy ctor, run dtor on old + * entry storage. + * clearEntry Run dtor on entry. + * finalize Stub unless table->data was initialized and needs to + * be finalized. + * + * Note the reason why initEntry is optional: the default hooks (stubs) clear + * entry storage: On successful PL_DHashTableOperate(tbl, key, PL_DHASH_ADD), + * the returned entry pointer addresses an entry struct whose keyHash member + * has been set non-zero, but all other entry members are still clear (null). + * PL_DHASH_ADD callers can test such members to see whether the entry was + * newly created by the PL_DHASH_ADD call that just succeeded. If placement + * new or similar initialization is required, define an initEntry hook. Of + * course, the clearEntry hook must zero or null appropriately. + * + * XXX assumes 0 is null for pointer types. + */ +struct PLDHashTableOps { + /* Mandatory hooks. All implementations must provide these. */ + PLDHashAllocTable allocTable; + PLDHashFreeTable freeTable; + PLDHashGetKey getKey; + PLDHashHashKey hashKey; + PLDHashMatchEntry matchEntry; + PLDHashMoveEntry moveEntry; + PLDHashClearEntry clearEntry; + PLDHashFinalize finalize; + + /* Optional hooks start here. If null, these are not called. */ + PLDHashInitEntry initEntry; +}; + +/* + * Default implementations for the above ops. + */ +PR_EXTERN(void *) +PL_DHashAllocTable(PLDHashTable *table, PRUint32 nbytes); + +PR_EXTERN(void) +PL_DHashFreeTable(PLDHashTable *table, void *ptr); + +PR_EXTERN(PLDHashNumber) +PL_DHashStringKey(PLDHashTable *table, const void *key); + +/* A minimal entry contains a keyHash header and a void key pointer. */ +struct PLDHashEntryStub { + PLDHashEntryHdr hdr; + const void *key; +}; + +PR_EXTERN(const void *) +PL_DHashGetKeyStub(PLDHashTable *table, PLDHashEntryHdr *entry); + +PR_EXTERN(PLDHashNumber) +PL_DHashVoidPtrKeyStub(PLDHashTable *table, const void *key); + +PR_EXTERN(PRBool) +PL_DHashMatchEntryStub(PLDHashTable *table, + const PLDHashEntryHdr *entry, + const void *key); + +PR_EXTERN(PRBool) +PL_DHashMatchStringKey(PLDHashTable *table, + const PLDHashEntryHdr *entry, + const void *key); + +PR_EXTERN(void) +PL_DHashMoveEntryStub(PLDHashTable *table, + const PLDHashEntryHdr *from, + PLDHashEntryHdr *to); + +PR_EXTERN(void) +PL_DHashClearEntryStub(PLDHashTable *table, PLDHashEntryHdr *entry); + +PR_EXTERN(void) +PL_DHashFreeStringKey(PLDHashTable *table, PLDHashEntryHdr *entry); + +PR_EXTERN(void) +PL_DHashFinalizeStub(PLDHashTable *table); + +/* + * If you use PLDHashEntryStub or a subclass of it as your entry struct, and + * if your entries move via memcpy and clear via memset(0), you can use these + * stub operations. + */ +PR_EXTERN(const PLDHashTableOps *) +PL_DHashGetStubOps(void); + +/* + * Dynamically allocate a new PLDHashTable using malloc, initialize it using + * PL_DHashTableInit, and return its address. Return null on malloc failure. + * Note that the entry storage at table->entryStore will be allocated using + * the ops->allocTable callback. + */ +PR_EXTERN(PLDHashTable *) +PL_NewDHashTable(const PLDHashTableOps *ops, void *data, PRUint32 entrySize, + PRUint32 capacity); + +/* + * Finalize table's data, free its entry storage (via table->ops->freeTable), + * and return the memory starting at table to the malloc heap. + */ +PR_EXTERN(void) +PL_DHashTableDestroy(PLDHashTable *table); + +/* + * Initialize table with ops, data, entrySize, and capacity. Capacity is a + * guess for the smallest table size at which the table will usually be less + * than 75% loaded (the table will grow or shrink as needed; capacity serves + * only to avoid inevitable early growth from PL_DHASH_MIN_SIZE). + */ +PR_EXTERN(PRBool) +PL_DHashTableInit(PLDHashTable *table, const PLDHashTableOps *ops, void *data, + PRUint32 entrySize, PRUint32 capacity); + +/* + * Set maximum and minimum alpha for table. The defaults are 0.75 and .25. + * maxAlpha must be in [0.5, 0.9375] for the default PL_DHASH_MIN_SIZE; or if + * MinSize=PL_DHASH_MIN_SIZE <= 256, in [0.5, (float)(MinSize-1)/MinSize]; or + * else in [0.5, 255.0/256]. minAlpha must be in [0, maxAlpha / 2), so that + * we don't shrink on the very next remove after growing a table upon adding + * an entry that brings entryCount past maxAlpha * tableSize. + */ +PR_IMPLEMENT(void) +PL_DHashTableSetAlphaBounds(PLDHashTable *table, + float maxAlpha, + float minAlpha); + +/* + * Call this macro with k, the number of pointer-sized words wasted per entry + * under chaining, to compute the minimum alpha at which double hashing still + * beats chaining. + */ +#define PL_DHASH_MIN_ALPHA(table, k) \ + ((float)((table)->entrySize / sizeof(void *) - 1) \ + / ((table)->entrySize / sizeof(void *) + (k))) + +/* + * Finalize table's data, free its entry storage using table->ops->freeTable, + * and leave its members unchanged from their last live values (which leaves + * pointers dangling). If you want to burn cycles clearing table, it's up to + * your code to call memset. + */ +PR_EXTERN(void) +PL_DHashTableFinish(PLDHashTable *table); + +/* + * To consolidate keyHash computation and table grow/shrink code, we use a + * single entry point for lookup, add, and remove operations. The operation + * codes are declared here, along with codes returned by PLDHashEnumerator + * functions, which control PL_DHashTableEnumerate's behavior. + */ +typedef enum PLDHashOperator { + PL_DHASH_LOOKUP = 0, /* lookup entry */ + PL_DHASH_ADD = 1, /* add entry */ + PL_DHASH_REMOVE = 2, /* remove entry, or enumerator says remove */ + PL_DHASH_NEXT = 0, /* enumerator says continue */ + PL_DHASH_STOP = 1 /* enumerator says stop */ +} PLDHashOperator; + +/* + * To lookup a key in table, call: + * + * entry = PL_DHashTableOperate(table, key, PL_DHASH_LOOKUP); + * + * If PL_DHASH_ENTRY_IS_BUSY(entry) is true, key was found and it identifies + * entry. If PL_DHASH_ENTRY_IS_FREE(entry) is true, key was not found. + * + * To add an entry identified by key to table, call: + * + * entry = PL_DHashTableOperate(table, key, PL_DHASH_ADD); + * + * If entry is null upon return, then either the table is severely overloaded, + * and memory can't be allocated for entry storage via table->ops->allocTable; + * Or if table->ops->initEntry is non-null, the table->ops->initEntry op may + * have returned false. + * + * Otherwise, entry->keyHash has been set so that PL_DHASH_ENTRY_IS_BUSY(entry) + * is true, and it is up to the caller to initialize the key and value parts + * of the entry sub-type, if they have not been set already (i.e. if entry was + * not already in the table, and if the optional initEntry hook was not used). + * + * To remove an entry identified by key from table, call: + * + * (void) PL_DHashTableOperate(table, key, PL_DHASH_REMOVE); + * + * If key's entry is found, it is cleared (via table->ops->clearEntry) and + * the entry is marked so that PL_DHASH_ENTRY_IS_FREE(entry). This operation + * returns null unconditionally; you should ignore its return value. + */ +PR_EXTERN(PLDHashEntryHdr *) PL_DHASH_FASTCALL +PL_DHashTableOperate(PLDHashTable *table, const void *key, PLDHashOperator op); + +/* + * Remove an entry already accessed via LOOKUP or ADD. + * + * NB: this is a "raw" or low-level routine, intended to be used only where + * the inefficiency of a full PL_DHashTableOperate (which rehashes in order + * to find the entry given its key) is not tolerable. This function does not + * shrink the table if it is underloaded. It does not update stats #ifdef + * PL_DHASHMETER, either. + */ +PR_EXTERN(void) +PL_DHashTableRawRemove(PLDHashTable *table, PLDHashEntryHdr *entry); + +/* + * Enumerate entries in table using etor: + * + * count = PL_DHashTableEnumerate(table, etor, arg); + * + * PL_DHashTableEnumerate calls etor like so: + * + * op = etor(table, entry, number, arg); + * + * where number is a zero-based ordinal assigned to live entries according to + * their order in table->entryStore. + * + * The return value, op, is treated as a set of flags. If op is PL_DHASH_NEXT, + * then continue enumerating. If op contains PL_DHASH_REMOVE, then clear (via + * table->ops->clearEntry) and free entry. Then we check whether op contains + * PL_DHASH_STOP; if so, stop enumerating and return the number of live entries + * that were enumerated so far. Return the total number of live entries when + * enumeration completes normally. + * + * If etor calls PL_DHashTableOperate on table with op != PL_DHASH_LOOKUP, it + * must return PL_DHASH_STOP; otherwise undefined behavior results. + * + * If any enumerator returns PL_DHASH_REMOVE, table->entryStore may be shrunk + * or compressed after enumeration, but before PL_DHashTableEnumerate returns. + * Such an enumerator therefore can't safely set aside entry pointers, but an + * enumerator that never returns PL_DHASH_REMOVE can set pointers to entries + * aside, e.g., to avoid copying live entries into an array of the entry type. + * Copying entry pointers is cheaper, and safe so long as the caller of such a + * "stable" Enumerate doesn't use the set-aside pointers after any call either + * to PL_DHashTableOperate, or to an "unstable" form of Enumerate, which might + * grow or shrink entryStore. + * + * If your enumerator wants to remove certain entries, but set aside pointers + * to other entries that it retains, it can use PL_DHashTableRawRemove on the + * entries to be removed, returning PL_DHASH_NEXT to skip them. Likewise, if + * you want to remove entries, but for some reason you do not want entryStore + * to be shrunk or compressed, you can call PL_DHashTableRawRemove safely on + * the entry being enumerated, rather than returning PL_DHASH_REMOVE. + */ +typedef PLDHashOperator +(* PR_CALLBACK PLDHashEnumerator)(PLDHashTable *table, PLDHashEntryHdr *hdr, + PRUint32 number, void *arg); + +PR_EXTERN(PRUint32) +PL_DHashTableEnumerate(PLDHashTable *table, PLDHashEnumerator etor, void *arg); + +#ifdef PL_DHASHMETER +#include + +PR_EXTERN(void) +PL_DHashTableDumpMeter(PLDHashTable *table, PLDHashEnumerator dump, FILE *fp); +#endif + +PR_END_EXTERN_C + +#endif /* pldhash_h___ */ diff --git a/src/libs/xpcom18a4/xpcom/glue/.cvsignore b/src/libs/xpcom18a4/xpcom/glue/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/glue/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/xpcom/glue/Makefile.in b/src/libs/xpcom18a4/xpcom/glue/Makefile.in new file mode 100644 index 00000000..a3b1f24d --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/glue/Makefile.in @@ -0,0 +1,86 @@ +# ***** 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.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 2001 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# 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 ***** + +DEPTH = ../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk +include $(srcdir)/objs.mk + +DIRS = standalone + +MODULE = xpcom +LIBRARY_NAME = xpcomglue_s + +REQUIRES = $(NULL) + +LOCAL_INCLUDES = \ + -I$(srcdir)/../build \ + $(NULL) + +CPPSRCS = \ + $(XPCOM_GLUE_SRC_LCSRCS) \ + $(NULL) + +SDK_HEADERS = \ + nsIGenericFactory.h \ + nsIInterfaceRequestorUtils.h \ + nsISupportsImpl.h \ + nsISupportsUtils.h \ + nsIWeakReferenceUtils.h \ + $(XPCOM_GLUE_SRC_LEXPORTS) \ + $(NULL) + +SDK_LIBRARY = \ + $(LIB_PREFIX)xpcomglue_s.$(LIB_SUFFIX) \ + $(NULL) + +# we don't want the shared lib, but we want to force the creation of a static lib. +FORCE_STATIC_LIB = 1 + +# Force use of PIC +FORCE_USE_PIC = 1 + +include $(topsrcdir)/config/rules.mk + +# hack to work around objdir bustage +export:: + rm -f $(XPCOM_GLUE_SRC_CSRCS:.cpp=.$(OBJ_SUFFIX)) + +DEFINES += \ + -D_IMPL_NS_COM diff --git a/src/libs/xpcom18a4/xpcom/glue/nsCOMPtr.cpp b/src/libs/xpcom18a4/xpcom/glue/nsCOMPtr.cpp new file mode 100644 index 00000000..cac3c6d4 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/glue/nsCOMPtr.cpp @@ -0,0 +1,124 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Scott Collins + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsCOMPtr.h" + +nsresult +nsQueryInterface::operator()( const nsIID& aIID, void** answer ) const + { + nsresult status; + if ( mRawPtr ) + { + status = mRawPtr->QueryInterface(aIID, answer); +#ifdef NSCAP_FEATURE_TEST_NONNULL_QUERY_SUCCEEDS + NS_WARN_IF_FALSE(NS_SUCCEEDED(status), "interface not found---were you expecting that?"); +#endif + } + else + status = NS_ERROR_NULL_POINTER; + + return status; + } + +nsresult +nsQueryInterfaceWithError::operator()( const nsIID& aIID, void** answer ) const + { + nsresult status; + if ( mRawPtr ) + { + status = mRawPtr->QueryInterface(aIID, answer); +#ifdef NSCAP_FEATURE_TEST_NONNULL_QUERY_SUCCEEDS + NS_WARN_IF_FALSE(NS_SUCCEEDED(status), "interface not found---were you expecting that?"); +#endif + } + else + status = NS_ERROR_NULL_POINTER; + + if ( mErrorPtr ) + *mErrorPtr = status; + return status; + } + +nsCOMPtr_base::~nsCOMPtr_base() + { + NSCAP_LOG_RELEASE(this, mRawPtr); + if ( mRawPtr ) + NSCAP_RELEASE(this, mRawPtr); + } + +void +nsCOMPtr_base::assign_with_AddRef( nsISupports* rawPtr ) + { + if ( rawPtr ) + NSCAP_ADDREF(this, rawPtr); + assign_assuming_AddRef(rawPtr); + } + +void +nsCOMPtr_base::assign_from_qi( const nsQueryInterface qi, const nsIID& iid ) + { + nsISupports* newRawPtr; + if ( NS_FAILED( qi(iid, NS_REINTERPRET_CAST(void**, &newRawPtr)) ) ) + newRawPtr = 0; + assign_assuming_AddRef(newRawPtr); + } + +void +nsCOMPtr_base::assign_from_qi_with_error( const nsQueryInterfaceWithError& qi, const nsIID& iid ) + { + nsISupports* newRawPtr; + if ( NS_FAILED( qi(iid, NS_REINTERPRET_CAST(void**, &newRawPtr)) ) ) + newRawPtr = 0; + assign_assuming_AddRef(newRawPtr); + } + +void +nsCOMPtr_base::assign_from_helper( const nsCOMPtr_helper& helper, const nsIID& iid ) + { + nsISupports* newRawPtr; + if ( NS_FAILED( helper(iid, NS_REINTERPRET_CAST(void**, &newRawPtr)) ) ) + newRawPtr = 0; + assign_assuming_AddRef(newRawPtr); + } + +void** +nsCOMPtr_base::begin_assignment() + { + assign_assuming_AddRef(0); + return NS_REINTERPRET_CAST(void**, &mRawPtr); + } diff --git a/src/libs/xpcom18a4/xpcom/glue/nsCOMPtr.h b/src/libs/xpcom18a4/xpcom/glue/nsCOMPtr.h new file mode 100644 index 00000000..b5a0fd78 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/glue/nsCOMPtr.h @@ -0,0 +1,1405 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Scott Collins (original author) + * L. David Baron + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +#ifndef nsCOMPtr_h___ +#define nsCOMPtr_h___ + +/* + Having problems? + + See the User Manual at: + http://www.mozilla.org/projects/xpcom/nsCOMPtr.html + + + nsCOMPtr + better than a raw pointer + for owning objects + -- scc +*/ + + + // Wrapping includes can speed up compiles (see "Large Scale C++ Software Design") +#ifndef nsDebug_h___ +#include "nsDebug.h" + // for |NS_PRECONDITION| +#endif + +#ifndef nsISupportsUtils_h__ +#include "nsISupportsUtils.h" + // for |nsresult|, |NS_ADDREF|, |NS_GET_IID| et al +#endif + +#ifndef nscore_h___ +#include "nscore.h" + // for |NS_..._CAST|, |NS_COM| +#endif + + +/* + WARNING: + This file defines several macros for internal use only. These macros begin with the + prefix |NSCAP_|. Do not use these macros in your own code. They are for internal use + only for cross-platform compatibility, and are subject to change without notice. +*/ + + +#ifdef _MSC_VER + #define NSCAP_FEATURE_INLINE_STARTASSIGNMENT + // under VC++, we win by inlining StartAssignment + + // Also under VC++, at the highest warning level, we are overwhelmed with warnings + // about (unused) inline functions being removed. This is to be expected with + // templates, so we disable the warning. + #pragma warning( disable: 4514 ) +#endif + +#define NSCAP_FEATURE_USE_BASE + +#ifdef NS_DEBUG + #define NSCAP_FEATURE_TEST_DONTQUERY_CASES + #undef NSCAP_FEATURE_USE_BASE +//#define NSCAP_FEATURE_TEST_NONNULL_QUERY_SUCCEEDS +#endif + + /* + |...TEST_DONTQUERY_CASES| and |...DEBUG_PTR_TYPES| introduce some code that is + problematic on a select few of our platforms, e.g., QNX. Therefore, I'm providing + a mechanism by which these features can be explicitly disabled from the command-line. + */ + +#ifdef NSCAP_DISABLE_TEST_DONTQUERY_CASES + #undef NSCAP_FEATURE_TEST_DONTQUERY_CASES +#endif + +#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3) + // Our use of nsCOMPtr_base::mRawPtr violates the C++ standard's aliasing + // rules. Mark it with the may_alias attribute so that gcc 3.3 and higher + // don't reorder instructions based on aliasing assumptions for + // this variable. Fortunately, gcc versions < 3.3 do not do any + // optimizations that break nsCOMPtr. + + #define NS_MAY_ALIAS_PTR(t) t* __attribute__((__may_alias__)) +#else + #define NS_MAY_ALIAS_PTR(t) t* +#endif + +#if defined(NSCAP_DISABLE_DEBUG_PTR_TYPES) + #define NSCAP_FEATURE_USE_BASE +#endif + + +#ifdef HAVE_CPP_BOOL + typedef bool NSCAP_BOOL; +#else + typedef PRBool NSCAP_BOOL; +#endif + + + + + /* + The following three macros (|NSCAP_ADDREF|, |NSCAP_RELEASE|, and |NSCAP_LOG_ASSIGNMENT|) + allow external clients the ability to add logging or other interesting debug facilities. + In fact, if you want |nsCOMPtr| to participate in the standard logging facility, you + provide (e.g., in "nsTraceRefcnt.h") suitable definitions + + #define NSCAP_ADDREF(this, ptr) NS_ADDREF(ptr) + #define NSCAP_RELEASE(this, ptr) NS_RELEASE(ptr) + */ + +#ifndef NSCAP_ADDREF + #define NSCAP_ADDREF(this, ptr) (ptr)->AddRef() +#endif + +#ifndef NSCAP_RELEASE + #define NSCAP_RELEASE(this, ptr) (ptr)->Release() +#endif + + // Clients can define |NSCAP_LOG_ASSIGNMENT| to perform logging. +#ifdef NSCAP_LOG_ASSIGNMENT + // Remember that |NSCAP_LOG_ASSIGNMENT| was defined by some client so that we know + // to instantiate |~nsGetterAddRefs| in turn to note the external assignment into + // the |nsCOMPtr|. + #define NSCAP_LOG_EXTERNAL_ASSIGNMENT +#else + // ...otherwise, just strip it out of the code + #define NSCAP_LOG_ASSIGNMENT(this, ptr) +#endif + +#ifndef NSCAP_LOG_RELEASE + #define NSCAP_LOG_RELEASE(this, ptr) +#endif + + + + + /* + WARNING: + VC++4.2 is very picky. To compile under VC++4.2, the classes must be defined + in an order that satisfies: + + nsDerivedSafe < nsCOMPtr + already_AddRefed < nsCOMPtr + nsCOMPtr < nsGetterAddRefs + + The other compilers probably won't complain, so please don't reorder these + classes, on pain of breaking 4.2 compatibility. + */ + + +template +class nsDerivedSafe : public T + /* + No client should ever see or have to type the name of this class. It is the + artifact that makes it a compile-time error to call |AddRef| and |Release| + on a |nsCOMPtr|. DO NOT USE THIS TYPE DIRECTLY IN YOUR CODE. + + See |nsCOMPtr::operator->|, |nsCOMPtr::operator*|, et al. + + This type should be a nested class inside |nsCOMPtr|. + */ + { + private: +#ifdef HAVE_CPP_ACCESS_CHANGING_USING + using T::AddRef; + using T::Release; +#else + nsrefcnt AddRef(void); + nsrefcnt Release(void); +#endif + +#if !defined(AIX) && !defined(IRIX) + void operator delete( void*, size_t ); // NOT TO BE IMPLEMENTED + // declaring |operator delete| private makes calling delete on an interface pointer a compile error +#endif + + nsDerivedSafe& operator=( const T& ); // NOT TO BE IMPLEMENTED + // you may not call |operator=()| through a dereferenced |nsCOMPtr|, because you'd get the wrong one + + /* + Compiler warnings and errors: nsDerivedSafe operator=() hides inherited operator=(). + If you see that, that means somebody checked in a [XP]COM interface class that declares an + |operator=()|, and that's _bad_. So bad, in fact, that this declaration exists explicitly + to stop people from doing it. + */ + + protected: + nsDerivedSafe(); // NOT TO BE IMPLEMENTED + /* + This ctor exists to avoid compile errors and warnings about nsDeriviedSafe using the + default ctor but inheriting classes without an empty ctor. See bug 209667. + */ + }; + +#if !defined(HAVE_CPP_ACCESS_CHANGING_USING) && defined(NEED_CPP_UNUSED_IMPLEMENTATIONS) +template +nsrefcnt +nsDerivedSafe::AddRef() + { + return 0; + } + +template +nsrefcnt +nsDerivedSafe::Release() + { + return 0; + } + +#endif + + + +template +struct already_AddRefed + /* + ...cooperates with |nsCOMPtr| to allow you to assign in a pointer _without_ + |AddRef|ing it. You might want to use this as a return type from a function + that produces an already |AddRef|ed pointer as a result. + + See also |getter_AddRefs()|, |dont_AddRef()|, and |class nsGetterAddRefs|. + + This type should be a nested class inside |nsCOMPtr|. + + Yes, |already_AddRefed| could have been implemented as an |nsCOMPtr_helper| to + avoid adding specialized machinery to |nsCOMPtr| ... but this is the simplest + case, and perhaps worth the savings in time and space that its specific + implementation affords over the more general solution offered by + |nsCOMPtr_helper|. + */ + { + already_AddRefed( T* aRawPtr ) + : mRawPtr(aRawPtr) + { + // nothing else to do here + } + + T* get() const { return mRawPtr; } + + T* mRawPtr; + }; + +template +inline +const already_AddRefed +getter_AddRefs( T* aRawPtr ) + /* + ...makes typing easier, because it deduces the template type, e.g., + you write |dont_AddRef(fooP)| instead of |already_AddRefed(fooP)|. + */ + { + return already_AddRefed(aRawPtr); + } + +template +inline +const already_AddRefed +getter_AddRefs( const already_AddRefed aAlreadyAddRefedPtr ) + { + return aAlreadyAddRefedPtr; + } + +template +inline +const already_AddRefed +dont_AddRef( T* aRawPtr ) + { + return already_AddRefed(aRawPtr); + } + +template +inline +const already_AddRefed +dont_AddRef( const already_AddRefed aAlreadyAddRefedPtr ) + { + return aAlreadyAddRefedPtr; + } + + + +class nsCOMPtr_helper + /* + An |nsCOMPtr_helper| transforms commonly called getters into typesafe forms + that are more convenient to call, and more efficient to use with |nsCOMPtr|s. + Good candidates for helpers are |QueryInterface()|, |CreateInstance()|, etc. + + Here are the rules for a helper: + - it implements |operator()| to produce an interface pointer + - (except for its name) |operator()| is a valid [XP]COM `getter' + - the interface pointer that it returns is already |AddRef()|ed (as from any good getter) + - it matches the type requested with the supplied |nsIID| argument + - its constructor provides an optional |nsresult*| that |operator()| can fill + in with an error when it is executed + + See |class nsGetInterface| for an example. + */ + { + public: + virtual nsresult NS_FASTCALL operator()( const nsIID&, void** ) const = 0; + }; + +/* + |nsQueryInterface| could have been implemented as an |nsCOMPtr_helper| to + avoid adding specialized machinery in |nsCOMPtr|, But |do_QueryInterface| + is called often enough that the codesize savings are big enough to + warrant the specialcasing. +*/ + +class NS_COM nsQueryInterface + { + public: + nsQueryInterface( nsISupports* aRawPtr ) + : mRawPtr(aRawPtr) + { + // nothing else to do here + } + + nsresult NS_FASTCALL operator()( const nsIID& aIID, void** ) const; + + private: + nsISupports* mRawPtr; + }; + +class NS_COM nsQueryInterfaceWithError + { + public: + nsQueryInterfaceWithError( nsISupports* aRawPtr, nsresult* error ) + : mRawPtr(aRawPtr), + mErrorPtr(error) + { + // nothing else to do here + } + + nsresult NS_FASTCALL operator()( const nsIID& aIID, void** ) const; + + private: + nsISupports* mRawPtr; + nsresult* mErrorPtr; + }; + +inline +nsQueryInterface +do_QueryInterface( nsISupports* aRawPtr ) + { + return nsQueryInterface(aRawPtr); + } + +inline +nsQueryInterfaceWithError +do_QueryInterface( nsISupports* aRawPtr, nsresult* error ) + { + return nsQueryInterfaceWithError(aRawPtr, error); + } + +template +inline +void +do_QueryInterface( already_AddRefed& ) + { + // This signature exists soley to _stop_ you from doing the bad thing. + // Saying |do_QueryInterface()| on a pointer that is not otherwise owned by + // someone else is an automatic leak. See . + } + +template +inline +void +do_QueryInterface( already_AddRefed&, nsresult* ) + { + // This signature exists soley to _stop_ you from doing the bad thing. + // Saying |do_QueryInterface()| on a pointer that is not otherwise owned by + // someone else is an automatic leak. See . + } + + + +class nsCOMPtr_base + /* + ...factors implementation for all template versions of |nsCOMPtr|. + + This should really be an |nsCOMPtr|, but this wouldn't work + because unlike the + + Here's the way people normally do things like this + + template class Foo { ... }; + template <> class Foo { ... }; + template class Foo : private Foo { ... }; + */ + { + public: + + nsCOMPtr_base( nsISupports* rawPtr = 0 ) + : mRawPtr(rawPtr) + { + // nothing else to do here + } + + NS_COM NS_FASTCALL ~nsCOMPtr_base(); + + NS_COM void NS_FASTCALL assign_with_AddRef( nsISupports* ); + NS_COM void NS_FASTCALL assign_from_qi( const nsQueryInterface, const nsIID& ); + NS_COM void NS_FASTCALL assign_from_qi_with_error( const nsQueryInterfaceWithError&, const nsIID& ); + NS_COM void NS_FASTCALL assign_from_helper( const nsCOMPtr_helper&, const nsIID& ); + NS_COM void** NS_FASTCALL begin_assignment(); + + protected: + NS_MAY_ALIAS_PTR(nsISupports) mRawPtr; + + void + assign_assuming_AddRef( nsISupports* newPtr ) + { + /* + |AddRef()|ing the new value (before entering this function) before + |Release()|ing the old lets us safely ignore the self-assignment case. + We must, however, be careful only to |Release()| _after_ doing the + assignment, in case the |Release()| leads to our _own_ destruction, + which would, in turn, cause an incorrect second |Release()| of our old + pointer. Thank for discovering this. + */ + nsISupports* oldPtr = mRawPtr; + mRawPtr = newPtr; + NSCAP_LOG_ASSIGNMENT(this, newPtr); + NSCAP_LOG_RELEASE(this, oldPtr); + if ( oldPtr ) + NSCAP_RELEASE(this, oldPtr); + } + }; + +// template class nsGetterAddRefs; + +template +class nsCOMPtr +#ifdef NSCAP_FEATURE_USE_BASE + : private nsCOMPtr_base +#endif + { + +#ifdef NSCAP_FEATURE_USE_BASE + #define NSCAP_CTOR_BASE(x) nsCOMPtr_base(x) +#else + #define NSCAP_CTOR_BASE(x) mRawPtr(x) + + private: + void assign_with_AddRef( nsISupports* ); + void assign_from_qi( const nsQueryInterface, const nsIID& ); + void assign_from_qi_with_error( const nsQueryInterfaceWithError&, const nsIID& ); + void assign_from_helper( const nsCOMPtr_helper&, const nsIID& ); + void** begin_assignment(); + + void + assign_assuming_AddRef( T* newPtr ) + { + T* oldPtr = mRawPtr; + mRawPtr = newPtr; + NSCAP_LOG_ASSIGNMENT(this, newPtr); + NSCAP_LOG_RELEASE(this, oldPtr); + if ( oldPtr ) + NSCAP_RELEASE(this, oldPtr); + } + + private: + T* mRawPtr; +#endif + + public: + typedef T element_type; + +#ifndef NSCAP_FEATURE_USE_BASE + ~nsCOMPtr() + { + NSCAP_LOG_RELEASE(this, mRawPtr); + if ( mRawPtr ) + NSCAP_RELEASE(this, mRawPtr); + } +#endif + +#ifdef NSCAP_FEATURE_TEST_DONTQUERY_CASES + void + Assert_NoQueryNeeded() + { + if ( mRawPtr ) + { + nsCOMPtr query_result( do_QueryInterface(mRawPtr) ); + NS_ASSERTION(query_result.get() == mRawPtr, "QueryInterface needed"); + } + } + + #define NSCAP_ASSERT_NO_QUERY_NEEDED() Assert_NoQueryNeeded(); +#else + #define NSCAP_ASSERT_NO_QUERY_NEEDED() +#endif + + + // Constructors + + nsCOMPtr() + : NSCAP_CTOR_BASE(0) + // default constructor + { + NSCAP_LOG_ASSIGNMENT(this, 0); + } + + nsCOMPtr( const nsCOMPtr& aSmartPtr ) + : NSCAP_CTOR_BASE(aSmartPtr.mRawPtr) + // copy-constructor + { + if ( mRawPtr ) + NSCAP_ADDREF(this, mRawPtr); + NSCAP_LOG_ASSIGNMENT(this, aSmartPtr.mRawPtr); + } + + nsCOMPtr( T* aRawPtr ) + : NSCAP_CTOR_BASE(aRawPtr) + // construct from a raw pointer (of the right type) + { + if ( mRawPtr ) + NSCAP_ADDREF(this, mRawPtr); + NSCAP_LOG_ASSIGNMENT(this, aRawPtr); + NSCAP_ASSERT_NO_QUERY_NEEDED(); + } + + nsCOMPtr( const already_AddRefed& aSmartPtr ) + : NSCAP_CTOR_BASE(aSmartPtr.mRawPtr) + // construct from |dont_AddRef(expr)| + { + NSCAP_LOG_ASSIGNMENT(this, aSmartPtr.mRawPtr); + NSCAP_ASSERT_NO_QUERY_NEEDED(); + } + + nsCOMPtr( const nsQueryInterface qi ) + : NSCAP_CTOR_BASE(0) + // construct from |do_QueryInterface(expr)| + { + NSCAP_LOG_ASSIGNMENT(this, 0); + assign_from_qi(qi, NS_GET_IID(T)); + } + + nsCOMPtr( const nsQueryInterfaceWithError& qi ) + : NSCAP_CTOR_BASE(0) + // construct from |do_QueryInterface(expr, &rv)| + { + NSCAP_LOG_ASSIGNMENT(this, 0); + assign_from_qi_with_error(qi, NS_GET_IID(T)); + } + + nsCOMPtr( const nsCOMPtr_helper& helper ) + : NSCAP_CTOR_BASE(0) + // ...and finally, anything else we might need to construct from + // can exploit the |nsCOMPtr_helper| facility + { + NSCAP_LOG_ASSIGNMENT(this, 0); + assign_from_helper(helper, NS_GET_IID(T)); + NSCAP_ASSERT_NO_QUERY_NEEDED(); + } + + + // Assignment operators + + nsCOMPtr& + operator=( const nsCOMPtr& rhs ) + // copy assignment operator + { + assign_with_AddRef(rhs.mRawPtr); + return *this; + } + + nsCOMPtr& + operator=( T* rhs ) + // assign from a raw pointer (of the right type) + { + assign_with_AddRef(rhs); + NSCAP_ASSERT_NO_QUERY_NEEDED(); + return *this; + } + + nsCOMPtr& + operator=( const already_AddRefed& rhs ) + // assign from |dont_AddRef(expr)| + { + assign_assuming_AddRef(rhs.mRawPtr); + NSCAP_ASSERT_NO_QUERY_NEEDED(); + return *this; + } + + nsCOMPtr& + operator=( const nsQueryInterface rhs ) + // assign from |do_QueryInterface(expr)| + { + assign_from_qi(rhs, NS_GET_IID(T)); + return *this; + } + + nsCOMPtr& + operator=( const nsQueryInterfaceWithError& rhs ) + // assign from |do_QueryInterface(expr, &rv)| + { + assign_from_qi_with_error(rhs, NS_GET_IID(T)); + return *this; + } + + nsCOMPtr& + operator=( const nsCOMPtr_helper& rhs ) + // ...and finally, anything else we might need to assign from + // can exploit the |nsCOMPtr_helper| facility. + { + assign_from_helper(rhs, NS_GET_IID(T)); + NSCAP_ASSERT_NO_QUERY_NEEDED(); + return *this; + } + + void + swap( nsCOMPtr& rhs ) + // ...exchange ownership with |rhs|; can save a pair of refcount operations + { +#ifdef NSCAP_FEATURE_USE_BASE + nsISupports* temp = rhs.mRawPtr; +#else + T* temp = rhs.mRawPtr; +#endif + NSCAP_LOG_ASSIGNMENT(&rhs, mRawPtr); + NSCAP_LOG_ASSIGNMENT(this, temp); + NSCAP_LOG_RELEASE(this, mRawPtr); + NSCAP_LOG_RELEASE(&rhs, temp); + rhs.mRawPtr = mRawPtr; + mRawPtr = temp; + // |rhs| maintains the same invariants, so we don't need to |NSCAP_ASSERT_NO_QUERY_NEEDED| + } + + void + swap( T*& rhs ) + // ...exchange ownership with |rhs|; can save a pair of refcount operations + { +#ifdef NSCAP_FEATURE_USE_BASE + nsISupports* temp = rhs; +#else + T* temp = rhs; +#endif + NSCAP_LOG_ASSIGNMENT(this, temp); + NSCAP_LOG_RELEASE(this, mRawPtr); + rhs = NS_REINTERPRET_CAST(T*, mRawPtr); + mRawPtr = temp; + NSCAP_ASSERT_NO_QUERY_NEEDED(); + } + + + // Other pointer operators + + nsDerivedSafe* + get() const + /* + Prefer the implicit conversion provided automatically by |operator nsDerivedSafe*() const|. + Use |get()| _only_ to resolve ambiguity. + + Returns a |nsDerivedSafe*| to deny clients the use of |AddRef| and |Release|. + */ + { + return NS_REINTERPRET_CAST(nsDerivedSafe*, mRawPtr); + } + + operator nsDerivedSafe*() const + /* + ...makes an |nsCOMPtr| act like its underlying raw pointer type (except against |AddRef()|, |Release()|, + and |delete|) whenever it is used in a context where a raw pointer is expected. It is this operator + that makes an |nsCOMPtr| substitutable for a raw pointer. + + Prefer the implicit use of this operator to calling |get()|, except where necessary to resolve ambiguity. + */ + { + return get(); + } + + nsDerivedSafe* + operator->() const + { + NS_PRECONDITION(mRawPtr != 0, "You can't dereference a NULL nsCOMPtr with operator->()."); + return get(); + } + +#ifdef CANT_RESOLVE_CPP_CONST_AMBIGUITY + // broken version for IRIX + + nsCOMPtr* + get_address() const + // This is not intended to be used by clients. See |address_of| + // below. + { + return NS_CONST_CAST(nsCOMPtr*, this); + } + +#else // CANT_RESOLVE_CPP_CONST_AMBIGUITY + + nsCOMPtr* + get_address() + // This is not intended to be used by clients. See |address_of| + // below. + { + return this; + } + + const nsCOMPtr* + get_address() const + // This is not intended to be used by clients. See |address_of| + // below. + { + return this; + } + +#endif // CANT_RESOLVE_CPP_CONST_AMBIGUITY + + public: + nsDerivedSafe& + operator*() const + { + NS_PRECONDITION(mRawPtr != 0, "You can't dereference a NULL nsCOMPtr with operator*()."); + return *get(); + } + +#if 0 + private: + friend class nsGetterAddRefs; +#endif + + T** + StartAssignment() + { +#ifndef NSCAP_FEATURE_INLINE_STARTASSIGNMENT + return NS_REINTERPRET_CAST(T**, begin_assignment()); +#else + assign_assuming_AddRef(0); + return NS_REINTERPRET_CAST(T**, &mRawPtr); +#endif + } + }; + + + + /* + Specializing |nsCOMPtr| for |nsISupports| allows us to use |nsCOMPtr| the + same way people use |nsISupports*| and |void*|, i.e., as a `catch-all' pointer pointing + to any valid [XP]COM interface. Otherwise, an |nsCOMPtr| would only be able + to point to the single [XP]COM-correct |nsISupports| instance within an object; extra + querying ensues. Clients need to be able to pass around arbitrary interface pointers, + without hassles, through intermediary code that doesn't know the exact type. + */ + +NS_SPECIALIZE_TEMPLATE +class nsCOMPtr + : private nsCOMPtr_base + { + public: + typedef nsISupports element_type; + + // Constructors + + nsCOMPtr() + : nsCOMPtr_base(0) + // default constructor + { + NSCAP_LOG_ASSIGNMENT(this, 0); + } + + nsCOMPtr( const nsCOMPtr& aSmartPtr ) + : nsCOMPtr_base(aSmartPtr.mRawPtr) + // copy constructor + { + if ( mRawPtr ) + NSCAP_ADDREF(this, mRawPtr); + NSCAP_LOG_ASSIGNMENT(this, aSmartPtr.mRawPtr); + } + + nsCOMPtr( nsISupports* aRawPtr ) + : nsCOMPtr_base(aRawPtr) + // construct from a raw pointer (of the right type) + { + if ( mRawPtr ) + NSCAP_ADDREF(this, mRawPtr); + NSCAP_LOG_ASSIGNMENT(this, aRawPtr); + } + + nsCOMPtr( const already_AddRefed& aSmartPtr ) + : nsCOMPtr_base(aSmartPtr.mRawPtr) + // construct from |dont_AddRef(expr)| + { + NSCAP_LOG_ASSIGNMENT(this, aSmartPtr.mRawPtr); + } + + nsCOMPtr( const nsQueryInterface qi ) + : nsCOMPtr_base(0) + // assign from |do_QueryInterface(expr)| + { + NSCAP_LOG_ASSIGNMENT(this, 0); + assign_from_qi(qi, NS_GET_IID(nsISupports)); + } + + nsCOMPtr( const nsQueryInterfaceWithError& qi ) + : nsCOMPtr_base(0) + // assign from |do_QueryInterface(expr, &rv)| + { + NSCAP_LOG_ASSIGNMENT(this, 0); + assign_from_qi_with_error(qi, NS_GET_IID(nsISupports)); + } + + nsCOMPtr( const nsCOMPtr_helper& helper ) + : nsCOMPtr_base(0) + // ...and finally, anything else we might need to construct from + // can exploit the |nsCOMPtr_helper| facility + { + NSCAP_LOG_ASSIGNMENT(this, 0); + assign_from_helper(helper, NS_GET_IID(nsISupports)); + } + + + // Assignment operators + + nsCOMPtr& + operator=( const nsCOMPtr& rhs ) + // copy assignment operator + { + assign_with_AddRef(rhs.mRawPtr); + return *this; + } + + nsCOMPtr& + operator=( nsISupports* rhs ) + // assign from a raw pointer (of the right type) + { + assign_with_AddRef(rhs); + return *this; + } + + nsCOMPtr& + operator=( const already_AddRefed& rhs ) + // assign from |dont_AddRef(expr)| + { + assign_assuming_AddRef(rhs.mRawPtr); + return *this; + } + + nsCOMPtr& + operator=( const nsQueryInterface rhs ) + // assign from |do_QueryInterface(expr)| + { + assign_from_qi(rhs, NS_GET_IID(nsISupports)); + return *this; + } + + nsCOMPtr& + operator=( const nsQueryInterfaceWithError& rhs ) + // assign from |do_QueryInterface(expr, &rv)| + { + assign_from_qi_with_error(rhs, NS_GET_IID(nsISupports)); + return *this; + } + + nsCOMPtr& + operator=( const nsCOMPtr_helper& rhs ) + // ...and finally, anything else we might need to assign from + // can exploit the |nsCOMPtr_helper| facility. + { + assign_from_helper(rhs, NS_GET_IID(nsISupports)); + return *this; + } + + void + swap( nsCOMPtr& rhs ) + // ...exchange ownership with |rhs|; can save a pair of refcount operations + { + nsISupports* temp = rhs.mRawPtr; + NSCAP_LOG_ASSIGNMENT(&rhs, mRawPtr); + NSCAP_LOG_ASSIGNMENT(this, temp); + NSCAP_LOG_RELEASE(this, mRawPtr); + NSCAP_LOG_RELEASE(&rhs, temp); + rhs.mRawPtr = mRawPtr; + mRawPtr = temp; + } + + void + swap( nsISupports*& rhs ) + // ...exchange ownership with |rhs|; can save a pair of refcount operations + { + nsISupports* temp = rhs; + NSCAP_LOG_ASSIGNMENT(this, temp); + NSCAP_LOG_RELEASE(this, mRawPtr); + rhs = mRawPtr; + mRawPtr = temp; + } + + + // Other pointer operators + + nsDerivedSafe* + get() const + /* + Prefer the implicit conversion provided automatically by |operator nsDerivedSafe*() const|. + Use |get()| _only_ to resolve ambiguity. + + Returns a |nsDerivedSafe*| to deny clients the use of |AddRef| and |Release|. + */ + { + return NS_REINTERPRET_CAST(nsDerivedSafe*, mRawPtr); + } + + operator nsDerivedSafe*() const + /* + ...makes an |nsCOMPtr| act like its underlying raw pointer type (except against |AddRef()|, |Release()|, + and |delete|) whenever it is used in a context where a raw pointer is expected. It is this operator + that makes an |nsCOMPtr| substitutable for a raw pointer. + + Prefer the implicit use of this operator to calling |get()|, except where necessary to resolve ambiguity. + */ + { + return get(); + } + + nsDerivedSafe* + operator->() const + { + NS_PRECONDITION(mRawPtr != 0, "You can't dereference a NULL nsCOMPtr with operator->()."); + return get(); + } + +#ifdef CANT_RESOLVE_CPP_CONST_AMBIGUITY + // broken version for IRIX + + nsCOMPtr* + get_address() const + // This is not intended to be used by clients. See |address_of| + // below. + { + return NS_CONST_CAST(nsCOMPtr*, this); + } + +#else // CANT_RESOLVE_CPP_CONST_AMBIGUITY + + nsCOMPtr* + get_address() + // This is not intended to be used by clients. See |address_of| + // below. + { + return this; + } + + const nsCOMPtr* + get_address() const + // This is not intended to be used by clients. See |address_of| + // below. + { + return this; + } + +#endif // CANT_RESOLVE_CPP_CONST_AMBIGUITY + + public: + + nsDerivedSafe& + operator*() const + { + NS_PRECONDITION(mRawPtr != 0, "You can't dereference a NULL nsCOMPtr with operator*()."); + return *get(); + } + +#if 0 + private: + friend class nsGetterAddRefs; +#endif + + nsISupports** + StartAssignment() + { +#ifndef NSCAP_FEATURE_INLINE_STARTASSIGNMENT + return NS_REINTERPRET_CAST(nsISupports**, begin_assignment()); +#else + assign_assuming_AddRef(0); + return NS_REINTERPRET_CAST(nsISupports**, &mRawPtr); +#endif + } + }; + +#ifndef NSCAP_FEATURE_USE_BASE +template +void +nsCOMPtr::assign_with_AddRef( nsISupports* rawPtr ) + { + if ( rawPtr ) + NSCAP_ADDREF(this, rawPtr); + assign_assuming_AddRef(NS_REINTERPRET_CAST(T*, rawPtr)); + } + +template +void +nsCOMPtr::assign_from_qi( const nsQueryInterface qi, const nsIID& aIID ) + { + T* newRawPtr; + if ( NS_FAILED( qi(aIID, NS_REINTERPRET_CAST(void**, &newRawPtr)) ) ) + newRawPtr = 0; + assign_assuming_AddRef(newRawPtr); + } + +template +void +nsCOMPtr::assign_from_qi_with_error( const nsQueryInterfaceWithError& qi, const nsIID& aIID ) + { + T* newRawPtr; + if ( NS_FAILED( qi(aIID, NS_REINTERPRET_CAST(void**, &newRawPtr)) ) ) + newRawPtr = 0; + assign_assuming_AddRef(newRawPtr); + } + +template +void +nsCOMPtr::assign_from_helper( const nsCOMPtr_helper& helper, const nsIID& aIID ) + { + T* newRawPtr; + if ( NS_FAILED( helper(aIID, NS_REINTERPRET_CAST(void**, &newRawPtr)) ) ) + newRawPtr = 0; + assign_assuming_AddRef(newRawPtr); + } + +template +void** +nsCOMPtr::begin_assignment() + { + assign_assuming_AddRef(0); + return NS_REINTERPRET_CAST(void**, &mRawPtr); + } +#endif + +#ifdef CANT_RESOLVE_CPP_CONST_AMBIGUITY + +// This is the broken version for IRIX, which can't handle the version below. + +template +inline +nsCOMPtr* +address_of( const nsCOMPtr& aPtr ) + { + return aPtr.get_address(); + } + +#else // CANT_RESOLVE_CPP_CONST_AMBIGUITY + +template +inline +nsCOMPtr* +address_of( nsCOMPtr& aPtr ) + { + return aPtr.get_address(); + } + +template +inline +const nsCOMPtr* +address_of( const nsCOMPtr& aPtr ) + { + return aPtr.get_address(); + } + +#endif // CANT_RESOLVE_CPP_CONST_AMBIGUITY + +template +class nsGetterAddRefs + /* + ... + + This class is designed to be used for anonymous temporary objects in the + argument list of calls that return COM interface pointers, e.g., + + nsCOMPtr fooP; + ...->QueryInterface(iid, getter_AddRefs(fooP)) + + DO NOT USE THIS TYPE DIRECTLY IN YOUR CODE. Use |getter_AddRefs()| instead. + + When initialized with a |nsCOMPtr|, as in the example above, it returns + a |void**|, a |T**|, or an |nsISupports**| as needed, that the outer call (|QueryInterface| in this + case) can fill in. + + This type should be a nested class inside |nsCOMPtr|. + */ + { + public: + explicit + nsGetterAddRefs( nsCOMPtr& aSmartPtr ) + : mTargetSmartPtr(aSmartPtr) + { + // nothing else to do + } + +#if defined(NSCAP_FEATURE_TEST_DONTQUERY_CASES) || defined(NSCAP_LOG_EXTERNAL_ASSIGNMENT) + ~nsGetterAddRefs() + { +#ifdef NSCAP_LOG_EXTERNAL_ASSIGNMENT + NSCAP_LOG_ASSIGNMENT(NS_REINTERPRET_CAST(void *, address_of(mTargetSmartPtr)), mTargetSmartPtr.get()); +#endif + +#ifdef NSCAP_FEATURE_TEST_DONTQUERY_CASES + mTargetSmartPtr.Assert_NoQueryNeeded(); +#endif + } +#endif + + operator void**() + { + return NS_REINTERPRET_CAST(void**, mTargetSmartPtr.StartAssignment()); + } + + operator nsISupports**() + { + return NS_REINTERPRET_CAST(nsISupports**, mTargetSmartPtr.StartAssignment()); + } + + operator T**() + { + return mTargetSmartPtr.StartAssignment(); + } + + T*& + operator*() + { + return *(mTargetSmartPtr.StartAssignment()); + } + + private: + nsCOMPtr& mTargetSmartPtr; + }; + + +NS_SPECIALIZE_TEMPLATE +class nsGetterAddRefs + { + public: + explicit + nsGetterAddRefs( nsCOMPtr& aSmartPtr ) + : mTargetSmartPtr(aSmartPtr) + { + // nothing else to do + } + +#ifdef NSCAP_LOG_EXTERNAL_ASSIGNMENT + ~nsGetterAddRefs() + { + NSCAP_LOG_ASSIGNMENT(NS_REINTERPRET_CAST(void *, address_of(mTargetSmartPtr)), mTargetSmartPtr.get()); + } +#endif + + operator void**() + { + return NS_REINTERPRET_CAST(void**, mTargetSmartPtr.StartAssignment()); + } + + operator nsISupports**() + { + return mTargetSmartPtr.StartAssignment(); + } + + nsISupports*& + operator*() + { + return *(mTargetSmartPtr.StartAssignment()); + } + + private: + nsCOMPtr& mTargetSmartPtr; + }; + + +template +inline +nsGetterAddRefs +getter_AddRefs( nsCOMPtr& aSmartPtr ) + /* + Used around a |nsCOMPtr| when + ...makes the class |nsGetterAddRefs| invisible. + */ + { + return nsGetterAddRefs(aSmartPtr); + } + + + + // Comparing two |nsCOMPtr|s + +template +inline +NSCAP_BOOL +operator==( const nsCOMPtr& lhs, const nsCOMPtr& rhs ) + { + return NS_STATIC_CAST(const T*, lhs.get()) == NS_STATIC_CAST(const U*, rhs.get()); + } + + +template +inline +NSCAP_BOOL +operator!=( const nsCOMPtr& lhs, const nsCOMPtr& rhs ) + { + return NS_STATIC_CAST(const T*, lhs.get()) != NS_STATIC_CAST(const U*, rhs.get()); + } + + + // Comparing an |nsCOMPtr| to a raw pointer + +template +inline +NSCAP_BOOL +operator==( const nsCOMPtr& lhs, const U* rhs ) + { + return NS_STATIC_CAST(const T*, lhs.get()) == rhs; + } + +template +inline +NSCAP_BOOL +operator==( const U* lhs, const nsCOMPtr& rhs ) + { + return lhs == NS_STATIC_CAST(const T*, rhs.get()); + } + +template +inline +NSCAP_BOOL +operator!=( const nsCOMPtr& lhs, const U* rhs ) + { + return NS_STATIC_CAST(const T*, lhs.get()) != rhs; + } + +template +inline +NSCAP_BOOL +operator!=( const U* lhs, const nsCOMPtr& rhs ) + { + return lhs != NS_STATIC_CAST(const T*, rhs.get()); + } + + // To avoid ambiguities caused by the presence of builtin |operator==|s + // creating a situation where one of the |operator==| defined above + // has a better conversion for one argument and the builtin has a + // better conversion for the other argument, define additional + // |operator==| without the |const| on the raw pointer. + // See bug 65664 for details. + +// This is defined by an autoconf test, but VC++ also has a bug that +// prevents us from using these. (It also, fortunately, has the bug +// that we don't need them either.) +#if defined(_MSC_VER) && (_MSC_VER < 1310) +#define NSCAP_DONT_PROVIDE_NONCONST_OPEQ +#endif + +#ifndef NSCAP_DONT_PROVIDE_NONCONST_OPEQ +template +inline +NSCAP_BOOL +operator==( const nsCOMPtr& lhs, U* rhs ) + { + return NS_STATIC_CAST(const T*, lhs.get()) == NS_CONST_CAST(const U*, rhs); + } + +template +inline +NSCAP_BOOL +operator==( U* lhs, const nsCOMPtr& rhs ) + { + return NS_CONST_CAST(const U*, lhs) == NS_STATIC_CAST(const T*, rhs.get()); + } + +template +inline +NSCAP_BOOL +operator!=( const nsCOMPtr& lhs, U* rhs ) + { + return NS_STATIC_CAST(const T*, lhs.get()) != NS_CONST_CAST(const U*, rhs); + } + +template +inline +NSCAP_BOOL +operator!=( U* lhs, const nsCOMPtr& rhs ) + { + return NS_CONST_CAST(const U*, lhs) != NS_STATIC_CAST(const T*, rhs.get()); + } +#endif + + + + // Comparing an |nsCOMPtr| to |0| + +class NSCAP_Zero; + +template +inline +NSCAP_BOOL +operator==( const nsCOMPtr& lhs, NSCAP_Zero* rhs ) + // specifically to allow |smartPtr == 0| + { + return NS_STATIC_CAST(const void*, lhs.get()) == NS_REINTERPRET_CAST(const void*, rhs); + } + +template +inline +NSCAP_BOOL +operator==( NSCAP_Zero* lhs, const nsCOMPtr& rhs ) + // specifically to allow |0 == smartPtr| + { + return NS_REINTERPRET_CAST(const void*, lhs) == NS_STATIC_CAST(const void*, rhs.get()); + } + +template +inline +NSCAP_BOOL +operator!=( const nsCOMPtr& lhs, NSCAP_Zero* rhs ) + // specifically to allow |smartPtr != 0| + { + return NS_STATIC_CAST(const void*, lhs.get()) != NS_REINTERPRET_CAST(const void*, rhs); + } + +template +inline +NSCAP_BOOL +operator!=( NSCAP_Zero* lhs, const nsCOMPtr& rhs ) + // specifically to allow |0 != smartPtr| + { + return NS_REINTERPRET_CAST(const void*, lhs) != NS_STATIC_CAST(const void*, rhs.get()); + } + + +#ifdef HAVE_CPP_TROUBLE_COMPARING_TO_ZERO + + // We need to explicitly define comparison operators for `int' + // because the compiler is lame. + +template +inline +NSCAP_BOOL +operator==( const nsCOMPtr& lhs, int rhs ) + // specifically to allow |smartPtr == 0| + { + return NS_STATIC_CAST(const void*, lhs.get()) == NS_REINTERPRET_CAST(const void*, rhs); + } + +template +inline +NSCAP_BOOL +operator==( int lhs, const nsCOMPtr& rhs ) + // specifically to allow |0 == smartPtr| + { + return NS_REINTERPRET_CAST(const void*, lhs) == NS_STATIC_CAST(const void*, rhs.get()); + } + +#endif // !defined(HAVE_CPP_TROUBLE_COMPARING_TO_ZERO) + + // Comparing any two [XP]COM objects for identity + +inline +NSCAP_BOOL +SameCOMIdentity( nsISupports* lhs, nsISupports* rhs ) + { + return nsCOMPtr( do_QueryInterface(lhs) ) == nsCOMPtr( do_QueryInterface(rhs) ); + } + + + +template +inline +nsresult +CallQueryInterface( nsCOMPtr& aSourcePtr, DestinationType** aDestPtr ) + { + return CallQueryInterface(aSourcePtr.get(), aDestPtr); + } + +#endif // !defined(nsCOMPtr_h___) diff --git a/src/libs/xpcom18a4/xpcom/glue/nsComponentManagerUtils.cpp b/src/libs/xpcom18a4/xpcom/glue/nsComponentManagerUtils.cpp new file mode 100644 index 00000000..5733fc36 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/glue/nsComponentManagerUtils.cpp @@ -0,0 +1,133 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +#ifndef nsXPCOM_h__ +#include "nsXPCOM.h" +#endif + +#ifndef nsCOMPtr_h__ +#include "nsCOMPtr.h" +#endif + +#include "nsComponentManagerUtils.h" +#include "nsIServiceManagerUtils.h" + +nsresult +nsCreateInstanceByCID::operator()( const nsIID& aIID, void** aInstancePtr ) const +{ + nsCOMPtr compMgr; + nsresult status = NS_GetComponentManager(getter_AddRefs(compMgr)); + if (compMgr) + status = compMgr->CreateInstance(mCID, mOuter, aIID, aInstancePtr); + else if (NS_SUCCEEDED(status)) + status = NS_ERROR_UNEXPECTED; + + if ( NS_FAILED(status) ) + *aInstancePtr = 0; + + if ( mErrorPtr ) + *mErrorPtr = status; + return status; +} + +nsresult +nsCreateInstanceByContractID::operator()( const nsIID& aIID, void** aInstancePtr ) const +{ + nsresult status; + if ( mContractID ) { + nsCOMPtr compMgr; + status = NS_GetComponentManager(getter_AddRefs(compMgr)); + if (compMgr) + status = compMgr->CreateInstanceByContractID(mContractID, mOuter, + aIID, aInstancePtr); + else if (NS_SUCCEEDED(status)) + status = NS_ERROR_UNEXPECTED; + } + else + status = NS_ERROR_NULL_POINTER; + + if (NS_FAILED(status)) + *aInstancePtr = 0; + if ( mErrorPtr ) + *mErrorPtr = status; + return status; +} + + +nsresult +nsGetServiceByCID::operator()( const nsIID& aIID, void** aInstancePtr ) const +{ + nsresult status = NS_ERROR_FAILURE; + if ( mServiceManager ) { + status = mServiceManager->GetService(mCID, aIID, (void**)aInstancePtr); + } else { + nsCOMPtr mgr; + NS_GetServiceManager(getter_AddRefs(mgr)); + if (mgr) + status = mgr->GetService(mCID, aIID, (void**)aInstancePtr); + } + if ( NS_FAILED(status) ) + *aInstancePtr = 0; + + if ( mErrorPtr ) + *mErrorPtr = status; + return status; +} + +nsresult +nsGetServiceByContractID::operator()( const nsIID& aIID, void** aInstancePtr ) const +{ + nsresult status = NS_ERROR_FAILURE; + if ( mServiceManager ) { + status = mServiceManager->GetServiceByContractID(mContractID, aIID, (void**)aInstancePtr); + } else { + nsCOMPtr mgr; + NS_GetServiceManager(getter_AddRefs(mgr)); + if (mgr) + status = mgr->GetServiceByContractID(mContractID, aIID, (void**)aInstancePtr); + } + + if ( NS_FAILED(status) ) + *aInstancePtr = 0; + + if ( mErrorPtr ) + *mErrorPtr = status; + return status; +} + + + diff --git a/src/libs/xpcom18a4/xpcom/glue/nsDebug.cpp b/src/libs/xpcom18a4/xpcom/glue/nsDebug.cpp new file mode 100644 index 00000000..9e947f30 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/glue/nsDebug.cpp @@ -0,0 +1,119 @@ +/* ***** 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 XPCOM + * + * The Initial Developer of the Original Code is Doug Turner + * + * Portions created by the Initial Developer are Copyright (C) 2003 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * 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 "nsXPCOM.h" +#include "nsXPCOMPrivate.h" +#include "nsCOMPtr.h" +#include "nsIServiceManager.h" +#include "nsDebug.h" +#include "nsDebugImpl.h" + +static nsIDebug* gDebugObject = nsnull; + +// Note: Although the machinery here is similar to nsMemory.cpp, we cannot use +// NS_ASSERTION macros below because they end up in nsDebug::Assertion and +// therefore may produce endless recursion. + +static NS_METHOD FreeDebugObject(void) +{ + NS_IF_RELEASE(gDebugObject); + return NS_OK; +} + +#define ENSURE_DEBUGOBJECT \ + (gDebugObject ? PR_TRUE : (PRBool)(SetupDebugObject() != nsnull)) + +static nsIDebug* SetupDebugObject() +{ + if (!gDebugObject) + { + NS_GetDebug(&gDebugObject); + if (gDebugObject) + NS_RegisterXPCOMExitRoutine(FreeDebugObject, 0); + } + return gDebugObject; +} + +#ifdef XPCOM_GLUE +nsresult GlueStartupDebug() +{ + if (!gDebugObject) + { + NS_GetDebug(&gDebugObject); + if (!gDebugObject) + return NS_ERROR_FAILURE; + } + return NS_OK; +} + +void GlueShutdownDebug() +{ + NS_IF_RELEASE(gDebugObject); +} +#endif + +NS_COM void nsDebug::Abort(const char* aFile, PRIntn aLine) +{ + if (!ENSURE_DEBUGOBJECT) + return; + + gDebugObject->Abort(aFile, aLine); +} + +NS_COM void nsDebug::Break(const char* aFile, PRIntn aLine) +{ + if (!ENSURE_DEBUGOBJECT) + return; + + gDebugObject->Break(aFile, aLine); +} + +NS_COM void nsDebug::Warning(const char* aStr, + const char* aFile, + PRIntn aLine) +{ + if (!ENSURE_DEBUGOBJECT) + return; + gDebugObject->Warning(aStr, aFile, aLine); +} + +NS_COM void nsDebug::Assertion(const char* aStr, const char* aExpr, + const char* aFile, PRIntn aLine) +{ + if (!ENSURE_DEBUGOBJECT) + return; + gDebugObject->Assertion(aStr, aExpr, aFile, aLine); +} diff --git a/src/libs/xpcom18a4/xpcom/glue/nsDebug.h b/src/libs/xpcom18a4/xpcom/glue/nsDebug.h new file mode 100644 index 00000000..f2ed4c56 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/glue/nsDebug.h @@ -0,0 +1,276 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +#ifndef nsDebug_h___ +#define nsDebug_h___ + +#ifndef nscore_h___ +#include "nscore.h" +#endif + +#ifndef nsError_h__ +#include "nsError.h" +#endif + +#ifdef DEBUG +#define NS_DEBUG +#endif + +/** + * Namespace for debugging methods. Note that your code must use the + * macros defined later in this file so that the debug code can be + * conditionally compiled out. + */ + +/* in case this is included by a C file */ +#ifdef __cplusplus + +class nsDebug { +public: + + /** + * Log a warning message to the debug log. + */ + static NS_COM void Warning(const char* aMessage, + const char* aFile, PRIntn aLine); + + /** + * Abort the executing program. This works on all architectures. + */ + static NS_COM void Abort(const char* aFile, PRIntn aLine); + + /** + * Break the executing program into the debugger. + */ + static NS_COM void Break(const char* aFile, PRIntn aLine); + + /** + * Log an assertion message to the debug log + */ + static NS_COM void Assertion(const char* aStr, const char* aExpr, + const char* aFile, PRIntn aLine); +}; + +#ifdef DEBUG + +/** + * Abort the execution of the program if the expression evaluates to + * false. + * + * There is no status value returned from the macro. + * + * Note that the non-debug version of this macro does not + * evaluate the expression argument. Hence side effect statements + * as arguments to the macro will yield improper execution in a + * non-debug build. For example: + * + * NS_ABORT_IF_FALSE(0 == foo++, "yikes foo should be zero"); + * + * Note also that the non-debug version of this macro does not + * evaluate the message argument. + */ +#define NS_ABORT_IF_FALSE(_expr, _msg) \ + PR_BEGIN_MACRO \ + if (!(_expr)) { \ + nsDebug::Assertion(_msg, #_expr, __FILE__, __LINE__); \ + } \ + PR_END_MACRO + +/** + * Warn if a given condition is false. + * + * Program execution continues past the usage of this macro. + * + * Note also that the non-debug version of this macro does not + * evaluate the message argument. + */ +#define NS_WARN_IF_FALSE(_expr,_msg) \ + PR_BEGIN_MACRO \ + if (!(_expr)) { \ + nsDebug::Assertion(_msg, #_expr, __FILE__, __LINE__); \ + } \ + PR_END_MACRO + +/** + * Test a precondition for truth. If the expression is not true then + * trigger a program failure. + */ +#define NS_PRECONDITION(expr, str) \ + PR_BEGIN_MACRO \ + if (!(expr)) { \ + nsDebug::Assertion(str, #expr, __FILE__, __LINE__); \ + } \ + PR_END_MACRO + +/** + * Test an assertion for truth. If the expression is not true then + * trigger a program failure. + */ +#define NS_ASSERTION(expr, str) \ + PR_BEGIN_MACRO \ + if (!(expr)) { \ + nsDebug::Assertion(str, #expr, __FILE__, __LINE__); \ + } \ + PR_END_MACRO + +/** + * Test a post-condition for truth. If the expression is not true then + * trigger a program failure. + */ +#define NS_POSTCONDITION(expr, str) \ + PR_BEGIN_MACRO \ + if (!(expr)) { \ + nsDebug::Assertion(str, #expr, __FILE__, __LINE__); \ + } \ + PR_END_MACRO + +/** + * This macros triggers a program failure if executed. It indicates that + * an attempt was made to execute some unimplimented functionality. + */ +#define NS_NOTYETIMPLEMENTED(str) \ + nsDebug::Assertion(str, "NotYetImplemented", __FILE__, __LINE__) + +/** + * This macros triggers a program failure if executed. It indicates that + * an attempt was made to execute some unimplimented functionality. + */ +#define NS_NOTREACHED(str) \ + nsDebug::Assertion(str, "Not Reached", __FILE__, __LINE__) + +/** + * Log an error message. + */ +#define NS_ERROR(str) \ + nsDebug::Assertion(str, "Error", __FILE__, __LINE__) + +/** + * Log a warning message. + */ +#define NS_WARNING(str) \ + nsDebug::Warning(str, __FILE__, __LINE__) + +/** + * Trigger an abort + */ +#define NS_ABORT() \ + nsDebug::Abort(__FILE__, __LINE__) + +/** + * Cause a break + */ +#define NS_BREAK() \ + nsDebug::Break(__FILE__, __LINE__) + +#else /* NS_DEBUG */ + +/** + * The non-debug version of these macros do not evaluate the + * expression or the message arguments to the macro. + */ +#define NS_ABORT_IF_FALSE(_expr, _msg) /* nothing */ +#define NS_WARN_IF_FALSE(_expr, _msg) /* nothing */ +#define NS_PRECONDITION(expr, str) /* nothing */ +#define NS_ASSERTION(expr, str) /* nothing */ +#define NS_POSTCONDITION(expr, str) /* nothing */ +#define NS_NOTYETIMPLEMENTED(str) /* nothing */ +#define NS_NOTREACHED(str) /* nothing */ +#define NS_ERROR(str) /* nothing */ +#define NS_WARNING(str) /* nothing */ +#define NS_ABORT() /* nothing */ +#define NS_BREAK() /* nothing */ + +#endif /* ! NS_DEBUG */ +#endif /* __cplusplus */ + +// Macros for checking the trueness of an expression passed in within an +// interface implementation. These need to be compiled regardless of the +// NS_DEBUG flag +/////////////////////////////////////////////////////////////////////////////// + +#define NS_ENSURE_TRUE(x, ret) \ + PR_BEGIN_MACRO \ + if (NS_UNLIKELY(!(x))) { \ + NS_WARNING("NS_ENSURE_TRUE(" #x ") failed"); \ + return ret; \ + } \ + PR_END_MACRO + +#define NS_ENSURE_FALSE(x, ret) \ + NS_ENSURE_TRUE(!(x), ret) + +/////////////////////////////////////////////////////////////////////////////// +// Macros for checking results +/////////////////////////////////////////////////////////////////////////////// + +#define NS_ENSURE_SUCCESS(res, ret) \ + NS_ENSURE_TRUE(NS_SUCCEEDED(res), ret) + +/////////////////////////////////////////////////////////////////////////////// +// Macros for checking state and arguments upon entering interface boundaries +/////////////////////////////////////////////////////////////////////////////// + +#define NS_ENSURE_ARG(arg) \ + NS_ENSURE_TRUE(arg, NS_ERROR_INVALID_ARG) + +#define NS_ENSURE_ARG_POINTER(arg) \ + NS_ENSURE_TRUE(arg, NS_ERROR_INVALID_POINTER) + +#define NS_ENSURE_ARG_MIN(arg, min) \ + NS_ENSURE_TRUE((arg) >= min, NS_ERROR_INVALID_ARG) + +#define NS_ENSURE_ARG_MAX(arg, max) \ + NS_ENSURE_TRUE((arg) <= max, NS_ERROR_INVALID_ARG) + +#define NS_ENSURE_ARG_RANGE(arg, min, max) \ + NS_ENSURE_TRUE(((arg) >= min) && ((arg) <= max), NS_ERROR_INVALID_ARG) + +#define NS_ENSURE_STATE(state) \ + NS_ENSURE_TRUE(state, NS_ERROR_UNEXPECTED) + +#define NS_ENSURE_NO_AGGREGATION(outer) \ + NS_ENSURE_FALSE(outer, NS_ERROR_NO_AGGREGATION) + +#define NS_ENSURE_PROPER_AGGREGATION(outer, iid) \ + NS_ENSURE_FALSE(outer && !iid.Equals(NS_GET_IID(nsISupports)), NS_ERROR_INVALID_ARG) + +/////////////////////////////////////////////////////////////////////////////// + +#define NS_CheckThreadSafe(owningThread, msg) \ + NS_ASSERTION(owningThread == PR_GetCurrentThread(), msg) + +#endif /* nsDebug_h___ */ diff --git a/src/libs/xpcom18a4/xpcom/glue/nsGenericFactory.cpp b/src/libs/xpcom18a4/xpcom/glue/nsGenericFactory.cpp new file mode 100644 index 00000000..2d791943 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/glue/nsGenericFactory.cpp @@ -0,0 +1,547 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Pierre Phaneuf + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + + +// DO NOT COPY THIS CODE INTO YOUR SOURCE! USE NS_IMPL_NSGETMODULE() + +#include "nsGenericFactory.h" +#include "nsMemory.h" +#include "nsCOMPtr.h" +#include "nsIComponentManager.h" +#include "nsIComponentRegistrar.h" + +#ifdef XPCOM_GLUE +#include "nsXPCOMGlue.h" +#include "nsXPCOMPrivate.h" +#else +#include "nsIInterfaceRequestorUtils.h" +#include "nsINativeComponentLoader.h" +#endif + +nsGenericFactory::nsGenericFactory(const nsModuleComponentInfo *info) + : mInfo(info) +{ + if (mInfo && mInfo->mClassInfoGlobal) + *mInfo->mClassInfoGlobal = NS_STATIC_CAST(nsIClassInfo *, this); +} + +nsGenericFactory::~nsGenericFactory() +{ + if (mInfo) { + if (mInfo->mFactoryDestructor) + mInfo->mFactoryDestructor(); + if (mInfo->mClassInfoGlobal) + *mInfo->mClassInfoGlobal = 0; + } +} + +NS_IMPL_THREADSAFE_ISUPPORTS3(nsGenericFactory, + nsIGenericFactory, + nsIFactory, + nsIClassInfo) + +NS_IMETHODIMP nsGenericFactory::CreateInstance(nsISupports *aOuter, + REFNSIID aIID, void **aResult) +{ + if (mInfo->mConstructor) { + return mInfo->mConstructor(aOuter, aIID, aResult); + } + + return NS_ERROR_FACTORY_NOT_REGISTERED; +} + +NS_IMETHODIMP nsGenericFactory::LockFactory(PRBool aLock) +{ + // XXX do we care if (mInfo->mFlags & THREADSAFE)? + return NS_OK; +} + +NS_IMETHODIMP nsGenericFactory::GetInterfaces(PRUint32 *countp, + nsIID* **array) +{ + if (!mInfo->mGetInterfacesProc) { + *countp = 0; + *array = nsnull; + return NS_OK; + } + return mInfo->mGetInterfacesProc(countp, array); +} + +NS_IMETHODIMP nsGenericFactory::GetHelperForLanguage(PRUint32 language, + nsISupports **helper) +{ + if (mInfo->mGetLanguageHelperProc) + return mInfo->mGetLanguageHelperProc(language, helper); + *helper = nsnull; + return NS_OK; +} + +NS_IMETHODIMP nsGenericFactory::GetContractID(char **aContractID) +{ + if (mInfo->mContractID) { + *aContractID = (char *)nsMemory::Alloc(strlen(mInfo->mContractID) + 1); + if (!*aContractID) + return NS_ERROR_OUT_OF_MEMORY; + strcpy(*aContractID, mInfo->mContractID); + } else { + *aContractID = nsnull; + } + return NS_OK; +} + +NS_IMETHODIMP nsGenericFactory::GetClassDescription(char * *aClassDescription) +{ + if (mInfo->mDescription) { + *aClassDescription = (char *) + nsMemory::Alloc(strlen(mInfo->mDescription) + 1); + if (!*aClassDescription) + return NS_ERROR_OUT_OF_MEMORY; + strcpy(*aClassDescription, mInfo->mDescription); + } else { + *aClassDescription = nsnull; + } + return NS_OK; +} + +NS_IMETHODIMP nsGenericFactory::GetClassID(nsCID * *aClassID) +{ + *aClassID = + NS_REINTERPRET_CAST(nsCID*, + nsMemory::Clone(&mInfo->mCID, sizeof mInfo->mCID)); + if (! *aClassID) + return NS_ERROR_OUT_OF_MEMORY; + return NS_OK; +} + +NS_IMETHODIMP nsGenericFactory::GetClassIDNoAlloc(nsCID *aClassID) +{ + *aClassID = mInfo->mCID; + return NS_OK; +} + +NS_IMETHODIMP nsGenericFactory::GetImplementationLanguage(PRUint32 *langp) +{ + *langp = nsIProgrammingLanguage::CPLUSPLUS; + return NS_OK; +} + +NS_IMETHODIMP nsGenericFactory::GetFlags(PRUint32 *flagsp) +{ + *flagsp = mInfo->mFlags; + return NS_OK; +} + +// nsIGenericFactory: component-info accessors +NS_IMETHODIMP nsGenericFactory::SetComponentInfo(const nsModuleComponentInfo *info) +{ + if (mInfo && mInfo->mClassInfoGlobal) + *mInfo->mClassInfoGlobal = 0; + mInfo = info; + if (mInfo && mInfo->mClassInfoGlobal) + *mInfo->mClassInfoGlobal = NS_STATIC_CAST(nsIClassInfo *, this); + return NS_OK; +} + +NS_IMETHODIMP nsGenericFactory::GetComponentInfo(const nsModuleComponentInfo **infop) +{ + *infop = mInfo; + return NS_OK; +} + +NS_METHOD nsGenericFactory::Create(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr) +{ + // sorry, aggregation not spoken here. + nsresult res = NS_ERROR_NO_AGGREGATION; + if (outer == NULL) { + nsGenericFactory* factory = new nsGenericFactory; + if (factory != NULL) { + res = factory->QueryInterface(aIID, aInstancePtr); + if (res != NS_OK) + delete factory; + } else { + res = NS_ERROR_OUT_OF_MEMORY; + } + } + return res; +} + +NS_COM nsresult +NS_NewGenericFactory(nsIGenericFactory* *result, + const nsModuleComponentInfo *info) +{ + nsresult rv; + nsIGenericFactory* fact; + rv = nsGenericFactory::Create(NULL, NS_GET_IID(nsIGenericFactory), (void**)&fact); + if (NS_FAILED(rv)) return rv; + rv = fact->SetComponentInfo(info); + if (NS_FAILED(rv)) goto error; + *result = fact; + return rv; + + error: + NS_RELEASE(fact); + return rv; +} + +//////////////////////////////////////////////////////////////////////////////// + +nsGenericModule::nsGenericModule(const char* moduleName, PRUint32 componentCount, + const nsModuleComponentInfo* components, + nsModuleConstructorProc ctor, + nsModuleDestructorProc dtor, + const char** aLibDepends) + : mInitialized(PR_FALSE), + mModuleName(moduleName), + mComponentCount(componentCount), + mComponents(components), + mFactoriesNotToBeRegistered(nsnull), + mCtor(ctor), + mDtor(dtor), + mLibraryDependencies(aLibDepends) +{ +} + +nsGenericModule::~nsGenericModule() +{ + Shutdown(); + +#ifdef XPCOM_GLUE + XPCOMGlueShutdown(); +#endif + +} + +NS_IMPL_THREADSAFE_ISUPPORTS1(nsGenericModule, nsIModule) + +nsresult +nsGenericModule::AddFactoryNode(nsIGenericFactory* fact) +{ + if (!fact) + return NS_ERROR_FAILURE; + + FactoryNode *node = new FactoryNode(fact, mFactoriesNotToBeRegistered); + if (!node) + return NS_ERROR_OUT_OF_MEMORY; + + mFactoriesNotToBeRegistered = node; + return NS_OK; +} + + +// Perform our one-time intialization for this module +nsresult +nsGenericModule::Initialize(nsIComponentManager *compMgr) +{ + nsresult rv; + + if (mInitialized) { + return NS_OK; + } + + if (mCtor) { + rv = mCtor(this); + if (NS_FAILED(rv)) + return rv; + } + + +#ifdef XPCOM_GLUE + rv = XPCOMGlueStartup("."); + if (NS_FAILED(rv)) + return rv; +#endif + + nsCOMPtr registrar = do_QueryInterface(compMgr, &rv); + if (NS_FAILED(rv)) + return rv; + + // Eagerly populate factory/class object hash for entries + // without constructors. If we didn't, the class object would + // never get created. Also create the factory, which doubles + // as the class object, if the EAGER_CLASSINFO flag was given. + // This allows objects to be created (within their modules) + // via operator new rather than CreateInstance, yet still be + // QI'able to nsIClassInfo. + const nsModuleComponentInfo* desc = mComponents; + for (PRUint32 i = 0; i < mComponentCount; i++) { + if (!desc->mConstructor || + (desc->mFlags & nsIClassInfo::EAGER_CLASSINFO)) { + nsCOMPtr fact; + nsresult rv = NS_NewGenericFactory(getter_AddRefs(fact), desc); + if (NS_FAILED(rv)) return rv; + + // if we don't have a mConstructor, then we should not populate + // the component manager. + if (!desc->mConstructor) { + rv = AddFactoryNode(fact); + } else { + rv = registrar->RegisterFactory(desc->mCID, + desc->mDescription, + desc->mContractID, + fact); + } + if (NS_FAILED(rv)) return rv; + } + desc++; + } + + mInitialized = PR_TRUE; + return NS_OK; +} + +// Shutdown this module, releasing all of the module resources +void +nsGenericModule::Shutdown() +{ + // Free cached factories that were not registered. + FactoryNode* node; + while (mFactoriesNotToBeRegistered) + { + node = mFactoriesNotToBeRegistered->mNext; + delete mFactoriesNotToBeRegistered; + mFactoriesNotToBeRegistered = node; + } + + if (mInitialized) { + mInitialized = PR_FALSE; + + if (mDtor) + mDtor(this); + } +} + +// Create a factory object for creating instances of aClass. +NS_IMETHODIMP +nsGenericModule::GetClassObject(nsIComponentManager *aCompMgr, + const nsCID& aClass, + const nsIID& aIID, + void** r_classObj) +{ + nsresult rv; + + // Defensive programming: Initialize *r_classObj in case of error below + if (!r_classObj) { + return NS_ERROR_INVALID_POINTER; + } + *r_classObj = NULL; + + // Do one-time-only initialization if necessary + if (!mInitialized) { + rv = Initialize(aCompMgr); + if (NS_FAILED(rv)) { + // Initialization failed! yikes! + return rv; + } + } + + // Choose the appropriate factory, based on the desired instance + // class type (aClass). + const nsModuleComponentInfo* desc = mComponents; + for (PRUint32 i = 0; i < mComponentCount; i++) { + if (desc->mCID.Equals(aClass)) { + nsCOMPtr fact; + rv = NS_NewGenericFactory(getter_AddRefs(fact), desc); + if (NS_FAILED(rv)) return rv; + return fact->QueryInterface(aIID, r_classObj); + } + desc++; + } + // not found in descriptions +#ifndef XPCOM_GLUE +#ifdef DEBUG + char* cs = aClass.ToString(); + fprintf(stderr, "+++ nsGenericModule %s: unable to create factory for %s\n", mModuleName, cs); + // leak until we resolve the nsID Allocator. + // nsCRT::free(cs); +#endif // XXX put in stop-gap so that we don't search for this one again +#endif + return NS_ERROR_FACTORY_NOT_REGISTERED; +} + +NS_IMETHODIMP +nsGenericModule::RegisterSelf(nsIComponentManager *aCompMgr, + nsIFile* aPath, + const char* registryLocation, + const char* componentType) +{ + nsresult rv = NS_OK; + +#ifdef DEBUG + fprintf(stderr, "*** Registering %s components (all right -- a generic module!)\n", mModuleName); +#endif + + const nsModuleComponentInfo* cp = mComponents; + for (PRUint32 i = 0; i < mComponentCount; i++) { + // Register the component only if it has a constructor + if (cp->mConstructor) { + nsCOMPtr registrar = do_QueryInterface(aCompMgr, &rv); + if (registrar) + rv = registrar->RegisterFactoryLocation(cp->mCID, + cp->mDescription, + cp->mContractID, + aPath, + registryLocation, + componentType); + if (NS_FAILED(rv)) { +#ifdef DEBUG + fprintf(stderr, "nsGenericModule %s: unable to register %s component => %x\n", + mModuleName?mModuleName:"(null)", cp->mDescription?cp->mDescription:"(null)", rv); +#endif + break; + } + } + // Call the registration hook of the component, if any + if (cp->mRegisterSelfProc) + { + rv = cp->mRegisterSelfProc(aCompMgr, aPath, registryLocation, + componentType, cp); + if (NS_FAILED(rv)) { +#ifdef DEBUG + fprintf(stderr, "nsGenericModule %s: Register hook for %s component returned error => %x\n", + mModuleName?mModuleName:"(null)", cp->mDescription?cp->mDescription:"(null)", rv); +#endif + break; + } + } + cp++; + } + +#ifndef XPCOM_GLUE + // We want to tell the component loader of any dependencies + // we have so that the loader can resolve them for us. + + nsCOMPtr loader = do_GetInterface(aCompMgr); + if (loader && mLibraryDependencies) + { + for(int i=0; mLibraryDependencies[i] != nsnull && + mLibraryDependencies[i][0] != '\0'; i++) + { + loader->AddDependentLibrary(aPath, + mLibraryDependencies[i]); + } + loader = nsnull; + } +#endif + + + + return rv; +} + +NS_IMETHODIMP +nsGenericModule::UnregisterSelf(nsIComponentManager* aCompMgr, + nsIFile* aPath, + const char* registryLocation) +{ +#ifdef DEBUG + fprintf(stderr, "*** Unregistering %s components (all right -- a generic module!)\n", mModuleName); +#endif + const nsModuleComponentInfo* cp = mComponents; + for (PRUint32 i = 0; i < mComponentCount; i++) { + // Call the unregistration hook of the component, if any + if (cp->mUnregisterSelfProc) + { + cp->mUnregisterSelfProc(aCompMgr, aPath, registryLocation, cp); + } + + // Unregister the component + nsresult rv; + nsCOMPtr registrar = do_QueryInterface(aCompMgr, &rv); + if (registrar) + rv = registrar->UnregisterFactoryLocation(cp->mCID, aPath); + if (NS_FAILED(rv)) { +#ifdef DEBUG + fprintf(stderr, "nsGenericModule %s: unable to unregister %s component => %x\n", + mModuleName, cp->mDescription, rv); +#endif + } + cp++; + } + + return NS_OK; +} + +NS_IMETHODIMP +nsGenericModule::CanUnload(nsIComponentManager *aCompMgr, PRBool *okToUnload) +{ + if (!okToUnload) { + return NS_ERROR_INVALID_POINTER; + } + *okToUnload = PR_FALSE; + return NS_ERROR_FAILURE; +} + +NS_COM nsresult +NS_NewGenericModule2(nsModuleInfo* info, nsIModule* *result) +{ + nsresult rv = NS_OK; + + // Create and initialize the module instance + nsGenericModule *m = + new nsGenericModule(info->mModuleName, info->mCount, info->mComponents, + info->mCtor, info->mDtor, info->mLibraryDependencies); + + if (!m) + return NS_ERROR_OUT_OF_MEMORY; + + // Increase refcnt and store away nsIModule interface to m in result + NS_ADDREF(*result = m); + return rv; +} + +NS_COM nsresult +NS_NewGenericModule(const char* moduleName, + PRUint32 componentCount, + nsModuleComponentInfo* components, + nsModuleDestructorProc dtor, + nsIModule* *result) +{ + nsModuleInfo info; + memset(&info, 0, sizeof(info)); + + info.mVersion = NS_MODULEINFO_VERSION; + info.mModuleName = moduleName; + info.mComponents = components; + info.mCount = componentCount; + info.mDtor = dtor; + info.mLibraryDependencies = nsnull; + + return NS_NewGenericModule2(&info, result); +} + +//////////////////////////////////////////////////////////////////////////////// diff --git a/src/libs/xpcom18a4/xpcom/glue/nsGenericFactory.h b/src/libs/xpcom18a4/xpcom/glue/nsGenericFactory.h new file mode 100644 index 00000000..64afd0de --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/glue/nsGenericFactory.h @@ -0,0 +1,129 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +#ifndef nsGenericFactory_h___ +#define nsGenericFactory_h___ + +#include "nsCOMPtr.h" +#include "nsIGenericFactory.h" +#include "nsIClassInfo.h" + +/** + * Most factories follow this simple pattern, so why not just use a function + * pointer for most creation operations? + */ +class nsGenericFactory : public nsIGenericFactory, public nsIClassInfo { +public: + NS_DEFINE_STATIC_CID_ACCESSOR(NS_GENERICFACTORY_CID); + + nsGenericFactory(const nsModuleComponentInfo *info = NULL); + + NS_DECL_ISUPPORTS + NS_DECL_NSICLASSINFO + + /* nsIGenericFactory methods */ + NS_IMETHOD SetComponentInfo(const nsModuleComponentInfo *info); + NS_IMETHOD GetComponentInfo(const nsModuleComponentInfo **infop); + + NS_IMETHOD CreateInstance(nsISupports *aOuter, REFNSIID aIID, void **aResult); + + NS_IMETHOD LockFactory(PRBool aLock); + + static NS_METHOD Create(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr); +private: + ~nsGenericFactory(); + + const nsModuleComponentInfo *mInfo; +}; + +//////////////////////////////////////////////////////////////////////////////// + +#include "nsIModule.h" +#include "plhash.h" + +class nsGenericModule : public nsIModule +{ +public: + nsGenericModule(const char* moduleName, + PRUint32 componentCount, + const nsModuleComponentInfo* components, + nsModuleConstructorProc ctor, + nsModuleDestructorProc dtor, + const char** alibDepends); + +private: + ~nsGenericModule(); + +public: + NS_DECL_ISUPPORTS + + NS_DECL_NSIMODULE + + struct FactoryNode + { + FactoryNode(nsIGenericFactory* fact, FactoryNode* next) + { + mFactory = fact; + mNext = next; + } + ~FactoryNode(){} + + nsCOMPtr mFactory; + FactoryNode* mNext; + }; + + + + +protected: + nsresult Initialize(nsIComponentManager* compMgr); + + void Shutdown(); + nsresult AddFactoryNode(nsIGenericFactory* fact); + + PRBool mInitialized; + const char* mModuleName; + PRUint32 mComponentCount; + const nsModuleComponentInfo* mComponents; + FactoryNode* mFactoriesNotToBeRegistered; + nsModuleConstructorProc mCtor; + nsModuleDestructorProc mDtor; + const char** mLibraryDependencies; +}; + +#endif /* nsGenericFactory_h___ */ + diff --git a/src/libs/xpcom18a4/xpcom/glue/nsIGenericFactory.h b/src/libs/xpcom18a4/xpcom/glue/nsIGenericFactory.h new file mode 100644 index 00000000..82506e8e --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/glue/nsIGenericFactory.h @@ -0,0 +1,480 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +#ifndef nsIGenericFactory_h___ +#define nsIGenericFactory_h___ + +#include "nsIFactory.h" +#include "nsIModule.h" +#include "nsIClassInfo.h" +#ifdef HAVE_DEPENDENT_LIBS +#include "dependentLibs.h" +#endif + +// {3bc97f01-ccdf-11d2-bab8-b548654461fc} +#define NS_GENERICFACTORY_CID \ + { 0x3bc97f01, 0xccdf, 0x11d2, \ + { 0xba, 0xb8, 0xb5, 0x48, 0x65, 0x44, 0x61, 0xfc } } + +// {3bc97f00-ccdf-11d2-bab8-b548654461fc} +#define NS_IGENERICFACTORY_IID \ + { 0x3bc97f00, 0xccdf, 0x11d2, \ + { 0xba, 0xb8, 0xb5, 0x48, 0x65, 0x44, 0x61, 0xfc } } + +#define NS_GENERICFACTORY_CONTRACTID "@mozilla.org/generic-factory;1" +#define NS_GENERICFACTORY_CLASSNAME "Generic Factory" + +struct nsModuleComponentInfo; // forward declaration + +/** + * Provides a Generic nsIFactory implementation that can be used by + * DLLs with very simple factory needs. + */ +class nsIGenericFactory : public nsIFactory { +public: + NS_DEFINE_STATIC_IID_ACCESSOR(NS_IGENERICFACTORY_IID) + + NS_IMETHOD SetComponentInfo(const nsModuleComponentInfo *info) = 0; + NS_IMETHOD GetComponentInfo(const nsModuleComponentInfo **infop) = 0; +}; + +NS_COM nsresult +NS_NewGenericFactory(nsIGenericFactory **result, + const nsModuleComponentInfo *info); + + +/** Component Callbacks **/ + + /** + * NSConstructorProcPtr + * + * This function will be used by the generic factory to create an + * instance of the given CID. + * + * @param aOuter : Pointer to a component that wishes to be aggregated + * in the resulting instance. This will be nsnull if no + * aggregation is requested. + * @param iid : The IID of the interface being requested in + * the component which is being currently created. + * @param result : [out] Pointer to the newly created instance, if successful. + * + * @return NS_OK Component successfully created and the interface + * being requested was successfully returned in result. + * NS_NOINTERFACE Interface not accessible. + * NS_ERROR_NO_AGGREGATION if an 'outer' object is supplied, but the + * component is not aggregatable. + * NS_ERROR* Method failure. + **/ +typedef NS_CALLBACK(NSConstructorProcPtr)(nsISupports *aOuter, + REFNSIID aIID, + void **aResult); + +/** + * NSRegisterSelfProcPtr + * + * One time registration call back. Allows you to perform registration + * specific activity like adding yourself to a category. + * + * @param aCompMgr : The global component manager + * @param aFile : Component File. This file must have an associated + * loader and export the required symbols which this + * loader defines. + * @param aLoaderStr : Opaque loader specific string. This value is + * passed into the nsIModule's registerSelf + * callback and must be fowarded unmodified when + * registering factories via their location. + * @param aType : Component Type of CID aClass. This value is + * passed into the nsIModule's registerSelf + * callback and must be fowarded unmodified when + * registering factories via their location. + * @param aInfo : Pointer to array of nsModuleComponentInfo + * + * @param aInfo + * @return NS_OK Registration was successful. + * NS_ERROR* Method failure. + **/ +typedef NS_CALLBACK(NSRegisterSelfProcPtr)(nsIComponentManager *aCompMgr, + nsIFile *aPath, + const char *aLoaderStr, + const char *aType, + const nsModuleComponentInfo *aInfo); + +/** + * NSUnregisterSelfProcPtr + * + * One time unregistration call back. Allows you to perform unregistration + * specific activity like removing yourself from a category. + * + * @param aCompMgr : The global component manager + * @param aFile : Component File. This file must have an associated + * loader and export the required symbols which this + * loader defines. + * @param aLoaderStr : Opaque loader specific string. This value is + * passed into the nsIModule's registerSelf + * callback and must be fowarded unmodified when + * registering factories via their location + * @param aInfo : Pointer to array of nsModuleComponentInfo + * + * @param aInfo + * @return NS_OK Registration was successful. + * NS_ERROR* Method failure. + + **/ +typedef NS_CALLBACK(NSUnregisterSelfProcPtr)(nsIComponentManager *aCompMgr, + nsIFile *aPath, + const char *aLoaderStr, + const nsModuleComponentInfo *aInfo); + +/** + * NSFactoryDestructorProcPtr + * + * This function will be called when the factory is being destroyed. + * + **/ +typedef NS_CALLBACK(NSFactoryDestructorProcPtr)(void); + + +/** + * NSGetInterfacesProcPtr + * + * This function is used to implement class info. + * + * Get an ordered list of the interface ids that instances of the class + * promise to implement. Note that nsISupports is an implicit member + * of any such list and need not be included. + * + * Should set *count = 0 and *array = null and return NS_OK if getting the + * list is not supported. + * + * @see nsIClassInfo.idl + **/ +typedef NS_CALLBACK(NSGetInterfacesProcPtr)(PRUint32 *countp, + nsIID* **array); + +/** + * NSGetLanguageHelperProcPtr + * + * This function is used to implement class info. + * + * Get a language mapping specific helper object that may assist in using + * objects of this class in a specific lanaguage. For instance, if asked + * for the helper for nsIProgrammingLanguage::JAVASCRIPT this might return + * an object that can be QI'd into the nsIXPCScriptable interface to assist + * XPConnect in supplying JavaScript specific behavior to callers of the + * instance object. + * + * @see: nsIClassInfo.idl, nsIProgrammingLanguage.idl + * + * Should return null if no helper available for given language. + **/ +typedef NS_CALLBACK(NSGetLanguageHelperProcPtr)(PRUint32 language, + nsISupports **helper); + +/** + * nsModuleComponentInfo + * + * Use this type to define a list of module component info to pass to + * NS_NewGenericModule. + * + * @param mDescription : Class Name of given object + * @param mCID : CID of given object + * @param mContractID : Contract ID of given object + * @param mConstructor : Constructor of given object + * @param mRegisterSelfProc : (optional) Registration Callback + * @param mUnregisterSelfProc : (optional) Unregistration Callback + * @param mFactoryDestructor : (optional) Destruction Callback + * @param mGetInterfacesProc : (optional) Interfaces Callback + * @param mGetLanguageHelperProc : (optional) Language Helper Callback + * @param mClassInfoGlobal : (optional) Global Class Info of given object + * @param mFlags : (optional) Class Info Flags @see nsIClassInfo + * + * E.g.: + * static nsModuleComponentInfo components[] = { ... }; + * + * See xpcom/sample/nsSampleModule.cpp for more info. + */ +struct nsModuleComponentInfo { + const char* mDescription; + nsCID mCID; + const char* mContractID; + NSConstructorProcPtr mConstructor; + NSRegisterSelfProcPtr mRegisterSelfProc; + NSUnregisterSelfProcPtr mUnregisterSelfProc; + NSFactoryDestructorProcPtr mFactoryDestructor; + NSGetInterfacesProcPtr mGetInterfacesProc; + NSGetLanguageHelperProcPtr mGetLanguageHelperProc; + nsIClassInfo ** mClassInfoGlobal; + PRUint32 mFlags; +}; + + +/** Module Callbacks **/ + + +/** + * nsModuleConstructorProc + * + * This function is called when the module is first being constructed. + * @param self module which is being constructed. + * + * @return NS_OK Construction successful. + * NS_ERROR* Method failure which will result in module not being + * loaded. + **/ +typedef nsresult (PR_CALLBACK *nsModuleConstructorProc) (nsIModule *self); + + +/** + * nsModuleDestructorProc + * + * This function is called when the module is being destroyed. + * @param self module which is being destroyed. + * + **/ +typedef void (PR_CALLBACK *nsModuleDestructorProc) (nsIModule *self); + +/** + * nsModuleInfo + * + * Use this structure to define meta-information about the module + * itself, including the name, its components, and an optional + * module-level initialization or shutdown routine. + * + * @param mVersion : Module Info Version + * @param mModuleName : Module Name + * @param mComponents : Array of Components + * @param mCount : Count of mComponents + * @param mCtor : Module user defined constructor + * @param mDtor : Module user defined destructor + * @param mLibraryDependencies : array of library which this module is + * dependent on. + * + **/ + +struct nsModuleInfo { + PRUint32 mVersion; + const char* mModuleName; + const nsModuleComponentInfo* mComponents; + PRUint32 mCount; + nsModuleConstructorProc mCtor; + nsModuleDestructorProc mDtor; + const char** mLibraryDependencies; +}; + +/** + * Rev this if you change the nsModuleInfo, and are worried about + * binary compatibility. (Ostensibly fix NS_NewGenericModule2() to deal + * with older rev's at the same time.) + */ +#define NS_MODULEINFO_VERSION 0x00015000UL // 1.5 + +/** + * Create a new generic module. Use the NS_IMPL_NSGETMODULE macro, or + * one of its relatives, rather than using this directly. + */ +NS_COM nsresult +NS_NewGenericModule2(nsModuleInfo *info, nsIModule* *result); + +/** + * Obsolete. Use NS_NewGenericModule2() instead. + */ +NS_COM nsresult +NS_NewGenericModule(const char* moduleName, + PRUint32 componentCount, + nsModuleComponentInfo* components, + nsModuleDestructorProc dtor, + nsIModule* *result); + +#if defined(XPCOM_TRANSLATE_NSGM_ENTRY_POINT) +# define NS_MODULEINFO nsModuleInfo +# define NSMODULEINFO(_name) _name##_gModuleInfo +# define NSGETMODULE_ENTRY_POINT(_info) +# define NSDEPENDENT_LIBS(_name) const char* _name##_gDependlibs[]={DEPENDENT_LIBS "\0"}; +# define NSDEPENDENT_LIBS_NAME(_name) _name##_gDependlibs +#else +# define NS_MODULEINFO static nsModuleInfo +# define NSMODULEINFO(_name) gModuleInfo +# define NSDEPENDENT_LIBS(_name) static const char* gDependlibs[]={DEPENDENT_LIBS "\0"}; +# define NSDEPENDENT_LIBS_NAME(_name) gDependlibs +# define NSGETMODULE_ENTRY_POINT(_info) \ +extern "C" NS_EXPORT nsresult \ +NSGetModule(nsIComponentManager *servMgr, \ + nsIFile* location, \ + nsIModule** result) \ +{ \ + (void)servMgr; \ + (void)location; \ + return NS_NewGenericModule2(&(_info), result); \ +} +#endif + +/** + * Ease of use Macros which define NSGetModule for your component. + * See xpcom/sample/nsSampleModule.cpp for more info. + * + **/ + +#define NS_IMPL_NSGETMODULE(_name, _components) \ + NS_IMPL_NSGETMODULE_WITH_CTOR_DTOR(_name, _components, nsnull, nsnull) + +#define NS_IMPL_NSGETMODULE_WITH_CTOR(_name, _components, _ctor) \ + NS_IMPL_NSGETMODULE_WITH_CTOR_DTOR(_name, _components, _ctor, nsnull) + +#define NS_IMPL_NSGETMODULE_WITH_DTOR(_name, _components, _dtor) \ + NS_IMPL_NSGETMODULE_WITH_CTOR_DTOR(_name, _components, nsnull, _dtor) + +#ifndef DEPENDENT_LIBS + +#define NS_IMPL_NSGETMODULE_WITH_CTOR_DTOR(_name, _components, _ctor, _dtor) \ +NS_MODULEINFO NSMODULEINFO(_name) = { \ + NS_MODULEINFO_VERSION, \ + (#_name), \ + (_components), \ + (sizeof(_components) / sizeof(_components[0])), \ + (_ctor), \ + (_dtor), \ + (nsnull) \ +}; \ +NSGETMODULE_ENTRY_POINT(NSMODULEINFO(_name)) + +#else // DEPENDENT_LIBS + +#define NS_IMPL_NSGETMODULE_WITH_CTOR_DTOR(_name, _components, _ctor, _dtor) \ +NSDEPENDENT_LIBS(_name) \ +NS_MODULEINFO NSMODULEINFO(_name) = { \ + NS_MODULEINFO_VERSION, \ + (#_name), \ + (_components), \ + (sizeof(_components) / sizeof(_components[0])), \ + (_ctor), \ + (_dtor), \ + (NSDEPENDENT_LIBS_NAME(_name)) \ +}; \ +NSGETMODULE_ENTRY_POINT(NSMODULEINFO(_name)) + +#endif + +//////////////////////////////////////////////////////////////////////////////// + +#define NS_GENERIC_FACTORY_CONSTRUCTOR(_InstanceClass) \ +static NS_IMETHODIMP \ +_InstanceClass##Constructor(nsISupports *aOuter, REFNSIID aIID, \ + void **aResult) \ +{ \ + nsresult rv; \ + \ + _InstanceClass * inst; \ + \ + *aResult = NULL; \ + if (NULL != aOuter) { \ + rv = NS_ERROR_NO_AGGREGATION; \ + return rv; \ + } \ + \ + NS_NEWXPCOM(inst, _InstanceClass); \ + if (NULL == inst) { \ + rv = NS_ERROR_OUT_OF_MEMORY; \ + return rv; \ + } \ + NS_ADDREF(inst); \ + rv = inst->QueryInterface(aIID, aResult); \ + NS_RELEASE(inst); \ + \ + return rv; \ +} \ + + +#define NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(_InstanceClass, _InitMethod) \ +static NS_IMETHODIMP \ +_InstanceClass##Constructor(nsISupports *aOuter, REFNSIID aIID, \ + void **aResult) \ +{ \ + nsresult rv; \ + \ + _InstanceClass * inst; \ + \ + *aResult = NULL; \ + if (NULL != aOuter) { \ + rv = NS_ERROR_NO_AGGREGATION; \ + return rv; \ + } \ + \ + NS_NEWXPCOM(inst, _InstanceClass); \ + if (NULL == inst) { \ + rv = NS_ERROR_OUT_OF_MEMORY; \ + return rv; \ + } \ + NS_ADDREF(inst); \ + rv = inst->_InitMethod(); \ + if(NS_SUCCEEDED(rv)) { \ + rv = inst->QueryInterface(aIID, aResult); \ + } \ + NS_RELEASE(inst); \ + \ + return rv; \ +} \ + +// 'Constructor' that uses an existing getter function that gets a singleton. +// NOTE: assumes that getter does an AddRef - so additional AddRef is not done. +#define NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(_InstanceClass, _GetterProc) \ +static NS_IMETHODIMP \ +_InstanceClass##Constructor(nsISupports *aOuter, REFNSIID aIID, \ + void **aResult) \ +{ \ + nsresult rv; \ + \ + _InstanceClass * inst; \ + \ + *aResult = NULL; \ + if (NULL != aOuter) { \ + rv = NS_ERROR_NO_AGGREGATION; \ + return rv; \ + } \ + \ + inst = _GetterProc(); \ + if (NULL == inst) { \ + rv = NS_ERROR_OUT_OF_MEMORY; \ + return rv; \ + } \ + /* NS_ADDREF(inst); */ \ + rv = inst->QueryInterface(aIID, aResult); \ + NS_RELEASE(inst); \ + \ + return rv; \ +} \ + +#endif /* nsIGenericFactory_h___ */ diff --git a/src/libs/xpcom18a4/xpcom/glue/nsIInterfaceRequestorUtils.cpp b/src/libs/xpcom18a4/xpcom/glue/nsIInterfaceRequestorUtils.cpp new file mode 100644 index 00000000..b440c342 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/glue/nsIInterfaceRequestorUtils.cpp @@ -0,0 +1,64 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Scott Collins + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsIInterfaceRequestor.h" +#include "nsIInterfaceRequestorUtils.h" + +nsresult +nsGetInterface::operator()( const nsIID& aIID, void** aInstancePtr ) const +{ + nsresult status; + + if ( mSource ) + { + nsCOMPtr factoryPtr = do_QueryInterface(mSource, &status); + NS_ASSERTION(factoryPtr, "Did you know you were calling |do_GetInterface()| on an object that doesn't support the |nsIInterfaceRequestor| interface?"); + + if ( factoryPtr ) + status = factoryPtr->GetInterface(aIID, aInstancePtr); + + if ( NS_FAILED(status) ) + *aInstancePtr = 0; + } + else + status = NS_ERROR_NULL_POINTER; + + if ( mErrorPtr ) + *mErrorPtr = status; + return status; +} diff --git a/src/libs/xpcom18a4/xpcom/glue/nsIInterfaceRequestorUtils.h b/src/libs/xpcom18a4/xpcom/glue/nsIInterfaceRequestorUtils.h new file mode 100644 index 00000000..e971dd4b --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/glue/nsIInterfaceRequestorUtils.h @@ -0,0 +1,83 @@ +/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * ***** 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 the Mozilla browser. + * + * The Initial Developer of the Original Code is + * Netscape Communications, Inc. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +#ifndef __nsInterfaceRequestorUtils_h +#define __nsInterfaceRequestorUtils_h + +#include "nsCOMPtr.h" + +// a type-safe shortcut for calling the |GetInterface()| member function +// T must inherit from nsIInterfaceRequestor, but the cast may be ambiguous. +template +inline +nsresult +CallGetInterface( T* aSource, DestinationType** aDestination ) + { + NS_PRECONDITION(aSource, "null parameter"); + NS_PRECONDITION(aDestination, "null parameter"); + + return aSource->GetInterface(NS_GET_IID(DestinationType), + NS_REINTERPRET_CAST(void**, aDestination)); + } + +class NS_COM nsGetInterface : public nsCOMPtr_helper + { + public: + nsGetInterface( nsISupports* aSource, nsresult* error ) + : mSource(aSource), + mErrorPtr(error) + { + // nothing else to do here + } + + virtual nsresult NS_FASTCALL operator()( const nsIID&, void** ) const; + + private: + nsCOMPtr mSource; + nsresult* mErrorPtr; + }; + +inline +const nsGetInterface +do_GetInterface( nsISupports* aSource, nsresult* error = 0 ) + { + return nsGetInterface(aSource, error); + } + +#endif // __nsInterfaceRequestorUtils_h + diff --git a/src/libs/xpcom18a4/xpcom/glue/nsISupportsImpl.h b/src/libs/xpcom18a4/xpcom/glue/nsISupportsImpl.h new file mode 100644 index 00000000..588a2c73 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/glue/nsISupportsImpl.h @@ -0,0 +1,1246 @@ +/* ***** 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 XPCOM. + * + * The Initial Developer of the Original Code is Netscape Communications Corp. + * Portions created by the Initial Developer are Copyright (C) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * 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 ***** */ + + +#ifndef nsISupportsImpl_h__ +#define nsISupportsImpl_h__ + +#ifndef nscore_h___ +#include "nscore.h" +#endif + +#ifndef nsISupportsBase_h__ +#include "nsISupportsBase.h" +#endif + +#include "prthread.h" /* needed for thread-safety checks */ +#include "pratom.h" /* needed for PR_AtomicIncrement and PR_AtomicDecrement */ + +#include "nsDebug.h" +#include "nsTraceRefcnt.h" +#ifdef VBOX +# include "iprt/asm.h" +# include "iprt/assert.h" +#endif + +//////////////////////////////////////////////////////////////////////////////// +// Macros to help detect thread-safety: + +#if defined(NS_DEBUG) + +class nsAutoOwningThread { +public: + nsAutoOwningThread() { mThread = PR_GetCurrentThread(); } + void *GetThread() const { return mThread; } + +private: + void *mThread; +}; + +#define NS_DECL_OWNINGTHREAD nsAutoOwningThread _mOwningThread; +#define NS_ASSERT_OWNINGTHREAD(_class) \ + NS_CheckThreadSafe(_mOwningThread.GetThread(), #_class " not thread-safe") + +#else // !(defined(NS_DEBUG)) + +#define NS_DECL_OWNINGTHREAD /* nothing */ +#define NS_ASSERT_OWNINGTHREAD(_class) ((void)0) + +#endif // !(defined(NS_DEBUG)) + +class nsAutoRefCnt { + + public: + nsAutoRefCnt() : mValue(0) +#ifdef VBOX + , mState(0) +#endif + {} + nsAutoRefCnt(nsrefcnt aValue) : mValue(aValue) {} + + // only support prefix increment/decrement + nsrefcnt operator++() { return ++mValue; } + nsrefcnt operator--() { return --mValue; } + + nsrefcnt operator=(nsrefcnt aValue) { return (mValue = aValue); } + operator nsrefcnt() const { return mValue; } + nsrefcnt get() const { return mValue; } +#ifdef VBOX + nsrefcnt *ref() { return &mValue; } + PRUint32 getState() const { return mState; } + PRUint32 *refState() { return &mState; } +#endif + private: + // do not define these to enforce the faster prefix notation + nsrefcnt operator++(int); + nsrefcnt operator--(int); + nsrefcnt mValue; +#ifdef VBOX + PRUint32 mState; +#endif +}; + +/////////////////////////////////////////////////////////////////////////////// + +/** + * Declare the reference count variable and the implementations of the + * AddRef and QueryInterface methods. + */ + +#define NS_DECL_ISUPPORTS \ +public: \ + NS_IMETHOD QueryInterface(REFNSIID aIID, \ + void** aInstancePtr); \ + NS_IMETHOD_(nsrefcnt) AddRef(void); \ + NS_IMETHOD_(nsrefcnt) Release(void); \ +protected: \ + nsAutoRefCnt mRefCnt; \ + NS_DECL_OWNINGTHREAD \ +public: + + +/////////////////////////////////////////////////////////////////////////////// + +/** + * Previously used to initialize the reference count, but no longer needed. + * + * DEPRECATED. + */ +#define NS_INIT_ISUPPORTS() ((void)0) + +/** + * Use this macro to implement the AddRef method for a given _class + * @param _class The name of the class implementing the method + */ +#define NS_IMPL_ADDREF(_class) \ +NS_IMETHODIMP_(nsrefcnt) _class::AddRef(void) \ +{ \ + NS_PRECONDITION(PRInt32(mRefCnt) >= 0, "illegal refcnt"); \ + NS_ASSERT_OWNINGTHREAD(_class); \ + ++mRefCnt; \ + NS_LOG_ADDREF(this, mRefCnt, #_class, sizeof(*this)); \ + return mRefCnt; \ +} + +/** + * Use this macro to implement the AddRef method for a given _class + * implemented as a wholly owned aggregated object intended to implement + * interface(s) for its owner + * @param _class The name of the class implementing the method + * @param _aggregator the owning/containing object + */ +#define NS_IMPL_ADDREF_USING_AGGREGATOR(_class, _aggregator) \ +NS_IMETHODIMP_(nsrefcnt) _class::AddRef(void) \ +{ \ + NS_PRECONDITION(_aggregator, "null aggregator"); \ + return (_aggregator)->AddRef(); \ +} + +/** + * Use this macro to implement the Release method for a given + * _class. + * @param _class The name of the class implementing the method + * @param _destroy A statement that is executed when the object's + * refcount drops to zero. + * + * For example, + * + * NS_IMPL_RELEASE_WITH_DESTROY(Foo, Destroy(this)) + * + * will cause + * + * Destroy(this); + * + * to be invoked when the object's refcount drops to zero. This + * allows for arbitrary teardown activity to occur (e.g., deallocation + * of object allocated with placement new). + */ +#define NS_IMPL_RELEASE_WITH_DESTROY(_class, _destroy) \ +NS_IMETHODIMP_(nsrefcnt) _class::Release(void) \ +{ \ + NS_PRECONDITION(0 != mRefCnt, "dup release"); \ + NS_ASSERT_OWNINGTHREAD(_class); \ + --mRefCnt; \ + NS_LOG_RELEASE(this, mRefCnt, #_class); \ + if (mRefCnt == 0) { \ + mRefCnt = 1; /* stabilize */ \ + _destroy; \ + return 0; \ + } \ + return mRefCnt; \ +} + +/** + * Use this macro to implement the Release method for a given _class + * @param _class The name of the class implementing the method + * + * A note on the 'stabilization' of the refcnt to one. At that point, + * the object's refcount will have gone to zero. The object's + * destructor may trigger code that attempts to QueryInterface() and + * Release() 'this' again. Doing so will temporarily increment and + * decrement the refcount. (Only a logic error would make one try to + * keep a permanent hold on 'this'.) To prevent re-entering the + * destructor, we make sure that no balanced refcounting can return + * the refcount to |0|. + */ +#define NS_IMPL_RELEASE(_class) \ + NS_IMPL_RELEASE_WITH_DESTROY(_class, NS_DELETEXPCOM(this)) + +/** + * Use this macro to implement the Release method for a given _class + * implemented as a wholly owned aggregated object intended to implement + * interface(s) for its owner + * @param _class The name of the class implementing the method + * @param _aggregator the owning/containing object + */ +#define NS_IMPL_RELEASE_USING_AGGREGATOR(_class, _aggregator) \ +NS_IMETHODIMP_(nsrefcnt) _class::Release(void) \ +{ \ + NS_PRECONDITION(_aggregator, "null aggregator"); \ + return (_aggregator)->Release(); \ +} + + + +/////////////////////////////////////////////////////////////////////////////// + +/* + * Some convenience macros for implementing QueryInterface + */ + +/** + * This implements query interface with two assumptions: First, the + * class in question implements nsISupports and its own interface and + * nothing else. Second, the implementation of the class's primary + * inheritance chain leads to its own interface. + * + * @param _class The name of the class implementing the method + * @param _classiiddef The name of the #define symbol that defines the IID + * for the class (e.g. NS_ISUPPORTS_IID) + */ + +#define NS_IMPL_QUERY_HEAD(_class) \ +NS_IMETHODIMP _class::QueryInterface(REFNSIID aIID, void** aInstancePtr) \ +{ \ + NS_ASSERTION(aInstancePtr, \ + "QueryInterface requires a non-NULL destination!"); \ + nsISupports* foundInterface; + +#define NS_IMPL_QUERY_BODY(_interface) \ + if ( aIID.Equals(NS_GET_IID(_interface)) ) \ + foundInterface = NS_STATIC_CAST(_interface*, this); \ + else + +#define NS_IMPL_QUERY_BODY_CONDITIONAL(_interface, condition) \ + if ( (condition) && aIID.Equals(NS_GET_IID(_interface))) \ + foundInterface = NS_STATIC_CAST(_interface*, this); \ + else + +#define NS_IMPL_QUERY_BODY_AMBIGUOUS(_interface, _implClass) \ + if ( aIID.Equals(NS_GET_IID(_interface)) ) \ + foundInterface = NS_STATIC_CAST(_interface*, \ + NS_STATIC_CAST(_implClass*, this)); \ + else + +#define NS_IMPL_QUERY_BODY_AGGREGATED(_interface, _aggregate) \ + if ( aIID.Equals(NS_GET_IID(_interface)) ) \ + foundInterface = NS_STATIC_CAST(_interface*, _aggregate); \ + else + +#define NS_IMPL_QUERY_TAIL_GUTS \ + foundInterface = 0; \ + nsresult status; \ + if ( !foundInterface ) \ + status = NS_NOINTERFACE; \ + else \ + { \ + NS_ADDREF(foundInterface); \ + status = NS_OK; \ + } \ + *aInstancePtr = foundInterface; \ + return status; \ +} + +#define NS_IMPL_QUERY_TAIL_INHERITING(_baseclass) \ + foundInterface = 0; \ + nsresult status; \ + if ( !foundInterface ) \ + status = _baseclass::QueryInterface(aIID, (void**)&foundInterface); \ + else \ + { \ + NS_ADDREF(foundInterface); \ + status = NS_OK; \ + } \ + *aInstancePtr = foundInterface; \ + return status; \ +} + +#define NS_IMPL_QUERY_TAIL_USING_AGGREGATOR(_aggregator) \ + foundInterface = 0; \ + nsresult status; \ + if ( !foundInterface ) { \ + NS_ASSERTION(_aggregator, "null aggregator"); \ + status = _aggregator->QueryInterface(aIID, (void**)&foundInterface); \ + } else \ + { \ + NS_ADDREF(foundInterface); \ + status = NS_OK; \ + } \ + *aInstancePtr = foundInterface; \ + return status; \ +} + +#define NS_IMPL_QUERY_TAIL(_supports_interface) \ + NS_IMPL_QUERY_BODY_AMBIGUOUS(nsISupports, _supports_interface) \ + NS_IMPL_QUERY_TAIL_GUTS + + + /* + This is the new scheme. Using this notation now will allow us to switch to + a table driven mechanism when it's ready. Note the difference between this + and the (currently) underlying NS_IMPL_QUERY_INTERFACE mechanism. You must + explicitly mention |nsISupports| when using the interface maps. + */ +#define NS_INTERFACE_MAP_BEGIN(_implClass) NS_IMPL_QUERY_HEAD(_implClass) +#define NS_INTERFACE_MAP_ENTRY(_interface) NS_IMPL_QUERY_BODY(_interface) +#define NS_INTERFACE_MAP_ENTRY_CONDITIONAL(_interface, condition) \ + NS_IMPL_QUERY_BODY_CONDITIONAL(_interface, condition) +#define NS_INTERFACE_MAP_ENTRY_AGGREGATED(_interface,_aggregate) \ + NS_IMPL_QUERY_BODY_AGGREGATED(_interface,_aggregate) + +#define NS_INTERFACE_MAP_END NS_IMPL_QUERY_TAIL_GUTS +#define NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(_interface, _implClass) \ + NS_IMPL_QUERY_BODY_AMBIGUOUS(_interface, _implClass) +#define NS_INTERFACE_MAP_END_INHERITING(_baseClass) \ + NS_IMPL_QUERY_TAIL_INHERITING(_baseClass) +#define NS_INTERFACE_MAP_END_AGGREGATED(_aggregator) \ + NS_IMPL_QUERY_TAIL_USING_AGGREGATOR(_aggregator) + +#define NS_IMPL_QUERY_INTERFACE0(_class) \ + NS_INTERFACE_MAP_BEGIN(_class) \ + NS_INTERFACE_MAP_ENTRY(nsISupports) \ + NS_INTERFACE_MAP_END + +#define NS_IMPL_QUERY_INTERFACE1(_class, _i1) \ + NS_INTERFACE_MAP_BEGIN(_class) \ + NS_INTERFACE_MAP_ENTRY(_i1) \ + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, _i1) \ + NS_INTERFACE_MAP_END + +#define NS_IMPL_QUERY_INTERFACE2(_class, _i1, _i2) \ + NS_INTERFACE_MAP_BEGIN(_class) \ + NS_INTERFACE_MAP_ENTRY(_i1) \ + NS_INTERFACE_MAP_ENTRY(_i2) \ + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, _i1) \ + NS_INTERFACE_MAP_END + +#define NS_IMPL_QUERY_INTERFACE3(_class, _i1, _i2, _i3) \ + NS_INTERFACE_MAP_BEGIN(_class) \ + NS_INTERFACE_MAP_ENTRY(_i1) \ + NS_INTERFACE_MAP_ENTRY(_i2) \ + NS_INTERFACE_MAP_ENTRY(_i3) \ + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, _i1) \ + NS_INTERFACE_MAP_END + +#define NS_IMPL_QUERY_INTERFACE4(_class, _i1, _i2, _i3, _i4) \ + NS_INTERFACE_MAP_BEGIN(_class) \ + NS_INTERFACE_MAP_ENTRY(_i1) \ + NS_INTERFACE_MAP_ENTRY(_i2) \ + NS_INTERFACE_MAP_ENTRY(_i3) \ + NS_INTERFACE_MAP_ENTRY(_i4) \ + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, _i1) \ + NS_INTERFACE_MAP_END + +#define NS_IMPL_QUERY_INTERFACE5(_class, _i1, _i2, _i3, _i4, _i5) \ + NS_INTERFACE_MAP_BEGIN(_class) \ + NS_INTERFACE_MAP_ENTRY(_i1) \ + NS_INTERFACE_MAP_ENTRY(_i2) \ + NS_INTERFACE_MAP_ENTRY(_i3) \ + NS_INTERFACE_MAP_ENTRY(_i4) \ + NS_INTERFACE_MAP_ENTRY(_i5) \ + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, _i1) \ + NS_INTERFACE_MAP_END + +#define NS_IMPL_QUERY_INTERFACE6(_class, _i1, _i2, _i3, _i4, _i5, _i6) \ + NS_INTERFACE_MAP_BEGIN(_class) \ + NS_INTERFACE_MAP_ENTRY(_i1) \ + NS_INTERFACE_MAP_ENTRY(_i2) \ + NS_INTERFACE_MAP_ENTRY(_i3) \ + NS_INTERFACE_MAP_ENTRY(_i4) \ + NS_INTERFACE_MAP_ENTRY(_i5) \ + NS_INTERFACE_MAP_ENTRY(_i6) \ + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, _i1) \ + NS_INTERFACE_MAP_END + +#define NS_IMPL_QUERY_INTERFACE7(_class, _i1, _i2, _i3, _i4, _i5, _i6, _i7) \ + NS_INTERFACE_MAP_BEGIN(_class) \ + NS_INTERFACE_MAP_ENTRY(_i1) \ + NS_INTERFACE_MAP_ENTRY(_i2) \ + NS_INTERFACE_MAP_ENTRY(_i3) \ + NS_INTERFACE_MAP_ENTRY(_i4) \ + NS_INTERFACE_MAP_ENTRY(_i5) \ + NS_INTERFACE_MAP_ENTRY(_i6) \ + NS_INTERFACE_MAP_ENTRY(_i7) \ + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, _i1) \ + NS_INTERFACE_MAP_END + +#define NS_IMPL_QUERY_INTERFACE8(_class, _i1, _i2, _i3, _i4, _i5, _i6, \ + _i7, _i8) \ + NS_INTERFACE_MAP_BEGIN(_class) \ + NS_INTERFACE_MAP_ENTRY(_i1) \ + NS_INTERFACE_MAP_ENTRY(_i2) \ + NS_INTERFACE_MAP_ENTRY(_i3) \ + NS_INTERFACE_MAP_ENTRY(_i4) \ + NS_INTERFACE_MAP_ENTRY(_i5) \ + NS_INTERFACE_MAP_ENTRY(_i6) \ + NS_INTERFACE_MAP_ENTRY(_i7) \ + NS_INTERFACE_MAP_ENTRY(_i8) \ + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, _i1) \ + NS_INTERFACE_MAP_END + +#define NS_IMPL_QUERY_INTERFACE9(_class, _i1, _i2, _i3, _i4, _i5, _i6, \ + _i7, _i8, _i9) \ + NS_INTERFACE_MAP_BEGIN(_class) \ + NS_INTERFACE_MAP_ENTRY(_i1) \ + NS_INTERFACE_MAP_ENTRY(_i2) \ + NS_INTERFACE_MAP_ENTRY(_i3) \ + NS_INTERFACE_MAP_ENTRY(_i4) \ + NS_INTERFACE_MAP_ENTRY(_i5) \ + NS_INTERFACE_MAP_ENTRY(_i6) \ + NS_INTERFACE_MAP_ENTRY(_i7) \ + NS_INTERFACE_MAP_ENTRY(_i8) \ + NS_INTERFACE_MAP_ENTRY(_i9) \ + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, _i1) \ + NS_INTERFACE_MAP_END + +#define NS_IMPL_QUERY_INTERFACE10(_class, _i1, _i2, _i3, _i4, _i5, _i6, \ + _i7, _i8, _i9, _i10) \ + NS_INTERFACE_MAP_BEGIN(_class) \ + NS_INTERFACE_MAP_ENTRY(_i1) \ + NS_INTERFACE_MAP_ENTRY(_i2) \ + NS_INTERFACE_MAP_ENTRY(_i3) \ + NS_INTERFACE_MAP_ENTRY(_i4) \ + NS_INTERFACE_MAP_ENTRY(_i5) \ + NS_INTERFACE_MAP_ENTRY(_i6) \ + NS_INTERFACE_MAP_ENTRY(_i7) \ + NS_INTERFACE_MAP_ENTRY(_i8) \ + NS_INTERFACE_MAP_ENTRY(_i9) \ + NS_INTERFACE_MAP_ENTRY(_i10) \ + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, _i1) \ + NS_INTERFACE_MAP_END + +#define NS_IMPL_QUERY_INTERFACE11(_class, _i1, _i2, _i3, _i4, _i5, _i6, \ + _i7, _i8, _i9, _i10, _i11) \ + NS_INTERFACE_MAP_BEGIN(_class) \ + NS_INTERFACE_MAP_ENTRY(_i1) \ + NS_INTERFACE_MAP_ENTRY(_i2) \ + NS_INTERFACE_MAP_ENTRY(_i3) \ + NS_INTERFACE_MAP_ENTRY(_i4) \ + NS_INTERFACE_MAP_ENTRY(_i5) \ + NS_INTERFACE_MAP_ENTRY(_i6) \ + NS_INTERFACE_MAP_ENTRY(_i7) \ + NS_INTERFACE_MAP_ENTRY(_i8) \ + NS_INTERFACE_MAP_ENTRY(_i9) \ + NS_INTERFACE_MAP_ENTRY(_i10) \ + NS_INTERFACE_MAP_ENTRY(_i11) \ + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, _i1) \ + NS_INTERFACE_MAP_END + + +#define NS_IMPL_THREADSAFE_QUERY_INTERFACE0 NS_IMPL_QUERY_INTERFACE0 +#define NS_IMPL_THREADSAFE_QUERY_INTERFACE1 NS_IMPL_QUERY_INTERFACE1 +#define NS_IMPL_THREADSAFE_QUERY_INTERFACE2 NS_IMPL_QUERY_INTERFACE2 +#define NS_IMPL_THREADSAFE_QUERY_INTERFACE3 NS_IMPL_QUERY_INTERFACE3 +#define NS_IMPL_THREADSAFE_QUERY_INTERFACE4 NS_IMPL_QUERY_INTERFACE4 +#define NS_IMPL_THREADSAFE_QUERY_INTERFACE5 NS_IMPL_QUERY_INTERFACE5 +#define NS_IMPL_THREADSAFE_QUERY_INTERFACE6 NS_IMPL_QUERY_INTERFACE6 +#define NS_IMPL_THREADSAFE_QUERY_INTERFACE7 NS_IMPL_QUERY_INTERFACE7 +#define NS_IMPL_THREADSAFE_QUERY_INTERFACE8 NS_IMPL_QUERY_INTERFACE8 +#define NS_IMPL_THREADSAFE_QUERY_INTERFACE9 NS_IMPL_QUERY_INTERFACE9 +#define NS_IMPL_THREADSAFE_QUERY_INTERFACE10 NS_IMPL_QUERY_INTERFACE10 +#define NS_IMPL_THREADSAFE_QUERY_INTERFACE11 NS_IMPL_QUERY_INTERFACE11 + +/** + * Declare that you're going to inherit from something that already + * implements nsISupports, but also implements an additional interface, thus + * causing an ambiguity. In this case you don't need another mRefCnt, you + * just need to forward the definitions to the appropriate superclass. E.g. + * + * class Bar : public Foo, public nsIBar { // both provide nsISupports + * public: + * NS_DECL_ISUPPORTS_INHERITED + * ...other nsIBar and Bar methods... + * }; + */ +#define NS_DECL_ISUPPORTS_INHERITED \ +public: \ + NS_IMETHOD QueryInterface(REFNSIID aIID, \ + void** aInstancePtr); \ + NS_IMETHOD_(nsrefcnt) AddRef(void); \ + NS_IMETHOD_(nsrefcnt) Release(void); \ + +/** + * These macros can be used in conjunction with NS_DECL_ISUPPORTS_INHERITED + * to implement the nsISupports methods, forwarding the invocations to a + * superclass that already implements nsISupports. + * + * Note that I didn't make these inlined because they're virtual methods. + */ + +#define NS_IMPL_ADDREF_INHERITED(Class, Super) \ +NS_IMETHODIMP_(nsrefcnt) Class::AddRef(void) \ +{ \ + return Super::AddRef(); \ +} \ + +#define NS_IMPL_RELEASE_INHERITED(Class, Super) \ +NS_IMETHODIMP_(nsrefcnt) Class::Release(void) \ +{ \ + return Super::Release(); \ +} \ + +#define NS_IMPL_QUERY_INTERFACE_INHERITED0(Class, Super) \ + NS_IMPL_QUERY_HEAD(Class) \ + NS_IMPL_QUERY_TAIL_INHERITING(Super) \ + +#define NS_IMPL_QUERY_INTERFACE_INHERITED1(Class, Super, i1) \ + NS_IMPL_QUERY_HEAD(Class) \ + NS_IMPL_QUERY_BODY(i1) \ + NS_IMPL_QUERY_TAIL_INHERITING(Super) \ + +#define NS_IMPL_QUERY_INTERFACE_INHERITED2(Class, Super, i1, i2) \ + NS_IMPL_QUERY_HEAD(Class) \ + NS_IMPL_QUERY_BODY(i1) \ + NS_IMPL_QUERY_BODY(i2) \ + NS_IMPL_QUERY_TAIL_INHERITING(Super) \ + +#define NS_IMPL_QUERY_INTERFACE_INHERITED3(Class, Super, i1, i2, i3) \ + NS_IMPL_QUERY_HEAD(Class) \ + NS_IMPL_QUERY_BODY(i1) \ + NS_IMPL_QUERY_BODY(i2) \ + NS_IMPL_QUERY_BODY(i3) \ + NS_IMPL_QUERY_TAIL_INHERITING(Super) \ + +#define NS_IMPL_QUERY_INTERFACE_INHERITED4(Class, Super, i1, i2, i3, i4) \ + NS_IMPL_QUERY_HEAD(Class) \ + NS_IMPL_QUERY_BODY(i1) \ + NS_IMPL_QUERY_BODY(i2) \ + NS_IMPL_QUERY_BODY(i3) \ + NS_IMPL_QUERY_BODY(i4) \ + NS_IMPL_QUERY_TAIL_INHERITING(Super) \ + +#define NS_IMPL_QUERY_INTERFACE_INHERITED5(Class,Super,i1,i2,i3,i4,i5) \ + NS_IMPL_QUERY_HEAD(Class) \ + NS_IMPL_QUERY_BODY(i1) \ + NS_IMPL_QUERY_BODY(i2) \ + NS_IMPL_QUERY_BODY(i3) \ + NS_IMPL_QUERY_BODY(i4) \ + NS_IMPL_QUERY_BODY(i5) \ + NS_IMPL_QUERY_TAIL_INHERITING(Super) \ + +#define NS_IMPL_QUERY_INTERFACE_INHERITED6(Class,Super,i1,i2,i3,i4,i5,i6) \ + NS_IMPL_QUERY_HEAD(Class) \ + NS_IMPL_QUERY_BODY(i1) \ + NS_IMPL_QUERY_BODY(i2) \ + NS_IMPL_QUERY_BODY(i3) \ + NS_IMPL_QUERY_BODY(i4) \ + NS_IMPL_QUERY_BODY(i5) \ + NS_IMPL_QUERY_BODY(i6) \ + NS_IMPL_QUERY_TAIL_INHERITING(Super) \ + +/** + * Convenience macros for implementing all nsISupports methods for + * a simple class. + * @param _class The name of the class implementing the method + * @param _classiiddef The name of the #define symbol that defines the IID + * for the class (e.g. NS_ISUPPORTS_IID) + */ + +#define NS_IMPL_ISUPPORTS0(_class) \ + NS_IMPL_ADDREF(_class) \ + NS_IMPL_RELEASE(_class) \ + NS_IMPL_QUERY_INTERFACE0(_class) + +#define NS_IMPL_ISUPPORTS1(_class, _interface) \ + NS_IMPL_ADDREF(_class) \ + NS_IMPL_RELEASE(_class) \ + NS_IMPL_QUERY_INTERFACE1(_class, _interface) + +#define NS_IMPL_ISUPPORTS2(_class, _i1, _i2) \ + NS_IMPL_ADDREF(_class) \ + NS_IMPL_RELEASE(_class) \ + NS_IMPL_QUERY_INTERFACE2(_class, _i1, _i2) + +#define NS_IMPL_ISUPPORTS3(_class, _i1, _i2, _i3) \ + NS_IMPL_ADDREF(_class) \ + NS_IMPL_RELEASE(_class) \ + NS_IMPL_QUERY_INTERFACE3(_class, _i1, _i2, _i3) + +#define NS_IMPL_ISUPPORTS4(_class, _i1, _i2, _i3, _i4) \ + NS_IMPL_ADDREF(_class) \ + NS_IMPL_RELEASE(_class) \ + NS_IMPL_QUERY_INTERFACE4(_class, _i1, _i2, _i3, _i4) + +#define NS_IMPL_ISUPPORTS5(_class, _i1, _i2, _i3, _i4, _i5) \ + NS_IMPL_ADDREF(_class) \ + NS_IMPL_RELEASE(_class) \ + NS_IMPL_QUERY_INTERFACE5(_class, _i1, _i2, _i3, _i4, _i5) + +#define NS_IMPL_ISUPPORTS6(_class, _i1, _i2, _i3, _i4, _i5, _i6) \ + NS_IMPL_ADDREF(_class) \ + NS_IMPL_RELEASE(_class) \ + NS_IMPL_QUERY_INTERFACE6(_class, _i1, _i2, _i3, _i4, _i5, _i6) + +#define NS_IMPL_ISUPPORTS7(_class, _i1, _i2, _i3, _i4, _i5, _i6, _i7) \ + NS_IMPL_ADDREF(_class) \ + NS_IMPL_RELEASE(_class) \ + NS_IMPL_QUERY_INTERFACE7(_class, _i1, _i2, _i3, _i4, _i5, _i6, _i7) + +#define NS_IMPL_ISUPPORTS8(_class, _i1, _i2, _i3, _i4, _i5, _i6, _i7, _i8) \ + NS_IMPL_ADDREF(_class) \ + NS_IMPL_RELEASE(_class) \ + NS_IMPL_QUERY_INTERFACE8(_class, _i1, _i2, _i3, _i4, _i5, _i6, _i7, _i8) + +#define NS_IMPL_ISUPPORTS9(_class, _i1, _i2, _i3, _i4, _i5, _i6, _i7, _i8, \ + _i9) \ + NS_IMPL_ADDREF(_class) \ + NS_IMPL_RELEASE(_class) \ + NS_IMPL_QUERY_INTERFACE9(_class, _i1, _i2, _i3, _i4, _i5, _i6, _i7, _i8, _i9) + +#define NS_IMPL_ISUPPORTS10(_class, _i1, _i2, _i3, _i4, _i5, _i6, _i7, _i8, \ + _i9, _i10) \ + NS_IMPL_ADDREF(_class) \ + NS_IMPL_RELEASE(_class) \ + NS_IMPL_QUERY_INTERFACE10(_class, _i1, _i2, _i3, _i4, _i5, _i6, _i7, _i8, \ + _i9, _i10) + +#define NS_IMPL_ISUPPORTS11(_class, _i1, _i2, _i3, _i4, _i5, _i6, _i7, _i8, \ + _i9, _i10, _i11) \ + NS_IMPL_ADDREF(_class) \ + NS_IMPL_RELEASE(_class) \ + NS_IMPL_QUERY_INTERFACE11(_class, _i1, _i2, _i3, _i4, _i5, _i6, _i7, _i8, \ + _i9, _i10, _i11) + +#define NS_IMPL_ISUPPORTS_INHERITED0(Class, Super) \ + NS_IMPL_QUERY_INTERFACE_INHERITED0(Class, Super) \ + NS_IMPL_ADDREF_INHERITED(Class, Super) \ + NS_IMPL_RELEASE_INHERITED(Class, Super) \ + +#define NS_IMPL_ISUPPORTS_INHERITED1(Class, Super, i1) \ + NS_IMPL_QUERY_INTERFACE_INHERITED1(Class, Super, i1) \ + NS_IMPL_ADDREF_INHERITED(Class, Super) \ + NS_IMPL_RELEASE_INHERITED(Class, Super) \ + +#define NS_IMPL_ISUPPORTS_INHERITED2(Class, Super, i1, i2) \ + NS_IMPL_QUERY_INTERFACE_INHERITED2(Class, Super, i1, i2) \ + NS_IMPL_ADDREF_INHERITED(Class, Super) \ + NS_IMPL_RELEASE_INHERITED(Class, Super) \ + +#define NS_IMPL_ISUPPORTS_INHERITED3(Class, Super, i1, i2, i3) \ + NS_IMPL_QUERY_INTERFACE_INHERITED3(Class, Super, i1, i2, i3) \ + NS_IMPL_ADDREF_INHERITED(Class, Super) \ + NS_IMPL_RELEASE_INHERITED(Class, Super) \ + +#define NS_IMPL_ISUPPORTS_INHERITED4(Class, Super, i1, i2, i3, i4) \ + NS_IMPL_QUERY_INTERFACE_INHERITED4(Class, Super, i1, i2, i3, i4) \ + NS_IMPL_ADDREF_INHERITED(Class, Super) \ + NS_IMPL_RELEASE_INHERITED(Class, Super) \ + +#define NS_IMPL_ISUPPORTS_INHERITED5(Class, Super, i1, i2, i3, i4, i5) \ + NS_IMPL_QUERY_INTERFACE_INHERITED5(Class, Super, i1, i2, i3, i4, i5) \ + NS_IMPL_ADDREF_INHERITED(Class, Super) \ + NS_IMPL_RELEASE_INHERITED(Class, Super) \ + +#define NS_IMPL_ISUPPORTS_INHERITED6(Class, Super, i1, i2, i3, i4, i5, i6) \ + NS_IMPL_QUERY_INTERFACE_INHERITED6(Class, Super, i1, i2, i3, i4, i5, i6) \ + NS_IMPL_ADDREF_INHERITED(Class, Super) \ + NS_IMPL_RELEASE_INHERITED(Class, Super) \ + +/////////////////////////////////////////////////////////////////////////////// +/** + * + * Threadsafe implementations of the ISupports convenience macros + * + */ + +/** + * Use this macro to implement the AddRef method for a given _class + * @param _class The name of the class implementing the method + */ + +#ifdef VBOX +#define NS_IMPL_THREADSAFE_ADDREF(_class) \ +NS_IMETHODIMP_(nsrefcnt) _class::AddRef(void) \ +{ \ + nsrefcnt count = mRefCnt.get(); \ + PRUint32 state = mRefCnt.getState(); \ + AssertReleaseMsg( state <= 1 \ + && ( (state == 0 && count == 0) \ + || (state == 1 && count < PR_UINT32_MAX/2)), \ + ("AddRef: illegal refcnt=%u state=%d\n", count, state)); \ + switch (state) \ + { \ + case 0: \ + if (!ASMAtomicCmpXchgU32(mRefCnt.refState(), 1, 0)) \ + AssertReleaseMsgFailed(("AddRef: racing for first increment\n")); \ + count = ASMAtomicIncU32(mRefCnt.ref()); \ + AssertReleaseMsg(count == 1, \ + ("AddRef: unexpected refcnt=%u\n", count)); \ + break; \ + case 1: \ + count = ASMAtomicIncU32(mRefCnt.ref()); \ + AssertReleaseMsg(count <= PR_UINT32_MAX/2, \ + ("AddRef: unexpected refcnt=%u\n", count)); \ + break; \ + case 2: \ + AssertReleaseMsgFailed(("AddRef: freed object\n")); \ + break; \ + default: \ + AssertReleaseMsgFailed(("AddRef: garbage object\n")); \ + } \ + NS_LOG_ADDREF(this, count, #_class, sizeof(*this)); \ + return count; \ +} +#else +#define NS_IMPL_THREADSAFE_ADDREF(_class) \ +NS_IMETHODIMP_(nsrefcnt) _class::AddRef(void) \ +{ \ + NS_PRECONDITION(PRInt32(mRefCnt) >= 0, "illegal refcnt"); \ + nsrefcnt count; \ + count = PR_AtomicIncrement((PRInt32*)&mRefCnt); \ + NS_LOG_ADDREF(this, count, #_class, sizeof(*this)); \ + return count; \ +} +#endif + +/** + * Use this macro to implement the Release method for a given _class + * @param _class The name of the class implementing the method + */ + +#ifdef VBOX +#define NS_IMPL_THREADSAFE_RELEASE(_class) \ +NS_IMETHODIMP_(nsrefcnt) _class::Release(void) \ +{ \ + nsrefcnt count = mRefCnt.get(); \ + PRUint32 state = mRefCnt.getState(); \ + AssertReleaseMsg(state == 1 && count <= PR_UINT32_MAX/2, \ + ("Release: illegal refcnt=%u state=%d\n", count, state)); \ + switch (state) \ + { \ + case 0: \ + AssertReleaseMsgFailed(("Release: new object\n")); \ + break; \ + case 1: \ + count = ASMAtomicDecU32(mRefCnt.ref()); \ + AssertReleaseMsg(count < PR_UINT32_MAX/2, \ + ("Release: unexpected refcnt=%u\n", count)); \ + if (count == 0) \ + { \ + if (!ASMAtomicCmpXchgU32(mRefCnt.refState(), 2, 1)) \ + AssertReleaseMsgFailed(("Release: racing for state free\n")); \ + /* Use better stabilization: reserve everything with top bit set. */ \ + if (!ASMAtomicCmpXchgU32(mRefCnt.ref(), PR_UINT32_MAX/4*3, 0)) \ + AssertReleaseMsgFailed(("Release: racing for refcnt stabilize\n")); \ + NS_DELETEXPCOM(this); \ + } \ + break; \ + case 2: \ + AssertReleaseMsgFailed(("Release: freed object\n")); \ + break; \ + default: \ + AssertReleaseMsgFailed(("Release: garbage object\n")); \ + } \ + NS_LOG_RELEASE(this, count, #_class); \ + return count; \ +} +#else +#define NS_IMPL_THREADSAFE_RELEASE(_class) \ +NS_IMETHODIMP_(nsrefcnt) _class::Release(void) \ +{ \ + nsrefcnt count; \ + NS_PRECONDITION(0 != mRefCnt, "dup release"); \ + count = PR_AtomicDecrement((PRInt32 *)&mRefCnt); \ + NS_LOG_RELEASE(this, count, #_class); \ + if (0 == count) { \ + mRefCnt = 1; /* stabilize */ \ + /* enable this to find non-threadsafe destructors: */ \ + /* NS_ASSERT_OWNINGTHREAD(_class); */ \ + NS_DELETEXPCOM(this); \ + return 0; \ + } \ + return count; \ +} +#endif + +#define NS_IMPL_THREADSAFE_ISUPPORTS0(_class) \ + NS_IMPL_THREADSAFE_ADDREF(_class) \ + NS_IMPL_THREADSAFE_RELEASE(_class) \ + NS_IMPL_THREADSAFE_QUERY_INTERFACE0(_class) + +#define NS_IMPL_THREADSAFE_ISUPPORTS1(_class, _interface) \ + NS_IMPL_THREADSAFE_ADDREF(_class) \ + NS_IMPL_THREADSAFE_RELEASE(_class) \ + NS_IMPL_THREADSAFE_QUERY_INTERFACE1(_class, _interface) + +#define NS_IMPL_THREADSAFE_ISUPPORTS2(_class, _i1, _i2) \ + NS_IMPL_THREADSAFE_ADDREF(_class) \ + NS_IMPL_THREADSAFE_RELEASE(_class) \ + NS_IMPL_THREADSAFE_QUERY_INTERFACE2(_class, _i1, _i2) + +#define NS_IMPL_THREADSAFE_ISUPPORTS3(_class, _i1, _i2, _i3) \ + NS_IMPL_THREADSAFE_ADDREF(_class) \ + NS_IMPL_THREADSAFE_RELEASE(_class) \ + NS_IMPL_THREADSAFE_QUERY_INTERFACE3(_class, _i1, _i2, _i3) + +#define NS_IMPL_THREADSAFE_ISUPPORTS4(_class, _i1, _i2, _i3, _i4) \ + NS_IMPL_THREADSAFE_ADDREF(_class) \ + NS_IMPL_THREADSAFE_RELEASE(_class) \ + NS_IMPL_THREADSAFE_QUERY_INTERFACE4(_class, _i1, _i2, _i3, _i4) + +#define NS_IMPL_THREADSAFE_ISUPPORTS5(_class, _i1, _i2, _i3, _i4, _i5) \ + NS_IMPL_THREADSAFE_ADDREF(_class) \ + NS_IMPL_THREADSAFE_RELEASE(_class) \ + NS_IMPL_THREADSAFE_QUERY_INTERFACE5(_class, _i1, _i2, _i3, _i4, _i5) + +#define NS_IMPL_THREADSAFE_ISUPPORTS6(_class, _i1, _i2, _i3, _i4, _i5, _i6) \ + NS_IMPL_THREADSAFE_ADDREF(_class) \ + NS_IMPL_THREADSAFE_RELEASE(_class) \ + NS_IMPL_THREADSAFE_QUERY_INTERFACE6(_class, _i1, _i2, _i3, _i4, _i5, _i6) + +#define NS_IMPL_THREADSAFE_ISUPPORTS7(_class, _i1, _i2, _i3, _i4, _i5, _i6, \ + _i7) \ + NS_IMPL_THREADSAFE_ADDREF(_class) \ + NS_IMPL_THREADSAFE_RELEASE(_class) \ + NS_IMPL_THREADSAFE_QUERY_INTERFACE7(_class, _i1, _i2, _i3, _i4, _i5, _i6, \ + _i7) + +#define NS_IMPL_THREADSAFE_ISUPPORTS8(_class, _i1, _i2, _i3, _i4, _i5, _i6, \ + _i7, _i8) \ + NS_IMPL_THREADSAFE_ADDREF(_class) \ + NS_IMPL_THREADSAFE_RELEASE(_class) \ + NS_IMPL_THREADSAFE_QUERY_INTERFACE8(_class, _i1, _i2, _i3, _i4, _i5, _i6, \ + _i7, _i8) + +#define NS_IMPL_THREADSAFE_ISUPPORTS9(_class, _i1, _i2, _i3, _i4, _i5, _i6, \ + _i7, _i8, _i9) \ + NS_IMPL_THREADSAFE_ADDREF(_class) \ + NS_IMPL_THREADSAFE_RELEASE(_class) \ + NS_IMPL_THREADSAFE_QUERY_INTERFACE9(_class, _i1, _i2, _i3, _i4, _i5, _i6, \ + _i7, _i8, _i9) + +#define NS_IMPL_THREADSAFE_ISUPPORTS10(_class, _i1, _i2, _i3, _i4, _i5, _i6, \ + _i7, _i8, _i9, _i10) \ + NS_IMPL_THREADSAFE_ADDREF(_class) \ + NS_IMPL_THREADSAFE_RELEASE(_class) \ + NS_IMPL_THREADSAFE_QUERY_INTERFACE10(_class, _i1, _i2, _i3, _i4, _i5, _i6, \ + _i7, _i8, _i9, _i10) + +#define NS_IMPL_THREADSAFE_ISUPPORTS11(_class, _i1, _i2, _i3, _i4, _i5, _i6, \ + _i7, _i8, _i9, _i10, _i11) \ + NS_IMPL_THREADSAFE_ADDREF(_class) \ + NS_IMPL_THREADSAFE_RELEASE(_class) \ + NS_IMPL_THREADSAFE_QUERY_INTERFACE11(_class, _i1, _i2, _i3, _i4, _i5, _i6, \ + _i7, _i8, _i9, _i10, _i11) + +/////////////////////////////////////////////////////////////////////////////// +// Macros for implementing nsIClassInfo-related stuff. +/////////////////////////////////////////////////////////////////////////////// + +// include here instead of at the top because it requires the nsISupport decl +#include "nsIClassInfo.h" + +#define NS_CLASSINFO_NAME(_class) _class##_classInfoGlobal +#define NS_CI_INTERFACE_GETTER_NAME(_class) _class##_GetInterfacesHelper + +#define NS_DECL_CI_INTERFACE_GETTER(_class) \ + extern NS_IMETHODIMP NS_CI_INTERFACE_GETTER_NAME(_class)(PRUint32 *, \ + nsIID ***); + +#define NS_DECL_CLASSINFO(_class) \ + NS_DECL_CI_INTERFACE_GETTER(_class) \ + nsIClassInfo *NS_CLASSINFO_NAME(_class); + +#define NS_IMPL_QUERY_CLASSINFO(_class) \ + if ( aIID.Equals(NS_GET_IID(nsIClassInfo)) ) { \ + extern nsIClassInfo *NS_CLASSINFO_NAME(_class); \ + foundInterface = NS_STATIC_CAST(nsIClassInfo*, NS_CLASSINFO_NAME(_class));\ + } else + +#define NS_CLASSINFO_HELPER_BEGIN(_class, _c) \ +NS_IMETHODIMP \ +NS_CI_INTERFACE_GETTER_NAME(_class)(PRUint32 *count, nsIID ***array) \ +{ \ + *count = _c; \ + *array = (nsIID **)nsMemory::Alloc(sizeof (nsIID *) * _c); + +#define NS_CLASSINFO_HELPER_ENTRY(_i, _interface) \ + (*array)[_i] = (nsIID *)nsMemory::Clone(&NS_GET_IID(_interface), \ + sizeof(nsIID)); + +#define NS_CLASSINFO_HELPER_END \ + return NS_OK; \ +} + +#define NS_IMPL_CI_INTERFACE_GETTER1(_class, _interface) \ + NS_CLASSINFO_HELPER_BEGIN(_class, 1) \ + NS_CLASSINFO_HELPER_ENTRY(0, _interface) \ + NS_CLASSINFO_HELPER_END + +#define NS_IMPL_QUERY_INTERFACE1_CI(_class, _i1) \ + NS_INTERFACE_MAP_BEGIN(_class) \ + NS_INTERFACE_MAP_ENTRY(_i1) \ + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, _i1) \ + NS_IMPL_QUERY_CLASSINFO(_class) \ + NS_INTERFACE_MAP_END + +#define NS_IMPL_ISUPPORTS1_CI(_class, _interface) \ + NS_IMPL_ADDREF(_class) \ + NS_IMPL_RELEASE(_class) \ + NS_IMPL_QUERY_INTERFACE1_CI(_class, _interface) \ + NS_IMPL_CI_INTERFACE_GETTER1(_class, _interface) + +#define NS_IMPL_CI_INTERFACE_GETTER2(_class, _i1, _i2) \ + NS_CLASSINFO_HELPER_BEGIN(_class, 2) \ + NS_CLASSINFO_HELPER_ENTRY(0, _i1) \ + NS_CLASSINFO_HELPER_ENTRY(1, _i2) \ + NS_CLASSINFO_HELPER_END + +#define NS_IMPL_QUERY_INTERFACE2_CI(_class, _i1, _i2) \ + NS_INTERFACE_MAP_BEGIN(_class) \ + NS_INTERFACE_MAP_ENTRY(_i1) \ + NS_INTERFACE_MAP_ENTRY(_i2) \ + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, _i1) \ + NS_IMPL_QUERY_CLASSINFO(_class) \ + NS_INTERFACE_MAP_END + +#define NS_IMPL_ISUPPORTS2_CI(_class, _i1, _i2) \ + NS_IMPL_ADDREF(_class) \ + NS_IMPL_RELEASE(_class) \ + NS_IMPL_QUERY_INTERFACE2_CI(_class, _i1, _i2) \ + NS_IMPL_CI_INTERFACE_GETTER2(_class, _i1, _i2) + +#define NS_IMPL_CI_INTERFACE_GETTER3(_class, _i1, _i2, _i3) \ + NS_CLASSINFO_HELPER_BEGIN(_class, 3) \ + NS_CLASSINFO_HELPER_ENTRY(0, _i1) \ + NS_CLASSINFO_HELPER_ENTRY(1, _i2) \ + NS_CLASSINFO_HELPER_ENTRY(2, _i3) \ + NS_CLASSINFO_HELPER_END + +#define NS_IMPL_QUERY_INTERFACE3_CI(_class, _i1, _i2, _i3) \ + NS_INTERFACE_MAP_BEGIN(_class) \ + NS_INTERFACE_MAP_ENTRY(_i1) \ + NS_INTERFACE_MAP_ENTRY(_i2) \ + NS_INTERFACE_MAP_ENTRY(_i3) \ + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, _i1) \ + NS_IMPL_QUERY_CLASSINFO(_class) \ + NS_INTERFACE_MAP_END + +#define NS_IMPL_ISUPPORTS3_CI(_class, _i1, _i2, _i3) \ + NS_IMPL_ADDREF(_class) \ + NS_IMPL_RELEASE(_class) \ + NS_IMPL_QUERY_INTERFACE3_CI(_class, _i1, _i2, _i3) \ + NS_IMPL_CI_INTERFACE_GETTER3(_class, _i1, _i2, _i3) + +#define NS_IMPL_CI_INTERFACE_GETTER4(_class, _i1, _i2, _i3, _i4) \ + NS_CLASSINFO_HELPER_BEGIN(_class, 4) \ + NS_CLASSINFO_HELPER_ENTRY(0, _i1) \ + NS_CLASSINFO_HELPER_ENTRY(1, _i2) \ + NS_CLASSINFO_HELPER_ENTRY(2, _i3) \ + NS_CLASSINFO_HELPER_ENTRY(3, _i4) \ + NS_CLASSINFO_HELPER_END + +#define NS_IMPL_QUERY_INTERFACE4_CI(_class, _i1, _i2, _i3, _i4) \ + NS_INTERFACE_MAP_BEGIN(_class) \ + NS_INTERFACE_MAP_ENTRY(_i1) \ + NS_INTERFACE_MAP_ENTRY(_i2) \ + NS_INTERFACE_MAP_ENTRY(_i3) \ + NS_INTERFACE_MAP_ENTRY(_i4) \ + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, _i1) \ + NS_IMPL_QUERY_CLASSINFO(_class) \ + NS_INTERFACE_MAP_END + +#define NS_IMPL_ISUPPORTS4_CI(_class, _i1, _i2, _i3, _i4) \ + NS_IMPL_ADDREF(_class) \ + NS_IMPL_RELEASE(_class) \ + NS_IMPL_QUERY_INTERFACE4_CI(_class, _i1, _i2, _i3, _i4) \ + NS_IMPL_CI_INTERFACE_GETTER4(_class, _i1, _i2, _i3, _i4) + +#define NS_IMPL_CI_INTERFACE_GETTER5(_class, _i1, _i2, _i3, _i4, _i5) \ + NS_CLASSINFO_HELPER_BEGIN(_class, 5) \ + NS_CLASSINFO_HELPER_ENTRY(0, _i1) \ + NS_CLASSINFO_HELPER_ENTRY(1, _i2) \ + NS_CLASSINFO_HELPER_ENTRY(2, _i3) \ + NS_CLASSINFO_HELPER_ENTRY(3, _i4) \ + NS_CLASSINFO_HELPER_ENTRY(4, _i5) \ + NS_CLASSINFO_HELPER_END + +#define NS_IMPL_QUERY_INTERFACE5_CI(_class, _i1, _i2, _i3, _i4, _i5) \ + NS_INTERFACE_MAP_BEGIN(_class) \ + NS_INTERFACE_MAP_ENTRY(_i1) \ + NS_INTERFACE_MAP_ENTRY(_i2) \ + NS_INTERFACE_MAP_ENTRY(_i3) \ + NS_INTERFACE_MAP_ENTRY(_i4) \ + NS_INTERFACE_MAP_ENTRY(_i5) \ + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, _i1) \ + NS_IMPL_QUERY_CLASSINFO(_class) \ + NS_INTERFACE_MAP_END + +#define NS_IMPL_ISUPPORTS5_CI(_class, _i1, _i2, _i3, _i4, _i5) \ + NS_IMPL_ADDREF(_class) \ + NS_IMPL_RELEASE(_class) \ + NS_IMPL_QUERY_INTERFACE5_CI(_class, _i1, _i2, _i3, _i4, _i5) \ + NS_IMPL_CI_INTERFACE_GETTER5(_class, _i1, _i2, _i3, _i4, _i5) + +#define NS_IMPL_CI_INTERFACE_GETTER6(_class, _i1, _i2, _i3, _i4, _i5, _i6) \ + NS_CLASSINFO_HELPER_BEGIN(_class, 6) \ + NS_CLASSINFO_HELPER_ENTRY(0, _i1) \ + NS_CLASSINFO_HELPER_ENTRY(1, _i2) \ + NS_CLASSINFO_HELPER_ENTRY(2, _i3) \ + NS_CLASSINFO_HELPER_ENTRY(3, _i4) \ + NS_CLASSINFO_HELPER_ENTRY(4, _i5) \ + NS_CLASSINFO_HELPER_ENTRY(5, _i6) \ + NS_CLASSINFO_HELPER_END + +#define NS_IMPL_QUERY_INTERFACE6_CI(_class, _i1, _i2, _i3, _i4, _i5, _i6) \ + NS_INTERFACE_MAP_BEGIN(_class) \ + NS_INTERFACE_MAP_ENTRY(_i1) \ + NS_INTERFACE_MAP_ENTRY(_i2) \ + NS_INTERFACE_MAP_ENTRY(_i3) \ + NS_INTERFACE_MAP_ENTRY(_i4) \ + NS_INTERFACE_MAP_ENTRY(_i5) \ + NS_INTERFACE_MAP_ENTRY(_i6) \ + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, _i1) \ + NS_IMPL_QUERY_CLASSINFO(_class) \ + NS_INTERFACE_MAP_END + +#define NS_IMPL_ISUPPORTS6_CI(_class, _i1, _i2, _i3, _i4, _i5, _i6) \ + NS_IMPL_ADDREF(_class) \ + NS_IMPL_RELEASE(_class) \ + NS_IMPL_QUERY_INTERFACE6_CI(_class, _i1, _i2, _i3, _i4, _i5, _i6) \ + NS_IMPL_CI_INTERFACE_GETTER6(_class, _i1, _i2, _i3, _i4, _i5, _i6) + +#define NS_IMPL_CI_INTERFACE_GETTER7(_class, _i1, _i2, _i3, _i4, _i5, _i6, \ + _i7) \ + NS_CLASSINFO_HELPER_BEGIN(_class, 7) \ + NS_CLASSINFO_HELPER_ENTRY(0, _i1) \ + NS_CLASSINFO_HELPER_ENTRY(1, _i2) \ + NS_CLASSINFO_HELPER_ENTRY(2, _i3) \ + NS_CLASSINFO_HELPER_ENTRY(3, _i4) \ + NS_CLASSINFO_HELPER_ENTRY(4, _i5) \ + NS_CLASSINFO_HELPER_ENTRY(5, _i6) \ + NS_CLASSINFO_HELPER_ENTRY(6, _i7) \ + NS_CLASSINFO_HELPER_END + +#define NS_IMPL_QUERY_INTERFACE7_CI(_class, _i1, _i2, _i3, _i4, _i5, _i6, \ + _i7) \ + NS_INTERFACE_MAP_BEGIN(_class) \ + NS_INTERFACE_MAP_ENTRY(_i1) \ + NS_INTERFACE_MAP_ENTRY(_i2) \ + NS_INTERFACE_MAP_ENTRY(_i3) \ + NS_INTERFACE_MAP_ENTRY(_i4) \ + NS_INTERFACE_MAP_ENTRY(_i5) \ + NS_INTERFACE_MAP_ENTRY(_i6) \ + NS_INTERFACE_MAP_ENTRY(_i7) \ + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, _i1) \ + NS_IMPL_QUERY_CLASSINFO(_class) \ + NS_INTERFACE_MAP_END + +#define NS_IMPL_ISUPPORTS7_CI(_class, _i1, _i2, _i3, _i4, _i5, _i6, _i7) \ + NS_IMPL_ADDREF(_class) \ + NS_IMPL_RELEASE(_class) \ + NS_IMPL_QUERY_INTERFACE7_CI(_class, _i1, _i2, _i3, _i4, _i5, _i6, _i7) \ + NS_IMPL_CI_INTERFACE_GETTER7(_class, _i1, _i2, _i3, _i4, _i5, _i6, _i7) + +#define NS_IMPL_CI_INTERFACE_GETTER8(_class, _i1, _i2, _i3, _i4, _i5, _i6, \ + _i7, _i8) \ + NS_CLASSINFO_HELPER_BEGIN(_class, 8) \ + NS_CLASSINFO_HELPER_ENTRY(0, _i1) \ + NS_CLASSINFO_HELPER_ENTRY(1, _i2) \ + NS_CLASSINFO_HELPER_ENTRY(2, _i3) \ + NS_CLASSINFO_HELPER_ENTRY(3, _i4) \ + NS_CLASSINFO_HELPER_ENTRY(4, _i5) \ + NS_CLASSINFO_HELPER_ENTRY(5, _i6) \ + NS_CLASSINFO_HELPER_ENTRY(6, _i7) \ + NS_CLASSINFO_HELPER_ENTRY(7, _i8) \ + NS_CLASSINFO_HELPER_END + +#define NS_IMPL_QUERY_INTERFACE8_CI(_class, _i1, _i2, _i3, _i4, _i5, _i6, \ + _i7, _i8) \ + NS_INTERFACE_MAP_BEGIN(_class) \ + NS_INTERFACE_MAP_ENTRY(_i1) \ + NS_INTERFACE_MAP_ENTRY(_i2) \ + NS_INTERFACE_MAP_ENTRY(_i3) \ + NS_INTERFACE_MAP_ENTRY(_i4) \ + NS_INTERFACE_MAP_ENTRY(_i5) \ + NS_INTERFACE_MAP_ENTRY(_i6) \ + NS_INTERFACE_MAP_ENTRY(_i7) \ + NS_INTERFACE_MAP_ENTRY(_i8) \ + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, _i1) \ + NS_IMPL_QUERY_CLASSINFO(_class) \ + NS_INTERFACE_MAP_END + +#define NS_IMPL_ISUPPORTS8_CI(_class, _i1, _i2, _i3, _i4, _i5, _i6, _i7, _i8) \ + NS_IMPL_ADDREF(_class) \ + NS_IMPL_RELEASE(_class) \ + NS_IMPL_QUERY_INTERFACE8_CI(_class, _i1, _i2, _i3, _i4, _i5, _i6, _i7, _i8) \ + NS_IMPL_CI_INTERFACE_GETTER8(_class, _i1, _i2, _i3, _i4, _i5, _i6, _i7, _i8) + +#define NS_IMPL_CI_INTERFACE_GETTER9(_class, _i1, _i2, _i3, _i4, _i5, _i6, \ + _i7, _i8, _i9) \ + NS_CLASSINFO_HELPER_BEGIN(_class, 9) \ + NS_CLASSINFO_HELPER_ENTRY(0, _i1) \ + NS_CLASSINFO_HELPER_ENTRY(1, _i2) \ + NS_CLASSINFO_HELPER_ENTRY(2, _i3) \ + NS_CLASSINFO_HELPER_ENTRY(3, _i4) \ + NS_CLASSINFO_HELPER_ENTRY(4, _i5) \ + NS_CLASSINFO_HELPER_ENTRY(5, _i6) \ + NS_CLASSINFO_HELPER_ENTRY(6, _i7) \ + NS_CLASSINFO_HELPER_ENTRY(7, _i8) \ + NS_CLASSINFO_HELPER_ENTRY(8, _i9) \ + NS_CLASSINFO_HELPER_END + +#define NS_IMPL_QUERY_INTERFACE9_CI(_class, _i1, _i2, _i3, _i4, _i5, _i6, \ + _i7, _i8, _i9) \ + NS_INTERFACE_MAP_BEGIN(_class) \ + NS_INTERFACE_MAP_ENTRY(_i1) \ + NS_INTERFACE_MAP_ENTRY(_i2) \ + NS_INTERFACE_MAP_ENTRY(_i3) \ + NS_INTERFACE_MAP_ENTRY(_i4) \ + NS_INTERFACE_MAP_ENTRY(_i5) \ + NS_INTERFACE_MAP_ENTRY(_i6) \ + NS_INTERFACE_MAP_ENTRY(_i7) \ + NS_INTERFACE_MAP_ENTRY(_i8) \ + NS_INTERFACE_MAP_ENTRY(_i9) \ + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, _i1) \ + NS_IMPL_QUERY_CLASSINFO(_class) \ + NS_INTERFACE_MAP_END + +#define NS_IMPL_ISUPPORTS9_CI(_class, _i1, _i2, _i3, _i4, _i5, _i6, _i7, \ + _i8, _i9) \ + NS_IMPL_ADDREF(_class) \ + NS_IMPL_RELEASE(_class) \ + NS_IMPL_QUERY_INTERFACE9_CI(_class, _i1, _i2, _i3, _i4, _i5, _i6, _i7, \ + _i8, _i9) \ + NS_IMPL_CI_INTERFACE_GETTER9(_class, _i1, _i2, _i3, _i4, _i5, _i6, _i7, \ + _i8, _i9) + +#define NS_IMPL_CI_INTERFACE_GETTER10(_class, _i1, _i2, _i3, _i4, _i5, _i6, \ + _i7, _i8, _i9, _i10) \ + NS_CLASSINFO_HELPER_BEGIN(_class, 10) \ + NS_CLASSINFO_HELPER_ENTRY(0, _i1) \ + NS_CLASSINFO_HELPER_ENTRY(1, _i2) \ + NS_CLASSINFO_HELPER_ENTRY(2, _i3) \ + NS_CLASSINFO_HELPER_ENTRY(3, _i4) \ + NS_CLASSINFO_HELPER_ENTRY(4, _i5) \ + NS_CLASSINFO_HELPER_ENTRY(5, _i6) \ + NS_CLASSINFO_HELPER_ENTRY(6, _i7) \ + NS_CLASSINFO_HELPER_ENTRY(7, _i8) \ + NS_CLASSINFO_HELPER_ENTRY(8, _i9) \ + NS_CLASSINFO_HELPER_ENTRY(9, _i10) \ + NS_CLASSINFO_HELPER_END + +#define NS_IMPL_CI_INTERFACE_GETTER11(_class, _i1, _i2, _i3, _i4, _i5, _i6, \ + _i7, _i8, _i9, _i10, _i11) \ + NS_CLASSINFO_HELPER_BEGIN(_class, 10) \ + NS_CLASSINFO_HELPER_ENTRY(0, _i1) \ + NS_CLASSINFO_HELPER_ENTRY(1, _i2) \ + NS_CLASSINFO_HELPER_ENTRY(2, _i3) \ + NS_CLASSINFO_HELPER_ENTRY(3, _i4) \ + NS_CLASSINFO_HELPER_ENTRY(4, _i5) \ + NS_CLASSINFO_HELPER_ENTRY(5, _i6) \ + NS_CLASSINFO_HELPER_ENTRY(6, _i7) \ + NS_CLASSINFO_HELPER_ENTRY(7, _i8) \ + NS_CLASSINFO_HELPER_ENTRY(8, _i9) \ + NS_CLASSINFO_HELPER_ENTRY(9, _i10) \ + NS_CLASSINFO_HELPER_ENTRY(10, _i11) \ + NS_CLASSINFO_HELPER_END + +#define NS_IMPL_QUERY_INTERFACE10_CI(_class, _i1, _i2, _i3, _i4, _i5, _i6, \ + _i7, _i8, _i9, _i10) \ + NS_INTERFACE_MAP_BEGIN(_class) \ + NS_INTERFACE_MAP_ENTRY(_i1) \ + NS_INTERFACE_MAP_ENTRY(_i2) \ + NS_INTERFACE_MAP_ENTRY(_i3) \ + NS_INTERFACE_MAP_ENTRY(_i4) \ + NS_INTERFACE_MAP_ENTRY(_i5) \ + NS_INTERFACE_MAP_ENTRY(_i6) \ + NS_INTERFACE_MAP_ENTRY(_i7) \ + NS_INTERFACE_MAP_ENTRY(_i8) \ + NS_INTERFACE_MAP_ENTRY(_i9) \ + NS_INTERFACE_MAP_ENTRY(_i10) \ + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, _i1) \ + NS_IMPL_QUERY_CLASSINFO(_class) \ + NS_INTERFACE_MAP_END + +#define NS_IMPL_QUERY_INTERFACE11_CI(_class, _i1, _i2, _i3, _i4, _i5, _i6, \ + _i7, _i8, _i9, _i10, _i11) \ + NS_INTERFACE_MAP_BEGIN(_class) \ + NS_INTERFACE_MAP_ENTRY(_i1) \ + NS_INTERFACE_MAP_ENTRY(_i2) \ + NS_INTERFACE_MAP_ENTRY(_i3) \ + NS_INTERFACE_MAP_ENTRY(_i4) \ + NS_INTERFACE_MAP_ENTRY(_i5) \ + NS_INTERFACE_MAP_ENTRY(_i6) \ + NS_INTERFACE_MAP_ENTRY(_i7) \ + NS_INTERFACE_MAP_ENTRY(_i8) \ + NS_INTERFACE_MAP_ENTRY(_i9) \ + NS_INTERFACE_MAP_ENTRY(_i10) \ + NS_INTERFACE_MAP_ENTRY(_i11) \ + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, _i1) \ + NS_IMPL_QUERY_CLASSINFO(_class) \ + NS_INTERFACE_MAP_END + +#define NS_IMPL_ISUPPORTS10_CI(_class, _i1, _i2, _i3, _i4, _i5, _i6, _i7, \ + _i8, _i9, _i10) \ + NS_IMPL_ADDREF(_class) \ + NS_IMPL_RELEASE(_class) \ + NS_IMPL_QUERY_INTERFACE10_CI(_class, _i1, _i2, _i3, _i4, _i5, _i6, _i7, \ + _i8, _i9, _i10) \ + NS_IMPL_CI_INTERFACE_GETTER10(_class, _i1, _i2, _i3, _i4, _i5, _i6, _i7, \ + _i8, _i9, _i10) + +#define NS_IMPL_ISUPPORTS11_CI(_class, _i1, _i2, _i3, _i4, _i5, _i6, _i7, \ + _i8, _i9, _i10, _i11) \ + NS_IMPL_ADDREF(_class) \ + NS_IMPL_RELEASE(_class) \ + NS_IMPL_QUERY_INTERFACE11_CI(_class, _i1, _i2, _i3, _i4, _i5, _i6, _i7, \ + _i8, _i9, _i10, _i11) \ + NS_IMPL_CI_INTERFACE_GETTER11(_class, _i1, _i2, _i3, _i4, _i5, _i6, _i7, \ + _i8, _i9, _i10, _i11) + +#define NS_INTERFACE_MAP_END_THREADSAFE NS_IMPL_QUERY_TAIL_GUTS + +#endif diff --git a/src/libs/xpcom18a4/xpcom/glue/nsISupportsUtils.h b/src/libs/xpcom18a4/xpcom/glue/nsISupportsUtils.h new file mode 100644 index 00000000..d8d002b1 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/glue/nsISupportsUtils.h @@ -0,0 +1,230 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Pierre Phaneuf + * Scott Collins + * Dan Mosedale + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +#ifndef nsISupportsUtils_h__ +#define nsISupportsUtils_h__ + +#ifndef nscore_h___ +#include "nscore.h" +#endif + +#ifndef nsISupportsBase_h__ +#include "nsISupportsBase.h" +#endif + +#ifndef nsError_h__ +#include "nsError.h" +#endif + +#ifndef nsDebug_h___ +#include "nsDebug.h" +#endif + +#ifndef nsISupportsImpl_h__ +#include "nsISupportsImpl.h" +#endif + +/** + * Macro for instantiating a new object that implements nsISupports. + * Note that you can only use this if you adhere to the no arguments + * constructor com policy (which you really should!). + * @param _result Where the new instance pointer is stored + * @param _type The type of object to call "new" with. + */ +#define NS_NEWXPCOM(_result,_type) \ + PR_BEGIN_MACRO \ + _result = new _type(); \ + PR_END_MACRO + +/** + * Macro for deleting an object that implements nsISupports. + * @param _ptr The object to delete. + */ +#define NS_DELETEXPCOM(_ptr) \ + PR_BEGIN_MACRO \ + delete (_ptr); \ + PR_END_MACRO + +/** + * Macro for adding a reference to an interface. + * @param _ptr The interface pointer. + */ +#define NS_ADDREF(_ptr) \ + (_ptr)->AddRef() + +/** + * Macro for adding a reference to this. This macro should be used + * because NS_ADDREF (when tracing) may require an ambiguous cast + * from the pointers primary type to nsISupports. This macro sidesteps + * that entire problem. + */ +#define NS_ADDREF_THIS() \ + AddRef() + + +extern "C++" { +// ...because some one is accidentally including this file inside +// an |extern "C"| + + +// Making this a |inline| |template| allows |expr| to be evaluated only once, +// yet still denies you the ability to |AddRef()| an |nsCOMPtr|. +template +inline +nsrefcnt +ns_if_addref( T expr ) +{ + return expr ? expr->AddRef() : 0; +} + +} /* extern "C++" */ + +/** + * Macro for adding a reference to an interface that checks for NULL. + * @param _expr The interface pointer. + */ +#define NS_IF_ADDREF(_expr) ns_if_addref(_expr) + +/* + * Given these declarations, it explicitly OK and efficient to end a `getter' with: + * + * NS_IF_ADDREF(*result = mThing); + * + * even if |mThing| is an |nsCOMPtr|. If |mThing| is an |nsCOMPtr|, however, it is still + * _illegal_ to say |NS_IF_ADDREF(mThing)|. + */ + +/** + * Macro for releasing a reference to an interface. + * @param _ptr The interface pointer. + */ +#define NS_RELEASE(_ptr) \ + PR_BEGIN_MACRO \ + (_ptr)->Release(); \ + (_ptr) = 0; \ + PR_END_MACRO + +/** + * Macro for releasing a reference to an interface. + * @param _ptr The interface pointer. + */ +#define NS_RELEASE_THIS() \ + Release() + +/** + * Macro for releasing a reference to an interface, except that this + * macro preserves the return value from the underlying Release call. + * The interface pointer argument will only be NULLed if the reference count + * goes to zero. + * + * @param _ptr The interface pointer. + */ +#define NS_RELEASE2(_ptr,_rv) \ + PR_BEGIN_MACRO \ + _rv = (_ptr)->Release(); \ + if (0 == (_rv)) (_ptr) = 0; \ + PR_END_MACRO + +/** + * Macro for releasing a reference to an interface that checks for NULL; + * @param _ptr The interface pointer. + */ +#define NS_IF_RELEASE(_ptr) \ + PR_BEGIN_MACRO \ + if (_ptr) { \ + (_ptr)->Release(); \ + (_ptr) = 0; \ + } \ + PR_END_MACRO + +/* + * Often you have to cast an implementation pointer, e.g., |this|, to an + * |nsISupports*|, but because you have multiple inheritance, a simple cast + * is ambiguous. One could simply say, e.g., (given a base |nsIBase|), + * |NS_STATIC_CAST(nsIBase*, this)|; but that disguises the fact that what + * you are really doing is disambiguating the |nsISupports|. You could make + * that more obvious with a double cast, e.g., |NS_STATIC_CAST(nsISupports*, + * NS_STATIC_CAST(nsIBase*, this))|, but that is bulky and harder to read... + * + * The following macro is clean, short, and obvious. In the example above, + * you would use it like this: |NS_ISUPPORTS_CAST(nsIBase*, this)|. + */ + +#define NS_ISUPPORTS_CAST(__unambiguousBase, __expr) \ + NS_STATIC_CAST(nsISupports*, NS_STATIC_CAST(__unambiguousBase, __expr)) + +extern "C++" { +// ...because some one is accidentally including this file inside +// an |extern "C"| + +class nsISupports; + +template +struct nsCOMTypeInfo +{ + static const nsIID& GetIID() { return T::GetIID(); } +}; + +NS_SPECIALIZE_TEMPLATE +struct nsCOMTypeInfo +{ + static const nsIID& GetIID() { + static const nsIID iid_NS_ISUPPORTS_IID = NS_ISUPPORTS_IID; return iid_NS_ISUPPORTS_IID; + } +}; + +#define NS_GET_IID(T) nsCOMTypeInfo::GetIID() + +// a type-safe shortcut for calling the |QueryInterface()| member function +template +inline +nsresult +CallQueryInterface( T* aSource, DestinationType** aDestination ) +{ + NS_PRECONDITION(aSource, "null parameter"); + NS_PRECONDITION(aDestination, "null parameter"); + + return aSource->QueryInterface(NS_GET_IID(DestinationType), + NS_REINTERPRET_CAST(void**, aDestination)); +} + +} // extern "C++" + +#endif /* __nsISupportsUtils_h */ diff --git a/src/libs/xpcom18a4/xpcom/glue/nsIWeakReferenceUtils.h b/src/libs/xpcom18a4/xpcom/glue/nsIWeakReferenceUtils.h new file mode 100644 index 00000000..17d1bd79 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/glue/nsIWeakReferenceUtils.h @@ -0,0 +1,162 @@ +/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Scott Collins (Original Author) + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +#ifndef nsIWeakReferenceUtils_h__ +#define nsIWeakReferenceUtils_h__ + +#ifndef nsCOMPtr_h__ +#include "nsCOMPtr.h" +#endif + +typedef nsCOMPtr nsWeakPtr; + +/** + * + */ + +// a type-safe shortcut for calling the |QueryReferent()| member function +// T must inherit from nsIWeakReference, but the cast may be ambiguous. +template +inline +nsresult +CallQueryReferent( T* aSource, DestinationType** aDestination ) + { + NS_PRECONDITION(aSource, "null parameter"); + NS_PRECONDITION(aDestination, "null parameter"); + + return aSource->QueryReferent(NS_GET_IID(DestinationType), + NS_REINTERPRET_CAST(void**, aDestination)); + } + + +class NS_COM nsQueryReferent : public nsCOMPtr_helper + { + public: + nsQueryReferent( nsIWeakReference* aWeakPtr, nsresult* error ) + : mWeakPtr(aWeakPtr), + mErrorPtr(error) + { + // nothing else to do here + } + + virtual nsresult NS_FASTCALL operator()( const nsIID& aIID, void** ) const; + + private: + nsIWeakReference* mWeakPtr; + nsresult* mErrorPtr; + }; + +inline +const nsQueryReferent +do_QueryReferent( nsIWeakReference* aRawPtr, nsresult* error = 0 ) + { + return nsQueryReferent(aRawPtr, error); + } + + + +class NS_COM nsGetWeakReference : public nsCOMPtr_helper + { + public: + nsGetWeakReference( nsISupports* aRawPtr, nsresult* error ) + : mRawPtr(aRawPtr), + mErrorPtr(error) + { + // nothing else to do here + } + + virtual nsresult NS_FASTCALL operator()( const nsIID&, void** ) const; + + private: + nsISupports* mRawPtr; + nsresult* mErrorPtr; + }; + + /** + * |do_GetWeakReference| is a convenience function that bundles up all the work needed + * to get a weak reference to an arbitrary object, i.e., the |QueryInterface|, test, and + * call through to |GetWeakReference|, and put it into your |nsCOMPtr|. + * It is specifically designed to cooperate with |nsCOMPtr| (or |nsWeakPtr|) like so: + * |nsWeakPtr myWeakPtr = do_GetWeakReference(aPtr);|. + */ +inline +const nsGetWeakReference +do_GetWeakReference( nsISupports* aRawPtr, nsresult* error = 0 ) + { + return nsGetWeakReference(aRawPtr, error); + } + +inline +void +do_GetWeakReference( nsIWeakReference* aRawPtr, nsresult* error = 0 ) + { + // This signature exists soley to _stop_ you from doing a bad thing. + // Saying |do_GetWeakReference()| on a weak reference itself, + // is very likely to be a programmer error. + } + +template +inline +void +do_GetWeakReference( already_AddRefed& ) + { + // This signature exists soley to _stop_ you from doing the bad thing. + // Saying |do_GetWeakReference()| on a pointer that is not otherwise owned by + // someone else is an automatic leak. See . + } + +template +inline +void +do_GetWeakReference( already_AddRefed&, nsresult* ) + { + // This signature exists soley to _stop_ you from doing the bad thing. + // Saying |do_GetWeakReference()| on a pointer that is not otherwise owned by + // someone else is an automatic leak. See . + } + + + + /** + * Deprecated, use |do_GetWeakReference| instead. + */ +extern NS_COM +nsIWeakReference* +NS_GetWeakReference( nsISupports* , nsresult* aResult=0 ); + +#endif diff --git a/src/libs/xpcom18a4/xpcom/glue/nsMemory.cpp b/src/libs/xpcom18a4/xpcom/glue/nsMemory.cpp new file mode 100644 index 00000000..2449c58e --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/glue/nsMemory.cpp @@ -0,0 +1,151 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsXPCOM.h" +#include "nsMemory.h" +#include "nsXPCOMPrivate.h" + +static nsIMemory* gMemory = nsnull; + +static NS_METHOD FreeGlobalMemory(void) +{ + NS_ASSERTION(gMemory, "must be not null after SetupGlobalMemory"); + NS_IF_RELEASE(gMemory); + return NS_OK; +} + +#define ENSURE_ALLOCATOR \ + (gMemory ? PR_TRUE : (PRBool)(SetupGlobalMemory() != nsnull)) + +static nsIMemory* +SetupGlobalMemory() +{ + NS_ASSERTION(!gMemory, "must be called once"); + if (!gMemory) + { + NS_GetMemoryManager(&gMemory); + NS_ASSERTION(gMemory, "can't get memory manager!"); + if (gMemory) + NS_RegisterXPCOMExitRoutine(FreeGlobalMemory, 0); + } + return gMemory; +} + +#ifdef XPCOM_GLUE +nsresult GlueStartupMemory() +{ + NS_ASSERTION(!gMemory, "must be called once"); + if (!gMemory) + { + NS_GetMemoryManager(&gMemory); + NS_ASSERTION(gMemory, "can't get memory manager!"); + if (!gMemory) + return NS_ERROR_FAILURE; + } + return NS_OK; +} + +void GlueShutdownMemory() +{ + NS_IF_RELEASE(gMemory); +} +#endif + +//////////////////////////////////////////////////////////////////////////////// +// nsMemory static helper routines + +NS_COM void* +nsMemory::Alloc(PRSize size) +{ + if (!ENSURE_ALLOCATOR) + return nsnull; + + return gMemory->Alloc(size); +} + +NS_COM void* +nsMemory::Realloc(void* ptr, PRSize size) +{ + if (!ENSURE_ALLOCATOR) + return nsnull; + + return gMemory->Realloc(ptr, size); +} + +NS_COM void +nsMemory::Free(void* ptr) +{ + if (!ENSURE_ALLOCATOR) + return; + + gMemory->Free(ptr); +} + +NS_COM nsresult +nsMemory::HeapMinimize(PRBool aImmediate) +{ + if (!ENSURE_ALLOCATOR) + return NS_ERROR_FAILURE; + + return gMemory->HeapMinimize(aImmediate); +} + +NS_COM void* +nsMemory::Clone(const void* ptr, PRSize size) +{ + if (!ENSURE_ALLOCATOR) + return nsnull; + + void* newPtr = gMemory->Alloc(size); + if (newPtr) + memcpy(newPtr, ptr, size); + return newPtr; +} + +NS_COM nsIMemory* +nsMemory::GetGlobalMemoryService() +{ + if (!ENSURE_ALLOCATOR) + return nsnull; + + nsIMemory* result = gMemory; + NS_IF_ADDREF(result); + return result; +} + +//---------------------------------------------------------------------- + diff --git a/src/libs/xpcom18a4/xpcom/glue/nsMemory.h b/src/libs/xpcom18a4/xpcom/glue/nsMemory.h new file mode 100644 index 00000000..4ee48bf0 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/glue/nsMemory.h @@ -0,0 +1,154 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +#ifndef nsMemory_h__ +#define nsMemory_h__ + +#include "nsIMemory.h" + +#define NS_MEMORY_CONTRACTID "@mozilla.org/xpcom/memory-service;1" +#define NS_MEMORY_CLASSNAME "Global Memory Service" +#define NS_MEMORY_CID \ +{ /* 30a04e40-38e7-11d4-8cf5-0060b0fc14a3 */ \ + 0x30a04e40, \ + 0x38e7, \ + 0x11d4, \ + {0x8c, 0xf5, 0x00, 0x60, 0xb0, 0xfc, 0x14, 0xa3} \ +} + + +/** + * Static helper routines to manage memory. These routines allow easy access + * to xpcom's built-in (global) nsIMemory implementation, without needing + * to go through the service manager to get it. However this requires clients + * to link with the xpcom DLL. + * + * This class is not threadsafe and is intented for use only on the main + * thread. + */ +class nsMemory +{ +public: + static NS_COM void* Alloc(size_t size); + static NS_COM void* Realloc(void* ptr, size_t size); + static NS_COM void Free(void* ptr); + static NS_COM nsresult HeapMinimize(PRBool aImmediate); + static NS_COM void* Clone(const void* ptr, size_t size); + static NS_COM nsIMemory* GetGlobalMemoryService(); // AddRefs +}; + +/** + * Macro to free all elements of an XPCOM array of a given size using + * freeFunc, then frees the array itself using nsMemory::Free(). + * + * Note that this macro (and its wrappers) can be used to deallocate a + * partially- or completely-built array while unwinding an error + * condition inside the XPCOM routine that was going to return the + * array. For this to work on a partially-built array, your code + * needs to be building the array from index 0 upwards, and simply + * pass the number of elements that have already been built (and thus + * need to be freed) as |size|. + * + * Thanks to for suggesting this form, which + * allows the macro to be used with NS_RELEASE / NS_RELEASE_IF in + * addition to nsMemory::Free. + * + * @param size Number of elements in the array. If not a constant, this + * should be a PRInt32. Note that this means this macro + * will not work if size >= 2^31. + * @param array The array to be freed. + * @param freeFunc The function or macro to be used to free it. + * For arrays of nsISupports (or any class derived + * from it), NS_IF_RELEASE (or NS_RELEASE) should be + * passed as freeFunc. For most (all?) other pointer + * types (including XPCOM strings and wstrings), + * nsMemory::Free should be used, since the + * shared-allocator (nsMemory) is what will have been + * used to allocate the memory. + */ +#define NS_FREE_XPCOM_POINTER_ARRAY(size, array, freeFunc) \ + PR_BEGIN_MACRO \ + PRInt32 iter_ = PRInt32(size); \ + while (--iter_ >= 0) \ + freeFunc((array)[iter_]); \ + nsMemory::Free((array)); \ + PR_END_MACRO + +// convenience macros for commonly used calls. mmmmm. syntactic sugar. + +/** + * Macro to free arrays of non-refcounted objects allocated by the + * shared allocator (nsMemory) such as strings and wstrings. A + * convenience wrapper around NS_FREE_XPCOM_POINTER_ARRAY. + * + * @param size Number of elements in the array. If not a constant, this + * should be a PRInt32. Note that this means this macro + * will not work if size >= 2^31. + * @param array The array to be freed. + */ +#define NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(size, array) \ + NS_FREE_XPCOM_POINTER_ARRAY((size), (array), nsMemory::Free) + +/** + * Macro to free an array of pointers to nsISupports (or classes + * derived from it). A convenience wrapper around + * NS_FREE_XPCOM_POINTER_ARRAY. + * + * Note that if you know that none of your nsISupports pointers are + * going to be 0, you can gain a bit of speed by calling + * NS_FREE_XPCOM_POINTER_ARRAY directly and using NS_RELEASE as your + * free function. + * + * @param size Number of elements in the array. If not a constant, this + * should be a PRInt32. Note that this means this macro + * will not work if size >= 2^31. + * @param array The array to be freed. + */ +#define NS_FREE_XPCOM_ISUPPORTS_POINTER_ARRAY(size, array) \ + NS_FREE_XPCOM_POINTER_ARRAY((size), (array), NS_IF_RELEASE) + +/** + * Helpful array length function for calculating the length of a + * statically declared array. + */ + +#define NS_ARRAY_LENGTH(array_) \ + (sizeof(array_)/sizeof(array_[0])) + + +#endif // nsMemory_h__ + diff --git a/src/libs/xpcom18a4/xpcom/glue/nsServiceManagerUtils.h b/src/libs/xpcom18a4/xpcom/glue/nsServiceManagerUtils.h new file mode 100644 index 00000000..b225b6a2 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/glue/nsServiceManagerUtils.h @@ -0,0 +1,183 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 XPCOM. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +#ifndef nsIServiceManagerUtils_h__ +#define nsIServiceManagerUtils_h__ + +#include "nsIServiceManager.h" +#include "nsIServiceManagerObsolete.h" +#include "nsCOMPtr.h" + +//////////////////////////////////////////////////////////////////////////// +// Using servicemanager with COMPtrs +class NS_COM nsGetServiceByCID : public nsCOMPtr_helper +{ + public: + nsGetServiceByCID( const nsCID& aCID, nsISupports* aServiceManager, nsresult* aErrorPtr ) + : mCID(aCID), + mServiceManager( do_QueryInterface(aServiceManager) ), + mErrorPtr(aErrorPtr) + { + // nothing else to do + } + + virtual nsresult NS_FASTCALL operator()( const nsIID&, void** ) const; + + private: + const nsCID& mCID; + nsCOMPtr mServiceManager; + nsresult* mErrorPtr; +}; + +inline +const nsGetServiceByCID +do_GetService( const nsCID& aCID, nsresult* error = 0 ) +{ + return nsGetServiceByCID(aCID, 0, error); +} + +inline +const nsGetServiceByCID +do_GetService( const nsCID& aCID, nsISupports* aServiceManager, nsresult* error = 0 ) +{ + return nsGetServiceByCID(aCID, aServiceManager, error); +} + +class NS_COM nsGetServiceByContractID : public nsCOMPtr_helper +{ + public: + nsGetServiceByContractID( const char* aContractID, nsISupports* aServiceManager, nsresult* aErrorPtr ) + : mContractID(aContractID), + mServiceManager( do_QueryInterface(aServiceManager) ), + mErrorPtr(aErrorPtr) + { + // nothing else to do + } + + virtual nsresult NS_FASTCALL operator()( const nsIID&, void** ) const; + + private: + const char* mContractID; + nsCOMPtr mServiceManager; + nsresult* mErrorPtr; +}; + +inline +const nsGetServiceByContractID +do_GetService( const char* aContractID, nsresult* error = 0 ) +{ + return nsGetServiceByContractID(aContractID, 0, error); +} + +inline +const nsGetServiceByContractID +do_GetService( const char* aContractID, nsISupports* aServiceManager, nsresult* error = 0 ) +{ + return nsGetServiceByContractID(aContractID, aServiceManager, error); +} + +class nsGetServiceFromCategory : public nsCOMPtr_helper +{ + public: + nsGetServiceFromCategory(const char* aCategory, const char* aEntry, + nsISupports* aServiceManager, + nsresult* aErrorPtr) + : mCategory(aCategory), + mEntry(aEntry), + mServiceManager( do_QueryInterface(aServiceManager) ), + mErrorPtr(aErrorPtr) + { + // nothing else to do + } + + virtual nsresult NS_FASTCALL operator()( const nsIID&, void** ) const; + protected: + const char* mCategory; + const char* mEntry; + nsCOMPtr mServiceManager; + nsresult* mErrorPtr; +}; + +inline +const nsGetServiceFromCategory +do_GetServiceFromCategory( const char* category, const char* entry, + nsresult* error = 0) +{ + return nsGetServiceFromCategory(category, entry, 0, error); +} + +// type-safe shortcuts for calling |GetService| +template +inline +nsresult +CallGetService( const nsCID &aClass, + DestinationType** aDestination) +{ + NS_PRECONDITION(aDestination, "null parameter"); + + nsCOMPtr mgr; + nsresult rv = NS_GetServiceManager(getter_AddRefs(mgr)); + + if (NS_FAILED(rv)) + return rv; + + return mgr->GetService(aClass, + NS_GET_IID(DestinationType), + NS_REINTERPRET_CAST(void**, aDestination)); +} + +template +inline +nsresult +CallGetService( const char *aContractID, + DestinationType** aDestination) +{ + NS_PRECONDITION(aContractID, "null parameter"); + NS_PRECONDITION(aDestination, "null parameter"); + + nsCOMPtr mgr; + nsresult rv = NS_GetServiceManager(getter_AddRefs(mgr)); + + if (NS_FAILED(rv)) + return rv; + + return mgr->GetServiceByContractID(aContractID, + NS_GET_IID(DestinationType), + NS_REINTERPRET_CAST(void**, aDestination)); +} + +#endif diff --git a/src/libs/xpcom18a4/xpcom/glue/nsTraceRefcnt.cpp b/src/libs/xpcom18a4/xpcom/glue/nsTraceRefcnt.cpp new file mode 100644 index 00000000..14e9469b --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/glue/nsTraceRefcnt.cpp @@ -0,0 +1,125 @@ +/* ***** 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 XPCOM + * + * The Initial Developer of the Original Code is Doug Turner + * + * Portions created by the Initial Developer are Copyright (C) 2003 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * 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 "nsXPCOM.h" +#include "nsXPCOMPrivate.h" +#include "nsCOMPtr.h" +#include "nsIServiceManager.h" +#include "nsTraceRefcnt.h" +#include "nsTraceRefcntImpl.h" + +static nsITraceRefcnt* gTraceRefcntObject = nsnull; + +static NS_METHOD FreeTraceRefcntObject(void) +{ + NS_IF_RELEASE(gTraceRefcntObject); + return NS_OK; +} + +#define ENSURE_TRACEOBJECT \ + (gTraceRefcntObject || SetupTraceRefcntObject() != nsnull) + +static nsITraceRefcnt* SetupTraceRefcntObject() +{ + NS_GetTraceRefcnt(&gTraceRefcntObject); + if (gTraceRefcntObject) + NS_RegisterXPCOMExitRoutine(FreeTraceRefcntObject, 0); + return gTraceRefcntObject; +} + +#ifdef XPCOM_GLUE +nsresult GlueStartupTraceRefcnt() +{ + NS_GetTraceRefcnt(&gTraceRefcntObject); + if (!gTraceRefcntObject) + return NS_ERROR_FAILURE; + return NS_OK; +} + +void GlueShutdownTraceRefcnt() +{ + NS_IF_RELEASE(gTraceRefcntObject); +} +#endif + +NS_COM void +nsTraceRefcnt::LogAddRef(void * aPtr, nsrefcnt aNewRefcnt, const char *aTypeName, PRUint32 aInstanceSize) +{ + if (!ENSURE_TRACEOBJECT) + return; + gTraceRefcntObject->LogAddRef(aPtr, aNewRefcnt, aTypeName, aInstanceSize); +} + +NS_COM void +nsTraceRefcnt::LogRelease(void * aPtr, nsrefcnt aNewRefcnt, const char *aTypeName) +{ + if (!ENSURE_TRACEOBJECT) + return; + gTraceRefcntObject->LogRelease(aPtr, aNewRefcnt, aTypeName); +} + +NS_COM void +nsTraceRefcnt::LogCtor(void * aPtr, const char *aTypeName, PRUint32 aInstanceSize) +{ + if (!ENSURE_TRACEOBJECT) + return; + gTraceRefcntObject->LogCtor(aPtr, aTypeName, aInstanceSize); +} + +NS_COM void +nsTraceRefcnt::LogDtor(void * aPtr, const char *aTypeName, PRUint32 aInstanceSize) +{ + if (!ENSURE_TRACEOBJECT) + return; + gTraceRefcntObject->LogDtor(aPtr, aTypeName, aInstanceSize); +} + +NS_COM void +nsTraceRefcnt::LogAddCOMPtr(void * aPtr, nsISupports *aObject) +{ + if (!ENSURE_TRACEOBJECT) + return; + gTraceRefcntObject->LogAddCOMPtr(aPtr, aObject); +} + +NS_COM void +nsTraceRefcnt::LogReleaseCOMPtr(void * aPtr, nsISupports *aObject) +{ + if (!ENSURE_TRACEOBJECT) + return; + gTraceRefcntObject->LogReleaseCOMPtr(aPtr, aObject); +} + diff --git a/src/libs/xpcom18a4/xpcom/glue/nsTraceRefcnt.h b/src/libs/xpcom18a4/xpcom/glue/nsTraceRefcnt.h new file mode 100644 index 00000000..afafda4b --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/glue/nsTraceRefcnt.h @@ -0,0 +1,135 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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 Communicator client code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * L. David Baron + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ +#ifndef nsTraceRefcnt_h___ +#define nsTraceRefcnt_h___ + +#include "nscore.h" + +class nsISupports; + +// By default refcnt logging is not part of the build. +#undef NS_BUILD_REFCNT_LOGGING + +#if (defined(DEBUG) || defined(FORCE_BUILD_REFCNT_LOGGING)) +// Make refcnt logging part of the build. This doesn't mean that +// actual logging will occur (that requires a separate enable; see +// nsTraceRefcnt.h for more information). +#define NS_BUILD_REFCNT_LOGGING 1 +#endif + +// If NO_BUILD_REFCNT_LOGGING is defined then disable refcnt logging +// in the build. This overrides FORCE_BUILD_REFCNT_LOGGING. +#if defined(NO_BUILD_REFCNT_LOGGING) +#undef NS_BUILD_REFCNT_LOGGING +#endif + +#ifdef NS_BUILD_REFCNT_LOGGING + +#define NS_LOG_ADDREF(_p, _rc, _type, _size) \ + nsTraceRefcnt::LogAddRef((_p), (_rc), (_type), (PRUint32) (_size)) + +#define NS_LOG_RELEASE(_p, _rc, _type) \ + nsTraceRefcnt::LogRelease((_p), (_rc), (_type)) + +#define MOZ_DECL_CTOR_COUNTER(_type) + +#define MOZ_COUNT_CTOR(_type) \ +PR_BEGIN_MACRO \ + nsTraceRefcnt::LogCtor((void*)this, #_type, sizeof(*this)); \ +PR_END_MACRO + +#define MOZ_COUNT_DTOR(_type) \ +PR_BEGIN_MACRO \ + nsTraceRefcnt::LogDtor((void*)this, #_type, sizeof(*this)); \ +PR_END_MACRO + +#ifdef HAVE_CPP_DYNAMIC_CAST_TO_VOID_PTR // from autoconf (XXX needs to be + // set for non-autoconf platforms) + +// nsCOMPtr.h allows these macros to be defined by clients +// These logging functions require dynamic_cast, so we don't +// define these macros if we don't have dynamic_cast. +#define NSCAP_LOG_ASSIGNMENT(_c, _p) \ + if (_p) \ + nsTraceRefcnt::LogAddCOMPtr((_c),NS_STATIC_CAST(nsISupports*,_p)) + +#define NSCAP_LOG_RELEASE(_c, _p) \ + if (_p) \ + nsTraceRefcnt::LogReleaseCOMPtr((_c), NS_STATIC_CAST(nsISupports*,_p)) + +#endif /* HAVE_CPP_DYNAMIC_CAST_TO_VOID_PTR */ + +#else /* !NS_BUILD_REFCNT_LOGGING */ + +#define NS_LOG_ADDREF(_p, _rc, _type, _size) +#define NS_LOG_RELEASE(_p, _rc, _type) +#define MOZ_DECL_CTOR_COUNTER(_type) +#define MOZ_COUNT_CTOR(_type) +#define MOZ_COUNT_DTOR(_type) + +#endif /* NS_BUILD_REFCNT_LOGGING */ + +//---------------------------------------------------------------------- + +/** + * Note: The implementations for these methods are no-ops in a build + * where NS_BUILD_REFCNT_LOGGING is disabled. + */ +class nsTraceRefcnt { +public: + static NS_COM void LogAddRef(void* aPtr, + nsrefcnt aNewRefCnt, + const char* aTypeName, + PRUint32 aInstanceSize); + + static NS_COM void LogRelease(void* aPtr, + nsrefcnt aNewRefCnt, + const char* aTypeName); + + static NS_COM void LogCtor(void* aPtr, const char* aTypeName, + PRUint32 aInstanceSize); + + static NS_COM void LogDtor(void* aPtr, const char* aTypeName, + PRUint32 aInstanceSize); + + static NS_COM void LogAddCOMPtr(void *aCOMPtr, nsISupports *aObject); + + static NS_COM void LogReleaseCOMPtr(void *aCOMPtr, nsISupports *aObject); + +}; +#endif /* nsTraceRefcnt_h___ */ diff --git a/src/libs/xpcom18a4/xpcom/glue/nsWeakReference.cpp b/src/libs/xpcom18a4/xpcom/glue/nsWeakReference.cpp new file mode 100644 index 00000000..76d9f593 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/glue/nsWeakReference.cpp @@ -0,0 +1,169 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * ***** 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 the Mozilla browser. + * + * The Initial Developer of the Original Code is + * Netscape Communications, Inc. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Scott Collins + * Pierre Phaneuf + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +// nsWeakReference.cpp + +#include "nsWeakReference.h" +#include "nsCOMPtr.h" + +nsresult +nsQueryReferent::operator()( const nsIID& aIID, void** answer ) const + { + nsresult status; + if ( mWeakPtr ) + { + if ( NS_FAILED(status = mWeakPtr->QueryReferent(aIID, answer)) ) + *answer = 0; + } + else + status = NS_ERROR_NULL_POINTER; + + if ( mErrorPtr ) + *mErrorPtr = status; + return status; + } + +nsresult +nsGetWeakReference::operator()( const nsIID&, void** aResult ) const + { + nsresult status; + // nsIWeakReference** result = &NS_STATIC_CAST(nsIWeakReference*, *aResult); + *aResult = 0; + + if ( mRawPtr ) + { + nsCOMPtr factoryPtr = do_QueryInterface(mRawPtr, &status); + NS_ASSERTION(factoryPtr, "Oops! You're asking for a weak reference to an object that doesn't support that."); + if ( factoryPtr ) + { + nsIWeakReference* temp; + status = factoryPtr->GetWeakReference(&temp); + *aResult = temp; + } + // else, |status| has already been set by |do_QueryInterface| + } + else + status = NS_ERROR_NULL_POINTER; + + if ( mErrorPtr ) + *mErrorPtr = status; + return status; + } + + +NS_COM nsIWeakReference* // or else |already_AddRefed| +NS_GetWeakReference( nsISupports* aInstancePtr, nsresult* aErrorPtr ) + { + void* result = 0; + nsGetWeakReference(aInstancePtr, aErrorPtr)(NS_GET_IID(nsIWeakReference), &result); + return NS_STATIC_CAST(nsIWeakReference*, result); + } + +NS_COM nsresult +nsSupportsWeakReference::GetWeakReference( nsIWeakReference** aInstancePtr ) + { + if ( !aInstancePtr ) + return NS_ERROR_NULL_POINTER; + + if ( !mProxy ) + mProxy = new nsWeakReference(this); + *aInstancePtr = mProxy; + + nsresult status; + if ( !*aInstancePtr ) + status = NS_ERROR_OUT_OF_MEMORY; + else + { + NS_ADDREF(*aInstancePtr); + status = NS_OK; + } + + return status; + } + +NS_IMETHODIMP_(nsrefcnt) +nsWeakReference::AddRef() + { + return ++mRefCount; + } + +NS_IMETHODIMP_(nsrefcnt) +nsWeakReference::Release() + { + nsrefcnt temp = --mRefCount; + if ( !mRefCount ) + delete this; + return temp; + } + +NS_IMETHODIMP +nsWeakReference::QueryInterface( const nsIID& aIID, void** aInstancePtr ) + { + NS_ASSERTION(aInstancePtr, "QueryInterface requires a non-NULL destination!"); + + if ( !aInstancePtr ) + return NS_ERROR_NULL_POINTER; + + nsISupports* foundInterface; + if ( aIID.Equals(NS_GET_IID(nsIWeakReference)) ) + foundInterface = NS_STATIC_CAST(nsIWeakReference*, this); + else if ( aIID.Equals(NS_GET_IID(nsISupports)) ) + foundInterface = NS_STATIC_CAST(nsISupports*, this); + else + foundInterface = 0; + + nsresult status; + if ( !foundInterface ) + status = NS_NOINTERFACE; + else + { + NS_ADDREF(foundInterface); + status = NS_OK; + } + + *aInstancePtr = foundInterface; + return status; + } + +NS_IMETHODIMP +nsWeakReference::QueryReferent( const nsIID& aIID, void** aInstancePtr ) + { + return mReferent ? mReferent->QueryInterface(aIID, aInstancePtr) : NS_ERROR_NULL_POINTER; + } diff --git a/src/libs/xpcom18a4/xpcom/glue/nsWeakReference.h b/src/libs/xpcom18a4/xpcom/glue/nsWeakReference.h new file mode 100644 index 00000000..96e63f22 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/glue/nsWeakReference.h @@ -0,0 +1,150 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * ***** 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 the Mozilla browser. + * + * The Initial Developer of the Original Code is + * Netscape Communications, Inc. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Scott Collins + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +#ifndef nsWeakReference_h__ +#define nsWeakReference_h__ + +// nsWeakReference.h + +#include "nsIWeakReference.h" + +class nsWeakReference; + +#undef IMETHOD_VISIBILITY +#define IMETHOD_VISIBILITY NS_VISIBILITY_DEFAULT + +class NS_COM nsSupportsWeakReference : public nsISupportsWeakReference + { + public: + nsSupportsWeakReference() + : mProxy(0) + { + // nothing else to do here + } + + NS_DECL_NSISUPPORTSWEAKREFERENCE + + protected: + inline ~nsSupportsWeakReference(); + + private: + friend class nsWeakReference; + + void + NoticeProxyDestruction() + // ...called (only) by an |nsWeakReference| from _its_ dtor. + { + mProxy = 0; + } + + nsWeakReference* mProxy; + + protected: + + inline void ClearWeakReferences(); + PRBool HasWeakReferences() const {return mProxy != 0;} + }; + +#undef IMETHOD_VISIBILITY +#define IMETHOD_VISIBILITY NS_VISIBILITY_HIDDEN + +class NS_COM nsWeakReference : public nsIWeakReference + { + public: + // nsISupports... + NS_IMETHOD_(nsrefcnt) AddRef(); + NS_IMETHOD_(nsrefcnt) Release(); + NS_IMETHOD QueryInterface( const nsIID&, void** ); + + // nsIWeakReference... + NS_DECL_NSIWEAKREFERENCE + + private: + friend class nsSupportsWeakReference; + + nsWeakReference( nsSupportsWeakReference* referent ) + : mRefCount(0), + mReferent(referent) + // ...I can only be constructed by an |nsSupportsWeakReference| + { + // nothing else to do here + } + + ~nsWeakReference() + // ...I will only be destroyed by calling |delete| myself. + { + if ( mReferent ) + mReferent->NoticeProxyDestruction(); + } + + void + NoticeReferentDestruction() + // ...called (only) by an |nsSupportsWeakReference| from _its_ dtor. + { + mReferent = 0; + } + + nsrefcnt mRefCount; + nsSupportsWeakReference* mReferent; + }; + +inline +void +nsSupportsWeakReference::ClearWeakReferences() + /* + Usually being called from |nsSupportsWeakReference::~nsSupportsWeakReference| + will be good enough, but you may have a case where you need to call disconnect + your weak references in an outer destructor (to prevent some client holding a + weak reference from re-entering your destructor). + */ + { + if ( mProxy ) + { + mProxy->NoticeReferentDestruction(); + mProxy = 0; + } + } + +inline +nsSupportsWeakReference::~nsSupportsWeakReference() + { + ClearWeakReferences(); + } + +#endif diff --git a/src/libs/xpcom18a4/xpcom/glue/objs.mk b/src/libs/xpcom18a4/xpcom/glue/objs.mk new file mode 100644 index 00000000..d6d04a5a --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/glue/objs.mk @@ -0,0 +1,60 @@ +# ***** 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.org. +# +# 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): +# +# 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 ***** + +XPCOM_GLUE_SRC_LCSRCS = \ + nsCOMPtr.cpp \ + nsComponentManagerUtils.cpp \ + nsDebug.cpp \ + nsGenericFactory.cpp \ + nsIInterfaceRequestorUtils.cpp \ + nsMemory.cpp \ + nsTraceRefcnt.cpp \ + nsWeakReference.cpp \ + $(NULL) \ + +XPCOM_GLUE_SRC_LEXPORTS = \ + nsCOMPtr.h \ + nsDebug.h \ + nsGenericFactory.h \ + nsIGenericFactory.h \ + nsMemory.h \ + nsTraceRefcnt.h \ + nsWeakReference.h \ + $(NULL) + + + +XPCOM_GLUE_SRC_CSRCS := $(addprefix $(topsrcdir)/xpcom/glue/, $(XPCOM_GLUE_SRC_LCSRCS)) diff --git a/src/libs/xpcom18a4/xpcom/glue/standalone/.cvsignore b/src/libs/xpcom18a4/xpcom/glue/standalone/.cvsignore new file mode 100644 index 00000000..a0182c1f --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/glue/standalone/.cvsignore @@ -0,0 +1,8 @@ +Makefile +nsCOMPtr.cpp +nsDebug.cpp +nsGenericFactory.cpp +nsIInterfaceRequestorUtils.cpp +nsMemory.cpp +nsWeakReference.cpp +nsComponentManagerUtils.cpp diff --git a/src/libs/xpcom18a4/xpcom/glue/standalone/Makefile.in b/src/libs/xpcom18a4/xpcom/glue/standalone/Makefile.in new file mode 100644 index 00000000..ae23d8e0 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/glue/standalone/Makefile.in @@ -0,0 +1,88 @@ +# ***** 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.org. +# +# 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): +# +# 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 ***** + +DEPTH = ../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk +include $(srcdir)/../objs.mk + +MODULE = xpcom +LIBRARY_NAME = xpcomglue + +REQUIRES = string \ + $(NULL) + +LOCAL_INCLUDES = \ + -I$(srcdir)/../../build \ + $(NULL) + +CPPSRCS = \ + $(XPCOM_GLUE_SRC_LCSRCS) \ + nsXPCOMGlue.cpp \ + nsGREDirServiceProvider.cpp \ + $(NULL) + +SDK_HEADERS = \ + nsXPCOMGlue.h \ + $(NULL) + +SDK_LIBRARY = \ + $(LIB_PREFIX)xpcomglue.$(LIB_SUFFIX) \ + $(NULL) + +# we don't want the shared lib, but we want to force the creation of a static lib. +FORCE_STATIC_LIB = 1 + +# Force use of PIC +FORCE_USE_PIC = 1 + +GARBAGE += $(XPCOM_GLUE_SRC_LCSRCS) $(wildcard *.$(OBJ_SUFFIX)) + +ifeq ($(OS_ARCH),WINNT) +GARBAGE += $(addprefix $(srcdir)/,$(XPCOM_GLUE_SRC_LCSRCS)) +endif + +SRCS_IN_OBJDIR = 1 + +include $(topsrcdir)/config/rules.mk + +export:: $(XPCOM_GLUE_SRC_CSRCS) + $(INSTALL) $^ . + +DEFINES += -DXPCOM_GLUE diff --git a/src/libs/xpcom18a4/xpcom/glue/standalone/nsGREDirServiceProvider.cpp b/src/libs/xpcom18a4/xpcom/glue/standalone/nsGREDirServiceProvider.cpp new file mode 100644 index 00000000..4a1247eb --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/glue/standalone/nsGREDirServiceProvider.cpp @@ -0,0 +1,596 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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 Communicator. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corp. + * Portions created by the Initial Developer are Copyright (C) 2003 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Sean Su + * + * 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 "nsBuildID.h" + +#include "nsEmbedString.h" +#include "nsXPCOMPrivate.h" +#include "nsXPCOMGlue.h" +#include "nsILocalFile.h" +#include "nsIDirectoryService.h" +#include "nsDirectoryServiceDefs.h" +#include "nsCOMPtr.h" + +#include "nspr.h" +#include "plstr.h" + +#ifdef XP_WIN32 +#include +#include +#elif defined(XP_OS2) +#define INCL_DOS +#include +#include +#include +#include "prenv.h" +#elif defined(XP_MACOSX) +#include +#include +#elif defined(XP_UNIX) +#include +#include +#include +#include +#include "prenv.h" +#elif defined(XP_BEOS) +#include +#include +#include +#include +#include +#include +#include +#include "prenv.h" +#endif + +#include + +#include "nsGREDirServiceProvider.h" + +PRBool GRE_GetCurrentProcessDirectory(char* buffer); +PRBool GRE_GetPathFromConfigDir(const char* dirname, char* buffer); +PRBool GRE_GetPathFromConfigFile(const char* dirname, char* buffer); + +//***************************************************************************** +// nsGREDirServiceProvider::nsISupports +//***************************************************************************** + +NS_IMPL_ISUPPORTS1(nsGREDirServiceProvider, nsIDirectoryServiceProvider) + +//***************************************************************************** +// nsGREDirServiceProvider::nsIDirectoryServiceProvider +//***************************************************************************** + +NS_IMETHODIMP +nsGREDirServiceProvider::GetFile(const char *prop, PRBool *persistant, nsIFile **_retval) +{ + *_retval = nsnull; + *persistant = PR_TRUE; + + //--------------------------------------------------------------- + // Note that by returning a valid localFile's for NS_GRE_DIR, + // your app is indicating to XPCOM that it found a GRE version + // with which it's compatible with and intends to be "run against" + // that GRE. + // + // Please see http://www.mozilla.org/projects/embedding/GRE.html + // for more info on GRE. + //--------------------------------------------------------------- + if(strcmp(prop, NS_GRE_DIR) == 0) + { + nsILocalFile* lfile = nsnull; + nsresult rv = GRE_GetGREDirectory(&lfile); + *_retval = lfile; + return rv; + } + + return NS_ERROR_FAILURE; +} + +//***************************************************************************** +// Implementations from nsXPCOMGlue.h and helper functions. +//***************************************************************************** + +PRBool +GRE_GetCurrentProcessDirectory(char* buffer) +{ + *buffer = '\0'; + +#ifdef XP_WIN + if ( ::GetModuleFileName(0, buffer, MAXPATHLEN) ) { + // chop of the executable name by finding the rightmost backslash + char* lastSlash = PL_strrchr(buffer, '\\'); + if (lastSlash) { + *(lastSlash) = '\0'; + return PR_TRUE; + } + } + +#elif defined(XP_MACOSX) + // Works even if we're not bundled. + CFBundleRef appBundle = CFBundleGetMainBundle(); + if (appBundle != nsnull) + { + CFURLRef bundleURL = CFBundleCopyExecutableURL(appBundle); + if (bundleURL != nsnull) + { + CFURLRef parentURL = CFURLCreateCopyDeletingLastPathComponent(kCFAllocatorDefault, bundleURL); + if (parentURL) + { + CFStringRef path = CFURLCopyFileSystemPath(parentURL, kCFURLPOSIXPathStyle); + if (path) + { + CFStringGetCString(path, buffer, MAXPATHLEN, kCFStringEncodingUTF8); + CFRelease(path); + } + CFRelease(parentURL); + } + CFRelease(bundleURL); + } +#if 0 /* bird: Causes crashes in objc_msgSend() later if released. I dunno why really. + Something could be seriously screwed up somewhere else, but this'll have + to do for now. (appBundle isn't released in the other place it's used.) */ + CFRelease(appBundle); +#endif + } + if (*buffer) return PR_TRUE; + +#elif defined(XP_UNIX) + +#if 0 /* we need .so location. */ + // Actually we have a way on linux. + static volatile bool fPathSet = false; + static char szPath[MAXPATHLEN]; + if (!fPathSet) + { + char buf2[MAXPATHLEN + 3]; + buf2[0] = '\0'; + + /* + * Env.var. VBOX_XPCOM_HOME first. + */ + char *psz = PR_GetEnv("VBOX_XPCOM_HOME"); + if (psz) + { + if (strlen(psz) < MAXPATHLEN) + { + if (!realpath(psz, buf2)) + strcpy(buf2, psz); + strcat(buf2, "/x"); /* for the filename stripping */ + } + } + + /* + * The dynamic loader. + */ + if (!buf2[0]) + { + Dl_info DlInfo = {0}; + if ( !dladdr((const void *)GRE_GetCurrentProcessDirectory, &DlInfo) + && DlInfo.dli_fname) + { + if (!realpath(DlInfo.dli_fname, buf2)) + buf2[0] = '\0'; + } + } + + /* + * Executable location. + */ + if (!buf2[0]) + { + char buf[MAXPATHLEN]; + int cchLink = readlink("/proc/self/exe", buf, sizeof(buf) - 1); + if (cchLink > 0 || cchLink != sizeof(buf) - 1) + { + buf[cchLink] = '\0'; + if (!realpath(buf, buf2)) + buf2[0] = '\0'; + } + } + + /* + * Copy to static buffer on success. + */ + if (buf2[0]) + { + char *p = strrchr(buf2, '/'); + if (p) + { + p[p == buf2] = '\0'; + #ifdef DEBUG + printf("debug: (1) VBOX_XPCOM_HOME=%s\n", buf2); + #endif + strcpy(szPath, buf2); + fPathSet = true; + } + } + } + if (fPathSet) + { + strcpy(buffer, szPath); + return PR_TRUE; + } +#endif + + // In the absence of a good way to get the executable directory let + // us try this for unix: + // - if VBOX_XPCOM_HOME is defined, that is it + // - else give the current directory + + // The MOZ_DEFAULT_VBOX_XPCOM_HOME variable can be set at configure time with + // a --with-default-mozilla-five-home=foo autoconf flag. + // + // The idea here is to allow for builds that have a default VBOX_XPCOM_HOME + // regardless of the environment. This makes it easier to write apps that + // embed mozilla without having to worry about setting up the environment + // + // We do this py putenv()ing the default value into the environment. Note that + // we only do this if it is not already set. +#ifdef MOZ_DEFAULT_VBOX_XPCOM_HOME + if (PR_GetEnv("VBOX_XPCOM_HOME") == nsnull) + { + putenv("VBOX_XPCOM_HOME=" MOZ_DEFAULT_VBOX_XPCOM_HOME); + } +#endif + + char *moz5 = PR_GetEnv("VBOX_XPCOM_HOME"); + + if (moz5 && *moz5) + { + if (!realpath(moz5, buffer)) + strcpy(buffer, moz5); + + return PR_TRUE; + } + else + { +#if defined(DEBUG) + static PRBool firstWarning = PR_TRUE; + + if(firstWarning) { + // Warn that VBOX_XPCOM_HOME not set, once. + printf("Warning: VBOX_XPCOM_HOME not set.\n"); + firstWarning = PR_FALSE; + } +#endif /* DEBUG */ + + // Fall back to current directory. + if (getcwd(buffer, MAXPATHLEN)) + { + return PR_TRUE; + } + } + +#elif defined(XP_OS2) + PPIB ppib; + PTIB ptib; + char* p; + DosGetInfoBlocks( &ptib, &ppib); + DosQueryModuleName( ppib->pib_hmte, MAXPATHLEN, buffer); + p = strrchr( buffer, '\\'); // XXX DBCS misery + if (p) { + *p = '\0'; + return PR_TRUE; + } + +#elif defined(XP_BEOS) + + char *moz5 = getenv("VBOX_XPCOM_HOME"); + if (moz5) + { + strcpy(buffer, moz5); + return PR_TRUE; + } + else + { + int32 cookie = 0; + image_info info; + char *p; + *buffer = 0; + if(get_next_image_info(0, &cookie, &info) == B_OK) + { + strcpy(buffer, info.name); + if((p = strrchr(buffer, '/')) != 0) + { + *p = 0; + + return PR_TRUE; + } + } + } + +#endif + + return PR_FALSE; +} + +/** + * the GRE location is stored in a static buffer so that we don't have + * to compute it multiple times. + */ + +static char sGRELocation[MAXPATHLEN] = ""; + +extern "C" char const * +GRE_GetGREPath() +{ + // we've already done this... + if (*sGRELocation) + return sGRELocation; + + char buffer[MAXPATHLEN]; + + // If the xpcom library exists in the current process directory, + // then we will not use any GRE. The assumption here is that the + // GRE is in the same directory as the executable. + if (GRE_GetCurrentProcessDirectory(buffer)) { + PRUint32 pathlen = strlen(buffer); + strcpy(buffer + pathlen, XPCOM_FILE_PATH_SEPARATOR XPCOM_DLL); + + struct stat libStat; + int statResult = stat(buffer, &libStat); + + if (statResult != -1) { + //found our xpcom lib in the current process directory + buffer[pathlen] = '\0'; + strcpy(sGRELocation, buffer); + return sGRELocation; + } + } + + // if GRE_HOME is in the environment, use that GRE + const char* env = PR_GetEnv("GRE_HOME"); + if (env && *env) { +#if XP_UNIX + if (!realpath(env, sGRELocation)) + strcpy(sGRELocation, env); +#elif XP_WIN32 + if (!_fullpath(sGRELocation, env, MAXPATHLEN)) + strcpy(sGRELocation, env); +#endif + // xxxbsmedberg: it would help that other platforms had a "make absolute" function + return sGRELocation; + } + + // the Gecko bits that sit next to the application or in the LD_LIBRARY_PATH + env = PR_GetEnv("USE_LOCAL_GRE"); + if (env && *env) + return nsnull; + +#if XP_UNIX + // check in the HOME directory + env = PR_GetEnv("HOME"); + if (env && *env) { +# ifdef VBOX + snprintf(buffer, sizeof(buffer), "%s" XPCOM_FILE_PATH_SEPARATOR GRE_CONF_NAME, env); +# else + sprintf(buffer, "%s" XPCOM_FILE_PATH_SEPARATOR GRE_CONF_NAME, env); +# endif + + if (GRE_GetPathFromConfigFile(buffer, sGRELocation)) { + return sGRELocation; + } + } +#endif + + env = PR_GetEnv("MOZ_GRE_CONF"); + if (env) { + if (GRE_GetPathFromConfigFile(env, sGRELocation)) { + return sGRELocation; + } + } + +#if XP_UNIX + // Look for a group of config files in /etc/gre.d/ + if (GRE_GetPathFromConfigDir(GRE_CONF_DIR, sGRELocation)) { + return sGRELocation; + } + + // Look for a global /etc/gre.conf file + if (GRE_GetPathFromConfigFile(GRE_CONF_PATH, sGRELocation)) { + return sGRELocation; + } +#endif + +#if XP_WIN32 + char szKey[256]; + HKEY hRegKey = NULL; + DWORD dwLength = MAXPATHLEN; + + // A couple of key points here: + // 1. Note the usage of the "Software\\Mozilla\\GRE" subkey - this allows + // us to have multiple versions of GREs on the same machine by having + // subkeys such as 1.0, 1.1, 2.0 etc. under it. + // 2. In this sample below we're looking for the location of GRE version 1.2 + // i.e. we're compatible with GRE 1.2 and we're trying to find it's install + // location. + // + // Please see http://www.mozilla.org/projects/embedding/GRE.html for + // more info. + // + strcpy(szKey, GRE_WIN_REG_LOC GRE_BUILD_ID); + + if (::RegOpenKeyEx(HKEY_CURRENT_USER, szKey, 0, KEY_QUERY_VALUE, &hRegKey) == ERROR_SUCCESS) { + if (::RegQueryValueEx(hRegKey, "GreHome", NULL, NULL, (BYTE *)sGRELocation, &dwLength) != ERROR_SUCCESS) { + *sGRELocation = '\0'; + } + ::RegCloseKey(hRegKey); + + if (*sGRELocation) + return sGRELocation; + } + + if (::RegOpenKeyEx(HKEY_LOCAL_MACHINE, szKey, 0, KEY_QUERY_VALUE, &hRegKey) == ERROR_SUCCESS) { + if (::RegQueryValueEx(hRegKey, "GreHome", NULL, NULL, (BYTE *)sGRELocation, &dwLength) != ERROR_SUCCESS) { + *sGRELocation = '\0'; + } + ::RegCloseKey(hRegKey); + + if (*sGRELocation) + return sGRELocation; + } +#endif + + return nsnull; +} + +PRBool +GRE_GetPathFromConfigDir(const char* dirname, char* buffer) +{ + // Open the directory provided and try to read any files in that + // directory that end with .conf. We look for an entry that might + // point to the GRE that we're interested in. + PRDir *dir = PR_OpenDir(dirname); + if (!dir) + return nsnull; + + PRBool found = PR_FALSE; + PRDirEntry *entry; + + while (!found && (entry = PR_ReadDir(dir, PR_SKIP_BOTH))) { + + // Only look for files that end in .conf + char *offset = PL_strrstr(entry->name, ".conf"); + if (!offset) + continue; + + if (offset != entry->name + strlen(entry->name) - 5) + continue; + + nsEmbedCString fullPath; + NS_CStringAppendData(fullPath, dirname); + NS_CStringAppendData(fullPath, XPCOM_FILE_PATH_SEPARATOR); + NS_CStringAppendData(fullPath, entry->name); + + found = GRE_GetPathFromConfigFile(fullPath.get(), buffer); + } + + PR_CloseDir(dir); + + return found; +} + +PRBool +GRE_GetPathFromConfigFile(const char* filename, char* pathBuffer) +{ + *pathBuffer = '\0'; + char buffer[1024]; + FILE *cfg; + PRBool foundHeader = PR_FALSE; + PRInt32 versionLen = sizeof(GRE_BUILD_ID)-1; + + if((cfg=fopen(filename,"r"))==nsnull) { + return nsnull; + } + + while (fgets(buffer, 1024, cfg) != nsnull) { + // skip over comment lines and blank lines + if (buffer[0] == '#' || buffer[0] == '\n') { + continue; + } + + // we found a section heading, check to see if it is the one we are intersted in. + if (buffer[0] == '[') { + if (!strncmp (buffer+1, GRE_BUILD_ID, versionLen)) { + foundHeader = PR_TRUE; + } + continue; + } + + if (foundHeader && !strncmp (buffer, "GRE_PATH=", 9)) { + strcpy(pathBuffer, buffer + 9); + // kill the line feed if any + PRInt32 len = strlen(pathBuffer); + len--; + + if (pathBuffer[len] == '\n') + pathBuffer[len] = '\0'; + break; + } + } + fclose(cfg); + return (*pathBuffer != '\0'); +} + +extern "C" nsresult +GRE_GetGREDirectory(nsILocalFile* *_retval) +{ + NS_ENSURE_ARG_POINTER(_retval); + nsresult rv = NS_ERROR_FAILURE; + + // Get the path of the GRE which is compatible with our embedding application + // from the registry + + const char *pGREDir = GRE_GetGREPath(); + if(pGREDir) { + nsCOMPtr tempLocal; + nsEmbedCString leaf; + NS_CStringSetData(leaf, pGREDir); + rv = NS_NewNativeLocalFile(leaf, PR_TRUE, getter_AddRefs(tempLocal)); + + if (NS_SUCCEEDED(rv)) { + *_retval = tempLocal; + NS_ADDREF(*_retval); + } + } + return rv; +} + +static char sXPCOMPath[MAXPATHLEN]; + +extern "C" const char* +GRE_GetXPCOMPath() +{ + const char* grePath = GRE_GetGREPath(); + + if (!grePath) { + grePath = PR_GetEnv("VBOX_XPCOM_HOME"); + if (!grePath || !*grePath) { + return nsnull; + } + } + +#ifdef VBOX + snprintf(sXPCOMPath, sizeof(sXPCOMPath), "%s" XPCOM_FILE_PATH_SEPARATOR XPCOM_DLL, grePath); +#else + sprintf(sXPCOMPath, "%s" XPCOM_FILE_PATH_SEPARATOR XPCOM_DLL, grePath); +#endif + + return sXPCOMPath; +} diff --git a/src/libs/xpcom18a4/xpcom/glue/standalone/nsGREDirServiceProvider.h b/src/libs/xpcom18a4/xpcom/glue/standalone/nsGREDirServiceProvider.h new file mode 100644 index 00000000..0638a127 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/glue/standalone/nsGREDirServiceProvider.h @@ -0,0 +1,68 @@ +/* ***** 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 Communicator. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corp. + * Portions created by the Initial Developer are Copyright (C) 2003 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Sean Su + * + * 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 ***** */ + +#ifndef nsGREDirServiceProvider_h_ +#define nsGREDirServiceProvider_h_ + +#include "nsIDirectoryService.h" + +#ifndef MAXPATHLEN +#ifdef _MAX_PATH +#define MAXPATHLEN _MAX_PATH +#elif defined(CCHMAXPATH) +#define MAXPATHLEN CCHMAXPATH +#else +#define MAXPATHLEN 1024 +#endif +#endif + +/** + * the directoryserviceprovider used by GRE_Startup when calling NS_InitXPCOM2 + */ +class nsGREDirServiceProvider : public nsIDirectoryServiceProvider +{ +public: + nsGREDirServiceProvider() { } + + NS_DECL_ISUPPORTS + NS_DECL_NSIDIRECTORYSERVICEPROVIDER + +private: + ~nsGREDirServiceProvider() { } +}; + +#endif // nsGREDirServiceProvider.h diff --git a/src/libs/xpcom18a4/xpcom/glue/standalone/nsXPCOMGlue.cpp b/src/libs/xpcom18a4/xpcom/glue/standalone/nsXPCOMGlue.cpp new file mode 100644 index 00000000..091538fa --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/glue/standalone/nsXPCOMGlue.cpp @@ -0,0 +1,524 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* vim:set ts=4 sw=4 et cindent: */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsXPCOMGlue.h" + +#include "nspr.h" +#include "nsMemory.h" +#include "nsGREDirServiceProvider.h" +#include "nsXPCOMPrivate.h" +#include +#ifdef VBOX +# include +#endif + +#if XP_WIN32 +#include +#endif + +void GRE_AddGREToEnvironment(); + +// functions provided by nsMemory.cpp and nsDebug.cpp +nsresult GlueStartupMemory(); +void GlueShutdownMemory(); +nsresult GlueStartupDebug(); +void GlueShutdownDebug(); + +static PRLibrary *xpcomLib; +static XPCOMFunctions xpcomFunctions; + +extern "C" +nsresult XPCOMGlueStartup(const char* xpcomFile) +{ +#ifdef XPCOM_GLUE_NO_DYNAMIC_LOADING + return NS_OK; +#else + nsresult rv = NS_OK; + GetFrozenFunctionsFunc function = nsnull; + + xpcomFunctions.version = XPCOM_GLUE_VERSION; + xpcomFunctions.size = sizeof(XPCOMFunctions); + + // + // if xpcomFile == ".", then we assume xpcom is already loaded, and we'll + // use NSPR to find NS_GetFrozenFunctions from the list of already loaded + // libraries. + // + // otherwise, we try to load xpcom and then look for NS_GetFrozenFunctions. + // if xpcomFile == NULL, then we try to load xpcom by name w/o a fully + // qualified path. + // + + if (xpcomFile && (xpcomFile[0] == '.' && xpcomFile[1] == '\0')) { + function = (GetFrozenFunctionsFunc) + PR_FindSymbolAndLibrary("NS_GetFrozenFunctions", &xpcomLib); + if (!function) { + // The symbol was not found, so failover to loading XPCOM_DLL, + // and look for the symbol there. See bug 240986 for details. + xpcomFile = nsnull; + } + else { + char *libPath = PR_GetLibraryFilePathname(XPCOM_DLL, (PRFuncPtr) function); + if (!libPath) + rv = NS_ERROR_FAILURE; + else { + rv = (*function)(&xpcomFunctions, libPath); + PR_Free(libPath); + } + } + } + + if (!function) { + PRLibSpec libSpec; + + libSpec.type = PR_LibSpec_Pathname; + if (!xpcomFile) + libSpec.value.pathname = XPCOM_DLL; + else + libSpec.value.pathname = xpcomFile; + + xpcomLib = PR_LoadLibraryWithFlags(libSpec, PR_LD_LAZY|PR_LD_GLOBAL); +#ifdef RT_OS_DARWIN /* vbox */ + /* works around bundle problem. */ + if (!xpcomLib) { + const char *home = PR_GetEnv("VBOX_XPCOM_HOME"); + if (home) { + char path[PATH_MAX]; + snprintf(path, sizeof(path), "%s/%s", home, libSpec.value.pathname); + libSpec.value.pathname = path; + xpcomLib = PR_LoadLibraryWithFlags(libSpec, PR_LD_LAZY|PR_LD_GLOBAL); + } + } +#endif + if (!xpcomLib) + return NS_ERROR_FAILURE; + + function = (GetFrozenFunctionsFunc) PR_FindSymbol(xpcomLib, "NS_GetFrozenFunctions"); + + if (!function) + rv = NS_ERROR_FAILURE; + else + rv = (*function)(&xpcomFunctions, libSpec.value.pathname); + } + + if (NS_FAILED(rv)) + goto bail; + + rv = GlueStartupDebug(); + if (NS_FAILED(rv)) + goto bail; + + // startup the nsMemory + rv = GlueStartupMemory(); + if (NS_FAILED(rv)) { + GlueShutdownDebug(); + goto bail; + } + + GRE_AddGREToEnvironment(); + return NS_OK; + +bail: + PR_UnloadLibrary(xpcomLib); + xpcomLib = nsnull; + memset(&xpcomFunctions, 0, sizeof(xpcomFunctions)); + return NS_ERROR_FAILURE; +#endif +} + +extern "C" +nsresult XPCOMGlueShutdown() +{ +#ifdef XPCOM_GLUE_NO_DYNAMIC_LOADING + return NS_OK; +#else + + GlueShutdownMemory(); + + GlueShutdownDebug(); + + if (xpcomLib) { + PR_UnloadLibrary(xpcomLib); + xpcomLib = nsnull; + } + + memset(&xpcomFunctions, 0, sizeof(xpcomFunctions)); + return NS_OK; +#endif +} + +#ifndef XPCOM_GLUE_NO_DYNAMIC_LOADING +extern "C" NS_COM nsresult +NS_InitXPCOM2(nsIServiceManager* *result, + nsIFile* binDirectory, + nsIDirectoryServiceProvider* appFileLocationProvider) +{ + if (!xpcomFunctions.init) + return NS_ERROR_NOT_INITIALIZED; + return xpcomFunctions.init(result, binDirectory, appFileLocationProvider); +} + +extern "C" NS_COM nsresult +NS_ShutdownXPCOM(nsIServiceManager* servMgr) +{ + if (!xpcomFunctions.shutdown) + return NS_ERROR_NOT_INITIALIZED; + return xpcomFunctions.shutdown(servMgr); +} + +extern "C" NS_COM nsresult +NS_GetServiceManager(nsIServiceManager* *result) +{ + if (!xpcomFunctions.getServiceManager) + return NS_ERROR_NOT_INITIALIZED; + return xpcomFunctions.getServiceManager(result); +} + +extern "C" NS_COM nsresult +NS_GetComponentManager(nsIComponentManager* *result) +{ + if (!xpcomFunctions.getComponentManager) + return NS_ERROR_NOT_INITIALIZED; + return xpcomFunctions.getComponentManager(result); +} + +extern "C" NS_COM nsresult +NS_GetComponentRegistrar(nsIComponentRegistrar* *result) +{ + if (!xpcomFunctions.getComponentRegistrar) + return NS_ERROR_NOT_INITIALIZED; + return xpcomFunctions.getComponentRegistrar(result); +} + +extern "C" NS_COM nsresult +NS_GetMemoryManager(nsIMemory* *result) +{ + if (!xpcomFunctions.getMemoryManager) + return NS_ERROR_NOT_INITIALIZED; + return xpcomFunctions.getMemoryManager(result); +} + +extern "C" NS_COM nsresult +NS_NewLocalFile(const nsAString &path, PRBool followLinks, nsILocalFile* *result) +{ + if (!xpcomFunctions.newLocalFile) + return NS_ERROR_NOT_INITIALIZED; + return xpcomFunctions.newLocalFile(path, followLinks, result); +} + +extern "C" NS_COM nsresult +NS_NewNativeLocalFile(const nsACString &path, PRBool followLinks, nsILocalFile* *result) +{ + if (!xpcomFunctions.newNativeLocalFile) + return NS_ERROR_NOT_INITIALIZED; + return xpcomFunctions.newNativeLocalFile(path, followLinks, result); +} + +extern "C" NS_COM nsresult +NS_RegisterXPCOMExitRoutine(XPCOMExitRoutine exitRoutine, PRUint32 priority) +{ + if (!xpcomFunctions.registerExitRoutine) + return NS_ERROR_NOT_INITIALIZED; + return xpcomFunctions.registerExitRoutine(exitRoutine, priority); +} + +extern "C" NS_COM nsresult +NS_UnregisterXPCOMExitRoutine(XPCOMExitRoutine exitRoutine) +{ + if (!xpcomFunctions.unregisterExitRoutine) + return NS_ERROR_NOT_INITIALIZED; + return xpcomFunctions.unregisterExitRoutine(exitRoutine); +} + +extern "C" NS_COM nsresult +NS_GetDebug(nsIDebug* *result) +{ + if (!xpcomFunctions.getDebug) + return NS_ERROR_NOT_INITIALIZED; + return xpcomFunctions.getDebug(result); +} + + +extern "C" NS_COM nsresult +NS_GetTraceRefcnt(nsITraceRefcnt* *result) +{ + if (!xpcomFunctions.getTraceRefcnt) + return NS_ERROR_NOT_INITIALIZED; + return xpcomFunctions.getTraceRefcnt(result); +} + + +extern "C" NS_COM nsresult +NS_StringContainerInit(nsStringContainer &aStr) +{ + if (!xpcomFunctions.stringContainerInit) + return NS_ERROR_NOT_INITIALIZED; + return xpcomFunctions.stringContainerInit(aStr); +} + +extern "C" NS_COM void +NS_StringContainerFinish(nsStringContainer &aStr) +{ + if (xpcomFunctions.stringContainerFinish) + xpcomFunctions.stringContainerFinish(aStr); +} + +extern "C" NS_COM PRUint32 +NS_StringGetData(const nsAString &aStr, const PRUnichar **aBuf, PRBool *aTerm) +{ + if (!xpcomFunctions.stringGetData) { + *aBuf = nsnull; + return 0; + } + return xpcomFunctions.stringGetData(aStr, aBuf, aTerm); +} + +extern "C" NS_COM PRUnichar * +NS_StringCloneData(const nsAString &aStr) +{ + if (!xpcomFunctions.stringCloneData) + return nsnull; + return xpcomFunctions.stringCloneData(aStr); +} + +extern "C" NS_COM nsresult +NS_StringSetData(nsAString &aStr, const PRUnichar *aBuf, PRUint32 aCount) +{ + if (!xpcomFunctions.stringSetData) + return NS_ERROR_NOT_INITIALIZED; + + return xpcomFunctions.stringSetData(aStr, aBuf, aCount); +} + +extern "C" NS_COM nsresult +NS_StringSetDataRange(nsAString &aStr, PRUint32 aCutStart, PRUint32 aCutLength, + const PRUnichar *aBuf, PRUint32 aCount) +{ + if (!xpcomFunctions.stringSetDataRange) + return NS_ERROR_NOT_INITIALIZED; + return xpcomFunctions.stringSetDataRange(aStr, aCutStart, aCutLength, aBuf, aCount); +} + +extern "C" NS_COM nsresult +NS_StringCopy(nsAString &aDest, const nsAString &aSrc) +{ + if (!xpcomFunctions.stringCopy) + return NS_ERROR_NOT_INITIALIZED; + return xpcomFunctions.stringCopy(aDest, aSrc); +} + + +extern "C" NS_COM nsresult +NS_CStringContainerInit(nsCStringContainer &aStr) +{ + if (!xpcomFunctions.cstringContainerInit) + return NS_ERROR_NOT_INITIALIZED; + return xpcomFunctions.cstringContainerInit(aStr); +} + +extern "C" NS_COM void +NS_CStringContainerFinish(nsCStringContainer &aStr) +{ + if (xpcomFunctions.cstringContainerFinish) + xpcomFunctions.cstringContainerFinish(aStr); +} + +extern "C" NS_COM PRUint32 +NS_CStringGetData(const nsACString &aStr, const char **aBuf, PRBool *aTerm) +{ + if (!xpcomFunctions.cstringGetData) { + *aBuf = nsnull; + return 0; + } + return xpcomFunctions.cstringGetData(aStr, aBuf, aTerm); +} + +extern "C" NS_COM char * +NS_CStringCloneData(const nsACString &aStr) +{ + if (!xpcomFunctions.cstringCloneData) + return nsnull; + return xpcomFunctions.cstringCloneData(aStr); +} + +extern "C" NS_COM nsresult +NS_CStringSetData(nsACString &aStr, const char *aBuf, PRUint32 aCount) +{ + if (!xpcomFunctions.cstringSetData) + return NS_ERROR_NOT_INITIALIZED; + return xpcomFunctions.cstringSetData(aStr, aBuf, aCount); +} + +extern "C" NS_COM nsresult +NS_CStringSetDataRange(nsACString &aStr, PRUint32 aCutStart, PRUint32 aCutLength, + const char *aBuf, PRUint32 aCount) +{ + if (!xpcomFunctions.cstringSetDataRange) + return NS_ERROR_NOT_INITIALIZED; + return xpcomFunctions.cstringSetDataRange(aStr, aCutStart, aCutLength, aBuf, aCount); +} + +extern "C" NS_COM nsresult +NS_CStringCopy(nsACString &aDest, const nsACString &aSrc) +{ + if (!xpcomFunctions.cstringCopy) + return NS_ERROR_NOT_INITIALIZED; + return xpcomFunctions.cstringCopy(aDest, aSrc); +} + +extern "C" NS_COM nsresult +NS_CStringToUTF16(const nsACString &aSrc, PRUint32 aSrcEncoding, nsAString &aDest) +{ + if (!xpcomFunctions.cstringToUTF16) + return NS_ERROR_NOT_INITIALIZED; + return xpcomFunctions.cstringToUTF16(aSrc, aSrcEncoding, aDest); +} + +extern "C" NS_COM nsresult +NS_UTF16ToCString(const nsAString &aSrc, PRUint32 aDestEncoding, nsACString &aDest) +{ + if (!xpcomFunctions.utf16ToCString) + return NS_ERROR_NOT_INITIALIZED; + return xpcomFunctions.utf16ToCString(aSrc, aDestEncoding, aDest); +} + +#endif // #ifndef XPCOM_GLUE_NO_DYNAMIC_LOADING + + +static char sEnvString[MAXPATHLEN*10]; +static char* spEnvString = 0; + +void +GRE_AddGREToEnvironment() +{ + const char* grePath = GRE_GetGREPath(); + char szPath[MAXPATHLEN]; + if (!grePath) + return; + + const char* path = PR_GetEnv(XPCOM_SEARCH_KEY); + if (!path) + path = ""; +#ifdef VBOX + else + { + /* sEnvString is part of the environment because of putenv(). + * path is only temporarily used and not argument of putenv() itself */ + snprintf(szPath, sizeof(szPath), "%s", path); + path = szPath; + } +#endif + + if (spEnvString) PR_smprintf_free(spEnvString); + + /** + * if the PATH string is longer than our static buffer, allocate a + * buffer for the environment string. This buffer will be leaked at shutdown! + */ + if (strlen(grePath) + strlen(path) + + sizeof(XPCOM_SEARCH_KEY) + sizeof(XPCOM_ENV_PATH_SEPARATOR) > MAXPATHLEN*10) { + if (PR_smprintf(XPCOM_SEARCH_KEY "=%s" XPCOM_ENV_PATH_SEPARATOR "%s", + grePath, + path)) { + PR_SetEnv(spEnvString); + } + } else { + if (sprintf(sEnvString, + XPCOM_SEARCH_KEY "=%s" XPCOM_ENV_PATH_SEPARATOR "%s", + grePath, + path) > 0) { + PR_SetEnv(sEnvString); + } + } + +#if XP_WIN32 + // On windows, the current directory is searched before the + // PATH environment variable. This is a very bad thing + // since libraries in the cwd will be picked up before + // any that are in either the application or GRE directory. + + if (grePath) { + SetCurrentDirectory(grePath); + } +#endif +} + + +// Default GRE startup/shutdown code + +extern "C" +nsresult GRE_Startup() +{ + const char* xpcomLocation = GRE_GetXPCOMPath(); + + // Startup the XPCOM Glue that links us up with XPCOM. + nsresult rv = XPCOMGlueStartup(xpcomLocation); + + if (NS_FAILED(rv)) { + NS_WARNING("gre: XPCOMGlueStartup failed"); + return rv; + } + + nsGREDirServiceProvider *provider = new nsGREDirServiceProvider(); + if ( !provider ) { + NS_WARNING("GRE_Startup failed"); + XPCOMGlueShutdown(); + return NS_ERROR_OUT_OF_MEMORY; + } + + nsCOMPtr servMan; + NS_ADDREF( provider ); + rv = NS_InitXPCOM2(getter_AddRefs(servMan), nsnull, provider); + NS_RELEASE(provider); + + if ( NS_FAILED(rv) || !servMan) { + NS_WARNING("gre: NS_InitXPCOM failed"); + XPCOMGlueShutdown(); + return rv; + } + + return NS_OK; +} + +extern "C" +nsresult GRE_Shutdown() +{ + NS_ShutdownXPCOM(nsnull); + XPCOMGlueShutdown(); + return NS_OK; +} diff --git a/src/libs/xpcom18a4/xpcom/glue/standalone/nsXPCOMGlue.h b/src/libs/xpcom18a4/xpcom/glue/standalone/nsXPCOMGlue.h new file mode 100644 index 00000000..6044e084 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/glue/standalone/nsXPCOMGlue.h @@ -0,0 +1,109 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nscore.h" + +class nsILocalFile; + +/** + * Initialize the XPCOM glue by dynamically linking against the XPCOM + * shared library indicated by xpcomFile. + */ + +extern "C" +nsresult XPCOMGlueStartup(const char* xpcomFile); + + +/** + * Finish the XPCOM glue after it is no longer needed. + */ + +extern "C" +nsresult XPCOMGlueShutdown(); + + +/** + * Locate the path of a compatible GRE. + * + * @return string buffer pointing to the GRE path (without a trailing + * directory separator). Callers do no need to free this buffer. + */ + +extern "C" +char const * GRE_GetGREPath(); + + +/** + * Locate the path of a compatible GRE. This is returned as an + * nsILocalFile instead of a char*. + * + * @param _retval Ordinary XPCOM getter, returns an addrefed interface. + */ + +extern "C" +nsresult GRE_GetGREDirectory(nsILocalFile* *_retval); + + +/** + * Locate the path of the XPCOM binary of a compatible GRE. + * The result of this function is normally passed directly to + * XPCOMGlueStartup. + * + * @return string buffer pointing to the XPCOM DLL path. Callers do + * not need to free this buffer. + */ + +extern "C" +char const * GRE_GetXPCOMPath(); + + +/** + * Embedding applications which don't need a custom + * directoryserviceprovider may use GRE_Startup to start the XPCOM + * glue and initialize the GRE in one step. + */ + +extern "C" +nsresult GRE_Startup(); + + +/** + * Shut down XPCOM and the XPCOM glue in one step. + */ + +extern "C" +nsresult GRE_Shutdown(); diff --git a/src/libs/xpcom18a4/xpcom/io/.cvsignore b/src/libs/xpcom18a4/xpcom/io/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/xpcom/io/Makefile.in b/src/libs/xpcom18a4/xpcom/io/Makefile.in new file mode 100644 index 00000000..ed2f3f6d --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/Makefile.in @@ -0,0 +1,175 @@ +# +# ***** 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.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of 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 ***** + +DEPTH = ../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = xpcom +XPIDL_MODULE = xpcom_io +LIBRARY_NAME = xpcomio_s +GRE_MODULE = 1 +REQUIRES = string \ + $(NULL) + +ifneq (,$(filter mac cocoa,$(MOZ_WIDGET_TOOLKIT))) +REQUIRES += macmorefiles +endif + +CPPSRCS = \ + nsAppFileLocationProvider.cpp \ + nsBinaryStream.cpp \ + nsByteArrayInputStream.cpp \ + nsDirectoryService.cpp \ + nsEscape.cpp \ + nsFastLoadFile.cpp \ + nsFastLoadService.cpp \ + nsInputStreamTee.cpp \ + nsLinebreakConverter.cpp \ + nsLocalFileCommon.cpp \ + nsMultiplexInputStream.cpp \ + nsPipe3.cpp \ + nsStreamUtils.cpp \ + nsScriptableInputStream.cpp \ + nsSegmentedBuffer.cpp \ + SpecialSystemDirectory.cpp \ + nsStorageStream.cpp \ + nsStringStream.cpp \ + nsUnicharInputStream.cpp \ + nsNativeCharsetUtils.cpp \ + $(NULL) + +ifeq ($(MOZ_WIDGET_TOOLKIT),os2) +CPPSRCS += nsLocalFileOS2.cpp +else +ifneq (,$(filter mac cocoa,$(MOZ_WIDGET_TOOLKIT))) +CPPSRCS += nsLocalFileOSX.cpp +else +ifeq ($(MOZ_WIDGET_TOOLKIT),windows) +CPPSRCS += nsLocalFileWin.cpp +else +CPPSRCS += nsLocalFileUnix.cpp +endif # windows +endif # mac +endif # OS2 + +EXPORTS = \ + nsAppDirectoryServiceDefs.h \ + nsDirectoryService.h \ + nsDirectoryServiceUtils.h \ + nsEscape.h \ + nsFastLoadPtr.h \ + nsFastLoadService.h \ + nsIUnicharInputStream.h \ + nsLinebreakConverter.h \ + nsLocalFile.h \ + nsMultiplexInputStream.h \ + nsScriptableInputStream.h \ + nsStorageStream.h \ + nsStringIO.h \ + nsStringStream.h \ + nsStreamUtils.h \ + nsNativeCharsetUtils.h \ + $(NULL) + +ifeq ($(MOZ_WIDGET_TOOLKIT),os2) +EXPORTS += nsLocalFileOS2.h +else +ifneq (,$(filter mac cocoa,$(MOZ_WIDGET_TOOLKIT))) +EXPORTS += nsLocalFileOSX.h +else +ifeq ($(MOZ_WIDGET_TOOLKIT),windows) +EXPORTS += nsLocalFileWin.h +else +EXPORTS += nsLocalFileUnix.h +endif # windows +endif # mac +endif # os2 + +XPIDLSRCS = \ + nsIBinaryInputStream.idl \ + nsIBinaryOutputStream.idl \ + nsIByteArrayInputStream.idl \ + nsIFastLoadFileControl.idl \ + nsIFastLoadService.idl \ + nsIInputStreamTee.idl \ + nsILineInputStream.idl \ + nsIMultiplexInputStream.idl \ + nsIObjectInputStream.idl \ + nsIObjectOutputStream.idl \ + nsIPipe.idl \ + nsISeekableStream.idl \ + nsIStorageStream.idl \ + nsIStringStream.idl \ + nsIStreamBufferAccess.idl \ + nsIAsyncInputStream.idl \ + nsIAsyncOutputStream.idl \ + $(NULL) + +ifneq (,$(filter mac cocoa,$(MOZ_WIDGET_TOOLKIT))) +XPIDLSRCS += nsILocalFileMac.idl +endif + +SDK_XPIDLSRCS = \ + nsIDirectoryService.idl \ + nsIFile.idl \ + nsILocalFile.idl \ + nsIInputStream.idl \ + nsIOutputStream.idl \ + nsIScriptableInputStream.idl \ + $(NULL) + +SDK_HEADERS = \ + nsDirectoryServiceDefs.h \ + $(NULL) + +EXPORTS := $(addprefix $(srcdir)/, $(EXPORTS)) + +# we don't want the shared lib, but we want to force the creation of a static lib. +FORCE_STATIC_LIB = 1 + +# Force use of PIC +FORCE_USE_PIC = 1 + +include $(topsrcdir)/config/rules.mk + +DEFINES += -D_IMPL_NS_COM + +LOCAL_INCLUDES = -I.. diff --git a/src/libs/xpcom18a4/xpcom/io/SpecialSystemDirectory.cpp b/src/libs/xpcom18a4/xpcom/io/SpecialSystemDirectory.cpp new file mode 100644 index 00000000..5d1bc4fd --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/SpecialSystemDirectory.cpp @@ -0,0 +1,770 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Doug Turner + * IBM Corp. + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "SpecialSystemDirectory.h" +#include "nsString.h" +#include "nsDependentString.h" + + +#ifdef XP_MAC + +#include +#include +#include +#include +#include +#include "nsIInternetConfigService.h" + + +#if UNIVERSAL_INTERFACES_VERSION < 0x0340 + enum { + kSystemDomain = -32766, /* Read-only system hierarchy.*/ + kLocalDomain = -32765, /* All users of a single machine have access to these resources.*/ + kNetworkDomain = -32764, /* All users configured to use a common network server has access to these resources.*/ + kUserDomain = -32763, /* Read/write. Resources that are private to the user.*/ + kClassicDomain = -32762, /* Domain referring to the currently configured Classic System Folder*/ + + kDomainLibraryFolderType = FOUR_CHAR_CODE('dlib') + }; +#endif + +#elif defined(XP_WIN) + +#include +#include +#include +#include +#include + +#elif defined(XP_OS2) + +#define MAX_PATH _MAX_PATH +#define INCL_WINWORKPLACE +#define INCL_DOSMISC +#define INCL_DOSMODULEMGR +#define INCL_DOSPROCESS +#define INCL_WINSHELLDATA +#include +#include +#include +#include "prenv.h" + +#elif defined(XP_UNIX) + +#include +#include +#include +#include "prenv.h" +# if defined(XP_MACOSX) && defined(VBOX_WITH_NEWER_OSX_SDK) +# include +# endif + +#elif defined(XP_BEOS) + +#include +#include +#include +#include +#include +#include +#include +#include "prenv.h" + +#endif + +#if defined(VMS) +#include +#endif + + + +#if defined (XP_WIN) +typedef BOOL (WINAPI * GetSpecialPathProc) (HWND hwndOwner, LPSTR lpszPath, int nFolder, BOOL fCreate); +GetSpecialPathProc gGetSpecialPathProc = NULL; +static HINSTANCE gShell32DLLInst = NULL; +#endif +NS_COM void StartupSpecialSystemDirectory() +{ +#if defined (XP_WIN) + /* On windows, the old method to get file locations is incredibly slow. + As of this writing, 3 calls to GetWindowsFolder accounts for 3% of mozilla + startup. Replacing these older calls with a single call to SHGetSpecialFolderPath + effectively removes these calls from the performace radar. We need to + support the older way of file location lookup on systems that do not have + IE4. (Note: gets the ansi version: SHGetSpecialFolderPathA). + */ + gShell32DLLInst = LoadLibrary("Shell32.dll"); + if(gShell32DLLInst) + { + gGetSpecialPathProc = (GetSpecialPathProc) GetProcAddress(gShell32DLLInst, + "SHGetSpecialFolderPathA"); + } +#endif +} + +NS_COM void ShutdownSpecialSystemDirectory() +{ +#if defined (XP_WIN) + if (gShell32DLLInst) + { + FreeLibrary(gShell32DLLInst); + gShell32DLLInst = NULL; + gGetSpecialPathProc = NULL; + } +#endif +} + +#if defined (XP_WIN) + +//---------------------------------------------------------------------------------------- +static nsresult GetWindowsFolder(int folder, nsILocalFile** aFile) +//---------------------------------------------------------------------------------------- +{ + if (gGetSpecialPathProc) { + TCHAR path[MAX_PATH]; + HRESULT result = gGetSpecialPathProc(NULL, path, folder, true); + + if (!SUCCEEDED(result)) + return NS_ERROR_FAILURE; + + // Append the trailing slash + int len = strlen(path); + if (len>1 && path[len-1] != '\\') + { + path[len] = '\\'; + path[len + 1] = '\0'; + } + + return NS_NewNativeLocalFile(nsDependentCString(path), + PR_TRUE, + aFile); + } + + nsresult rv = NS_ERROR_FAILURE; + LPMALLOC pMalloc = NULL; + LPSTR pBuffer = NULL; + LPITEMIDLIST pItemIDList = NULL; + int len; + + // Get the shell's allocator. + if (!SUCCEEDED(SHGetMalloc(&pMalloc))) + return NS_ERROR_FAILURE; + + // Allocate a buffer + if ((pBuffer = (LPSTR) pMalloc->Alloc(MAX_PATH + 2)) == NULL) + return NS_ERROR_FAILURE; + + // Get the PIDL for the folder. + if (!SUCCEEDED(SHGetSpecialFolderLocation( + NULL, folder, &pItemIDList))) + goto Clean; + + if (!SUCCEEDED(SHGetPathFromIDList(pItemIDList, pBuffer))) + goto Clean; + + // Append the trailing slash + len = strlen(pBuffer); + pBuffer[len] = '\\'; + pBuffer[len + 1] = '\0'; + + // Assign the directory + rv = NS_NewNativeLocalFile(nsDependentCString(pBuffer), + PR_TRUE, + aFile); + +Clean: + // Clean up. + if (pItemIDList) + pMalloc->Free(pItemIDList); + if (pBuffer) + pMalloc->Free(pBuffer); + + pMalloc->Release(); + + return rv; +} + +#endif // XP_WIN + + + + +nsresult +GetSpecialSystemDirectory(SystemDirectories aSystemSystemDirectory, + nsILocalFile** aFile) +{ +#ifdef XP_MAC + OSErr err; + short vRefNum; + long dirID; +#endif + + switch (aSystemSystemDirectory) + { + case OS_DriveDirectory: +#if defined (XP_WIN) + { + char path[_MAX_PATH]; + PRInt32 len = GetWindowsDirectory( path, _MAX_PATH ); + if (len) + { + if ( path[1] == ':' && path[2] == '\\' ) + path[3] = 0; + } + + return NS_NewNativeLocalFile(nsDependentCString(path), + PR_TRUE, + aFile); + } +#elif defined(XP_OS2) + { + ULONG ulBootDrive = 0; + char buffer[] = " :\\OS2\\"; + DosQuerySysInfo( QSV_BOOT_DRIVE, QSV_BOOT_DRIVE, + &ulBootDrive, sizeof ulBootDrive); + buffer[0] = 'A' - 1 + ulBootDrive; // duh, 1-based index... + + return NS_NewNativeLocalFile(nsDependentCString(buffer), + PR_TRUE, + aFile); + } +#elif defined(XP_MAC) + { + return nsIFileFromOSType(kVolumeRootFolderType, aFile); + } +#else + return NS_NewNativeLocalFile(nsDependentCString("/"), + PR_TRUE, + aFile); + +#endif + + case OS_TemporaryDirectory: +#if defined (XP_WIN) + { + char path[_MAX_PATH]; + DWORD len = GetTempPath(_MAX_PATH, path); + return NS_NewNativeLocalFile(nsDependentCString(path), + PR_TRUE, + aFile); + } +#elif defined(XP_OS2) + { + char buffer[CCHMAXPATH] = ""; + char *c = getenv( "TMP"); + if( c) strcpy( buffer, c); + else + { + c = getenv( "TEMP"); + if( c) strcpy( buffer, c); + } + + return NS_NewNativeLocalFile(nsDependentCString(buffer), + PR_TRUE, + aFile); + } +#elif defined(XP_MAC) + return nsIFileFromOSType(kTemporaryFolderType, aFile); + +#elif defined(XP_MACOSX) + { + return GetOSXFolderType(kUserDomain, kTemporaryFolderType, aFile); + } + +#elif defined(XP_UNIX) || defined(XP_BEOS) + { + static const char *tPath = nsnull; + if (!tPath) { + tPath = PR_GetEnv("TMPDIR"); + if (!tPath || !*tPath) { + tPath = PR_GetEnv("TMP"); + if (!tPath || !*tPath) { + tPath = PR_GetEnv("TEMP"); + if (!tPath || !*tPath) { + tPath = "/tmp/"; + } + } + } + } + return NS_NewNativeLocalFile(nsDependentCString(tPath), + PR_TRUE, + aFile); + } +#else + break; +#endif + +#if defined(XP_MAC) + case Mac_SystemDirectory: + return nsIFileFromOSType(kSystemFolderType, aFile); + + case Mac_DesktopDirectory: + return nsIFileFromOSType(kDesktopFolderType, aFile); + + case Mac_TrashDirectory: + return nsIFileFromOSType(kTrashFolderType, aFile); + + case Mac_StartupDirectory: + return nsIFileFromOSType(kStartupFolderType, aFile); + + case Mac_ShutdownDirectory: + return nsIFileFromOSType(kShutdownFolderType, aFile); + + case Mac_AppleMenuDirectory: + return nsIFileFromOSType(kAppleMenuFolderType, aFile); + + case Mac_ControlPanelDirectory: + return nsIFileFromOSType(kControlPanelFolderType, aFile); + + case Mac_ExtensionDirectory: + return nsIFileFromOSType(kExtensionFolderType, aFile); + + case Mac_FontsDirectory: + return nsIFileFromOSType(kFontsFolderType, aFile); + + case Mac_ClassicPreferencesDirectory: + { + // whether Mac OS X or pre-Mac OS X, return Classic's Prefs folder + short domain; + long response; + err = ::Gestalt(gestaltSystemVersion, &response); + domain = (!err && response >= 0x00001000) ? kClassicDomain : kOnSystemDisk; + err = ::FindFolder(domain, kPreferencesFolderType, true, &vRefNum, &dirID); + if (!err) { + err = ::FSMakeFSSpec(vRefNum, dirID, "\p", &mSpec); + } + return NS_FILE_RESULT(err); + } + + case Mac_PreferencesDirectory: + { + // if Mac OS X, return Mac OS X's Prefs folder + // if pre-Mac OS X, return Mac OS's Prefs folder + err = ::FindFolder(kOnSystemDisk, kPreferencesFolderType, true, &vRefNum, &dirID); + if (!err) { + err = ::FSMakeFSSpec(vRefNum, dirID, "\p", &mSpec); + } + return NS_FILE_RESULT(err); + } + + case Mac_DocumentsDirectory: + return nsIFileFromOSType(kDocumentsFolderType, aFile); + + case Mac_InternetSearchDirectory: + return nsIFileFromOSType(kInternetSearchSitesFolderType, aFile); + + case Mac_DefaultDownloadDirectory: + return nsIFileFromOSType(kDefaultDownloadFolderType, aFile); + + case Mac_UserLibDirectory: + { + FSSpec spec; + err = ::FindFolder(kUserDomain, kDomainLibraryFolderType, true, &vRefNum, &dirID); + if (!err) { + err = ::FSMakeFSSpec(vRefNum, dirID, "\p", &spec); + } + + return NS_NewLocalFileWithFSSpec(&spec, PR_FALUE, aFile); + } +#endif + +#if defined (XP_WIN) + case Win_SystemDirectory: + { + char path[_MAX_PATH]; + PRInt32 len = GetSystemDirectory( path, _MAX_PATH ); + + // Need enough space to add the trailing backslash + if (len > _MAX_PATH-2) + break; + path[len] = '\\'; + path[len+1] = '\0'; + + return NS_NewNativeLocalFile(nsDependentCString(path), + PR_TRUE, + aFile); + } + + case Win_WindowsDirectory: + { + char path[_MAX_PATH]; + PRInt32 len = GetWindowsDirectory( path, _MAX_PATH ); + + // Need enough space to add the trailing backslash + if (len > _MAX_PATH-2) + break; + + path[len] = '\\'; + path[len+1] = '\0'; + + return NS_NewNativeLocalFile(nsDependentCString(path), + PR_TRUE, + aFile); + } + + case Win_HomeDirectory: + { + char path[_MAX_PATH]; + if (GetEnvironmentVariable(TEXT("HOME"), path, _MAX_PATH) > 0) + { + PRInt32 len = strlen(path); + // Need enough space to add the trailing backslash + if (len > _MAX_PATH - 2) + break; + + path[len] = '\\'; + path[len+1] = '\0'; + + return NS_NewNativeLocalFile(nsDependentCString(path), + PR_TRUE, + aFile); + } + + if (GetEnvironmentVariable(TEXT("HOMEDRIVE"), path, _MAX_PATH) > 0) + { + char temp[_MAX_PATH]; + if (GetEnvironmentVariable(TEXT("HOMEPATH"), temp, _MAX_PATH) > 0) + strncat(path, temp, _MAX_PATH); + + PRInt32 len = strlen(path); + + // Need enough space to add the trailing backslash + if (len > _MAX_PATH - 2) + break; + + path[len] = '\\'; + path[len+1] = '\0'; + + return NS_NewNativeLocalFile(nsDependentCString(path), + PR_TRUE, + aFile); + } + } + case Win_Desktop: + { + return GetWindowsFolder(CSIDL_DESKTOP, aFile); + } + case Win_Programs: + { + return GetWindowsFolder(CSIDL_PROGRAMS, aFile); + } + case Win_Controls: + { + return GetWindowsFolder(CSIDL_CONTROLS, aFile); + } + case Win_Printers: + { + return GetWindowsFolder(CSIDL_PRINTERS, aFile); + } + case Win_Personal: + { + return GetWindowsFolder(CSIDL_PERSONAL, aFile); + } + case Win_Favorites: + { + return GetWindowsFolder(CSIDL_FAVORITES, aFile); + } + case Win_Startup: + { + return GetWindowsFolder(CSIDL_STARTUP, aFile); + } + case Win_Recent: + { + return GetWindowsFolder(CSIDL_RECENT, aFile); + } + case Win_Sendto: + { + return GetWindowsFolder(CSIDL_SENDTO, aFile); + } + case Win_Bitbucket: + { + return GetWindowsFolder(CSIDL_BITBUCKET, aFile); + } + case Win_Startmenu: + { + return GetWindowsFolder(CSIDL_STARTMENU, aFile); + } + case Win_Desktopdirectory: + { + return GetWindowsFolder(CSIDL_DESKTOPDIRECTORY, aFile); + } + case Win_Drives: + { + return GetWindowsFolder(CSIDL_DRIVES, aFile); + } + case Win_Network: + { + return GetWindowsFolder(CSIDL_NETWORK, aFile); + } + case Win_Nethood: + { + return GetWindowsFolder(CSIDL_NETHOOD, aFile); + } + case Win_Fonts: + { + return GetWindowsFolder(CSIDL_FONTS, aFile); + } + case Win_Templates: + { + return GetWindowsFolder(CSIDL_TEMPLATES, aFile); + } + case Win_Common_Startmenu: + { + return GetWindowsFolder(CSIDL_COMMON_STARTMENU, aFile); + } + case Win_Common_Programs: + { + return GetWindowsFolder(CSIDL_COMMON_PROGRAMS, aFile); + } + case Win_Common_Startup: + { + return GetWindowsFolder(CSIDL_COMMON_STARTUP, aFile); + } + case Win_Common_Desktopdirectory: + { + return GetWindowsFolder(CSIDL_COMMON_DESKTOPDIRECTORY, aFile); + } + case Win_Appdata: + { + return GetWindowsFolder(CSIDL_APPDATA, aFile); + } + case Win_Printhood: + { + return GetWindowsFolder(CSIDL_PRINTHOOD, aFile); + } + case Win_Cookies: + { + return GetWindowsFolder(CSIDL_COOKIES, aFile); + } +#endif // XP_WIN + +#if defined(XP_UNIX) + case Unix_LocalDirectory: + return NS_NewNativeLocalFile(nsDependentCString("/usr/local/netscape/"), + PR_TRUE, + aFile); + case Unix_LibDirectory: + return NS_NewNativeLocalFile(nsDependentCString("/usr/local/lib/netscape/"), + PR_TRUE, + aFile); + + case Unix_HomeDirectory: +#ifdef VMS + { + char *pHome; + pHome = getenv("HOME"); + if (*pHome == '/') { + return NS_NewNativeLocalFile(nsDependentCString(pHome), + PR_TRUE, + aFile); + + } + else + { + return NS_NewNativeLocalFile(nsDependentCString(decc$translate_vms(pHome)), + PR_TRUE, + aFile); + } + } +#else + return NS_NewNativeLocalFile(nsDependentCString(PR_GetEnv("HOME")), + PR_TRUE, + aFile); + +#endif + +#endif + +#ifdef XP_BEOS + case BeOS_SettingsDirectory: + { + char path[MAXPATHLEN]; + find_directory(B_USER_SETTINGS_DIRECTORY, 0, 0, path, MAXPATHLEN); + // Need enough space to add the trailing backslash + int len = strlen(path); + if (len > MAXPATHLEN-2) + break; + path[len] = '/'; + path[len+1] = '\0'; + return NS_NewNativeLocalFile(nsDependentCString(path), + PR_TRUE, + aFile); + } + + case BeOS_HomeDirectory: + { + char path[MAXPATHLEN]; + find_directory(B_USER_DIRECTORY, 0, 0, path, MAXPATHLEN); + // Need enough space to add the trailing backslash + int len = strlen(path); + if (len > MAXPATHLEN-2) + break; + path[len] = '/'; + path[len+1] = '\0'; + + return NS_NewNativeLocalFile(nsDependentCString(path), + PR_TRUE, + aFile); + } + + case BeOS_DesktopDirectory: + { + char path[MAXPATHLEN]; + find_directory(B_DESKTOP_DIRECTORY, 0, 0, path, MAXPATHLEN); + // Need enough space to add the trailing backslash + int len = strlen(path); + if (len > MAXPATHLEN-2) + break; + path[len] = '/'; + path[len+1] = '\0'; + + return NS_NewNativeLocalFile(nsDependentCString(path), + PR_TRUE, + aFile); + } + + case BeOS_SystemDirectory: + { + char path[MAXPATHLEN]; + find_directory(B_BEOS_DIRECTORY, 0, 0, path, MAXPATHLEN); + // Need enough space to add the trailing backslash + int len = strlen(path); + if (len > MAXPATHLEN-2) + break; + path[len] = '/'; + path[len+1] = '\0'; + + return NS_NewNativeLocalFile(nsDependentCString(path), + PR_TRUE, + aFile); + } +#endif +#ifdef XP_OS2 + case OS2_SystemDirectory: + { + ULONG ulBootDrive = 0; + char buffer[] = " :\\OS2\\System\\"; + DosQuerySysInfo( QSV_BOOT_DRIVE, QSV_BOOT_DRIVE, + &ulBootDrive, sizeof ulBootDrive); + buffer[0] = 'A' - 1 + ulBootDrive; // duh, 1-based index... + + return NS_NewNativeLocalFile(nsDependentCString(buffer), + PR_TRUE, + aFile); + } + + case OS2_OS2Directory: + { + ULONG ulBootDrive = 0; + char buffer[] = " :\\OS2\\"; + DosQuerySysInfo( QSV_BOOT_DRIVE, QSV_BOOT_DRIVE, + &ulBootDrive, sizeof ulBootDrive); + buffer[0] = 'A' - 1 + ulBootDrive; // duh, 1-based index... + + return NS_NewNativeLocalFile(nsDependentCString(buffer), + PR_TRUE, + aFile); + } + + case OS2_HomeDirectory: + { + nsresult rv; + char *tPath = PR_GetEnv("MOZILLA_HOME"); + char buffer[CCHMAXPATH]; + /* If MOZILLA_HOME is not set, use GetCurrentProcessDirectory */ + /* To ensure we get a long filename system */ + if (!tPath || !*tPath) { + PPIB ppib; + PTIB ptib; + DosGetInfoBlocks( &ptib, &ppib); + DosQueryModuleName( ppib->pib_hmte, CCHMAXPATH, buffer); + *strrchr( buffer, '\\') = '\0'; // XXX DBCS misery + tPath = buffer; + } + rv = NS_NewNativeLocalFile(nsDependentCString(tPath), + PR_TRUE, + aFile); + + PrfWriteProfileString(HINI_USERPROFILE, "Mozilla", "Home", tPath); + return rv; + } + + case OS2_DesktopDirectory: + { + char szPath[CCHMAXPATH + 1]; + BOOL fSuccess; + fSuccess = WinQueryActiveDesktopPathname (szPath, sizeof(szPath)); + int len = strlen (szPath); + if (len > CCHMAXPATH -1) + break; + szPath[len] = '\\'; + szPath[len + 1] = '\0'; + + return NS_NewNativeLocalFile(nsDependentCString(szPath), + PR_TRUE, + aFile); + } +#endif + default: + break; + } + return NS_ERROR_NOT_AVAILABLE; +} + +#if defined (XP_MACOSX) +nsresult +GetOSXFolderType(short aDomain, OSType aFolderType, nsILocalFile **localFile) +{ + OSErr err; + FSRef fsRef; + nsresult rv = NS_ERROR_FAILURE; + + err = ::FSFindFolder(aDomain, aFolderType, kCreateFolder, &fsRef); + if (err == noErr) + { + NS_NewLocalFile(EmptyString(), PR_TRUE, localFile); + nsCOMPtr localMacFile(do_QueryInterface(*localFile)); + if (localMacFile) + rv = localMacFile->InitWithFSRef(&fsRef); + } + return rv; +} +#endif + diff --git a/src/libs/xpcom18a4/xpcom/io/SpecialSystemDirectory.h b/src/libs/xpcom18a4/xpcom/io/SpecialSystemDirectory.h new file mode 100644 index 00000000..b4aaf30e --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/SpecialSystemDirectory.h @@ -0,0 +1,136 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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 Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Doug Turner + * IBM Corp. + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +#ifndef _SPECIALSYSTEMDIRECTORY_H_ +#define _SPECIALSYSTEMDIRECTORY_H_ + +#include "nscore.h" +#include "nsILocalFile.h" + +#if defined(XP_MAC) || defined(XP_MACOSX) +# ifndef VBOX_WITH_NEWER_OSX_SDK +# include +# endif +#include "nsILocalFileMac.h" +#include "prenv.h" +#endif + + +extern NS_COM void StartupSpecialSystemDirectory(); +extern NS_COM void ShutdownSpecialSystemDirectory(); + + +enum SystemDirectories { + OS_DriveDirectory = 1, + OS_TemporaryDirectory = 2, + OS_CurrentProcessDirectory= 3, + OS_CurrentWorkingDirectory= 4, + XPCOM_CurrentProcessComponentDirectory= 5, + XPCOM_CurrentProcessComponentRegistry= 6, + + Moz_BinDirectory = 100 , + Mac_SystemDirectory = 101, + Mac_DesktopDirectory = 102, + Mac_TrashDirectory = 103, + Mac_StartupDirectory = 104, + Mac_ShutdownDirectory = 105, + Mac_AppleMenuDirectory = 106, + Mac_ControlPanelDirectory = 107, + Mac_ExtensionDirectory = 108, + Mac_FontsDirectory = 109, + Mac_ClassicPreferencesDirectory = 110, + Mac_DocumentsDirectory = 111, + Mac_InternetSearchDirectory = 112, + Mac_DefaultDownloadDirectory = 113, + Mac_UserLibDirectory = 114, + Mac_PreferencesDirectory = 115, + + Win_SystemDirectory = 201, + Win_WindowsDirectory = 202, + Win_HomeDirectory = 203, + Win_Desktop = 204, + Win_Programs = 205, + Win_Controls = 206, + Win_Printers = 207, + Win_Personal = 208, + Win_Favorites = 209, + Win_Startup = 210, + Win_Recent = 211, + Win_Sendto = 212, + Win_Bitbucket = 213, + Win_Startmenu = 214, + Win_Desktopdirectory = 215, + Win_Drives = 216, + Win_Network = 217, + Win_Nethood = 218, + Win_Fonts = 219, + Win_Templates = 220, + Win_Common_Startmenu = 221, + Win_Common_Programs = 222, + Win_Common_Startup = 223, + Win_Common_Desktopdirectory = 224, + Win_Appdata = 225, + Win_Printhood = 226, + Win_Cookies = 227, + + Unix_LocalDirectory = 301, + Unix_LibDirectory = 302, + Unix_HomeDirectory = 303, + + BeOS_SettingsDirectory = 401, + BeOS_HomeDirectory = 402, + BeOS_DesktopDirectory = 403, + BeOS_SystemDirectory = 404, + + OS2_SystemDirectory = 501, + OS2_OS2Directory = 502, + OS2_DesktopDirectory = 503, + OS2_HomeDirectory = 504 +}; + +nsresult +GetSpecialSystemDirectory(SystemDirectories aSystemSystemDirectory, + nsILocalFile** aFile); +#if defined(XP_MACOSX) +nsresult +GetOSXFolderType(short aDomain, OSType aFolderType, nsILocalFile **localFile); +#endif + +#endif diff --git a/src/libs/xpcom18a4/xpcom/io/macDirectoryCopy.c b/src/libs/xpcom18a4/xpcom/io/macDirectoryCopy.c new file mode 100644 index 00000000..838dffa2 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/macDirectoryCopy.c @@ -0,0 +1,784 @@ +/* +** Apple Macintosh Developer Technical Support +** +** DirectoryCopy: A robust, general purpose directory copy routine. +** +** by Jim Luther, Apple Developer Technical Support Emeritus +** +** File: DirectoryCopy.c +** +** Copyright © 1992-1998 Apple Computer, Inc. +** All rights reserved. +** +** You may incorporate this sample code into your applications without +** restriction, though the sample code has been provided "AS IS" and the +** responsibility for its operation is 100% yours. However, what you are +** not permitted to do is to redistribute the source as "DSC Sample Code" +** after having made changes. If you're going to re-distribute the source, +** we require that you make it clear in the source that the code was +** descended from Apple Sample Code, but that you've made changes. +*/ + +// Modified to allow renaming the destination folder + +#include +#include +#include +#include +#include + +#define __COMPILINGMOREFILES + +#include "MoreFiles.h" +#include "MoreFilesExtras.h" +#include "MoreDesktopMgr.h" +#include "FileCopy.h" +#include "MacDirectoryCopy.h" +#include + + +/*****************************************************************************/ + +enum +{ + getNextItemOp = 1, /* couldn't access items in this directory - no access privileges */ + copyDirCommentOp = 2, /* couldn't copy directory's Finder comment */ + copyDirAccessPrivsOp = 3, /* couldn't copy directory's AFP access privileges */ + copyDirFMAttributesOp = 4, /* couldn't copy directory's File Manager attributes */ + dirCreateOp = 5, /* couldn't create destination directory */ + fileCopyOp = 6 /* couldn't copy file */ +}; + +/*****************************************************************************/ + + + +#define CallCopyErrProc(userRoutine, error, failedOperation, srcVRefNum, srcDirID, srcName, dstVRefNum, dstDirID, dstName) \ + (*(userRoutine))((error), (failedOperation), (srcVRefNum), (srcDirID), (srcName), (dstVRefNum), (dstDirID), (dstName)) + +/*****************************************************************************/ + +typedef pascal Boolean (*CopyFilterProcPtr) (const CInfoPBRec * const cpbPtr); + +/* ¦ Prototype for the CopyFilterProc function. + This is the prototype for the CopyFilterProc function called by + FilteredDirectoryCopy and GetLevelSize. If true is returned, + the file/folder is included in the copy, otherwise it is excluded. + + pb input: Points to the CInfoPBRec for the item under consideration. + + __________ + + Also see: FilteredDirectoryCopy, FSpFilteredDirectoryCopy +*/ + +#define CallCopyFilterProc(userRoutine, cpbPtr) (*(userRoutine))((cpbPtr)) + + + +/*****************************************************************************/ + +/* local constants */ + +enum +{ + dirCopyBigCopyBuffSize = 0x00004000, + dirCopyMinCopyBuffSize = 0x00000200 +}; + + +/*****************************************************************************/ + +/* local data structures */ + +/* The EnumerateGlobals structure is used to minimize the amount of +** stack space used when recursively calling CopyLevel and to hold +** global information that might be needed at any time. */ + +#if PRAGMA_STRUCT_ALIGN +#pragma options align=mac68k +#endif +struct EnumerateGlobals +{ + Ptr copyBuffer; /* pointer to buffer used for file copy operations */ + long bufferSize; /* the size of the copy buffer */ + CopyErrProcPtr errorHandler; /* pointer to error handling function */ + CopyFilterProcPtr copyFilterProc; /* pointer to filter function */ + OSErr error; /* temporary holder of results - saves 2 bytes of stack each level */ + Boolean bailout; /* set to true to by error handling function if fatal error */ + short destinationVRefNum; /* the destination vRefNum */ + Str63 itemName; /* the name of the current item */ + CInfoPBRec myCPB; /* the parameter block used for PBGetCatInfo calls */ +}; +#if PRAGMA_STRUCT_ALIGN +#pragma options align=reset +#endif + +typedef struct EnumerateGlobals EnumerateGlobals; +typedef EnumerateGlobals *EnumerateGlobalsPtr; + + +/* The PreflightGlobals structure is used to minimize the amount of +** stack space used when recursively calling GetLevelSize and to hold +** global information that might be needed at any time. */ + +#if PRAGMA_STRUCT_ALIGN +#pragma options align=mac68k +#endif +struct PreflightGlobals +{ + OSErr result; /* temporary holder of results - saves 2 bytes of stack each level */ + Str63 itemName; /* the name of the current item */ + CInfoPBRec myCPB; /* the parameter block used for PBGetCatInfo calls */ + + unsigned long dstBlksPerAllocBlk; /* the number of 512 byte blocks per allocation block on destination */ + + unsigned long allocBlksNeeded; /* the total number of allocation blocks needed */ + + unsigned long tempBlocks; /* temporary storage for calculations (save some stack space) */ + CopyFilterProcPtr copyFilterProc; /* pointer to filter function */ +}; +#if PRAGMA_STRUCT_ALIGN +#pragma options align=reset +#endif + +typedef struct PreflightGlobals PreflightGlobals; +typedef PreflightGlobals *PreflightGlobalsPtr; + +/*****************************************************************************/ + +/* static prototypes */ + +static void GetLevelSize(long currentDirID, + PreflightGlobals *theGlobals); + +static OSErr PreflightDirectoryCopySpace(short srcVRefNum, + long srcDirID, + short dstVRefNum, + CopyFilterProcPtr copyFilterProc, + Boolean *spaceOK); + +static void CopyLevel(long sourceDirID, + long dstDirID, + EnumerateGlobals *theGlobals); + +/*****************************************************************************/ + +static void GetLevelSize(long currentDirID, + PreflightGlobals *theGlobals) +{ + short index = 1; + + do + { + theGlobals->myCPB.dirInfo.ioFDirIndex = index; + theGlobals->myCPB.dirInfo.ioDrDirID = currentDirID; /* we need to do this every time */ + /* through, since GetCatInfo */ + /* returns ioFlNum in this field */ + theGlobals->result = PBGetCatInfoSync(&theGlobals->myCPB); + if ( theGlobals->result == noErr ) + { + if ( (theGlobals->copyFilterProc == NULL) || + CallCopyFilterProc(theGlobals->copyFilterProc, &theGlobals->myCPB) ) /* filter if filter proc was supplied */ + { + /* Either there's no filter proc OR the filter proc says to use this item */ + if ( (theGlobals->myCPB.dirInfo.ioFlAttrib & ioDirMask) != 0 ) + { + /* we have a directory */ + + GetLevelSize(theGlobals->myCPB.dirInfo.ioDrDirID, theGlobals); /* recurse */ + theGlobals->result = noErr; /* clear error return on way back */ + } + else + { + /* We have a file - add its allocation blocks to allocBlksNeeded. */ + /* Since space on Mac OS disks is always allocated in allocation blocks, */ + /* this takes into account rounding up to the end of an allocation block. */ + + /* get number of 512-byte blocks needed for data fork */ + if ( ((unsigned long)theGlobals->myCPB.hFileInfo.ioFlLgLen & 0x000001ff) != 0 ) + { + theGlobals->tempBlocks = ((unsigned long)theGlobals->myCPB.hFileInfo.ioFlLgLen >> 9) + 1; + } + else + { + theGlobals->tempBlocks = (unsigned long)theGlobals->myCPB.hFileInfo.ioFlLgLen >> 9; + } + /* now, calculate number of new allocation blocks needed for the data fork and add it to the total */ + if ( theGlobals->tempBlocks % theGlobals->dstBlksPerAllocBlk ) + { + theGlobals->allocBlksNeeded += (theGlobals->tempBlocks / theGlobals->dstBlksPerAllocBlk) + 1; + } + else + { + theGlobals->allocBlksNeeded += theGlobals->tempBlocks / theGlobals->dstBlksPerAllocBlk; + } + + /* get number of 512-byte blocks needed for resource fork */ + if ( ((unsigned long)theGlobals->myCPB.hFileInfo.ioFlRLgLen & 0x000001ff) != 0 ) + { + theGlobals->tempBlocks = ((unsigned long)theGlobals->myCPB.hFileInfo.ioFlRLgLen >> 9) + 1; + } + else + { + theGlobals->tempBlocks = (unsigned long)theGlobals->myCPB.hFileInfo.ioFlRLgLen >> 9; + } + /* now, calculate number of new allocation blocks needed for the resource fork and add it to the total */ + if ( theGlobals->tempBlocks % theGlobals->dstBlksPerAllocBlk ) + { + theGlobals->allocBlksNeeded += (theGlobals->tempBlocks / theGlobals->dstBlksPerAllocBlk) + 1; + } + else + { + theGlobals->allocBlksNeeded += theGlobals->tempBlocks / theGlobals->dstBlksPerAllocBlk; + } + } + } + } + ++index; + } while ( theGlobals->result == noErr ); +} + +/*****************************************************************************/ + +static OSErr PreflightDirectoryCopySpace(short srcVRefNum, + long srcDirID, + short dstVRefNum, + CopyFilterProcPtr copyFilterProc, + Boolean *spaceOK) +{ + XVolumeParam pb; + OSErr error; + unsigned long dstFreeBlocks; + PreflightGlobals theGlobals; + + error = XGetVolumeInfoNoName(NULL, dstVRefNum, &pb); + if ( error == noErr ) + { + /* Convert freeBytes to free disk blocks (512-byte blocks) */ +#if (UNIVERSAL_INTERFACES_VERSION >= 0x0330) + dstFreeBlocks = (pb.ioVFreeBytes >> 9); +#else + dstFreeBlocks = (pb.ioVFreeBytes.hi << 23) + (pb.ioVFreeBytes.lo >> 9); +#endif + /* get allocation block size (always multiple of 512) and divide by 512 + to get number of 512-byte blocks per allocation block */ + theGlobals.dstBlksPerAllocBlk = ((unsigned long)pb.ioVAlBlkSiz >> 9); + + theGlobals.allocBlksNeeded = 0; + + theGlobals.myCPB.dirInfo.ioNamePtr = theGlobals.itemName; + theGlobals.myCPB.dirInfo.ioVRefNum = srcVRefNum; + + theGlobals.copyFilterProc = copyFilterProc; + + GetLevelSize(srcDirID, &theGlobals); + + /* Is there enough room on the destination volume for the source file? */ + /* Note: This will work because the largest number of disk blocks supported */ + /* on a 2TB volume is 0xffffffff and (allocBlksNeeded * dstBlksPerAllocBlk) */ + /* will always be less than 0xffffffff. */ + *spaceOK = ((theGlobals.allocBlksNeeded * theGlobals.dstBlksPerAllocBlk) <= dstFreeBlocks); + } + + return ( error ); +} + +/*****************************************************************************/ + +static void CopyLevel(long sourceDirID, + long dstDirID, + EnumerateGlobals *theGlobals) +{ + long currentSrcDirID; + long newDirID; + short index = 1; + + do + { + /* Get next source item at the current directory level */ + + theGlobals->myCPB.dirInfo.ioFDirIndex = index; + theGlobals->myCPB.dirInfo.ioDrDirID = sourceDirID; + theGlobals->error = PBGetCatInfoSync(&theGlobals->myCPB); + + if ( theGlobals->error == noErr ) + { + if ( (theGlobals->copyFilterProc == NULL) || + CallCopyFilterProc(theGlobals->copyFilterProc, &theGlobals->myCPB) ) /* filter if filter proc was supplied */ + { + /* Either there's no filter proc OR the filter proc says to use this item */ + + /* We have an item. Is it a file or directory? */ + if ( (theGlobals->myCPB.hFileInfo.ioFlAttrib & ioDirMask) != 0 ) + { + /* We have a directory */ + + /* Create a new directory at the destination. No errors allowed! */ + theGlobals->error = DirCreate(theGlobals->destinationVRefNum, dstDirID, theGlobals->itemName, &newDirID); + if ( theGlobals->error == noErr ) + { + /* Save the current source directory ID where we can get it when we come back + ** from recursion land. */ + currentSrcDirID = theGlobals->myCPB.dirInfo.ioDrDirID; + + /* Dive again (copy the directory level we just found below this one) */ + CopyLevel(theGlobals->myCPB.dirInfo.ioDrDirID, newDirID, theGlobals); + + if ( !theGlobals->bailout ) + { + /* Copy comment from old to new directory. */ + /* Ignore the result because we really don't care if it worked or not. */ + (void) DTCopyComment(theGlobals->myCPB.dirInfo.ioVRefNum, currentSrcDirID, NULL, theGlobals->destinationVRefNum, newDirID, NULL); + + /* Copy directory attributes (dates, etc.) to newDirID. */ + /* No errors allowed */ + theGlobals->error = CopyFileMgrAttributes(theGlobals->myCPB.dirInfo.ioVRefNum, currentSrcDirID, NULL, theGlobals->destinationVRefNum, newDirID, NULL, true); + + /* handle any errors from CopyFileMgrAttributes */ + if ( theGlobals->error != noErr ) + { + if ( theGlobals->errorHandler != NULL ) + { + theGlobals->bailout = CallCopyErrProc(theGlobals->errorHandler, theGlobals->error, copyDirFMAttributesOp, + theGlobals->myCPB.dirInfo.ioVRefNum, currentSrcDirID, NULL, + theGlobals->destinationVRefNum, newDirID, NULL); + } + else + { + /* If you don't handle the errors with an error handler, */ + /* then the copy stops here. */ + theGlobals->bailout = true; + } + } + } + } + else /* error handling for DirCreate */ + { + if ( theGlobals->errorHandler != NULL ) + { + theGlobals->bailout = CallCopyErrProc(theGlobals->errorHandler, theGlobals->error, dirCreateOp, + theGlobals->myCPB.dirInfo.ioVRefNum, currentSrcDirID, NULL, + theGlobals->destinationVRefNum, dstDirID, theGlobals->itemName); + } + else + { + /* If you don't handle the errors with an error handler, */ + /* then the copy stops here. */ + theGlobals->bailout = true; + } + } + + if ( !theGlobals->bailout ) + { + /* clear error return on way back if we aren't bailing out */ + theGlobals->error = noErr; + } + } + else + { + /* We have a file, so copy it */ + + theGlobals->error = FileCopy(theGlobals->myCPB.hFileInfo.ioVRefNum, + theGlobals->myCPB.hFileInfo.ioFlParID, + theGlobals->itemName, + theGlobals->destinationVRefNum, + dstDirID, + NULL, + NULL, + theGlobals->copyBuffer, + theGlobals->bufferSize, + false); + + /* handle any errors from FileCopy */ + if ( theGlobals->error != noErr ) + { + if ( theGlobals->errorHandler != NULL ) + { + theGlobals->bailout = CallCopyErrProc(theGlobals->errorHandler, theGlobals->error, fileCopyOp, + theGlobals->myCPB.hFileInfo.ioVRefNum, theGlobals->myCPB.hFileInfo.ioFlParID, theGlobals->itemName, + theGlobals->destinationVRefNum, dstDirID, NULL); + if ( !theGlobals->bailout ) + { + /* If the CopyErrProc handled the problem, clear the error here */ + theGlobals->error = noErr; + } + } + else + { + /* If you don't handle the errors with an error handler, */ + /* then the copy stops here. */ + theGlobals->bailout = true; + } + } + } + } + } + else + { /* error handling for PBGetCatInfo */ + /* it's normal to get a fnfErr when indexing; that only means you've hit the end of the directory */ + if ( theGlobals->error != fnfErr ) + { + if ( theGlobals->errorHandler != NULL ) + { + theGlobals->bailout = CallCopyErrProc(theGlobals->errorHandler, theGlobals->error, getNextItemOp, + theGlobals->myCPB.dirInfo.ioVRefNum, sourceDirID, NULL, 0, 0, NULL); + if ( !theGlobals->bailout ) + { + /* If the CopyErrProc handled the problem, clear the error here */ + theGlobals->error = noErr; + } + } + else + { + /* If you don't handle the errors with an error handler, */ + /* then the copy stops here. */ + theGlobals->bailout = true; + } + } + } + ++index; /* prepare to get next item */ + } while ( (theGlobals->error == noErr) && (!theGlobals->bailout) ); /* time to fall back a level? */ +} + +/*****************************************************************************/ + +pascal OSErr FilteredDirectoryCopy(short srcVRefNum, + long srcDirID, + ConstStr255Param srcName, + short dstVRefNum, + long dstDirID, + ConstStr255Param dstName, + void *copyBufferPtr, + long copyBufferSize, + Boolean preflight, + CopyErrProcPtr copyErrHandler, + CopyFilterProcPtr copyFilterProc, ConstStr255Param newName ); +/* ¦ Make a copy of a directory structure in a new location with item filtering. + The FilteredDirectoryCopy function makes a copy of a directory + structure in a new location. If copyBufferPtr <> NIL, it points to + a buffer of copyBufferSize that is used to copy files data. The + larger the supplied buffer, the faster the copy. If + copyBufferPtr = NIL, then this routine allocates a buffer in the + application heap. If you pass a copy buffer to this routine, make + its size a multiple of 512 ($200) bytes for optimum performance. + + The optional copyFilterProc parameter lets a routine you define + decide what files or directories are copied to the destination. + + FilteredDirectoryCopy normally creates a new directory *in* the + specified destination directory and copies the source directory's + content into the new directory. However, if root parent directory + (fsRtParID) is passed as the dstDirID parameter and NULL is + passed as the dstName parameter, DirectoryCopy renames the + destination volume to the source directory's name (truncating + if the name is longer than 27 characters) and copies the source + directory's content into the destination volume's root directory. + This special case is supported by FilteredDirectoryCopy, but + not by FSpFilteredDirectoryCopy since with FSpFilteredDirectoryCopy, + the dstName parameter can not be NULL. + + srcVRefNum input: Source volume specification. + srcDirID input: Source directory ID. + srcName input: Source directory name, or nil if + srcDirID specifies the directory. + dstVRefNum input: Destination volume specification. + dstDirID input: Destination directory ID. + dstName input: Destination directory name, or nil if + dstDirID specifies the directory. + copyBufferPtr input: Points to a buffer of copyBufferSize that + is used the i/o buffer for the copy or + nil if you want DirectoryCopy to allocate its + own buffer in the application heap. + copyBufferSize input: The size of the buffer pointed to + by copyBufferPtr. + preflight input: If true, DirectoryCopy makes sure there are + enough allocation blocks on the destination + volume to hold the directory's files before + starting the copy. + copyErrHandler input: A pointer to the routine you want called if an + error condition is detected during the copy, or + nil if you don't want to handle error conditions. + If you don't handle error conditions, the first + error will cause the copy to quit and + DirectoryCopy will return the error. + Error handling is recommended... + copyFilterProc input: A pointer to the filter routine you want called + for each item in the source directory, or NULL + if you don't want to filter. + + Result Codes + noErr 0 No error + readErr Ð19 Driver does not respond to read requests + writErr Ð20 Driver does not respond to write requests + badUnitErr Ð21 Driver reference number does not + match unit table + unitEmptyErr Ð22 Driver reference number specifies a + nil handle in unit table + abortErr Ð27 Request aborted by KillIO + notOpenErr Ð28 Driver not open + dskFulErr -34 Destination volume is full + nsvErr -35 No such volume + ioErr -36 I/O error + bdNamErr -37 Bad filename + tmfoErr -42 Too many files open + fnfErr -43 Source file not found, or destination + directory does not exist + wPrErr -44 Volume locked by hardware + fLckdErr -45 File is locked + vLckdErr -46 Destination volume is read-only + fBsyErr -47 The source or destination file could + not be opened with the correct access + modes + dupFNErr -48 Destination file already exists + opWrErr -49 File already open for writing + paramErr -50 No default volume or function not + supported by volume + permErr -54 File is already open and cannot be opened using specified deny modes + memFullErr -108 Copy buffer could not be allocated + dirNFErr -120 Directory not found or incomplete pathname + wrgVolTypErr -123 Function not supported by volume + afpAccessDenied -5000 User does not have the correct access + afpDenyConflict -5006 The source or destination file could + not be opened with the correct access + modes + afpObjectTypeErr -5025 Source is a directory, directory not found + or incomplete pathname + + __________ + + Also see: CopyErrProcPtr, CopyFilterProcPtr, FSpFilteredDirectoryCopy, + DirectoryCopy, FSpDirectoryCopy, FileCopy, FSpFileCopy +*/ + +/*****************************************************************************/ + +pascal OSErr FilteredDirectoryCopy(short srcVRefNum, + long srcDirID, + ConstStr255Param srcName, + short dstVRefNum, + long dstDirID, + ConstStr255Param dstName, + void *copyBufferPtr, + long copyBufferSize, + Boolean preflight, + CopyErrProcPtr copyErrHandler, + CopyFilterProcPtr copyFilterProc, ConstStr255Param newName) +{ + EnumerateGlobals theGlobals; + Boolean isDirectory; + OSErr error; + Boolean ourCopyBuffer = false; + Str63 srcDirName, oldDiskName; + Boolean spaceOK; + + /* Make sure a copy buffer is allocated. */ + if ( copyBufferPtr == NULL ) + { + /* The caller didn't supply a copy buffer so grab one from the application heap. + ** Try to get a big copy buffer, if we can't, try for a 512-byte buffer. + ** If 512 bytes aren't available, we're in trouble. */ + copyBufferSize = dirCopyBigCopyBuffSize; + copyBufferPtr = NewPtr(copyBufferSize); + if ( copyBufferPtr == NULL ) + { + copyBufferSize = dirCopyMinCopyBuffSize; + copyBufferPtr = NewPtr(copyBufferSize); + if ( copyBufferPtr == NULL ) + { + return ( memFullErr ); + } + } + ourCopyBuffer = true; + } + + /* Get the real dirID where we're copying from and make sure it is a directory. */ + error = GetDirectoryID(srcVRefNum, srcDirID, srcName, &srcDirID, &isDirectory); + if ( error != noErr ) + { + goto ErrorExit; + } + if ( !isDirectory ) + { + error = dirNFErr; + goto ErrorExit; + } + + /* Special case destination if it is the root parent directory. */ + /* Since you can't create the root directory, this is needed if */ + /* you want to copy a directory's content to a disk's root directory. */ + if ( (dstDirID == fsRtParID) && (dstName == NULL) ) + { + dstDirID = fsRtParID; + isDirectory = true; + error = noErr; + } + else + { + /* Get the real dirID where we're going to put the copy and make sure it is a directory. */ + error = GetDirectoryID(dstVRefNum, dstDirID, dstName, &dstDirID, &isDirectory); + if ( error != noErr ) + { + goto ErrorExit; + } + if ( !isDirectory ) + { + error = dirNFErr; + goto ErrorExit; + } + } + + /* Get the real vRefNum of both the source and destination */ + error = DetermineVRefNum(srcName, srcVRefNum, &srcVRefNum); + if ( error != noErr ) + { + goto ErrorExit; + } + error = DetermineVRefNum(dstName, dstVRefNum, &dstVRefNum); + if ( error != noErr ) + { + goto ErrorExit; + } + + if ( preflight ) + { + error = PreflightDirectoryCopySpace(srcVRefNum, srcDirID, dstVRefNum, copyFilterProc, &spaceOK); + if ( error != noErr ) + { + goto ErrorExit; + } + if ( !spaceOK ) + { + error = dskFulErr; /* not enough room on destination */ + goto ErrorExit; + } + } + + /* Create the new directory in the destination directory with the */ + /* same name as the source directory. */ + /* + if newName is not empty use it rather than the original dir name. + */ + if ( newName[0] == 0 ) + { + error = GetDirName(srcVRefNum, srcDirID, srcDirName); + if ( error != noErr ) + { + goto ErrorExit; + } + } + else + { + memcpy(srcDirName, newName, 32 ); + + } + /* Again, special case destination if the destination is the */ + /* root parent directory. This time, we'll rename the disk to */ + /* the source directory name. */ + if ( dstDirID == fsRtParID ) + { + /* Get the current name of the destination disk */ + error = GetDirName(dstVRefNum, fsRtDirID, oldDiskName); + if ( error == noErr ) + { + /* Shorten the name if it's too long to be the volume name */ + TruncPString(srcDirName, srcDirName, 27); + + /* Rename the disk */ + error = HRename(dstVRefNum, fsRtParID, oldDiskName, srcDirName); + /* and copy to the root directory */ + dstDirID = fsRtDirID; + } + } + else + { + error = DirCreate(dstVRefNum, dstDirID, srcDirName, &dstDirID); + } + if ( error != noErr ) + { + /* handle any errors from DirCreate */ + if ( copyErrHandler != NULL ) + { + if ( CallCopyErrProc(copyErrHandler, error, dirCreateOp, + srcVRefNum, srcDirID, NULL, + dstVRefNum, dstDirID, srcDirName) ) + { + goto ErrorExit; + } + else + { + /* If the CopyErrProc handled the problem, clear the error here */ + /* and continue */ + error = noErr; + } + } + else + { + /* If you don't handle the errors with an error handler, */ + /* then the copy stops here. */ + goto ErrorExit; + } + } + + /* dstDirID is now the newly created directory! */ + + /* Set up the globals we need to access from the recursive routine. */ + theGlobals.copyBuffer = (Ptr)copyBufferPtr; + theGlobals.bufferSize = copyBufferSize; + theGlobals.destinationVRefNum = dstVRefNum; /* so we can get to it always */ + theGlobals.myCPB.hFileInfo.ioNamePtr = (StringPtr)&theGlobals.itemName; + theGlobals.myCPB.hFileInfo.ioVRefNum = srcVRefNum; + theGlobals.errorHandler = copyErrHandler; + theGlobals.bailout = false; + theGlobals.copyFilterProc = copyFilterProc; + + /* Here we go into recursion land... */ + CopyLevel(srcDirID, dstDirID, &theGlobals); + error = theGlobals.error; /* get the result */ + + if ( !theGlobals.bailout ) + { + /* Copy comment from source to destination directory. */ + /* Ignore the result because we really don't care if it worked or not. */ + (void) DTCopyComment(srcVRefNum, srcDirID, NULL, dstVRefNum, dstDirID, NULL); + + /* Copy the File Manager attributes */ + error = CopyFileMgrAttributes(srcVRefNum, srcDirID, NULL, + dstVRefNum, dstDirID, NULL, true); + + /* handle any errors from CopyFileMgrAttributes */ + if ( (error != noErr) && (copyErrHandler != NULL) ) + { + theGlobals.bailout = CallCopyErrProc(copyErrHandler, error, copyDirFMAttributesOp, + srcVRefNum, srcDirID, NULL, + dstVRefNum, dstDirID, NULL); + } + } + +ErrorExit: + /* Get rid of the copy buffer if we allocated it. */ + if ( ourCopyBuffer ) + { + DisposePtr((Ptr)copyBufferPtr); + } + + return ( error ); +} + + +/*****************************************************************************/ + + +pascal OSErr MacFSpDirectoryCopyRename(const FSSpec *srcSpec, + const FSSpec *dstSpec, + ConstStr255Param newName, + void *copyBufferPtr, + long copyBufferSize, + Boolean preflight, + CopyErrProcPtr copyErrHandler) +{ + return ( FilteredDirectoryCopy(srcSpec->vRefNum, srcSpec->parID, srcSpec->name, + dstSpec->vRefNum, dstSpec->parID, dstSpec->name, + copyBufferPtr, copyBufferSize, preflight, + copyErrHandler, NULL, newName) ); +} diff --git a/src/libs/xpcom18a4/xpcom/io/macDirectoryCopy.h b/src/libs/xpcom18a4/xpcom/io/macDirectoryCopy.h new file mode 100644 index 00000000..361c820e --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/macDirectoryCopy.h @@ -0,0 +1,158 @@ +/* +** Apple Macintosh Developer Technical Support +** +** DirectoryCopy: A robust, general purpose directory copy routine. +** +** by Jim Luther, Apple Developer Technical Support Emeritus +** +** File: DirectoryCopy.h +** +** Copyright © 1992-1998 Apple Computer, Inc. +** All rights reserved. +** +** You may incorporate this sample code into your applications without +** restriction, though the sample code has been provided "AS IS" and the +** responsibility for its operation is 100% yours. However, what you are +** not permitted to do is to redistribute the source as "DSC Sample Code" +** after having made changes. If you're going to re-distribute the source, +** we require that you make it clear in the source that the code was +** descended from Apple Sample Code, but that you've made changes. +*/ + +// Modified to allow renaming the destination folder + +#ifndef __MACDIRECTORYCOPY__ +#define __MACDIRECTORYCOPY__ + +#include +#include + +#include "Optimization.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef pascal Boolean (*CopyErrProcPtr) (OSErr error, + short failedOperation, + short srcVRefNum, + long srcDirID, + ConstStr255Param srcName, + short dstVRefNum, + long dstDirID, + ConstStr255Param dstName); +/* ¦ Prototype for the CopyErrProc function DirectoryCopy calls. + This is the prototype for the CopyErrProc function DirectoryCopy + calls if an error condition is detected sometime during the copy. If + CopyErrProc returns false, then DirectoryCopy attempts to continue with + the directory copy operation. If CopyErrProc returns true, then + DirectoryCopy stops the directory copy operation. + + error input: The error result code that caused CopyErrProc to + be called. + failedOperation input: The operation that returned an error to + DirectoryCopy. + srcVRefNum input: Source volume specification. + srcDirID input: Source directory ID. + srcName input: Source file or directory name, or nil if + srcDirID specifies the directory. + dstVRefNum input: Destination volume specification. + dstDirID input: Destination directory ID. + dstName input: Destination file or directory name, or nil if + dstDirID specifies the directory. + + __________ + + Also see: FilteredDirectoryCopy, FSpFilteredDirectoryCopy, DirectoryCopy, FSpDirectoryCopy +*/ + +pascal OSErr MacFSpDirectoryCopyRename(const FSSpec *srcSpec, + const FSSpec *dstSpec, + ConstStr255Param newName, + void *copyBufferPtr, + long copyBufferSize, + Boolean preflight, + CopyErrProcPtr copyErrHandler); +/* ¦ Make a copy of a directory structure in a new location. + The FSpDirectoryCopy function makes a copy of a directory structure in a + new location. If copyBufferPtr <> NIL, it points to a buffer of + copyBufferSize that is used to copy files data. The larger the + supplied buffer, the faster the copy. If copyBufferPtr = NIL, then this + routine allocates a buffer in the application heap. If you pass a + copy buffer to this routine, make its size a multiple of 512 + ($200) bytes for optimum performance. + + srcSpec input: An FSSpec record specifying the directory to copy. + dstSpec input: An FSSpec record specifying destination directory + of the copy. + copyBufferPtr input: Points to a buffer of copyBufferSize that + is used the i/o buffer for the copy or + nil if you want DirectoryCopy to allocate its + own buffer in the application heap. + copyBufferSize input: The size of the buffer pointed to + by copyBufferPtr. + preflight input: If true, FSpDirectoryCopy makes sure there are + enough allocation blocks on the destination + volume to hold the directory's files before + starting the copy. + copyErrHandler input: A pointer to the routine you want called if an + error condition is detected during the copy, or + nil if you don't want to handle error conditions. + If you don't handle error conditions, the first + error will cause the copy to quit and + DirectoryCopy will return the error. + Error handling is recommended... + + Result Codes + noErr 0 No error + readErr Ð19 Driver does not respond to read requests + writErr Ð20 Driver does not respond to write requests + badUnitErr Ð21 Driver reference number does not + match unit table + unitEmptyErr Ð22 Driver reference number specifies a + nil handle in unit table + abortErr Ð27 Request aborted by KillIO + notOpenErr Ð28 Driver not open + dskFulErr -34 Destination volume is full + nsvErr -35 No such volume + ioErr -36 I/O error + bdNamErr -37 Bad filename + tmfoErr -42 Too many files open + fnfErr -43 Source file not found, or destination + directory does not exist + wPrErr -44 Volume locked by hardware + fLckdErr -45 File is locked + vLckdErr -46 Destination volume is read-only + fBsyErr -47 The source or destination file could + not be opened with the correct access + modes + dupFNErr -48 Destination file already exists + opWrErr -49 File already open for writing + paramErr -50 No default volume or function not + supported by volume + permErr -54 File is already open and cannot be opened using specified deny modes + memFullErr -108 Copy buffer could not be allocated + dirNFErr -120 Directory not found or incomplete pathname + wrgVolTypErr -123 Function not supported by volume + afpAccessDenied -5000 User does not have the correct access + afpDenyConflict -5006 The source or destination file could + not be opened with the correct access + modes + afpObjectTypeErr -5025 Source is a directory, directory not found + or incomplete pathname + + __________ + + Also see: CopyErrProcPtr, DirectoryCopy, FilteredDirectoryCopy, + FSpFilteredDirectoryCopy, FileCopy, FSpFileCopy +*/ + +/*****************************************************************************/ + +#ifdef __cplusplus +} +#endif + +#include "OptimizationEnd.h" + +#endif /* __DIRECTORYCOPY__ */ diff --git a/src/libs/xpcom18a4/xpcom/io/nsAppDirectoryServiceDefs.h b/src/libs/xpcom18a4/xpcom/io/nsAppDirectoryServiceDefs.h new file mode 100644 index 00000000..768cb38f --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsAppDirectoryServiceDefs.h @@ -0,0 +1,120 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Conrad Carlen conrad@ingress.com + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +#ifndef nsAppDirectoryServiceDefs_h___ +#define nsAppDirectoryServiceDefs_h___ + +//======================================================================================== +// +// Defines property names for directories available from standard nsIDirectoryServiceProviders. +// These keys are not guaranteed to exist because the nsIDirectoryServiceProviders which +// provide them are optional. +// +// Keys whose definition ends in "DIR" or "FILE" return a single nsIFile (or subclass). +// Keys whose definition ends in "LIST" return an nsISimpleEnumerator which enumerates a +// list of file objects. +// +// System and XPCOM level properties are defined in nsDirectoryServiceDefs.h. +// +//======================================================================================== + + +// -------------------------------------------------------------------------------------- +// Files and directories which exist on a per-product basis +// -------------------------------------------------------------------------------------- + +#define NS_APP_APPLICATION_REGISTRY_FILE "AppRegF" +#define NS_APP_APPLICATION_REGISTRY_DIR "AppRegD" + +#define NS_APP_DEFAULTS_50_DIR "DefRt" // The root dir of all defaults dirs +#define NS_APP_PREF_DEFAULTS_50_DIR "PrfDef" +#define NS_APP_PROFILE_DEFAULTS_50_DIR "profDef" // The profile defaults of the "current" + // locale. Should be first choice. +#define NS_APP_PROFILE_DEFAULTS_NLOC_50_DIR "ProfDefNoLoc" // The profile defaults of the "default" + // installed locale. Second choice + // when above is not available. + +#define NS_APP_USER_PROFILES_ROOT_DIR "DefProfRt" // The dir where user profile dirs get created. + +#define NS_APP_RES_DIR "ARes" +#define NS_APP_CHROME_DIR "AChrom" +#define NS_APP_PLUGINS_DIR "APlugns" // Deprecated - use NS_APP_PLUGINS_DIR_LIST +#define NS_APP_SEARCH_DIR "SrchPlugns" + +#define NS_APP_CHROME_DIR_LIST "AChromDL" +#define NS_APP_PLUGINS_DIR_LIST "APluginsDL" + +// -------------------------------------------------------------------------------------- +// Files and directories which exist on a per-profile basis +// These locations are typically provided by the profile mgr +// -------------------------------------------------------------------------------------- + +// In a shared profile environment, prefixing a profile-relative +// key with NS_SHARED returns a location that is shared by +// other users of the profile. Without this prefix, the consumer +// has exclusive access to this location. + +#define NS_SHARED "SHARED" + +#define NS_APP_PREFS_50_DIR "PrefD" // Directory which contains user prefs +#define NS_APP_PREFS_50_FILE "PrefF" +#define NS_APP_PREFS_DEFAULTS_DIR_LIST "PrefDL" + +#define NS_APP_USER_PROFILE_50_DIR "ProfD" + +#define NS_APP_USER_CHROME_DIR "UChrm" + +#define NS_APP_LOCALSTORE_50_FILE "LclSt" +#define NS_APP_HISTORY_50_FILE "UHist" +#define NS_APP_USER_PANELS_50_FILE "UPnls" +#define NS_APP_USER_MIMETYPES_50_FILE "UMimTyp" +#define NS_APP_CACHE_PARENT_DIR "cachePDir" + +#define NS_APP_BOOKMARKS_50_FILE "BMarks" + +#define NS_APP_DOWNLOADS_50_FILE "DLoads" + +#define NS_APP_SEARCH_50_FILE "SrchF" + +#define NS_APP_MAIL_50_DIR "MailD" +#define NS_APP_IMAP_MAIL_50_DIR "IMapMD" +#define NS_APP_NEWS_50_DIR "NewsD" +#define NS_APP_MESSENGER_FOLDER_CACHE_50_DIR "MFCaD" + +#define NS_APP_INSTALL_CLEANUP_DIR "XPIClnupD" //location of xpicleanup.dat xpicleanup.exe +#endif diff --git a/src/libs/xpcom18a4/xpcom/io/nsAppFileLocationProvider.cpp b/src/libs/xpcom18a4/xpcom/io/nsAppFileLocationProvider.cpp new file mode 100644 index 00000000..9d4f785d --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsAppFileLocationProvider.cpp @@ -0,0 +1,608 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Conrad Carlen + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsAppFileLocationProvider.h" +#include "nsAppDirectoryServiceDefs.h" +#include "nsDirectoryServiceDefs.h" +#include "nsIAtom.h" +#include "nsILocalFile.h" +#include "nsString.h" +#include "nsXPIDLString.h" +#include "nsISimpleEnumerator.h" +#include "prenv.h" +#include "nsCRT.h" + +#if (defined(XP_MAC) || defined(XP_MACOSX)) && !defined(VBOX_MACOSX_FOLLOWS_UNIX_IO) +#include +#include +#include +#include +#include "nsILocalFileMac.h" +#elif defined(XP_OS2) +#define INCL_DOSPROCESS +#define INCL_DOSMODULEMGR +#include +#elif defined(XP_WIN) +#include +#include +#elif defined(XP_UNIX) +#include +#include +#include +#elif defined(XP_BEOS) +#include +#include +#include +#endif + + +// WARNING: These hard coded names need to go away. They need to +// come from localizable resources + +#if defined(XP_MAC) || defined(XP_MACOSX) +#define APP_REGISTRY_NAME NS_LITERAL_CSTRING("Application Registry") +#define ESSENTIAL_FILES NS_LITERAL_CSTRING("Essential Files") +#elif defined(XP_WIN) || defined(XP_OS2) +#define APP_REGISTRY_NAME NS_LITERAL_CSTRING("registry.dat") +#else +#define APP_REGISTRY_NAME NS_LITERAL_CSTRING("appreg") +#endif + +// define default product directory +#ifdef XP_MAC +#define DEFAULT_PRODUCT_DIR NS_LITERAL_CSTRING("Mozilla") +#else +#define DEFAULT_PRODUCT_DIR NS_LITERAL_CSTRING(MOZ_USER_DIR) +#endif + +// Locally defined keys used by nsAppDirectoryEnumerator +#define NS_ENV_PLUGINS_DIR "EnvPlugins" // env var MOZ_PLUGIN_PATH +#define NS_USER_PLUGINS_DIR "UserPlugins" + +#if defined(XP_MAC) || defined(XP_MACOSX) +#define NS_MACOSX_USER_PLUGIN_DIR "OSXUserPlugins" +#define NS_MACOSX_LOCAL_PLUGIN_DIR "OSXLocalPlugins" +#define NS_MAC_CLASSIC_PLUGIN_DIR "MacSysPlugins" +#endif + +#if defined(XP_MAC) +#define DEFAULTS_DIR_NAME NS_LITERAL_CSTRING("Defaults") +#define DEFAULTS_PREF_DIR_NAME NS_LITERAL_CSTRING("Pref") +#define DEFAULTS_PROFILE_DIR_NAME NS_LITERAL_CSTRING("Profile") +#define RES_DIR_NAME NS_LITERAL_CSTRING("Res") +#define CHROME_DIR_NAME NS_LITERAL_CSTRING("Chrome") +#define PLUGINS_DIR_NAME NS_LITERAL_CSTRING("Plug-ins") +#define SEARCH_DIR_NAME NS_LITERAL_CSTRING("Search Plugins") +#else +#define DEFAULTS_DIR_NAME NS_LITERAL_CSTRING("defaults") +#define DEFAULTS_PREF_DIR_NAME NS_LITERAL_CSTRING("pref") +#define DEFAULTS_PROFILE_DIR_NAME NS_LITERAL_CSTRING("profile") +#define RES_DIR_NAME NS_LITERAL_CSTRING("res") +#define CHROME_DIR_NAME NS_LITERAL_CSTRING("chrome") +#define PLUGINS_DIR_NAME NS_LITERAL_CSTRING("plugins") +#define SEARCH_DIR_NAME NS_LITERAL_CSTRING("searchplugins") +#endif + +//***************************************************************************** +// nsAppFileLocationProvider::Constructor/Destructor +//***************************************************************************** + +nsAppFileLocationProvider::nsAppFileLocationProvider() +{ +} + +//***************************************************************************** +// nsAppFileLocationProvider::nsISupports +//***************************************************************************** + +NS_IMPL_THREADSAFE_ISUPPORTS2(nsAppFileLocationProvider, nsIDirectoryServiceProvider, nsIDirectoryServiceProvider2) + +//***************************************************************************** +// nsAppFileLocationProvider::nsIDirectoryServiceProvider +//***************************************************************************** + +NS_IMETHODIMP +nsAppFileLocationProvider::GetFile(const char *prop, PRBool *persistant, nsIFile **_retval) +{ + nsCOMPtr localFile; + nsresult rv = NS_ERROR_FAILURE; + + NS_ENSURE_ARG(prop); + *_retval = nsnull; + *persistant = PR_TRUE; + +#if (defined (XP_MAC) || defined(XP_MACOSX)) && !defined(VBOX_MACOSX_FOLLOWS_UNIX_IO) + short foundVRefNum; + SInt32 foundDirID; + FSSpec fileSpec; + nsCOMPtr macFile; +#endif + + if (nsCRT::strcmp(prop, NS_APP_APPLICATION_REGISTRY_DIR) == 0) + { + rv = GetProductDirectory(getter_AddRefs(localFile)); + } + else if (nsCRT::strcmp(prop, NS_APP_APPLICATION_REGISTRY_FILE) == 0) + { + rv = GetProductDirectory(getter_AddRefs(localFile)); + if (NS_SUCCEEDED(rv)) + rv = localFile->AppendNative(APP_REGISTRY_NAME); + } + else if (nsCRT::strcmp(prop, NS_APP_DEFAULTS_50_DIR) == 0) + { + rv = CloneMozBinDirectory(getter_AddRefs(localFile)); + if (NS_SUCCEEDED(rv)) + rv = localFile->AppendRelativeNativePath(DEFAULTS_DIR_NAME); + } + else if (nsCRT::strcmp(prop, NS_APP_PREF_DEFAULTS_50_DIR) == 0) + { + rv = CloneMozBinDirectory(getter_AddRefs(localFile)); + if (NS_SUCCEEDED(rv)) { + rv = localFile->AppendRelativeNativePath(DEFAULTS_DIR_NAME); + if (NS_SUCCEEDED(rv)) + rv = localFile->AppendRelativeNativePath(DEFAULTS_PREF_DIR_NAME); + } + } + else if (nsCRT::strcmp(prop, NS_APP_PROFILE_DEFAULTS_50_DIR) == 0 || + nsCRT::strcmp(prop, NS_APP_PROFILE_DEFAULTS_NLOC_50_DIR) == 0) + { + rv = CloneMozBinDirectory(getter_AddRefs(localFile)); + if (NS_SUCCEEDED(rv)) { + rv = localFile->AppendRelativeNativePath(DEFAULTS_DIR_NAME); + if (NS_SUCCEEDED(rv)) + rv = localFile->AppendRelativeNativePath(DEFAULTS_PROFILE_DIR_NAME); + } + } + else if (nsCRT::strcmp(prop, NS_APP_USER_PROFILES_ROOT_DIR) == 0) + { + rv = GetDefaultUserProfileRoot(getter_AddRefs(localFile)); + } + else if (nsCRT::strcmp(prop, NS_APP_RES_DIR) == 0) + { + rv = CloneMozBinDirectory(getter_AddRefs(localFile)); + if (NS_SUCCEEDED(rv)) + rv = localFile->AppendRelativeNativePath(RES_DIR_NAME); + } + else if (nsCRT::strcmp(prop, NS_APP_CHROME_DIR) == 0) + { + rv = CloneMozBinDirectory(getter_AddRefs(localFile)); + if (NS_SUCCEEDED(rv)) + rv = localFile->AppendRelativeNativePath(CHROME_DIR_NAME); + } + else if (nsCRT::strcmp(prop, NS_APP_PLUGINS_DIR) == 0) + { + rv = CloneMozBinDirectory(getter_AddRefs(localFile)); + if (NS_SUCCEEDED(rv)) + rv = localFile->AppendRelativeNativePath(PLUGINS_DIR_NAME); + } +#if (defined(XP_MAC) || defined(XP_MACOSX)) && !defined(VBOX_MACOSX_FOLLOWS_UNIX_IO) + else if (nsCRT::strcmp(prop, NS_MACOSX_USER_PLUGIN_DIR) == 0) + { + if (!(::FindFolder(kUserDomain, + kInternetPlugInFolderType, + kDontCreateFolder, &foundVRefNum, &foundDirID)) && + !(::FSMakeFSSpec(foundVRefNum, foundDirID, "\p", &fileSpec))) { + rv = NS_NewLocalFileWithFSSpec(&fileSpec, PR_TRUE, getter_AddRefs(macFile)); + if (NS_SUCCEEDED(rv)) + localFile = macFile; + } + } + else if (nsCRT::strcmp(prop, NS_MACOSX_LOCAL_PLUGIN_DIR) == 0) + { + if (!(::FindFolder(kLocalDomain, + kInternetPlugInFolderType, + kDontCreateFolder, &foundVRefNum, &foundDirID)) && + !(::FSMakeFSSpec(foundVRefNum, foundDirID, "\p", &fileSpec))) { + rv = NS_NewLocalFileWithFSSpec(&fileSpec, PR_TRUE, getter_AddRefs(macFile)); + if (NS_SUCCEEDED(rv)) + localFile = macFile; + } + } + else if (nsCRT::strcmp(prop, NS_MAC_CLASSIC_PLUGIN_DIR) == 0) + { + if (!(::FindFolder(kOnAppropriateDisk, + kInternetPlugInFolderType, + kDontCreateFolder, &foundVRefNum, &foundDirID)) && + !(::FSMakeFSSpec(foundVRefNum, foundDirID, "\p", &fileSpec))) { + rv = NS_NewLocalFileWithFSSpec(&fileSpec, PR_TRUE, getter_AddRefs(macFile)); + if (NS_SUCCEEDED(rv)) + localFile = macFile; + } + } +#else + else if (nsCRT::strcmp(prop, NS_ENV_PLUGINS_DIR) == 0) + { + NS_ERROR("Don't use nsAppFileLocationProvider::GetFile(NS_ENV_PLUGINS_DIR, ...). " + "Use nsAppFileLocationProvider::GetFiles(...)."); + const char *pathVar = PR_GetEnv("VBOX_XPCOM_PLUGIN_PATH"); + if (pathVar) + rv = NS_NewNativeLocalFile(nsDependentCString(pathVar), PR_TRUE, getter_AddRefs(localFile)); + } + else if (nsCRT::strcmp(prop, NS_USER_PLUGINS_DIR) == 0) + { + rv = GetProductDirectory(getter_AddRefs(localFile)); + if (NS_SUCCEEDED(rv)) + rv = localFile->AppendRelativeNativePath(PLUGINS_DIR_NAME); + } +#endif + else if (nsCRT::strcmp(prop, NS_APP_SEARCH_DIR) == 0) + { + rv = CloneMozBinDirectory(getter_AddRefs(localFile)); + if (NS_SUCCEEDED(rv)) + rv = localFile->AppendRelativeNativePath(SEARCH_DIR_NAME); + } + else if (nsCRT::strcmp(prop, NS_APP_INSTALL_CLEANUP_DIR) == 0) + { + // This is cloned so that embeddors will have a hook to override + // with their own cleanup dir. See bugzilla bug #105087 + rv = CloneMozBinDirectory(getter_AddRefs(localFile)); +#ifdef XP_MAC + if (NS_SUCCEEDED(rv)) + rv = localFile->AppendNative(ESSENTIAL_FILES); +#endif + + } + + if (localFile && NS_SUCCEEDED(rv)) + return localFile->QueryInterface(NS_GET_IID(nsIFile), (void**)_retval); + + return rv; +} + + +NS_METHOD nsAppFileLocationProvider::CloneMozBinDirectory(nsILocalFile **aLocalFile) +{ + NS_ENSURE_ARG_POINTER(aLocalFile); + nsresult rv; + + if (!mMozBinDirectory) + { + // Get the mozilla bin directory + // 1. Check the directory service first for NS_XPCOM_CURRENT_PROCESS_DIR + // This will be set if a directory was passed to NS_InitXPCOM + // 2. If that doesn't work, set it to be the current process directory + nsCOMPtr + directoryService(do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv)); + if (NS_FAILED(rv)) + return rv; + + rv = directoryService->Get(NS_XPCOM_CURRENT_PROCESS_DIR, NS_GET_IID(nsIFile), getter_AddRefs(mMozBinDirectory)); + if (NS_FAILED(rv)) { + rv = directoryService->Get(NS_OS_CURRENT_PROCESS_DIR, NS_GET_IID(nsIFile), getter_AddRefs(mMozBinDirectory)); + if (NS_FAILED(rv)) + return rv; + } + } + + nsCOMPtr aFile; + rv = mMozBinDirectory->Clone(getter_AddRefs(aFile)); + if (NS_FAILED(rv)) + return rv; + + nsCOMPtr lfile = do_QueryInterface (aFile); + if (!lfile) + return NS_ERROR_FAILURE; + + NS_IF_ADDREF(*aLocalFile = lfile); + return NS_OK; +} + + +//---------------------------------------------------------------------------------------- +// GetProductDirectory - Gets the directory which contains the application data folder +// +// UNIX : ~/.mozilla/ +// WIN : \Mozilla +// Mac : :Documents:Mozilla: +//---------------------------------------------------------------------------------------- +NS_METHOD nsAppFileLocationProvider::GetProductDirectory(nsILocalFile **aLocalFile) +{ + NS_ENSURE_ARG_POINTER(aLocalFile); + + nsresult rv; + PRBool exists; + nsCOMPtr localDir; + +#if defined(XP_MAC) + nsCOMPtr directoryService = + do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv); + if (NS_FAILED(rv)) return rv; + OSErr err; + long response; + err = ::Gestalt(gestaltSystemVersion, &response); + const char *prop = (!err && response >= 0x00001000) ? NS_MAC_USER_LIB_DIR : NS_MAC_DOCUMENTS_DIR; + rv = directoryService->Get(prop, NS_GET_IID(nsILocalFile), getter_AddRefs(localDir)); + if (NS_FAILED(rv)) return rv; +#elif defined(XP_MACOSX) && !defined(VBOX_MACOSX_FOLLOWS_UNIX_IO) + FSRef fsRef; + OSErr err = ::FSFindFolder(kUserDomain, kDomainLibraryFolderType, kCreateFolder, &fsRef); + if (err) return NS_ERROR_FAILURE; + NS_NewLocalFile(EmptyString(), PR_TRUE, getter_AddRefs(localDir)); + if (!localDir) return NS_ERROR_FAILURE; + nsCOMPtr localDirMac(do_QueryInterface(localDir)); + rv = localDirMac->InitWithFSRef(&fsRef); + if (NS_FAILED(rv)) return rv; +#elif defined(XP_OS2) + nsCOMPtr directoryService = + do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv); + if (NS_FAILED(rv)) return rv; + rv = directoryService->Get(NS_OS2_HOME_DIR, NS_GET_IID(nsILocalFile), getter_AddRefs(localDir)); + if (NS_FAILED(rv)) return rv; +#elif defined(XP_WIN) + nsCOMPtr directoryService = + do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv); + if (NS_FAILED(rv)) return rv; + rv = directoryService->Get(NS_WIN_APPDATA_DIR, NS_GET_IID(nsILocalFile), getter_AddRefs(localDir)); + if (NS_SUCCEEDED(rv)) + rv = localDir->Exists(&exists); + if (NS_FAILED(rv) || !exists) + { + // On some Win95 machines, NS_WIN_APPDATA_DIR does not exist - revert to NS_WIN_WINDOWS_DIR + localDir = nsnull; + rv = directoryService->Get(NS_WIN_WINDOWS_DIR, NS_GET_IID(nsILocalFile), getter_AddRefs(localDir)); + } + if (NS_FAILED(rv)) return rv; +#elif defined(XP_UNIX) + rv = NS_NewNativeLocalFile(nsDependentCString(PR_GetEnv("HOME")), PR_TRUE, getter_AddRefs(localDir)); + if (NS_FAILED(rv)) return rv; +#elif defined(XP_BEOS) + char path[MAXPATHLEN]; + find_directory(B_USER_SETTINGS_DIRECTORY, 0, 0, path, MAXPATHLEN); + // Need enough space to add the trailing backslash + int len = strlen(path); + if (len > MAXPATHLEN-2) + return NS_ERROR_FAILURE; + path[len] = '/'; + path[len+1] = '\0'; + rv = NS_NewNativeLocalFile(nsDependentCString(path), PR_TRUE, getter_AddRefs(localDir)); + if (NS_FAILED(rv)) return rv; +#else +#error dont_know_how_to_get_product_dir_on_your_platform +#endif + + rv = localDir->AppendRelativeNativePath(DEFAULT_PRODUCT_DIR); + if (NS_FAILED(rv)) return rv; + rv = localDir->Exists(&exists); + if (NS_SUCCEEDED(rv) && !exists) + rv = localDir->Create(nsIFile::DIRECTORY_TYPE, 0700); + if (NS_FAILED(rv)) return rv; + + *aLocalFile = localDir; + NS_ADDREF(*aLocalFile); + + return rv; +} + + +//---------------------------------------------------------------------------------------- +// GetDefaultUserProfileRoot - Gets the directory which contains each user profile dir +// +// UNIX : ~/.mozilla/ +// WIN : \Mozilla\Profiles +// Mac : :Documents:Mozilla:Profiles: +//---------------------------------------------------------------------------------------- +NS_METHOD nsAppFileLocationProvider::GetDefaultUserProfileRoot(nsILocalFile **aLocalFile) +{ + NS_ENSURE_ARG_POINTER(aLocalFile); + + nsresult rv; + nsCOMPtr localDir; + + rv = GetProductDirectory(getter_AddRefs(localDir)); + if (NS_FAILED(rv)) return rv; + +#if defined(XP_MAC) || defined(XP_MACOSX) || defined(XP_OS2) || defined(XP_WIN) + // These 3 platforms share this part of the path - do them as one + rv = localDir->AppendRelativeNativePath(NS_LITERAL_CSTRING("Profiles")); + if (NS_FAILED(rv)) return rv; + + PRBool exists; + rv = localDir->Exists(&exists); + if (NS_SUCCEEDED(rv) && !exists) + rv = localDir->Create(nsIFile::DIRECTORY_TYPE, 0775); + if (NS_FAILED(rv)) return rv; +#endif + + *aLocalFile = localDir; + NS_ADDREF(*aLocalFile); + + return rv; +} + +//***************************************************************************** +// nsAppFileLocationProvider::nsIDirectoryServiceProvider2 +//***************************************************************************** + +class nsAppDirectoryEnumerator : public nsISimpleEnumerator +{ + public: + NS_DECL_ISUPPORTS + + /** + * aKeyList is a null-terminated list of properties which are provided by aProvider + * They do not need to be publicly defined keys. + */ + nsAppDirectoryEnumerator(nsIDirectoryServiceProvider *aProvider, + const char* aKeyList[]) : + mProvider(aProvider), + mCurrentKey(aKeyList) + { + } + + NS_IMETHOD HasMoreElements(PRBool *result) + { + while (!mNext && *mCurrentKey) + { + PRBool dontCare; + nsCOMPtr testFile; + (void)mProvider->GetFile(*mCurrentKey++, &dontCare, getter_AddRefs(testFile)); + // Don't return a file which does not exist. + PRBool exists; + if (testFile && NS_SUCCEEDED(testFile->Exists(&exists)) && exists) + mNext = testFile; + } + *result = mNext != nsnull; + return NS_OK; + } + + NS_IMETHOD GetNext(nsISupports **result) + { + NS_ENSURE_ARG_POINTER(result); + *result = nsnull; + + PRBool hasMore; + HasMoreElements(&hasMore); + if (!hasMore) + return NS_ERROR_FAILURE; + + *result = mNext; + NS_IF_ADDREF(*result); + mNext = nsnull; + + return *result ? NS_OK : NS_ERROR_FAILURE; + } + + // Virtual destructor since subclass nsPathsDirectoryEnumerator + // does not re-implement Release() + + virtual ~nsAppDirectoryEnumerator() + { + } + + protected: + nsIDirectoryServiceProvider *mProvider; + const char** mCurrentKey; + nsCOMPtr mNext; +}; + +NS_IMPL_ISUPPORTS1(nsAppDirectoryEnumerator, nsISimpleEnumerator) + +/* nsPathsDirectoryEnumerator and PATH_SEPARATOR + * are not used on MacOS/X. */ + +#if defined(XP_WIN) || defined(XP_OS2)/* Win32, Win16, and OS/2 */ +#define PATH_SEPARATOR ';' +#else /*if defined(XP_UNIX) || defined(XP_BEOS)*/ +#define PATH_SEPARATOR ':' +#endif + +class nsPathsDirectoryEnumerator : public nsAppDirectoryEnumerator +{ + public: + /** + * aKeyList is a null-terminated list. + * The first element is a path list. + * The remainder are properties provided by aProvider. + * They do not need to be publicly defined keys. + */ + nsPathsDirectoryEnumerator(nsIDirectoryServiceProvider *aProvider, + const char* aKeyList[]) : + nsAppDirectoryEnumerator(aProvider, aKeyList+1), + mEndPath(aKeyList[0]) + { + } + + NS_IMETHOD HasMoreElements(PRBool *result) + { + if (mEndPath) + while (!mNext && *mEndPath) + { + const char *pathVar = mEndPath; + do { ++mEndPath; } while (*mEndPath && *mEndPath != PATH_SEPARATOR); + + nsCOMPtr localFile; + NS_NewNativeLocalFile(Substring(pathVar, mEndPath), + PR_TRUE, + getter_AddRefs(localFile)); + if (*mEndPath == PATH_SEPARATOR) + ++mEndPath; + // Don't return a "file" (directory) which does not exist. + PRBool exists; + if (localFile && + NS_SUCCEEDED(localFile->Exists(&exists)) && + exists) + mNext = localFile; + } + if (mNext) + *result = PR_TRUE; + else + nsAppDirectoryEnumerator::HasMoreElements(result); + + return NS_OK; + } + + protected: + const char *mEndPath; +}; + +NS_IMETHODIMP +nsAppFileLocationProvider::GetFiles(const char *prop, nsISimpleEnumerator **_retval) +{ + NS_ENSURE_ARG_POINTER(_retval); + *_retval = nsnull; + nsresult rv = NS_ERROR_FAILURE; + + if (!nsCRT::strcmp(prop, NS_APP_PLUGINS_DIR_LIST)) + { +#if (defined(XP_MAC) || defined(XP_MACOSX)) && !defined(VBOX_MACOSX_FOLLOWS_UNIX_IO) + static const char* osXKeys[] = { NS_APP_PLUGINS_DIR, NS_MACOSX_USER_PLUGIN_DIR, NS_MACOSX_LOCAL_PLUGIN_DIR, nsnull }; + static const char* os9Keys[] = { NS_APP_PLUGINS_DIR, NS_MAC_CLASSIC_PLUGIN_DIR, nsnull }; + static const char** keys; + + if (!keys) { + OSErr err; + SInt32 response; + err = ::Gestalt(gestaltSystemVersion, &response); + keys = (!err && response >= 0x00001000) ? osXKeys : os9Keys; + } + + *_retval = new nsAppDirectoryEnumerator(this, keys); +#else + static const char* keys[] = { nsnull, NS_APP_PLUGINS_DIR, nsnull }; + if (!keys[0] && !(keys[0] = PR_GetEnv("VBOX_XPCOM_PLUGIN_PATH"))) { + static const char nullstr = 0; + keys[0] = &nullstr; + } + *_retval = new nsPathsDirectoryEnumerator(this, keys); +#endif + NS_IF_ADDREF(*_retval); + rv = *_retval ? NS_OK : NS_ERROR_OUT_OF_MEMORY; + } + return rv; +} diff --git a/src/libs/xpcom18a4/xpcom/io/nsAppFileLocationProvider.h b/src/libs/xpcom18a4/xpcom/io/nsAppFileLocationProvider.h new file mode 100644 index 00000000..677ae00e --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsAppFileLocationProvider.h @@ -0,0 +1,67 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Conrad Carlen + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsIDirectoryService.h" +#include "nsILocalFile.h" + +class nsIFile; + +//***************************************************************************** +// class nsAppFileLocationProvider +//***************************************************************************** + +class nsAppFileLocationProvider : public nsIDirectoryServiceProvider2 +{ +public: + nsAppFileLocationProvider(); + + NS_DECL_ISUPPORTS + NS_DECL_NSIDIRECTORYSERVICEPROVIDER + NS_DECL_NSIDIRECTORYSERVICEPROVIDER2 + +private: + ~nsAppFileLocationProvider() {} + +protected: + NS_METHOD CloneMozBinDirectory(nsILocalFile **aLocalFile); + NS_METHOD GetProductDirectory(nsILocalFile **aLocalFile); + NS_METHOD GetDefaultUserProfileRoot(nsILocalFile **aLocalFile); + + nsCOMPtr mMozBinDirectory; +}; diff --git a/src/libs/xpcom18a4/xpcom/io/nsBinaryStream.cpp b/src/libs/xpcom18a4/xpcom/io/nsBinaryStream.cpp new file mode 100644 index 00000000..bc60eea3 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsBinaryStream.cpp @@ -0,0 +1,663 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * ***** 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 Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/** + * This file contains implementations of the nsIBinaryInputStream and + * nsIBinaryOutputStream interfaces. Together, these interfaces allows reading + * and writing of primitive data types (integers, floating-point values, + * booleans, etc.) to a stream in a binary, untagged, fixed-endianness format. + * This might be used, for example, to implement network protocols or to + * produce architecture-neutral binary disk files, i.e. ones that can be read + * and written by both big-endian and little-endian platforms. Output is + * written in big-endian order (high-order byte first), as this is traditional + * network order. + * + * @See nsIBinaryInputStream + * @See nsIBinaryOutputStream + */ +#include +#include "nsBinaryStream.h" +#include "nsCRT.h" +#include "nsIStreamBufferAccess.h" +#include "nsMemory.h" +#include "prlong.h" +#include "nsGenericFactory.h" + +NS_IMPL_ISUPPORTS3(nsBinaryOutputStream, nsIObjectOutputStream, nsIBinaryOutputStream, nsIOutputStream) + +NS_IMETHODIMP +nsBinaryOutputStream::Flush() { return mOutputStream->Flush(); } + +NS_IMETHODIMP +nsBinaryOutputStream::Close() { return mOutputStream->Close(); } + +NS_IMETHODIMP +nsBinaryOutputStream::Write(const char *aBuf, PRUint32 aCount, PRUint32 *aActualBytes) +{ + return mOutputStream->Write(aBuf, aCount, aActualBytes); +} + +NS_IMETHODIMP +nsBinaryOutputStream::WriteFrom(nsIInputStream *inStr, PRUint32 count, PRUint32 *_retval) +{ + NS_NOTREACHED("WriteFrom"); + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsBinaryOutputStream::WriteSegments(nsReadSegmentFun reader, void * closure, PRUint32 count, PRUint32 *_retval) +{ + NS_NOTREACHED("WriteSegments"); + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsBinaryOutputStream::IsNonBlocking(PRBool *aNonBlocking) +{ + return mOutputStream->IsNonBlocking(aNonBlocking); +} + +nsresult +nsBinaryOutputStream::WriteFully(const char *aBuf, PRUint32 aCount) +{ + nsresult rv; + PRUint32 bytesWritten; + + rv = mOutputStream->Write(aBuf, aCount, &bytesWritten); + if (NS_FAILED(rv)) return rv; + if (bytesWritten != aCount) + return NS_ERROR_FAILURE; + return NS_OK; +} + +NS_IMETHODIMP +nsBinaryOutputStream::SetOutputStream(nsIOutputStream *aOutputStream) +{ + NS_ENSURE_ARG_POINTER(aOutputStream); + mOutputStream = aOutputStream; + mBufferAccess = do_QueryInterface(aOutputStream); + return NS_OK; +} + +NS_IMETHODIMP +nsBinaryOutputStream::WriteBoolean(PRBool aBoolean) +{ + return Write8(aBoolean); +} + +NS_IMETHODIMP +nsBinaryOutputStream::Write8(PRUint8 aByte) +{ + return WriteFully((const char*)&aByte, sizeof aByte); +} + +NS_IMETHODIMP +nsBinaryOutputStream::Write16(PRUint16 a16) +{ + a16 = NS_SWAP16(a16); + return WriteFully((const char*)&a16, sizeof a16); +} + +NS_IMETHODIMP +nsBinaryOutputStream::Write32(PRUint32 a32) +{ + a32 = NS_SWAP32(a32); + return WriteFully((const char*)&a32, sizeof a32); +} + +NS_IMETHODIMP +nsBinaryOutputStream::Write64(PRUint64 a64) +{ + nsresult rv; + PRUint32 bytesWritten; + + a64 = NS_SWAP64(a64); + rv = Write(NS_REINTERPRET_CAST(char*, &a64), sizeof a64, &bytesWritten); + if (NS_FAILED(rv)) return rv; + if (bytesWritten != sizeof a64) + return NS_ERROR_FAILURE; + return rv; +} + +NS_IMETHODIMP +nsBinaryOutputStream::WriteFloat(float aFloat) +{ + NS_ASSERTION(sizeof(float) == sizeof (PRUint32), + "False assumption about sizeof(float)"); + return Write32(*NS_REINTERPRET_CAST(PRUint32*, &aFloat)); +} + +NS_IMETHODIMP +nsBinaryOutputStream::WriteDouble(double aDouble) +{ + NS_ASSERTION(sizeof(double) == sizeof(PRUint64), + "False assumption about sizeof(double)"); + return Write64(*NS_REINTERPRET_CAST(PRUint64*, &aDouble)); +} + +NS_IMETHODIMP +nsBinaryOutputStream::WriteStringZ(const char *aString) +{ + PRUint32 length; + nsresult rv; + + length = strlen(aString); + rv = Write32(length); + if (NS_FAILED(rv)) return rv; + return WriteFully(aString, length); +} + +NS_IMETHODIMP +nsBinaryOutputStream::WriteWStringZ(const PRUnichar* aString) +{ + PRUint32 length, byteCount; + nsresult rv; + + length = nsCRT::strlen(aString); + rv = Write32(length); + if (NS_FAILED(rv)) return rv; + + if (length == 0) + return NS_OK; + byteCount = length * sizeof(PRUnichar); + +#ifdef IS_BIG_ENDIAN + rv = WriteBytes(NS_REINTERPRET_CAST(const char*, aString), byteCount); +#else + // XXX use WriteSegments here to avoid copy! + PRUnichar *copy, temp[64]; + if (length <= 64) { + copy = temp; + } else { + copy = NS_REINTERPRET_CAST(PRUnichar*, nsMemory::Alloc(byteCount)); + if (!copy) + return NS_ERROR_OUT_OF_MEMORY; + } + NS_ASSERTION((PRUptrdiff(aString) & 0x1) == 0, "aString not properly aligned"); + for (PRUint32 i = 0; i < length; i++) + copy[i] = NS_SWAP16(aString[i]); + rv = WriteBytes(NS_REINTERPRET_CAST(const char*, copy), byteCount); + if (copy != temp) + nsMemory::Free(copy); +#endif + + return rv; +} + +NS_IMETHODIMP +nsBinaryOutputStream::WriteUtf8Z(const PRUnichar* aString) +{ + NS_NOTREACHED("WriteUtf8Z"); + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsBinaryOutputStream::WriteBytes(const char *aString, PRUint32 aLength) +{ + nsresult rv; + PRUint32 bytesWritten; + + rv = Write(aString, aLength, &bytesWritten); + if (NS_FAILED(rv)) return rv; + if (bytesWritten != aLength) + return NS_ERROR_FAILURE; + return rv; +} + +NS_IMETHODIMP +nsBinaryOutputStream::WriteByteArray(PRUint8 *aBytes, PRUint32 aLength) +{ + return WriteBytes(NS_REINTERPRET_CAST(char *, aBytes), aLength); +} + +NS_IMETHODIMP +nsBinaryOutputStream::WriteObject(nsISupports* aObject, PRBool aIsStrongRef) +{ + NS_NOTREACHED("WriteObject"); + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsBinaryOutputStream::WriteSingleRefObject(nsISupports* aObject) +{ + NS_NOTREACHED("WriteSingleRefObject"); + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsBinaryOutputStream::WriteCompoundObject(nsISupports* aObject, + const nsIID& aIID, + PRBool aIsStrongRef) +{ + NS_NOTREACHED("WriteCompoundObject"); + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsBinaryOutputStream::WriteID(const nsIID& aIID) +{ + NS_NOTREACHED("WriteID"); + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP_(char*) +nsBinaryOutputStream::GetBuffer(PRUint32 aLength, PRUint32 aAlignMask) +{ + if (mBufferAccess) + return mBufferAccess->GetBuffer(aLength, aAlignMask); + return nsnull; +} + +NS_IMETHODIMP_(void) +nsBinaryOutputStream::PutBuffer(char* aBuffer, PRUint32 aLength) +{ + if (mBufferAccess) + mBufferAccess->PutBuffer(aBuffer, aLength); +} + +NS_IMPL_ISUPPORTS3(nsBinaryInputStream, nsIObjectInputStream, nsIBinaryInputStream, nsIInputStream) + +NS_IMETHODIMP +nsBinaryInputStream::Available(PRUint32* aResult) +{ + return mInputStream->Available(aResult); +} + +NS_IMETHODIMP +nsBinaryInputStream::Read(char* aBuffer, PRUint32 aCount, PRUint32 *aNumRead) +{ + return mInputStream->Read(aBuffer, aCount, aNumRead); +} + + +// when forwarding ReadSegments to mInputStream, we need to make sure +// 'this' is being passed to the writer each time. To do this, we need +// a thunking function which keeps the real input stream around. + +// the closure wrapper +struct ReadSegmentsClosure { + nsIInputStream* mRealInputStream; + void* mRealClosure; + nsWriteSegmentFun mRealWriter; +}; + +// the thunking function +static NS_METHOD +ReadSegmentForwardingThunk(nsIInputStream* aStream, + void *aClosure, + const char* aFromSegment, + PRUint32 aToOffset, + PRUint32 aCount, + PRUint32 *aWriteCount) +{ + ReadSegmentsClosure* thunkClosure = + NS_REINTERPRET_CAST(ReadSegmentsClosure*, aClosure); + + return thunkClosure->mRealWriter(thunkClosure->mRealInputStream, + thunkClosure->mRealClosure, + aFromSegment, aToOffset, + aCount, aWriteCount); +} + + +NS_IMETHODIMP +nsBinaryInputStream::ReadSegments(nsWriteSegmentFun writer, void * closure, PRUint32 count, PRUint32 *_retval) +{ + ReadSegmentsClosure thunkClosure = { this, closure, writer }; + + return mInputStream->ReadSegments(ReadSegmentForwardingThunk, &thunkClosure, count, _retval); +} + +NS_IMETHODIMP +nsBinaryInputStream::IsNonBlocking(PRBool *aNonBlocking) +{ + return mInputStream->IsNonBlocking(aNonBlocking); +} + +NS_IMETHODIMP +nsBinaryInputStream::Close() { return mInputStream->Close(); } + +NS_IMETHODIMP +nsBinaryInputStream::SetInputStream(nsIInputStream *aInputStream) +{ + NS_ENSURE_ARG_POINTER(aInputStream); + mInputStream = aInputStream; + mBufferAccess = do_QueryInterface(aInputStream); + return NS_OK; +} + +NS_IMETHODIMP +nsBinaryInputStream::ReadBoolean(PRBool* aBoolean) +{ + PRUint8 byteResult; + nsresult rv = Read8(&byteResult); + *aBoolean = byteResult; + return rv; +} + +NS_IMETHODIMP +nsBinaryInputStream::Read8(PRUint8* aByte) +{ + nsresult rv; + PRUint32 bytesRead; + + rv = Read(NS_REINTERPRET_CAST(char*, aByte), sizeof(*aByte), &bytesRead); + if (NS_FAILED(rv)) return rv; + if (bytesRead != 1) + return NS_ERROR_FAILURE; + return rv; +} + +NS_IMETHODIMP +nsBinaryInputStream::Read16(PRUint16* a16) +{ + nsresult rv; + PRUint32 bytesRead; + + rv = Read(NS_REINTERPRET_CAST(char*, a16), sizeof *a16, &bytesRead); + if (NS_FAILED(rv)) return rv; + if (bytesRead != sizeof *a16) + return NS_ERROR_FAILURE; + *a16 = NS_SWAP16(*a16); + return rv; +} + +NS_IMETHODIMP +nsBinaryInputStream::Read32(PRUint32* a32) +{ + nsresult rv; + PRUint32 bytesRead; + + rv = Read(NS_REINTERPRET_CAST(char*, a32), sizeof *a32, &bytesRead); + if (NS_FAILED(rv)) return rv; + if (bytesRead != sizeof *a32) + return NS_ERROR_FAILURE; + *a32 = NS_SWAP32(*a32); + return rv; +} + +NS_IMETHODIMP +nsBinaryInputStream::Read64(PRUint64* a64) +{ + nsresult rv; + PRUint32 bytesRead; + + rv = Read(NS_REINTERPRET_CAST(char*, a64), sizeof *a64, &bytesRead); + if (NS_FAILED(rv)) return rv; + if (bytesRead != sizeof *a64) + return NS_ERROR_FAILURE; + *a64 = NS_SWAP64(*a64); + return rv; +} + +NS_IMETHODIMP +nsBinaryInputStream::ReadFloat(float* aFloat) +{ + NS_ASSERTION(sizeof(float) == sizeof (PRUint32), + "False assumption about sizeof(float)"); + return Read32(NS_REINTERPRET_CAST(PRUint32*, aFloat)); +} + +NS_IMETHODIMP +nsBinaryInputStream::ReadDouble(double* aDouble) +{ + NS_ASSERTION(sizeof(double) == sizeof(PRUint64), + "False assumption about sizeof(double)"); + return Read64(NS_REINTERPRET_CAST(PRUint64*, aDouble)); +} + +static NS_METHOD +WriteSegmentToCString(nsIInputStream* aStream, + void *aClosure, + const char* aFromSegment, + PRUint32 aToOffset, + PRUint32 aCount, + PRUint32 *aWriteCount) +{ + nsACString* outString = NS_STATIC_CAST(nsACString*,aClosure); + + outString->Append(aFromSegment, aCount); + + *aWriteCount = aCount; + + return NS_OK; +} + +NS_IMETHODIMP +nsBinaryInputStream::ReadCString(nsACString& aString) +{ + nsresult rv; + PRUint32 length, bytesRead; + + rv = Read32(&length); + if (NS_FAILED(rv)) return rv; + + aString.Truncate(); + rv = ReadSegments(WriteSegmentToCString, &aString, length, &bytesRead); + if (NS_FAILED(rv)) return rv; + + if (bytesRead != length) + return NS_ERROR_FAILURE; + + return NS_OK; +} + + +// sometimes, WriteSegmentToString will be handed an odd-number of +// bytes, which means we only have half of the last PRUnichar +struct WriteStringClosure { + PRUnichar *mWriteCursor; + PRPackedBool mHasCarryoverByte; + char mCarryoverByte; +}; + +// there are a few cases we have to account for here: +// * even length buffer, no carryover - easy, just append +// * odd length buffer, no carryover - the last byte needs to be saved +// for carryover +// * odd length buffer, with carryover - first byte needs to be used +// with the carryover byte, and +// the rest of the even length +// buffer is appended as normal +// * even length buffer, with carryover - the first byte needs to be +// used with the previous carryover byte. +// this gives you an odd length buffer, +// so you have to save the last byte for +// the next carryover + + +// same version of the above, but with correct casting and endian swapping +static NS_METHOD +WriteSegmentToString(nsIInputStream* aStream, + void *aClosure, + const char* aFromSegment, + PRUint32 aToOffset, + PRUint32 aCount, + PRUint32 *aWriteCount) +{ + NS_PRECONDITION(aCount > 0, "Why are we being told to write 0 bytes?"); + NS_PRECONDITION(sizeof(PRUnichar) == 2, "We can't handle other sizes!"); + + WriteStringClosure* closure = NS_STATIC_CAST(WriteStringClosure*,aClosure); + PRUnichar *cursor = closure->mWriteCursor; + + // we're always going to consume the whole buffer no matter what + // happens, so take care of that right now.. that allows us to + // tweak aCount later. Do NOT move this! + *aWriteCount = aCount; + + // if the last Write had an odd-number of bytes read, then + if (closure->mHasCarryoverByte) { + // re-create the two-byte sequence we want to work with + char bytes[2] = { closure->mCarryoverByte, *aFromSegment }; + *cursor = *(PRUnichar*)bytes; + // Now the little endianness dance +#ifdef IS_LITTLE_ENDIAN + *cursor = (PRUnichar) NS_SWAP16(*cursor); +#endif + ++cursor; + + // now skip past the first byte of the buffer.. code from here + // can assume normal operations, but should not assume aCount + // is relative to the ORIGINAL buffer + ++aFromSegment; + --aCount; + + closure->mHasCarryoverByte = PR_FALSE; + } + + // this array is possibly unaligned... be careful how we access it! + const PRUnichar *unicodeSegment = + NS_REINTERPRET_CAST(const PRUnichar*, aFromSegment); + + // calculate number of full characters in segment (aCount could be odd!) + PRUint32 segmentLength = aCount / sizeof(PRUnichar); + + // copy all data into our aligned buffer. byte swap if necessary. + memcpy(cursor, unicodeSegment, segmentLength * sizeof(PRUnichar)); + PRUnichar *end = cursor + segmentLength; +#ifdef IS_LITTLE_ENDIAN + for (; cursor < end; ++cursor) + *cursor = (PRUnichar) NS_SWAP16(*cursor); +#endif + closure->mWriteCursor = end; + + // remember this is the modifed aCount and aFromSegment, + // so that will take into account the fact that we might have + // skipped the first byte in the buffer + if (aCount % sizeof(PRUnichar) != 0) { + // we must have had a carryover byte, that we'll need the next + // time around + closure->mCarryoverByte = aFromSegment[aCount - 1]; + closure->mHasCarryoverByte = PR_TRUE; + } + + return NS_OK; +} + + +NS_IMETHODIMP +nsBinaryInputStream::ReadString(nsAString& aString) +{ + nsresult rv; + PRUint32 length, bytesRead; + + rv = Read32(&length); + if (NS_FAILED(rv)) return rv; + + // pre-allocate output buffer, and get direct access to buffer... + aString.SetLength(length); + nsAString::iterator start; + aString.BeginWriting(start); + + WriteStringClosure closure; + closure.mWriteCursor = start.get(); + closure.mHasCarryoverByte = PR_FALSE; + + rv = ReadSegments(WriteSegmentToString, &closure, + length*sizeof(PRUnichar), &bytesRead); + if (NS_FAILED(rv)) return rv; + + NS_ASSERTION(!closure.mHasCarryoverByte, "some strange stream corruption!"); + + if (bytesRead != length*sizeof(PRUnichar)) + return NS_ERROR_FAILURE; + + return NS_OK; +} + +NS_IMETHODIMP +nsBinaryInputStream::ReadBytes(PRUint32 aLength, char* *_rval) +{ + nsresult rv; + PRUint32 bytesRead; + char* s; + + s = NS_REINTERPRET_CAST(char*, nsMemory::Alloc(aLength)); + if (!s) + return NS_ERROR_OUT_OF_MEMORY; + + rv = Read(s, aLength, &bytesRead); + if (NS_FAILED(rv)) { + nsMemory::Free(s); + return rv; + } + if (bytesRead != aLength) { + nsMemory::Free(s); + return NS_ERROR_FAILURE; + } + + *_rval = s; + return NS_OK; +} + +NS_IMETHODIMP +nsBinaryInputStream::ReadByteArray(PRUint32 aLength, PRUint8* *_rval) +{ + return ReadBytes(aLength, NS_REINTERPRET_CAST(char **, _rval)); +} + +NS_IMETHODIMP +nsBinaryInputStream::ReadObject(PRBool aIsStrongRef, nsISupports* *aObject) +{ + NS_NOTREACHED("ReadObject"); + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsBinaryInputStream::ReadID(nsID *aResult) +{ + NS_NOTREACHED("ReadID"); + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP_(char*) +nsBinaryInputStream::GetBuffer(PRUint32 aLength, PRUint32 aAlignMask) +{ + if (mBufferAccess) + return mBufferAccess->GetBuffer(aLength, aAlignMask); + return nsnull; +} + +NS_IMETHODIMP_(void) +nsBinaryInputStream::PutBuffer(char* aBuffer, PRUint32 aLength) +{ + if (mBufferAccess) + mBufferAccess->PutBuffer(aBuffer, aLength); +} + diff --git a/src/libs/xpcom18a4/xpcom/io/nsBinaryStream.h b/src/libs/xpcom18a4/xpcom/io/nsBinaryStream.h new file mode 100644 index 00000000..7be46dc7 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsBinaryStream.h @@ -0,0 +1,125 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * ***** 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 Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +#ifndef nsBinaryStream_h___ +#define nsBinaryStream_h___ + +#include "nsCOMPtr.h" +#include "nsAString.h" +#include "nsIObjectInputStream.h" +#include "nsIObjectOutputStream.h" +#include "nsIStreamBufferAccess.h" + +#define NS_BINARYOUTPUTSTREAM_CID \ +{ /* 86c37b9a-74e7-4672-844e-6e7dd83ba484 */ \ + 0x86c37b9a, \ + 0x74e7, \ + 0x4672, \ + {0x84, 0x4e, 0x6e, 0x7d, 0xd8, 0x3b, 0xa4, 0x84} \ +} + +#define NS_BINARYOUTPUTSTREAM_CONTRACTID "@mozilla.org/binaryoutputstream;1" +#define NS_BINARYOUTPUTSTREAM_CLASSNAME "Binary Output Stream" + +// Derive from nsIObjectOutputStream so this class can be used as a superclass +// by nsObjectOutputStream. +class nsBinaryOutputStream : public nsIObjectOutputStream +{ +public: + nsBinaryOutputStream() {}; + // virtual dtor since subclasses call our Release() + virtual ~nsBinaryOutputStream() {}; + +protected: + // nsISupports methods + NS_DECL_ISUPPORTS + + // nsIOutputStream methods + NS_DECL_NSIOUTPUTSTREAM + + // nsIBinaryOutputStream methods + NS_DECL_NSIBINARYOUTPUTSTREAM + + // nsIObjectOutputStream methods + NS_DECL_NSIOBJECTOUTPUTSTREAM + + // Call Write(), ensuring that all proffered data is written + nsresult WriteFully(const char *aBuf, PRUint32 aCount); + + nsCOMPtr mOutputStream; + nsCOMPtr mBufferAccess; +}; + +#define NS_BINARYINPUTSTREAM_CID \ +{ /* c521a612-2aad-46db-b6ab-3b821fb150b1 */ \ + 0xc521a612, \ + 0x2aad, \ + 0x46db, \ + {0xb6, 0xab, 0x3b, 0x82, 0x1f, 0xb1, 0x50, 0xb1} \ +} + +#define NS_BINARYINPUTSTREAM_CONTRACTID "@mozilla.org/binaryinputstream;1" +#define NS_BINARYINPUTSTREAM_CLASSNAME "Binary Input Stream" + +// Derive from nsIObjectInputStream so this class can be used as a superclass +// by nsObjectInputStream. +class nsBinaryInputStream : public nsIObjectInputStream +{ +public: + nsBinaryInputStream() {}; + // virtual dtor since subclasses call our Release() + virtual ~nsBinaryInputStream() {}; + +protected: + // nsISupports methods + NS_DECL_ISUPPORTS + + // nsIInputStream methods + NS_DECL_NSIINPUTSTREAM + + // nsIBinaryInputStream methods + NS_DECL_NSIBINARYINPUTSTREAM + + // nsIObjectInputStream methods + NS_DECL_NSIOBJECTINPUTSTREAM + + nsCOMPtr mInputStream; + nsCOMPtr mBufferAccess; +}; + +#endif // nsBinaryStream_h___ diff --git a/src/libs/xpcom18a4/xpcom/io/nsByteArrayInputStream.cpp b/src/libs/xpcom18a4/xpcom/io/nsByteArrayInputStream.cpp new file mode 100644 index 00000000..364f71d5 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsByteArrayInputStream.cpp @@ -0,0 +1,164 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * ***** 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 Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsByteArrayInputStream.h" +#include "nsMemory.h" + +NS_IMPL_THREADSAFE_ISUPPORTS2(nsByteArrayInputStream, nsIInputStream, nsIByteArrayInputStream) + +nsByteArrayInputStream::nsByteArrayInputStream (char *buffer, PRUint32 bytes) + : _buffer (buffer), _nbytes (bytes), _pos (0) +{ +} + +nsByteArrayInputStream::~nsByteArrayInputStream () +{ + if (_buffer != NULL) + nsMemory::Free (_buffer); +} + +NS_IMETHODIMP +nsByteArrayInputStream::Available (PRUint32* aResult) +{ + if (aResult == NULL) + return NS_ERROR_NULL_POINTER; + + if (_nbytes == 0 || _buffer == NULL) + *aResult = 0; + else + *aResult = _nbytes - _pos; + + return NS_OK; +} + +NS_IMETHODIMP +nsByteArrayInputStream::Read (char* aBuffer, PRUint32 aCount, PRUint32 *aNumRead) +{ + if (aBuffer == NULL || aNumRead == NULL) + return NS_ERROR_NULL_POINTER; + + if (_nbytes == 0) + return NS_ERROR_FAILURE; + + if (aCount == 0 || _pos == _nbytes) + *aNumRead = 0; + else + { + NS_ASSERTION (_buffer != NULL, "Stream buffer has been released - there's an ownership problem somewhere!"); + if (_buffer == NULL) + *aNumRead = 0; + else + if (aCount > _nbytes - _pos) + { + memcpy (aBuffer, &_buffer[_pos], *aNumRead = _nbytes - _pos); + _pos = _nbytes; + } + else + { + memcpy (aBuffer, &_buffer[_pos], *aNumRead = aCount); + _pos += aCount; + } + } + return NS_OK; +} + +NS_IMETHODIMP +nsByteArrayInputStream::ReadSegments(nsWriteSegmentFun writer, void * aClosure, PRUint32 aCount, PRUint32 *aNumRead) +{ + if (aNumRead == NULL) + return NS_ERROR_NULL_POINTER; + + if (_nbytes == 0) + return NS_ERROR_FAILURE; + + if (aCount == 0 || _pos == _nbytes) + *aNumRead = 0; + else { + NS_ASSERTION (_buffer != NULL, "Stream buffer has been released - there's an ownership problem somewhere!"); + PRUint32 readCount = PR_MIN(aCount, (_nbytes - _pos)); + if (_buffer == NULL) + *aNumRead = 0; + else { + nsresult rv = writer (this, aClosure, &_buffer[_pos], + _pos, readCount, aNumRead); + if (NS_SUCCEEDED(rv)) + _pos += *aNumRead; + } + } + + // do not propogate errors returned from writer! + return NS_OK; +} + +NS_IMETHODIMP +nsByteArrayInputStream::IsNonBlocking(PRBool *aNonBlocking) +{ + *aNonBlocking = PR_TRUE; + return NS_OK; +} + +NS_IMETHODIMP +nsByteArrayInputStream::Close () +{ + if (_buffer != NULL) + { + nsMemory::Free (_buffer); + _buffer = NULL; + _nbytes = 0; + } + else + return NS_ERROR_FAILURE; + + return NS_OK; +} + +NS_COM nsresult +NS_NewByteArrayInputStream (nsIByteArrayInputStream* *aResult, char * buffer, unsigned long bytes) +{ + if (aResult == NULL) + return NS_ERROR_NULL_POINTER; + + nsIByteArrayInputStream * stream = new nsByteArrayInputStream (buffer, bytes); + + if (!stream) + return NS_ERROR_OUT_OF_MEMORY; + + NS_ADDREF (stream); + *aResult = stream; + return NS_OK; +} diff --git a/src/libs/xpcom18a4/xpcom/io/nsByteArrayInputStream.h b/src/libs/xpcom18a4/xpcom/io/nsByteArrayInputStream.h new file mode 100644 index 00000000..2999eb5f --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsByteArrayInputStream.h @@ -0,0 +1,59 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * ***** 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 Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsIByteArrayInputStream.h" +#include "nsCOMPtr.h" + +class nsByteArrayInputStream : public nsIByteArrayInputStream +{ + // nsISupports methods + NS_DECL_ISUPPORTS + + // nsIInputStream methods + NS_DECL_NSIINPUTSTREAM + +public: + nsByteArrayInputStream (char *buffer, PRUint32 nbytes); + +private: + ~nsByteArrayInputStream (); + + char *_buffer; + PRUint32 _nbytes; + PRUint32 _pos; +}; diff --git a/src/libs/xpcom18a4/xpcom/io/nsDirectoryService.cpp b/src/libs/xpcom18a4/xpcom/io/nsDirectoryService.cpp new file mode 100644 index 00000000..60b16eda --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsDirectoryService.cpp @@ -0,0 +1,1241 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * IBM Corp. + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsCOMPtr.h" +#include "nsDirectoryService.h" +#include "nsDirectoryServiceDefs.h" +#include "nsLocalFile.h" +#include "nsDebug.h" +#include "nsStaticAtom.h" + +#if defined(XP_MAC) +#include +#include +#include +#include +#include +#elif defined(XP_WIN) +#include +#include +#include +#include +#elif defined(XP_UNIX) || defined(XP_MACOSX) +#include +#include +#include +#include +#include "prenv.h" +#ifdef XP_MACOSX +#include +#include +#include +# ifndef VBOX_WITH_NEWER_OSX_SDK +# include +# endif +#include +#include +#include +#include +#endif +#elif defined(XP_OS2) +#define MAX_PATH _MAX_PATH +#elif defined(XP_BEOS) +#include +#include +#include +#include +#include +#include +#include +#include "prenv.h" +#endif + +#include "SpecialSystemDirectory.h" +#include "nsAppFileLocationProvider.h" + +#if defined(XP_MAC) +#define COMPONENT_REGISTRY_NAME NS_LITERAL_CSTRING("Component Registry") +#define COMPONENT_DIRECTORY NS_LITERAL_CSTRING("Components") +#else +#define COMPONENT_REGISTRY_NAME NS_LITERAL_CSTRING("compreg.dat") +#define COMPONENT_DIRECTORY NS_LITERAL_CSTRING("components") +#endif + +#define XPTI_REGISTRY_NAME NS_LITERAL_CSTRING("xpti.dat") + +// define home directory +// For Windows platform, We are choosing Appdata folder as HOME +#if defined (XP_WIN) +#define HOME_DIR NS_WIN_APPDATA_DIR +#elif defined (XP_MAC) || defined (XP_MACOSX) +#define HOME_DIR NS_OSX_HOME_DIR +#elif defined (XP_UNIX) +#define HOME_DIR NS_UNIX_HOME_DIR +#elif defined (XP_OS2) +#define HOME_DIR NS_OS2_HOME_DIR +#elif defined (XP_BEOS) +#define HOME_DIR NS_BEOS_HOME_DIR +#endif + +//---------------------------------------------------------------------------------------- +nsresult +nsDirectoryService::GetCurrentProcessDirectory(nsILocalFile** aFile) +//---------------------------------------------------------------------------------------- +{ + NS_ENSURE_ARG_POINTER(aFile); + *aFile = nsnull; + + // Set the component registry location: + if (!mService) + return NS_ERROR_FAILURE; + + nsresult rv; + + nsCOMPtr dirService; + rv = nsDirectoryService::Create(nsnull, + NS_GET_IID(nsIProperties), + getter_AddRefs(dirService)); // needs to be around for life of product + + if (dirService) + { + nsCOMPtr aLocalFile; + dirService->Get(NS_XPCOM_INIT_CURRENT_PROCESS_DIR, NS_GET_IID(nsILocalFile), getter_AddRefs(aLocalFile)); + if (aLocalFile) + { + *aFile = aLocalFile; + NS_ADDREF(*aFile); + return NS_OK; + } + } + + nsLocalFile* localFile = new nsLocalFile; + + if (localFile == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + NS_ADDREF(localFile); + + + +#ifdef XP_WIN + char buf[MAX_PATH]; + if ( ::GetModuleFileName(0, buf, sizeof(buf)) ) { + // chop of the executable name by finding the rightmost backslash + char* lastSlash = PL_strrchr(buf, '\\'); + if (lastSlash) + *(lastSlash + 1) = '\0'; + + localFile->InitWithNativePath(nsDependentCString(buf)); + *aFile = localFile; + return NS_OK; + } + +#elif defined(XP_MAC) + // get info for the the current process to determine the directory + // its located in + OSErr err; + ProcessSerialNumber psn = {kNoProcess, kCurrentProcess}; + ProcessInfoRec pInfo; + FSSpec tempSpec; + + // initialize ProcessInfoRec before calling + // GetProcessInformation() or die horribly. + pInfo.processName = nil; + pInfo.processAppSpec = &tempSpec; + pInfo.processInfoLength = sizeof(ProcessInfoRec); + + err = GetProcessInformation(&psn, &pInfo); + if (!err) + { + // create an FSSpec from the volume and dirid of the app. + FSSpec appFSSpec; + ::FSMakeFSSpec(pInfo.processAppSpec->vRefNum, pInfo.processAppSpec->parID, 0, &appFSSpec); + + nsCOMPtr localFileMac = do_QueryInterface((nsIFile*)localFile); + if (localFileMac) + { + localFileMac->InitWithFSSpec(&appFSSpec); + *aFile = localFile; + return NS_OK; + } + } +#elif defined(XP_MACOSX) +# ifdef MOZ_DEFAULT_VBOX_XPCOM_HOME + rv = localFile->InitWithNativePath(nsDependentCString(MOZ_DEFAULT_VBOX_XPCOM_HOME)); + if (NS_SUCCEEDED(rv)) + *aFile = localFile; +# else + // Works even if we're not bundled. + CFBundleRef appBundle = CFBundleGetMainBundle(); + if (appBundle != nsnull) + { + CFURLRef bundleURL = CFBundleCopyExecutableURL(appBundle); + if (bundleURL != nsnull) + { + CFURLRef parentURL = CFURLCreateCopyDeletingLastPathComponent(kCFAllocatorDefault, bundleURL); + if (parentURL) + { + // Pass PR_TRUE for the "resolveAgainstBase" arg to CFURLGetFileSystemRepresentation. + // This will resolve the relative portion of the CFURL against it base, giving a full + // path, which CFURLCopyFileSystemPath doesn't do. + char buffer[PATH_MAX]; + if (CFURLGetFileSystemRepresentation(parentURL, PR_TRUE, (UInt8 *)buffer, sizeof(buffer))) + { +#ifdef DEBUG_conrad + printf("nsDirectoryService - CurrentProcessDir is: %s\n", buffer); +#endif + rv = localFile->InitWithNativePath(nsDependentCString(buffer)); + if (NS_SUCCEEDED(rv)) + *aFile = localFile; + } + CFRelease(parentURL); + } + CFRelease(bundleURL); + } + } +#endif + + NS_ASSERTION(*aFile, "nsDirectoryService - Could not determine CurrentProcessDir.\n"); + if (*aFile) + return NS_OK; + +#elif defined(XP_UNIX) + + // In the absence of a good way to get the executable directory let + // us try this for unix: + // - if VBOX_XPCOM_HOME is defined, that is it + // - else give the current directory + char buf[MAXPATHLEN]; + +#if 0 /* we need .so location. */ + // Actually we have a way on linux. + static volatile bool fPathSet = false; + static char szPath[MAXPATHLEN]; + if (!fPathSet) + { + char buf2[MAXPATHLEN + 3]; + buf2[0] = '\0'; + + /* + * Env.var. VBOX_XPCOM_HOME first. + */ + char *psz = PR_GetEnv("VBOX_XPCOM_HOME"); + if (psz) + { + if (strlen(psz) < MAXPATHLEN) + { + if (!realpath(psz, buf2)) + strcpy(buf2, psz); + strcat(buf2, "/x"); /* for the filename stripping */ + } + } + + /* + * The dynamic loader. + */ + if (!buf2[0]) + { + Dl_info DlInfo = {0}; + if ( !dladdr((void *)nsDirectoryService::mService, &DlInfo) + && DlInfo.dli_fname) + { + if (!realpath(DlInfo.dli_fname, buf2)) + buf2[0] = '\0'; + } + } + + /* + * Executable location. + */ + if (!buf2[0]) + { + char buf[MAXPATHLEN]; + int cchLink = readlink("/proc/self/exe", buf, sizeof(buf) - 1); + if (cchLink > 0 || cchLink != sizeof(buf) - 1) + { + buf[cchLink] = '\0'; + if (!realpath(buf, buf2)) + buf2[0] = '\0'; + } + } + + /* + * Copy to static buffer on success. + */ + if (buf2[0]) + { + char *p = strrchr(buf2, '/'); + if (p) + { + p[p == buf2] = '\0'; + #ifdef DEBUG + printf("debug: (1) VBOX_XPCOM_HOME=%s\n", buf2); + #endif + strcpy(szPath, buf2); + fPathSet = true; + } + } + } + if (fPathSet) + { + localFile->InitWithNativePath(nsDependentCString(szPath)); + *aFile = localFile; + return NS_OK; + } + +#endif + + + // The MOZ_DEFAULT_VBOX_XPCOM_HOME variable can be set at configure time with + // a --with-default-mozilla-five-home=foo autoconf flag. + // + // The idea here is to allow for builds that have a default VBOX_XPCOM_HOME + // regardless of the environment. This makes it easier to write apps that + // embed mozilla without having to worry about setting up the environment + // + // We do this py putenv()ing the default value into the environment. Note that + // we only do this if it is not already set. +#ifdef MOZ_DEFAULT_VBOX_XPCOM_HOME + if (PR_GetEnv("VBOX_XPCOM_HOME") == nsnull) + PR_SetEnv("VBOX_XPCOM_HOME=" MOZ_DEFAULT_VBOX_XPCOM_HOME); +#endif + + char *moz5 = PR_GetEnv("VBOX_XPCOM_HOME"); + + if (moz5) + { + if (realpath(moz5, buf)) { + localFile->InitWithNativePath(nsDependentCString(buf)); + *aFile = localFile; + return NS_OK; + } + } +#if defined(DEBUG) + static PRBool firstWarning = PR_TRUE; + + if(!moz5 && firstWarning) { + // Warn that VBOX_XPCOM_HOME not set, once. + printf("Warning: VBOX_XPCOM_HOME not set.\n"); + firstWarning = PR_FALSE; + } +#endif /* DEBUG */ + + // Fall back to current directory. + if (getcwd(buf, sizeof(buf))) + { + localFile->InitWithNativePath(nsDependentCString(buf)); + *aFile = localFile; + return NS_OK; + } + +#elif defined(XP_OS2) + PPIB ppib; + PTIB ptib; + char buffer[CCHMAXPATH]; + DosGetInfoBlocks( &ptib, &ppib); + DosQueryModuleName( ppib->pib_hmte, CCHMAXPATH, buffer); + *strrchr( buffer, '\\') = '\0'; // XXX DBCS misery + localFile->InitWithNativePath(nsDependentCString(buffer)); + *aFile = localFile; + return NS_OK; + +#elif defined(XP_BEOS) + + char *moz5 = getenv("VBOX_XPCOM_HOME"); + if (moz5) + { + localFile->InitWithNativePath(nsDependentCString(moz5)); + localFile->Normalize(); + *aFile = localFile; + return NS_OK; + } + else + { + static char buf[MAXPATHLEN]; + int32 cookie = 0; + image_info info; + char *p; + *buf = 0; + if(get_next_image_info(0, &cookie, &info) == B_OK) + { + strcpy(buf, info.name); + if((p = strrchr(buf, '/')) != 0) + { + *p = 0; + localFile->InitWithNativePath(nsDependentCString(buf)); + *aFile = localFile; + return NS_OK; + } + } + } + +#endif + + NS_RELEASE(localFile); + + NS_ERROR("unable to get current process directory"); + return NS_ERROR_FAILURE; +} // GetCurrentProcessDirectory() + + +nsIAtom* nsDirectoryService::sCurrentProcess = nsnull; +nsIAtom* nsDirectoryService::sComponentRegistry = nsnull; +nsIAtom* nsDirectoryService::sXPTIRegistry = nsnull; +nsIAtom* nsDirectoryService::sComponentDirectory = nsnull; +nsIAtom* nsDirectoryService::sGRE_Directory = nsnull; +nsIAtom* nsDirectoryService::sGRE_ComponentDirectory = nsnull; +nsIAtom* nsDirectoryService::sOS_DriveDirectory = nsnull; +nsIAtom* nsDirectoryService::sOS_TemporaryDirectory = nsnull; +nsIAtom* nsDirectoryService::sOS_CurrentProcessDirectory = nsnull; +nsIAtom* nsDirectoryService::sOS_CurrentWorkingDirectory = nsnull; +#if defined (XP_MACOSX) +nsIAtom* nsDirectoryService::sDirectory = nsnull; +nsIAtom* nsDirectoryService::sDesktopDirectory = nsnull; +nsIAtom* nsDirectoryService::sTrashDirectory = nsnull; +nsIAtom* nsDirectoryService::sStartupDirectory = nsnull; +nsIAtom* nsDirectoryService::sShutdownDirectory = nsnull; +nsIAtom* nsDirectoryService::sAppleMenuDirectory = nsnull; +nsIAtom* nsDirectoryService::sControlPanelDirectory = nsnull; +nsIAtom* nsDirectoryService::sExtensionDirectory = nsnull; +nsIAtom* nsDirectoryService::sFontsDirectory = nsnull; +nsIAtom* nsDirectoryService::sPreferencesDirectory = nsnull; +nsIAtom* nsDirectoryService::sDocumentsDirectory = nsnull; +nsIAtom* nsDirectoryService::sInternetSearchDirectory = nsnull; +nsIAtom* nsDirectoryService::sUserLibDirectory = nsnull; +nsIAtom* nsDirectoryService::sHomeDirectory = nsnull; +nsIAtom* nsDirectoryService::sDefaultDownloadDirectory = nsnull; +nsIAtom* nsDirectoryService::sUserDesktopDirectory = nsnull; +nsIAtom* nsDirectoryService::sLocalDesktopDirectory = nsnull; +nsIAtom* nsDirectoryService::sUserApplicationsDirectory = nsnull; +nsIAtom* nsDirectoryService::sLocalApplicationsDirectory = nsnull; +nsIAtom* nsDirectoryService::sUserDocumentsDirectory = nsnull; +nsIAtom* nsDirectoryService::sLocalDocumentsDirectory = nsnull; +nsIAtom* nsDirectoryService::sUserInternetPlugInDirectory = nsnull; +nsIAtom* nsDirectoryService::sLocalInternetPlugInDirectory = nsnull; +nsIAtom* nsDirectoryService::sUserFrameworksDirectory = nsnull; +nsIAtom* nsDirectoryService::sLocalFrameworksDirectory = nsnull; +nsIAtom* nsDirectoryService::sUserPreferencesDirectory = nsnull; +nsIAtom* nsDirectoryService::sLocalPreferencesDirectory = nsnull; +nsIAtom* nsDirectoryService::sPictureDocumentsDirectory = nsnull; +nsIAtom* nsDirectoryService::sMovieDocumentsDirectory = nsnull; +nsIAtom* nsDirectoryService::sMusicDocumentsDirectory = nsnull; +nsIAtom* nsDirectoryService::sInternetSitesDirectory = nsnull; +#elif defined (XP_WIN) +nsIAtom* nsDirectoryService::sSystemDirectory = nsnull; +nsIAtom* nsDirectoryService::sWindowsDirectory = nsnull; +nsIAtom* nsDirectoryService::sHomeDirectory = nsnull; +nsIAtom* nsDirectoryService::sDesktop = nsnull; +nsIAtom* nsDirectoryService::sPrograms = nsnull; +nsIAtom* nsDirectoryService::sControls = nsnull; +nsIAtom* nsDirectoryService::sPrinters = nsnull; +nsIAtom* nsDirectoryService::sPersonal = nsnull; +nsIAtom* nsDirectoryService::sFavorites = nsnull; +nsIAtom* nsDirectoryService::sStartup = nsnull; +nsIAtom* nsDirectoryService::sRecent = nsnull; +nsIAtom* nsDirectoryService::sSendto = nsnull; +nsIAtom* nsDirectoryService::sBitbucket = nsnull; +nsIAtom* nsDirectoryService::sStartmenu = nsnull; +nsIAtom* nsDirectoryService::sDesktopdirectory = nsnull; +nsIAtom* nsDirectoryService::sDrives = nsnull; +nsIAtom* nsDirectoryService::sNetwork = nsnull; +nsIAtom* nsDirectoryService::sNethood = nsnull; +nsIAtom* nsDirectoryService::sFonts = nsnull; +nsIAtom* nsDirectoryService::sTemplates = nsnull; +nsIAtom* nsDirectoryService::sCommon_Startmenu = nsnull; +nsIAtom* nsDirectoryService::sCommon_Programs = nsnull; +nsIAtom* nsDirectoryService::sCommon_Startup = nsnull; +nsIAtom* nsDirectoryService::sCommon_Desktopdirectory = nsnull; +nsIAtom* nsDirectoryService::sAppdata = nsnull; +nsIAtom* nsDirectoryService::sPrinthood = nsnull; +nsIAtom* nsDirectoryService::sWinCookiesDirectory = nsnull; +#elif defined (XP_UNIX) +nsIAtom* nsDirectoryService::sLocalDirectory = nsnull; +nsIAtom* nsDirectoryService::sLibDirectory = nsnull; +nsIAtom* nsDirectoryService::sHomeDirectory = nsnull; +#elif defined (XP_OS2) +nsIAtom* nsDirectoryService::sSystemDirectory = nsnull; +nsIAtom* nsDirectoryService::sOS2Directory = nsnull; +nsIAtom* nsDirectoryService::sHomeDirectory = nsnull; +nsIAtom* nsDirectoryService::sDesktopDirectory = nsnull; +#elif defined (XP_BEOS) +nsIAtom* nsDirectoryService::sSettingsDirectory = nsnull; +nsIAtom* nsDirectoryService::sHomeDirectory = nsnull; +nsIAtom* nsDirectoryService::sDesktopDirectory = nsnull; +nsIAtom* nsDirectoryService::sSystemDirectory = nsnull; +#endif + + +nsDirectoryService* nsDirectoryService::mService = nsnull; + +nsDirectoryService::nsDirectoryService() : + mHashtable(256, PR_TRUE) +{ +} + +NS_METHOD +nsDirectoryService::Create(nsISupports *outer, REFNSIID aIID, void **aResult) +{ + NS_ENSURE_ARG_POINTER(aResult); + if (!mService) + { + mService = new nsDirectoryService(); + if (!mService) + return NS_ERROR_OUT_OF_MEMORY; + } + return mService->QueryInterface(aIID, aResult); +} + +static const nsStaticAtom directory_atoms[] = { + { NS_XPCOM_CURRENT_PROCESS_DIR, &nsDirectoryService::sCurrentProcess }, + { NS_XPCOM_COMPONENT_REGISTRY_FILE, &nsDirectoryService::sComponentRegistry }, + { NS_XPCOM_COMPONENT_DIR, &nsDirectoryService::sComponentDirectory }, + { NS_XPCOM_XPTI_REGISTRY_FILE, &nsDirectoryService::sXPTIRegistry }, + { NS_GRE_DIR, &nsDirectoryService::sGRE_Directory }, + { NS_GRE_COMPONENT_DIR, &nsDirectoryService::sGRE_ComponentDirectory }, + { NS_OS_DRIVE_DIR, &nsDirectoryService::sOS_DriveDirectory }, + { NS_OS_TEMP_DIR, &nsDirectoryService::sOS_TemporaryDirectory }, + { NS_OS_CURRENT_PROCESS_DIR, &nsDirectoryService::sOS_CurrentProcessDirectory }, + { NS_OS_CURRENT_WORKING_DIR, &nsDirectoryService::sOS_CurrentWorkingDirectory }, + { NS_XPCOM_INIT_CURRENT_PROCESS_DIR, nsnull }, +#if defined (XP_MACOSX) + { NS_OS_SYSTEM_DIR, &nsDirectoryService::sDirectory }, + { NS_MAC_DESKTOP_DIR, &nsDirectoryService::sDesktopDirectory }, + { NS_MAC_TRASH_DIR, &nsDirectoryService::sTrashDirectory }, + { NS_MAC_STARTUP_DIR, &nsDirectoryService::sStartupDirectory }, + { NS_MAC_SHUTDOWN_DIR, &nsDirectoryService::sShutdownDirectory }, + { NS_MAC_APPLE_MENU_DIR, &nsDirectoryService::sAppleMenuDirectory }, + { NS_MAC_CONTROL_PANELS_DIR, &nsDirectoryService::sControlPanelDirectory }, + { NS_MAC_EXTENSIONS_DIR, &nsDirectoryService::sExtensionDirectory }, + { NS_MAC_FONTS_DIR, &nsDirectoryService::sFontsDirectory }, + { NS_MAC_PREFS_DIR, &nsDirectoryService::sPreferencesDirectory }, + { NS_MAC_DOCUMENTS_DIR, &nsDirectoryService::sDocumentsDirectory }, + { NS_MAC_INTERNET_SEARCH_DIR, &nsDirectoryService::sInternetSearchDirectory }, + { NS_MAC_USER_LIB_DIR, &nsDirectoryService::sUserLibDirectory }, + { NS_OSX_HOME_DIR, &nsDirectoryService::sHomeDirectory }, + { NS_OSX_DEFAULT_DOWNLOAD_DIR, &nsDirectoryService::sDefaultDownloadDirectory }, + { NS_OSX_USER_DESKTOP_DIR, &nsDirectoryService::sUserDesktopDirectory }, + { NS_OSX_LOCAL_DESKTOP_DIR, &nsDirectoryService::sLocalDesktopDirectory }, + { NS_OSX_USER_APPLICATIONS_DIR, &nsDirectoryService::sUserApplicationsDirectory }, + { NS_OSX_LOCAL_APPLICATIONS_DIR, &nsDirectoryService::sLocalApplicationsDirectory }, + { NS_OSX_USER_DOCUMENTS_DIR, &nsDirectoryService::sUserDocumentsDirectory }, + { NS_OSX_LOCAL_DOCUMENTS_DIR, &nsDirectoryService::sLocalDocumentsDirectory }, + { NS_OSX_USER_INTERNET_PLUGIN_DIR, &nsDirectoryService::sUserInternetPlugInDirectory }, + { NS_OSX_LOCAL_INTERNET_PLUGIN_DIR, &nsDirectoryService::sLocalInternetPlugInDirectory }, + { NS_OSX_USER_FRAMEWORKS_DIR, &nsDirectoryService::sUserFrameworksDirectory }, + { NS_OSX_LOCAL_FRAMEWORKS_DIR, &nsDirectoryService::sLocalFrameworksDirectory }, + { NS_OSX_USER_PREFERENCES_DIR, &nsDirectoryService::sUserPreferencesDirectory }, + { NS_OSX_LOCAL_PREFERENCES_DIR, &nsDirectoryService::sLocalPreferencesDirectory }, + { NS_OSX_PICTURE_DOCUMENTS_DIR, &nsDirectoryService::sPictureDocumentsDirectory }, + { NS_OSX_MOVIE_DOCUMENTS_DIR, &nsDirectoryService::sMovieDocumentsDirectory }, + { NS_OSX_MUSIC_DOCUMENTS_DIR, &nsDirectoryService::sMusicDocumentsDirectory }, + { NS_OSX_INTERNET_SITES_DIR, &nsDirectoryService::sInternetSitesDirectory }, +#elif defined (XP_WIN) + { NS_OS_SYSTEM_DIR, &nsDirectoryService::sSystemDirectory }, + { NS_WIN_WINDOWS_DIR, &nsDirectoryService::sWindowsDirectory }, + { NS_WIN_HOME_DIR, &nsDirectoryService::sHomeDirectory }, + { NS_WIN_DESKTOP_DIR, &nsDirectoryService::sDesktop }, + { NS_WIN_PROGRAMS_DIR, &nsDirectoryService::sPrograms }, + { NS_WIN_CONTROLS_DIR, &nsDirectoryService::sControls }, + { NS_WIN_PRINTERS_DIR, &nsDirectoryService::sPrinters }, + { NS_WIN_PERSONAL_DIR, &nsDirectoryService::sPersonal }, + { NS_WIN_FAVORITES_DIR, &nsDirectoryService::sFavorites }, + { NS_WIN_STARTUP_DIR, &nsDirectoryService::sStartup }, + { NS_WIN_RECENT_DIR, &nsDirectoryService::sRecent }, + { NS_WIN_SEND_TO_DIR, &nsDirectoryService::sSendto }, + { NS_WIN_BITBUCKET_DIR, &nsDirectoryService::sBitbucket }, + { NS_WIN_STARTMENU_DIR, &nsDirectoryService::sStartmenu }, + { NS_WIN_DESKTOP_DIRECTORY, &nsDirectoryService::sDesktopdirectory }, + { NS_WIN_DRIVES_DIR, &nsDirectoryService::sDrives }, + { NS_WIN_NETWORK_DIR, &nsDirectoryService::sNetwork }, + { NS_WIN_NETHOOD_DIR, &nsDirectoryService::sNethood }, + { NS_WIN_FONTS_DIR, &nsDirectoryService::sFonts }, + { NS_WIN_TEMPLATES_DIR, &nsDirectoryService::sTemplates }, + { NS_WIN_COMMON_STARTMENU_DIR, &nsDirectoryService::sCommon_Startmenu }, + { NS_WIN_COMMON_PROGRAMS_DIR, &nsDirectoryService::sCommon_Programs }, + { NS_WIN_COMMON_STARTUP_DIR, &nsDirectoryService::sCommon_Startup }, + { NS_WIN_COMMON_DESKTOP_DIRECTORY, &nsDirectoryService::sCommon_Desktopdirectory }, + { NS_WIN_APPDATA_DIR, &nsDirectoryService::sAppdata }, + { NS_WIN_PRINTHOOD, &nsDirectoryService::sPrinthood }, + { NS_WIN_COOKIES_DIR, &nsDirectoryService::sWinCookiesDirectory }, +#elif defined (XP_UNIX) + { NS_UNIX_LOCAL_DIR, &nsDirectoryService::sLocalDirectory }, + { NS_UNIX_LIB_DIR, &nsDirectoryService::sLibDirectory }, + { NS_UNIX_HOME_DIR, &nsDirectoryService::sHomeDirectory }, +#elif defined (XP_OS2) + { NS_OS_SYSTEM_DIR, &nsDirectoryService::sSystemDirectory }, + { NS_OS2_DIR, &nsDirectoryService::sOS2Directory }, + { NS_OS2_HOME_DIR, &nsDirectoryService::sHomeDirectory }, + { NS_OS2_DESKTOP_DIR, &nsDirectoryService::sDesktopDirectory }, +#elif defined (XP_BEOS) + { NS_OS_SYSTEM_DIR, &nsDirectoryService::sSystemDirectory }, + { NS_BEOS_SETTINGS_DIR, &nsDirectoryService::sSettingsDirectory }, + { NS_BEOS_HOME_DIR, &nsDirectoryService::sHomeDirectory }, + { NS_BEOS_DESKTOP_DIR, &nsDirectoryService::sDesktopDirectory }, +#endif +}; + +nsresult +nsDirectoryService::Init() +{ + nsresult rv; + + rv = NS_NewISupportsArray(getter_AddRefs(mProviders)); + if (NS_FAILED(rv)) return rv; + + NS_RegisterStaticAtoms(directory_atoms, NS_ARRAY_LENGTH(directory_atoms)); + + // Let the list hold the only reference to the provider. + nsAppFileLocationProvider *defaultProvider = new nsAppFileLocationProvider; + if (!defaultProvider) + return NS_ERROR_OUT_OF_MEMORY; + // AppendElement returns PR_TRUE for success. + rv = mProviders->AppendElement(defaultProvider) ? NS_OK : NS_ERROR_FAILURE; + + return rv; +} + +PRBool +nsDirectoryService::ReleaseValues(nsHashKey* key, void* data, void* closure) +{ + nsISupports* value = (nsISupports*)data; + NS_IF_RELEASE(value); + return PR_TRUE; +} + +nsDirectoryService::~nsDirectoryService() +{ + // clear the global + mService = nsnull; + +} + +NS_IMPL_THREADSAFE_ISUPPORTS4(nsDirectoryService, nsIProperties, nsIDirectoryService, nsIDirectoryServiceProvider, nsIDirectoryServiceProvider2) + + +NS_IMETHODIMP +nsDirectoryService::Undefine(const char* prop) +{ + nsCStringKey key(prop); + if (!mHashtable.Exists(&key)) + return NS_ERROR_FAILURE; + + mHashtable.Remove (&key); + return NS_OK; + } + +NS_IMETHODIMP +nsDirectoryService::GetKeys(PRUint32 *count, char ***keys) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +struct FileData +{ + FileData(const char* aProperty, + const nsIID& aUUID) : + property(aProperty), + data(nsnull), + persistent(PR_TRUE), + uuid(aUUID) {} + + const char* property; + nsISupports* data; + PRBool persistent; + const nsIID& uuid; +}; + +static PRBool FindProviderFile(nsISupports* aElement, void *aData) +{ + nsresult rv; + FileData* fileData = (FileData*)aData; + if (fileData->uuid.Equals(NS_GET_IID(nsISimpleEnumerator))) + { + // Not all providers implement this iface + nsCOMPtr prov2 = do_QueryInterface(aElement); + if (prov2) + { + rv = prov2->GetFiles(fileData->property, (nsISimpleEnumerator **)&fileData->data); + if (NS_SUCCEEDED(rv) && fileData->data) { + fileData->persistent = PR_FALSE; // Enumerators can never be peristent + return PR_FALSE; + } + } + } + else + { + nsCOMPtr prov = do_QueryInterface(aElement); + if (!prov) + return PR_FALSE; + rv = prov->GetFile(fileData->property, &fileData->persistent, (nsIFile **)&fileData->data); + if (NS_SUCCEEDED(rv) && fileData->data) + return PR_FALSE; + } + + return PR_TRUE; +} + +NS_IMETHODIMP +nsDirectoryService::Get(const char* prop, const nsIID & uuid, void* *result) +{ + nsCStringKey key(prop); + + nsCOMPtr value = dont_AddRef(mHashtable.Get(&key)); + + if (value) + { + nsCOMPtr cloneFile; + nsCOMPtr cachedFile = do_QueryInterface(value); + NS_ASSERTION(cachedFile, "nsIFile expected"); + + cachedFile->Clone(getter_AddRefs(cloneFile)); + return cloneFile->QueryInterface(uuid, result); + } + + // it is not one of our defaults, lets check any providers + FileData fileData(prop, uuid); + + mProviders->EnumerateBackwards(FindProviderFile, &fileData); + if (fileData.data) + { + if (fileData.persistent) + { + Set(prop, NS_STATIC_CAST(nsIFile*, fileData.data)); + } + nsresult rv = (fileData.data)->QueryInterface(uuid, result); + NS_RELEASE(fileData.data); // addref occurs in FindProviderFile() + return rv; + } + + FindProviderFile(NS_STATIC_CAST(nsIDirectoryServiceProvider*, this), &fileData); + if (fileData.data) + { + if (fileData.persistent) + { + Set(prop, NS_STATIC_CAST(nsIFile*, fileData.data)); + } + nsresult rv = (fileData.data)->QueryInterface(uuid, result); + NS_RELEASE(fileData.data); // addref occurs in FindProviderFile() + return rv; + } + + return NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +nsDirectoryService::Set(const char* prop, nsISupports* value) +{ + nsCStringKey key(prop); + if (mHashtable.Exists(&key) || value == nsnull) + return NS_ERROR_FAILURE; + + nsCOMPtr ourFile; + value->QueryInterface(NS_GET_IID(nsIFile), getter_AddRefs(ourFile)); + if (ourFile) + { + nsCOMPtr cloneFile; + ourFile->Clone (getter_AddRefs (cloneFile)); + mHashtable.Put(&key, cloneFile); + + return NS_OK; + } + + return NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +nsDirectoryService::Has(const char *prop, PRBool *_retval) +{ + *_retval = PR_FALSE; + nsCOMPtr value; + nsresult rv = Get(prop, NS_GET_IID(nsIFile), getter_AddRefs(value)); + if (NS_FAILED(rv)) + return rv; + + if (value) + { + *_retval = PR_TRUE; + } + + return rv; +} + +NS_IMETHODIMP +nsDirectoryService::RegisterProvider(nsIDirectoryServiceProvider *prov) +{ + nsresult rv; + if (!prov) + return NS_ERROR_FAILURE; + if (!mProviders) + return NS_ERROR_NOT_INITIALIZED; + + nsCOMPtr supports = do_QueryInterface(prov, &rv); + if (NS_FAILED(rv)) return rv; + + // AppendElement returns PR_TRUE for success. + return mProviders->AppendElement(supports) ? NS_OK : NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +nsDirectoryService::UnregisterProvider(nsIDirectoryServiceProvider *prov) +{ + nsresult rv; + if (!prov) + return NS_ERROR_FAILURE; + if (!mProviders) + return NS_ERROR_NOT_INITIALIZED; + + nsCOMPtr supports = do_QueryInterface(prov, &rv); + if (NS_FAILED(rv)) return rv; + + // RemoveElement returns PR_TRUE for success. + return mProviders->RemoveElement(supports) ? NS_OK : NS_ERROR_FAILURE; +} + +// DO NOT ADD ANY LOCATIONS TO THIS FUNCTION UNTIL YOU TALK TO: dougt@netscape.com. +// This is meant to be a place of xpcom or system specific file locations, not +// application specific locations. If you need the later, register a callback for +// your application. + +NS_IMETHODIMP +nsDirectoryService::GetFile(const char *prop, PRBool *persistent, nsIFile **_retval) +{ + nsCOMPtr localFile; + nsresult rv = NS_ERROR_FAILURE; + + *_retval = nsnull; + *persistent = PR_TRUE; + + nsIAtom* inAtom = NS_NewAtom(prop); + + // check to see if it is one of our defaults + + if (inAtom == nsDirectoryService::sCurrentProcess || + inAtom == nsDirectoryService::sOS_CurrentProcessDirectory ) + { + rv = GetCurrentProcessDirectory(getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sComponentRegistry) + { + rv = GetCurrentProcessDirectory(getter_AddRefs(localFile)); + if (!localFile) + return NS_ERROR_FAILURE; + + localFile->AppendNative(COMPONENT_DIRECTORY); + localFile->AppendNative(COMPONENT_REGISTRY_NAME); + } + else if (inAtom == nsDirectoryService::sXPTIRegistry) + { + rv = GetCurrentProcessDirectory(getter_AddRefs(localFile)); + if (!localFile) + return NS_ERROR_FAILURE; + + localFile->AppendNative(COMPONENT_DIRECTORY); + localFile->AppendNative(XPTI_REGISTRY_NAME); + } + + // Unless otherwise set, the core pieces of the GRE exist + // in the current process directory. + else if (inAtom == nsDirectoryService::sGRE_Directory) + { + rv = GetCurrentProcessDirectory(getter_AddRefs(localFile)); + } + // the GRE components directory is relative to the GRE directory + // by default; applications may override this behavior in special + // cases + else if (inAtom == nsDirectoryService::sGRE_ComponentDirectory) + { + rv = Get(NS_GRE_DIR, nsILocalFile::GetIID(), getter_AddRefs(localFile)); + if (localFile) + localFile->AppendNative(COMPONENT_DIRECTORY); + } + else if (inAtom == nsDirectoryService::sComponentDirectory) + { + rv = GetCurrentProcessDirectory(getter_AddRefs(localFile)); + if (localFile) + localFile->AppendNative(COMPONENT_DIRECTORY); + } + else if (inAtom == nsDirectoryService::sOS_DriveDirectory) + { + rv = GetSpecialSystemDirectory(OS_DriveDirectory, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sOS_TemporaryDirectory) + { + rv = GetSpecialSystemDirectory(OS_TemporaryDirectory, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sOS_CurrentProcessDirectory) + { + rv = GetSpecialSystemDirectory(OS_CurrentProcessDirectory, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sOS_CurrentWorkingDirectory) + { + rv = GetSpecialSystemDirectory(OS_CurrentWorkingDirectory, getter_AddRefs(localFile)); + } + +#if defined(XP_MACOSX) + else if (inAtom == nsDirectoryService::sDirectory) + { + rv = GetOSXFolderType(kClassicDomain, kSystemFolderType, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sDesktopDirectory) + { + rv = GetOSXFolderType(kClassicDomain, kDesktopFolderType, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sTrashDirectory) + { + rv = GetOSXFolderType(kClassicDomain, kTrashFolderType, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sStartupDirectory) + { + rv = GetOSXFolderType(kClassicDomain, kStartupFolderType, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sShutdownDirectory) + { + rv = GetOSXFolderType(kClassicDomain, kShutdownFolderType, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sAppleMenuDirectory) + { + rv = GetOSXFolderType(kClassicDomain, kAppleMenuFolderType, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sControlPanelDirectory) + { + rv = GetOSXFolderType(kClassicDomain, kControlPanelFolderType, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sExtensionDirectory) + { + rv = GetOSXFolderType(kClassicDomain, kExtensionFolderType, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sFontsDirectory) + { + rv = GetOSXFolderType(kClassicDomain, kFontsFolderType, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sPreferencesDirectory) + { + rv = GetOSXFolderType(kClassicDomain, kPreferencesFolderType, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sDocumentsDirectory) + { + rv = GetOSXFolderType(kClassicDomain, kDocumentsFolderType, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sInternetSearchDirectory) + { + rv = GetOSXFolderType(kClassicDomain, kInternetSearchSitesFolderType, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sUserLibDirectory) + { + rv = GetOSXFolderType(kUserDomain, kDomainLibraryFolderType, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sHomeDirectory) + { + rv = GetOSXFolderType(kUserDomain, kDomainTopLevelFolderType, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sDefaultDownloadDirectory) + { + NS_NewLocalFile(EmptyString(), PR_TRUE, getter_AddRefs(localFile)); + nsCOMPtr localMacFile(do_QueryInterface(localFile)); + + if (localMacFile) + { + OSErr err; + ICInstance icInstance; + + err = ::ICStart(&icInstance, 'XPCM'); + if (err == noErr) + { + ICAttr attrs; + ICFileSpec icFileSpec; + long size = kICFileSpecHeaderSize; + err = ::ICGetPref(icInstance, kICDownloadFolder, &attrs, &icFileSpec, &size); + if (err == noErr || (err == icTruncatedErr && size >= kICFileSpecHeaderSize)) + { + rv = localMacFile->InitWithFSSpec(&icFileSpec.fss); + } + ::ICStop(icInstance); + } + + if (NS_FAILED(rv)) + { + // We got an error getting the DL folder from IC so try finding the user's Desktop folder + rv = GetOSXFolderType(kUserDomain, kDesktopFolderType, getter_AddRefs(localFile)); + } + } + + // Don't cache the DL directory as the user may change it while we're running. + // Negligible perf hit as this directory is only requested for downloads + *persistent = PR_FALSE; + } + else if (inAtom == nsDirectoryService::sUserDesktopDirectory) + { + rv = GetOSXFolderType(kUserDomain, kDesktopFolderType, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sLocalDesktopDirectory) + { + rv = GetOSXFolderType(kLocalDomain, kDesktopFolderType, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sUserApplicationsDirectory) + { + rv = GetOSXFolderType(kUserDomain, kApplicationsFolderType, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sLocalApplicationsDirectory) + { + rv = GetOSXFolderType(kLocalDomain, kApplicationsFolderType, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sUserDocumentsDirectory) + { + rv = GetOSXFolderType(kUserDomain, kDocumentsFolderType, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sLocalDocumentsDirectory) + { + rv = GetOSXFolderType(kLocalDomain, kDocumentsFolderType, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sUserInternetPlugInDirectory) + { + rv = GetOSXFolderType(kUserDomain, kInternetPlugInFolderType, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sLocalInternetPlugInDirectory) + { + rv = GetOSXFolderType(kLocalDomain, kInternetPlugInFolderType, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sUserFrameworksDirectory) + { + rv = GetOSXFolderType(kUserDomain, kFrameworksFolderType, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sLocalFrameworksDirectory) + { + rv = GetOSXFolderType(kLocalDomain, kFrameworksFolderType, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sUserPreferencesDirectory) + { + rv = GetOSXFolderType(kUserDomain, kPreferencesFolderType, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sLocalPreferencesDirectory) + { + rv = GetOSXFolderType(kLocalDomain, kPreferencesFolderType, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sPictureDocumentsDirectory) + { + rv = GetOSXFolderType(kUserDomain, kPictureDocumentsFolderType, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sMovieDocumentsDirectory) + { + rv = GetOSXFolderType(kUserDomain, kMovieDocumentsFolderType, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sMusicDocumentsDirectory) + { + rv = GetOSXFolderType(kUserDomain, kMusicDocumentsFolderType, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sInternetSitesDirectory) + { + rv = GetOSXFolderType(kUserDomain, kInternetSitesFolderType, getter_AddRefs(localFile)); + } +#elif defined (XP_WIN) + else if (inAtom == nsDirectoryService::sSystemDirectory) + { + rv = GetSpecialSystemDirectory(Win_SystemDirectory, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sWindowsDirectory) + { + rv = GetSpecialSystemDirectory(Win_WindowsDirectory, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sHomeDirectory) + { + rv = GetSpecialSystemDirectory(Win_HomeDirectory, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sDesktop) + { + rv = GetSpecialSystemDirectory(Win_Desktop, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sPrograms) + { + rv = GetSpecialSystemDirectory(Win_Programs, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sControls) + { + rv = GetSpecialSystemDirectory(Win_Controls, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sPrinters) + { + rv = GetSpecialSystemDirectory(Win_Printers, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sPersonal) + { + rv = GetSpecialSystemDirectory(Win_Personal, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sFavorites) + { + rv = GetSpecialSystemDirectory(Win_Favorites, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sStartup) + { + rv = GetSpecialSystemDirectory(Win_Startup, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sRecent) + { + rv = GetSpecialSystemDirectory(Win_Recent, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sSendto) + { + rv = GetSpecialSystemDirectory(Win_Sendto, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sBitbucket) + { + rv = GetSpecialSystemDirectory(Win_Bitbucket, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sStartmenu) + { + rv = GetSpecialSystemDirectory(Win_Startmenu, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sDesktopdirectory) + { + rv = GetSpecialSystemDirectory(Win_Desktopdirectory, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sDrives) + { + rv = GetSpecialSystemDirectory(Win_Drives, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sNetwork) + { + rv = GetSpecialSystemDirectory(Win_Network, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sNethood) + { + rv = GetSpecialSystemDirectory(Win_Nethood, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sFonts) + { + rv = GetSpecialSystemDirectory(Win_Fonts, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sTemplates) + { + rv = GetSpecialSystemDirectory(Win_Templates, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sCommon_Startmenu) + { + rv = GetSpecialSystemDirectory(Win_Common_Startmenu, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sCommon_Programs) + { + rv = GetSpecialSystemDirectory(Win_Common_Programs, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sCommon_Startup) + { + rv = GetSpecialSystemDirectory(Win_Common_Startup, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sCommon_Desktopdirectory) + { + rv = GetSpecialSystemDirectory(Win_Common_Desktopdirectory, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sAppdata) + { + rv = GetSpecialSystemDirectory(Win_Appdata, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sPrinthood) + { + rv = GetSpecialSystemDirectory(Win_Printhood, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sWinCookiesDirectory) + { + rv = GetSpecialSystemDirectory(Win_Cookies, getter_AddRefs(localFile)); + } +#elif defined (XP_UNIX) + + else if (inAtom == nsDirectoryService::sLocalDirectory) + { + rv = GetSpecialSystemDirectory(Unix_LocalDirectory, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sLibDirectory) + { + rv = GetSpecialSystemDirectory(Unix_LibDirectory, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sHomeDirectory) + { + rv = GetSpecialSystemDirectory(Unix_HomeDirectory, getter_AddRefs(localFile)); + } +#elif defined (XP_OS2) + else if (inAtom == nsDirectoryService::sSystemDirectory) + { + rv = GetSpecialSystemDirectory(OS2_SystemDirectory, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sOS2Directory) + { + rv = GetSpecialSystemDirectory(OS2_OS2Directory, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sHomeDirectory) + { + rv = GetSpecialSystemDirectory(OS2_HomeDirectory, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sDesktopDirectory) + { + rv = GetSpecialSystemDirectory(OS2_DesktopDirectory, getter_AddRefs(localFile)); + } +#elif defined (XP_BEOS) + else if (inAtom == nsDirectoryService::sSettingsDirectory) + { + rv = GetSpecialSystemDirectory(BeOS_SettingsDirectory, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sHomeDirectory) + { + rv = GetSpecialSystemDirectory(BeOS_HomeDirectory, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sDesktopDirectory) + { + rv = GetSpecialSystemDirectory(BeOS_DesktopDirectory, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sSystemDirectory) + { + rv = GetSpecialSystemDirectory(BeOS_SystemDirectory, getter_AddRefs(localFile)); + } +#endif + + + NS_RELEASE(inAtom); + + if (localFile && NS_SUCCEEDED(rv)) + return localFile->QueryInterface(NS_GET_IID(nsIFile), (void**)_retval); +#ifdef DEBUG_dougt + printf("Failed to find directory for key: %s\n", prop); +#endif + return rv; +} + +NS_IMETHODIMP +nsDirectoryService::GetFiles(const char *prop, nsISimpleEnumerator **_retval) +{ + NS_ENSURE_ARG_POINTER(_retval); + *_retval = nsnull; + + return NS_ERROR_FAILURE; +} diff --git a/src/libs/xpcom18a4/xpcom/io/nsDirectoryService.h b/src/libs/xpcom18a4/xpcom/io/nsDirectoryService.h new file mode 100644 index 00000000..67e6e371 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsDirectoryService.h @@ -0,0 +1,177 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * IBM Corp. + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +#ifndef nsDirectoryService_h___ +#define nsDirectoryService_h___ + +#include "nsIDirectoryService.h" +#include "nsHashtable.h" +#include "nsILocalFile.h" +#include "nsISupportsArray.h" +#include "nsIAtom.h" + +#define NS_XPCOM_INIT_CURRENT_PROCESS_DIR "MozBinD" // Can be used to set NS_XPCOM_CURRENT_PROCESS_DIR + // CANNOT be used to GET a location + +class nsDirectoryService : public nsIDirectoryService, + public nsIProperties, + public nsIDirectoryServiceProvider2 +{ + public: + + NS_DEFINE_STATIC_CID_ACCESSOR(NS_DIRECTORY_SERVICE_CID); + + // nsISupports interface + NS_DECL_ISUPPORTS + + NS_DECL_NSIPROPERTIES + + NS_DECL_NSIDIRECTORYSERVICE + + NS_DECL_NSIDIRECTORYSERVICEPROVIDER + + NS_DECL_NSIDIRECTORYSERVICEPROVIDER2 + + nsDirectoryService(); + + static NS_METHOD + Create(nsISupports *aOuter, REFNSIID aIID, void **aResult); + +private: + ~nsDirectoryService(); + + nsresult GetCurrentProcessDirectory(nsILocalFile** aFile); + + static nsDirectoryService* mService; + static PRBool PR_CALLBACK ReleaseValues(nsHashKey* key, void* data, void* closure); + nsSupportsHashtable mHashtable; + nsCOMPtr mProviders; + +public: + static nsIAtom *sCurrentProcess; + static nsIAtom *sComponentRegistry; + static nsIAtom *sComponentDirectory; + static nsIAtom *sXPTIRegistry; + static nsIAtom *sGRE_Directory; + static nsIAtom *sGRE_ComponentDirectory; + static nsIAtom *sOS_DriveDirectory; + static nsIAtom *sOS_TemporaryDirectory; + static nsIAtom *sOS_CurrentProcessDirectory; + static nsIAtom *sOS_CurrentWorkingDirectory; +#if defined (XP_MACOSX) + static nsIAtom *sDirectory; + static nsIAtom *sDesktopDirectory; + static nsIAtom *sTrashDirectory; + static nsIAtom *sStartupDirectory; + static nsIAtom *sShutdownDirectory; + static nsIAtom *sAppleMenuDirectory; + static nsIAtom *sControlPanelDirectory; + static nsIAtom *sExtensionDirectory; + static nsIAtom *sFontsDirectory; + static nsIAtom *sPreferencesDirectory; + static nsIAtom *sDocumentsDirectory; + static nsIAtom *sInternetSearchDirectory; + static nsIAtom *sUserLibDirectory; + static nsIAtom *sHomeDirectory; + static nsIAtom *sDefaultDownloadDirectory; + static nsIAtom *sUserDesktopDirectory; + static nsIAtom *sLocalDesktopDirectory; + static nsIAtom *sUserApplicationsDirectory; + static nsIAtom *sLocalApplicationsDirectory; + static nsIAtom *sUserDocumentsDirectory; + static nsIAtom *sLocalDocumentsDirectory; + static nsIAtom *sUserInternetPlugInDirectory; + static nsIAtom *sLocalInternetPlugInDirectory; + static nsIAtom *sUserFrameworksDirectory; + static nsIAtom *sLocalFrameworksDirectory; + static nsIAtom *sUserPreferencesDirectory; + static nsIAtom *sLocalPreferencesDirectory; + static nsIAtom *sPictureDocumentsDirectory; + static nsIAtom *sMovieDocumentsDirectory; + static nsIAtom *sMusicDocumentsDirectory; + static nsIAtom *sInternetSitesDirectory; +#elif defined (XP_WIN) + static nsIAtom *sSystemDirectory; + static nsIAtom *sWindowsDirectory; + static nsIAtom *sHomeDirectory; + static nsIAtom *sDesktop; + static nsIAtom *sPrograms; + static nsIAtom *sControls; + static nsIAtom *sPrinters; + static nsIAtom *sPersonal; + static nsIAtom *sFavorites; + static nsIAtom *sStartup; + static nsIAtom *sRecent; + static nsIAtom *sSendto; + static nsIAtom *sBitbucket; + static nsIAtom *sStartmenu; + static nsIAtom *sDesktopdirectory; + static nsIAtom *sDrives; + static nsIAtom *sNetwork; + static nsIAtom *sNethood; + static nsIAtom *sFonts; + static nsIAtom *sTemplates; + static nsIAtom *sCommon_Startmenu; + static nsIAtom *sCommon_Programs; + static nsIAtom *sCommon_Startup; + static nsIAtom *sCommon_Desktopdirectory; + static nsIAtom *sAppdata; + static nsIAtom *sPrinthood; + static nsIAtom *sWinCookiesDirectory; +#elif defined (XP_UNIX) + static nsIAtom *sLocalDirectory; + static nsIAtom *sLibDirectory; + static nsIAtom *sHomeDirectory; +#elif defined (XP_OS2) + static nsIAtom *sSystemDirectory; + static nsIAtom *sOS2Directory; + static nsIAtom *sHomeDirectory; + static nsIAtom *sDesktopDirectory; +#elif defined (XP_BEOS) + static nsIAtom *sSettingsDirectory; + static nsIAtom *sHomeDirectory; + static nsIAtom *sDesktopDirectory; + static nsIAtom *sSystemDirectory; +#endif + + +}; + + +#endif + diff --git a/src/libs/xpcom18a4/xpcom/io/nsDirectoryServiceDefs.h b/src/libs/xpcom18a4/xpcom/io/nsDirectoryServiceDefs.h new file mode 100644 index 00000000..6b3c8ba4 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsDirectoryServiceDefs.h @@ -0,0 +1,197 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Conrad Carlen conrad@ingress.com + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/** + * Defines the property names for directories available from + * nsIDirectoryService. These dirs are always available even if no + * nsIDirectoryServiceProviders have been registered with the service. + * Application level keys are defined in nsAppDirectoryServiceDefs.h. + * + * Keys whose definition ends in "DIR" or "FILE" return a single nsIFile (or + * subclass). Keys whose definition ends in "LIST" return an nsISimpleEnumerator + * which enumerates a list of file objects. + * + * Defines listed in this file are FROZEN. This list may grow. + */ + +#ifndef nsDirectoryServiceDefs_h___ +#define nsDirectoryServiceDefs_h___ + +/* General OS specific locations */ + +#define NS_OS_HOME_DIR "Home" +#define NS_OS_TEMP_DIR "TmpD" +#define NS_OS_CURRENT_WORKING_DIR "CurWorkD" + +/* Property returns the directory in which the procces was started from. + * On Unix this will be the path in the VBOX_XPCOM_HOME env var and if + * unset will be the current working directory. + */ +#define NS_OS_CURRENT_PROCESS_DIR "CurProcD" + +/* This location is similar to NS_OS_CURRENT_PROCESS_DIR, however, + * NS_XPCOM_CURRENT_PROCESS_DIR can be overriden by passing a "bin + * directory" to NS_InitXPCOM2(). + */ +#define NS_XPCOM_CURRENT_PROCESS_DIR "XCurProcD" + +/* Property will return the location of the application components + * directory. By default, this directory will be contained in the + * NS_XPCOM_CURRENT_PROCESS_DIR. + */ +#define NS_XPCOM_COMPONENT_DIR "ComsD" + +/* Property will return a list of components directories that will + * will be registered after the application components directory. + */ +#define NS_XPCOM_COMPONENT_DIR_LIST "ComsDL" + +/* Property will return the location of the application components + * registry file. + */ +#define NS_XPCOM_COMPONENT_REGISTRY_FILE "ComRegF" + +/* Property will return the location of the application XPTI + * registry file. + */ +#define NS_XPCOM_XPTI_REGISTRY_FILE "XptiRegF" + +/* Property will return the location of the the XPCOM Shared Library. + */ +#define NS_XPCOM_LIBRARY_FILE "XpcomLib" + +/* Property will return the current location of the the GRE directory. + * If no GRE is used, this propery will behave like + * NS_XPCOM_CURRENT_PROCESS_DIR. + */ +#define NS_GRE_DIR "GreD" + +/* Property will return the current location of the the GRE component + * directory. If no GRE is used, this propery will behave like + * NS_XPCOM_COMPONENT_DIR. + */ +#define NS_GRE_COMPONENT_DIR "GreComsD" + + +/* Platform Specific Locations */ + +#if !defined (XP_UNIX) || defined(XP_MACOSX) + #define NS_OS_SYSTEM_DIR "SysD" +#endif + +#if defined (XP_MACOSX) + #define NS_MAC_DESKTOP_DIR "Desk" + #define NS_MAC_TRASH_DIR "Trsh" + #define NS_MAC_STARTUP_DIR "Strt" + #define NS_MAC_SHUTDOWN_DIR "Shdwn" + #define NS_MAC_APPLE_MENU_DIR "ApplMenu" + #define NS_MAC_CONTROL_PANELS_DIR "CntlPnl" + #define NS_MAC_EXTENSIONS_DIR "Exts" + #define NS_MAC_FONTS_DIR "Fnts" + #define NS_MAC_PREFS_DIR "Prfs" + #define NS_MAC_DOCUMENTS_DIR "Docs" + #define NS_MAC_INTERNET_SEARCH_DIR "ISrch" + #define NS_OSX_HOME_DIR "Home" + #define NS_MAC_HOME_DIR NS_OSX_HOME_DIR + #define NS_MAC_DEFAULT_DOWNLOAD_DIR "DfltDwnld" + #define NS_MAC_USER_LIB_DIR "ULibDir" // Only available under OS X + #define NS_OSX_DEFAULT_DOWNLOAD_DIR NS_MAC_DEFAULT_DOWNLOAD_DIR + #define NS_OSX_USER_DESKTOP_DIR "UsrDsk" + #define NS_OSX_LOCAL_DESKTOP_DIR "LocDsk" + #define NS_OSX_USER_APPLICATIONS_DIR "UsrApp" + #define NS_OSX_LOCAL_APPLICATIONS_DIR "LocApp" + #define NS_OSX_USER_DOCUMENTS_DIR "UsrDocs" + #define NS_OSX_LOCAL_DOCUMENTS_DIR "LocDocs" + #define NS_OSX_USER_INTERNET_PLUGIN_DIR "UsrIntrntPlgn" + #define NS_OSX_LOCAL_INTERNET_PLUGIN_DIR "LoclIntrntPlgn" + #define NS_OSX_USER_FRAMEWORKS_DIR "UsrFrmwrks" + #define NS_OSX_LOCAL_FRAMEWORKS_DIR "LocFrmwrks" + #define NS_OSX_USER_PREFERENCES_DIR "UsrPrfs" + #define NS_OSX_LOCAL_PREFERENCES_DIR "LocPrfs" + #define NS_OSX_PICTURE_DOCUMENTS_DIR "Pct" + #define NS_OSX_MOVIE_DOCUMENTS_DIR "Mov" + #define NS_OSX_MUSIC_DOCUMENTS_DIR "Music" + #define NS_OSX_INTERNET_SITES_DIR "IntrntSts" +#elif defined (XP_WIN) + #define NS_WIN_WINDOWS_DIR "WinD" + #define NS_WIN_HOME_DIR "Home" + #define NS_WIN_DESKTOP_DIR "DeskV" // virtual folder at the root of the namespace + #define NS_WIN_PROGRAMS_DIR "Progs" + #define NS_WIN_CONTROLS_DIR "Cntls" + #define NS_WIN_PRINTERS_DIR "Prnts" + #define NS_WIN_PERSONAL_DIR "Pers" + #define NS_WIN_FAVORITES_DIR "Favs" + #define NS_WIN_STARTUP_DIR "Strt" + #define NS_WIN_RECENT_DIR "Rcnt" + #define NS_WIN_SEND_TO_DIR "SndTo" + #define NS_WIN_BITBUCKET_DIR "Buckt" + #define NS_WIN_STARTMENU_DIR "Strt" + #define NS_WIN_DESKTOP_DIRECTORY "DeskP" // file sys dir which physically stores objects on desktop + #define NS_WIN_DRIVES_DIR "Drivs" + #define NS_WIN_NETWORK_DIR "NetW" + #define NS_WIN_NETHOOD_DIR "netH" + #define NS_WIN_FONTS_DIR "Fnts" + #define NS_WIN_TEMPLATES_DIR "Tmpls" + #define NS_WIN_COMMON_STARTMENU_DIR "CmStrt" + #define NS_WIN_COMMON_PROGRAMS_DIR "CmPrgs" + #define NS_WIN_COMMON_STARTUP_DIR "CmStrt" + #define NS_WIN_COMMON_DESKTOP_DIRECTORY "CmDeskP" + #define NS_WIN_APPDATA_DIR "AppData" + #define NS_WIN_PRINTHOOD "PrntHd" + #define NS_WIN_COOKIES_DIR "CookD" +#elif defined (XP_UNIX) + #define NS_UNIX_LOCAL_DIR "Locl" + #define NS_UNIX_LIB_DIR "LibD" + #define NS_UNIX_HOME_DIR "Home" +#elif defined (XP_OS2) + #define NS_OS2_DIR "OS2Dir" + #define NS_OS2_HOME_DIR "Home" + #define NS_OS2_DESKTOP_DIR "Desk" +#elif defined (XP_BEOS) + #define NS_BEOS_SETTINGS_DIR "Setngs" + #define NS_BEOS_HOME_DIR "Home" + #define NS_BEOS_DESKTOP_DIR "Desk" +#endif + +/* Deprecated */ + +#define NS_OS_DRIVE_DIR "DrvD" + + + +#endif diff --git a/src/libs/xpcom18a4/xpcom/io/nsDirectoryServiceUtils.h b/src/libs/xpcom18a4/xpcom/io/nsDirectoryServiceUtils.h new file mode 100644 index 00000000..f2482c76 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsDirectoryServiceUtils.h @@ -0,0 +1,61 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +#ifndef nsDirectoryServiceUtils_h___ +#define nsDirectoryServiceUtils_h___ + +#include "nsIServiceManager.h" +#include "nsIProperties.h" +#include "nsCOMPtr.h" + +#define NS_DIRECTORY_SERVICE_CID {0xf00152d0,0xb40b,0x11d3,{0x8c, 0x9c, 0x00, 0x00, 0x64, 0x65, 0x73, 0x74}} + +inline nsresult +NS_GetSpecialDirectory(const char* specialDirName, nsIFile* *result) +{ + nsresult rv; + static NS_DEFINE_CID(kDirectoryServiceCID, NS_DIRECTORY_SERVICE_CID); + nsCOMPtr serv(do_GetService(kDirectoryServiceCID, &rv)); + if (NS_FAILED(rv)) + return rv; + + return serv->Get(specialDirName, NS_GET_IID(nsIFile), + NS_REINTERPRET_CAST(void**, result)); +} + +#endif diff --git a/src/libs/xpcom18a4/xpcom/io/nsEscape.cpp b/src/libs/xpcom18a4/xpcom/io/nsEscape.cpp new file mode 100644 index 00000000..758339e4 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsEscape.cpp @@ -0,0 +1,491 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +// First checked in on 98/12/03 by John R. McMullen, derived from net.h/mkparse.c. + +#include "nsEscape.h" +#include "nsMemory.h" +#include "nsCRT.h" +#include "nsReadableUtils.h" + +const int netCharType[256] = +/* Bit 0 xalpha -- the alphas +** Bit 1 xpalpha -- as xalpha but +** converts spaces to plus and plus to %2B +** Bit 3 ... path -- as xalphas but doesn't escape '/' +*/ + /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */ + { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x */ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 1x */ + 0,0,0,0,0,0,0,0,0,0,7,4,0,7,7,4, /* 2x !"#$%&'()*+,-./ */ + 7,7,7,7,7,7,7,7,7,7,0,0,0,0,0,0, /* 3x 0123456789:;<=>? */ + 0,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, /* 4x @ABCDEFGHIJKLMNO */ + /* bits for '@' changed from 7 to 0 so '@' can be escaped */ + /* in usernames and passwords in publishing. */ + 7,7,7,7,7,7,7,7,7,7,7,0,0,0,0,7, /* 5X PQRSTUVWXYZ[\]^_ */ + 0,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, /* 6x `abcdefghijklmno */ + 7,7,7,7,7,7,7,7,7,7,7,0,0,0,0,0, /* 7X pqrstuvwxyz{\}~ DEL */ + 0, }; + +/* decode % escaped hex codes into character values + */ +#define UNHEX(C) \ + ((C >= '0' && C <= '9') ? C - '0' : \ + ((C >= 'A' && C <= 'F') ? C - 'A' + 10 : \ + ((C >= 'a' && C <= 'f') ? C - 'a' + 10 : 0))) + + +#define IS_OK(C) (netCharType[((unsigned int) (C))] & (mask)) +#define HEX_ESCAPE '%' + +//---------------------------------------------------------------------------------------- +static char* nsEscapeCount( + const char * str, + PRInt32 len, + nsEscapeMask mask, + PRInt32* out_len) +//---------------------------------------------------------------------------------------- +{ + if (!str) + return 0; + + int i, extra = 0; + static const char hexChars[] = "0123456789ABCDEF"; + + register const unsigned char* src = (const unsigned char *) str; + for (i = 0; i < len; i++) + { + if (!IS_OK(*src++)) + extra += 2; /* the escape, plus an extra byte for each nibble */ + } + + char* result = (char *)nsMemory::Alloc(len + extra + 1); + if (!result) + return 0; + + register unsigned char* dst = (unsigned char *) result; + src = (const unsigned char *) str; + if (mask == url_XPAlphas) + { + for (i = 0; i < len; i++) + { + unsigned char c = *src++; + if (IS_OK(c)) + *dst++ = c; + else if (c == ' ') + *dst++ = '+'; /* convert spaces to pluses */ + else + { + *dst++ = HEX_ESCAPE; + *dst++ = hexChars[c >> 4]; /* high nibble */ + *dst++ = hexChars[c & 0x0f]; /* low nibble */ + } + } + } + else + { + for (i = 0; i < len; i++) + { + unsigned char c = *src++; + if (IS_OK(c)) + *dst++ = c; + else + { + *dst++ = HEX_ESCAPE; + *dst++ = hexChars[c >> 4]; /* high nibble */ + *dst++ = hexChars[c & 0x0f]; /* low nibble */ + } + } + } + + *dst = '\0'; /* tack on eos */ + if(out_len) + *out_len = dst - (unsigned char *) result; + return result; +} + +//---------------------------------------------------------------------------------------- +NS_COM char* nsEscape(const char * str, nsEscapeMask mask) +//---------------------------------------------------------------------------------------- +{ + if(!str) + return NULL; + return nsEscapeCount(str, (PRInt32)strlen(str), mask, NULL); +} + +//---------------------------------------------------------------------------------------- +NS_COM char* nsUnescape(char * str) +//---------------------------------------------------------------------------------------- +{ + nsUnescapeCount(str); + return str; +} + +//---------------------------------------------------------------------------------------- +NS_COM PRInt32 nsUnescapeCount(char * str) +//---------------------------------------------------------------------------------------- +{ + register char *src = str; + register char *dst = str; + static const char hexChars[] = "0123456789ABCDEFabcdef"; + + char c1[] = " "; + char c2[] = " "; + char* const pc1 = c1; + char* const pc2 = c2; + + while (*src) + { + c1[0] = *(src+1); + if (*(src+1) == '\0') + c2[0] = '\0'; + else + c2[0] = *(src+2); + + if (*src != HEX_ESCAPE || PL_strpbrk(pc1, hexChars) == 0 || + PL_strpbrk(pc2, hexChars) == 0 ) + *dst++ = *src++; + else + { + src++; /* walk over escape */ + if (*src) + { + *dst = UNHEX(*src) << 4; + src++; + } + if (*src) + { + *dst = (*dst + UNHEX(*src)); + src++; + } + dst++; + } + } + + *dst = 0; + return (int)(dst - str); + +} /* NET_UnEscapeCnt */ + + +NS_COM char * +nsEscapeHTML(const char * string) +{ + /* XXX Hardcoded max entity len. The +1 is for the trailing null. */ + char *rv = (char *) nsMemory::Alloc(strlen(string) * 6 + 1); + char *ptr = rv; + + if(rv) + { + for(; *string != '\0'; string++) + { + if(*string == '<') + { + *ptr++ = '&'; + *ptr++ = 'l'; + *ptr++ = 't'; + *ptr++ = ';'; + } + else if(*string == '>') + { + *ptr++ = '&'; + *ptr++ = 'g'; + *ptr++ = 't'; + *ptr++ = ';'; + } + else if(*string == '&') + { + *ptr++ = '&'; + *ptr++ = 'a'; + *ptr++ = 'm'; + *ptr++ = 'p'; + *ptr++ = ';'; + } + else if (*string == '"') + { + *ptr++ = '&'; + *ptr++ = 'q'; + *ptr++ = 'u'; + *ptr++ = 'o'; + *ptr++ = 't'; + *ptr++ = ';'; + } + else if (*string == '\'') + { + *ptr++ = '&'; + *ptr++ = '#'; + *ptr++ = '3'; + *ptr++ = '9'; + *ptr++ = ';'; + } + else + { + *ptr++ = *string; + } + } + *ptr = '\0'; + } + + return(rv); +} + +NS_COM PRUnichar * +nsEscapeHTML2(const PRUnichar *aSourceBuffer, PRInt32 aSourceBufferLen) +{ + // if the caller didn't calculate the length + if (aSourceBufferLen == -1) { + aSourceBufferLen = nsCRT::strlen(aSourceBuffer); // ...then I will + } + + /* XXX Hardcoded max entity len. */ + PRUnichar *resultBuffer = (PRUnichar *)nsMemory::Alloc(aSourceBufferLen * + 6 * sizeof(PRUnichar) + sizeof(PRUnichar('\0'))); + PRUnichar *ptr = resultBuffer; + + if (resultBuffer) { + PRInt32 i; + + for(i = 0; i < aSourceBufferLen; i++) { + if(aSourceBuffer[i] == '<') { + *ptr++ = '&'; + *ptr++ = 'l'; + *ptr++ = 't'; + *ptr++ = ';'; + } else if(aSourceBuffer[i] == '>') { + *ptr++ = '&'; + *ptr++ = 'g'; + *ptr++ = 't'; + *ptr++ = ';'; + } else if(aSourceBuffer[i] == '&') { + *ptr++ = '&'; + *ptr++ = 'a'; + *ptr++ = 'm'; + *ptr++ = 'p'; + *ptr++ = ';'; + } else if (aSourceBuffer[i] == '"') { + *ptr++ = '&'; + *ptr++ = 'q'; + *ptr++ = 'u'; + *ptr++ = 'o'; + *ptr++ = 't'; + *ptr++ = ';'; + } else if (aSourceBuffer[i] == '\'') { + *ptr++ = '&'; + *ptr++ = '#'; + *ptr++ = '3'; + *ptr++ = '9'; + *ptr++ = ';'; + } else { + *ptr++ = aSourceBuffer[i]; + } + } + *ptr = 0; + } + + return resultBuffer; +} + +//---------------------------------------------------------------------------------------- + +const int EscapeChars[256] = +/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */ +{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1x */ + 0,1023, 0, 512,1023, 0,1023,1023,1023,1023,1023,1023,1023,1023, 953, 784, /* 2x !"#$%&'()*+,-./ */ + 1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1008, 912, 0,1008, 0, 768, /* 3x 0123456789:;<=>? */ + 1008,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023, /* 4x @ABCDEFGHIJKLMNO */ + 1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023, 896, 896, 896, 896,1023, /* 5x PQRSTUVWXYZ[\]^_ */ + 0,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023, /* 6x `abcdefghijklmno */ + 1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023, 896,1012, 896,1023, 0, /* 7x pqrstuvwxyz{|}~ */ + 0 /* 8x DEL */ +}; + +#define NO_NEED_ESC(C) (EscapeChars[((unsigned int) (C))] & (mask)) + +//---------------------------------------------------------------------------------------- + +/* returns an escaped string */ + +/* use the following masks to specify which + part of an URL you want to escape: + + esc_Scheme = 1 + esc_Username = 2 + esc_Password = 4 + esc_Host = 8 + esc_Directory = 16 + esc_FileBaseName = 32 + esc_FileExtension = 64 + esc_Param = 128 + esc_Query = 256 + esc_Ref = 512 +*/ + +/* by default this function will not escape parts of a string + that already look escaped, which means it already includes + a valid hexcode. This is done to avoid multiple escapes of + a string. Use the following mask to force escaping of a + string: + + esc_Forced = 1024 +*/ + +NS_COM PRBool NS_EscapeURL(const char *part, + PRInt32 partLen, + PRInt16 mask, + nsACString &result) +{ + if (!part) { + NS_NOTREACHED("null pointer"); + return PR_FALSE; + } + + int i = 0; + static const char hexChars[] = "0123456789ABCDEF"; + if (partLen < 0) + partLen = strlen(part); + PRBool forced = (mask & esc_Forced); + PRBool ignoreNonAscii = (mask & esc_OnlyASCII); + PRBool ignoreAscii = (mask & esc_OnlyNonASCII); + PRBool writing = (mask & esc_AlwaysCopy); + PRBool colon = (mask & esc_Colon); + + register const unsigned char* src = (const unsigned char *) part; + + char tempBuffer[100]; + unsigned int tempBufferPos = 0; + + for (i = 0; i < partLen; i++) + { + unsigned char c = *src++; + + // if the char has not to be escaped or whatever follows % is + // a valid escaped string, just copy the char. + // + // Also the % will not be escaped until forced + // See bugzilla bug 61269 for details why we changed this + // + // And, we will not escape non-ascii characters if requested. + // On special request we will also escape the colon even when + // not covered by the matrix. + // ignoreAscii is not honored for control characters (C0 and DEL) + if ((NO_NEED_ESC(c) || (c == HEX_ESCAPE && !forced) + || (c > 0x7f && ignoreNonAscii) + || (c > 0x1f && c < 0x7f && ignoreAscii)) + && !(c == ':' && colon)) + { + if (writing) + tempBuffer[tempBufferPos++] = c; + } + else /* do the escape magic */ + { + if (!writing) + { + result.Append(part, i); + writing = PR_TRUE; + } + tempBuffer[tempBufferPos++] = HEX_ESCAPE; + tempBuffer[tempBufferPos++] = hexChars[c >> 4]; /* high nibble */ + tempBuffer[tempBufferPos++] = hexChars[c & 0x0f]; /* low nibble */ + } + + if (tempBufferPos >= sizeof(tempBuffer) - 4) + { + NS_ASSERTION(writing, "should be writing"); + tempBuffer[tempBufferPos] = '\0'; + result += tempBuffer; + tempBufferPos = 0; + } + } + if (writing) { + tempBuffer[tempBufferPos] = '\0'; + result += tempBuffer; + } + return writing; +} + +#define ISHEX(c) memchr(hexChars, c, sizeof(hexChars)-1) + +NS_COM PRBool NS_UnescapeURL(const char *str, PRInt32 len, PRInt16 flags, nsACString &result) +{ + if (!str) { + NS_NOTREACHED("null pointer"); + return PR_FALSE; + } + + if (len < 0) + len = strlen(str); + + PRBool ignoreNonAscii = (flags & esc_OnlyASCII); + PRBool writing = (flags & esc_AlwaysCopy); + PRBool skipControl = (flags & esc_SkipControl); + + static const char hexChars[] = "0123456789ABCDEFabcdef"; + + const char *last = str; + const char *p = str; + + for (int i=0; i= '8') && + !(skipControl && + (*p1 < '2' || (*p1 == '7' && (*p2 == 'f' || *p2 == 'F'))))) { + //printf("- p1=%c p2=%c\n", *p1, *p2); + writing = PR_TRUE; + if (p > last) { + //printf("- p=%p, last=%p\n", p, last); + result.Append(last, p - last); + last = p; + } + char u = (UNHEX(*p1) << 4) + UNHEX(*p2); + //printf("- u=%c\n", u); + result.Append(u); + i += 2; + p += 2; + last += 3; + } + } + } + if (writing && last < str + len) + result.Append(last, str + len - last); + + return writing; +} diff --git a/src/libs/xpcom18a4/xpcom/io/nsEscape.h b/src/libs/xpcom18a4/xpcom/io/nsEscape.h new file mode 100644 index 00000000..aaf56738 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsEscape.h @@ -0,0 +1,196 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* First checked in on 98/12/03 by John R. McMullen, derived from net.h/mkparse.c. */ + +#ifndef _ESCAPE_H_ +#define _ESCAPE_H_ + +#include "prtypes.h" +#include "nscore.h" +#include "nsError.h" +#include "nsString.h" + +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +#define nsEscape VBoxNsxpnsEscape +#define nsUnescape VBoxNsxpnsUnescape +#define nsUnescapeCount VBoxNsxpnsUnescapeCount +#define nsEscapeHTML VBoxNsxpnsEscapeHTML +#define nsEscapeHTML2 VBoxNsxpnsEscapeHTML2 +#endif /* VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + +/** + * Valid mask values for nsEscape + */ +typedef enum { + url_XAlphas = PR_BIT(0) /**< Normal escape - leave alphas intact, escape the rest */ +, url_XPAlphas = PR_BIT(1) /**< As url_XAlphas, but convert spaces (0x20) to '+' and plus to %2B */ +, url_Path = PR_BIT(2) /**< As url_XAlphas, but don't escape slash ('/') */ +} nsEscapeMask; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Escape the given string according to mask + * @param str The string to escape + * @param mask How to escape the string + * @return A newly allocated escaped string that must be free'd with + * nsCRT::free, or null on failure + */ +NS_COM char * nsEscape(const char * str, nsEscapeMask mask); + +NS_COM char * nsUnescape(char * str); + /* decode % escaped hex codes into character values, + * modifies the parameter, returns the same buffer + */ + +NS_COM PRInt32 nsUnescapeCount (char * str); + /* decode % escaped hex codes into character values, + * modifies the parameter buffer, returns the length of the result + * (result may contain \0's). + */ + +NS_COM char * +nsEscapeHTML(const char * string); + +NS_COM PRUnichar * +nsEscapeHTML2(const PRUnichar *aSourceBuffer, + PRInt32 aSourceBufferLen = -1); + /* + * Escape problem char's for HTML display + */ + + +#ifdef __cplusplus +} +#endif + + +/** + * NS_EscapeURL/NS_UnescapeURL constants for |flags| parameter: + */ +enum EscapeMask { + /** url components **/ + esc_Scheme = PR_BIT(0), + esc_Username = PR_BIT(1), + esc_Password = PR_BIT(2), + esc_Host = PR_BIT(3), + esc_Directory = PR_BIT(4), + esc_FileBaseName = PR_BIT(5), + esc_FileExtension = PR_BIT(6), + esc_FilePath = esc_Directory | esc_FileBaseName | esc_FileExtension, + esc_Param = PR_BIT(7), + esc_Query = PR_BIT(8), + esc_Ref = PR_BIT(9), + /** special flags **/ + esc_Minimal = esc_Scheme | esc_Username | esc_Password | esc_Host | esc_FilePath | esc_Param | esc_Query | esc_Ref, + esc_Forced = PR_BIT(10), /* forces escaping of existing escape sequences */ + esc_OnlyASCII = PR_BIT(11), /* causes non-ascii octets to be skipped */ + esc_OnlyNonASCII = PR_BIT(12), /* causes _graphic_ ascii octets (0x20-0x7E) + * to be skipped when escaping. causes all + * ascii octets to be skipped when unescaping */ + esc_AlwaysCopy = PR_BIT(13), /* copy input to result buf even if escaping is unnecessary */ + esc_Colon = PR_BIT(14), /* forces escape of colon */ + esc_SkipControl = PR_BIT(15) /* skips C0 and DEL from unescaping */ +}; + +/** + * NS_EscapeURL + * + * Escapes invalid char's in an URL segment. Has no side-effect if the URL + * segment is already escaped. Otherwise, the escaped URL segment is appended + * to |result|. + * + * @param str url segment string + * @param len url segment string length (-1 if unknown) + * @param flags url segment type flag + * @param result result buffer, untouched if part is already escaped + * + * @return TRUE if escaping was performed, FALSE otherwise. + */ +NS_COM PRBool NS_EscapeURL(const char *str, + PRInt32 len, + PRInt16 flags, + nsACString &result); + +/** + * Expands URL escape sequences... beware embedded null bytes! + * + * @param str url string to unescape + * @param len length of |str| + * @param flags only esc_OnlyNonASCII, esc_SkipControl and esc_AlwaysCopy + * are recognized + * @param result result buffer, untouched if |str| is already unescaped + * + * @return TRUE if unescaping was performed, FALSE otherwise. + */ +NS_COM PRBool NS_UnescapeURL(const char *str, + PRInt32 len, + PRInt16 flags, + nsACString &result); + +/** returns resultant string length **/ +inline PRInt32 NS_UnescapeURL(char *str) { return nsUnescapeCount(str); } + +/** + * string friendly versions... + */ +inline const nsACString & +NS_EscapeURL(const nsASingleFragmentCString &part, PRInt16 partType, nsACString &result) { + const char *temp; + if (NS_EscapeURL(part.BeginReading(temp), part.Length(), partType, result)) + return result; + return part; +} +inline const nsACString & +NS_UnescapeURL(const nsASingleFragmentCString &str, PRInt16 flags, nsACString &result) { + const char *temp; + if (NS_UnescapeURL(str.BeginReading(temp), str.Length(), flags, result)) + return result; + return str; +} +// inline unescape +inline nsAFlatCString & +NS_UnescapeURL(nsAFlatCString &str) +{ + str.SetLength(nsUnescapeCount(str.BeginWriting())); + return str; +} + +#endif // _ESCAPE_H_ diff --git a/src/libs/xpcom18a4/xpcom/io/nsFastLoadFile.cpp b/src/libs/xpcom18a4/xpcom/io/nsFastLoadFile.cpp new file mode 100644 index 00000000..56b09d22 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsFastLoadFile.cpp @@ -0,0 +1,2581 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 FastLoad code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Brendan Eich (original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 +#include "prtypes.h" +#include "nscore.h" +#include "nsDebug.h" +#include "nsEnumeratorUtils.h" +#include "nsMemory.h" +#include "nsXPIDLString.h" +#include "nsString.h" +#include "nsReadableUtils.h" + +#include "nsIComponentManager.h" +#include "nsIFile.h" +#include "nsILocalFile.h" +#include "nsISeekableStream.h" +#include "nsISerializable.h" +#include "nsIStreamBufferAccess.h" + +#include "nsBinaryStream.h" +#include "nsFastLoadFile.h" +#include "nsInt64.h" + +#ifdef DEBUG_brendan +# define METERING +# define DEBUG_MUX +#endif + +#ifdef METERING +# define METER(x) x +#else +# define METER(x) /* nothing */ +#endif + +#ifdef DEBUG_MUX +# include +# include + +static void trace_mux(char mode, const char *format, ...) +{ + va_list ap; + static FILE *tfp; + if (!tfp) { + char tfn[16]; + sprintf(tfn, "/tmp/mux.%ctrace", mode); + tfp = fopen(tfn, "w"); + if (!tfp) + return; + setvbuf(tfp, NULL, _IOLBF, 0); + } + va_start(ap, format); + vfprintf(tfp, format, ap); + va_end(ap); +} + +# define TRACE_MUX(args) trace_mux args +#else +# define TRACE_MUX(args) /* nothing */ +#endif + +/* + * Fletcher's 16-bit checksum, using 32-bit two's-complement arithmetic. + */ +#define FOLD_ONES_COMPLEMENT_CARRY(X) ((X) = ((X) & 0xffff) + ((X) >> 16)) +#define ONES_COMPLEMENT_ACCUMULATE(X,Y) (X) += (Y); if ((X) & 0x80000000) \ + FOLD_ONES_COMPLEMENT_CARRY(X) +#define FLETCHER_ACCUMULATE(A,B,U) ONES_COMPLEMENT_ACCUMULATE(A, U); \ + ONES_COMPLEMENT_ACCUMULATE(B, A) + +PR_IMPLEMENT(PRUint32) +NS_AccumulateFastLoadChecksum(PRUint32 *aChecksum, + const PRUint8* aBuffer, + PRUint32 aLength, + PRBool aLastBuffer) +{ + PRUint32 C = *aChecksum; + PRUint32 A = C & 0xffff; + PRUint32 B = C >> 16; + + PRUint16 U = 0; + if (aLength >= 4) { + PRBool odd = PRWord(aBuffer) & 1; + switch (PRWord(aBuffer) & 3) { + case 3: + U = (aBuffer[0] << 8) | aBuffer[1]; + FLETCHER_ACCUMULATE(A, B, U); + U = aBuffer[2]; + aBuffer += 3; + aLength -= 3; + break; + + case 2: + U = (aBuffer[0] << 8) | aBuffer[1]; + FLETCHER_ACCUMULATE(A, B, U); + U = 0; + aBuffer += 2; + aLength -= 2; + break; + + case 1: + U = *aBuffer++; + aLength--; + break; + } + + PRUint32 W; + if (odd) { + while (aLength > 3) { + W = *NS_REINTERPRET_CAST(const PRUint32*, aBuffer); + U <<= 8; +#ifdef IS_BIG_ENDIAN + U |= W >> 24; + FLETCHER_ACCUMULATE(A, B, U); + U = PRUint16(W >> 8); + FLETCHER_ACCUMULATE(A, B, U); + U = W & 0xff; +#else + U |= W & 0xff; + FLETCHER_ACCUMULATE(A, B, U); + U = PRUint16(W >> 8); + U = NS_SWAP16(U); + FLETCHER_ACCUMULATE(A, B, U); + U = W >> 24; +#endif + aBuffer += 4; + aLength -= 4; + } + aBuffer--; // we're odd, we didn't checksum the last byte + aLength++; + } else { + while (aLength > 3) { + W = *NS_REINTERPRET_CAST(const PRUint32*, aBuffer); +#ifdef IS_BIG_ENDIAN + U = W >> 16; + FLETCHER_ACCUMULATE(A, B, U); + U = PRUint16(W); + FLETCHER_ACCUMULATE(A, B, U); +#else + U = NS_SWAP16(W); + FLETCHER_ACCUMULATE(A, B, U); + U = W >> 16; + U = NS_SWAP16(W); + FLETCHER_ACCUMULATE(A, B, U); +#endif + aBuffer += 4; + aLength -= 4; + } + } + } + + if (aLastBuffer) { + NS_ASSERTION(aLength <= 4, "aLength botch"); + switch (aLength) { + case 4: + U = (aBuffer[0] << 8) | aBuffer[1]; + FLETCHER_ACCUMULATE(A, B, U); + U = (aBuffer[2] << 8) | aBuffer[3]; + FLETCHER_ACCUMULATE(A, B, U); + break; + + case 3: + U = (aBuffer[0] << 8) | aBuffer[1]; + FLETCHER_ACCUMULATE(A, B, U); + U = aBuffer[2]; + FLETCHER_ACCUMULATE(A, B, U); + break; + + case 2: + U = (aBuffer[0] << 8) | aBuffer[1]; + FLETCHER_ACCUMULATE(A, B, U); + break; + + case 1: + U = aBuffer[0]; + FLETCHER_ACCUMULATE(A, B, U); + break; + } + + aLength = 0; + } + + while (A >> 16) + FOLD_ONES_COMPLEMENT_CARRY(A); + while (B >> 16) + FOLD_ONES_COMPLEMENT_CARRY(B); + + *aChecksum = (B << 16) | A; + return aLength; +} + +PR_IMPLEMENT(PRUint32) +NS_AddFastLoadChecksums(PRUint32 sum1, PRUint32 sum2, PRUint32 sum2ByteCount) +{ + PRUint32 A1 = sum1 & 0xffff; + PRUint32 B1 = sum1 >> 16; + + PRUint32 A2 = sum2 & 0xffff; + PRUint32 B2 = sum2 >> 16; + + PRUint32 A = A1 + A2; + while (A >> 16) + FOLD_ONES_COMPLEMENT_CARRY(A); + + PRUint32 B = B2; + for (PRUint32 n = (sum2ByteCount + 1) / 2; n != 0; n--) + ONES_COMPLEMENT_ACCUMULATE(B, B1); + while (B >> 16) + FOLD_ONES_COMPLEMENT_CARRY(B); + + return (B << 16) | A; +} + +#undef FOLD_ONES_COMPLEMENT_CARRY +#undef ONES_COMPLEMENT_ACCUMULATE +#undef FLETCHER_ACCUMULATE + +static const char magic[] = MFL_FILE_MAGIC; + +// -------------------------- nsFastLoadFileReader -------------------------- + +nsID nsFastLoadFileReader::nsFastLoadFooter::gDummyID; +nsFastLoadFileReader::nsObjectMapEntry + nsFastLoadFileReader::nsFastLoadFooter::gDummySharpObjectEntry; + +NS_IMPL_ISUPPORTS_INHERITED5(nsFastLoadFileReader, + nsBinaryInputStream, + nsIObjectInputStream, + nsIFastLoadFileControl, + nsIFastLoadReadControl, + nsISeekableStream, + nsIFastLoadFileReader) + +MOZ_DECL_CTOR_COUNTER(nsFastLoadFileReader) + +nsresult +nsFastLoadFileReader::ReadHeader(nsFastLoadHeader *aHeader) +{ + nsresult rv; + PRUint32 bytesRead; + + rv = Read(NS_REINTERPRET_CAST(char*, aHeader), sizeof *aHeader, &bytesRead); + if (NS_FAILED(rv)) + return rv; + + if (bytesRead != sizeof *aHeader || + memcmp(aHeader->mMagic, magic, MFL_FILE_MAGIC_SIZE)) { + return NS_ERROR_UNEXPECTED; + } + + aHeader->mChecksum = NS_SWAP32(aHeader->mChecksum); + aHeader->mVersion = NS_SWAP32(aHeader->mVersion); + aHeader->mFooterOffset = NS_SWAP32(aHeader->mFooterOffset); + aHeader->mFileSize = NS_SWAP32(aHeader->mFileSize); + + return NS_OK; +} + +// nsIFastLoadFileControl methods: + +NS_IMETHODIMP +nsFastLoadFileReader::GetChecksum(PRUint32 *aChecksum) +{ + *aChecksum = mHeader.mChecksum; + return NS_OK; +} + +NS_IMETHODIMP +nsFastLoadFileReader::SetChecksum(PRUint32 aChecksum) +{ + mHeader.mChecksum = aChecksum; + return NS_OK; +} + +struct nsStringMapEntry : public PLDHashEntryHdr { + const char* mString; // key, must come first + nsISupports* mURI; // for SelectMuxedDocument return value +}; + +struct nsDocumentMapEntry : public nsStringMapEntry { + PRUint32 mInitialSegmentOffset; // offset of URI's first segment in file +}; + +struct nsDocumentMapReadEntry : public nsDocumentMapEntry { + PRUint32 mNextSegmentOffset; // offset of URI's next segment to read + PRUint32 mBytesLeft : 31, // bytes remaining in current segment + mNeedToSeek : 1; // flag to defer Seek from Select to + // Read, in case there is no Read before + // another entry is Selected (to improve + // input stream buffer utilization) + PRInt64 mSaveOffset; // in case demux schedule differs from + // mux schedule +}; + +PR_STATIC_CALLBACK(void) +strmap_ClearEntry(PLDHashTable *aTable, PLDHashEntryHdr *aHdr) +{ + nsStringMapEntry* entry = NS_STATIC_CAST(nsStringMapEntry*, aHdr); + + if (entry->mString) + nsMemory::Free((void*) entry->mString); + NS_IF_RELEASE(entry->mURI); + PL_DHashClearEntryStub(aTable, aHdr); +} + +static const PLDHashTableOps strmap_DHashTableOps = { + PL_DHashAllocTable, + PL_DHashFreeTable, + PL_DHashGetKeyStub, + PL_DHashStringKey, + PL_DHashMatchStringKey, + PL_DHashMoveEntryStub, + strmap_ClearEntry, + PL_DHashFinalizeStub, + NULL +}; + +// An nsObjectMapEntry holds a strong reference to an XPCOM object, unless the +// mObject member, when cast to NSFastLoadOID, has its MFL_OBJECT_DEF_TAG bit +// set. NB: we rely on the fact that an nsISupports* is never an odd pointer. +struct nsObjectMapEntry : public PLDHashEntryHdr { + nsISupports* mObject; // key, must come first +}; + +// Fast mapping from URI object pointer back to spec-indexed document info. +struct nsURIMapReadEntry : public nsObjectMapEntry { + nsDocumentMapReadEntry* mDocMapEntry; +}; + +PR_STATIC_CALLBACK(void) +objmap_ClearEntry(PLDHashTable *aTable, PLDHashEntryHdr *aHdr) +{ + nsObjectMapEntry* entry = NS_STATIC_CAST(nsObjectMapEntry*, aHdr); + + // Ignore tagged object ids stored as object pointer keys (the updater + // code does this). + if ((NS_PTR_TO_INT32(entry->mObject) & MFL_OBJECT_DEF_TAG) == 0) + NS_IF_RELEASE(entry->mObject); + PL_DHashClearEntryStub(aTable, aHdr); +} + +static const PLDHashTableOps objmap_DHashTableOps = { + PL_DHashAllocTable, + PL_DHashFreeTable, + PL_DHashGetKeyStub, + PL_DHashVoidPtrKeyStub, + PL_DHashMatchEntryStub, + PL_DHashMoveEntryStub, + objmap_ClearEntry, + PL_DHashFinalizeStub, + NULL +}; + +NS_IMETHODIMP +nsFastLoadFileReader::HasMuxedDocument(const char* aURISpec, PRBool *aResult) +{ + nsDocumentMapReadEntry* docMapEntry = + NS_STATIC_CAST(nsDocumentMapReadEntry*, + PL_DHashTableOperate(&mFooter.mDocumentMap, aURISpec, + PL_DHASH_LOOKUP)); + + *aResult = PL_DHASH_ENTRY_IS_BUSY(docMapEntry); + return NS_OK; +} + +NS_IMETHODIMP +nsFastLoadFileReader::StartMuxedDocument(nsISupports* aURI, const char* aURISpec) +{ + nsDocumentMapReadEntry* docMapEntry = + NS_STATIC_CAST(nsDocumentMapReadEntry*, + PL_DHashTableOperate(&mFooter.mDocumentMap, aURISpec, + PL_DHASH_LOOKUP)); + + // If the spec isn't in the map, return NS_ERROR_NOT_AVAILABLE so the + // FastLoad service can try for a file update. + if (PL_DHASH_ENTRY_IS_FREE(docMapEntry)) + return NS_ERROR_NOT_AVAILABLE; + + nsCOMPtr key(do_QueryInterface(aURI)); + nsURIMapReadEntry* uriMapEntry = + NS_STATIC_CAST(nsURIMapReadEntry*, + PL_DHashTableOperate(&mFooter.mURIMap, key, + PL_DHASH_ADD)); + if (!uriMapEntry) + return NS_ERROR_OUT_OF_MEMORY; + + NS_ASSERTION(uriMapEntry->mDocMapEntry == nsnull, + "URI mapped to two different specs?"); + if (uriMapEntry->mDocMapEntry) + return NS_ERROR_UNEXPECTED; + + docMapEntry->mURI = aURI; + NS_ADDREF(docMapEntry->mURI); + uriMapEntry->mObject = key; + NS_ADDREF(uriMapEntry->mObject); + uriMapEntry->mDocMapEntry = docMapEntry; + TRACE_MUX(('r', "start %p (%p) %s\n", aURI, key.get(), aURISpec)); + return NS_OK; +} + +NS_IMETHODIMP +nsFastLoadFileReader::SelectMuxedDocument(nsISupports* aURI, + nsISupports** aResult) +{ + nsresult rv; + + // Find the given URI's entry and select it for more reading. + nsCOMPtr key(do_QueryInterface(aURI)); + nsURIMapReadEntry* uriMapEntry = + NS_STATIC_CAST(nsURIMapReadEntry*, + PL_DHashTableOperate(&mFooter.mURIMap, key, + PL_DHASH_LOOKUP)); + + // If the URI isn't in the map, return NS_ERROR_NOT_AVAILABLE so the + // FastLoad service can try selecting the file updater. + if (PL_DHASH_ENTRY_IS_FREE(uriMapEntry)) + return NS_ERROR_NOT_AVAILABLE; + + // If we're interrupting another document's segment, save its offset so + // we can seek back when it's reselected. If prevDocMapEntry->mNeedToSeek + // is set, that means the stream is not positioned for prevDocMapEntry, to + // avoid buffer thrashing. See below in this function for more. + nsDocumentMapReadEntry* prevDocMapEntry = mCurrentDocumentMapEntry; + if (prevDocMapEntry && + prevDocMapEntry->mBytesLeft && + !prevDocMapEntry->mNeedToSeek) { + rv = Tell(&prevDocMapEntry->mSaveOffset); + if (NS_FAILED(rv)) + return rv; + } + + // It turns out we get a fair amount of redundant select calls, thanks to + // non-blocking hunks of data from the parser that are devoid of scripts. + // As more data gets FastLoaded, the number of these useless selects will + // decline. + nsDocumentMapReadEntry* docMapEntry = uriMapEntry->mDocMapEntry; + if (docMapEntry == prevDocMapEntry) { + TRACE_MUX(('r', "select prev %s same as current!\n", + docMapEntry->mString)); + } + + // Invariant: docMapEntry->mBytesLeft implies docMapEntry->mSaveOffset has + // been set non-zero by the Tell call above. + else if (docMapEntry->mBytesLeft) { + NS_ASSERTION(docMapEntry->mSaveOffset != 0, + "reselecting from multiplex at unsaved offset?"); + + // Defer Seek till Read, in case of "ping-pong" Selects without any + // intervening Reads, to avoid dumping the underlying mInputStream's + // input buffer for cases where alternate "pongs" fall in the same + // buffer. + docMapEntry->mNeedToSeek = PR_TRUE; + } + + *aResult = prevDocMapEntry ? prevDocMapEntry->mURI : nsnull; + NS_IF_ADDREF(*aResult); + + mCurrentDocumentMapEntry = docMapEntry; +#ifdef DEBUG_MUX + PRInt64 currentSegmentOffset; + Tell(¤tSegmentOffset); + trace_mux('r', "select %p (%p) offset %ld\n", + aURI, key.get(), (long) currentSegmentOffset); +#endif + return NS_OK; +} + +NS_IMETHODIMP +nsFastLoadFileReader::EndMuxedDocument(nsISupports* aURI) +{ + nsCOMPtr key(do_QueryInterface(aURI)); + nsURIMapReadEntry* uriMapEntry = + NS_STATIC_CAST(nsURIMapReadEntry*, + PL_DHashTableOperate(&mFooter.mURIMap, key, + PL_DHASH_LOOKUP)); + + // If the URI isn't in the map, return NS_ERROR_NOT_AVAILABLE so the + // FastLoad service can try to end a select on its file updater. + if (PL_DHASH_ENTRY_IS_FREE(uriMapEntry)) + return NS_ERROR_NOT_AVAILABLE; + + // Drop our ref to the URI object that was passed to StartMuxedDocument, + // we no longer need it, and we do not want to extend its lifetime. + if (uriMapEntry->mDocMapEntry) + NS_RELEASE(uriMapEntry->mDocMapEntry->mURI); + + // Shrink the table if half the entries are removed sentinels. + PRUint32 size = PL_DHASH_TABLE_SIZE(&mFooter.mURIMap); + if (mFooter.mURIMap.removedCount >= (size >> 2)) + PL_DHashTableOperate(&mFooter.mURIMap, key, PL_DHASH_REMOVE); + else + PL_DHashTableRawRemove(&mFooter.mURIMap, uriMapEntry); + + TRACE_MUX(('r', "end %p (%p)\n", aURI, key.get())); + return NS_OK; +} + +NS_IMETHODIMP +nsFastLoadFileReader::Read(char* aBuffer, PRUint32 aCount, PRUint32 *aBytesRead) +{ + nsresult rv; + + nsDocumentMapReadEntry* entry = mCurrentDocumentMapEntry; + if (entry) { + // Don't call our Seek wrapper, as it clears mCurrentDocumentMapEntry. + nsCOMPtr seekable(do_QueryInterface(mInputStream)); + if (entry->mNeedToSeek) { + rv = seekable->Seek(nsISeekableStream::NS_SEEK_SET, + entry->mSaveOffset); + if (NS_FAILED(rv)) + return rv; + + entry->mNeedToSeek = PR_FALSE; + } + + // Loop to handle empty segments, which may be generated by the + // writer, given Start A; Start B; Select A; Select B; write B data; + // multiplexing schedules, which do tend to occur given non-blocking + // i/o with LIFO scheduling. XXXbe investigate LIFO issues + while (entry->mBytesLeft == 0) { + // Check for unexpected end of multiplexed stream. + NS_ASSERTION(entry->mNextSegmentOffset != 0, + "document demuxed from FastLoad file more than once?"); + if (entry->mNextSegmentOffset == 0) + return NS_ERROR_UNEXPECTED; + + rv = seekable->Seek(nsISeekableStream::NS_SEEK_SET, + entry->mNextSegmentOffset); + if (NS_FAILED(rv)) + return rv; + + // Clear mCurrentDocumentMapEntry temporarily to avoid recursion. + mCurrentDocumentMapEntry = nsnull; + + rv = Read32(&entry->mNextSegmentOffset); + if (NS_SUCCEEDED(rv)) { + PRUint32 bytesLeft = 0; + rv = Read32(&bytesLeft); + entry->mBytesLeft = bytesLeft; + } + + mCurrentDocumentMapEntry = entry; + if (NS_FAILED(rv)) + return rv; + + NS_ASSERTION(entry->mBytesLeft >= 8, "demux segment length botch!"); + entry->mBytesLeft -= 8; + } + } + + rv = mInputStream->Read(aBuffer, aCount, aBytesRead); + + if (NS_SUCCEEDED(rv) && entry) { + NS_ASSERTION(entry->mBytesLeft >= *aBytesRead, "demux Read underflow!"); + entry->mBytesLeft -= *aBytesRead; + +#ifdef NS_DEBUG + // Invariant: !entry->mBytesLeft implies entry->mSaveOffset == 0. + if (entry->mBytesLeft == 0) + entry->mSaveOffset = 0; +#endif + } + return rv; +} + +NS_IMETHODIMP +nsFastLoadFileReader::ReadSegments(nsWriteSegmentFun aWriter, void* aClosure, + PRUint32 aCount, PRUint32 *aResult) +{ + nsDocumentMapReadEntry* entry = mCurrentDocumentMapEntry; + + NS_ASSERTION(!entry || (!entry->mNeedToSeek && entry->mBytesLeft != 0), + "ReadSegments called from above nsFastLoadFileReader layer?!"); + + nsresult rv = nsBinaryInputStream::ReadSegments(aWriter, aClosure, aCount, + aResult); + if (NS_SUCCEEDED(rv) && entry) { + NS_ASSERTION(entry->mBytesLeft >= *aResult, + "demux ReadSegments underflow!"); + entry->mBytesLeft -= *aResult; + +#ifdef NS_DEBUG + // Invariant: !entry->mBytesLeft implies entry->mSaveOffset == 0. + if (entry->mBytesLeft == 0) + entry->mSaveOffset = 0; +#endif + } + return rv; +} + +/** + * XXX tuneme + */ +#define MFL_CHECKSUM_BUFSIZE 8192 + +NS_IMETHODIMP +nsFastLoadFileReader::ComputeChecksum(PRUint32 *aResult) +{ + nsCOMPtr stream = mInputStream; + + nsCOMPtr seekable(do_QueryInterface(stream)); + PRInt64 saveOffset; + nsresult rv = seekable->Tell(&saveOffset); + if (NS_FAILED(rv)) + return rv; + + nsCOMPtr bufferAccess(do_QueryInterface(stream)); + if (bufferAccess) { + rv = bufferAccess->GetUnbufferedStream(getter_AddRefs(stream)); + if (NS_FAILED(rv)) + return rv; + + seekable = do_QueryInterface(stream); + if (!seekable) + return NS_ERROR_UNEXPECTED; + } + + rv = seekable->Seek(nsISeekableStream::NS_SEEK_SET, 0); + if (NS_FAILED(rv)) + return rv; + + char buf[MFL_CHECKSUM_BUFSIZE]; + PRUint32 len, rem; + + rem = offsetof(nsFastLoadHeader, mChecksum); + rv = stream->Read(buf, rem, &len); + if (NS_FAILED(rv)) + return rv; + if (len != rem) + return NS_ERROR_UNEXPECTED; + + rv = seekable->Seek(nsISeekableStream::NS_SEEK_CUR, 4); + if (NS_FAILED(rv)) + return rv; + memset(buf + rem, 0, 4); + rem += 4; + + PRUint32 checksum = 0; + while (NS_SUCCEEDED(rv = stream->Read(buf + rem, sizeof buf - rem, &len)) && + len) { + len += rem; + rem = NS_AccumulateFastLoadChecksum(&checksum, + NS_REINTERPRET_CAST(PRUint8*, buf), + len, + PR_FALSE); + if (rem) + memcpy(buf, buf + len - rem, rem); + } + if (NS_FAILED(rv)) + return rv; + + if (rem) { + NS_AccumulateFastLoadChecksum(&checksum, + NS_REINTERPRET_CAST(PRUint8*, buf), + rem, + PR_TRUE); + } + + rv = seekable->Seek(nsISeekableStream::NS_SEEK_SET, saveOffset); + if (NS_FAILED(rv)) + return rv; + + *aResult = checksum; + return NS_OK; +} + +NS_IMETHODIMP +nsFastLoadFileReader::GetDependencies(nsISimpleEnumerator* *aDependencies) +{ + return NS_NewArrayEnumerator(aDependencies, mFooter.mDependencies); +} + +nsresult +nsFastLoadFileReader::ReadFooter(nsFastLoadFooter *aFooter) +{ + nsresult rv; + + rv = ReadFooterPrefix(aFooter); + if (NS_FAILED(rv)) + return rv; + + aFooter->mIDMap = new nsID[aFooter->mNumIDs]; + if (!aFooter->mIDMap) + return NS_ERROR_OUT_OF_MEMORY; + + PRUint32 i, n; + for (i = 0, n = aFooter->mNumIDs; i < n; i++) { + rv = ReadSlowID(&aFooter->mIDMap[i]); + if (NS_FAILED(rv)) + return rv; + } + + aFooter->mObjectMap = new nsObjectMapEntry[aFooter->mNumSharpObjects]; + if (!aFooter->mObjectMap) + return NS_ERROR_OUT_OF_MEMORY; + + for (i = 0, n = aFooter->mNumSharpObjects; i < n; i++) { + nsObjectMapEntry* entry = &aFooter->mObjectMap[i]; + + rv = ReadSharpObjectInfo(entry); + if (NS_FAILED(rv)) + return rv; + + entry->mReadObject = nsnull; + entry->mSkipOffset = 0; + entry->mSaveStrongRefCnt = entry->mStrongRefCnt; + entry->mSaveWeakRefCnt = entry->mWeakRefCnt; + } + + if (!PL_DHashTableInit(&aFooter->mDocumentMap, &strmap_DHashTableOps, + (void *)this, sizeof(nsDocumentMapReadEntry), + aFooter->mNumMuxedDocuments)) { + aFooter->mDocumentMap.ops = nsnull; + return NS_ERROR_OUT_OF_MEMORY; + } + + if (!PL_DHashTableInit(&aFooter->mURIMap, &objmap_DHashTableOps, + (void *)this, sizeof(nsURIMapReadEntry), + aFooter->mNumMuxedDocuments)) { + aFooter->mURIMap.ops = nsnull; + return NS_ERROR_OUT_OF_MEMORY; + } + + for (i = 0, n = aFooter->mNumMuxedDocuments; i < n; i++) { + nsFastLoadMuxedDocumentInfo info; + + rv = ReadMuxedDocumentInfo(&info); + if (NS_FAILED(rv)) + return rv; + + nsDocumentMapReadEntry* entry = + NS_STATIC_CAST(nsDocumentMapReadEntry*, + PL_DHashTableOperate(&aFooter->mDocumentMap, + info.mURISpec, + PL_DHASH_ADD)); + if (!entry) { + nsMemory::Free((void*) info.mURISpec); + return NS_ERROR_OUT_OF_MEMORY; + } + + NS_ASSERTION(!entry->mString, "duplicate URISpec in MuxedDocumentMap"); + entry->mString = info.mURISpec; + entry->mURI = nsnull; + entry->mInitialSegmentOffset = info.mInitialSegmentOffset; + entry->mNextSegmentOffset = info.mInitialSegmentOffset; + entry->mBytesLeft = 0; + entry->mNeedToSeek = PR_FALSE; + entry->mSaveOffset = 0; + } + + nsCOMPtr readDeps; + rv = NS_NewISupportsArray(getter_AddRefs(readDeps)); + if (NS_FAILED(rv)) + return rv; + + nsCAutoString filename; + for (i = 0, n = aFooter->mNumDependencies; i < n; i++) { + rv = ReadCString(filename); + if (NS_FAILED(rv)) + return rv; + + PRInt64 fastLoadMtime; + rv = Read64(NS_REINTERPRET_CAST(PRUint64*, &fastLoadMtime)); + if (NS_FAILED(rv)) + return rv; + + nsCOMPtr file; + rv = NS_NewNativeLocalFile(filename, PR_TRUE, getter_AddRefs(file)); + if (NS_FAILED(rv)) + return rv; + + PRInt64 currentMtime; + rv = file->GetLastModifiedTime(¤tMtime); + if (NS_FAILED(rv)) + return rv; + + if (LL_NE(fastLoadMtime, currentMtime)) { +#ifdef DEBUG + nsCAutoString path; + file->GetNativePath(path); + printf("%s mtime changed, invalidating FastLoad file\n", + path.get()); +#endif + return NS_ERROR_FAILURE; + } + + rv = readDeps->AppendElement(file); + if (NS_FAILED(rv)) + return rv; + } + + aFooter->mDependencies = readDeps; + return NS_OK; +} + +nsresult +nsFastLoadFileReader::ReadFooterPrefix(nsFastLoadFooterPrefix *aFooterPrefix) +{ + nsresult rv; + + rv = Read32(&aFooterPrefix->mNumIDs); + if (NS_FAILED(rv)) + return rv; + + rv = Read32(&aFooterPrefix->mNumSharpObjects); + if (NS_FAILED(rv)) + return rv; + + rv = Read32(&aFooterPrefix->mNumMuxedDocuments); + if (NS_FAILED(rv)) + return rv; + + rv = Read32(&aFooterPrefix->mNumDependencies); + if (NS_FAILED(rv)) + return rv; + + return NS_OK; +} + +nsresult +nsFastLoadFileReader::ReadSlowID(nsID *aID) +{ + nsresult rv; + + rv = Read32(&aID->m0); + if (NS_FAILED(rv)) + return rv; + + rv = Read16(&aID->m1); + if (NS_FAILED(rv)) + return rv; + + rv = Read16(&aID->m2); + if (NS_FAILED(rv)) + return rv; + + PRUint32 bytesRead; + rv = Read(NS_REINTERPRET_CAST(char*, aID->m3), sizeof aID->m3, &bytesRead); + if (NS_FAILED(rv)) + return rv; + + if (bytesRead != sizeof aID->m3) + return NS_ERROR_FAILURE; + return NS_OK; +} + +nsresult +nsFastLoadFileReader::ReadFastID(NSFastLoadID *aID) +{ + nsresult rv = Read32(aID); + if (NS_SUCCEEDED(rv)) + *aID ^= MFL_ID_XOR_KEY; + return rv; +} + +nsresult +nsFastLoadFileReader::ReadSharpObjectInfo(nsFastLoadSharpObjectInfo *aInfo) +{ + nsresult rv; + + rv = Read32(&aInfo->mCIDOffset); + if (NS_FAILED(rv)) + return rv; + + NS_ASSERTION(aInfo->mCIDOffset != 0, + "fastload reader: mCIDOffset cannot be zero!"); + + rv = Read16(&aInfo->mStrongRefCnt); + if (NS_FAILED(rv)) + return rv; + + rv = Read16(&aInfo->mWeakRefCnt); + if (NS_FAILED(rv)) + return rv; + + return NS_OK; +} + +nsresult +nsFastLoadFileReader::ReadMuxedDocumentInfo(nsFastLoadMuxedDocumentInfo *aInfo) +{ + nsresult rv; + + nsCAutoString spec; + rv = ReadCString(spec); + if (NS_FAILED(rv)) + return rv; + + rv = Read32(&aInfo->mInitialSegmentOffset); + if (NS_FAILED(rv)) + return rv; + + aInfo->mURISpec = ToNewCString(spec); + return NS_OK; +} + +nsresult +nsFastLoadFileReader::Open() +{ + nsCOMPtr seekable(do_QueryInterface(mInputStream)); + if (!seekable) + return NS_ERROR_UNEXPECTED; + + nsresult rv; + + // Don't bother buffering the header, as we immediately seek to EOF. + nsCOMPtr + bufferAccess(do_QueryInterface(mInputStream)); + if (bufferAccess) + bufferAccess->DisableBuffering(); + + rv = ReadHeader(&mHeader); + + if (bufferAccess) + bufferAccess->EnableBuffering(); + if (NS_FAILED(rv)) + return rv; + + if (mHeader.mVersion != MFL_FILE_VERSION) + return NS_ERROR_UNEXPECTED; + if (mHeader.mFooterOffset == 0) + return NS_ERROR_UNEXPECTED; + + rv = seekable->Seek(nsISeekableStream::NS_SEEK_END, 0); + if (NS_FAILED(rv)) + return rv; + + PRInt64 fileSize; + rv = seekable->Tell(&fileSize); + if (NS_FAILED(rv)) + return rv; + + nsInt64 fileSize64 = fileSize; + const nsInt64 maxUint32 = PR_UINT32_MAX; + NS_ASSERTION(fileSize64 <= maxUint32, "fileSize must fit in 32 bits"); + if ((PRUint32) fileSize64 != mHeader.mFileSize) + return NS_ERROR_UNEXPECTED; + + rv = seekable->Seek(nsISeekableStream::NS_SEEK_SET, + PRInt32(mHeader.mFooterOffset)); + if (NS_FAILED(rv)) + return rv; + + rv = ReadFooter(&mFooter); + if (NS_FAILED(rv)) + return rv; + + return seekable->Seek(nsISeekableStream::NS_SEEK_SET, + sizeof(nsFastLoadHeader)); +} + +NS_IMETHODIMP +nsFastLoadFileReader::Close() +{ + // Give up our strong "keepalive" references, in case not all objects that + // were deserialized were fully re-connected. + // + // This happens for sure when an nsFastLoadFileUpdater is created and wraps + // an nsFastLoadFileReader whose data was already deserialized by an earlier + // FastLoad episode. The reader is useful in the second such episode during + // a session not so much for reading objects as for its footer information, + // which primes the updater's tables so that after the update completes, the + // FastLoad file has a superset footer. + + for (PRUint32 i = 0, n = mFooter.mNumSharpObjects; i < n; i++) { + nsObjectMapEntry* entry = &mFooter.mObjectMap[i]; + entry->mReadObject = nsnull; + } + + return mInputStream->Close(); +} + +nsresult +nsFastLoadFileReader::DeserializeObject(nsISupports* *aObject) +{ + nsresult rv; + NSFastLoadID fastCID; + + rv = ReadFastID(&fastCID); + if (NS_FAILED(rv)) + return rv; + + const nsID& slowCID = mFooter.GetID(fastCID); + nsCOMPtr object(do_CreateInstance(slowCID, &rv)); + if (NS_FAILED(rv)) + return rv; + + nsCOMPtr serializable(do_QueryInterface(object)); + if (!serializable) + return NS_ERROR_FAILURE; + + rv = serializable->Read(this); + if (NS_FAILED(rv)) + return rv; + + *aObject = object; + NS_ADDREF(*aObject); + return NS_OK; +} + +nsresult +nsFastLoadFileReader::ReadObject(PRBool aIsStrongRef, nsISupports* *aObject) +{ + nsresult rv; + NSFastLoadOID oid; + + rv = Read32(&oid); + if (NS_FAILED(rv)) + return rv; + oid ^= MFL_OID_XOR_KEY; + + nsCOMPtr object; + + if (oid == MFL_DULL_OBJECT_OID) { + // A very dull object, defined at point of single (strong) reference. + NS_ASSERTION(aIsStrongRef, "dull object read via weak ref!"); + + rv = DeserializeObject(getter_AddRefs(object)); + if (NS_FAILED(rv)) + return rv; + } else { + NS_ASSERTION((oid & MFL_WEAK_REF_TAG) == + (aIsStrongRef ? 0 : MFL_WEAK_REF_TAG), + "strong vs. weak ref deserialization mismatch!"); + + nsObjectMapEntry* entry = &mFooter.GetSharpObjectEntry(oid); + + // Check whether we've already deserialized the object for this OID. + object = entry->mReadObject; + if (!object) { + nsCOMPtr seekable(do_QueryInterface(mInputStream)); + PRInt64 saveOffset; + nsDocumentMapReadEntry* saveDocMapEntry = nsnull; + + rv = seekable->Tell(&saveOffset); + if (NS_FAILED(rv)) + return rv; + + PRUint32 saveOffset32 = saveOffset; + if (entry->mCIDOffset != saveOffset32) { + // We skipped deserialization of this object from its position + // earlier in the input stream, presumably due to the reference + // there being an nsFastLoadPtr, or (more likely) because the + // object was muxed in another document, and deserialization + // order does not match serialization order. So we must seek + // back and read it now. + NS_ASSERTION(entry->mCIDOffset < saveOffset32, + "out of order object?!"); + + // Ape our Seek wrapper by clearing mCurrentDocumentMapEntry. + // This allows for a skipped object to be referenced from two + // or more multiplexed documents in the FastLoad file. + saveDocMapEntry = mCurrentDocumentMapEntry; + mCurrentDocumentMapEntry = nsnull; + rv = seekable->Seek(nsISeekableStream::NS_SEEK_SET, + entry->mCIDOffset); + if (NS_FAILED(rv)) + return rv; + } + + rv = DeserializeObject(getter_AddRefs(object)); + if (NS_FAILED(rv)) + return rv; + + if (entry->mCIDOffset != saveOffset32) { + // Save the "skip offset" in case we need to skip this object + // definition when reading forward, later on. + rv = seekable->Tell(&entry->mSkipOffset); + if (NS_FAILED(rv)) + return rv; + + // Restore stream offset and mCurrentDocumentMapEntry in case + // we're still reading forward through a part of the multiplex + // to get object definitions eagerly. + rv = seekable->Seek(nsISeekableStream::NS_SEEK_SET, saveOffset); + if (NS_FAILED(rv)) + return rv; + mCurrentDocumentMapEntry = saveDocMapEntry; + } + + // Save object until all refs have been deserialized. + entry->mReadObject = object; + } else { + // What if we are at a definition that's already been read? This + // case arises when a sharp object's def is serialized before its + // refs, while a non-defining ref is deserialized before the def. + // We must skip over the object definition. + if (oid & MFL_OBJECT_DEF_TAG) { + NS_ASSERTION(entry->mSkipOffset != 0, "impossible! see above"); + nsCOMPtr + seekable(do_QueryInterface(mInputStream)); + rv = seekable->Seek(nsISeekableStream::NS_SEEK_SET, + entry->mSkipOffset); + if (NS_FAILED(rv)) + return rv; + } + } + + if (aIsStrongRef) { + NS_ASSERTION(entry->mStrongRefCnt != 0, + "mStrongRefCnt underflow!"); + --entry->mStrongRefCnt; + } else { + NS_ASSERTION(MFL_GET_WEAK_REFCNT(entry) != 0, + "mWeakRefCnt underflow!"); + MFL_DROP_WEAK_REFCNT(entry); + } + + if (entry->mStrongRefCnt == 0 && MFL_GET_WEAK_REFCNT(entry) == 0) + entry->mReadObject = nsnull; + } + + if (oid & MFL_QUERY_INTERFACE_TAG) { + NSFastLoadID iid; + rv = ReadFastID(&iid); + if (NS_FAILED(rv)) + return rv; + + rv = object->QueryInterface(mFooter.GetID(iid), + NS_REINTERPRET_CAST(void**, aObject)); + if (NS_FAILED(rv)) + return rv; + } else { + *aObject = object; + NS_ADDREF(*aObject); + } + + return NS_OK; +} + +NS_IMETHODIMP +nsFastLoadFileReader::ReadID(nsID *aResult) +{ + nsresult rv; + NSFastLoadID fastID; + + rv = ReadFastID(&fastID); + if (NS_FAILED(rv)) + return rv; + + *aResult = mFooter.GetID(fastID); + return NS_OK; +} + +NS_IMETHODIMP +nsFastLoadFileReader::Seek(PRInt32 aWhence, PRInt64 aOffset) +{ + mCurrentDocumentMapEntry = nsnull; + nsCOMPtr seekable(do_QueryInterface(mInputStream)); + return seekable->Seek(aWhence, aOffset); +} + +NS_IMETHODIMP +nsFastLoadFileReader::Tell(PRInt64 *aResult) +{ + nsCOMPtr seekable(do_QueryInterface(mInputStream)); + return seekable->Tell(aResult); +} + +NS_IMETHODIMP +nsFastLoadFileReader::SetEOF() +{ + nsCOMPtr seekable(do_QueryInterface(mInputStream)); + return seekable->SetEOF(); +} + +NS_COM nsresult +NS_NewFastLoadFileReader(nsIObjectInputStream* *aResult, + nsIInputStream* aSrcStream) +{ + nsFastLoadFileReader* reader = new nsFastLoadFileReader(aSrcStream); + if (!reader) + return NS_ERROR_OUT_OF_MEMORY; + + // Stabilize reader's refcnt. + nsCOMPtr stream(reader); + + nsresult rv = reader->Open(); + if (NS_FAILED(rv)) + return rv; + + *aResult = stream; + NS_ADDREF(*aResult); + return NS_OK; +} + +// -------------------------- nsFastLoadFileWriter -------------------------- + +NS_IMPL_ISUPPORTS_INHERITED4(nsFastLoadFileWriter, + nsBinaryOutputStream, + nsIObjectOutputStream, + nsIFastLoadFileControl, + nsIFastLoadWriteControl, + nsISeekableStream) + +MOZ_DECL_CTOR_COUNTER(nsFastLoadFileWriter) + +struct nsIDMapEntry : public PLDHashEntryHdr { + NSFastLoadID mFastID; // 1 + nsFastLoadFooter::mIDMap index + nsID mSlowID; // key, used by PLDHashTableOps below +}; + +PR_STATIC_CALLBACK(const void *) +idmap_GetKey(PLDHashTable *aTable, PLDHashEntryHdr *aHdr) +{ + nsIDMapEntry* entry = NS_STATIC_CAST(nsIDMapEntry*, aHdr); + + return &entry->mSlowID; +} + +PR_STATIC_CALLBACK(PLDHashNumber) +idmap_HashKey(PLDHashTable *aTable, const void *aKey) +{ + const nsID *idp = NS_REINTERPRET_CAST(const nsID*, aKey); + + return idp->m0; +} + +PR_STATIC_CALLBACK(PRBool) +idmap_MatchEntry(PLDHashTable *aTable, + const PLDHashEntryHdr *aHdr, + const void *aKey) +{ + const nsIDMapEntry* entry = NS_STATIC_CAST(const nsIDMapEntry*, aHdr); + const nsID *idp = NS_REINTERPRET_CAST(const nsID*, aKey); + + return memcmp(&entry->mSlowID, idp, sizeof(nsID)) == 0; +} + +static const PLDHashTableOps idmap_DHashTableOps = { + PL_DHashAllocTable, + PL_DHashFreeTable, + idmap_GetKey, + idmap_HashKey, + idmap_MatchEntry, + PL_DHashMoveEntryStub, + PL_DHashClearEntryStub, + PL_DHashFinalizeStub, + NULL +}; + +nsresult +nsFastLoadFileWriter::MapID(const nsID& aSlowID, NSFastLoadID *aResult) +{ + nsIDMapEntry* entry = + NS_STATIC_CAST(nsIDMapEntry*, + PL_DHashTableOperate(&mIDMap, &aSlowID, PL_DHASH_ADD)); + if (!entry) + return NS_ERROR_OUT_OF_MEMORY; + + if (entry->mFastID == 0) { + entry->mFastID = mIDMap.entryCount; + entry->mSlowID = aSlowID; + } + + *aResult = entry->mFastID; + return NS_OK; +} + +nsresult +nsFastLoadFileWriter::WriteHeader(nsFastLoadHeader *aHeader) +{ + nsresult rv; + PRUint32 bytesWritten; + + rv = Write(aHeader->mMagic, MFL_FILE_MAGIC_SIZE, &bytesWritten); + if (NS_FAILED(rv)) + return rv; + + if (bytesWritten != MFL_FILE_MAGIC_SIZE) + return NS_ERROR_FAILURE; + + rv = Write32(aHeader->mChecksum); + if (NS_FAILED(rv)) + return rv; + + rv = Write32(aHeader->mVersion); + if (NS_FAILED(rv)) + return rv; + + rv = Write32(aHeader->mFooterOffset); + if (NS_FAILED(rv)) + return rv; + + rv = Write32(aHeader->mFileSize); + if (NS_FAILED(rv)) + return rv; + + return NS_OK; +} + +// nsIFastLoadFileControl methods: + +NS_IMETHODIMP +nsFastLoadFileWriter::GetChecksum(PRUint32 *aChecksum) +{ + if (mHeader.mChecksum == 0) + return NS_ERROR_NOT_AVAILABLE; + *aChecksum = mHeader.mChecksum; + return NS_OK; +} + +NS_IMETHODIMP +nsFastLoadFileWriter::SetChecksum(PRUint32 aChecksum) +{ + mHeader.mChecksum = aChecksum; + return NS_OK; +} + +struct nsDocumentMapWriteEntry : public nsDocumentMapEntry { + PRUint32 mCurrentSegmentOffset; // last written segment's offset +}; + +// Fast mapping from URI object pointer back to spec-indexed document info. +// We also may need the slow mapping from mURISpec to nsDocumentMapWriteEntry, +// because the writer's mDocumentMap double hash table may grow "behind the +// back of" each mURIMap entry's mDocMapEntry member. +struct nsURIMapWriteEntry : public nsObjectMapEntry { + nsDocumentMapWriteEntry* mDocMapEntry; + PRUint32 mGeneration; + const char* mURISpec; +}; + +NS_IMETHODIMP +nsFastLoadFileWriter::HasMuxedDocument(const char* aURISpec, PRBool *aResult) +{ + nsDocumentMapWriteEntry* docMapEntry = + NS_STATIC_CAST(nsDocumentMapWriteEntry*, + PL_DHashTableOperate(&mDocumentMap, aURISpec, + PL_DHASH_LOOKUP)); + + *aResult = PL_DHASH_ENTRY_IS_BUSY(docMapEntry); + return NS_OK; +} + +NS_IMETHODIMP +nsFastLoadFileWriter::StartMuxedDocument(nsISupports* aURI, + const char* aURISpec) +{ + // Save mDocumentMap table generation and mCurrentDocumentMapEntry key in + // case the hash table grows during the PL_DHASH_ADD operation. + PRUint32 saveGeneration = mDocumentMap.generation; + const char* saveURISpec = mCurrentDocumentMapEntry + ? mCurrentDocumentMapEntry->mString + : nsnull; + + nsDocumentMapWriteEntry* docMapEntry = + NS_STATIC_CAST(nsDocumentMapWriteEntry*, + PL_DHashTableOperate(&mDocumentMap, aURISpec, + PL_DHASH_ADD)); + if (!docMapEntry) + return NS_ERROR_OUT_OF_MEMORY; + + // If the generation number changed, refresh mCurrentDocumentMapEntry. + if (mCurrentDocumentMapEntry && mDocumentMap.generation != saveGeneration) { + mCurrentDocumentMapEntry = + NS_STATIC_CAST(nsDocumentMapWriteEntry*, + PL_DHashTableOperate(&mDocumentMap, saveURISpec, + PL_DHASH_LOOKUP)); + NS_ASSERTION(PL_DHASH_ENTRY_IS_BUSY(mCurrentDocumentMapEntry), + "mCurrentDocumentMapEntry lost during table growth?!"); + + // Refresh saveGeneration for use below when initializing uriMapEntry. + saveGeneration = mDocumentMap.generation; + } + + NS_ASSERTION(docMapEntry->mString == nsnull, + "redundant multiplexed document?"); + if (docMapEntry->mString) + return NS_ERROR_UNEXPECTED; + + void* spec = nsMemory::Clone(aURISpec, strlen(aURISpec) + 1); + if (!spec) + return NS_ERROR_OUT_OF_MEMORY; + docMapEntry->mString = NS_REINTERPRET_CAST(const char*, spec); + docMapEntry->mURI = aURI; + NS_ADDREF(docMapEntry->mURI); + + nsCOMPtr key(do_QueryInterface(aURI)); + nsURIMapWriteEntry* uriMapEntry = + NS_STATIC_CAST(nsURIMapWriteEntry*, + PL_DHashTableOperate(&mURIMap, key, PL_DHASH_ADD)); + if (!uriMapEntry) + return NS_ERROR_OUT_OF_MEMORY; + + NS_ASSERTION(uriMapEntry->mDocMapEntry == nsnull, + "URI mapped to two different specs?"); + if (uriMapEntry->mDocMapEntry) + return NS_ERROR_UNEXPECTED; + + uriMapEntry->mObject = key; + NS_ADDREF(uriMapEntry->mObject); + uriMapEntry->mDocMapEntry = docMapEntry; + uriMapEntry->mGeneration = saveGeneration; + uriMapEntry->mURISpec = NS_REINTERPRET_CAST(const char*, spec); + TRACE_MUX(('w', "start %p (%p) %s\n", aURI, key.get(), aURISpec)); + return NS_OK; +} + +NS_IMETHODIMP +nsFastLoadFileWriter::SelectMuxedDocument(nsISupports* aURI, + nsISupports** aResult) +{ + // Avoid repeatedly QI'ing to nsISeekableStream as we tell and seek. + nsCOMPtr seekable(do_QueryInterface(mOutputStream)); + + // Capture the current file offset (XXXbe maintain our own via Write?) + nsresult rv; + PRInt64 currentSegmentOffset; + rv = seekable->Tell(¤tSegmentOffset); + if (NS_FAILED(rv)) + return rv; + + PRUint32 currentSegmentOffset32 = currentSegmentOffset; + // Look for an existing entry keyed by aURI, added by StartMuxedDocument. + nsCOMPtr key(do_QueryInterface(aURI)); + nsURIMapWriteEntry* uriMapEntry = + NS_STATIC_CAST(nsURIMapWriteEntry*, + PL_DHashTableOperate(&mURIMap, key, PL_DHASH_LOOKUP)); + NS_ASSERTION(PL_DHASH_ENTRY_IS_BUSY(uriMapEntry), + "SelectMuxedDocument without prior StartMuxedDocument?"); + if (PL_DHASH_ENTRY_IS_FREE(uriMapEntry)) + return NS_ERROR_UNEXPECTED; + + // Beware that uriMapEntry->mDocMapEntry may be stale, if an mDocumentMap + // addition caused that table to grow. We save the mDocumentMap generation + // in each uriMapEntry and compare it to the current generation, rehashing + // uriMapEntry->mURISpec if necessary. + + nsDocumentMapWriteEntry* docMapEntry = uriMapEntry->mDocMapEntry; + if (uriMapEntry->mGeneration != mDocumentMap.generation) { + docMapEntry = + NS_STATIC_CAST(nsDocumentMapWriteEntry*, + PL_DHashTableOperate(&mDocumentMap, + uriMapEntry->mURISpec, + PL_DHASH_LOOKUP)); + NS_ASSERTION(PL_DHASH_ENTRY_IS_BUSY(docMapEntry), "lost mDocMapEntry!?"); + uriMapEntry->mDocMapEntry = docMapEntry; + uriMapEntry->mGeneration = mDocumentMap.generation; + } + docMapEntry = uriMapEntry->mDocMapEntry; + + // If there is a muxed document segment open, close it now by setting its + // length, stored in the second PRUint32 of the segment. + nsDocumentMapWriteEntry* prevDocMapEntry = mCurrentDocumentMapEntry; + if (prevDocMapEntry) { + if (prevDocMapEntry == docMapEntry) { + TRACE_MUX(('w', "select prev %s same as current!\n", + prevDocMapEntry->mString)); + *aResult = docMapEntry->mURI; + NS_ADDREF(*aResult); + return NS_OK; + } + + PRUint32 prevSegmentOffset = prevDocMapEntry->mCurrentSegmentOffset; + TRACE_MUX(('w', "select prev %s offset %lu\n", + prevDocMapEntry->mString, prevSegmentOffset)); + + rv = seekable->Seek(nsISeekableStream::NS_SEEK_SET, + prevSegmentOffset + 4); + if (NS_FAILED(rv)) + return rv; + + // The length counts all bytes in the segment, including the header + // that contains [nextSegmentOffset, length]. + rv = Write32(currentSegmentOffset32 - prevSegmentOffset); + if (NS_FAILED(rv)) + return rv; + + // Seek back to the current offset only if we are not going to seek + // back to *this* entry's last "current" segment offset and write its + // next segment offset at the first PRUint32 of the segment. + if (!docMapEntry->mInitialSegmentOffset) { + rv = seekable->Seek(nsISeekableStream::NS_SEEK_SET, + currentSegmentOffset); + if (NS_FAILED(rv)) + return rv; + } + } + + // If this entry was newly added, set its key and initial segment offset. + // Otherwise, seek back to write the next segment offset of the previous + // segment for this document in the multiplex. + if (!docMapEntry->mInitialSegmentOffset) { + docMapEntry->mInitialSegmentOffset = currentSegmentOffset32; + } else { + rv = seekable->Seek(nsISeekableStream::NS_SEEK_SET, + docMapEntry->mCurrentSegmentOffset); + if (NS_FAILED(rv)) + return rv; + + rv = Write32(currentSegmentOffset32); + if (NS_FAILED(rv)) + return rv; + + rv = seekable->Seek(nsISeekableStream::NS_SEEK_SET, + currentSegmentOffset); + if (NS_FAILED(rv)) + return rv; + } + + // Update this document's current segment offset so we can later fix its + // next segment offset (unless it is last, in which case we leave the zero + // placeholder as a terminator). + docMapEntry->mCurrentSegmentOffset = currentSegmentOffset32; + + rv = Write32(0); // nextSegmentOffset placeholder + if (NS_FAILED(rv)) + return rv; + + rv = Write32(0); // length placeholder + if (NS_FAILED(rv)) + return rv; + + *aResult = prevDocMapEntry ? prevDocMapEntry->mURI : nsnull; + NS_IF_ADDREF(*aResult); + + mCurrentDocumentMapEntry = docMapEntry; + TRACE_MUX(('w', "select %p (%p) offset %lu\n", + aURI, key.get(), currentSegmentOffset)); + return NS_OK; +} + +NS_IMETHODIMP +nsFastLoadFileWriter::EndMuxedDocument(nsISupports* aURI) +{ + nsCOMPtr key(do_QueryInterface(aURI)); + nsURIMapWriteEntry* uriMapEntry = + NS_STATIC_CAST(nsURIMapWriteEntry*, + PL_DHashTableOperate(&mURIMap, key, PL_DHASH_LOOKUP)); + + // If the URI isn't in the map, nsFastLoadFileWriter::StartMuxedDocument + // must have been called with a redundant URI, *and* its caller must have + // ignored the NS_ERROR_UNEXPECTED it returned in that case. + if (PL_DHASH_ENTRY_IS_FREE(uriMapEntry)) { + TRACE_MUX(('w', "bad end %p (%p)\n", aURI, key.get())); + return NS_ERROR_UNEXPECTED; + } + + // Drop our ref to the URI object that was passed to StartMuxedDocument, + // we no longer need it, and we do not want to extend its lifetime. + if (uriMapEntry->mDocMapEntry) + NS_RELEASE(uriMapEntry->mDocMapEntry->mURI); + + // Shrink the table if half the entries are removed sentinels. + PRUint32 size = PL_DHASH_TABLE_SIZE(&mURIMap); + if (mURIMap.removedCount >= (size >> 2)) + PL_DHashTableOperate(&mURIMap, key, PL_DHASH_REMOVE); + else + PL_DHashTableRawRemove(&mURIMap, uriMapEntry); + + TRACE_MUX(('w', "end %p (%p)\n", aURI, key.get())); + return NS_OK; +} + +struct nsDependencyMapEntry : public nsStringMapEntry { + PRInt64 mLastModified; +}; + +NS_IMETHODIMP +nsFastLoadFileWriter::AddDependency(nsIFile* aFile) +{ + nsCAutoString path; + nsresult rv = aFile->GetNativePath(path); + if (NS_FAILED(rv)) + return rv; + + nsDependencyMapEntry* entry = + NS_STATIC_CAST(nsDependencyMapEntry*, + PL_DHashTableOperate(&mDependencyMap, path.get(), + PL_DHASH_ADD)); + if (!entry) + return NS_ERROR_OUT_OF_MEMORY; + + if (!entry->mString) { + const char *tmp = ToNewCString(path); + if (!tmp) + return NS_ERROR_OUT_OF_MEMORY; + entry->mString = tmp; + + // If we can't get the last modified time from aFile, assume it does + // not exist, or is otherwise inaccessible to us (due to permissions), + // remove the dependency, and suppress the failure. + // + // Otherwise, we would end up aborting the fastload process due to a + // missing .js or .xul or other file on every startup. + + rv = aFile->GetLastModifiedTime(&entry->mLastModified); + if (NS_FAILED(rv)) { + PL_DHashTableOperate(&mDependencyMap, path.get(), PL_DHASH_REMOVE); + rv = NS_OK; + } + } + return rv; +} + +nsresult +nsFastLoadFileWriter::WriteFooterPrefix(const nsFastLoadFooterPrefix& aFooterPrefix) +{ + nsresult rv; + + rv = Write32(aFooterPrefix.mNumIDs); + if (NS_FAILED(rv)) + return rv; + + rv = Write32(aFooterPrefix.mNumSharpObjects); + if (NS_FAILED(rv)) + return rv; + + rv = Write32(aFooterPrefix.mNumMuxedDocuments); + if (NS_FAILED(rv)) + return rv; + + rv = Write32(aFooterPrefix.mNumDependencies); + if (NS_FAILED(rv)) + return rv; + + return NS_OK; +} + +nsresult +nsFastLoadFileWriter::WriteSlowID(const nsID& aID) +{ + nsresult rv; + + rv = Write32(aID.m0); + if (NS_FAILED(rv)) + return rv; + + rv = Write16(aID.m1); + if (NS_FAILED(rv)) + return rv; + + rv = Write16(aID.m2); + if (NS_FAILED(rv)) + return rv; + + PRUint32 bytesWritten; + rv = Write(NS_REINTERPRET_CAST(const char*, aID.m3), sizeof aID.m3, + &bytesWritten); + if (NS_FAILED(rv)) + return rv; + + if (bytesWritten != sizeof aID.m3) + return NS_ERROR_FAILURE; + return NS_OK; +} + +nsresult +nsFastLoadFileWriter::WriteFastID(NSFastLoadID aID) +{ + return Write32(aID ^ MFL_ID_XOR_KEY); +} + +nsresult +nsFastLoadFileWriter::WriteSharpObjectInfo(const nsFastLoadSharpObjectInfo& aInfo) +{ + nsresult rv; + + NS_ASSERTION(aInfo.mCIDOffset != 0, + "fastload writer: mCIDOffset cannot be zero!"); + + rv = Write32(aInfo.mCIDOffset); + if (NS_FAILED(rv)) + return rv; + + rv = Write16(aInfo.mStrongRefCnt); + if (NS_FAILED(rv)) + return rv; + + rv = Write16(aInfo.mWeakRefCnt); + if (NS_FAILED(rv)) + return rv; + + return NS_OK; +} + +nsresult +nsFastLoadFileWriter::WriteMuxedDocumentInfo(const nsFastLoadMuxedDocumentInfo& aInfo) +{ + nsresult rv; + + rv = WriteStringZ(aInfo.mURISpec); + if (NS_FAILED(rv)) + return rv; + + rv = Write32(aInfo.mInitialSegmentOffset); + if (NS_FAILED(rv)) + return rv; + + return NS_OK; +} + +PLDHashOperator PR_CALLBACK +nsFastLoadFileWriter::IDMapEnumerate(PLDHashTable *aTable, + PLDHashEntryHdr *aHdr, + PRUint32 aNumber, + void *aData) +{ + nsIDMapEntry* entry = NS_STATIC_CAST(nsIDMapEntry*, aHdr); + PRUint32 index = entry->mFastID - 1; + nsID* vector = NS_REINTERPRET_CAST(nsID*, aData); + + NS_ASSERTION(index < aTable->entryCount, "bad nsIDMap index!"); + vector[index] = entry->mSlowID; + return PL_DHASH_NEXT; +} + +struct nsSharpObjectMapEntry : public nsObjectMapEntry { + NSFastLoadOID mOID; + nsFastLoadSharpObjectInfo mInfo; +}; + +PLDHashOperator PR_CALLBACK +nsFastLoadFileWriter::ObjectMapEnumerate(PLDHashTable *aTable, + PLDHashEntryHdr *aHdr, + PRUint32 aNumber, + void *aData) +{ + nsSharpObjectMapEntry* entry = NS_STATIC_CAST(nsSharpObjectMapEntry*, aHdr); + PRUint32 index = MFL_OID_TO_SHARP_INDEX(entry->mOID); + nsFastLoadSharpObjectInfo* vector = + NS_REINTERPRET_CAST(nsFastLoadSharpObjectInfo*, aData); + + NS_ASSERTION(index < aTable->entryCount, "bad nsObjectMap index!"); + vector[index] = entry->mInfo; + + NS_ASSERTION(entry->mInfo.mStrongRefCnt, "no strong ref in serialization!"); + + // Ignore tagged object ids stored as object pointer keys (the updater + // code does this). + if ((NS_PTR_TO_INT32(entry->mObject) & MFL_OBJECT_DEF_TAG) == 0) + NS_RELEASE(entry->mObject); + + return PL_DHASH_NEXT; +} + +PLDHashOperator PR_CALLBACK +nsFastLoadFileWriter::DocumentMapEnumerate(PLDHashTable *aTable, + PLDHashEntryHdr *aHdr, + PRUint32 aNumber, + void *aData) +{ + nsFastLoadFileWriter* writer = + NS_REINTERPRET_CAST(nsFastLoadFileWriter*, aTable->data); + nsDocumentMapWriteEntry* entry = + NS_STATIC_CAST(nsDocumentMapWriteEntry*, aHdr); + nsresult* rvp = NS_REINTERPRET_CAST(nsresult*, aData); + + nsFastLoadMuxedDocumentInfo info; + info.mURISpec = entry->mString; + info.mInitialSegmentOffset = entry->mInitialSegmentOffset; + *rvp = writer->WriteMuxedDocumentInfo(info); + + return NS_FAILED(*rvp) ? PL_DHASH_STOP : PL_DHASH_NEXT; +} + +PLDHashOperator PR_CALLBACK +nsFastLoadFileWriter::DependencyMapEnumerate(PLDHashTable *aTable, + PLDHashEntryHdr *aHdr, + PRUint32 aNumber, + void *aData) +{ + nsFastLoadFileWriter* writer = + NS_REINTERPRET_CAST(nsFastLoadFileWriter*, aTable->data); + nsDependencyMapEntry* entry = NS_STATIC_CAST(nsDependencyMapEntry*, aHdr); + nsresult* rvp = NS_REINTERPRET_CAST(nsresult*, aData); + + *rvp = writer->WriteStringZ(entry->mString); + if (NS_SUCCEEDED(*rvp)) + *rvp = writer->Write64(entry->mLastModified); + + return NS_FAILED(*rvp) ? PL_DHASH_STOP :PL_DHASH_NEXT; +} + +nsresult +nsFastLoadFileWriter::WriteFooter() +{ + nsresult rv; + PRUint32 i, count; + + nsFastLoadFooterPrefix footerPrefix; + footerPrefix.mNumIDs = mIDMap.entryCount; + footerPrefix.mNumSharpObjects = mObjectMap.entryCount; + footerPrefix.mNumMuxedDocuments = mDocumentMap.entryCount; + footerPrefix.mNumDependencies = mDependencyMap.entryCount; + + rv = WriteFooterPrefix(footerPrefix); + if (NS_FAILED(rv)) + return rv; + + // Enumerate mIDMap into a vector indexed by mFastID and write it. + nsID* idvec = new nsID[footerPrefix.mNumIDs]; + if (!idvec) + return NS_ERROR_OUT_OF_MEMORY; + + count = PL_DHashTableEnumerate(&mIDMap, IDMapEnumerate, idvec); + NS_ASSERTION(count == footerPrefix.mNumIDs, "bad mIDMap enumeration!"); + for (i = 0; i < count; i++) { + rv = WriteSlowID(idvec[i]); + if (NS_FAILED(rv)) break; + } + + delete[] idvec; + if (NS_FAILED(rv)) + return rv; + + // Enumerate mObjectMap into a vector indexed by mOID and write it. + nsFastLoadSharpObjectInfo* objvec = + new nsFastLoadSharpObjectInfo[footerPrefix.mNumSharpObjects]; + if (!objvec) + return NS_ERROR_OUT_OF_MEMORY; +#ifdef NS_DEBUG + memset(objvec, 0, footerPrefix.mNumSharpObjects * + sizeof(nsFastLoadSharpObjectInfo)); +#endif + + count = PL_DHashTableEnumerate(&mObjectMap, ObjectMapEnumerate, objvec); + NS_ASSERTION(count == footerPrefix.mNumSharpObjects, + "bad mObjectMap enumeration!"); + for (i = 0; i < count; i++) { + rv = WriteSharpObjectInfo(objvec[i]); + if (NS_FAILED(rv)) break; + } + + delete[] objvec; + if (NS_FAILED(rv)) + return rv; + + // Enumerate mDocumentMap, writing nsFastLoadMuxedDocumentInfo records + count = PL_DHashTableEnumerate(&mDocumentMap, DocumentMapEnumerate, &rv); + if (NS_FAILED(rv)) + return rv; + + NS_ASSERTION(count == footerPrefix.mNumMuxedDocuments, + "bad mDocumentMap enumeration!"); + + // Write out make-like file dependencies. + count = PL_DHashTableEnumerate(&mDependencyMap, DependencyMapEnumerate, &rv); + if (NS_FAILED(rv)) + return rv; + + return NS_OK; +} + +nsresult +nsFastLoadFileWriter::Init() +{ + if (!PL_DHashTableInit(&mIDMap, &idmap_DHashTableOps, (void *)this, + sizeof(nsIDMapEntry), PL_DHASH_MIN_SIZE)) { + mIDMap.ops = nsnull; + return NS_ERROR_OUT_OF_MEMORY; + } + + if (!PL_DHashTableInit(&mObjectMap, &objmap_DHashTableOps, (void *)this, + sizeof(nsSharpObjectMapEntry), PL_DHASH_MIN_SIZE)) { + mObjectMap.ops = nsnull; + return NS_ERROR_OUT_OF_MEMORY; + } + + if (!PL_DHashTableInit(&mDocumentMap, &strmap_DHashTableOps, (void *)this, + sizeof(nsDocumentMapWriteEntry), + PL_DHASH_MIN_SIZE)) { + mDocumentMap.ops = nsnull; + return NS_ERROR_OUT_OF_MEMORY; + } + + if (!PL_DHashTableInit(&mURIMap, &objmap_DHashTableOps, (void *)this, + sizeof(nsURIMapWriteEntry), PL_DHASH_MIN_SIZE)) { + mURIMap.ops = nsnull; + return NS_ERROR_OUT_OF_MEMORY; + } + + if (!PL_DHashTableInit(&mDependencyMap, &strmap_DHashTableOps, (void *)this, + sizeof(nsDependencyMapEntry), PL_DHASH_MIN_SIZE)) { + mDependencyMap.ops = nsnull; + return NS_ERROR_OUT_OF_MEMORY; + } + + return NS_OK; +} + +nsresult +nsFastLoadFileWriter::Open() +{ + nsCOMPtr seekable(do_QueryInterface(mOutputStream)); + if (!seekable) + return NS_ERROR_UNEXPECTED; + + nsresult rv; + + rv = seekable->Seek(nsISeekableStream::NS_SEEK_SET, + sizeof(nsFastLoadHeader)); + if (NS_FAILED(rv)) + return rv; + + return Init(); +} + +NS_IMETHODIMP +nsFastLoadFileWriter::Close() +{ + nsresult rv; + + memcpy(mHeader.mMagic, magic, MFL_FILE_MAGIC_SIZE); + mHeader.mChecksum = 0; + mHeader.mVersion = MFL_FILE_VERSION; + + nsCOMPtr seekable(do_QueryInterface(mOutputStream)); + + PRInt64 footerOffset; + rv = seekable->Tell(&footerOffset); + + LL_L2UI(mHeader.mFooterOffset, footerOffset); + if (NS_FAILED(rv)) + return rv; + + // If there is a muxed document segment open, close it now by setting its + // length, stored in the second PRUint32 of the segment. + if (mCurrentDocumentMapEntry) { + PRUint32 currentSegmentOffset = + mCurrentDocumentMapEntry->mCurrentSegmentOffset; + rv = seekable->Seek(nsISeekableStream::NS_SEEK_SET, + currentSegmentOffset + 4); + if (NS_FAILED(rv)) + return rv; + + rv = Write32(mHeader.mFooterOffset - currentSegmentOffset); + if (NS_FAILED(rv)) + return rv; + + // Seek back to the current offset to write the footer. + rv = seekable->Seek(nsISeekableStream::NS_SEEK_SET, + mHeader.mFooterOffset); + if (NS_FAILED(rv)) + return rv; + + mCurrentDocumentMapEntry = nsnull; + } + + rv = WriteFooter(); + if (NS_FAILED(rv)) + return rv; + PRInt64 fileSize; + rv = seekable->Tell(&fileSize); + LL_L2UI(mHeader.mFileSize, fileSize); + if (NS_FAILED(rv)) + return rv; + + rv = seekable->Seek(nsISeekableStream::NS_SEEK_SET, 0); + if (NS_FAILED(rv)) + return rv; + + rv = WriteHeader(&mHeader); + if (NS_FAILED(rv)) + return rv; + + // Now compute the checksum, using mFileIO to get an input stream on the + // underlying FastLoad file. + if (mFileIO) { + // Get the unbuffered output stream, which flushes the buffered header + // so we can read and checksum it along with the rest of the file, and + // which allows us to write the checksum directly. + nsCOMPtr + bufferAccess(do_QueryInterface(mOutputStream)); + nsCOMPtr output; + rv = bufferAccess->GetUnbufferedStream(getter_AddRefs(output)); + if (NS_FAILED(rv) || !output) + return NS_ERROR_UNEXPECTED; + + nsCOMPtr input; + rv = mFileIO->GetInputStream(getter_AddRefs(input)); + if (NS_FAILED(rv)) + return rv; + + // Get the unbuffered input stream, to avoid copying overhead and to + // keep our view of the file coherent with the writer -- we don't want + // to hit a stale buffer in the reader's underlying stream. + bufferAccess = do_QueryInterface(input); + rv = bufferAccess->GetUnbufferedStream(getter_AddRefs(input)); + if (NS_FAILED(rv) || !input) + return NS_ERROR_UNEXPECTED; + + // Seek the input stream to offset 0, in case it's a reader who has + // already been used to consume some of the FastLoad file. + seekable = do_QueryInterface(input); + rv = seekable->Seek(nsISeekableStream::NS_SEEK_SET, 0); + if (NS_FAILED(rv)) + return rv; + + char buf[MFL_CHECKSUM_BUFSIZE]; + PRUint32 len, rem = 0; + PRUint32 checksum = 0; + + // Ok, we're finally ready to checksum the FastLoad file we just wrote! + while (NS_SUCCEEDED(rv = + input->Read(buf + rem, sizeof buf - rem, &len)) && + len) { + len += rem; + rem = NS_AccumulateFastLoadChecksum(&checksum, + NS_REINTERPRET_CAST(PRUint8*, + buf), + len, + PR_FALSE); + if (rem) + memcpy(buf, buf + len - rem, rem); + } + if (NS_FAILED(rv)) + return rv; + + if (rem) { + NS_AccumulateFastLoadChecksum(&checksum, + NS_REINTERPRET_CAST(PRUint8*, buf), + rem, + PR_TRUE); + } + + // Store the checksum in the FastLoad file header and remember it via + // mHeader.mChecksum, for GetChecksum. + seekable = do_QueryInterface(output); + rv = seekable->Seek(nsISeekableStream::NS_SEEK_SET, + offsetof(nsFastLoadHeader, mChecksum)); + if (NS_FAILED(rv)) + return rv; + + mHeader.mChecksum = checksum; + checksum = NS_SWAP32(checksum); + PRUint32 bytesWritten; + rv = output->Write(NS_REINTERPRET_CAST(char*, &checksum), + sizeof checksum, + &bytesWritten); + if (NS_FAILED(rv)) + return rv; + if (bytesWritten != sizeof checksum) + return NS_ERROR_FAILURE; + } + + return mOutputStream->Close(); +} + +// Psuedo-tag used as flag between WriteSingleRefObject and WriteObjectCommon. +#define MFL_SINGLE_REF_PSEUDO_TAG PR_BIT(MFL_OBJECT_TAG_BITS) + +nsresult +nsFastLoadFileWriter::WriteObjectCommon(nsISupports* aObject, + PRBool aIsStrongRef, + PRUint32 aTags) +{ + nsrefcnt rc; + nsresult rv; + + NS_ASSERTION((NS_PTR_TO_INT32(aObject) & MFL_OBJECT_DEF_TAG) == 0, + "odd nsISupports*, oh no!"); + + // Here be manual refcounting dragons! + rc = aObject->AddRef(); + NS_ASSERTION(rc != 0, "bad refcnt when writing aObject!"); + + NSFastLoadOID oid; + nsCOMPtr classInfo; + + if (rc == 2 && (aTags & MFL_SINGLE_REF_PSEUDO_TAG)) { + // Dull object: only one strong ref and no weak refs in serialization. + // Conservative: we don't trust the caller if there are more than two + // refs (one from the AddRef above, one from the data structure that's + // being serialized). + oid = MFL_DULL_OBJECT_OID; + aObject->Release(); + } else { + // Object is presumed to be multiply connected through some combo of + // strong and weak refs. Hold onto it via mObjectMap. + nsSharpObjectMapEntry* entry = + NS_STATIC_CAST(nsSharpObjectMapEntry*, + PL_DHashTableOperate(&mObjectMap, aObject, + PL_DHASH_ADD)); + if (!entry) { + aObject->Release(); + return NS_ERROR_OUT_OF_MEMORY; + } + + if (!entry->mObject) { + // First time we've seen this object address: add it to mObjectMap + // and serialize the object at the current stream offset. + PRInt64 thisOffset; + rv = Tell(&thisOffset); + if (NS_FAILED(rv)) { + aObject->Release(); + return rv; + } + + // NB: aObject was already held, and mObject is a raw nsISupports*. + entry->mObject = aObject; + + oid = (mObjectMap.entryCount << MFL_OBJECT_TAG_BITS); + entry->mOID = oid; + + // NB: the (32-bit, fast) CID and object data follow the OID. + entry->mInfo.mCIDOffset = thisOffset + sizeof(oid); + entry->mInfo.mStrongRefCnt = aIsStrongRef ? 1 : 0; + entry->mInfo.mWeakRefCnt = aIsStrongRef ? 0 : 1; + + // Record in oid the fact that we're defining this object in the + // stream, and get the object's class info here, so we can take + // note of singletons in order to avoid reserializing them when + // updating after reading. + oid |= MFL_OBJECT_DEF_TAG; + classInfo = do_QueryInterface(aObject); + if (!classInfo) + return NS_ERROR_FAILURE; + + PRUint32 flags; + if (NS_SUCCEEDED(classInfo->GetFlags(&flags)) && + (flags & nsIClassInfo::SINGLETON)) { + MFL_SET_SINGLETON_FLAG(&entry->mInfo); + } + } else { + // Already serialized, recover oid and update the desired refcnt. + oid = entry->mOID; + if (aIsStrongRef) { + ++entry->mInfo.mStrongRefCnt; + NS_ASSERTION(entry->mInfo.mStrongRefCnt != 0, + "mStrongRefCnt overflow"); + } else { + MFL_BUMP_WEAK_REFCNT(&entry->mInfo); + NS_ASSERTION(MFL_GET_WEAK_REFCNT(&entry->mInfo) != 0, + "mWeakRefCnt overflow"); + } + + aObject->Release(); + } + } + + if (!aIsStrongRef) + oid |= MFL_WEAK_REF_TAG; + oid |= (aTags & MFL_QUERY_INTERFACE_TAG); + + rv = Write32(oid ^ MFL_OID_XOR_KEY); + if (NS_FAILED(rv)) + return rv; + + if (oid & MFL_OBJECT_DEF_TAG) { + nsCOMPtr serializable(do_QueryInterface(aObject)); + if (!serializable) + return NS_ERROR_FAILURE; + + nsCID slowCID; + rv = classInfo->GetClassIDNoAlloc(&slowCID); + if (NS_FAILED(rv)) + return rv; + + NSFastLoadID fastCID; + rv = MapID(slowCID, &fastCID); + if (NS_FAILED(rv)) + return rv; + + rv = WriteFastID(fastCID); + if (NS_FAILED(rv)) + return rv; + + rv = serializable->Write(this); + if (NS_FAILED(rv)) + return rv; + } + + return NS_OK; +} + +NS_IMETHODIMP +nsFastLoadFileWriter::WriteObject(nsISupports* aObject, PRBool aIsStrongRef) +{ +#ifdef NS_DEBUG + nsCOMPtr rootObject(do_QueryInterface(aObject)); + + NS_ASSERTION(rootObject.get() == aObject, + "bad call to WriteObject -- call WriteCompoundObject!"); +#endif + + return WriteObjectCommon(aObject, aIsStrongRef, 0); +} + +NS_IMETHODIMP +nsFastLoadFileWriter::WriteSingleRefObject(nsISupports* aObject) +{ +#ifdef NS_DEBUG + nsCOMPtr rootObject(do_QueryInterface(aObject)); + + NS_ASSERTION(rootObject.get() == aObject, + "bad call to WriteSingleRefObject -- call WriteCompoundObject!"); +#endif + + return WriteObjectCommon(aObject, PR_TRUE, MFL_SINGLE_REF_PSEUDO_TAG); +} + +NS_IMETHODIMP +nsFastLoadFileWriter::WriteCompoundObject(nsISupports* aObject, + const nsIID& aIID, + PRBool aIsStrongRef) +{ + nsresult rv; + nsCOMPtr rootObject(do_QueryInterface(aObject)); + +#ifdef NS_DEBUG + nsCOMPtr roundtrip; + rootObject->QueryInterface(aIID, getter_AddRefs(roundtrip)); + + NS_ASSERTION(rootObject.get() != aObject, + "wasteful call to WriteCompoundObject -- call WriteObject!"); + NS_ASSERTION(roundtrip.get() == aObject, + "bad aggregation or multiple inheritance detected by call to " + "WriteCompoundObject!"); +#endif + + rv = WriteObjectCommon(rootObject, aIsStrongRef, MFL_QUERY_INTERFACE_TAG); + if (NS_FAILED(rv)) + return rv; + + NSFastLoadID iid; + rv = MapID(aIID, &iid); + if (NS_FAILED(rv)) + return rv; + + return WriteFastID(iid); +} + +NS_IMETHODIMP +nsFastLoadFileWriter::WriteID(const nsID& aID) +{ + nsresult rv; + NSFastLoadID fastID; + + rv = MapID(aID, &fastID); + if (NS_FAILED(rv)) + return rv; + + return WriteFastID(fastID); +} + +NS_IMETHODIMP +nsFastLoadFileWriter::Seek(PRInt32 aWhence, PRInt64 aOffset) +{ + mCurrentDocumentMapEntry = nsnull; + nsCOMPtr seekable(do_QueryInterface(mOutputStream)); + return seekable->Seek(aWhence, aOffset); +} + +NS_IMETHODIMP +nsFastLoadFileWriter::Tell(PRInt64 *aResult) +{ + nsCOMPtr seekable(do_QueryInterface(mOutputStream)); + return seekable->Tell(aResult); +} + +NS_IMETHODIMP +nsFastLoadFileWriter::SetEOF() +{ + nsCOMPtr seekable(do_QueryInterface(mOutputStream)); + return seekable->SetEOF(); +} + +NS_COM nsresult +NS_NewFastLoadFileWriter(nsIObjectOutputStream* *aResult, + nsIOutputStream* aDestStream, + nsIFastLoadFileIO* aFileIO) +{ + nsFastLoadFileWriter* writer = + new nsFastLoadFileWriter(aDestStream, aFileIO); + if (!writer) + return NS_ERROR_OUT_OF_MEMORY; + + // Stabilize writer's refcnt. + nsCOMPtr stream(writer); + + nsresult rv = writer->Open(); + if (NS_FAILED(rv)) + return rv; + + *aResult = stream; + NS_ADDREF(*aResult); + return NS_OK; +} + +// -------------------------- nsFastLoadFileUpdater -------------------------- + +NS_IMPL_ISUPPORTS_INHERITED1(nsFastLoadFileUpdater, + nsFastLoadFileWriter, + nsIFastLoadFileIO) + +NS_IMETHODIMP +nsFastLoadFileUpdater::GetInputStream(nsIInputStream** aResult) +{ + *aResult = mInputStream; + NS_IF_ADDREF(*aResult); + return NS_OK; +} + +NS_IMETHODIMP +nsFastLoadFileUpdater::GetOutputStream(nsIOutputStream** aResult) +{ + *aResult = nsnull; + return NS_OK; +} + +PLDHashOperator PR_CALLBACK +nsFastLoadFileUpdater::CopyReadDocumentMapEntryToUpdater(PLDHashTable *aTable, + PLDHashEntryHdr *aHdr, + PRUint32 aNumber, + void *aData) +{ + nsDocumentMapReadEntry* readEntry = + NS_STATIC_CAST(nsDocumentMapReadEntry*, aHdr); + nsFastLoadFileUpdater* updater = + NS_REINTERPRET_CAST(nsFastLoadFileUpdater*, aData); + + void* spec = nsMemory::Clone(readEntry->mString, + strlen(readEntry->mString) + 1); + if (!spec) + return PL_DHASH_STOP; + + nsDocumentMapWriteEntry* writeEntry = + NS_STATIC_CAST(nsDocumentMapWriteEntry*, + PL_DHashTableOperate(&updater->mDocumentMap, spec, + PL_DHASH_ADD)); + if (!writeEntry) { + nsMemory::Free(spec); + return PL_DHASH_STOP; + } + + writeEntry->mString = NS_REINTERPRET_CAST(const char*, spec); + writeEntry->mURI = nsnull; + writeEntry->mInitialSegmentOffset = readEntry->mInitialSegmentOffset; + writeEntry->mCurrentSegmentOffset = 0; + return PL_DHASH_NEXT; +} + +nsresult +nsFastLoadFileUpdater::Open(nsFastLoadFileReader* aReader) +{ + nsCOMPtr seekable(do_QueryInterface(mOutputStream)); + if (!seekable) + return NS_ERROR_UNEXPECTED; + + nsresult rv; + rv = nsFastLoadFileWriter::Init(); + if (NS_FAILED(rv)) + return rv; + + PRUint32 i, n; + + // Map from dense, zero-based, uint32 NSFastLoadID in reader to 16-byte + // nsID in updater. + nsID* readIDMap = aReader->mFooter.mIDMap; + for (i = 0, n = aReader->mFooter.mNumIDs; i < n; i++) { + NSFastLoadID fastID; + rv = MapID(readIDMap[i], &fastID); + NS_ASSERTION(fastID == i + 1, "huh?"); + if (NS_FAILED(rv)) + return rv; + } + + // Map from reader dense, zero-based MFL_OID_TO_SHARP_INDEX(oid) to sharp + // object offset and refcnt information in updater. + nsFastLoadFileReader::nsObjectMapEntry* readObjectMap = + aReader->mFooter.mObjectMap; + + // Prepare to save aReader state in case we need to seek back and read a + // singleton object that might otherwise get written by this updater. + nsDocumentMapReadEntry* saveDocMapEntry = nsnull; + nsCOMPtr inputSeekable; + PRInt64 saveOffset = 0; + + for (i = 0, n = aReader->mFooter.mNumSharpObjects; i < n; i++) { + nsFastLoadFileReader::nsObjectMapEntry* readEntry = &readObjectMap[i]; + + NS_ASSERTION(readEntry->mCIDOffset != 0, + "fastload updater: mCIDOffset cannot be zero!"); + + // If the reader didn't read this object but it's a singleton, we must + // "deserialize" it now, to discover its one and only root nsISupports + // address. The object already exists in memory if it was created at + // startup without resort to the FastLoad file. The canonical example + // is the system principal object held by all XUL JS scripts. + + nsISupports* obj = readEntry->mReadObject; + if (!obj && MFL_GET_SINGLETON_FLAG(readEntry)) { + if (!saveDocMapEntry) { + inputSeekable = do_QueryInterface(aReader->mInputStream); + rv = inputSeekable->Tell(&saveOffset); + if (NS_FAILED(rv)) + return rv; + + saveDocMapEntry = aReader->mCurrentDocumentMapEntry; + aReader->mCurrentDocumentMapEntry = nsnull; + } + + rv = inputSeekable->Seek(nsISeekableStream::NS_SEEK_SET, + readEntry->mCIDOffset); + if (NS_FAILED(rv)) + return rv; + + rv = aReader + ->DeserializeObject(getter_AddRefs(readEntry->mReadObject)); + if (NS_FAILED(rv)) + return rv; + obj = readEntry->mReadObject; + + // Don't forget to set mSkipOffset in case someone calls the reader + // to "deserialize" (yet again) the object we just read. + // + // Say the singleton is the system principal, and the FastLoad file + // contains data for navigator.xul including scripts and functions. + // If we update the FastLoad file to contain data for messenger.xul + // in a separate session started via mozilla -mail, *and during the + // same FastLoad episode in this session* race to open a navigator + // window, we will attempt to read all objects serialized in the + // navigator.xul portion of the FastLoad file. + // + // mSkipOffset must be set in such a case so the reader can skip + // the system principal's serialized data, because the updater for + // messenger.xul being opened here has already read it. + + rv = inputSeekable->Tell(&readEntry->mSkipOffset); + if (NS_FAILED(rv)) + return rv; + } + + NSFastLoadOID oid = MFL_SHARP_INDEX_TO_OID(i); + void* key = obj + ? NS_REINTERPRET_CAST(void*, obj) + : NS_REINTERPRET_CAST(void*, (oid | MFL_OBJECT_DEF_TAG)); + + nsSharpObjectMapEntry* writeEntry = + NS_STATIC_CAST(nsSharpObjectMapEntry*, + PL_DHashTableOperate(&mObjectMap, key, + PL_DHASH_ADD)); + if (!writeEntry) + return NS_ERROR_OUT_OF_MEMORY; + + // Hold the object if there is one, so that objmap_ClearEntry can + // release the reference. + NS_IF_ADDREF(obj); + writeEntry->mObject = NS_REINTERPRET_CAST(nsISupports*, key); + writeEntry->mOID = oid; + writeEntry->mInfo.mCIDOffset = readEntry->mCIDOffset; + writeEntry->mInfo.mStrongRefCnt = readEntry->mSaveStrongRefCnt; + writeEntry->mInfo.mWeakRefCnt = readEntry->mSaveWeakRefCnt; + } + + // If we had to read any singletons, restore aReader's saved state. + if (saveDocMapEntry) { + rv = inputSeekable->Seek(nsISeekableStream::NS_SEEK_SET, saveOffset); + if (NS_FAILED(rv)) + return rv; + + aReader->mCurrentDocumentMapEntry = saveDocMapEntry; + } + + // Copy URI spec string and initial segment offset in FastLoad file from + // nsDocumentMapReadEntry in reader to nsDocumentMapWriteEntry in updater. + // If we didn't enumerate all entries, we ran out of memory. + n = PL_DHashTableEnumerate(&aReader->mFooter.mDocumentMap, + CopyReadDocumentMapEntryToUpdater, + this); + if (n != aReader->mFooter.mDocumentMap.entryCount) + return NS_ERROR_OUT_OF_MEMORY; + + // Copy source filename dependencies from reader to updater. + nsISupportsArray* readDeps = aReader->mFooter.mDependencies; + rv = readDeps->Count(&n); + if (NS_FAILED(rv)) + return rv; + + for (i = 0; i < n; i++) { + nsCOMPtr file; + rv = readDeps->GetElementAt(i, getter_AddRefs(file)); + if (NS_FAILED(rv)) + return rv; + + rv = AddDependency(file); + if (NS_FAILED(rv)) + return rv; + } + + // Seek to the reader's footer offset so we overwrite the footer. First, + // update the header to have a zero mFooterOffset, which will invalidate + // the FastLoad file on next startup read attempt, should we crash before + // completing this update. + rv = seekable->Seek(nsISeekableStream::NS_SEEK_SET, + offsetof(nsFastLoadHeader, mFooterOffset)); + if (NS_FAILED(rv)) + return rv; + + rv = Write32(0); + if (NS_FAILED(rv)) + return rv; + + rv = seekable->Seek(nsISeekableStream::NS_SEEK_SET, + aReader->mHeader.mFooterOffset); + if (NS_FAILED(rv)) + return rv; + + // Avoid creating yet another object by implementing nsIFastLoadFileIO on + // this updater, and save aReader's input stream so it can be returned by + // GetInputStream called from nsFastLoadFileWriter::Close. This requires + // that we override Close to break the resulting zero-length cycle. + mFileIO = this; + mInputStream = aReader->mInputStream; + return NS_OK; +} + +NS_IMETHODIMP +nsFastLoadFileUpdater::Close() +{ + // Call base-class Close implementation, which uses mFileIO. + nsresult rv = nsFastLoadFileWriter::Close(); + + // Break degenerate cycle from this->mFileIO to this. + mFileIO = nsnull; + return rv; +} + +NS_COM nsresult +NS_NewFastLoadFileUpdater(nsIObjectOutputStream* *aResult, + nsIOutputStream* aOutputStream, + nsIObjectInputStream* aReaderAsStream) +{ + // Make sure that aReaderAsStream is an nsFastLoadFileReader. + nsCOMPtr reader(do_QueryInterface(aReaderAsStream)); + if (!reader) + return NS_ERROR_UNEXPECTED; + + nsFastLoadFileUpdater* updater = new nsFastLoadFileUpdater(aOutputStream); + if (!updater) + return NS_ERROR_OUT_OF_MEMORY; + + // Stabilize updater's refcnt. + nsCOMPtr stream(updater); + + nsresult rv = updater->Open(NS_STATIC_CAST(nsFastLoadFileReader*, + aReaderAsStream)); + if (NS_FAILED(rv)) + return rv; + + *aResult = stream; + NS_ADDREF(*aResult); + return NS_OK; +} diff --git a/src/libs/xpcom18a4/xpcom/io/nsFastLoadFile.h b/src/libs/xpcom18a4/xpcom/io/nsFastLoadFile.h new file mode 100644 index 00000000..9f6f061a --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsFastLoadFile.h @@ -0,0 +1,566 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 FastLoad code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Brendan Eich (original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +#ifndef nsFastLoadFile_h___ +#define nsFastLoadFile_h___ + +/** + * Mozilla FastLoad file format and helper types. + */ + +#include "prtypes.h" +#include "pldhash.h" + +#include "nsBinaryStream.h" +#include "nsCOMPtr.h" +#include "nsDebug.h" +#include "nsID.h" +#include "nsMemory.h" +#include "nsVoidArray.h" + +#include "nsIFastLoadFileControl.h" +#include "nsIFastLoadService.h" +#include "nsISeekableStream.h" +#include "nsISupportsArray.h" + +/** + * FastLoad file Object ID (OID) is an identifier for multiply and cyclicly + * connected objects in the serialized graph of all reachable objects. + * + * Holy Mixed Metaphors: JS, after Common Lisp, uses #n= to define a "sharp + * variable" naming an object that's multiply or cyclicly connected, and #n# + * to stand for a connection to an already-defined object. We too call any + * object with multiple references "sharp", and (here it comes) any object + * with only one reference "dull". + * + * Note that only sharp objects require a mapping from OID to FastLoad file + * offset and other information. Dull objects can be serialized _in situ_ + * (where they are referenced) and deserialized when their (singular, shared) + * OID is scanned. + * + * We also compress 16-byte XPCOM IDs into 32-bit dense identifiers to save + * space. See nsFastLoadFooter, below, for the mapping data structure used to + * compute an nsID given an NSFastLoadID. + */ +typedef PRUint32 NSFastLoadID; // nsFastLoadFooter::mIDMap index +typedef PRUint32 NSFastLoadOID; // nsFastLoadFooter::mObjectMap index + +/** + * A Mozilla FastLoad file is an untagged (in general) stream of objects and + * primitive-type data. Small integers are fairly common, and could easily be + * confused for NSFastLoadIDs and NSFastLoadOIDs. To help catch bugs where + * reader and writer code fail to match, we XOR unlikely 32-bit numbers with + * NSFastLoad*IDs when storing and fetching. The following unlikely values are + * irrational numbers ((sqrt(5)-1)/2, sqrt(2)-1) represented in fixed point. + * + * The reader XORs, converts the ID to an index, and bounds-checks all array + * accesses that use the index. Array access code asserts that the index is in + * bounds, and returns a dummy array element if it isn't. + */ +#define MFL_ID_XOR_KEY 0x9E3779B9 // key XOR'd with ID when serialized +#define MFL_OID_XOR_KEY 0x6A09E667 // key XOR'd with OID when serialized + +/** + * An OID can be tagged to introduce the serialized definition of the object, + * or to stand for a strong or weak reference to that object. Thus the high + * 29 bits actually identify the object, and the low three bits tell whether + * the object is being defined or just referenced -- and via what inheritance + * chain or inner object, if necessary. + * + * The MFL_QUERY_INTERFACE_TAG bit helps us cope with aggregation and multiple + * inheritance: object identity follows the XPCOM rule, but a deserializer may + * need to query for an interface not on the primary inheritance chain ending + * in the nsISupports whose address uniquely identifies the XPCOM object being + * referenced or defined. + */ +#define MFL_OBJECT_TAG_BITS 3 +#define MFL_OBJECT_TAG_MASK PR_BITMASK(MFL_OBJECT_TAG_BITS) + +#define MFL_OBJECT_DEF_TAG 1U // object definition follows this OID +#define MFL_WEAK_REF_TAG 2U // OID weakly refers to a prior object + // NB: do not confuse with nsWeakPtr! +#define MFL_QUERY_INTERFACE_TAG 4U // QI object to the ID follows this OID + // NB: an NSFastLoadID, not an nsIID! + +/** + * The dull object identifier introduces the definition of all objects that + * have only one (necessarily strong) ref in the serialization. The definition + * appears at the point of reference. + */ +#define MFL_DULL_OBJECT_OID MFL_OBJECT_DEF_TAG + +/** + * Convert an OID to an index into nsFastLoadFooter::mObjectMap. + */ +#define MFL_OID_TO_SHARP_INDEX(oid) (((oid) >> MFL_OBJECT_TAG_BITS) - 1) +#define MFL_SHARP_INDEX_TO_OID(index) (((index) + 1) << MFL_OBJECT_TAG_BITS) + +/** + * Magic "number" at start of a FastLoad file. Inspired by the PNG "magic" + * string, which inspired XPCOM's typelib (.xpt) file magic. Guaranteed to be + * corrupted by FTP-as-ASCII and other likely errors, meaningful to clued-in + * humans, and ending in ^Z to terminate erroneous text input on Windows. + */ +#define MFL_FILE_MAGIC "XPCOM\nMozFASL\r\n\032" +#define MFL_FILE_MAGIC_SIZE 16 + +#define MFL_FILE_VERSION_0 0 +#define MFL_FILE_VERSION_1 1000 +#define MFL_FILE_VERSION 4 // fix to note singletons in object map + +/** + * Compute Fletcher's 16-bit checksum over aLength bytes starting at aBuffer, + * with the initial accumulators seeded from *aChecksum, and final checksum + * returned in *aChecksum. The return value is the number of unchecked bytes, + * which may be non-zero if aBuffer is misaligned or aLength is odd. Callers + * should copy any remaining bytes to the front of the next buffer. + * + * If aLastBuffer is false, do not check any bytes remaining due to misaligned + * aBuffer or odd aLength, instead returning the remaining byte count. But if + * aLastBuffer is true, treat aBuffer as the last buffer in the file and check + * every byte, returning 0. Here's a read-loop checksumming sketch: + * + * char buf[BUFSIZE]; + * PRUint32 len, rem = 0; + * PRUint32 checksum = 0; + * + * while (NS_SUCCEEDED(rv = Read(buf + rem, sizeof buf - rem, &len)) && len) { + * len += rem; + * rem = NS_AccumulateFastLoadChecksum(&checksum, + * NS_REINTERPRET_CAST(PRUint8*, buf), + * len, + * PR_FALSE); + * if (rem) + * memcpy(buf, buf + len - rem, rem); + * } + * + * if (rem) { + * NS_AccumulateFastLoadChecksum(&checksum, + * NS_REINTERPRET_CAST(PRUint8*, buf), + * rem, + * PR_TRUE); + * } + * + * After this, if NS_SUCCEEDED(rv), checksum contains a valid FastLoad sum. + */ +PR_EXTERN(PRUint32) +NS_AccumulateFastLoadChecksum(PRUint32 *aChecksum, + const PRUint8* aBuffer, + PRUint32 aLength, + PRBool aLastBuffer); + +PR_EXTERN(PRUint32) +NS_AddFastLoadChecksums(PRUint32 sum1, PRUint32 sum2, PRUint32 sum2ByteCount); + +/** + * Header at the start of a FastLoad file. + */ +struct nsFastLoadHeader { + char mMagic[MFL_FILE_MAGIC_SIZE]; + PRUint32 mChecksum; + PRUint32 mVersion; + PRUint32 mFooterOffset; + PRUint32 mFileSize; +}; + +/** + * Footer prefix structure (footer header, ugh), after which come arrays of + * structures or strings counted by these members. + */ +struct nsFastLoadFooterPrefix { + PRUint32 mNumIDs; + PRUint32 mNumSharpObjects; + PRUint32 mNumMuxedDocuments; + PRUint32 mNumDependencies; +}; + +struct nsFastLoadSharpObjectInfo { + PRUint32 mCIDOffset; // offset of object's NSFastLoadID and data + PRUint16 mStrongRefCnt; + PRUint16 mWeakRefCnt; // high bit is singleton flag, see below +}; + +#define MFL_SINGLETON_FLAG 0x8000 +#define MFL_WEAK_REFCNT_MASK 0x7fff + +#define MFL_GET_SINGLETON_FLAG(ip) ((ip)->mWeakRefCnt & MFL_SINGLETON_FLAG) +#define MFL_GET_WEAK_REFCNT(ip) ((ip)->mWeakRefCnt & MFL_WEAK_REFCNT_MASK) + +#define MFL_SET_SINGLETON_FLAG(ip) \ + ((ip)->mWeakRefCnt |= MFL_SINGLETON_FLAG) +#define MFL_SET_WEAK_REFCNT(ip,rc) \ + ((ip)->mWeakRefCnt = (((ip)->mWeakRefCnt & MFL_SINGLETON_FLAG) | (rc))) + +#define MFL_BUMP_WEAK_REFCNT(ip) (++(ip)->mWeakRefCnt) +#define MFL_DROP_WEAK_REFCNT(ip) (--(ip)->mWeakRefCnt) + +struct nsFastLoadMuxedDocumentInfo { + const char* mURISpec; + PRUint32 mInitialSegmentOffset; +}; + +// forward declarations of opaque types defined in nsFastLoadFile.cpp +struct nsDocumentMapReadEntry; +struct nsDocumentMapWriteEntry; + +// So nsFastLoadFileUpdater can verify that its nsIObjectInputStream parameter +// is an nsFastLoadFileReader. +#define NS_FASTLOADFILEREADER_IID \ + {0x7d37d1bb,0xcef3,0x4c5f,{0x97,0x68,0x0f,0x89,0x7f,0x1a,0xe1,0x40}} + +struct nsIFastLoadFileReader : public nsISupports { + NS_DEFINE_STATIC_IID_ACCESSOR(NS_FASTLOADFILEREADER_IID) +}; + +/** + * Inherit from the concrete class nsBinaryInputStream, which inherits from + * abstract nsIObjectInputStream but does not implement its direct methods. + * Though the names are not as clear as I'd like, this seems to be the best + * way to share nsBinaryStream.cpp code. + */ +class nsFastLoadFileReader + : public nsBinaryInputStream, + public nsIFastLoadReadControl, + public nsISeekableStream, + public nsIFastLoadFileReader +{ + public: + nsFastLoadFileReader(nsIInputStream *aStream) + : mCurrentDocumentMapEntry(nsnull) { + SetInputStream(aStream); + MOZ_COUNT_CTOR(nsFastLoadFileReader); + } + + virtual ~nsFastLoadFileReader() { + MOZ_COUNT_DTOR(nsFastLoadFileReader); + } + + private: + // nsISupports methods + NS_DECL_ISUPPORTS_INHERITED + + // overridden nsIObjectInputStream methods + NS_IMETHOD ReadObject(PRBool aIsStrongRef, nsISupports* *_retval); + NS_IMETHOD ReadID(nsID *aResult); + + // nsIFastLoadFileControl methods + NS_DECL_NSIFASTLOADFILECONTROL + + // nsIFastLoadReadControl methods + NS_DECL_NSIFASTLOADREADCONTROL + + // nsISeekableStream methods + NS_DECL_NSISEEKABLESTREAM + + // Override Read so we can demultiplex a document interleaved with others. + NS_IMETHOD Read(char* aBuffer, PRUint32 aCount, PRUint32 *aBytesRead); + + // Override ReadSegments too, as nsBinaryInputStream::ReadSegments does + // not call through our overridden Read method -- it calls directly into + // the underlying input stream. + NS_IMETHODIMP ReadSegments(nsWriteSegmentFun aWriter, void* aClosure, + PRUint32 aCount, PRUint32 *aResult); + + nsresult ReadHeader(nsFastLoadHeader *aHeader); + + /** + * In-memory representation of an indexed nsFastLoadSharpObjectInfo record. + */ + struct nsObjectMapEntry : public nsFastLoadSharpObjectInfo { + nsCOMPtr mReadObject; + PRInt64 mSkipOffset; + PRUint16 mSaveStrongRefCnt; // saved for an Update + PRUint16 mSaveWeakRefCnt; // after a Read + }; + + /** + * In-memory representation of the FastLoad file footer. + */ + struct nsFastLoadFooter : public nsFastLoadFooterPrefix { + nsFastLoadFooter() + : mIDMap(nsnull), + mObjectMap(nsnull) { + mDocumentMap.ops = mURIMap.ops = nsnull; + } + + ~nsFastLoadFooter() { + delete[] mIDMap; + delete[] mObjectMap; + if (mDocumentMap.ops) + PL_DHashTableFinish(&mDocumentMap); + if (mURIMap.ops) + PL_DHashTableFinish(&mURIMap); + } + + // These can't be static within GetID and GetSharpObjectEntry or the + // toolchains on HP-UX 10.20's, RH 7.0, and Mac OS X all barf at link + // time ("common symbols not allowed with MY_DHLIB output format", to + // quote the OS X rev of gcc). + static nsID gDummyID; + static nsObjectMapEntry gDummySharpObjectEntry; + + const nsID& GetID(NSFastLoadID aFastId) const { + PRUint32 index = aFastId - 1; + NS_ASSERTION(index < mNumIDs, "aFastId out of range"); + if (index >= mNumIDs) + return gDummyID; + return mIDMap[index]; + } + + nsObjectMapEntry& + GetSharpObjectEntry(NSFastLoadOID aOID) const { + PRUint32 index = MFL_OID_TO_SHARP_INDEX(aOID); + NS_ASSERTION(index < mNumSharpObjects, "aOID out of range"); + if (index >= mNumSharpObjects) + return gDummySharpObjectEntry; + return mObjectMap[index]; + } + + // Map from dense, zero-based, uint32 NSFastLoadID to 16-byte nsID. + nsID* mIDMap; + + // Map from dense, zero-based MFL_OID_TO_SHARP_INDEX(oid) to sharp + // object offset and refcnt information. + nsObjectMapEntry* mObjectMap; + + // Map from URI spec string to nsDocumentMapReadEntry, which helps us + // demultiplex a document's objects from among the interleaved object + // stream segments in the FastLoad file. + PLDHashTable mDocumentMap; + + // Fast mapping from URI object pointer to mDocumentMap entry, valid + // only while the muxed document is loading. + PLDHashTable mURIMap; + + // List of source filename dependencies that should trigger regeneration + // of the FastLoad file. + nsCOMPtr mDependencies; + }; + + nsresult ReadFooter(nsFastLoadFooter *aFooter); + nsresult ReadFooterPrefix(nsFastLoadFooterPrefix *aFooterPrefix); + nsresult ReadSlowID(nsID *aID); + nsresult ReadFastID(NSFastLoadID *aID); + nsresult ReadSharpObjectInfo(nsFastLoadSharpObjectInfo *aInfo); + nsresult ReadMuxedDocumentInfo(nsFastLoadMuxedDocumentInfo *aInfo); + nsresult DeserializeObject(nsISupports* *aObject); + + nsresult Open(); + NS_IMETHOD Close(); + + protected: + nsFastLoadHeader mHeader; + nsFastLoadFooter mFooter; + + nsDocumentMapReadEntry* mCurrentDocumentMapEntry; + + friend class nsFastLoadFileUpdater; +}; + +NS_COM nsresult +NS_NewFastLoadFileReader(nsIObjectInputStream* *aResult, + nsIInputStream* aSrcStream); + +/** + * Inherit from the concrete class nsBinaryInputStream, which inherits from + * abstract nsIObjectInputStream but does not implement its direct methods. + * Though the names are not as clear as I'd like, this seems to be the best + * way to share nsBinaryStream.cpp code. + */ +class nsFastLoadFileWriter + : public nsBinaryOutputStream, + public nsIFastLoadWriteControl, + public nsISeekableStream +{ + public: + nsFastLoadFileWriter(nsIOutputStream *aStream, nsIFastLoadFileIO* aFileIO) + : mCurrentDocumentMapEntry(nsnull), + mFileIO(aFileIO) + { + SetOutputStream(aStream); + mHeader.mChecksum = 0; + mIDMap.ops = mObjectMap.ops = mDocumentMap.ops = mURIMap.ops = nsnull; + mDependencyMap.ops = nsnull; + MOZ_COUNT_CTOR(nsFastLoadFileWriter); + } + + virtual ~nsFastLoadFileWriter() + { + if (mIDMap.ops) + PL_DHashTableFinish(&mIDMap); + if (mObjectMap.ops) + PL_DHashTableFinish(&mObjectMap); + if (mDocumentMap.ops) + PL_DHashTableFinish(&mDocumentMap); + if (mURIMap.ops) + PL_DHashTableFinish(&mURIMap); + if (mDependencyMap.ops) + PL_DHashTableFinish(&mDependencyMap); + MOZ_COUNT_DTOR(nsFastLoadFileWriter); + } + + private: + // nsISupports methods + NS_DECL_ISUPPORTS_INHERITED + + // overridden nsIObjectOutputStream methods + NS_IMETHOD WriteObject(nsISupports* aObject, PRBool aIsStrongRef); + NS_IMETHOD WriteSingleRefObject(nsISupports* aObject); + NS_IMETHOD WriteCompoundObject(nsISupports* aObject, + const nsIID& aIID, + PRBool aIsStrongRef); + NS_IMETHOD WriteID(const nsID& aID); + + // nsIFastLoadFileControl methods + NS_DECL_NSIFASTLOADFILECONTROL + + // nsIFastLoadWriteControl methods + NS_DECL_NSIFASTLOADWRITECONTROL + + // nsISeekableStream methods + NS_DECL_NSISEEKABLESTREAM + + nsresult MapID(const nsID& aSlowID, NSFastLoadID *aResult); + + nsresult WriteHeader(nsFastLoadHeader *aHeader); + nsresult WriteFooter(); + nsresult WriteFooterPrefix(const nsFastLoadFooterPrefix& aFooterPrefix); + nsresult WriteSlowID(const nsID& aID); + nsresult WriteFastID(NSFastLoadID aID); + nsresult WriteSharpObjectInfo(const nsFastLoadSharpObjectInfo& aInfo); + nsresult WriteMuxedDocumentInfo(const nsFastLoadMuxedDocumentInfo& aInfo); + + nsresult Init(); + nsresult Open(); + NS_IMETHOD Close(); + + nsresult WriteObjectCommon(nsISupports* aObject, + PRBool aIsStrongRef, + PRUint32 aQITag); + + static PLDHashOperator PR_CALLBACK + IDMapEnumerate(PLDHashTable *aTable, + PLDHashEntryHdr *aHdr, + PRUint32 aNumber, + void *aData); + + static PLDHashOperator PR_CALLBACK + ObjectMapEnumerate(PLDHashTable *aTable, + PLDHashEntryHdr *aHdr, + PRUint32 aNumber, + void *aData); + + static PLDHashOperator PR_CALLBACK + DocumentMapEnumerate(PLDHashTable *aTable, + PLDHashEntryHdr *aHdr, + PRUint32 aNumber, + void *aData); + + static PLDHashOperator PR_CALLBACK + DependencyMapEnumerate(PLDHashTable *aTable, + PLDHashEntryHdr *aHdr, + PRUint32 aNumber, + void *aData); + + protected: + nsFastLoadHeader mHeader; + + PLDHashTable mIDMap; + PLDHashTable mObjectMap; + PLDHashTable mDocumentMap; + PLDHashTable mURIMap; + PLDHashTable mDependencyMap; + + nsDocumentMapWriteEntry* mCurrentDocumentMapEntry; + nsCOMPtr mFileIO; +}; + +NS_COM nsresult +NS_NewFastLoadFileWriter(nsIObjectOutputStream* *aResult, + nsIOutputStream* aDestStream, + nsIFastLoadFileIO* aFileIO); + +/** + * Subclass of nsFastLoadFileWriter, friend of nsFastLoadFileReader which it + * wraps when a FastLoad file needs to be updated. The wrapped reader can be + * used to demulitplex data for documents already in the FastLoad file, while + * the updater writes new data over the old footer, then writes a new footer + * that maps all data on Close. + */ +class nsFastLoadFileUpdater + : public nsFastLoadFileWriter, + nsIFastLoadFileIO +{ + public: + nsFastLoadFileUpdater(nsIOutputStream* aOutputStream) + : nsFastLoadFileWriter(aOutputStream, nsnull) { + MOZ_COUNT_CTOR(nsFastLoadFileUpdater); + } + + virtual ~nsFastLoadFileUpdater() { + MOZ_COUNT_DTOR(nsFastLoadFileUpdater); + } + + private: + // nsISupports methods + NS_DECL_ISUPPORTS_INHERITED + + // nsIFastLoadFileIO methods + NS_DECL_NSIFASTLOADFILEIO + + nsresult Open(nsFastLoadFileReader* aReader); + NS_IMETHOD Close(); + + static PLDHashOperator PR_CALLBACK + CopyReadDocumentMapEntryToUpdater(PLDHashTable *aTable, + PLDHashEntryHdr *aHdr, + PRUint32 aNumber, + void *aData); + + friend class nsFastLoadFileReader; + + protected: + nsCOMPtr mInputStream; +}; + +NS_COM nsresult +NS_NewFastLoadFileUpdater(nsIObjectOutputStream* *aResult, + nsIOutputStream* aOutputStream, + nsIObjectInputStream* aReaderAsStream); + +#endif // nsFastLoadFile_h___ diff --git a/src/libs/xpcom18a4/xpcom/io/nsFastLoadPtr.h b/src/libs/xpcom18a4/xpcom/io/nsFastLoadPtr.h new file mode 100644 index 00000000..0c832357 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsFastLoadPtr.h @@ -0,0 +1,112 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 FastLoad code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Brendan Eich (original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +#ifndef nsFastLoadPtr_h___ +#define nsFastLoadPtr_h___ + +/** + * Mozilla FastLoad file object pointer template type. + * + * Use nsFastLoadPtr rather than nsCOMPtr when declaring a strong XPCOM + * ref member of a data structure that's conditionally loaded at application + * startup. You must be willing to tolerate the null mRawPtr test on every + * dereference of this member pointer, or else copy it to a local to optimize + * away the cost. + */ + +#ifndef nsCOMPtr_h___ +#include "nsCOMPtr.h" +#endif + +#ifndef nsIFastLoadService_h___ +#include "nsIFastLoadService.h" +#endif + +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +#define gFastLoadService_ VBoxNsxpgFastLoadService_ +#endif /* VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + +/** + * nsFastLoadPtr is a template class, so we don't want a class static service + * pointer member declared in nsFastLoadPtr, above. Plus, we need special + * declaration magic to export data across DLL/DSO boundaries. So we use an + * old-fashioned global variable that refers weakly to the one true FastLoad + * service. This pointer is maintained by that singleton's ctor and dtor. + */ +PR_EXPORT_DATA(nsIFastLoadService*) gFastLoadService_; + +template +class nsFastLoadPtr : public nsCOMPtr { + public: + nsDerivedSafe* get() const { + if (!this->mRawPtr) { + gFastLoadService_->GetFastLoadReferent( + NS_REINTERPRET_CAST(nsISupports**, + &this->mRawPtr)); + } + return NS_REINTERPRET_CAST(nsDerivedSafe*, this->mRawPtr); + } + + /** + * Deserialize an nsFastLoadPtr from aInputStream, skipping the referent + * object, but saving the object's offset for later deserialization. + * + * Lowercase name _a la_ get, because it's called the same way -- not via + * operator->(). + */ + nsresult read(nsIObjectInputStream* aInputStream) { + return gFastLoadService_->ReadFastLoadPtr(aInputStream, + NS_REINTERPRET_CAST(nsISupports**, + &this->mRawPtr)); + } + + /** + * Serialize an nsFastLoadPtr reference and possibly the referent object, + * if that object has not yet been serialized. + * + * Lowercase name _a la_ get, because it's called the same way -- not via + * operator->(). + */ + nsresult write(nsIObjectOutputStream* aOutputStream) { + return gFastLoadService_->WriteFastLoadPtr(aOutputStream, + NS_REINTERPRET_CAST(nsISupports*, + this->mRawPtr)); + } +}; + +#endif // nsFastLoadPtr_h___ diff --git a/src/libs/xpcom18a4/xpcom/io/nsFastLoadService.cpp b/src/libs/xpcom18a4/xpcom/io/nsFastLoadService.cpp new file mode 100644 index 00000000..4df187c1 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsFastLoadService.cpp @@ -0,0 +1,571 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 FastLoad code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Brendan Eich (original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "prtypes.h" +#include "prio.h" +#include "prtime.h" +#include "pldhash.h" + +#include "nsAppDirectoryServiceDefs.h" +#include "nsAutoLock.h" +#include "nsCOMPtr.h" +#include "nsFastLoadFile.h" +#include "nsFastLoadPtr.h" +#include "nsFastLoadService.h" +#include "nsString.h" + +#include "nsIComponentManager.h" +#include "nsIEnumerator.h" +#include "nsIFastLoadFileControl.h" +#include "nsIFile.h" +#include "nsIObjectInputStream.h" +#include "nsIObjectOutputStream.h" +#include "nsISeekableStream.h" +#include "nsISupports.h" + +PR_IMPLEMENT_DATA(nsIFastLoadService*) gFastLoadService_ = nsnull; + +NS_IMPL_THREADSAFE_ISUPPORTS1(nsFastLoadService, nsIFastLoadService) + +nsFastLoadService::nsFastLoadService() + : mLock(nsnull), + mFastLoadPtrMap(nsnull), + mDirection(0) +{ + NS_ASSERTION(gFastLoadService_ == nsnull, "double FastLoadService init?"); + gFastLoadService_ = this; +} + +nsFastLoadService::~nsFastLoadService() +{ + gFastLoadService_ = nsnull; + + if (mInputStream) + mInputStream->Close(); + if (mOutputStream) + mOutputStream->Close(); + + if (mFastLoadPtrMap) + PL_DHashTableDestroy(mFastLoadPtrMap); + if (mLock) + PR_DestroyLock(mLock); +} + +NS_IMETHODIMP +nsFastLoadService::Create(nsISupports *aOuter, REFNSIID aIID, void **aResult) +{ + *aResult = nsnull; + if (aOuter) + return NS_ERROR_NO_AGGREGATION; + + nsFastLoadService* fastLoadService = new nsFastLoadService(); + if (!fastLoadService) + return NS_ERROR_OUT_OF_MEMORY; + + fastLoadService->mLock = PR_NewLock(); + if (!fastLoadService->mLock) { + delete fastLoadService; + return NS_ERROR_OUT_OF_MEMORY; + } + + NS_ADDREF(fastLoadService); + nsresult rv = fastLoadService->QueryInterface(aIID, aResult); + NS_RELEASE(fastLoadService); + return rv; +} + +#if defined XP_MAC + +// Mac format: " FastLoad File" with capitalized. +# include "nsCRT.h" + +# define MASSAGE_BASENAME(bn) (bn.SetCharAt(nsCRT::ToUpper(bn.CharAt(0)), 0)) +# define PLATFORM_FASL_SUFFIX " FastLoad File" + +#elif defined(XP_UNIX) || defined(XP_BEOS) + +// Unix format: ".mfasl". +# define MASSAGE_BASENAME(bn) /* nothing */ +# define PLATFORM_FASL_SUFFIX ".mfasl" + +#elif defined(XP_WIN) || defined(XP_OS2) + +// Windows format: ".mfl". +# define MASSAGE_BASENAME(bn) /* nothing */ +# define PLATFORM_FASL_SUFFIX ".mfl" + +#endif + +nsresult +nsFastLoadService::NewFastLoadFile(const char* aBaseName, nsIFile* *aResult) +{ + nsresult rv; + nsCOMPtr file; + + rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, + getter_AddRefs(file)); + if (NS_FAILED(rv)) + return rv; + + nsCAutoString name(aBaseName); + MASSAGE_BASENAME(name); + name += PLATFORM_FASL_SUFFIX; + rv = file->AppendNative(name); + if (NS_FAILED(rv)) + return rv; + + *aResult = file; + NS_ADDREF(*aResult); + return NS_OK; +} + +NS_IMETHODIMP +nsFastLoadService::NewInputStream(nsIInputStream* aSrcStream, + nsIObjectInputStream* *aResult) +{ + nsAutoLock lock(mLock); + + nsCOMPtr stream; + nsresult rv = NS_NewFastLoadFileReader(getter_AddRefs(stream), aSrcStream); + if (NS_FAILED(rv)) + return rv; + + *aResult = stream; + NS_ADDREF(*aResult); + return NS_OK; +} + +NS_IMETHODIMP +nsFastLoadService::NewOutputStream(nsIOutputStream* aDestStream, + nsIObjectOutputStream* *aResult) +{ + nsAutoLock lock(mLock); + + return NS_NewFastLoadFileWriter(aResult, aDestStream, mFileIO); +} + +NS_IMETHODIMP +nsFastLoadService::GetInputStream(nsIObjectInputStream* *aResult) +{ + NS_IF_ADDREF(*aResult = mInputStream); + return NS_OK; +} + +NS_IMETHODIMP +nsFastLoadService::SetInputStream(nsIObjectInputStream* aStream) +{ + nsAutoLock lock(mLock); + mInputStream = aStream; + return NS_OK; +} + +NS_IMETHODIMP +nsFastLoadService::GetOutputStream(nsIObjectOutputStream* *aResult) +{ + NS_IF_ADDREF(*aResult = mOutputStream); + return NS_OK; +} + +NS_IMETHODIMP +nsFastLoadService::SetOutputStream(nsIObjectOutputStream* aStream) +{ + nsAutoLock lock(mLock); + mOutputStream = aStream; + return NS_OK; +} + +NS_IMETHODIMP +nsFastLoadService::GetFileIO(nsIFastLoadFileIO* *aResult) +{ + NS_IF_ADDREF(*aResult = mFileIO); + return NS_OK; +} + +NS_IMETHODIMP +nsFastLoadService::SetFileIO(nsIFastLoadFileIO* aFileIO) +{ + nsAutoLock lock(mLock); + mFileIO = aFileIO; + return NS_OK; +} + +NS_IMETHODIMP +nsFastLoadService::GetDirection(PRInt32 *aResult) +{ + *aResult = mDirection; + return NS_OK; +} + +NS_IMETHODIMP +nsFastLoadService::HasMuxedDocument(const char* aURISpec, PRBool *aResult) +{ + nsresult rv = NS_ERROR_NOT_AVAILABLE; + nsCOMPtr control; + + *aResult = PR_FALSE; + nsAutoLock lock(mLock); + + if (mInputStream) { + control = do_QueryInterface(mInputStream); + if (control) + rv = control->HasMuxedDocument(aURISpec, aResult); + } + + if (! *aResult && mOutputStream) { + control = do_QueryInterface(mOutputStream); + if (control) + rv = control->HasMuxedDocument(aURISpec, aResult); + } + + return rv; +} + +NS_IMETHODIMP +nsFastLoadService::StartMuxedDocument(nsISupports* aURI, const char* aURISpec, + PRInt32 aDirectionFlags) +{ + nsresult rv = NS_ERROR_NOT_AVAILABLE; + nsCOMPtr control; + nsAutoLock lock(mLock); + + // Try for an input stream first, in case aURISpec's data is multiplexed + // in the current FastLoad file. + if ((aDirectionFlags & NS_FASTLOAD_READ) && mInputStream) { + control = do_QueryInterface(mInputStream); + if (control) { + // If aURISpec is not in the multiplex, control->StartMuxedDocument + // will return NS_ERROR_NOT_AVAILABLE. + rv = control->StartMuxedDocument(aURI, aURISpec); + if (NS_SUCCEEDED(rv) || rv != NS_ERROR_NOT_AVAILABLE) + return rv; + + // Ok, aURISpec is not in the existing mux. If we have no output + // stream yet, wrap the reader with a FastLoad file updater. + if (!mOutputStream && mFileIO) { + nsCOMPtr output; + rv = mFileIO->GetOutputStream(getter_AddRefs(output)); + if (NS_FAILED(rv)) + return rv; + + // NB: mInputStream must be an nsFastLoadFileReader! + rv = NS_NewFastLoadFileUpdater(getter_AddRefs(mOutputStream), + output, + mInputStream); + if (NS_FAILED(rv)) + return rv; + } + + if (aDirectionFlags == NS_FASTLOAD_READ) { + // Tell our caller to re-start multiplexing, rather than attempt + // to select and deserialize now. + return NS_ERROR_NOT_AVAILABLE; + } + } + } + + if ((aDirectionFlags & NS_FASTLOAD_WRITE) && mOutputStream) { + control = do_QueryInterface(mOutputStream); + if (control) + rv = control->StartMuxedDocument(aURI, aURISpec); + } + return rv; +} + +NS_IMETHODIMP +nsFastLoadService::SelectMuxedDocument(nsISupports* aURI, nsISupports** aResult) +{ + nsresult rv = NS_ERROR_NOT_AVAILABLE; + nsCOMPtr control; + nsAutoLock lock(mLock); + + // Try to select the reader, if any; then only if the URI was not in the + // file already, select the writer/updater. + if (mInputStream) { + control = do_QueryInterface(mInputStream); + if (control) { + rv = control->SelectMuxedDocument(aURI, aResult); + if (NS_SUCCEEDED(rv)) + mDirection = NS_FASTLOAD_READ; + } + } + + if (rv == NS_ERROR_NOT_AVAILABLE && mOutputStream) { + control = do_QueryInterface(mOutputStream); + if (control) { + rv = control->SelectMuxedDocument(aURI, aResult); + if (NS_SUCCEEDED(rv)) + mDirection = NS_FASTLOAD_WRITE; + } + } + + return rv; +} + +NS_IMETHODIMP +nsFastLoadService::EndMuxedDocument(nsISupports* aURI) +{ + nsresult rv = NS_ERROR_NOT_AVAILABLE; + nsCOMPtr control; + nsAutoLock lock(mLock); + + // Try to end the document identified by aURI in the reader, if any; then + // only if the URI was not in the file already, end the writer/updater. + if (mInputStream) { + control = do_QueryInterface(mInputStream); + if (control) + rv = control->EndMuxedDocument(aURI); + } + + if (rv == NS_ERROR_NOT_AVAILABLE && mOutputStream) { + control = do_QueryInterface(mOutputStream); + if (control) + rv = control->EndMuxedDocument(aURI); + } + + mDirection = 0; + return rv; +} + +NS_IMETHODIMP +nsFastLoadService::AddDependency(nsIFile* aFile) +{ + nsAutoLock lock(mLock); + + nsCOMPtr control(do_QueryInterface(mOutputStream)); + if (!control) + return NS_ERROR_NOT_AVAILABLE; + + return control->AddDependency(aFile); +} + +NS_IMETHODIMP +nsFastLoadService::ComputeChecksum(nsIFile* aFile, + nsIFastLoadReadControl* aControl, + PRUint32 *aChecksum) +{ + nsCAutoString path; + nsresult rv = aFile->GetNativePath(path); + if (NS_FAILED(rv)) + return rv; + + nsCStringKey key(path); + PRUint32 checksum = NS_PTR_TO_INT32(mChecksumTable.Get(&key)); + if (checksum) { + *aChecksum = checksum; + return NS_OK; + } + + rv = aControl->ComputeChecksum(&checksum); + if (NS_FAILED(rv)) + return rv; + +#ifndef VBOX + mChecksumTable.Put(&key, NS_INT32_TO_PTR(checksum)); +#else /* VBOX */ + mChecksumTable.Put(&key, (void *)(uintptr_t)checksum); +#endif /* VBOX */ + *aChecksum = checksum; + return NS_OK; +} + +NS_IMETHODIMP +nsFastLoadService::CacheChecksum(nsIFile* aFile, nsIObjectOutputStream *aStream) +{ + nsCOMPtr control(do_QueryInterface(aStream)); + if (!control) + return NS_ERROR_FAILURE; + + PRUint32 checksum; + nsresult rv = control->GetChecksum(&checksum); + if (NS_FAILED(rv)) + return rv; + + nsCAutoString path; + rv = aFile->GetNativePath(path); + if (NS_FAILED(rv)) + return rv; + + nsCStringKey key(path); +#ifndef VBOX + mChecksumTable.Put(&key, NS_INT32_TO_PTR(checksum)); +#else /* VBOX */ + mChecksumTable.Put(&key, (void *)(uintptr_t)checksum); +#endif /* VBOX */ + return NS_OK; +} + +struct nsFastLoadPtrEntry : public PLDHashEntryHdr { + nsISupports** mPtrAddr; // key, must come first for PL_DHashGetStubOps + PRUint32 mOffset; +}; + +NS_IMETHODIMP +nsFastLoadService::GetFastLoadReferent(nsISupports* *aPtrAddr) +{ + NS_ASSERTION(*aPtrAddr == nsnull, + "aPtrAddr doesn't point to null nsFastLoadPtr::mRawAddr?"); + + nsAutoLock lock(mLock); + if (!mFastLoadPtrMap || !mInputStream) + return NS_OK; + + nsFastLoadPtrEntry* entry = + NS_STATIC_CAST(nsFastLoadPtrEntry*, + PL_DHashTableOperate(mFastLoadPtrMap, aPtrAddr, + PL_DHASH_LOOKUP)); + if (PL_DHASH_ENTRY_IS_FREE(entry)) + return NS_OK; + + nsresult rv; + nsCOMPtr seekable(do_QueryInterface(mInputStream)); + + rv = seekable->Seek(nsISeekableStream::NS_SEEK_SET, entry->mOffset); + if (NS_FAILED(rv)) + return rv; + + rv = mInputStream->ReadObject(PR_TRUE, aPtrAddr); + if (NS_FAILED(rv)) + return rv; + + // Shrink the table if half the entries are removed sentinels. + PRUint32 size = PL_DHASH_TABLE_SIZE(mFastLoadPtrMap); + if (mFastLoadPtrMap->removedCount >= (size >> 2)) + PL_DHashTableOperate(mFastLoadPtrMap, entry, PL_DHASH_REMOVE); + else + PL_DHashTableRawRemove(mFastLoadPtrMap, entry); + + return NS_OK; +} + +NS_IMETHODIMP +nsFastLoadService::ReadFastLoadPtr(nsIObjectInputStream* aInputStream, + nsISupports* *aPtrAddr) +{ + // nsFastLoadPtrs self-construct to null, so if we have a non-null value + // in our inout parameter, we must have been read already, alright! + if (*aPtrAddr) + return NS_OK; + + nsresult rv; + PRUint32 nextOffset; + nsAutoLock lock(mLock); + + rv = aInputStream->Read32(&nextOffset); + if (NS_FAILED(rv)) + return rv; + + nsCOMPtr seekable(do_QueryInterface(aInputStream)); + if (!seekable) + return NS_ERROR_FAILURE; + + PRInt64 thisOffset; + rv = seekable->Tell(&thisOffset); + if (NS_FAILED(rv)) + return rv; + + rv = seekable->Seek(nsISeekableStream::NS_SEEK_SET, nextOffset); + if (NS_FAILED(rv)) + return rv; + + if (!mFastLoadPtrMap) { + mFastLoadPtrMap = PL_NewDHashTable(PL_DHashGetStubOps(), this, + sizeof(nsFastLoadPtrEntry), + PL_DHASH_MIN_SIZE); + if (!mFastLoadPtrMap) + return NS_ERROR_OUT_OF_MEMORY; + } + + nsFastLoadPtrEntry* entry = + NS_STATIC_CAST(nsFastLoadPtrEntry*, + PL_DHashTableOperate(mFastLoadPtrMap, aPtrAddr, + PL_DHASH_ADD)); + NS_ASSERTION(entry->mPtrAddr == nsnull, "duplicate nsFastLoadPtr?!"); + + entry->mPtrAddr = aPtrAddr; + + LL_L2UI(entry->mOffset, thisOffset); + return NS_OK; +} + +NS_IMETHODIMP +nsFastLoadService::WriteFastLoadPtr(nsIObjectOutputStream* aOutputStream, + nsISupports* aObject) +{ + NS_ASSERTION(aObject != nsnull, "writing an unread nsFastLoadPtr?!"); + if (!aObject) + return NS_ERROR_UNEXPECTED; + + nsresult rv; + nsAutoLock lock(mLock); // serialize writes to aOutputStream + + nsCOMPtr seekable(do_QueryInterface(aOutputStream)); + if (!seekable) + return NS_ERROR_FAILURE; + + PRInt64 saveOffset; + rv = seekable->Tell(&saveOffset); + if (NS_FAILED(rv)) + return rv; + + rv = aOutputStream->Write32(0); // nextOffset placeholder + if (NS_FAILED(rv)) + return rv; + + rv = aOutputStream->WriteObject(aObject, PR_TRUE); + if (NS_FAILED(rv)) + return rv; + + PRInt64 nextOffset; + rv = seekable->Tell(&nextOffset); + if (NS_FAILED(rv)) + return rv; + + rv = seekable->Seek(nsISeekableStream::NS_SEEK_SET, saveOffset); + if (NS_FAILED(rv)) + return rv; + + rv = aOutputStream->Write32(nextOffset); + if (NS_FAILED(rv)) + return rv; + + rv = seekable->Seek(nsISeekableStream::NS_SEEK_SET, nextOffset); + if (NS_FAILED(rv)) + return rv; + + return NS_OK; +} diff --git a/src/libs/xpcom18a4/xpcom/io/nsFastLoadService.h b/src/libs/xpcom18a4/xpcom/io/nsFastLoadService.h new file mode 100644 index 00000000..8f1aa6ae --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsFastLoadService.h @@ -0,0 +1,71 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 FastLoad code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Brendan Eich (original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "prtypes.h" +#include "pldhash.h" +#include "nsCOMPtr.h" +#include "nsHashtable.h" +#include "nsIFastLoadService.h" +#include "nsIObjectInputStream.h" +#include "nsIObjectOutputStream.h" + +class nsFastLoadFileReader; +class nsFastLoadFileWriter; + +class nsFastLoadService : public nsIFastLoadService +{ + public: + nsFastLoadService(); + private: + ~nsFastLoadService(); + + public: + NS_DECL_ISUPPORTS + NS_DECL_NSIFASTLOADSERVICE + + static NS_METHOD + Create(nsISupports *aOuter, REFNSIID aIID, void **aResult); + + private: + PRLock* mLock; + PLDHashTable* mFastLoadPtrMap; + nsCOMPtr mInputStream; + nsCOMPtr mOutputStream; + nsCOMPtr mFileIO; + PRInt32 mDirection; + nsHashtable mChecksumTable; +}; diff --git a/src/libs/xpcom18a4/xpcom/io/nsIAsyncInputStream.idl b/src/libs/xpcom18a4/xpcom/io/nsIAsyncInputStream.idl new file mode 100644 index 00000000..6ce0bb30 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsIAsyncInputStream.idl @@ -0,0 +1,136 @@ +/* ***** 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 "nsIInputStream.idl" + +interface nsIInputStreamCallback; +interface nsIEventTarget; + +/** + * If an input stream is non-blocking, it may return NS_BASE_STREAM_WOULD_BLOCK + * when read. The caller must then wait for the stream to have some data to + * read. If the stream implements nsIAsyncInputStream, then the caller can use + * this interface to request an asynchronous notification when the stream + * becomes readable or closed (via the AsyncWait method). + * + * While this interface is almost exclusively used with non-blocking streams, it + * is not necessary that nsIInputStream::isNonBlocking return true. Nor is it + * necessary that a non-blocking nsIInputStream implementation also implement + * nsIAsyncInputStream. + */ +[scriptable, uuid(15a15329-00de-44e8-ab06-0d0b0d43dc5b)] +interface nsIAsyncInputStream : nsIInputStream +{ + /** + * This method closes the stream and sets its internal status. If the + * stream is already closed, then this method is ignored. Once the stream + * is closed, the stream's status cannot be changed. Any successful status + * code passed to this method is treated as NS_BASE_STREAM_CLOSED, which + * has an effect equivalent to nsIInputStream::close. + * + * NOTE: this method exists in part to support pipes, which have both an + * input end and an output end. If the input end of a pipe is closed, then + * writes to the output end of the pipe will fail. The error code returned + * when an attempt is made to write to a "broken" pipe corresponds to the + * status code passed in when the input end of the pipe was closed, which + * greatly simplifies working with pipes in some cases. + * + * @param aStatus + * The error that will be reported if this stream is accessed after + * it has been closed. + */ + void closeWithStatus(in nsresult aStatus); + + /** + * Asynchronously wait for the stream to be readable or closed. The + * notification is one-shot, meaning that each asyncWait call will result + * in exactly one notification callback. After the OnInputStreamReady event + * is dispatched, the stream releases its reference to the + * nsIInputStreamCallback object. It is safe to call asyncWait again from the + * notification handler. + * + * This method may be called at any time (even if read has not been called). + * In other words, this method may be called when the stream already has + * data to read. It may also be called when the stream is closed. If the + * stream is already readable or closed when AsyncWait is called, then the + * OnInputStreamReady event will be dispatched immediately. Otherwise, the + * event will be dispatched when the stream becomes readable or closed. + * + * @param aCallback + * This object is notified when the stream becomes ready. + * @param aFlags + * This parameter specifies optional flags passed in to configure + * the behavior of this method. Pass zero to specify no flags. + * @param aRequestedCount + * Wait until at least this many bytes can be read. This is only + * a suggestion to the underlying stream; it may be ignored. The + * caller may pass zero to indicate no preference. + * @param aEventTarget + * Specify NULL to receive notification on ANY thread (possibly even + * recursively on the calling thread -- i.e., synchronously), or + * specify that the notification be delivered to a specific event + * target. + */ + void asyncWait(in nsIInputStreamCallback aCallback, + in unsigned long aFlags, + in unsigned long aRequestedCount, + in nsIEventTarget aEventTarget); + + /** + * If passed to asyncWait, this flag overrides the default behavior, + * causing the OnInputStreamReady notification to be suppressed until the + * stream becomes closed (either as a result of closeWithStatus/close being + * called on the stream or possibly due to some error in the underlying + * stream). + */ + const unsigned long WAIT_CLOSURE_ONLY = (1<<0); +}; + +/** + * This is a companion interface for nsIAsyncInputStream::asyncWait. + */ +[scriptable, uuid(d1f28e94-3a6e-4050-a5f5-2e81b1fc2a43)] +interface nsIInputStreamCallback : nsISupports +{ + /** + * Called to indicate that the stream is either readable or closed. + * + * @param aStream + * The stream whose asyncWait method was called. + */ + void onInputStreamReady(in nsIAsyncInputStream aStream); +}; diff --git a/src/libs/xpcom18a4/xpcom/io/nsIAsyncOutputStream.idl b/src/libs/xpcom18a4/xpcom/io/nsIAsyncOutputStream.idl new file mode 100644 index 00000000..b0dd9ec0 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsIAsyncOutputStream.idl @@ -0,0 +1,136 @@ +/* ***** 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 "nsIOutputStream.idl" + +interface nsIOutputStreamCallback; +interface nsIEventTarget; + +/** + * If an output stream is non-blocking, it may return NS_BASE_STREAM_WOULD_BLOCK + * when written to. The caller must then wait for the stream to become + * writable. If the stream implements nsIAsyncOutputStream, then the caller can + * use this interface to request an asynchronous notification when the stream + * becomes writable or closed (via the AsyncWait method). + * + * While this interface is almost exclusively used with non-blocking streams, it + * is not necessary that nsIOutputStream::isNonBlocking return true. Nor is it + * necessary that a non-blocking nsIOutputStream implementation also implement + * nsIAsyncOutputStream. + */ +[scriptable, uuid(10dc9c94-8aff-49c6-8af9-d7fdb7339dae)] +interface nsIAsyncOutputStream : nsIOutputStream +{ + /** + * This method closes the stream and sets its internal status. If the + * stream is already closed, then this method is ignored. Once the stream + * is closed, the stream's status cannot be changed. Any successful status + * code passed to this method is treated as NS_BASE_STREAM_CLOSED, which + * is equivalent to nsIInputStream::close. + * + * NOTE: this method exists in part to support pipes, which have both an + * input end and an output end. If the output end of a pipe is closed, then + * reads from the input end of the pipe will fail. The error code returned + * when an attempt is made to read from a "closed" pipe corresponds to the + * status code passed in when the output end of the pipe is closed, which + * greatly simplifies working with pipes in some cases. + * + * @param aStatus + * The error that will be reported if this stream is accessed after + * it has been closed. + */ + void closeWithStatus(in nsresult reason); + + /** + * Asynchronously wait for the stream to be writable or closed. The + * notification is one-shot, meaning that each asyncWait call will result + * in exactly one notification callback. After the OnOutputStreamReady event + * is dispatched, the stream releases its reference to the + * nsIOutputStreamCallback object. It is safe to call asyncWait again from the + * notification handler. + * + * This method may be called at any time (even if write has not been called). + * In other words, this method may be called when the stream already has + * room for more data. It may also be called when the stream is closed. If + * the stream is already writable or closed when AsyncWait is called, then the + * OnOutputStreamReady event will be dispatched immediately. Otherwise, the + * event will be dispatched when the stream becomes writable or closed. + * + * @param aCallback + * This object is notified when the stream becomes ready. + * @param aFlags + * This parameter specifies optional flags passed in to configure + * the behavior of this method. Pass zero to specify no flags. + * @param aRequestedCount + * Wait until at least this many bytes can be written. This is only + * a suggestion to the underlying stream; it may be ignored. The + * caller may pass zero to indicate no preference. + * @param aEventTarget + * Specify NULL to receive notification on ANY thread (possibly even + * recursively on the calling thread -- i.e., synchronously), or + * specify that the notification be delivered to a specific event + * target. + */ + void asyncWait(in nsIOutputStreamCallback aCallback, + in unsigned long aFlags, + in unsigned long aRequestedCount, + in nsIEventTarget aEventTarget); + + /** + * If passed to asyncWait, this flag overrides the default behavior, + * causing the OnOutputStreamReady notification to be suppressed until the + * stream becomes closed (either as a result of closeWithStatus/close being + * called on the stream or possibly due to some error in the underlying + * stream). + */ + const unsigned long WAIT_CLOSURE_ONLY = (1<<0); +}; + +/** + * This is a companion interface for nsIAsyncOutputStream::asyncWait. + */ +[scriptable, uuid(40dbcdff-9053-42c5-a57c-3ec910d0f148)] +interface nsIOutputStreamCallback : nsISupports +{ + /** + * Called to indicate that the stream is either writable or closed. + * + * @param aStream + * The stream whose asyncWait method was called. + */ + void onOutputStreamReady(in nsIAsyncOutputStream aStream); +}; diff --git a/src/libs/xpcom18a4/xpcom/io/nsIBaseStream.idl b/src/libs/xpcom18a4/xpcom/io/nsIBaseStream.idl new file mode 100644 index 00000000..12e4c5f0 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsIBaseStream.idl @@ -0,0 +1,45 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsISupports.idl" + +[scriptable, uuid(6ccb17a0-e95e-11d1-beae-00805f8a66dc)] +interface nsIBaseStream : nsISupports +{ + /** Close the stream. */ + void close(); +}; diff --git a/src/libs/xpcom18a4/xpcom/io/nsIBinaryInputStream.idl b/src/libs/xpcom18a4/xpcom/io/nsIBinaryInputStream.idl new file mode 100644 index 00000000..bc9ea0b5 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsIBinaryInputStream.idl @@ -0,0 +1,121 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * ***** 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 Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsIInputStream.idl" +#include "nsrootidl.idl" + +/** + * This interface allows consumption of primitive data types from a "binary + * stream" containing untagged, big-endian binary data, i.e. as produced by an + * implementation of nsIBinaryOutputStream. This might be used, for example, + * to implement network protocols or to read from architecture-neutral disk + * files, i.e. ones that can be read and written by both big-endian and + * little-endian platforms. + * + * @See nsIBinaryOutputStream + */ + +[scriptable, uuid(7b456cb0-8772-11d3-90cf-0040056a906e)] +interface nsIBinaryInputStream : nsIInputStream { + void setInputStream(in nsIInputStream aInputStream); + + PRBool readBoolean(); + + PRUint8 read8(); + PRUint16 read16(); + PRUint32 read32(); + PRUint64 read64(); + + float readFloat(); + double readDouble(); + + /** + * Read a NUL-terminated 8-bit char* string from a binary stream. + */ + ACString readCString(); + + /** + * Read a NUL-terminated 16-bit PRUnichar* string from a binary stream. + */ + AString readString(); + + /** + * Read an opaque byte array from a binary stream. + */ + void readBytes(in PRUint32 aLength, + [size_is(aLength), retval] out string aString); + + /** + * Read an opaque byte array from a binary stream, storing the results + * as an array of PRUint8s. + */ + void readByteArray(in PRUint32 aLength, + [array, size_is(aLength), retval] out PRUint8 aBytes); +}; + +%{C++ + +inline nsresult +NS_ReadOptionalCString(nsIBinaryInputStream* aStream, nsACString& aResult) +{ + PRBool nonnull; + nsresult rv = aStream->ReadBoolean(&nonnull); + if (NS_SUCCEEDED(rv)) { + if (nonnull) + rv = aStream->ReadCString(aResult); + else + aResult.Truncate(); + } + return rv; +} + +inline nsresult +NS_ReadOptionalString(nsIBinaryInputStream* aStream, nsAString& aResult) +{ + PRBool nonnull; + nsresult rv = aStream->ReadBoolean(&nonnull); + if (NS_SUCCEEDED(rv)) { + if (nonnull) + rv = aStream->ReadString(aResult); + else + aResult.Truncate(); + } + return rv; +} + +%} diff --git a/src/libs/xpcom18a4/xpcom/io/nsIBinaryOutputStream.idl b/src/libs/xpcom18a4/xpcom/io/nsIBinaryOutputStream.idl new file mode 100644 index 00000000..16a100b7 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsIBinaryOutputStream.idl @@ -0,0 +1,119 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * ***** 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 Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsIOutputStream.idl" +#include "nsrootidl.idl" + +/** + * This interface allows writing of primitive data types (integers, + * floating-point values, booleans, etc.) to a stream in a binary, untagged, + * fixed-endianness format. This might be used, for example, to implement + * network protocols or to produce architecture-neutral binary disk files, + * i.e. ones that can be read and written by both big-endian and little-endian + * platforms. Output is written in big-endian order (high-order byte first), + * as this is traditional network order. + * + * @See nsIBinaryInputStream + */ + +[scriptable, uuid(204ee610-8765-11d3-90cf-0040056a906e)] +interface nsIBinaryOutputStream : nsIOutputStream { + void setOutputStream(in nsIOutputStream aOutputStream); + + void writeBoolean(in PRBool aBoolean); + + void write8(in PRUint8 aByte); + void write16(in PRUint16 a16); + void write32(in PRUint32 a32); + void write64(in PRUint64 a64); + + void writeFloat(in float aFloat); + void writeDouble(in double aDouble); + + /** + * Write a NUL-terminated 8-bit char* string to a binary stream. + */ + void writeStringZ(in string aString); + + /** + * Write a NUL-terminated 16-bit PRUnichar* string to a binary stream. + */ + void writeWStringZ(in wstring aString); + + /** + * Write a NUL-terminated UTF8-encoded string to a binary stream, produced + * from a NUL-terminated 16-bit PRUnichar* string argument. + */ + void writeUtf8Z(in wstring aString); + + /** + * Write an opaque byte array to a binary stream. + */ + void writeBytes([size_is(aLength)] in string aString, in PRUint32 aLength); + + /** + * Write an opaque byte array to a binary stream. + */ + void writeByteArray([array, size_is(aLength)] in PRUint8 aBytes, + in PRUint32 aLength); + +}; + +%{C++ + +inline nsresult +NS_WriteOptionalStringZ(nsIBinaryOutputStream* aStream, const char* aString) +{ + PRBool nonnull = (aString != nsnull); + nsresult rv = aStream->WriteBoolean(nonnull); + if (NS_SUCCEEDED(rv) && nonnull) + rv = aStream->WriteStringZ(aString); + return rv; +} + +inline nsresult +NS_WriteOptionalWStringZ(nsIBinaryOutputStream* aStream, const PRUnichar* aString) +{ + PRBool nonnull = (aString != nsnull); + nsresult rv = aStream->WriteBoolean(nonnull); + if (NS_SUCCEEDED(rv) && nonnull) + rv = aStream->WriteWStringZ(aString); + return rv; +} + +%} diff --git a/src/libs/xpcom18a4/xpcom/io/nsIByteArrayInputStream.idl b/src/libs/xpcom18a4/xpcom/io/nsIByteArrayInputStream.idl new file mode 100644 index 00000000..a124e923 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsIByteArrayInputStream.idl @@ -0,0 +1,48 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsIInputStream.idl" + +[scriptable, uuid(b5a21556-35fc-4815-aff1-f9142639686e)] +interface nsIByteArrayInputStream : nsIInputStream +{ +}; + +%{C++ +extern NS_COM nsresult +NS_NewByteArrayInputStream (nsIByteArrayInputStream ** aResult, char * buffer, unsigned long size); +%} diff --git a/src/libs/xpcom18a4/xpcom/io/nsIDirectoryEnumerator.idl b/src/libs/xpcom18a4/xpcom/io/nsIDirectoryEnumerator.idl new file mode 100644 index 00000000..b32a7f62 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsIDirectoryEnumerator.idl @@ -0,0 +1,68 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 the Directory Enumerator Interface. + * + * The Initial Developer of the Original Code is Google Inc. + * Portions created by the Initial Developer are Copyright (C) 2005 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Ben Goodger + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsISupports.idl" + +interface nsIFile; + +/** + * This interface provides a means for enumerating the contents of a directory. + * It is similar to nsISimpleEnumerator except the retrieved entries are QI'ed + * to nsIFile, and there is a mechanism for closing the directory when the + * enumeration is complete. + * + * @status UNDER_REVIEW + */ +[scriptable, uuid(31f7f4ae-6916-4f2d-a81e-926a4e3022ee)] +interface nsIDirectoryEnumerator : nsISupports +{ + /** + * Retrieves the next file in the sequence. The "nextFile" element is the + * first element upon the first call. This attribute is null if there is no + * next element. + */ + readonly attribute nsIFile nextFile; + + /** + * Closes the directory being enumerated, releasing the system resource. + * @throws NS_OK if the call succeeded and the directory was closed. + * NS_ERROR_FAILURE if the directory close failed. + * It is safe to call this function many times. + */ + void close(); +}; + diff --git a/src/libs/xpcom18a4/xpcom/io/nsIDirectoryService.idl b/src/libs/xpcom18a4/xpcom/io/nsIDirectoryService.idl new file mode 100644 index 00000000..c34b7aa9 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsIDirectoryService.idl @@ -0,0 +1,138 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsISupports.idl" +#include "nsIFile.idl" + +/** + * nsIDirectoryServiceProvider + * + * Used by Directory Service to get file locations. + * + * @status FROZEN + */ + +[scriptable, uuid(bbf8cab0-d43a-11d3-8cc2-00609792278c)] +interface nsIDirectoryServiceProvider: nsISupports +{ + /** + * getFile + * + * Directory Service calls this when it gets the first request for + * a prop or on every request if the prop is not persistent. + * + * @param prop The symbolic name of the file. + * @param persistent TRUE - The returned file will be cached by Directory + * Service. Subsequent requests for this prop will + * bypass the provider and use the cache. + * FALSE - The provider will be asked for this prop + * each time it is requested. + * + * @return The file represented by the property. + * + */ + nsIFile getFile(in string prop, out PRBool persistent); +}; + +/** + * nsIDirectoryServiceProvider2 + * + * An extension of nsIDirectoryServiceProvider which allows + * multiple files to be returned for the given key. + * + * @status FROZEN + */ + +[scriptable, uuid(2f977d4b-5485-11d4-87e2-0010a4e75ef2)] +interface nsIDirectoryServiceProvider2: nsIDirectoryServiceProvider +{ + /** + * getFiles + * + * Directory Service calls this when it gets a request for + * a prop and the requested type is nsISimpleEnumerator. + * + * @param prop The symbolic name of the file list. + * + * @return An enumerator for a list of file locations. + * The elements in the enumeration are nsIFile + * + */ + nsISimpleEnumerator getFiles(in string prop); +}; + +/** + * nsIDirectoryService + * + * @status FROZEN + */ + +[scriptable, uuid(57a66a60-d43a-11d3-8cc2-00609792278c)] +interface nsIDirectoryService: nsISupports +{ + /** + * init + * + * Must be called. Used internally by XPCOM initialization. + * + */ + void init(); + + /** + * registerProvider + * + * Register a provider with the service. + * + * @param prov The service will keep a strong reference + * to this object. It will be released when + * the service is released. + * + */ + void registerProvider(in nsIDirectoryServiceProvider prov); + + /** + * unregisterProvider + * + * Unregister a provider with the service. + * + * @param prov + * + */ + void unregisterProvider(in nsIDirectoryServiceProvider prov); +}; + + diff --git a/src/libs/xpcom18a4/xpcom/io/nsIFastLoadFileControl.idl b/src/libs/xpcom18a4/xpcom/io/nsIFastLoadFileControl.idl new file mode 100644 index 00000000..99f5a287 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsIFastLoadFileControl.idl @@ -0,0 +1,123 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 FastLoad code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Brendan Eich (original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsISupports.idl" +#include "nsrootidl.idl" + +interface nsIFile; +interface nsISimpleEnumerator; + +/** + * The nsIFastLoadFileControl interface and its subinterfaces are mix-ins for + * classes implementing nsIObjectInputStream and nsIObjectOutputStream, so that + * those stream types can be used with nsIFastLoadService to access and compute + * FastLoad file checksums, update and check FastLoad file dependencies, and + * multiplex documents loaded via non-blocking i/o. + * + * If an nsIObjectInputStream class doesn't support nsIFastLoadReadControl, or + * an nsIObjectOutputStream class doesn't support nsIFastLoadWriteControl, that + * implementation may still be useful for object serialization, but it can't be + * used to read or write a Mozilla FastLoad file. + */ +[scriptable, uuid(8a1e2c63-af50-4147-af7e-26289dc180dd)] +interface nsIFastLoadFileControl : nsISupports +{ + /** + * Get and set the recorded checksum value from the FastLoad file header. + */ + attribute PRUint32 checksum; + + /** + * Multiplexed document control methods. A FastLoad file may contain + * multiple interleaved documents identified by a URI specifier string, + * and indexed for fast multiplexor select by an opaque URI object key. + * You StartMuxedDocument when initiating a document load, then Select + * before every batch of calls to (de)serialize document data, and End + * when the load completes. + * + * Document multiplexing is necessary to support incremental FastLoad + * development in a non-blocking i/o architecture such as Mozilla, where + * some (but not all, at first, or for a while during development) of the + * results of parsing and compiling various inputs can be multiplexed to + * or from a FastLoad file. + * + * Note: Select returns the previously selected URI object in case the + * caller is synchronously selecting and writing data to the FastLoad + * file, so the caller can reselect the previous URI and return to code + * the continues to write FastLoad data for the previous URI, unaware of + * the nested select/write/reselect. + */ + void startMuxedDocument(in nsISupports aURI, in string aURISpec); + nsISupports selectMuxedDocument(in nsISupports aURI); + void endMuxedDocument(in nsISupports aURI); + + /** + * Return true if aURISpec identifies a muxed document in the FastLoad + * file, false otherwise. + */ + boolean hasMuxedDocument(in string aURISpec); +}; + +[scriptable, uuid(652ecec6-d40b-45b6-afef-641d6c63a35b)] +interface nsIFastLoadReadControl : nsIFastLoadFileControl +{ + /** + * Computes the correct checksum of the FastLoad file, independent of the + * header's checksum value. The header checksum field is treated as zero + * when computing the checksum. + */ + PRUint32 computeChecksum(); + + /** + * Get the collection of dependency nsIFile instances recorded during the + * FastLoad file write or read/update process, and checked during the read + * process to invalidate the FastLoad file if any dependencies are newer. + */ + readonly attribute nsISimpleEnumerator dependencies; +}; + +[scriptable, uuid(2ad6e9e6-1379-4e45-a899-a54b27ff915c)] +interface nsIFastLoadWriteControl : nsIFastLoadFileControl +{ + /** + * Add a file dependency of the FastLoad file (e.g., a .jar file) to the + * set of dependencies that trigger regeneration if any dependency has a + * last-modified-time greater than the FastLoad file's mtime. + */ + void addDependency(in nsIFile aFile); +}; diff --git a/src/libs/xpcom18a4/xpcom/io/nsIFastLoadService.idl b/src/libs/xpcom18a4/xpcom/io/nsIFastLoadService.idl new file mode 100644 index 00000000..0b177463 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsIFastLoadService.idl @@ -0,0 +1,155 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 FastLoad code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Brendan Eich (original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsISupports.idl" +#include "nsrootidl.idl" + +interface nsIFastLoadReadControl; +interface nsIFile; +interface nsIInputStream; +interface nsIOutputStream; +interface nsIObjectInputStream; +interface nsIObjectOutputStream; + +[scriptable, uuid(715577db-d9c5-464a-a32e-0a40c29b22d4)] +interface nsIFastLoadFileIO : nsISupports +{ + readonly attribute nsIInputStream inputStream; + readonly attribute nsIOutputStream outputStream; +}; + +[scriptable, uuid(759e475e-0c23-4dbf-b1b8-78c9369e3072)] +interface nsIFastLoadService : nsISupports +{ + nsIFile newFastLoadFile(in string aBaseName); + + nsIObjectInputStream newInputStream(in nsIInputStream aSrcStream); + nsIObjectOutputStream newOutputStream(in nsIOutputStream aDestStream); + + // Flag values for the direction attribute and the aDirectionFlags + // parameter to startMuxedDocument. + const PRInt32 NS_FASTLOAD_READ = 1; + const PRInt32 NS_FASTLOAD_WRITE = 2; + + attribute nsIObjectInputStream inputStream; + attribute nsIObjectOutputStream outputStream; + attribute nsIFastLoadFileIO fileIO; + readonly attribute PRInt32 direction; + + /** + * These methods associate a URI object with its spec, for faster select + * using the object pointer as a key, rather than the spec string. The + * selectMuxedDocument method returns the previously selected URI object, + * in case a caller needs to reselect the previous after muxing data for + * a given URI synchronously. For the non-blocking or "asynchronous" i/o + * case, the caller must select the source URI from the FastLoad multiplex + * before writing a new burst of data parsed from the slow-loaded source. + * + * Clients of inputStream and outputStream should try to demultiplex data + * from the input stream only if fastLoadService->StartMuxedDocument(uri, + * urispec, NS_FASTLOAD_READ) succeeds. If StartMuxedDocument fails with + * NS_ERROR_NOT_AVAILABLE, callers should slow-load the documents, muxing + * their data to the current output stream. + */ + void startMuxedDocument(in nsISupports aURI, + in string aURISpec, + in PRInt32 aDirectionFlags); + nsISupports selectMuxedDocument(in nsISupports aURI); + void endMuxedDocument(in nsISupports aURI); + + void addDependency(in nsIFile aFile); + + PRUint32 computeChecksum(in nsIFile aFile, + in nsIFastLoadReadControl aControl); + void cacheChecksum(in nsIFile aFile, + in nsIObjectOutputStream aStream); + + [noscript] void getFastLoadReferent(inout nsISupports aPtr); + + [noscript] void readFastLoadPtr(in nsIObjectInputStream aInputStream, + inout nsISupports aPtr); + + [noscript] void writeFastLoadPtr(in nsIObjectOutputStream aOutputStream, + in nsISupports aPtr); + + /** + * Return true if aURISpec identifies a muxed document in the FastLoad + * file, false otherwise. + */ + boolean hasMuxedDocument(in string aURISpec); +}; + +%{C++ +#define NS_FASTLOADSERVICE_CLASSNAME "Mozilla FastLoad Service" + +#define NS_FASTLOADSERVICE_CID \ + {0xc943093c,0xac94,0x4bee,{0x84,0x0b,0x8b,0x5a,0x6e,0x31,0x4f,0xa7}} + +#define NS_FASTLOADSERVICE_CONTRACTID \ + "@mozilla.org/fast-load-service;1" + +#ifndef nsCOMPtr_h___ +# include "nsCOMPtr.h" +#endif +#ifndef __gen_nsIFile_h__ +# include "nsIFile.h" +#endif +#ifndef nsIServiceManager_h___ +# include "nsIServiceManager.h" +#endif + +inline const nsGetServiceByCID +do_GetFastLoadService(nsresult *aResultCode = 0) +{ + static NS_DEFINE_CID(kFastLoadServiceCID, NS_FASTLOADSERVICE_CID); + return nsGetServiceByCID(kFastLoadServiceCID, nsnull, aResultCode); +} + +inline nsresult +NS_AddFastLoadDependency(nsIFile* aFile) +{ + nsCOMPtr fastLoadService(do_GetFastLoadService()); + if (fastLoadService) { + nsresult rv = fastLoadService->AddDependency(aFile); + if (NS_FAILED(rv) && rv != NS_ERROR_NOT_AVAILABLE) + return rv; + } + return NS_OK; +} + +%} diff --git a/src/libs/xpcom18a4/xpcom/io/nsIFile.idl b/src/libs/xpcom18a4/xpcom/io/nsIFile.idl new file mode 100644 index 00000000..1d70858e --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsIFile.idl @@ -0,0 +1,343 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Doug Turner + * Christopher Blizzard + * Darin Fisher + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsISupports.idl" + +interface nsISimpleEnumerator; + +/** + * This is the only correct cross-platform way to specify a file. + * Strings are not such a way. If you grew up on windows or unix, you + * may think they are. Welcome to reality. + * + * All methods with string parameters have two forms. The preferred + * form operates on UCS-2 encoded characters strings. An alternate + * form operates on characters strings encoded in the "native" charset. + * + * A string containing characters encoded in the native charset cannot + * be safely passed to javascript via xpconnect. Therefore, the "native + * methods" are not scriptable. + * + * @status FROZEN + */ +[scriptable, uuid(c8c0a080-0868-11d3-915f-d9d889d48e3c)] +interface nsIFile : nsISupports +{ + /** + * Create Types + * + * NORMAL_FILE_TYPE - A normal file. + * DIRECTORY_TYPE - A directory/folder. + */ + const unsigned long NORMAL_FILE_TYPE = 0; + const unsigned long DIRECTORY_TYPE = 1; + + /** + * append[Native] + * + * This function is used for constructing a descendent of the + * current nsIFile. + * + * @param node + * A string which is intended to be a child node of the nsIFile. + * For the |appendNative| method, the node must be in the native + * filesystem charset. + */ + void append(in AString node); + [noscript] void appendNative(in ACString node); + + /** + * Normalize the pathName (e.g. removing .. and . components on Unix). + */ + void normalize(); + + /** + * create + * + * This function will create a new file or directory in the + * file system. Any nodes that have not been created or + * resolved, will be. If the file or directory already + * exists create() will return NS_ERROR_FILE_ALREADY_EXISTS. + * + * @param type + * This specifies the type of file system object + * to be made. The only two types at this time + * are file and directory which are defined above. + * If the type is unrecongnized, we will return an + * error (NS_ERROR_FILE_UNKNOWN_TYPE). + * + * @param permissions + * The unix style octal permissions. This may + * be ignored on systems that do not need to do + * permissions. + */ + void create(in unsigned long type, in unsigned long permissions); + + /** + * Accessor to the leaf name of the file itself. + * For the |nativeLeafName| method, the nativeLeafName must + * be in the native filesystem charset. + */ + attribute AString leafName; + [noscript] attribute ACString nativeLeafName; + + /** + * copyTo[Native] + * + * This will copy this file to the specified newParentDir. + * If a newName is specified, the file will be renamed. + * If 'this' is not created we will return an error + * (NS_ERROR_FILE_TARGET_DOES_NOT_EXIST). + * + * copyTo may fail if the file already exists in the destination + * directory. + * + * copyTo will NOT resolve aliases/shortcuts during the copy. + * + * @param newParentDir + * This param is the destination directory. If the + * newParentDir is null, copyTo() will use the parent + * directory of this file. If the newParentDir is not + * empty and is not a directory, an error will be + * returned (NS_ERROR_FILE_DESTINATION_NOT_DIR). For the + * |CopyToNative| method, the newName must be in the + * native filesystem charset. + * + * @param newName + * This param allows you to specify a new name for + * the file to be copied. This param may be empty, in + * which case the current leaf name will be used. + */ + void copyTo(in nsIFile newParentDir, in AString newName); + [noscript] void CopyToNative(in nsIFile newParentDir, in ACString newName); + + /** + * copyToFollowingLinks[Native] + * + * This function is identical to copyTo with the exception that, + * as the name implies, it follows symbolic links. The XP_UNIX + * implementation always follow symbolic links when copying. For + * the |CopyToFollowingLinks| method, the newName must be in the + * native filesystem charset. + */ + void copyToFollowingLinks(in nsIFile newParentDir, in AString newName); + [noscript] void copyToFollowingLinksNative(in nsIFile newParentDir, in ACString newName); + + /** + * moveTo[Native] + * + * A method to move this file or directory to newParentDir. + * If a newName is specified, the file or directory will be renamed. + * If 'this' is not created we will return an error + * (NS_ERROR_FILE_TARGET_DOES_NOT_EXIST). + * If 'this' is a file, and the destination file already exists, moveTo + * will replace the old file. + * + * moveTo will NOT resolve aliases/shortcuts during the copy. + * moveTo will do the right thing and allow copies across volumes. + * moveTo will return an error (NS_ERROR_FILE_DIR_NOT_EMPTY) if 'this' is + * a directory and the destination directory is not empty. + * moveTo will return an error (NS_ERROR_FILE_ACCESS_DENIED) if 'this' is + * a directory and the destination directory is not writable. + * + * @param newParentDir + * This param is the destination directory. If the + * newParentDir is empty, moveTo() will rename the file + * within its current directory. If the newParentDir is + * not empty and does not name a directory, an error will + * be returned (NS_ERROR_FILE_DESTINATION_NOT_DIR). For + * the |moveToNative| method, the newName must be in the + * native filesystem charset. + * + * @param newName + * This param allows you to specify a new name for + * the file to be moved. This param may be empty, in + * which case the current leaf name will be used. + */ + void moveTo(in nsIFile newParentDir, in AString newName); + [noscript] void moveToNative(in nsIFile newParentDir, in ACString newName); + + /** + * This will try to delete this file. The 'recursive' flag + * must be PR_TRUE to delete directories which are not empty. + * + * This will not resolve any symlinks. + */ + void remove(in boolean recursive); + + /** + * Attributes of nsIFile. + */ + + attribute unsigned long permissions; + attribute unsigned long permissionsOfLink; + + /** + * File Times are to be in milliseconds from + * midnight (00:00:00), January 1, 1970 Greenwich Mean + * Time (GMT). + */ + attribute PRInt64 lastModifiedTime; + attribute PRInt64 lastModifiedTimeOfLink; + + /** + * WARNING! On the Mac, getting/setting the file size with nsIFile + * only deals with the size of the data fork. If you need to + * know the size of the combined data and resource forks use the + * GetFileSizeWithResFork() method defined on nsILocalFileMac. + */ + attribute PRInt64 fileSize; + readonly attribute PRInt64 fileSizeOfLink; + + /** + * target & path + * + * Accessor to the string path. The native version of these + * strings are not guaranteed to be a usable path to pass to + * NSPR or the C stdlib. There are problems that affect + * platforms on which a path does not fully specify a file + * because two volumes can have the same name (e.g., XP_MAC). + * This is solved by holding "private", native data in the + * nsIFile implementation. This native data is lost when + * you convert to a string. + * + * DO NOT PASS TO USE WITH NSPR OR STDLIB! + * + * target + * Find out what the symlink points at. Will give error + * (NS_ERROR_FILE_INVALID_PATH) if not a symlink. + * + * path + * Find out what the nsIFile points at. + * + * Note that the ACString attributes are returned in the + * native filesystem charset. + * + */ + readonly attribute AString target; + [noscript] readonly attribute ACString nativeTarget; + readonly attribute AString path; + [noscript] readonly attribute ACString nativePath; + + boolean exists(); + boolean isWritable(); + boolean isReadable(); + boolean isExecutable(); + boolean isHidden(); + boolean isDirectory(); + boolean isFile(); + boolean isSymlink(); + /** + * Not a regular file, not a directory, not a symlink. + */ + boolean isSpecial(); + + /** + * createUnique + * + * This function will create a new file or directory in the + * file system. Any nodes that have not been created or + * resolved, will be. If this file already exists, we try + * variations on the leaf name "suggestedName" until we find + * one that did not already exist. + * + * If the search for nonexistent files takes too long + * (thousands of the variants already exist), we give up and + * return NS_ERROR_FILE_TOO_BIG. + * + * @param type + * This specifies the type of file system object + * to be made. The only two types at this time + * are file and directory which are defined above. + * If the type is unrecongnized, we will return an + * error (NS_ERROR_FILE_UNKNOWN_TYPE). + * + * @param permissions + * The unix style octal permissions. This may + * be ignored on systems that do not need to do + * permissions. + */ + void createUnique(in unsigned long type, in unsigned long permissions); + + /** + * clone() + * + * This function will allocate and initialize a nsIFile object to the + * exact location of the |this| nsIFile. + * + * @param file + * A nsIFile which this object will be initialize + * with. + * + */ + nsIFile clone(); + + /** + * Will determine if the inFile equals this. + */ + boolean equals(in nsIFile inFile); + + /** + * Will determine if inFile is a descendant of this file + * If |recur| is true, look in subdirectories too + */ + boolean contains(in nsIFile inFile, in boolean recur); + + /** + * Parent will be null when this is at the top of the volume. + */ + readonly attribute nsIFile parent; + + /** + * Returns an enumeration of the elements in a directory. Each + * element in the enumeration is an nsIFile. + * + * @return NS_ERROR_FILE_NOT_DIRECTORY if the current nsIFile does + * not specify a directory. + */ + readonly attribute nsISimpleEnumerator directoryEntries; +}; + +%{C++ +#ifndef MOZILLA_STRICT_API +#include "nsDirectoryServiceUtils.h" +#endif +%} diff --git a/src/libs/xpcom18a4/xpcom/io/nsIInputStream.idl b/src/libs/xpcom18a4/xpcom/io/nsIInputStream.idl new file mode 100644 index 00000000..827f6363 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsIInputStream.idl @@ -0,0 +1,139 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Warren Harris + * Darin Fisher + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsISupports.idl" + +interface nsIInputStream; + +%{C++ +/** + * The signature of the writer function passed to ReadSegments. This + * is the "consumer" of data that gets read from the stream's buffer. + * + * @param aInStream stream being read + * @param aClosure opaque parameter passed to ReadSegments + * @param aFromSegment pointer to memory owned by the input stream + * @param aToOffset amount already read (since ReadSegments was called) + * @param aCount length of fromSegment + * @param aWriteCount number of bytes read + * + * Implementers should return the following: + * + * @return NS_OK and (*aWriteCount > 0) if consumed some data + * @return if not interested in consuming any data + * + * Errors are never passed to the caller of ReadSegments. + * + * NOTE: returning NS_OK and (*aWriteCount = 0) has undefined behavior. + * + * @status FROZEN + */ +typedef NS_CALLBACK(nsWriteSegmentFun)(nsIInputStream *aInStream, + void *aClosure, + const char *aFromSegment, + PRUint32 aToOffset, + PRUint32 aCount, + PRUint32 *aWriteCount); +%} + +native nsWriteSegmentFun(nsWriteSegmentFun); + +/** + * nsIInputStream + * + * @status FROZEN + */ +[scriptable, uuid(fa9c7f6c-61b3-11d4-9877-00c04fa0cf4a)] +interface nsIInputStream : nsISupports +{ + /** + * Close the stream. + */ + void close(); + + /** + * @return number of bytes currently available in the stream + */ + unsigned long available(); + + /** + * Read data from the stream. + * + * @param aBuf the buffer into which the data is to be read + * @param aCount the maximum number of bytes to be read + * + * @return number of bytes read (may be less than aCount). + * @return 0 if reached end of file + * + * @throws NS_BASE_STREAM_WOULD_BLOCK if reading from the input stream would + * block the calling thread (non-blocking mode only) + * @throws on failure + */ + [noscript] unsigned long read(in charPtr aBuf, in unsigned long aCount); + + /** + * Low-level read method that has access to the stream's underlying buffer. + * The writer function may be called multiple times for segmented buffers. + * ReadSegments is expected to keep calling the writer until either there is + * nothing left to read or the writer returns an error. ReadSegments should + * not call the writer with zero bytes to consume. + * + * @param aWriter the "consumer" of the data to be read + * @param aClosure opaque parameter passed to writer + * @param aCount the maximum number of bytes to be read + * + * @return number of bytes read (may be less than aCount) + * @return 0 if reached end of file (or if aWriter refused to consume data) + * + * @throws NS_BASE_STREAM_WOULD_BLOCK if reading from the input stream would + * block the calling thread (non-blocking mode only) + * @throws on failure + * + * NOTE: this function may be unimplemented if a stream has no underlying + * buffer (e.g., socket input stream). + */ + [noscript] unsigned long readSegments(in nsWriteSegmentFun aWriter, + in voidPtr aClosure, + in unsigned long aCount); + + /** + * @return true if stream is non-blocking + */ + boolean isNonBlocking(); +}; diff --git a/src/libs/xpcom18a4/xpcom/io/nsIInputStreamTee.idl b/src/libs/xpcom18a4/xpcom/io/nsIInputStreamTee.idl new file mode 100644 index 00000000..524e7ee2 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsIInputStreamTee.idl @@ -0,0 +1,61 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher (original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsIInputStream.idl" + +interface nsIOutputStream; + +/** + * A nsIInputStreamTee is a wrapper for an input stream, that when read + * reads the specified amount of data from its |source| and copies that + * data to its |sink|. |sink| must be a blocking output stream. + */ +[scriptable, uuid(44e8b2c8-1ecb-4a63-8b23-3e3500c34f32)] +interface nsIInputStreamTee : nsIInputStream +{ + attribute nsIInputStream source; + attribute nsIOutputStream sink; +}; + +%{C++ +// factory method +extern NS_COM nsresult +NS_NewInputStreamTee(nsIInputStream **tee, // read from this input stream + nsIInputStream *source, + nsIOutputStream *sink); +%} diff --git a/src/libs/xpcom18a4/xpcom/io/nsILineInputStream.idl b/src/libs/xpcom18a4/xpcom/io/nsILineInputStream.idl new file mode 100644 index 00000000..23781dc4 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsILineInputStream.idl @@ -0,0 +1,54 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Boris Zbarsky . + * Portions created by the Initial Developer are Copyright (C) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsISupports.idl" + +interface nsILineInputStream; + +[scriptable, uuid(c97b466c-1e6e-4773-a4ab-2b2b3190a7a6)] +interface nsILineInputStream : nsISupports +{ + /** + * Read a single line from the stream, where a line is a + * possibly zero length sequence of 8bit chars terminated by a + * CR, LF, CRLF, LFCR, or eof. + * The line terminator is not returned. + * Return false for end of file, true otherwise + */ + boolean readLine(out ACString aLine); +}; diff --git a/src/libs/xpcom18a4/xpcom/io/nsILocalFile.idl b/src/libs/xpcom18a4/xpcom/io/nsILocalFile.idl new file mode 100644 index 00000000..8d7a1dda --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsILocalFile.idl @@ -0,0 +1,180 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Doug Turner + * Darin Fisher + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsIFile.idl" + +%{C++ +#include "prio.h" +#include "prlink.h" +#include +%} + +[ptr] native PRFileDescStar(PRFileDesc); +[ptr] native PRLibraryStar(PRLibrary); +[ptr] native FILE(FILE); + +/** + * This interface adds methods to nsIFile that are particular to a file + * that is accessible via the local file system. + * + * It follows the same string conventions as nsIFile. + * + * @status FROZEN + */ +[scriptable, uuid(aa610f20-a889-11d3-8c81-000064657374)] +interface nsILocalFile : nsIFile +{ + /** + * initWith[Native]Path + * + * This function will initialize the nsILocalFile object. Any + * internal state information will be reset. + * + * NOTE: This function has a known bug on the macintosh and + * other OSes which do not represent file locations as paths. + * If you do use this function, be very aware of this problem! + * + * @param filePath + * A string which specifies a full file path to a + * location. Relative paths will be treated as an + * error (NS_ERROR_FILE_UNRECOGNIZED_PATH). For + * initWithNativePath, the filePath must be in the native + * filesystem charset. + */ + void initWithPath(in AString filePath); + [noscript] void initWithNativePath(in ACString filePath); + + /** + * initWithFile + * + * Initialize this object with another file + * + * @param aFile + * the file this becomes equivalent to + */ + void initWithFile(in nsILocalFile aFile); + + /** + * followLinks + * + * This attribute will determine if the nsLocalFile will auto + * resolve symbolic links. By default, this value will be false + * on all non unix systems. On unix, this attribute is effectively + * a noop. + */ + attribute PRBool followLinks; + + [noscript] PRFileDescStar openNSPRFileDesc(in long flags, in long mode); + [noscript] FILE openANSIFileDesc(in string mode); + + [noscript] PRLibraryStar load(); + + readonly attribute PRInt64 diskSpaceAvailable; + + /** + * appendRelative[Native]Path + * + * Append a relative path to the current path of the nsILocalFile object. + * + * @param relativeFilePath + * relativeFilePath is a native relative path. For security reasons, + * this cannot contain .. or cannot start with a directory separator. + * For the |appendRelativeNativePath| method, the relativeFilePath + * must be in the native filesystem charset. + */ + void appendRelativePath(in AString relativeFilePath); + [noscript] void appendRelativeNativePath(in ACString relativeFilePath); + + /** + * Accessor to a null terminated string which will specify + * the file in a persistent manner for disk storage. + * + * The character set of this attribute is undefined. DO NOT TRY TO + * INTERPRET IT AS HUMAN READABLE TEXT! + */ + attribute ACString persistentDescriptor; + + /** + * reveal + * + * Ask the operating system to open the folder which contains + * this file or folder. This routine only works on platforms which + * support the ability to open a folder... + */ + void reveal(); + + /** + * launch + * + * Ask the operating system to attempt to open the file. + * this really just simulates "double clicking" the file on your platform. + * This routine only works on platforms which support this functionality. + */ + void launch(); + + /** + * getRelativeDescriptor + * + * Returns a relative file path in an opaque, XP format. It is therefore + * not a native path. + * + * The character set of the string returned from this function is + * undefined. DO NOT TRY TO INTERPRET IT AS HUMAN READABLE TEXT! + * + * @param fromFile + * the file from which the descriptor is relative. + * There is no defined result if this param is null. + */ + ACString getRelativeDescriptor(in nsILocalFile fromFile); + + /** + * setRelativeDescriptor + * + * Initializes the file to the location relative to fromFile using + * a string returned by getRelativeDescriptor. + * + * @param fromFile + * the file to which the descriptor is relative + * @param relative + * the relative descriptor obtained from getRelativeDescriptor + */ + void setRelativeDescriptor(in nsILocalFile fromFile, in ACString relativeDesc); +}; + diff --git a/src/libs/xpcom18a4/xpcom/io/nsILocalFileMac.idl b/src/libs/xpcom18a4/xpcom/io/nsILocalFileMac.idl new file mode 100644 index 00000000..e04ea7c5 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsILocalFileMac.idl @@ -0,0 +1,262 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Conrad Carlen + * Mark Mentovai + * + * 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 "nsILocalFile.idl" + +%{C++ +#include +#include +%} + + native OSType(OSType); + native FSSpec(FSSpec); +[ptr] native FSSpecPtr(FSSpec); + native FSRef(FSRef); +[ptr] native FSRefPtr(FSRef); + native CFURLRef(CFURLRef); + +[scriptable, uuid(748f3ffe-27d9-4402-9de9-494badbeebf4)] +interface nsILocalFileMac : nsILocalFile +{ + /** + * initWithCFURL + * + * Init this object with a CFURLRef + * + * NOTE: Supported only for XP_MACOSX or TARGET_CARBON + * NOTE: If the path of the CFURL is /a/b/c, at least a/b must exist beforehand. + * + * @param aCFURL the CoreFoundation URL + * + */ + [noscript] void initWithCFURL(in CFURLRef aCFURL); + + /** + * initWithFSRef + * + * Init this object with an FSRef + * + * NOTE: Supported only for XP_MACOSX or TARGET_CARBON + * + * @param aFSRef the native file spec + * + */ + [noscript] void initWithFSRef([const] in FSRefPtr aFSRef); + + /** + * initWithFSSpec + * + * Init this object with an FSSpec + * Legacy method - leaving in place for now + * + * @param aFileSpec the native file spec + * + */ + [noscript] void initWithFSSpec([const] in FSSpecPtr aFileSpec); + + /** + * initToAppWithCreatorCode + * + * Init this object to point to an application having the given + * creator code. If this app is missing, this will fail. It will first + * look for running application with the given creator. + * + * @param aAppCreator the signature of the app + * + */ + [noscript] void initToAppWithCreatorCode(in OSType aAppCreator); + + /** + * getCFURL + * + * Returns the CFURLRef of the file object. The caller is + * responsible for calling CFRelease() on it. + * + * NOTE: Observes the state of the followLinks attribute. + * If the file object is an alias and followLinks is TRUE, returns + * the target of the alias. If followLinks is FALSE, returns + * the unresolved alias file. + * + * NOTE: Supported only for XP_MACOSX or TARGET_CARBON + * + * @return + * + */ + [noscript] CFURLRef getCFURL(); + + /** + * getFSRef + * + * Returns the FSRef of the file object. + * + * NOTE: Observes the state of the followLinks attribute. + * If the file object is an alias and followLinks is TRUE, returns + * the target of the alias. If followLinks is FALSE, returns + * the unresolved alias file. + * + * NOTE: Supported only for XP_MACOSX or TARGET_CARBON + * + * @return + * + */ + [noscript] FSRef getFSRef(); + + /** + * getFSSpec + * + * Returns the FSSpec of the file object. + * + * NOTE: Observes the state of the followLinks attribute. + * If the file object is an alias and followLinks is TRUE, returns + * the target of the alias. If followLinks is FALSE, returns + * the unresolved alias file. + * + * @return + * + */ + [noscript] FSSpec getFSSpec(); + + /** + * fileSizeWithResFork + * + * Returns the combined size of both the data fork and the resource + * fork (if present) rather than just the size of the data fork + * as returned by GetFileSize() + * + */ + readonly attribute PRInt64 fileSizeWithResFork; + + /** + * Use with SetFileType() to specify the signature of current process + */ + const unsigned long CURRENT_PROCESS_CREATOR = 0x8000000; + + /** + * fileType, creator + * + * File type and creator attributes + * + */ + [noscript] attribute OSType fileType; + [noscript] attribute OSType fileCreator; + + /** + * setFileTypeAndCreatorFromMIMEType + * + * Sets the file type and creator code from a MIME type. + * Internet Config is used to determine the mapping. + * + * @param aMIMEType + * + */ + void setFileTypeAndCreatorFromMIMEType(in string aMIMEType); + + /** + * setFileTypeAndCreatorFromExtension + * + * Sets the file type and creator code from a file extension + * Internet Config is used to determine the mapping. + * + * @param aExtension + * + */ + void setFileTypeAndCreatorFromExtension(in string aExtension); + + /** + * launchWithDoc + * + * Launch the application that this file points to with a document. + * + * @param aDocToLoad Must not be NULL. If no document, use nsILocalFile::launch + * @param aLaunchInBackground TRUE if the application should not come to the front. + * + */ + void launchWithDoc(in nsILocalFile aDocToLoad, in boolean aLaunchInBackground); + + /** + * openDocWithApp + * + * Open the document that this file points to with the given application. + * + * @param aAppToOpenWith The application with which to open the document. + * If NULL, the creator code of the document is used + * to determine the application. + * @param aLaunchInBackground TRUE if the application should not come to the front. + * + */ + void openDocWithApp(in nsILocalFile aAppToOpenWith, in boolean aLaunchInBackground); + + /** + * isPackage + * + * returns true if a directory is determined to be a package under Mac OS 9/X + * + */ + boolean isPackage(); + + /** + * bundleDisplayName + * + * returns the display name of the application bundle (usually the human + * readable name of the application) + */ + readonly attribute AString bundleDisplayName; + + /** + * bundleIdentifier + * + * returns the identifier of the bundle + */ + readonly attribute AUTF8String bundleIdentifier; +}; + +%{C++ +extern "C" +{ + +#ifndef XP_MACOSX +NS_EXPORT const char* NS_TruncNodeName(const char *aNode, char *outBuf); +#endif + +NS_EXPORT nsresult NS_NewLocalFileWithFSSpec(const FSSpec* inSpec, PRBool followSymlinks, nsILocalFileMac* *result); + +// NS_NewLocalFileWithFSRef is available since Mozilla 1.8.1. +NS_EXPORT nsresult NS_NewLocalFileWithFSRef(const FSRef* aFSRef, PRBool aFollowSymlinks, nsILocalFileMac** result); +} +%} diff --git a/src/libs/xpcom18a4/xpcom/io/nsILocalFileOS2.idl b/src/libs/xpcom18a4/xpcom/io/nsILocalFileOS2.idl new file mode 100644 index 00000000..95b4177b --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsILocalFileOS2.idl @@ -0,0 +1,90 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Richard L. Walsh. + * Portions created by the Initial Developer are Copyright (C) 2005 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Rich Walsh (Original Author) + * + * 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 "nsILocalFile.idl" + +interface nsIArray; + +[scriptable, uuid(26de2089-239d-4697-818b-bae1fe8e8e0d)] +interface nsILocalFileOS2 : nsILocalFile +{ + /** + * getFileTypes + * + * Returns the file's .TYPE extended attribute as an array of + * nsISupportsCStrings. + * + */ + nsIArray getFileTypes( ); + + /** + * setFileTypes + * + * Sets the file's .TYPE extended attribute from a comma-separated + * list of types (this format is used because clients are unlikely + * to write more than a single type). + * @param fileTypes + * a string in the filesystem's native character set + * + */ + void setFileTypes( in ACString fileTypes ); + + /** + * isFileType + * + * Returns TRUE if the file has a .TYPE extended attribute that + * matches the string passed in. The comparison is case-sensitive. + * @param fileType + * a string in the filesystem's native character set + * + */ + PRBool isFileType( in ACString fileType ); + + /** + * setFileSource + * + * Identifies the origin of a downloaded file by writing the + * source URI's spec to the .SUBJECT extended attribute. + * + * @param aURI + * the source URI + * + */ + void setFileSource( in AUTF8String aURI ); +}; diff --git a/src/libs/xpcom18a4/xpcom/io/nsIMultiplexInputStream.idl b/src/libs/xpcom18a4/xpcom/io/nsIMultiplexInputStream.idl new file mode 100644 index 00000000..ec309ecd --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsIMultiplexInputStream.idl @@ -0,0 +1,88 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 frightening to behold. + * + * The Initial Developer of the Original Code is + * Jonas Sicking. + * Portions created by the Initial Developer are Copyright (C) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Jonas Sicking + * + * 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 "nsIInputStream.idl" + +/** + * The multiplex stream concatinates a list of input streams into a single + * stream. + */ + +[scriptable, uuid(a076fd12-1dd1-11b2-b19a-d53b5dffaade)] +interface nsIMultiplexInputStream : nsIInputStream +{ + /** + * Number of streams in this multiplex-stream + */ + readonly attribute unsigned long count; + + /** + * Appends a stream to the end of the streams. The cursor of the stream + * should be located at the beginning of the stream if the implementation + * of this nsIMultiplexInputStream also is used as an nsISeekableStream. + * @param stream stream to append + */ + void appendStream(in nsIInputStream stream); + + /** + * Insert a stream at specified index. If the cursor of this stream is at + * the beginning of the stream at index, the cursor will be placed at the + * beginning of the inserted stream instead. + * The cursor of the new stream should be located at the beginning of the + * stream if the implementation of this nsIMultiplexInputStream also is + * used as an nsISeekableStream. + * @param stream stream to insert + * @param index index to insert stream at, must be <= count + */ + void insertStream(in nsIInputStream stream, in unsigned long index); + + /** + * Remove stream at specified index. If this stream is the one currently + * being read the readcursor is moved to the beginning of the next + * stream + * @param index remove stream at this index, must be < count + */ + void removeStream(in unsigned long index); + + /** + * Get stream at specified index. + * @param index return stream at this index, must be < count + * @return stream at specified index + */ + nsIInputStream getStream(in unsigned long index); +}; diff --git a/src/libs/xpcom18a4/xpcom/io/nsIObjectInputStream.idl b/src/libs/xpcom18a4/xpcom/io/nsIObjectInputStream.idl new file mode 100644 index 00000000..97c0ca6e --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsIObjectInputStream.idl @@ -0,0 +1,87 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 FastLoad code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Brendan Eich (original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsIBinaryInputStream.idl" +#include "nsrootidl.idl" + +/** + * @see nsIObjectOutputStream + * @see nsIBinaryInputStream + */ + +[scriptable, uuid(6c248606-4eae-46fa-9df0-ba58502368eb)] +interface nsIObjectInputStream : nsIBinaryInputStream +{ + /** + * Read an object from this stream to satisfy a strong or weak reference + * to one of its interfaces. If the interface was not along the primary + * inheritance chain ending in the "root" or XPCOM-identity nsISupports, + * readObject will QueryInterface from the deserialized object root to the + * correct interface, which was specified when the object was serialized. + * + * @see nsIObjectOutputStream + */ + nsISupports readObject(in PRBool aIsStrongRef); + + [notxpcom] nsresult readID(out nsID aID); + + /** + * Optimized deserialization support -- see nsIStreamBufferAccess.idl. + */ + [notxpcom] charPtr getBuffer(in PRUint32 aLength, in PRUint32 aAlignMask); + [notxpcom] void putBuffer(in charPtr aBuffer, in PRUint32 aLength); +}; + +%{C++ + +inline nsresult +NS_ReadOptionalObject(nsIObjectInputStream* aStream, PRBool aIsStrongRef, + nsISupports* *aResult) +{ + PRBool nonnull; + nsresult rv = aStream->ReadBoolean(&nonnull); + if (NS_SUCCEEDED(rv)) { + if (nonnull) + rv = aStream->ReadObject(aIsStrongRef, aResult); + else + *aResult = nsnull; + } + return rv; +} + +%} diff --git a/src/libs/xpcom18a4/xpcom/io/nsIObjectOutputStream.idl b/src/libs/xpcom18a4/xpcom/io/nsIObjectOutputStream.idl new file mode 100644 index 00000000..b8072127 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsIObjectOutputStream.idl @@ -0,0 +1,131 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 FastLoad code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Brendan Eich (original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsIBinaryOutputStream.idl" +#include "nsrootidl.idl" + +/** + * @See nsIObjectInputStream + * @See nsIBinaryOutputStream + */ + +[scriptable, uuid(92c898ac-5fde-4b99-87b3-5d486422094b)] +interface nsIObjectOutputStream : nsIBinaryOutputStream +{ + /** + * Write the object whose "root" or XPCOM-identity nsISupports is aObject. + * The cause for writing this object is a strong or weak reference, so the + * aIsStrongRef argument must tell which kind of pointer is being followed + * here during serialization. + * + * If the object has only one strong reference in the serialization and no + * weak refs, use writeSingleRefObject. This is a valuable optimization: + * it saves space in the stream, and cycles on both ends of the process. + * + * If the reference being serialized is a pointer to an interface not on + * the primary inheritance chain ending in the root nsISupports, you must + * call writeCompoundObject instead of this method. + */ + void writeObject(in nsISupports aObject, in PRBool aIsStrongRef); + + /** + * Write an object referenced singly and strongly via its root nsISupports + * or a subclass of its root nsISupports. There must not be other refs to + * aObject in memory, or in the serialization. + */ + void writeSingleRefObject(in nsISupports aObject); + + /** + * Write the object referenced by an interface pointer at aObject that + * inherits from a non-primary nsISupports, i.e., a reference to one of + * the multiply inherited interfaces derived from an nsISupports other + * than the root or XPCOM-identity nsISupports; or a reference to an + * inner object in the case of true XPCOM aggregation. aIID identifies + * this interface. + */ + void writeCompoundObject(in nsISupports aObject, + in nsIIDRef aIID, + in PRBool aIsStrongRef); + + void writeID(in nsIDRef aID); + + /** + * Optimized serialization support -- see nsIStreamBufferAccess.idl. + */ + [notxpcom] charPtr getBuffer(in PRUint32 aLength, in PRUint32 aAlignMask); + [notxpcom] void putBuffer(in charPtr aBuffer, in PRUint32 aLength); +}; + +%{C++ + +inline nsresult +NS_WriteOptionalObject(nsIObjectOutputStream* aStream, nsISupports* aObject, + PRBool aIsStrongRef) +{ + PRBool nonnull = (aObject != nsnull); + nsresult rv = aStream->WriteBoolean(nonnull); + if (NS_SUCCEEDED(rv) && nonnull) + rv = aStream->WriteObject(aObject, aIsStrongRef); + return rv; +} + +inline nsresult +NS_WriteOptionalSingleRefObject(nsIObjectOutputStream* aStream, + nsISupports* aObject) +{ + PRBool nonnull = (aObject != nsnull); + nsresult rv = aStream->WriteBoolean(nonnull); + if (NS_SUCCEEDED(rv) && nonnull) + rv = aStream->WriteSingleRefObject(aObject); + return rv; +} + +inline nsresult +NS_WriteOptionalCompoundObject(nsIObjectOutputStream* aStream, + nsISupports* aObject, + const nsIID& aIID, + PRBool aIsStrongRef) +{ + PRBool nonnull = (aObject != nsnull); + nsresult rv = aStream->WriteBoolean(nonnull); + if (NS_SUCCEEDED(rv) && nonnull) + rv = aStream->WriteCompoundObject(aObject, aIID, aIsStrongRef); + return rv; +} + +%} diff --git a/src/libs/xpcom18a4/xpcom/io/nsIObservableInputStream.idl b/src/libs/xpcom18a4/xpcom/io/nsIObservableInputStream.idl new file mode 100644 index 00000000..66b2d6e6 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsIObservableInputStream.idl @@ -0,0 +1,67 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 Corp. + * 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 "nsISupports.idl" + +interface nsIInputStream; +interface nsIInputStreamObserver; + +[scriptable, uuid(6f489efe-1dd2-11b2-af78-fb84ae21591b)] +interface nsIObservableInputStream : nsISupports +{ + /** + * Allows users to set an observer on an input stream to receive notifications + * about the consumer emptying the input stream's underlying buffer, or closing the + * stream. This is necessary for non-blocking streams so that the producer can suspend + * itself until more data can be written. + */ + attribute nsIInputStreamObserver observer; +}; + +[scriptable, uuid(019d67cc-61b4-11d4-9877-00c04fa0cf4a)] +interface nsIInputStreamObserver : nsISupports +{ + /** + * Called when the input stream's consumer has read all the existing data from the stream. + */ + void onEmpty(in nsIInputStream inStr); + + /** + * Called when the consumer closes its end of the stream. + */ + void onClose(in nsIInputStream inStr); +}; diff --git a/src/libs/xpcom18a4/xpcom/io/nsIObservableOutputStream.idl b/src/libs/xpcom18a4/xpcom/io/nsIObservableOutputStream.idl new file mode 100644 index 00000000..4cdab3c1 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsIObservableOutputStream.idl @@ -0,0 +1,67 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 Corp. + * 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 "nsISupports.idl" + +interface nsIOutputStream; +interface nsIOutputStreamObserver; + +[scriptable, uuid(15b374f8-1dd2-11b2-87ab-c3299d704fd3)] +interface nsIObservableOutputStream : nsISupports +{ + /** + * Allows users to set an observer on an input stream to receive notifications + * about the consumer emptying the input stream's underlying buffer, or closing the + * stream. This is necessary for non-blocking streams so that the producer can suspend + * itself until more data can be written. + */ + attribute nsIOutputStreamObserver observer; +}; + +[scriptable, uuid(12314194-61b4-11d4-9877-00c04fa0cf4a)] +interface nsIOutputStreamObserver : nsISupports +{ + /** + * Called when the output stream's producer has written more data into the stream. + */ + void onWrite(in nsIOutputStream outStr, in unsigned long amount); + + /** + * Called when the stream's underlying buffer becomes full. + */ + void onFull(in nsIOutputStream outStr); +}; diff --git a/src/libs/xpcom18a4/xpcom/io/nsIOutputStream.idl b/src/libs/xpcom18a4/xpcom/io/nsIOutputStream.idl new file mode 100644 index 00000000..ec5035c6 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsIOutputStream.idl @@ -0,0 +1,167 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Warren Harris + * Darin Fisher + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsISupports.idl" + +interface nsIOutputStream; +interface nsIInputStream; + +%{C++ +/** + * The signature for the reader function passed to WriteSegments. This + * is the "provider" of data that gets written into the stream's buffer. + * + * @param aOutStream stream being written to + * @param aClosure opaque parameter passed to WriteSegments + * @param aToSegment pointer to memory owned by the output stream + * @param aFromOffset amount already written (since WriteSegments was called) + * @param aCount length of toSegment + * @param aReadCount number of bytes written + * + * Implementers should return the following: + * + * @return NS_OK and (*aReadCount > 0) if successfully provided some data + * @return NS_OK and (*aReadCount = 0) or + * @return if not interested in providing any data + * + * Errors are never passed to the caller of WriteSegments. + * + * @status FROZEN + */ +typedef NS_CALLBACK(nsReadSegmentFun)(nsIOutputStream *aOutStream, + void *aClosure, + char *aToSegment, + PRUint32 aFromOffset, + PRUint32 aCount, + PRUint32 *aReadCount); +%} + +native nsReadSegmentFun(nsReadSegmentFun); + +/** + * nsIOutputStream + * + * @status FROZEN + */ +[scriptable, uuid(0d0acd2a-61b4-11d4-9877-00c04fa0cf4a)] +interface nsIOutputStream : nsISupports +{ + /** + * Close the stream. Forces the output stream to flush any buffered data. + * + * @throws NS_BASE_STREAM_WOULD_BLOCK if unable to flush without blocking + * the calling thread (non-blocking mode only) + */ + void close(); + + /** + * Flush the stream. + * + * @throws NS_BASE_STREAM_WOULD_BLOCK if unable to flush without blocking + * the calling thread (non-blocking mode only) + */ + void flush(); + + /** + * Write data into the stream. + * + * @param aBuf the buffer containing the data to be written + * @param aCount the maximum number of bytes to be written + * + * @return number of bytes written (may be less than aCount) + * + * @throws NS_BASE_STREAM_WOULD_BLOCK if writing to the output stream would + * block the calling thread (non-blocking mode only) + * @throws on failure + */ + unsigned long write(in string aBuf, in unsigned long aCount); + + /** + * Writes data into the stream from an input stream. + * + * @param aFromStream the stream containing the data to be written + * @param aCount the maximum number of bytes to be written + * + * @return number of bytes written (may be less than aCount) + * + * @throws NS_BASE_STREAM_WOULD_BLOCK if writing to the output stream would + * block the calling thread (non-blocking mode only) + * @throws on failure + * + * NOTE: This method is defined by this interface in order to allow the + * output stream to efficiently copy the data from the input stream into + * its internal buffer (if any). If this method was provided as an external + * facility, a separate char* buffer would need to be used in order to call + * the output stream's other Write method. + */ + unsigned long writeFrom(in nsIInputStream aFromStream, + in unsigned long aCount); + + /** + * Low-level write method that has access to the stream's underlying buffer. + * The reader function may be called multiple times for segmented buffers. + * WriteSegments is expected to keep calling the reader until either there + * is nothing left to write or the reader returns an error. WriteSegments + * should not call the reader with zero bytes to provide. + * + * @param aReader the "provider" of the data to be written + * @param aClosure opaque parameter passed to reader + * @param aCount the maximum number of bytes to be written + * + * @return number of bytes written (may be less than aCount) + * + * @throws NS_BASE_STREAM_WOULD_BLOCK if writing to the output stream would + * block the calling thread (non-blocking mode only) + * @throws on failure + * + * NOTE: this function may be unimplemented if a stream has no underlying + * buffer (e.g., socket output stream). + */ + [noscript] unsigned long writeSegments(in nsReadSegmentFun aReader, + in voidPtr aClosure, + in unsigned long aCount); + + /** + * @return true if stream is non-blocking + * + * NOTE: writing to a blocking output stream will block the calling thread + * until all given data can be consumed by the stream. + */ + boolean isNonBlocking(); +}; diff --git a/src/libs/xpcom18a4/xpcom/io/nsIPipe.idl b/src/libs/xpcom18a4/xpcom/io/nsIPipe.idl new file mode 100644 index 00000000..bbe3d978 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsIPipe.idl @@ -0,0 +1,211 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsIAsyncInputStream.idl" +#include "nsIAsyncOutputStream.idl" + +interface nsIMemory; + +/** + * nsIPipe represents an in-process buffer that can be read using nsIInputStream + * and written using nsIOutputStream. The reader and writer of a pipe do not + * have to be on the same thread. As a result, the pipe is an ideal mechanism + * to bridge data exchange between two threads. For example, a worker thread + * might write data to a pipe from which the main thread will read. + * + * Each end of the pipe can be either blocking or non-blocking. Recall that a + * non-blocking stream will return NS_BASE_STREAM_WOULD_BLOCK if it cannot be + * read or written to without blocking the calling thread. For example, if you + * try to read from an empty pipe that has not yet been closed, then if that + * pipe's input end is non-blocking, then the read call will fail immediately + * with NS_BASE_STREAM_WOULD_BLOCK as the error condition. However, if that + * pipe's input end is blocking, then the read call will not return until the + * pipe has data or until the pipe is closed. This example presumes that the + * pipe is being filled asynchronously on some background thread. + * + * The pipe supports nsIAsyncInputStream and nsIAsyncOutputStream, which give + * the user of a non-blocking pipe the ability to wait for the pipe to become + * ready again. For example, in the case of an empty non-blocking pipe, the + * user can call AsyncWait on the input end of the pipe to be notified when + * the pipe has data to read (or when the pipe becomes closed). + * + * NS_NewPipe2 and NS_NewPipe provide convenient pipe constructors. In most + * cases nsIPipe is not actually used. It is usually enough to just get + * references to the pipe's input and output end. In which case, the pipe is + * automatically closed when the respective pipe ends are released. + */ +[scriptable, uuid(f4211abc-61b3-11d4-9877-00c04fa0cf4a)] +interface nsIPipe : nsISupports +{ + /** + * initialize this pipe + */ + void init(in boolean nonBlockingInput, + in boolean nonBlockingOutput, + in unsigned long segmentSize, + in unsigned long segmentCount, + in nsIMemory segmentAllocator); + + /** + * The pipe's input end, which also implements nsISearchableInputStream. + */ + readonly attribute nsIAsyncInputStream inputStream; + + /** + * The pipe's output end. + */ + readonly attribute nsIAsyncOutputStream outputStream; +}; + +/** + * XXX this interface doesn't really belong in here. It is here because + * currently nsPipeInputStream is the only implementation of this interface. + */ +[scriptable, uuid(8C39EF62-F7C9-11d4-98F5-001083010E9B)] +interface nsISearchableInputStream : nsISupports +{ + /** + * Searches for a string in the input stream. Since the stream has a notion + * of EOF, it is possible that the string may at some time be in the + * buffer, but is is not currently found up to some offset. Consequently, + * both the found and not found cases return an offset: + * if found, return offset where it was found + * if not found, return offset of the first byte not searched + * In the case the stream is at EOF and the string is not found, the first + * byte not searched will correspond to the length of the buffer. + */ + void search(in string forString, + in boolean ignoreCase, + out boolean found, + out unsigned long offsetSearchedTo); +}; + +%{C++ + +/** + * NS_NewPipe2 + * + * This function supercedes NS_NewPipe. It differs from NS_NewPipe in two + * major ways: + * (1) returns nsIAsyncInputStream and nsIAsyncOutputStream, so it is + * not necessary to QI in order to access these interfaces. + * (2) the size of the pipe is determined by the number of segments + * times the size of each segment. + * + * @param pipeIn + * resulting input end of the pipe + * @param pipeOut + * resulting output end of the pipe + * @param nonBlockingInput + * true specifies non-blocking input stream behavior + * @param nonBlockingOutput + * true specifies non-blocking output stream behavior + * @param segmentSize + * specifies the segment size in bytes (pass 0 to use default value) + * @param segmentCount + * specifies the max number of segments (pass 0 to use default value) + * passing PR_UINT32_MAX here causes the pipe to have "infinite" space. + * this mode can be useful in some cases, but should always be used with + * caution. the default value for this parameter is a finite value. + * @param segmentAlloc + * pass reference to nsIMemory to have all pipe allocations use this + * allocator (pass null to use the default allocator) + */ +extern NS_COM nsresult +NS_NewPipe2(nsIAsyncInputStream **pipeIn, + nsIAsyncOutputStream **pipeOut, + PRBool nonBlockingInput = PR_FALSE, + PRBool nonBlockingOutput = PR_FALSE, + PRUint32 segmentSize = 0, + PRUint32 segmentCount = 0, + nsIMemory *segmentAlloc = nsnull); + +/** + * NS_NewPipe + * + * Preserved for backwards compatibility. Plus, this interface is more + * amiable in certain contexts (e.g., when you don't need the pipe's async + * capabilities). + * + * @param pipeIn + * resulting input end of the pipe + * @param pipeOut + * resulting output end of the pipe + * @param segmentSize + * specifies the segment size in bytes (pass 0 to use default value) + * @param maxSize + * specifies the max size of the pipe (pass 0 to use default value) + * number of segments is maxSize / segmentSize, and maxSize must be a + * multiple of segmentSize. passing PR_UINT32_MAX here causes the + * pipe to have "infinite" space. this mode can be useful in some + * cases, but should always be used with caution. the default value + * for this parameter is a finite value. + * @param nonBlockingInput + * true specifies non-blocking input stream behavior + * @param nonBlockingOutput + * true specifies non-blocking output stream behavior + * @param segmentAlloc + * pass reference to nsIMemory to have all pipe allocations use this + * allocator (pass null to use the default allocator) + */ +inline nsresult +NS_NewPipe(nsIInputStream **pipeIn, + nsIOutputStream **pipeOut, + PRUint32 segmentSize = 0, + PRUint32 maxSize = 0, + PRBool nonBlockingInput = PR_FALSE, + PRBool nonBlockingOutput = PR_FALSE, + nsIMemory *segmentAlloc = nsnull) +{ + PRUint32 segmentCount; + if (segmentSize == 0) + segmentCount = 0; // use default + else + segmentCount = maxSize / segmentSize; + + nsIAsyncInputStream *in; + nsIAsyncOutputStream *out; + nsresult rv = NS_NewPipe2(&in, &out, nonBlockingInput, nonBlockingOutput, + segmentSize, segmentCount, segmentAlloc); + if (NS_FAILED(rv)) return rv; + + *pipeIn = in; + *pipeOut = out; + return NS_OK; +} + +%} diff --git a/src/libs/xpcom18a4/xpcom/io/nsIScriptableInputStream.idl b/src/libs/xpcom18a4/xpcom/io/nsIScriptableInputStream.idl new file mode 100644 index 00000000..9a21b1d0 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsIScriptableInputStream.idl @@ -0,0 +1,73 @@ +/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsISupports.idl" + +interface nsIInputStream; + +/** + * nsIScriptableInputStream provides scriptable access to the nsIInputStream. + * + * @status FROZEN + */ +[scriptable, uuid(a2a32f90-9b90-11d3-a189-0050041caf44)] +interface nsIScriptableInputStream : nsISupports +{ + /** + * Closes the stream. + */ + void close(); + + /** Wrap the given nsIInputStream with this nsIScriptableInputStream. + * @param aInputStream [in] parameter providing the stream to wrap + */ + void init(in nsIInputStream aInputStream); + + /** Return the number of bytes currently available in the stream + * @param _retval [out] parameter to hold the number of bytes + * if an error occurs, the parameter will be undefined + * @return error status + */ + unsigned long available(); + + /** Read data from the stream. + * @param aCount [in] the maximum number of bytes to read + * @param _retval [out] the data + */ + string read(in unsigned long aCount); +}; diff --git a/src/libs/xpcom18a4/xpcom/io/nsISeekableStream.idl b/src/libs/xpcom18a4/xpcom/io/nsISeekableStream.idl new file mode 100644 index 00000000..b2827c12 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsISeekableStream.idl @@ -0,0 +1,102 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 FastLoad code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + + +/* + * nsISeekableStream + * + * Note that a stream might not implement all methods (e.g., a readonly stream + * won't implement setEOF) + * + * @status UNDER_REVIEW + */ + +#include "nsISupports.idl" + +[scriptable, uuid(8429d350-1040-4661-8b71-f2a6ba455980)] +interface nsISeekableStream : nsISupports +{ + /* + * Sets the stream pointer to the value of the 'offset' parameter + */ + const PRInt32 NS_SEEK_SET = 0; + + /* + * Sets the stream pointer to its current location plus the value + * of the offset parameter. + */ + const PRInt32 NS_SEEK_CUR = 1; + + /* + * Sets the stream pointer to the size of the stream plus the value + * of the offset parameter. + */ + const PRInt32 NS_SEEK_END = 2; + + /** + * seek + * + * This method moves the stream offset of the steam implementing this + * interface. + * + * @param whence specifies how to interpret the 'offset' parameter in + * setting the stream offset associated with the implementing + * stream. + * + * @param offset specifies a value, in bytes, that is used in conjunction + * with the 'whence' parameter to set the stream offset of the + * implementing stream. A negative value causes seeking in + * the reverse direction. + */ + void seek(in long whence, in long long offset); + + /** + * tell + * + * This method reports the current offset, in bytes, from the start of the + * stream. + */ + long long tell(); + + + /** + * setEOF + * + * This method truncates the stream at the current offset. + */ + void setEOF(); +}; diff --git a/src/libs/xpcom18a4/xpcom/io/nsIStorageStream.idl b/src/libs/xpcom18a4/xpcom/io/nsIStorageStream.idl new file mode 100644 index 00000000..148136b9 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsIStorageStream.idl @@ -0,0 +1,107 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * ***** 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 Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsISupports.idl" +#include "nsrootidl.idl" + +interface nsIMemory; +interface nsIInputStream; +interface nsIOutputStream; + +/** + * The nsIStorageStream interface maintains an internal data buffer that can be + * filled using a single output stream. One or more independent input streams + * can be created to read the data from the buffer non-destructively. + */ + +[scriptable, uuid(604ad9d0-753e-11d3-90ca-34278643278f)] +interface nsIStorageStream : nsISupports +{ + /** + * + * Initialize the stream, setting up the amount of space that will be + * allocated for the stream's backing-store. + * + * @param segmentSize + * Size of each segment. Must be a power of two. + * @param maxSize + * Maximum total size of this stream. length will always be less + * than or equal to this value. Passing PR_UINT32_MAX is safe. + * @param segmentAllocator + * Which allocator to use for the segments. May be null, in which + * case a default allocator will be used. + */ + void init(in PRUint32 segmentSize, in PRUint32 maxSize, in nsIMemory segmentAllocator); + + /** + * Get a reference to the one and only output stream for this instance. + * The zero-based startPosition argument is used is used to set the initial + * write cursor position. The startPosition cannot be set larger than the + * current buffer length. Calling this method has the side-effect of + * truncating the internal buffer to startPosition bytes. + */ + nsIOutputStream getOutputStream(in PRInt32 startPosition); + + /** + * Create a new input stream to read data (written by the singleton output + * stream) from the internal buffer. Multiple, independent input streams + * can be created. + */ + nsIInputStream newInputStream(in PRInt32 startPosition); + + /** + * The length attribute indicates the total number of bytes stored in the + * nsIStorageStream internal buffer, regardless of any consumption by input + * streams. Assigning to the length field can be used to truncate the + * buffer data, but can not be used when either the instance's output + * stream is in use. + * + * @See #writeInProgress */ + attribute PRUint32 length; + + /** + * True, when output stream has not yet been Close'ed + */ + readonly attribute boolean writeInProgress; +}; + +%{C++ +// Factory method +NS_COM nsresult +NS_NewStorageStream(PRUint32 segmentSize, PRUint32 maxSize, nsIStorageStream **result); +%} diff --git a/src/libs/xpcom18a4/xpcom/io/nsIStreamBufferAccess.idl b/src/libs/xpcom18a4/xpcom/io/nsIStreamBufferAccess.idl new file mode 100644 index 00000000..dc41585f --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsIStreamBufferAccess.idl @@ -0,0 +1,191 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 FastLoad code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Brendan Eich (original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsISupports.idl" +#include "nsrootidl.idl" + +/** + * An interface for access to a buffering stream implementation's underlying + * memory buffer. + * + * Stream implementations that QueryInterface to nsIStreamBufferAccess must + * ensure that all buffers are aligned on the most restrictive type size for + * the current architecture (e.g., sizeof(double) for RISCy CPUs). malloc(3) + * satisfies this requirement. + */ +[uuid(ac923b72-ac87-4892-ac7a-ca385d429435)] +interface nsIStreamBufferAccess : nsISupports +{ + /** + * Get access to a contiguous, aligned run of bytes in the stream's buffer. + * Exactly one successful getBuffer call must occur before a putBuffer call + * taking the non-null pointer returned by the successful getBuffer. + * + * The run of bytes are the next bytes (modulo alignment padding) to read + * for an input stream, and the next bytes (modulo alignment padding) to + * store before (eventually) writing buffered data to an output stream. + * There can be space beyond this run of bytes in the buffer for further + * accesses before the fill or flush point is reached. + * + * @param aLength + * Count of contiguous bytes requested at the address A that satisfies + * (A & aAlignMask) == 0 in the buffer, starting from the current stream + * position, mapped to a buffer address B. The stream implementation + * must pad from B to A by skipping bytes (if input stream) or storing + * zero bytes (if output stream). + * + * @param aAlignMask + * Bit-mask computed by subtracting 1 from the power-of-two alignment + * modulus (e.g., 3 or sizeof(PRUint32)-1 for PRUint32 alignment). + * + * @return + * The aligned pointer to aLength bytes in the buffer, or null if the + * buffer has no room for aLength bytes starting at the next address A + * after the current position that satisfies (A & aAlignMask) == 0. + */ + [notxpcom] charPtr getBuffer(in PRUint32 aLength, in PRUint32 aAlignMask); + + /** + * Relinquish access to the stream's buffer, filling if at end of an input + * buffer, flushing if completing an output buffer. After a getBuffer call + * that returns non-null, putBuffer must be called. + * + * @param aBuffer + * A non-null pointer returned by getBuffer on the same stream buffer + * access object. + * + * @param aLength + * The same count of contiguous bytes passed to the getBuffer call that + * returned aBuffer. + */ + [notxpcom] void putBuffer(in charPtr aBuffer, in PRUint32 aLength); + + /** + * Disable and enable buffering on the stream implementing this interface. + * DisableBuffering flushes an output stream's buffer, and invalidates an + * input stream's buffer. + */ + void disableBuffering(); + void enableBuffering(); + + /** + * The underlying, unbuffered input or output stream. + */ + readonly attribute nsISupports unbufferedStream; +}; + +%{C++ + +// Swap macros, used to convert to/from canonical (big-endian) format +#if defined IS_LITTLE_ENDIAN + +# define NS_SWAP16(x) ((((x) & 0xff) << 8) | (((x) >> 8) & 0xff)) +# define NS_SWAP32(x) ((NS_SWAP16((x) & 0xffff) << 16) | (NS_SWAP16((x) >> 16))) + +// We want to avoid casting to 32-bit types if possible, since that violates +// aliasing rules (a standard compiler may assume that pointers of two types +// do not address overlapping storage). +// +// XXX What if we have a compiler that follows aliasing rules strictly but +// doesn't have a 64-bit int type? +// +// XXXbe shouldn't NSPR's LL_INIT work for non-constant arguments in all cases? + +# if defined HAVE_LONG_LONG +# if PR_BYTES_PER_LONG == 8 +# define ULL_(x) x ## UL +# elif (defined WIN32 || defined WIN16) && !defined __GNUC__ +# define ULL_(x) ((uint64) x ## i64) +# else +# define ULL_(x) x ## ULL +# endif + +# define NS_SWAP64(x) ((((x) & ULL_(0xff00000000000000)) >> 56) | \ + (((x) & ULL_(0x00ff000000000000)) >> 40) | \ + (((x) & ULL_(0x0000ff0000000000)) >> 24) | \ + (((x) & ULL_(0x000000ff00000000)) >> 8) | \ + (((x) & ULL_(0x00000000ff000000)) << 8) | \ + (((x) & ULL_(0x0000000000ff0000)) << 24) | \ + (((x) & ULL_(0x000000000000ff00)) << 40) | \ + (((x) /* & ULL_(0x00000000000000ff) */) << 56)) +# else +# define NS_SWAP64(x) LL_INIT((((x).lo /* & 0xff000000ul */) >> 24) | \ + (((x).lo & 0x00ff0000ul) >> 8) | \ + (((x).lo & 0x0000ff00ul) << 8) | \ + (((x).lo /* & 0x000000fful */) << 24), \ + (((x).hi /* & 0xff000000ul */) >> 24) | \ + (((x).hi & 0x00ff0000ul) >> 8) | \ + (((x).hi & 0x0000ff00ul) << 8) | \ + (((x).hi /* & 0x000000fful */) << 24)) +# endif + +#elif defined IS_BIG_ENDIAN + +# define NS_SWAP16(x) (x) +# define NS_SWAP32(x) (x) +# define NS_SWAP64(x) (x) + +#else + +# error "Unknown byte order" + +#endif + +/** + * These macros get and put a buffer given either an sba parameter that may + * point to an object implementing nsIStreamBufferAccess, nsIObjectInputStream, + * or nsIObjectOutputStream. + */ +#define NS_GET_BUFFER(sba,n,a) ((sba)->GetBuffer(n, a)) +#define NS_PUT_BUFFER(sba,p,n) ((sba)->PutBuffer(p, n)) + +#define NS_GET8(p) (*(PRUint8*)(p)) +#define NS_GET16(p) NS_SWAP16(*(PRUint16*)(p)) +#define NS_GET32(p) NS_SWAP32(*(PRUint32*)(p)) +#define NS_GET64(p) NS_SWAP64(*(PRUint64*)(p)) +#define NS_GET_FLOAT(p) ((float)NS_SWAP32(*(PRUint32*)(p))) +#define NS_GET_DOUBLE(p) ((double)NS_SWAP64(*(PRUint64*)(p))) + +#define NS_PUT8(p,x) (*(PRUint8*)(p) = (x)) +#define NS_PUT16(p,x) (*(PRUint16*)(p) = NS_SWAP16(x)) +#define NS_PUT32(p,x) (*(PRUint32*)(p) = NS_SWAP32(x)) +#define NS_PUT64(p,x) (*(PRUint64*)(p) = NS_SWAP64(x)) +#define NS_PUT_FLOAT(p,x) (*(PRUint32*)(p) = NS_SWAP32(*(PRUint32*)&(x))) +#define NS_PUT_DOUBLE(p,x) (*(PRUint64*)(p) = NS_SWAP64(*(PRUint64*)&(x))) + +%} diff --git a/src/libs/xpcom18a4/xpcom/io/nsIStringStream.idl b/src/libs/xpcom18a4/xpcom/io/nsIStringStream.idl new file mode 100644 index 00000000..09a90548 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsIStringStream.idl @@ -0,0 +1,138 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * mcmullen@netscape.com (original author) + * scc@mozilla.org + * davidm@netscape.com + * darin@netscape.com + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/** + * Based on original code from nsIStringStream.h + */ + +#include "nsIInputStream.idl" + +/** + * nsIStringInputStream + * + * Provides scriptable and specialized C++ only methods for initializing a + * nsIInputStream implementation with a simple character array. + */ +[scriptable, uuid(450cd2d4-f0fd-424d-b365-b1251f80fd53)] +interface nsIStringInputStream : nsIInputStream +{ + /** + * SetData - assign data to the input stream (copied on assignment). + * + * @param data - stream data + * @param dataLen - stream data length (-1 if length should be computed) + * + * NOTE: C++ code should consider using AdoptData or ShareData to avoid + * making an extra copy of the stream data. + */ + void setData(in string data, in long dataLen); + + /** + * NOTE: the following methods are designed to give C++ code added control + * over the ownership and lifetime of the stream data. Use with care :-) + */ + + /** + * AdoptData - assign data to the input stream. the input stream takes + * ownership of the given data buffer and will nsMemory::Free it when + * the input stream is destroyed. + * + * @param data - stream data + * @param dataLen - stream data length (-1 if length should be computed) + */ + [noscript] void adoptData(in charPtr data, in long dataLen); + + /** + * ShareData - assign data to the input stream. the input stream references + * the given data buffer until the input stream is destroyed. the given + * data buffer must outlive the input stream. + * + * @param data - stream data + * @param dataLen - stream data length (-1 if length should be computed) + */ + [noscript] void shareData(in string data, in long dataLen); +}; + +%{C++ + +//----------------------------------------------------------------------------- +// C++ factory methods +//----------------------------------------------------------------------------- + +#include "nsIInputStream.h" +#include "nsString.h" + +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +#define NS_NewByteInputStream VBoxNsxpNS_NewByteInputStream +#define NS_NewCStringInputStream VBoxNsxpNS_NewCStringInputStream +#define NS_NewCharInputStream VBoxNsxpNS_NewCharInputStream +#define NS_NewStringInputStream VBoxNsxpNS_NewStringInputStream +#endif /* VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + +//----------------------------------------------------------------------------- +// Factory method to get an nsInputStream from an nsAString. Result will +// implement nsIStringInputStream and nsIRandomAccessStore +extern "C" NS_COM nsresult +NS_NewStringInputStream(nsIInputStream** aStreamResult, + const nsAString& aStringToRead); + +//----------------------------------------------------------------------------- +// Factory method to get an nsInputStream from an nsACString. Result will +// implement nsIStringInputStream and nsIRandomAccessStore +extern "C" NS_COM nsresult +NS_NewCStringInputStream(nsIInputStream** aStreamResult, + const nsACString& aStringToRead); + +//----------------------------------------------------------------------------- +// Factory method to get an nsInputStream from a string. Result will +// implement nsIStringInputStream and nsIRandomAccessStore +extern "C" NS_COM nsresult +NS_NewCharInputStream(nsIInputStream** aStreamResult, + const char* aStringToRead); + +//----------------------------------------------------------------------------- +// Factory method to get an nsInputStream from a byte buffer. Result will +// implement nsIStringInputStream and nsIRandomAccessStore +extern "C" NS_COM nsresult +NS_NewByteInputStream(nsIInputStream** aStreamResult, + const char* aStringToRead, + PRInt32 aLength); +%} diff --git a/src/libs/xpcom18a4/xpcom/io/nsIUnicharInputStream.h b/src/libs/xpcom18a4/xpcom/io/nsIUnicharInputStream.h new file mode 100644 index 00000000..7232249d --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsIUnicharInputStream.h @@ -0,0 +1,94 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ +#ifndef nsIUnicharInputStream_h___ +#define nsIUnicharInputStream_h___ + +#include "nsIInputStream.h" +#include "nsString.h" +#include "nscore.h" + +class nsIUnicharInputStream; + +typedef NS_CALLBACK(nsWriteUnicharSegmentFun)(nsIUnicharInputStream *aInStream, + void *aClosure, + const PRUnichar *aFromSegment, + PRUint32 aToOffset, + PRUint32 aCount, + PRUint32 *aWriteCount); +/* c4bcf6ee-3a79-4d77-8d48-f17be3199b3b */ +#define NS_IUNICHAR_INPUT_STREAM_IID \ +{ 0xc4bcf6ee, 0x3a79, 0x4d77, \ + {0x8d, 0x48, 0xf1, 0x7b, 0xe3, 0x19, 0x9b, 0x3b} } + +/** Abstract unicode character input stream + * @see nsIInputStream + */ +class NS_NO_VTABLE nsIUnicharInputStream : public nsISupports { +public: + NS_DEFINE_STATIC_IID_ACCESSOR(NS_IUNICHAR_INPUT_STREAM_IID) + + NS_IMETHOD Read(PRUnichar* aBuf, + PRUint32 aCount, + PRUint32 *aReadCount) = 0; + NS_IMETHOD Close() = 0; + NS_IMETHOD ReadSegments(nsWriteUnicharSegmentFun aWriter, + void* aClosure, + PRUint32 aCount, + PRUint32 *aReadCount) = 0; +}; + +/** + * Create a nsIUnicharInputStream that wraps up a string. Data is fed + * from the string out until the done. When this object is destroyed + * it destroyes the string (so make a copy if you don't want it doing + * that) + */ +extern NS_COM nsresult + NS_NewStringUnicharInputStream(nsIUnicharInputStream** aInstancePtrResult, + nsString* aString); + +/** Create a new nsUnicharInputStream that provides a converter for the + * byte input stream aStreamToWrap. If no converter can be found then + * nsnull is returned and the error code is set to + * NS_INPUTSTREAM_NO_CONVERTER. + */ +extern NS_COM nsresult + NS_NewUTF8ConverterStream(nsIUnicharInputStream** aInstancePtrResult, + nsIInputStream* aStreamToWrap, + PRInt32 aBufferSize = 0); + +#endif /* nsUnicharInputStream_h___ */ diff --git a/src/libs/xpcom18a4/xpcom/io/nsInputStreamTee.cpp b/src/libs/xpcom18a4/xpcom/io/nsInputStreamTee.cpp new file mode 100644 index 00000000..b0651ad1 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsInputStreamTee.cpp @@ -0,0 +1,224 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher (original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsIInputStreamTee.h" +#include "nsIInputStream.h" +#include "nsIOutputStream.h" +#include "nsCOMPtr.h" + +class nsInputStreamTee : public nsIInputStreamTee +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIINPUTSTREAM + NS_DECL_NSIINPUTSTREAMTEE + + nsInputStreamTee(); + +private: + ~nsInputStreamTee() {} + + nsresult TeeSegment(const char *buf, PRUint32 count); + + static NS_METHOD WriteSegmentFun(nsIInputStream *, void *, const char *, + PRUint32, PRUint32, PRUint32 *); + +private: + nsCOMPtr mSource; + nsCOMPtr mSink; + nsWriteSegmentFun mWriter; // for implementing ReadSegments + void *mClosure; // for implementing ReadSegments +}; + +nsInputStreamTee::nsInputStreamTee() +{ +} + +nsresult +nsInputStreamTee::TeeSegment(const char *buf, PRUint32 count) +{ + if (!mSink) + return NS_OK; // nothing to do + nsresult rv; + PRUint32 bytesWritten = 0; + while (count) { + rv = mSink->Write(buf + bytesWritten, count, &bytesWritten); + if (NS_FAILED(rv)) { + // ok, this is not a fatal error... just drop our reference to mSink + // and continue on as if nothing happened. + NS_WARNING("Write failed (non-fatal)"); + // catch possible misuse of the input stream tee + NS_ASSERTION(rv != NS_BASE_STREAM_WOULD_BLOCK, "sink must be a blocking stream"); + mSink = 0; + break; + } + NS_ASSERTION(bytesWritten <= count, "wrote too much"); + count -= bytesWritten; + } + return NS_OK; +} + +NS_METHOD +nsInputStreamTee::WriteSegmentFun(nsIInputStream *in, void *closure, const char *fromSegment, + PRUint32 offset, PRUint32 count, PRUint32 *writeCount) +{ + nsInputStreamTee *tee = NS_REINTERPRET_CAST(nsInputStreamTee *, closure); + + nsresult rv = tee->mWriter(in, tee->mClosure, fromSegment, offset, count, writeCount); + if (NS_FAILED(rv) || (*writeCount == 0)) { + NS_ASSERTION((NS_FAILED(rv) ? (*writeCount == 0) : PR_TRUE), + "writer returned an error with non-zero writeCount"); + return rv; + } + + return tee->TeeSegment(fromSegment, *writeCount); +} + +NS_IMPL_ISUPPORTS2(nsInputStreamTee, + nsIInputStreamTee, + nsIInputStream) + +NS_IMETHODIMP +nsInputStreamTee::Close() +{ + NS_ENSURE_TRUE(mSource, NS_ERROR_NOT_INITIALIZED); + nsresult rv = mSource->Close(); + mSource = 0; + mSink = 0; + return rv; +} + +NS_IMETHODIMP +nsInputStreamTee::Available(PRUint32 *avail) +{ + NS_ENSURE_TRUE(mSource, NS_ERROR_NOT_INITIALIZED); + return mSource->Available(avail); +} + +NS_IMETHODIMP +nsInputStreamTee::Read(char *buf, PRUint32 count, PRUint32 *bytesRead) +{ + NS_ENSURE_TRUE(mSource, NS_ERROR_NOT_INITIALIZED); + + nsresult rv = mSource->Read(buf, count, bytesRead); + if (NS_FAILED(rv) || (*bytesRead == 0)) + return rv; + + return TeeSegment(buf, *bytesRead); +} + +NS_IMETHODIMP +nsInputStreamTee::ReadSegments(nsWriteSegmentFun writer, + void *closure, + PRUint32 count, + PRUint32 *bytesRead) +{ + NS_ENSURE_TRUE(mSource, NS_ERROR_NOT_INITIALIZED); + + mWriter = writer; + mClosure = closure; + + return mSource->ReadSegments(WriteSegmentFun, this, count, bytesRead); +} + +NS_IMETHODIMP +nsInputStreamTee::IsNonBlocking(PRBool *result) +{ + NS_ENSURE_TRUE(mSource, NS_ERROR_NOT_INITIALIZED); + return mSource->IsNonBlocking(result); +} + +NS_IMETHODIMP +nsInputStreamTee::SetSource(nsIInputStream *source) +{ + mSource = source; + return NS_OK; +} + +NS_IMETHODIMP +nsInputStreamTee::GetSource(nsIInputStream **source) +{ + NS_IF_ADDREF(*source = mSource); + return NS_OK; +} + +NS_IMETHODIMP +nsInputStreamTee::SetSink(nsIOutputStream *sink) +{ +#ifdef DEBUG + if (sink) { + PRBool nonBlocking; + nsresult rv = sink->IsNonBlocking(&nonBlocking); + if (NS_FAILED(rv) || nonBlocking) + NS_ERROR("sink should be a blocking stream"); + } +#endif + mSink = sink; + return NS_OK; +} + +NS_IMETHODIMP +nsInputStreamTee::GetSink(nsIOutputStream **sink) +{ + NS_IF_ADDREF(*sink = mSink); + return NS_OK; +} + +// factory method + +NS_COM nsresult +NS_NewInputStreamTee(nsIInputStream **result, + nsIInputStream *source, + nsIOutputStream *sink) +{ + nsresult rv; + + nsCOMPtr tee; + NS_NEWXPCOM(tee, nsInputStreamTee); + if (!tee) + return NS_ERROR_OUT_OF_MEMORY; + + rv = tee->SetSource(source); + if (NS_FAILED(rv)) return rv; + + rv = tee->SetSink(sink); + if (NS_FAILED(rv)) return rv; + + NS_ADDREF(*result = tee); + return rv; +} diff --git a/src/libs/xpcom18a4/xpcom/io/nsLinebreakConverter.cpp b/src/libs/xpcom18a4/xpcom/io/nsLinebreakConverter.cpp new file mode 100644 index 00000000..88905f97 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsLinebreakConverter.cpp @@ -0,0 +1,495 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsLinebreakConverter.h" + +#include "nsMemory.h" +#include "nsCRT.h" + + +#if defined(XP_WIN) && defined(_MSC_VER) && (_MSC_VER <= 1100) +#define LOSER_CHAR_CAST(t) (char *)(t) +#define LOSER_UNICHAR_CAST(t) (PRUnichar *)(t) +#else +#define LOSER_CHAR_CAST(t) (t) +#define LOSER_UNICHAR_CAST(t) (t) +#endif + +/*---------------------------------------------------------------------------- + GetLinebreakString + + Could make this inline +----------------------------------------------------------------------------*/ +static const char* GetLinebreakString(nsLinebreakConverter::ELinebreakType aBreakType) +{ + static const char* const sLinebreaks[] = { + "", // any + NS_LINEBREAK, // platform + LFSTR, // content + CRLF, // net + CRSTR, // Mac + LFSTR, // Unix + CRLF, // Windows + nsnull + }; + + return sLinebreaks[aBreakType]; +} + + +/*---------------------------------------------------------------------------- + AppendLinebreak + + Wee inline method to append a line break. Modifies ioDest. +----------------------------------------------------------------------------*/ +template +void AppendLinebreak(T*& ioDest, const char* lineBreakStr) +{ + *ioDest++ = *lineBreakStr; + + if (lineBreakStr[1]) + *ioDest++ = lineBreakStr[1]; +} + +/*---------------------------------------------------------------------------- + CountChars + + Counts occurrences of breakStr in aSrc +----------------------------------------------------------------------------*/ +template +PRInt32 CountLinebreaks(const T* aSrc, PRInt32 inLen, const char* breakStr) +{ + const T* src = aSrc; + const T* srcEnd = aSrc + inLen; + PRInt32 theCount = 0; + + while (src < srcEnd) + { + if (*src == *breakStr) + { + src ++; + if (src < srcEnd && breakStr[1] && *src == breakStr[1]) + src ++; + + theCount ++; + } + else + { + src ++; + } + } + + return theCount; +} + + +/*---------------------------------------------------------------------------- + ConvertBreaks + + ioLen *includes* a terminating null, if any +----------------------------------------------------------------------------*/ +template +static T* ConvertBreaks(const T* inSrc, PRInt32& ioLen, const char* srcBreak, const char* destBreak) +{ + NS_ASSERTION(inSrc && srcBreak && destBreak, "Got a null string"); + + T* resultString = nsnull; + + // handle the no conversion case + if (nsCRT::strcmp(srcBreak, destBreak) == 0) + { + resultString = (T *)nsMemory::Alloc(sizeof(T) * ioLen); + if (!resultString) return nsnull; + memcpy(resultString, inSrc, sizeof(T) * ioLen); // includes the null, if any + return resultString; + } + + PRInt32 srcBreakLen = strlen(srcBreak); + PRInt32 destBreakLen = strlen(destBreak); + + // handle the easy case, where the string length does not change, and the + // breaks are only 1 char long, i.e. CR <-> LF + if (srcBreakLen == destBreakLen && srcBreakLen == 1) + { + resultString = (T *)nsMemory::Alloc(sizeof(T) * ioLen); + if (!resultString) return nsnull; + + const T* src = inSrc; + const T* srcEnd = inSrc + ioLen; // includes null, if any + T* dst = resultString; + + char srcBreakChar = *srcBreak; // we know it's one char long already + char dstBreakChar = *destBreak; + + while (src < srcEnd) + { + if (*src == srcBreakChar) + { + *dst++ = dstBreakChar; + src++; + } + else + { + *dst++ = *src++; + } + } + + // ioLen does not change + } + else + { + // src and dest termination is different length. Do it a slower way. + + // count linebreaks in src. Assumes that chars in 2-char linebreaks are unique. + PRInt32 numLinebreaks = CountLinebreaks(inSrc, ioLen, srcBreak); + + PRInt32 newBufLen = ioLen - (numLinebreaks * srcBreakLen) + (numLinebreaks * destBreakLen); + resultString = (T *)nsMemory::Alloc(sizeof(T) * newBufLen); + if (!resultString) return nsnull; + + const T* src = inSrc; + const T* srcEnd = inSrc + ioLen; // includes null, if any + T* dst = resultString; + + while (src < srcEnd) + { + if (*src == *srcBreak) + { + *dst++ = *destBreak; + if (destBreak[1]) + *dst++ = destBreak[1]; + + src ++; + if (src < srcEnd && srcBreak[1] && *src == srcBreak[1]) + src ++; + } + else + { + *dst++ = *src++; + } + } + + ioLen = newBufLen; + } + + return resultString; +} + + +/*---------------------------------------------------------------------------- + ConvertBreaksInSitu + + Convert breaks in situ. Can only do this if the linebreak length + does not change. +----------------------------------------------------------------------------*/ +template +static void ConvertBreaksInSitu(T* inSrc, PRInt32 inLen, char srcBreak, char destBreak) +{ + T* src = inSrc; + T* srcEnd = inSrc + inLen; + + while (src < srcEnd) + { + if (*src == srcBreak) + *src = destBreak; + + src ++; + } +} + + +/*---------------------------------------------------------------------------- + ConvertUnknownBreaks + + Convert unknown line breaks to the specified break. + + This will convert CRLF pairs to one break, and single CR or LF to a break. +----------------------------------------------------------------------------*/ +template +static T* ConvertUnknownBreaks(const T* inSrc, PRInt32& ioLen, const char* destBreak) +{ + const T* src = inSrc; + const T* srcEnd = inSrc + ioLen; // includes null, if any + + PRInt32 destBreakLen = strlen(destBreak); + PRInt32 finalLen = 0; + + while (src < srcEnd) + { + if (*src == nsCRT::CR) + { + if (src < srcEnd && src[1] == nsCRT::LF) + { + // CRLF + finalLen += destBreakLen; + src ++; + } + else + { + // Lone CR + finalLen += destBreakLen; + } + } + else if (*src == nsCRT::LF) + { + // Lone LF + finalLen += destBreakLen; + } + else + { + finalLen ++; + } + src ++; + } + + T* resultString = (T *)nsMemory::Alloc(sizeof(T) * finalLen); + if (!resultString) return nsnull; + + src = inSrc; + srcEnd = inSrc + ioLen; // includes null, if any + + T* dst = resultString; + + while (src < srcEnd) + { + if (*src == nsCRT::CR) + { + if (src < srcEnd && src[1] == nsCRT::LF) + { + // CRLF + AppendLinebreak(dst, destBreak); + src ++; + } + else + { + // Lone CR + AppendLinebreak(dst, destBreak); + } + } + else if (*src == nsCRT::LF) + { + // Lone LF + AppendLinebreak(dst, destBreak); + } + else + { + *dst++ = *src; + } + src ++; + } + + ioLen = finalLen; + return resultString; +} + + +#ifdef XP_MAC +#pragma mark - +#endif + + +/*---------------------------------------------------------------------------- + ConvertLineBreaks + +----------------------------------------------------------------------------*/ +char* nsLinebreakConverter::ConvertLineBreaks(const char* aSrc, + ELinebreakType aSrcBreaks, ELinebreakType aDestBreaks, PRInt32 aSrcLen, PRInt32* outLen) +{ + NS_ASSERTION(aDestBreaks != eLinebreakAny, "Invalid parameter"); + if (!aSrc) return nsnull; + + PRInt32 sourceLen = (aSrcLen == kIgnoreLen) ? strlen(aSrc) + 1 : aSrcLen; + + char* resultString; + if (aSrcBreaks == eLinebreakAny) + resultString = ConvertUnknownBreaks(LOSER_CHAR_CAST(aSrc), sourceLen, GetLinebreakString(aDestBreaks)); + else + resultString = ConvertBreaks(LOSER_CHAR_CAST(aSrc), sourceLen, GetLinebreakString(aSrcBreaks), GetLinebreakString(aDestBreaks)); + + if (outLen) + *outLen = sourceLen; + return resultString; +} + + +/*---------------------------------------------------------------------------- + ConvertLineBreaksInSitu + +----------------------------------------------------------------------------*/ +nsresult nsLinebreakConverter::ConvertLineBreaksInSitu(char **ioBuffer, ELinebreakType aSrcBreaks, + ELinebreakType aDestBreaks, PRInt32 aSrcLen, PRInt32* outLen) +{ + NS_ASSERTION(ioBuffer && *ioBuffer, "Null pointer passed"); + if (!ioBuffer || !*ioBuffer) return NS_ERROR_NULL_POINTER; + + NS_ASSERTION(aDestBreaks != eLinebreakAny, "Invalid parameter"); + + PRInt32 sourceLen = (aSrcLen == kIgnoreLen) ? strlen(*ioBuffer) + 1 : aSrcLen; + + // can we convert in-place? + const char* srcBreaks = GetLinebreakString(aSrcBreaks); + const char* dstBreaks = GetLinebreakString(aDestBreaks); + + if ( (aSrcBreaks != eLinebreakAny) && + (strlen(srcBreaks) == 1) && + (strlen(dstBreaks) == 1) ) + { + ConvertBreaksInSitu(*ioBuffer, sourceLen, *srcBreaks, *dstBreaks); + if (outLen) + *outLen = sourceLen; + } + else + { + char* destBuffer; + + if (aSrcBreaks == eLinebreakAny) + destBuffer = ConvertUnknownBreaks(*ioBuffer, sourceLen, dstBreaks); + else + destBuffer = ConvertBreaks(*ioBuffer, sourceLen, srcBreaks, dstBreaks); + + if (!destBuffer) return NS_ERROR_OUT_OF_MEMORY; + *ioBuffer = destBuffer; + if (outLen) + *outLen = sourceLen; + } + + return NS_OK; +} + + +/*---------------------------------------------------------------------------- + ConvertUnicharLineBreaks + +----------------------------------------------------------------------------*/ +PRUnichar* nsLinebreakConverter::ConvertUnicharLineBreaks(const PRUnichar* aSrc, + ELinebreakType aSrcBreaks, ELinebreakType aDestBreaks, PRInt32 aSrcLen, PRInt32* outLen) +{ + NS_ASSERTION(aDestBreaks != eLinebreakAny, "Invalid parameter"); + if (!aSrc) return nsnull; + + PRInt32 bufLen = (aSrcLen == kIgnoreLen) ? nsCRT::strlen(aSrc) + 1 : aSrcLen; + + PRUnichar* resultString; + if (aSrcBreaks == eLinebreakAny) + resultString = ConvertUnknownBreaks(LOSER_UNICHAR_CAST(aSrc), bufLen, GetLinebreakString(aDestBreaks)); + else + resultString = ConvertBreaks(LOSER_UNICHAR_CAST(aSrc), bufLen, GetLinebreakString(aSrcBreaks), GetLinebreakString(aDestBreaks)); + + if (outLen) + *outLen = bufLen; + return resultString; +} + + +/*---------------------------------------------------------------------------- + ConvertStringLineBreaks + +----------------------------------------------------------------------------*/ +nsresult nsLinebreakConverter::ConvertUnicharLineBreaksInSitu(PRUnichar **ioBuffer, + ELinebreakType aSrcBreaks, ELinebreakType aDestBreaks, PRInt32 aSrcLen, PRInt32* outLen) +{ + NS_ASSERTION(ioBuffer && *ioBuffer, "Null pointer passed"); + if (!ioBuffer || !*ioBuffer) return NS_ERROR_NULL_POINTER; + NS_ASSERTION(aDestBreaks != eLinebreakAny, "Invalid parameter"); + + PRInt32 sourceLen = (aSrcLen == kIgnoreLen) ? nsCRT::strlen(*ioBuffer) + 1 : aSrcLen; + + // can we convert in-place? + const char* srcBreaks = GetLinebreakString(aSrcBreaks); + const char* dstBreaks = GetLinebreakString(aDestBreaks); + + if ( (aSrcBreaks != eLinebreakAny) && + (strlen(srcBreaks) == 1) && + (strlen(dstBreaks) == 1) ) + { + ConvertBreaksInSitu(*ioBuffer, sourceLen, *srcBreaks, *dstBreaks); + if (outLen) + *outLen = sourceLen; + } + else + { + PRUnichar* destBuffer; + + if (aSrcBreaks == eLinebreakAny) + destBuffer = ConvertUnknownBreaks(*ioBuffer, sourceLen, dstBreaks); + else + destBuffer = ConvertBreaks(*ioBuffer, sourceLen, srcBreaks, dstBreaks); + + if (!destBuffer) return NS_ERROR_OUT_OF_MEMORY; + *ioBuffer = destBuffer; + if (outLen) + *outLen = sourceLen; + } + + return NS_OK; +} + +/*---------------------------------------------------------------------------- + ConvertStringLineBreaks + +----------------------------------------------------------------------------*/ +nsresult nsLinebreakConverter::ConvertStringLineBreaks(nsString& ioString, + ELinebreakType aSrcBreaks, ELinebreakType aDestBreaks) +{ + + NS_ASSERTION(aDestBreaks != eLinebreakAny, "Invalid parameter"); + + // nothing to do + if (ioString.IsEmpty()) return NS_OK; + + nsresult rv; + + // remember the old buffer in case + // we blow it away later + nsString::char_iterator stringBuf; + ioString.BeginWriting(stringBuf); + + PRInt32 newLen; + + rv = ConvertUnicharLineBreaksInSitu(&stringBuf, + aSrcBreaks, aDestBreaks, + ioString.Length() + 1, &newLen); + if (NS_FAILED(rv)) return rv; + + if (stringBuf != ioString.get()) + ioString.Adopt(stringBuf); + + return NS_OK; +} + + + diff --git a/src/libs/xpcom18a4/xpcom/io/nsLinebreakConverter.h b/src/libs/xpcom18a4/xpcom/io/nsLinebreakConverter.h new file mode 100644 index 00000000..ec4bce57 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsLinebreakConverter.h @@ -0,0 +1,156 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +#ifndef nsLinebreakConverter_h_ +#define nsLinebreakConverter_h_ + + +#include "nscore.h" +#include "nsString.h" + +// utility class for converting between different line breaks. + +class NS_COM nsLinebreakConverter +{ +public: + + // Note: enum must match char* array in GetLinebreakString + typedef enum { + eLinebreakAny, // any kind of linebreak (i.e. "don't care" source) + + eLinebreakPlatform, // platform linebreak + eLinebreakContent, // Content model linebreak (LF) + eLinebreakNet, // Form submission linebreak (CRLF) + + eLinebreakMac, // CR + eLinebreakUnix, // LF + eLinebreakWindows // CRLF + + } ELinebreakType; + + enum { + kIgnoreLen = -1 + }; + + /* ConvertLineBreaks + * Convert line breaks in the supplied string, allocating and returning + * a new buffer. Returns nsnull on failure. + * @param aSrc: the source string. if aSrcLen == kIgnoreLen this string is assumed + * to be null terminated, otherwise it must be at least aSrcLen long. + * @param aSrcBreaks: the line breaks in the source. If unknown, pass eLinebreakAny. + * If known, pass the known value, as this may be more efficient. + * @param aDestBreaks: the line breaks you want in the output. + * @param aSrcLen: length of the source. If -1, the source is assumed to be a null- + * terminated string. + * @param aOutLen: used to return character length of returned buffer, if not null. + */ + static char* ConvertLineBreaks(const char* aSrc, + ELinebreakType aSrcBreaks, ELinebreakType aDestBreaks, + PRInt32 aSrcLen = kIgnoreLen, PRInt32* aOutLen = nsnull); + + + /* ConvertUnicharLineBreaks + * Convert line breaks in the supplied string, allocating and returning + * a new buffer. Returns nsnull on failure. + * @param aSrc: the source string. if aSrcLen == kIgnoreLen this string is assumed + * to be null terminated, otherwise it must be at least aSrcLen long. + * @param aSrcBreaks: the line breaks in the source. If unknown, pass eLinebreakAny. + * If known, pass the known value, as this may be more efficient. + * @param aDestBreaks: the line breaks you want in the output. + * @param aSrcLen: length of the source, in characters. If -1, the source is assumed to be a null- + * terminated string. + * @param aOutLen: used to return character length of returned buffer, if not null. + */ + static PRUnichar* ConvertUnicharLineBreaks(const PRUnichar* aSrc, + ELinebreakType aSrcBreaks, ELinebreakType aDestBreaks, + PRInt32 aSrcLen = kIgnoreLen, PRInt32* aOutLen = nsnull); + + + /* ConvertStringLineBreaks + * Convert line breaks in the supplied string, changing the string buffer (i.e. in-place conversion) + * @param ioString: the string to be converted. + * @param aSrcBreaks: the line breaks in the source. If unknown, pass eLinebreakAny. + * If known, pass the known value, as this may be more efficient. + * @param aDestBreaks: the line breaks you want in the output. + * @param aSrcLen: length of the source, in characters. If -1, the source is assumed to be a null- + * terminated string. + */ + static nsresult ConvertStringLineBreaks(nsString& ioString, ELinebreakType aSrcBreaks, ELinebreakType aDestBreaks); + + + /* ConvertLineBreaksInSitu + * Convert line breaks in place if possible. NOTE: THIS MAY REALLOCATE THE BUFFER, + * BUT IT WON'T FREE THE OLD BUFFER (because it doesn't know how). So be prepared + * to keep a copy of the old pointer, and free it if this passes back a new pointer. + * ALSO NOTE: DON'T PASS A STATIC STRING POINTER TO THIS FUNCTION. + * + * @param ioBuffer: the source buffer. if aSrcLen == kIgnoreLen this string is assumed + * to be null terminated, otherwise it must be at least aSrcLen long. + * @param aSrcBreaks: the line breaks in the source. If unknown, pass eLinebreakAny. + * If known, pass the known value, as this may be more efficient. + * @param aDestBreaks: the line breaks you want in the output. + * @param aSrcLen: length of the source. If -1, the source is assumed to be a null- + * terminated string. + * @param aOutLen: used to return character length of returned buffer, if not null. + */ + static nsresult ConvertLineBreaksInSitu(char **ioBuffer, ELinebreakType aSrcBreaks, ELinebreakType aDestBreaks, + PRInt32 aSrcLen = kIgnoreLen, PRInt32* aOutLen = nsnull); + + + /* ConvertUnicharLineBreaksInSitu + * Convert line breaks in place if possible. NOTE: THIS MAY REALLOCATE THE BUFFER, + * BUT IT WON'T FREE THE OLD BUFFER (because it doesn't know how). So be prepared + * to keep a copy of the old pointer, and free it if this passes back a new pointer. + * + * @param ioBuffer: the source buffer. if aSrcLen == kIgnoreLen this string is assumed + * to be null terminated, otherwise it must be at least aSrcLen long. + * @param aSrcBreaks: the line breaks in the source. If unknown, pass eLinebreakAny. + * If known, pass the known value, as this may be more efficient. + * @param aDestBreaks: the line breaks you want in the output. + * @param aSrcLen: length of the source in characters. If -1, the source is assumed to be a null- + * terminated string. + * @param aOutLen: used to return character length of returned buffer, if not null. + */ + static nsresult ConvertUnicharLineBreaksInSitu(PRUnichar **ioBuffer, ELinebreakType aSrcBreaks, ELinebreakType aDestBreaks, + PRInt32 aSrcLen = kIgnoreLen, PRInt32* aOutLen = nsnull); + +}; + + + + +#endif // nsLinebreakConverter_h_ diff --git a/src/libs/xpcom18a4/xpcom/io/nsLocalFile.h b/src/libs/xpcom18a4/xpcom/io/nsLocalFile.h new file mode 100644 index 00000000..8201affb --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsLocalFile.h @@ -0,0 +1,118 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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 Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** + * + * This Original Code has been modified by IBM Corporation. Modifications made by IBM + * described herein are Copyright (c) International Business Machines Corporation, 2000. + * Modifications to Mozilla code or documentation identified per MPL Section 3.3 + * + * Date Modified by Description of modification + * 04/20/2000 IBM Corp. OS/2 build. + */ + +#ifndef _NS_LOCAL_FILE_H_ +#define _NS_LOCAL_FILE_H_ + +#define NS_LOCAL_FILE_CID {0x2e23e220, 0x60be, 0x11d3, {0x8c, 0x4a, 0x00, 0x00, 0x64, 0x65, 0x73, 0x74}} + +#define NS_DECL_NSLOCALFILE_UNICODE_METHODS \ + nsresult AppendUnicode(const PRUnichar *aNode); \ + nsresult GetUnicodeLeafName(PRUnichar **aLeafName); \ + nsresult SetUnicodeLeafName(const PRUnichar *aLeafName); \ + nsresult CopyToUnicode(nsIFile *aNewParentDir, const PRUnichar *aNewLeafName); \ + nsresult CopyToFollowingLinksUnicode(nsIFile *aNewParentDir, const PRUnichar *aNewLeafName); \ + nsresult MoveToUnicode(nsIFile *aNewParentDir, const PRUnichar *aNewLeafName); \ + nsresult GetUnicodeTarget(PRUnichar **aTarget); \ + nsresult GetUnicodePath(PRUnichar **aPath); \ + nsresult InitWithUnicodePath(const PRUnichar *aPath); \ + nsresult AppendRelativeUnicodePath(const PRUnichar *aRelativePath); + +// nsXPComInit needs to know about how we are implemented, +// so here we will export it. Other users should not depend +// on this. + +#include +#include "nsILocalFile.h" + +#ifdef XP_WIN +#include "nsLocalFileWin.h" +#elif defined(XP_MACOSX) && !defined(VBOX_MACOSX_FOLLOWS_UNIX_IO) +#include "nsLocalFileOSX.h" +#elif defined(XP_MAC) +#include "nsLocalFileMac.h" +#elif defined(XP_UNIX) || defined(XP_BEOS) +#include "nsLocalFileUnix.h" +#elif defined(XP_OS2) +#include "nsLocalFileOS2.h" +#else +#error NOT_IMPLEMENTED +#endif + +#define NSRESULT_FOR_RETURN(ret) (((ret) < 0) ? NSRESULT_FOR_ERRNO() : NS_OK) + +inline nsresult +nsresultForErrno(int err) +{ + switch (err) { + case 0: + return NS_OK; + case ENOENT: + return NS_ERROR_FILE_TARGET_DOES_NOT_EXIST; + case ENOTDIR: + return NS_ERROR_FILE_DESTINATION_NOT_DIR; +#ifdef ENOLINK + case ENOLINK: + return NS_ERROR_FILE_UNRESOLVABLE_SYMLINK; +#endif /* ENOLINK */ + case EEXIST: + return NS_ERROR_FILE_ALREADY_EXISTS; +#ifdef EPERM + case EPERM: +#endif /* EPERM */ + case EACCES: + return NS_ERROR_FILE_ACCESS_DENIED; + default: + return NS_ERROR_FAILURE; + } +} + +#define NSRESULT_FOR_ERRNO() nsresultForErrno(errno) + +void NS_StartupLocalFile(); +void NS_ShutdownLocalFile(); + +#endif diff --git a/src/libs/xpcom18a4/xpcom/io/nsLocalFileCommon.cpp b/src/libs/xpcom18a4/xpcom/io/nsLocalFileCommon.cpp new file mode 100644 index 00000000..664c5304 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsLocalFileCommon.cpp @@ -0,0 +1,278 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Doug Turner + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsIServiceManager.h" + +#include "nsLocalFile.h" // includes platform-specific headers +#include "nsLocalFileUnicode.h" + +#include "nsString.h" +#include "nsCOMPtr.h" +#include "nsReadableUtils.h" +#include "nsPrintfCString.h" +#include "nsCRT.h" + +#ifdef XP_WIN +#include +#endif + + +void NS_StartupLocalFile() +{ + nsLocalFile::GlobalInit(); +} + +void NS_ShutdownLocalFile() +{ + nsLocalFile::GlobalShutdown(); +} + +#if (!defined(XP_MAC) && !defined(XP_MACOSX)) || defined(VBOX_MACOSX_FOLLOWS_UNIX_IO) +NS_IMETHODIMP +nsLocalFile::InitWithFile(nsILocalFile *aFile) +{ + NS_ENSURE_ARG(aFile); + + nsCAutoString path; + aFile->GetNativePath(path); + if (path.IsEmpty()) + return NS_ERROR_INVALID_ARG; + return InitWithNativePath(path); +} +#endif + +#if defined(XP_MAC) +#define kMaxFilenameLength 31 +#else +#define kMaxFilenameLength 255 +#endif + +NS_IMETHODIMP +nsLocalFile::CreateUnique(PRUint32 type, PRUint32 attributes) +{ + nsresult rv = Create(type, attributes); + + if (NS_SUCCEEDED(rv)) return NS_OK; + if (rv != NS_ERROR_FILE_ALREADY_EXISTS) return rv; + + nsCAutoString leafName; + rv = GetNativeLeafName(leafName); + + if (NS_FAILED(rv)) return rv; + + const char* lastDot = strrchr(leafName.get(), '.'); + char suffix[kMaxFilenameLength + 1] = ""; + if (lastDot) + { + strncpy(suffix, lastDot, kMaxFilenameLength); // include '.' + suffix[kMaxFilenameLength] = 0; // make sure it's null terminated + leafName.SetLength(lastDot - leafName.get()); // strip suffix and dot. + } + + const int maxRootLength = (kMaxFilenameLength - 4) - strlen(suffix) - 1; + + if ((int)leafName.Length() > (int)maxRootLength) + leafName.SetLength(maxRootLength); + + for (short indx = 1; indx < 10000; indx++) + { + // start with "Picture-1.jpg" after "Picture.jpg" exists + SetNativeLeafName(leafName + + nsPrintfCString("-%d", indx) + + nsDependentCString(suffix)); + + rv = Create(type, attributes); + + if (NS_SUCCEEDED(rv) || rv != NS_ERROR_FILE_ALREADY_EXISTS) + { + return rv; + } + } + + // The disk is full, sort of + return NS_ERROR_FILE_TOO_BIG; +} + +#if defined(XP_MAC) +static const PRUnichar kPathSeparatorChar = ':'; +#elif defined(XP_WIN) || defined(XP_OS2) +static const PRUnichar kPathSeparatorChar = '\\'; +#elif defined(XP_UNIX) || defined(XP_BEOS) +static const PRUnichar kPathSeparatorChar = '/'; +#else +#error Need to define file path separator for your platform +#endif + +#if defined(XP_MAC) +static const char kSlashStr[] = "/"; +static const char kESCSlashStr[] = "%2F"; +#endif + +static PRInt32 SplitPath(PRUnichar *path, PRUnichar **nodeArray, PRInt32 arrayLen) +{ + if (*path == 0) + return 0; + + PRUnichar **nodePtr = nodeArray; + if (*path == kPathSeparatorChar) + path++; + *nodePtr++ = path; + + for (PRUnichar *cp = path; *cp != 0; cp++) { + if (*cp == kPathSeparatorChar) { + *cp++ = 0; + if (*cp == 0) + break; + if (nodePtr - nodeArray >= arrayLen) + return -1; + *nodePtr++ = cp; + } + } + return nodePtr - nodeArray; +} + + +NS_IMETHODIMP +nsLocalFile::GetRelativeDescriptor(nsILocalFile *fromFile, nsACString& _retval) +{ + NS_ENSURE_ARG_POINTER(fromFile); + const PRInt32 kMaxNodesInPath = 32; + + // + // _retval will be UTF-8 encoded + // + + nsresult rv; + _retval.Truncate(0); + + nsAutoString thisPath, fromPath; + PRUnichar *thisNodes[kMaxNodesInPath], *fromNodes[kMaxNodesInPath]; + PRInt32 thisNodeCnt, fromNodeCnt, nodeIndex; + + rv = GetPath(thisPath); + if (NS_FAILED(rv)) + return rv; + rv = fromFile->GetPath(fromPath); + if (NS_FAILED(rv)) + return rv; + + // get raw pointer to mutable string buffer + PRUnichar *thisPathPtr; thisPath.BeginWriting(thisPathPtr); + PRUnichar *fromPathPtr; fromPath.BeginWriting(fromPathPtr); + + thisNodeCnt = SplitPath(thisPathPtr, thisNodes, kMaxNodesInPath); + fromNodeCnt = SplitPath(fromPathPtr, fromNodes, kMaxNodesInPath); + if (thisNodeCnt < 0 || fromNodeCnt < 0) + return NS_ERROR_FAILURE; + + for (nodeIndex = 0; nodeIndex < thisNodeCnt && nodeIndex < fromNodeCnt; ++nodeIndex) { +#ifdef XP_WIN + if (_wcsicmp(thisNodes[nodeIndex], fromNodes[nodeIndex])) + break; +#else + if (nsCRT::strcmp(thisNodes[nodeIndex], fromNodes[nodeIndex])) + break; +#endif + } + + PRInt32 branchIndex = nodeIndex; + for (nodeIndex = branchIndex; nodeIndex < fromNodeCnt; nodeIndex++) + _retval.AppendLiteral("../"); + for (nodeIndex = branchIndex; nodeIndex < thisNodeCnt; nodeIndex++) { + NS_ConvertUCS2toUTF8 nodeStr(thisNodes[nodeIndex]); +#ifdef XP_MAC + nodeStr.ReplaceSubstring(kSlashStr, kESCSlashStr); +#endif + _retval.Append(nodeStr); + if (nodeIndex + 1 < thisNodeCnt) + _retval.Append('/'); + } + + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::SetRelativeDescriptor(nsILocalFile *fromFile, const nsACString& relativeDesc) +{ + NS_NAMED_LITERAL_CSTRING(kParentDirStr, "../"); + + nsCOMPtr targetFile; + nsresult rv = fromFile->Clone(getter_AddRefs(targetFile)); + if (NS_FAILED(rv)) + return rv; + + // + // relativeDesc is UTF-8 encoded + // + + nsCString::const_iterator strBegin, strEnd; + relativeDesc.BeginReading(strBegin); + relativeDesc.EndReading(strEnd); + + nsCString::const_iterator nodeBegin(strBegin), nodeEnd(strEnd); + nsCString::const_iterator pos(strBegin); + + nsCOMPtr parentDir; + while (FindInReadable(kParentDirStr, nodeBegin, nodeEnd)) { + rv = targetFile->GetParent(getter_AddRefs(parentDir)); + if (NS_FAILED(rv)) + return rv; + targetFile = parentDir; + + nodeBegin = nodeEnd; + pos = nodeEnd; + nodeEnd = strEnd; + } + + nodeBegin = nodeEnd = pos; + while (nodeEnd != strEnd) { + FindCharInReadable('/', nodeEnd, strEnd); +#ifdef XP_MAC + nsCAutoString nodeString(Substring(nodeBegin, nodeEnd)); + nodeString.ReplaceSubstring(kESCSlashStr, kSlashStr); + targetFile->Append(NS_ConvertUTF8toUCS2(nodeString)); +#else + targetFile->Append(NS_ConvertUTF8toUCS2(Substring(nodeBegin, nodeEnd))); +#endif + if (nodeEnd != strEnd) // If there's more left in the string, inc over the '/' nodeEnd is on. + ++nodeEnd; + nodeBegin = nodeEnd; + } + + nsCOMPtr targetLocalFile(do_QueryInterface(targetFile)); + return InitWithFile(targetLocalFile); +} diff --git a/src/libs/xpcom18a4/xpcom/io/nsLocalFileMac.cpp b/src/libs/xpcom18a4/xpcom/io/nsLocalFileMac.cpp new file mode 100644 index 00000000..bebc76c1 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsLocalFileMac.cpp @@ -0,0 +1,3554 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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 Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Steve Dagley + * John R. McMullen + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsCOMPtr.h" +#include "nsMemory.h" +#include "nsXPIDLString.h" + +#include "nsLocalFile.h" +#include "nsNativeCharsetUtils.h" +#include "nsISimpleEnumerator.h" +#include "nsIComponentManager.h" +#include "nsIInternetConfigService.h" +#include "nsIMIMEInfo.h" +#include "prtypes.h" +#include "prerror.h" + +#include "nsReadableUtils.h" +#include "nsITimelineService.h" + +#ifdef XP_MACOSX +#include "nsXPIDLString.h" + +#include "private/pprio.h" +#else +#include "pprio.h" // Include this rather than prio.h so we get def of PR_ImportFile +#endif +#include "prmem.h" +#include "plbase64.h" + +#include "FullPath.h" +#include "FileCopy.h" +#include "MoreFilesExtras.h" +#include "DirectoryCopy.h" +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include "macDirectoryCopy.h" + +#include + +// Stupid @#$% header looks like its got extern mojo but it doesn't really +extern "C" +{ +#ifndef XP_MACOSX +// BADPINK - this MSL header doesn't exist under macosx :-( +#include +#endif +} + +#if TARGET_CARBON +#include // Needed for definition of kUnresolvedCFragSymbolAddress +#include +#endif + +#pragma mark [Constants] + +const OSType kDefaultCreator = 'MOSS'; + +#pragma mark - +#pragma mark [nsPathParser] + +class nsPathParser +{ +public: + nsPathParser(const nsACString &path); + + ~nsPathParser() + { + if (mAllocatedBuffer) + nsMemory::Free(mAllocatedBuffer); + } + + const char* First() + { + return nsCRT::strtok(mBuffer, ":", &mNewString); + } + const char* Next() + { + return nsCRT::strtok(mNewString, ":", &mNewString); + } + const char* Remainder() + { + return mNewString; + } + +private: + char mAutoBuffer[512]; + char *mAllocatedBuffer; + char *mBuffer, *mNewString; +}; + +nsPathParser::nsPathParser(const nsACString &inPath) : + mAllocatedBuffer(nsnull), mNewString(nsnull) +{ + PRUint32 inPathLen = inPath.Length(); + if (inPathLen >= sizeof(mAutoBuffer)) { + mAllocatedBuffer = (char *)nsMemory::Alloc(inPathLen + 1); + mBuffer = mAllocatedBuffer; + } + else + mBuffer = mAutoBuffer; + + // copy inPath into mBuffer + nsACString::const_iterator start, end; + inPath.BeginReading(start); + inPath.EndReading(end); + + PRUint32 size, offset = 0; + for ( ; start != end; start.advance(size)) { + const char* buf = start.get(); + size = start.size_forward(); + memcpy(mBuffer + offset, buf, size); + offset += size; + } + mBuffer[offset] = '\0'; +} + +#pragma mark - +#pragma mark [static util funcs] + +static inline void ClearFSSpec(FSSpec& aSpec) +{ + aSpec.vRefNum = 0; + aSpec.parID = 0; + aSpec.name[0] = 0; +} + + +// Simple func to map Mac OS errors into nsresults +static nsresult MacErrorMapper(OSErr inErr) +{ + nsresult outErr; + + switch (inErr) + { + case noErr: + outErr = NS_OK; + break; + + case fnfErr: + outErr = NS_ERROR_FILE_NOT_FOUND; + break; + + case dupFNErr: + outErr = NS_ERROR_FILE_ALREADY_EXISTS; + break; + + case dskFulErr: + outErr = NS_ERROR_FILE_DISK_FULL; + break; + + case fLckdErr: + outErr = NS_ERROR_FILE_IS_LOCKED; + break; + + // Can't find good map for some + case bdNamErr: + outErr = NS_ERROR_FAILURE; + break; + + default: + outErr = NS_ERROR_FAILURE; + break; + } + return outErr; +} + + + +/*---------------------------------------------------------------------------- + IsEqualFSSpec + + Compare two canonical FSSpec records. + + Entry: file1 = pointer to first FSSpec record. + file2 = pointer to second FSSpec record. + + Exit: function result = true if the FSSpec records are equal. +----------------------------------------------------------------------------*/ + +static PRBool IsEqualFSSpec(const FSSpec& file1, const FSSpec& file2) +{ + return + file1.vRefNum == file2.vRefNum && + file1.parID == file2.parID && + EqualString(file1.name, file2.name, false, true); +} + + +/*---------------------------------------------------------------------------- + GetParentFolderSpec + + Given an FSSpec to a (possibly non-existent) file, get an FSSpec for its + parent directory. + +----------------------------------------------------------------------------*/ + +static OSErr GetParentFolderSpec(const FSSpec& fileSpec, FSSpec& parentDirSpec) +{ + CInfoPBRec pBlock = {0}; + OSErr err = noErr; + + parentDirSpec.name[0] = 0; + + pBlock.dirInfo.ioVRefNum = fileSpec.vRefNum; + pBlock.dirInfo.ioDrDirID = fileSpec.parID; + pBlock.dirInfo.ioNamePtr = (StringPtr)parentDirSpec.name; + pBlock.dirInfo.ioFDirIndex = -1; //get info on parID + err = PBGetCatInfoSync(&pBlock); + if (err != noErr) return err; + + parentDirSpec.vRefNum = fileSpec.vRefNum; + parentDirSpec.parID = pBlock.dirInfo.ioDrParID; + + return err; +} + + +/*---------------------------------------------------------------------------- + VolHasDesktopDB + + Check to see if a volume supports the new desktop database. + + Entry: vRefNum = vol ref num of volumn + + Exit: function result = error code. + *hasDesktop = true if volume has the new desktop database. +----------------------------------------------------------------------------*/ + +static OSErr VolHasDesktopDB (short vRefNum, Boolean *hasDesktop) +{ + HParamBlockRec pb; + GetVolParmsInfoBuffer info; + OSErr err = noErr; + + pb.ioParam.ioCompletion = nil; + pb.ioParam.ioNamePtr = nil; + pb.ioParam.ioVRefNum = vRefNum; + pb.ioParam.ioBuffer = (Ptr)&info; + pb.ioParam.ioReqCount = sizeof(info); + err = PBHGetVolParmsSync(&pb); + *hasDesktop = err == noErr && (info.vMAttrib & (1L << bHasDesktopMgr)) != 0; + return err; +} + + +/*---------------------------------------------------------------------------- + GetLastModDateTime + + Get the last mod date and time of a file. + + Entry: fSpec = pointer to file spec. + + Exit: function result = error code. + *lastModDateTime = last mod date and time. +----------------------------------------------------------------------------*/ + +static OSErr GetLastModDateTime(const FSSpec *fSpec, unsigned long *lastModDateTime) +{ + CInfoPBRec pBlock; + OSErr err = noErr; + + pBlock.hFileInfo.ioNamePtr = (StringPtr)fSpec->name; + pBlock.hFileInfo.ioVRefNum = fSpec->vRefNum; + pBlock.hFileInfo.ioFDirIndex = 0; + pBlock.hFileInfo.ioDirID = fSpec->parID; + err = PBGetCatInfoSync(&pBlock); + if (err != noErr) return err; + *lastModDateTime = pBlock.hFileInfo.ioFlMdDat; + return noErr; +} + + +/*---------------------------------------------------------------------------- + FindAppOnVolume + + Find an application on a volume. + + Entry: sig = application signature. + vRefNum = vol ref num + + Exit: function result = error code + = afpItemNotFound if app not found on vol. + *file = file spec for application on volume. +----------------------------------------------------------------------------*/ + +static OSErr FindAppOnVolume (OSType sig, short vRefNum, FSSpec *file) +{ + DTPBRec pb; + OSErr err = noErr; + short ioDTRefNum, i; + FInfo fInfo; + FSSpec candidate; + unsigned long lastModDateTime, maxLastModDateTime; + + memset(&pb, 0, sizeof(DTPBRec)); + pb.ioCompletion = nil; + pb.ioVRefNum = vRefNum; + pb.ioNamePtr = nil; + err = PBDTGetPath(&pb); + if (err != noErr) return err; + ioDTRefNum = pb.ioDTRefNum; + + memset(&pb, 0, sizeof(DTPBRec)); + pb.ioCompletion = nil; + pb.ioIndex = 0; + pb.ioFileCreator = sig; + pb.ioNamePtr = file->name; + pb.ioDTRefNum = ioDTRefNum; + err = PBDTGetAPPLSync(&pb); + + if (err == fnfErr || err == paramErr) return afpItemNotFound; + if (err != noErr) return err; + + file->vRefNum = vRefNum; + file->parID = pb.ioAPPLParID; + + err = FSpGetFInfo(file, &fInfo); + if (err == noErr) return noErr; + + i = 1; + maxLastModDateTime = 0; + while (true) + { + memset(&pb, 0, sizeof(DTPBRec)); + pb.ioCompletion = nil; + pb.ioIndex = i; + pb.ioFileCreator = sig; + pb.ioNamePtr = candidate.name; + pb.ioDTRefNum = ioDTRefNum; + err = PBDTGetAPPLSync(&pb); + if (err != noErr) break; + candidate.vRefNum = vRefNum; + candidate.parID = pb.ioAPPLParID; + err = GetLastModDateTime(file, &lastModDateTime); + if (err == noErr) { + if (lastModDateTime > maxLastModDateTime) { + maxLastModDateTime = lastModDateTime; + *file = candidate; + } + } + i++; + } + + return maxLastModDateTime > 0 ? noErr : afpItemNotFound; +} + + +/*---------------------------------------------------------------------------- + GetIndVolume + + Get a volume reference number by volume index. + + Entry: index = volume index + + Exit: function result = error code. + *vRefNum = vol ref num of indexed volume. +----------------------------------------------------------------------------*/ + +static OSErr GetIndVolume(short index, short *vRefNum) +{ + HParamBlockRec pb; + Str63 volumeName; + OSErr err = noErr; + + pb.volumeParam.ioCompletion = nil; + pb.volumeParam.ioNamePtr = volumeName; + pb.volumeParam.ioVolIndex = index; + + err = PBHGetVInfoSync(&pb); + + *vRefNum = pb.volumeParam.ioVRefNum; + return err; +} + + +// Private NSPR functions +static unsigned long gJanuaryFirst1970Seconds = 0; +/* + * The geographic location and time zone information of a Mac + * are stored in extended parameter RAM. The ReadLocation + * produdure uses the geographic location record, MachineLocation, + * to read the geographic location and time zone information in + * extended parameter RAM. + * + * Because serial port and SLIP conflict with ReadXPram calls, + * we cache the call here. + * + * Caveat: this caching will give the wrong result if a session + * extend across the DST changeover time. + */ + +static void MyReadLocation(MachineLocation *loc) +{ + static MachineLocation storedLoc; + static Boolean didReadLocation = false; + + if (!didReadLocation) { + ReadLocation(&storedLoc); + didReadLocation = true; + } + *loc = storedLoc; +} + +static long GMTDelta(void) +{ + MachineLocation loc; + long gmtDelta; + + MyReadLocation(&loc); + gmtDelta = loc.u.gmtDelta & 0x00ffffff; + if (gmtDelta & 0x00800000) { /* test sign extend bit */ + gmtDelta |= 0xff000000; + } + return gmtDelta; +} + +static void MacintoshInitializeTime(void) +{ + /* + * The NSPR epoch is midnight, Jan. 1, 1970 GMT. + * + * At midnight Jan. 1, 1970 GMT, the local time was + * midnight Jan. 1, 1970 + GMTDelta(). + * + * Midnight Jan. 1, 1970 is 86400 * (365 * (1970 - 1904) + 17) + * = 2082844800 seconds since the Mac epoch. + * (There were 17 leap years from 1904 to 1970.) + * + * So the NSPR epoch is 2082844800 + GMTDelta() seconds since + * the Mac epoch. Whew! :-) + */ + gJanuaryFirst1970Seconds = 2082844800 + GMTDelta(); +} + +static nsresult ConvertMacTimeToMilliseconds( PRInt64* aLastModifiedTime, PRUint32 timestamp ) +{ + if ( gJanuaryFirst1970Seconds == 0) + MacintoshInitializeTime(); + timestamp -= gJanuaryFirst1970Seconds; + PRTime usecPerSec, dateInMicroSeconds; + LL_I2L(dateInMicroSeconds, timestamp); + LL_I2L(usecPerSec, PR_MSEC_PER_SEC); + LL_MUL(*aLastModifiedTime, usecPerSec, dateInMicroSeconds); + return NS_OK; +} + +static nsresult ConvertMillisecondsToMacTime(PRInt64 aTime, PRUint32 *aOutMacTime) +{ + NS_ENSURE_ARG( aOutMacTime ); + + PRTime usecPerSec, dateInSeconds; + dateInSeconds = LL_ZERO; + + LL_I2L(usecPerSec, PR_MSEC_PER_SEC); + LL_DIV(dateInSeconds, aTime, usecPerSec); // dateInSeconds = aTime/1,000 + LL_L2UI(*aOutMacTime, dateInSeconds); + *aOutMacTime += 2082844800; // date + Mac epoch + + return NS_OK; +} + +static void myPLstrcpy(Str255 dst, const char* src) +{ + int srcLength = strlen(src); + NS_ASSERTION(srcLength <= 255, "Oops, Str255 can't hold >255 chars"); + if (srcLength > 255) + srcLength = 255; + dst[0] = srcLength; + memcpy(&dst[1], src, srcLength); +} + +static void myPLstrncpy(Str255 dst, const char* src, int inMax) +{ + int srcLength = strlen(src); + if (srcLength > inMax) + srcLength = inMax; + dst[0] = srcLength; + memcpy(&dst[1], src, srcLength); +} + +/* + NS_TruncNodeName + + Utility routine to do a mid-trunc on a potential file name so that it is + no longer than 31 characters. Until we move to the HFS+ APIs we need this + to come up with legal Mac file names. + + Entry: aNode = initial file name + outBuf = scratch buffer for the truncated name (MUST be >= 32 characters) + + Exit: function result = pointer to truncated name. Will be either aNode or outBuf. + +*/ +const char* NS_TruncNodeName(const char *aNode, char *outBuf) +{ + PRUint32 nodeLen; + if ((nodeLen = strlen(aNode)) > 31) + { + static PRBool sInitialized = PR_FALSE; + static CharByteTable sTable; + // Init to "..." in case we fail to get the ellipsis token + static char sEllipsisTokenStr[4] = { '.', '.', '.', 0 }; + static PRUint8 sEllipsisTokenLen = 3; + + if (!sInitialized) + { + // Entries in the table are: + // 0 == 1 byte char + // 1 == 2 byte char + FillParseTable(sTable, smSystemScript); + + Handle itl4ResHandle = nsnull; + long offset, len; + ::GetIntlResourceTable(smSystemScript, smUnTokenTable, &itl4ResHandle, &offset, &len); + if (itl4ResHandle) + { + UntokenTable *untokenTableRec = (UntokenTable *)(*itl4ResHandle + offset); + if (untokenTableRec->lastToken >= tokenEllipsis) + { + offset += untokenTableRec->index[tokenEllipsis]; + char *tokenStr = (*itl4ResHandle + offset); + sEllipsisTokenLen = tokenStr[0]; + memcpy(sEllipsisTokenStr, &tokenStr[1], sEllipsisTokenLen); + } + ::ReleaseResource(itl4ResHandle); + } + sInitialized = PR_TRUE; + } + + PRInt32 halfLen = (31 - sEllipsisTokenLen) / 2; + PRInt32 charSize = 0, srcPos, destPos; + for (srcPos = 0; srcPos + charSize <= halfLen; srcPos += charSize) + charSize = sTable[aNode[srcPos]] ? 2 : 1; + + memcpy(outBuf, aNode, srcPos); + memcpy(outBuf + srcPos, sEllipsisTokenStr, sEllipsisTokenLen); + destPos = srcPos + sEllipsisTokenLen; + + for (; srcPos < nodeLen - halfLen; srcPos += charSize) + charSize = sTable[aNode[srcPos]] ? 2 : 1; + + memcpy(outBuf + destPos, aNode + srcPos, nodeLen - srcPos); + destPos += (nodeLen - srcPos); + outBuf[destPos] = '\0'; + return outBuf; + } + return aNode; +} + +/** + * HFSPlusGetRawPath returns the path for an FSSpec as a unicode string. + * + * The reason for this routine instead of just calling FSRefMakePath is + * (1) inSpec does not have to exist + * (2) FSRefMakePath uses '/' as the separator under OSX and ':' under OS9 + */ +static OSErr HFSPlusGetRawPath(const FSSpec& inSpec, nsAString& outStr) +{ + OSErr err; + nsAutoString ucPathString; + + outStr.Truncate(0); + + FSRef nodeRef; + FSCatalogInfo catalogInfo; + catalogInfo.parentDirID = 0; + err = ::FSpMakeFSRef(&inSpec, &nodeRef); + + if (err == fnfErr) { + FSSpec parentDirSpec; + err = GetParentFolderSpec(inSpec, parentDirSpec); + if (err == noErr) { + const char *startPtr = (const char*)&inSpec.name[1]; + NS_CopyNativeToUnicode(Substring(startPtr, startPtr + PRUint32(inSpec.name[0])), outStr); + err = ::FSpMakeFSRef(&parentDirSpec, &nodeRef); + } + } + + while (err == noErr && catalogInfo.parentDirID != fsRtParID) { + HFSUniStr255 nodeName; + FSRef parentRef; + err = ::FSGetCatalogInfo(&nodeRef, + kFSCatInfoNodeFlags + kFSCatInfoParentDirID, + &catalogInfo, + &nodeName, + nsnull, + &parentRef); + if (err == noErr) + { + if (catalogInfo.nodeFlags & kFSNodeIsDirectoryMask) + nodeName.unicode[nodeName.length++] = PRUnichar(':'); + const PRUnichar* nodeNameUni = (const PRUnichar*) nodeName.unicode; + outStr.Insert(Substring(nodeNameUni, nodeNameUni + nodeName.length), 0); + nodeRef = parentRef; + } + } + return err; +} + + +// The R**co FSSpec resolver - +// it slices, it dices, it juliannes fries and it even creates FSSpecs out of whatever you feed it +// This function will take a path and a starting FSSpec and generate a FSSpec to represent +// the target of the two. If the intial FSSpec is null the path alone will be resolved +static OSErr ResolvePathAndSpec(const char * filePath, FSSpec *inSpec, PRBool createDirs, FSSpec *outSpec) +{ + OSErr err = noErr; + size_t inLength = strlen(filePath); + Boolean isRelative = (filePath && inSpec); + FSSpec tempSpec; + Str255 ppath; + Boolean isDirectory; + + if (isRelative && inSpec) + { + outSpec->vRefNum = inSpec->vRefNum; + outSpec->parID = inSpec->parID; + + if (inSpec->name[0] != 0) + { + long theDirID; + + err = FSpGetDirectoryID(inSpec, &theDirID, &isDirectory); + + if (err == noErr && isDirectory) + outSpec->parID = theDirID; + else if (err == fnfErr && createDirs) + { + err = FSpDirCreate(inSpec, smCurrentScript, &theDirID); + if (err == noErr) + outSpec->parID = theDirID; + else if (err == fnfErr) + err = dirNFErr; + } + } + } + else + { + outSpec->vRefNum = 0; + outSpec->parID = 0; + } + + if (err) + return err; + + // Try making an FSSpec from the path + if (inLength < 255) + { + // Use tempSpec as dest because if FSMakeFSSpec returns dirNFErr, it + // will reset the dest spec and we'll lose what we determined above. + + myPLstrcpy(ppath, filePath); + err = ::FSMakeFSSpec(outSpec->vRefNum, outSpec->parID, ppath, &tempSpec); + if (err == noErr || err == fnfErr) + *outSpec = tempSpec; + } + else if (!isRelative) + { + err = ::FSpLocationFromFullPath(inLength, filePath, outSpec); + } + else + { // If the path is relative and >255 characters we need to manually walk the + // path appending each node to the initial FSSpec so to reach that code we + // set the err to bdNamErr and fall into the code below + err = bdNamErr; + } + + // If we successfully created a spec then leave + if (err == noErr) + return err; + + // We get here when the directory hierarchy needs to be created or we're resolving + // a relative path >255 characters long + if (err == dirNFErr || err == bdNamErr) + { + const char* path = filePath; + + if (!isRelative) // If path is relative, we still need vRefNum & parID. + { + outSpec->vRefNum = 0; + outSpec->parID = 0; + } + + do + { + // Locate the colon that terminates the node. + // But if we've a partial path (starting with a colon), find the second one. + const char* nextColon = strchr(path + (*path == ':'), ':'); + // Well, if there are no more colons, point to the end of the string. + if (!nextColon) + nextColon = path + strlen(path); + + // Make a pascal string out of this node. Include initial + // and final colon, if any! + myPLstrncpy(ppath, path, nextColon - path + 1); + + // Use this string as a relative path using the directory created + // on the previous round (or directory 0,0 on the first round). + err = ::FSMakeFSSpec(outSpec->vRefNum, outSpec->parID, ppath, outSpec); + + // If this was the leaf node, then we are done. + if (!*nextColon) + break; + + // Since there's more to go, we have to get the directory ID, which becomes + // the parID for the next round. + if (err == noErr) + { + // The directory (or perhaps a file) exists. Find its dirID. + long dirID; + err = ::FSpGetDirectoryID(outSpec, &dirID, &isDirectory); + if (!isDirectory) + err = dupFNErr; // oops! a file exists with that name. + if (err != noErr) + break; // bail if we've got an error + outSpec->parID = dirID; + } + else if ((err == fnfErr) && createDirs) + { + // If we got "file not found" and we're allowed to create directories + // then we need to create one + err = ::FSpDirCreate(outSpec, smCurrentScript, &outSpec->parID); + // For some reason, this usually returns fnfErr, even though it works. + if (err == fnfErr) + err = noErr; + } + if (err != noErr) + break; + path = nextColon; // next round + } while (true); + } + + return err; +} + + +#pragma mark - +#pragma mark [StFollowLinksState] +class StFollowLinksState +{ + public: + StFollowLinksState(nsILocalFile *aFile) : + mFile(aFile) + { + NS_ASSERTION(mFile, "StFollowLinksState passed a NULL file."); + if (mFile) + mFile->GetFollowLinks(&mSavedState); + } + + StFollowLinksState(nsILocalFile *aFile, PRBool followLinksState) : + mFile(aFile) + { + NS_ASSERTION(mFile, "StFollowLinksState passed a NULL file."); + if (mFile) { + mFile->GetFollowLinks(&mSavedState); + mFile->SetFollowLinks(followLinksState); + } + } + + ~StFollowLinksState() + { + if (mFile) + mFile->SetFollowLinks(mSavedState); + } + + private: + nsCOMPtr mFile; + PRBool mSavedState; +}; + +#pragma mark - +#pragma mark [nsDirEnumerator] +class nsDirEnumerator : public nsISimpleEnumerator +{ + public: + + NS_DECL_ISUPPORTS + + nsDirEnumerator() + { + } + + nsresult Init(nsILocalFileMac* parent) + { + NS_ENSURE_ARG(parent); + nsresult rv; + FSSpec fileSpec; + + rv = parent->GetFSSpec(&fileSpec); + if (NS_FAILED(rv)) + return rv; + + OSErr err; + Boolean isDirectory; + + err = ::FSpGetDirectoryID(&fileSpec, &mDirID, &isDirectory); + if (err || !isDirectory) + return NS_ERROR_FILE_NOT_DIRECTORY; + + mCatInfo.hFileInfo.ioNamePtr = mItemName; + mCatInfo.hFileInfo.ioVRefNum = fileSpec.vRefNum; + mItemIndex = 1; + + return NS_OK; + } + + NS_IMETHOD HasMoreElements(PRBool *result) + { + nsresult rv = NS_OK; + if (mNext == nsnull) + { + mItemName[0] = 0; + mCatInfo.dirInfo.ioFDirIndex = mItemIndex; + mCatInfo.dirInfo.ioDrDirID = mDirID; + + OSErr err = ::PBGetCatInfoSync(&mCatInfo); + if (err == fnfErr) + { + // end of dir entries + *result = PR_FALSE; + return NS_OK; + } + + // Make a new nsILocalFile for the new element + FSSpec tempSpec; + tempSpec.vRefNum = mCatInfo.hFileInfo.ioVRefNum; + tempSpec.parID = mDirID; + ::BlockMoveData(mItemName, tempSpec.name, mItemName[0] + 1); + + rv = NS_NewLocalFileWithFSSpec(&tempSpec, PR_TRUE, getter_AddRefs(mNext)); + if (NS_FAILED(rv)) + return rv; + } + *result = mNext != nsnull; + return NS_OK; + } + + NS_IMETHOD GetNext(nsISupports **result) + { + NS_ENSURE_ARG_POINTER(result); + *result = nsnull; + + nsresult rv; + PRBool hasMore; + rv = HasMoreElements(&hasMore); + if (NS_FAILED(rv)) return rv; + + *result = mNext; // might return nsnull + NS_IF_ADDREF(*result); + + mNext = nsnull; + ++mItemIndex; + return NS_OK; + } + + private: + ~nsDirEnumerator() {} + + protected: + nsCOMPtr mNext; + + CInfoPBRec mCatInfo; + short mItemIndex; + long mDirID; + Str63 mItemName; +}; + +NS_IMPL_ISUPPORTS1(nsDirEnumerator, nsISimpleEnumerator) + +#pragma mark - + +OSType nsLocalFile::sCurrentProcessSignature = 0; +PRBool nsLocalFile::sHasHFSPlusAPIs = PR_FALSE; +PRBool nsLocalFile::sRunningOSX = PR_FALSE; + +#pragma mark [CTOR/DTOR] +nsLocalFile::nsLocalFile() : + mFollowLinks(PR_TRUE), + mFollowLinksDirty(PR_TRUE), + mSpecDirty(PR_TRUE), + mCatInfoDirty(PR_TRUE), + mType('TEXT'), + mCreator(kDefaultCreator) +{ + ClearFSSpec(mSpec); + ClearFSSpec(mTargetSpec); + + InitClassStatics(); + if (sCurrentProcessSignature != 0) + mCreator = sCurrentProcessSignature; +} + +nsLocalFile::nsLocalFile(const nsLocalFile& srcFile) +{ + *this = srcFile; +} + +nsLocalFile::nsLocalFile(const FSSpec& aSpec, const nsACString& aAppendedPath) : + mFollowLinks(PR_TRUE), + mFollowLinksDirty(PR_TRUE), + mSpecDirty(PR_TRUE), + mSpec(aSpec), + mAppendedPath(aAppendedPath), + mCatInfoDirty(PR_TRUE), + mType('TEXT'), + mCreator(kDefaultCreator) +{ + ClearFSSpec(mTargetSpec); + + InitClassStatics(); + if (sCurrentProcessSignature != 0) + mCreator = sCurrentProcessSignature; +} + +nsLocalFile& nsLocalFile::operator=(const nsLocalFile& rhs) +{ + mFollowLinks = rhs.mFollowLinks; + mFollowLinksDirty = rhs.mFollowLinksDirty; + mSpecDirty = rhs.mSpecDirty; + mSpec = rhs.mSpec; + mAppendedPath = rhs.mAppendedPath; + mTargetSpec = rhs.mTargetSpec; + mCatInfoDirty = rhs.mCatInfoDirty; + mType = rhs.mType; + mCreator = rhs.mCreator; + + if (!rhs.mCatInfoDirty) + mCachedCatInfo = rhs.mCachedCatInfo; + + return *this; +} + +#pragma mark - +#pragma mark [nsISupports interface implementation] + +NS_IMPL_THREADSAFE_ISUPPORTS3(nsLocalFile, + nsILocalFileMac, + nsILocalFile, + nsIFile) + +NS_METHOD +nsLocalFile::nsLocalFileConstructor(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr) +{ + NS_ENSURE_ARG_POINTER(aInstancePtr); + NS_ENSURE_NO_AGGREGATION(outer); + + nsLocalFile* inst = new nsLocalFile(); + if (inst == NULL) + return NS_ERROR_OUT_OF_MEMORY; + + nsresult rv = inst->QueryInterface(aIID, aInstancePtr); + if (NS_FAILED(rv)) + { + delete inst; + return rv; + } + return NS_OK; +} + +// This function resets any cached information about the file. +void +nsLocalFile::MakeDirty() +{ + mSpecDirty = PR_TRUE; + mFollowLinksDirty = PR_TRUE; + mCatInfoDirty = PR_TRUE; + + ClearFSSpec(mTargetSpec); +} + + +/* attribute PRBool followLinks; */ +NS_IMETHODIMP +nsLocalFile::GetFollowLinks(PRBool *aFollowLinks) +{ + NS_ENSURE_ARG_POINTER(aFollowLinks); + *aFollowLinks = mFollowLinks; + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::SetFollowLinks(PRBool aFollowLinks) +{ + if (aFollowLinks != mFollowLinks) + { + mFollowLinks = aFollowLinks; + mFollowLinksDirty = PR_TRUE; + } + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::ResolveAndStat() +{ + OSErr err = noErr; + FSSpec resolvedSpec; + + // fnfErr means target spec is valid but doesn't exist. + // If the end result is fnfErr, we're cleanly resolved. + + if (mSpecDirty) + { + if (mAppendedPath.Length()) + { + err = ResolvePathAndSpec(mAppendedPath.get(), &mSpec, PR_FALSE, &resolvedSpec); + if (err == noErr) + mAppendedPath.Truncate(0); + } + else + err = ::FSMakeFSSpec(mSpec.vRefNum, mSpec.parID, mSpec.name, &resolvedSpec); + if (err == noErr) + { + mSpec = resolvedSpec; + mSpecDirty = PR_FALSE; + } + mFollowLinksDirty = PR_TRUE; + } + if (mFollowLinksDirty && (err == noErr)) + { + if (mFollowLinks) + { + // Resolve the alias to the original file. + resolvedSpec = mSpec; + Boolean resolvedWasFolder, resolvedWasAlias; + err = ::ResolveAliasFile(&resolvedSpec, TRUE, &resolvedWasFolder, &resolvedWasAlias); + if (err == noErr || err == fnfErr) { + err = noErr; + mTargetSpec = resolvedSpec; + mFollowLinksDirty = PR_FALSE; + } + } + else + { + mTargetSpec = mSpec; + mFollowLinksDirty = PR_FALSE; + } + mCatInfoDirty = PR_TRUE; + } + + return (MacErrorMapper(err)); +} + + +NS_IMETHODIMP +nsLocalFile::Clone(nsIFile **file) +{ + // Just copy-construct ourselves + *file = new nsLocalFile(*this); + if (!*file) + return NS_ERROR_OUT_OF_MEMORY; + + NS_ADDREF(*file); + + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::InitWithNativePath(const nsACString &filePath) +{ + // The incoming path must be a FULL path + + if (filePath.IsEmpty()) + return NS_ERROR_INVALID_ARG; + + MakeDirty(); + + // If it starts with a colon, it's invalid + if (filePath.First() == ':') + return NS_ERROR_FILE_UNRECOGNIZED_PATH; + + nsPathParser parser(filePath); + OSErr err; + Str255 pascalNode; + FSSpec nodeSpec; + + const char *root = parser.First(); + if (root == nsnull) + return NS_ERROR_FILE_UNRECOGNIZED_PATH; + + // The first component must be an existing volume + myPLstrcpy(pascalNode, root); + pascalNode[++pascalNode[0]] = ':'; + err = ::FSMakeFSSpec(0, 0, pascalNode, &nodeSpec); + if (err) + return NS_ERROR_FILE_UNRECOGNIZED_PATH; + + // Build as much of a spec as possible from the rest of the path + // What doesn't exist will be left over in mAppendedPath + const char *nextNode; + while ((nextNode = parser.Next()) != nsnull) { + long dirID; + Boolean isDir; + err = ::FSpGetDirectoryID(&nodeSpec, &dirID, &isDir); + if (err || !isDir) + break; + myPLstrcpy(pascalNode, nextNode); + err = ::FSMakeFSSpec(nodeSpec.vRefNum, dirID, pascalNode, &nodeSpec); + if (err == fnfErr) + break; + } + mSpec = nodeSpec; + mAppendedPath = parser.Remainder(); + + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::InitWithPath(const nsAString &filePath) +{ + nsresult rv; + nsCAutoString fsStr; + + if (NS_SUCCEEDED(rv = NS_CopyUnicodeToNative(filePath, fsStr))) + rv = InitWithNativePath(fsStr); + + return rv; +} + +NS_IMETHODIMP +nsLocalFile::InitWithFile(nsILocalFile *aFile) +{ + NS_ENSURE_ARG(aFile); + nsLocalFile *asLocalFile = dynamic_cast(aFile); + if (!asLocalFile) + return NS_ERROR_NO_INTERFACE; // Well, sort of. + *this = *asLocalFile; + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::OpenNSPRFileDesc(PRInt32 flags, PRInt32 mode, PRFileDesc **_retval) +{ +// Macintosh doesn't really have mode bits, just drop them +#pragma unused (mode) + + NS_ENSURE_ARG(_retval); + + nsresult rv = NS_OK; + FSSpec spec; + OSErr err = noErr; + + rv = ResolveAndStat(); + if (rv == NS_ERROR_FILE_NOT_FOUND && (flags & PR_CREATE_FILE)) + rv = NS_OK; + + if (flags & PR_CREATE_FILE) { + rv = Create(nsIFile::NORMAL_FILE_TYPE, 0); + /* If opening with the PR_EXCL flag the existence of the file prior to opening is an error */ + if ((flags & PR_EXCL) && (rv == NS_ERROR_FILE_ALREADY_EXISTS)) + return rv; + } + + rv = GetFSSpec(&spec); + if (NS_FAILED(rv)) + return rv; + + SInt8 perm; + if (flags & PR_RDWR) + perm = fsRdWrPerm; + else if (flags & PR_WRONLY) + perm = fsWrPerm; + else + perm = fsRdPerm; + + short refnum; + err = ::FSpOpenDF(&spec, perm, &refnum); + + if (err == noErr && (flags & PR_TRUNCATE)) + err = ::SetEOF(refnum, 0); + if (err == noErr && (flags & PR_APPEND)) + err = ::SetFPos(refnum, fsFromLEOF, 0); + if (err != noErr) + return MacErrorMapper(err); + + if ((*_retval = PR_ImportFile(refnum)) == 0) + return NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_FILES,(PR_GetError() & 0xFFFF)); + + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::OpenANSIFileDesc(const char *mode, FILE * *_retval) +{ + NS_ENSURE_ARG(mode); + NS_ENSURE_ARG_POINTER(_retval); + + nsresult rv; + FSSpec spec; + + rv = ResolveAndStat(); + if (NS_FAILED(rv) && rv != NS_ERROR_FILE_NOT_FOUND) + return rv; + + if (mode[0] == 'w' || mode[0] == 'a') // Create if it doesn't exist + { + if (rv == NS_ERROR_FILE_NOT_FOUND) { + mType = (mode[1] == 'b') ? 'BiNA' : 'TEXT'; + rv = Create(nsIFile::NORMAL_FILE_TYPE, 0); + if (NS_FAILED(rv)) + return rv; + } + } + + rv = GetFSSpec(&spec); + if (NS_FAILED(rv)) + return rv; + +#ifdef MACOSX + // FSp_fopen() doesn't exist under macosx :-( + nsXPIDLCString ourPath; + rv = GetPath(getter_Copies(ourPath)); + if (NS_FAILED(rv)) + return rv; + *_retval = fopen(ourPath, mode); +#else + *_retval = FSp_fopen(&spec, mode); +#endif + + if (*_retval) + return NS_OK; + + return NS_ERROR_FAILURE; +} + + +NS_IMETHODIMP +nsLocalFile::Create(PRUint32 type, PRUint32 attributes) +{ + OSErr err; + + if (type != NORMAL_FILE_TYPE && type != DIRECTORY_TYPE) + return NS_ERROR_FILE_UNKNOWN_TYPE; + + FSSpec newSpec; + + if (mAppendedPath.Length()) + { // We've got an FSSpec and an appended path so pass 'em both to ResolvePathAndSpec + err = ResolvePathAndSpec(mAppendedPath.get(), &mSpec, PR_TRUE, &newSpec); + } + else + { + err = ::FSMakeFSSpec(mSpec.vRefNum, mSpec.parID, mSpec.name, &newSpec); + } + + if (err != noErr && err != fnfErr) + return (MacErrorMapper(err)); + + switch (type) + { + case NORMAL_FILE_TYPE: + SetOSTypeAndCreatorFromExtension(); + err = ::FSpCreate(&newSpec, mCreator, mType, smCurrentScript); + break; + + case DIRECTORY_TYPE: + { + long newDirID; + err = ::FSpDirCreate(&newSpec, smCurrentScript, &newDirID); + // For some reason, this usually returns fnfErr, even though it works. + if (err == fnfErr) + err = noErr; + } + break; + + default: + return NS_ERROR_FILE_UNKNOWN_TYPE; + break; + } + + if (err == noErr) + { + mSpec = mTargetSpec = newSpec; + mAppendedPath.Truncate(0); + } + + return (MacErrorMapper(err)); +} + +NS_IMETHODIMP +nsLocalFile::AppendNative(const nsACString &aNode) +{ + if (aNode.IsEmpty()) + return NS_OK; + + nsACString::const_iterator start, end; + aNode.BeginReading(start); + aNode.EndReading(end); + if (FindCharInReadable(':', start, end)) + return NS_ERROR_FILE_UNRECOGNIZED_PATH; + + MakeDirty(); + + char truncBuffer[32]; + const char *node = NS_TruncNodeName(PromiseFlatCString(aNode).get(), truncBuffer); + + if (!mAppendedPath.Length()) + { + OSErr err; + Boolean resolvedWasFolder, resolvedWasAlias; + err = ::ResolveAliasFile(&mSpec, TRUE, &resolvedWasFolder, &resolvedWasAlias); + if (err == noErr) + { + long dirID; + Boolean isDir; + + if (!resolvedWasFolder) + return NS_ERROR_FILE_NOT_DIRECTORY; + if ((err = ::FSpGetDirectoryID(&mSpec, &dirID, &isDir)) != noErr) + return MacErrorMapper(err); + + FSSpec childSpec; + Str255 pascalNode; + myPLstrcpy(pascalNode, node); + err = ::FSMakeFSSpec(mSpec.vRefNum, dirID, pascalNode, &childSpec); + if (err && err != fnfErr) + return MacErrorMapper(err); + mSpec = childSpec; + } + else if (err == fnfErr) + mAppendedPath.Assign(node); + else + return MacErrorMapper(err); + } + else + { + if (mAppendedPath.First() != ':') + mAppendedPath.Insert(':', 0); + mAppendedPath.Append(":"); + mAppendedPath.Append(node); + } + + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::Append(const nsAString &node) +{ + nsresult rv; + nsCAutoString fsStr; + + if (NS_SUCCEEDED(rv = NS_CopyUnicodeToNative(node, fsStr))) + rv = AppendNative(fsStr); + + return rv; +} + +NS_IMETHODIMP +nsLocalFile::AppendRelativeNativePath(const nsACString &relPath) +{ + if (relPath.IsEmpty()) + return NS_ERROR_INVALID_ARG; + + nsresult rv; + nsPathParser parser(relPath); + const char* node = parser.First(); + + while (node) + { + if (NS_FAILED(rv = AppendNative(nsDependentCString(node)))) + return rv; + node = parser.Next(); + } + + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::AppendRelativePath(const nsAString &relPath) +{ + nsresult rv; + nsCAutoString fsStr; + + if (NS_SUCCEEDED(rv = NS_CopyUnicodeToNative(relPath, fsStr))) + rv = AppendRelativeNativePath(fsStr); + + return rv; +} + +NS_IMETHODIMP +nsLocalFile::GetNativeLeafName(nsACString &aLeafName) +{ + aLeafName.Truncate(); + + // See if we've had a path appended + if (mAppendedPath.Length()) + { + const char* temp = mAppendedPath.get(); + if (temp == nsnull) + return NS_ERROR_FILE_UNRECOGNIZED_PATH; + + const char* leaf = strrchr(temp, ':'); + + // if the working path is just a node without any directory delimeters. + if (leaf == nsnull) + leaf = temp; + else + leaf++; + + aLeafName = leaf; + } + else + { + // We don't have an appended path so grab the leaf name from the FSSpec + // Convert the Pascal string to a C string + PRInt32 len = mSpec.name[0]; + char* leafName = (char *)malloc(len + 1); + if (!leafName) return NS_ERROR_OUT_OF_MEMORY; + ::BlockMoveData(&mSpec.name[1], leafName, len); + leafName[len] = '\0'; + aLeafName = leafName; + free(leafName); + } + + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::GetLeafName(nsAString &aLeafName) +{ + nsresult rv; + nsCAutoString fsStr; + + if (NS_SUCCEEDED(rv = GetNativeLeafName(fsStr))) + rv = NS_CopyNativeToUnicode(fsStr, aLeafName); + return rv; +} + +NS_IMETHODIMP +nsLocalFile::SetNativeLeafName(const nsACString &aLeafName) +{ + if (aLeafName.IsEmpty()) + return NS_ERROR_INVALID_ARG; + + MakeDirty(); + + char truncBuffer[32]; + const char *leafName = NS_TruncNodeName(PromiseFlatCString(aLeafName).get(), truncBuffer); + + if (mAppendedPath.Length()) + { // Lop off the end of the appended path and replace it with the new leaf name + PRInt32 offset = mAppendedPath.RFindChar(':'); + if (offset || ((!offset) && (1 < mAppendedPath.Length()))) + { + mAppendedPath.Truncate(offset + 1); + } + mAppendedPath.Append(leafName); + } + else + { + // We don't have an appended path so directly modify the FSSpec + myPLstrcpy(mSpec.name, leafName); + } + + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::SetLeafName(const nsAString &aLeafName) +{ + nsresult rv; + nsCAutoString fsStr; + + if (NS_SUCCEEDED(rv = NS_CopyUnicodeToNative(aLeafName, fsStr))) + rv = SetNativeLeafName(fsStr); + + return rv; +} + +NS_IMETHODIMP +nsLocalFile::GetNativePath(nsACString &_retval) +{ + _retval.Truncate(); + + nsCAutoString fsCharSetPathStr; + +#if TARGET_CARBON + if (sHasHFSPlusAPIs) // should always be true under Carbon, but in case... + { + OSErr err; + nsresult rv; + nsAutoString ucPathString; + + if ((err = HFSPlusGetRawPath(mSpec, ucPathString)) != noErr) + return MacErrorMapper(err); + rv = NS_CopyUnicodeToNative(ucPathString, fsCharSetPathStr); + if (NS_FAILED(rv)) + return rv; + } + else +#endif + { + // Now would be a good time to call the code that makes an FSSpec into a path + short fullPathLen; + Handle fullPathHandle; + (void)::FSpGetFullPath(&mSpec, &fullPathLen, &fullPathHandle); + if (!fullPathHandle) + return NS_ERROR_OUT_OF_MEMORY; + + ::HLock(fullPathHandle); + fsCharSetPathStr.Assign(*fullPathHandle, fullPathLen); + ::DisposeHandle(fullPathHandle); + } + + // We need to make sure that even if we have a path to a + // directory we don't return the trailing colon. It breaks + // the component manager. (Bugzilla bug #26102) + if (fsCharSetPathStr.Last() == ':') + fsCharSetPathStr.Truncate(fsCharSetPathStr.Length() - 1); + + // Now, tack on mAppendedPath. It never ends in a colon. + if (mAppendedPath.Length()) + { + if (mAppendedPath.First() != ':') + fsCharSetPathStr.Append(":"); + fsCharSetPathStr.Append(mAppendedPath); + } + + _retval = fsCharSetPathStr; + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::GetPath(nsAString &_retval) +{ + nsresult rv = NS_OK; + +#if TARGET_CARBON + if (sHasHFSPlusAPIs) // should always be true under Carbon, but in case... + { + OSErr err; + nsAutoString ucPathString; + + if ((err = HFSPlusGetRawPath(mSpec, ucPathString)) != noErr) + return MacErrorMapper(err); + + // We need to make sure that even if we have a path to a + // directory we don't return the trailing colon. It breaks + // the component manager. (Bugzilla bug #26102) + if (ucPathString.Last() == PRUnichar(':')) + ucPathString.Truncate(ucPathString.Length() - 1); + + // Now, tack on mAppendedPath. It never ends in a colon. + if (mAppendedPath.Length()) + { + nsAutoString ucAppendage; + if (mAppendedPath.First() != ':') + ucPathString.Append(PRUnichar(':')); + rv = NS_CopyNativeToUnicode(mAppendedPath, ucAppendage); + if (NS_FAILED(rv)) + return rv; + ucPathString.Append(ucAppendage); + } + + _retval = ucPathString; + } + else +#endif + { + nsCAutoString fsStr; + + if (NS_SUCCEEDED(rv = GetNativePath(fsStr))) { + rv = NS_CopyNativeToUnicode(fsStr, _retval); + } + } + return rv; +} + +nsresult nsLocalFile::MoveCopy( nsIFile* newParentDir, const nsACString &newName, PRBool isCopy, PRBool followLinks ) +{ + OSErr macErr; + FSSpec srcSpec; + Str255 newPascalName; + nsresult rv; + + StFollowLinksState srcFollowState(this, followLinks); + rv = GetFSSpec(&srcSpec); + if ( NS_FAILED( rv ) ) + return rv; + + // If newParentDir == nsnull, it's a simple rename + if ( !newParentDir ) + { + myPLstrncpy( newPascalName, PromiseFlatCString(newName).get(), 255 ); + macErr = ::FSpRename( &srcSpec, newPascalName ); + return MacErrorMapper( macErr ); + } + + nsCOMPtr destDir(do_QueryInterface( newParentDir )); + StFollowLinksState destFollowState(destDir, followLinks); + FSSpec destSpec; + rv = destDir->GetFSSpec(&destSpec); + if ( NS_FAILED( rv ) ) + return rv; + + long dirID; + Boolean isDirectory; + macErr = ::FSpGetDirectoryID(&destSpec, &dirID, &isDirectory); + if ( macErr || !isDirectory ) + return NS_ERROR_FILE_DESTINATION_NOT_DIR; + + if ( !newName.IsEmpty() ) + myPLstrncpy( newPascalName, PromiseFlatCString(newName).get(), 255); + else + memcpy(newPascalName, srcSpec.name, srcSpec.name[0] + 1); + if ( isCopy ) + { + macErr = ::FSpGetDirectoryID(&srcSpec, &dirID, &isDirectory); + if (macErr == noErr) + { + const PRInt32 kCopyBufferSize = (1024 * 512); // allocate our own buffer to speed file copies. Bug #103202 + OSErr tempErr; + Handle copyBufferHand = ::TempNewHandle(kCopyBufferSize, &tempErr); + void* copyBuffer = nsnull; + PRInt32 copyBufferSize = 0; + + // it's OK if the allocated failed; FSpFileCopy will just fall back on its own internal 16k buffer + if (copyBufferHand) + { + ::HLock(copyBufferHand); + copyBuffer = *copyBufferHand; + copyBufferSize = kCopyBufferSize; + } + + if ( isDirectory ) + macErr = MacFSpDirectoryCopyRename( &srcSpec, &destSpec, newPascalName, copyBuffer, copyBufferSize, true, NULL ); + else + macErr = ::FSpFileCopy( &srcSpec, &destSpec, newPascalName, copyBuffer, copyBufferSize, true ); + + if (copyBufferHand) + ::DisposeHandle(copyBufferHand); + } + } + else + { + macErr= ::FSpMoveRenameCompat(&srcSpec, &destSpec, newPascalName); + if ( macErr == diffVolErr) + { + // On a different Volume so go for Copy and then delete + rv = CopyToNative( newParentDir, newName ); + if ( NS_FAILED ( rv ) ) + return rv; + return Remove( PR_TRUE ); + } + } + return MacErrorMapper( macErr ); +} + +NS_IMETHODIMP +nsLocalFile::CopyToNative(nsIFile *newParentDir, const nsACString &newName) +{ + return MoveCopy( newParentDir, newName, PR_TRUE, PR_FALSE ); +} + +NS_IMETHODIMP +nsLocalFile::CopyTo(nsIFile *newParentDir, const nsAString &newName) +{ + if (newName.IsEmpty()) + return CopyToNative(newParentDir, nsCString()); + + nsresult rv; + nsCAutoString fsStr; + if (NS_SUCCEEDED(rv = NS_CopyUnicodeToNative(newName, fsStr))) + rv = CopyToNative(newParentDir, fsStr); + return rv; +} + +NS_IMETHODIMP +nsLocalFile::CopyToFollowingLinksNative(nsIFile *newParentDir, const nsACString &newName) +{ + return MoveCopy( newParentDir, newName, PR_TRUE, PR_TRUE ); +} + +NS_IMETHODIMP +nsLocalFile::CopyToFollowingLinks(nsIFile *newParentDir, const nsAString &newName) +{ + if (newName.IsEmpty()) + return CopyToFollowingLinksNative(newParentDir, nsCString()); + + nsresult rv; + nsCAutoString fsStr; + if (NS_SUCCEEDED(rv = NS_CopyUnicodeToNative(newName, fsStr))) + rv = CopyToFollowingLinksNative(newParentDir, fsStr); + return rv; +} + +NS_IMETHODIMP +nsLocalFile::MoveToNative(nsIFile *newParentDir, const nsACString &newName) +{ + return MoveCopy( newParentDir, newName, PR_FALSE, PR_FALSE ); +} + +NS_IMETHODIMP +nsLocalFile::MoveTo(nsIFile *newParentDir, const nsAString &newName) +{ + if (newName.IsEmpty()) + return MoveToNative(newParentDir, nsCString()); + + nsresult rv; + nsCAutoString fsStr; + if (NS_SUCCEEDED(rv = NS_CopyUnicodeToNative(newName, fsStr))) + rv = MoveToNative(newParentDir, fsStr); + return rv; +} + +NS_IMETHODIMP +nsLocalFile::Load(PRLibrary * *_retval) +{ + PRBool isFile; + nsresult rv = IsFile(&isFile); + + if (NS_FAILED(rv)) + return rv; + + if (! isFile) + return NS_ERROR_FILE_IS_DIRECTORY; + + NS_TIMELINE_START_TIMER("PR_LoadLibrary"); + +#if !TARGET_CARBON + // This call to SystemTask is here to give the OS time to grow its + // FCB (file control block) list, which it seems to be unable to + // do unless we yield some time to the OS. See bugs 64978 & 70543 + // for the whole story. + ::SystemTask(); +#endif + + // Use the new PR_LoadLibraryWithFlags which allows us to use a FSSpec + PRLibSpec libSpec; + libSpec.type = PR_LibSpec_MacIndexedFragment; + libSpec.value.mac_indexed_fragment.fsspec = &mTargetSpec; + libSpec.value.mac_indexed_fragment.index = 0; + *_retval = PR_LoadLibraryWithFlags(libSpec, 0); + + NS_TIMELINE_STOP_TIMER("PR_LoadLibrary"); + NS_TIMELINE_MARK_TIMER("PR_LoadLibrary"); + + if (*_retval) + return NS_OK; + + return NS_ERROR_NULL_POINTER; +} + +NS_IMETHODIMP +nsLocalFile::Remove(PRBool recursive) +{ + OSErr err; + nsresult rv; + FSSpec specToDelete; + PRBool isDir; + + StFollowLinksState(this, PR_FALSE); + + rv = IsDirectory(&isDir); // Calls ResolveAndStat() + if (NS_FAILED(rv)) + return rv; + rv = GetFSSpec(&specToDelete); + if (NS_FAILED(rv)) + return rv; + + if (isDir && recursive) + err = ::DeleteDirectory( specToDelete.vRefNum, specToDelete.parID, specToDelete.name ); + else + err = ::HDelete( specToDelete.vRefNum, specToDelete.parID, specToDelete.name ); + + return MacErrorMapper( err ); +} + +NS_IMETHODIMP +nsLocalFile::GetLastModifiedTime(PRInt64 *aLastModifiedTime) +{ + NS_ENSURE_ARG(aLastModifiedTime); + *aLastModifiedTime = 0; + + nsresult rv = ResolveAndStat(); + if ( NS_FAILED( rv ) ) + return rv; + rv = UpdateCachedCatInfo(PR_TRUE); + if ( NS_FAILED( rv ) ) + return rv; + + // The mod date is in the same spot for files and dirs. + return ConvertMacTimeToMilliseconds( aLastModifiedTime, mCachedCatInfo.hFileInfo.ioFlMdDat ); +} + +NS_IMETHODIMP +nsLocalFile::SetLastModifiedTime(PRInt64 aLastModifiedTime) +{ + nsresult rv = ResolveAndStat(); + if ( NS_FAILED(rv) ) + return rv; + + PRUint32 macTime = 0; + OSErr err = noErr; + + ConvertMillisecondsToMacTime(aLastModifiedTime, &macTime); + + if (NS_SUCCEEDED(rv = UpdateCachedCatInfo(PR_TRUE))) + { + if (mCachedCatInfo.hFileInfo.ioFlAttrib & ioDirMask) + { + mCachedCatInfo.dirInfo.ioDrMdDat = macTime; + mCachedCatInfo.dirInfo.ioDrParID = mFollowLinks ? mTargetSpec.parID : mSpec.parID; + } + else + { + mCachedCatInfo.hFileInfo.ioFlMdDat = macTime; + mCachedCatInfo.hFileInfo.ioDirID = mFollowLinks ? mTargetSpec.parID : mSpec.parID; + } + + err = ::PBSetCatInfoSync(&mCachedCatInfo); + if (err != noErr) + return MacErrorMapper(err); + } + + return rv; +} + +NS_IMETHODIMP +nsLocalFile::GetLastModifiedTimeOfLink(PRInt64 *aLastModifiedTime) +{ + NS_ENSURE_ARG(aLastModifiedTime); + + nsresult rv; + PRBool isLink; + + rv = IsSymlink(&isLink); + if (NS_FAILED(rv)) + return rv; + if (!isLink) + return NS_ERROR_FAILURE; + + StFollowLinksState followState(this, PR_FALSE); + return GetLastModifiedTime(aLastModifiedTime); +} + +NS_IMETHODIMP +nsLocalFile::SetLastModifiedTimeOfLink(PRInt64 aLastModifiedTime) +{ + nsresult rv; + PRBool isLink; + + rv = IsSymlink(&isLink); + if (NS_FAILED(rv)) + return rv; + if (!isLink) + return NS_ERROR_FAILURE; + + StFollowLinksState followState(this, PR_FALSE); + return SetLastModifiedTime(aLastModifiedTime); +} + + +NS_IMETHODIMP +nsLocalFile::GetFileSize(PRInt64 *aFileSize) +{ + NS_ENSURE_ARG(aFileSize); + nsresult rv; + + *aFileSize = LL_Zero(); + + if (NS_SUCCEEDED(rv = ResolveAndStat()) && NS_SUCCEEDED(rv = UpdateCachedCatInfo(PR_TRUE))) + { + if (!(mCachedCatInfo.hFileInfo.ioFlAttrib & ioDirMask)) + { + long dataSize = mCachedCatInfo.hFileInfo.ioFlLgLen; + long resSize = mCachedCatInfo.hFileInfo.ioFlRLgLen; + + // For now we've only got 32 bits of file size info + PRInt64 dataInt64 = LL_Zero(); + PRInt64 resInt64 = LL_Zero(); + + // WARNING!!!!!! + // + // For now we do NOT add the data and resource fork sizes as there are several + // assumptions in the code (notably in form submit) that only the data fork is + // used. + // LL_I2L(resInt64, resSize); + + LL_I2L(dataInt64, dataSize); + + LL_ADD((*aFileSize), dataInt64, resInt64); + } + // leave size at zero for dirs + } + + return rv; +} + + +NS_IMETHODIMP +nsLocalFile::SetFileSize(PRInt64 aFileSize) +{ + nsresult rv = ResolveAndStat(); + if (NS_FAILED(rv)) + return rv; + + short refNum; + OSErr err; + PRInt32 aNewLength; + + LL_L2I(aNewLength, aFileSize); + + // Need to open the file to set the size + if (::FSpOpenDF(&mTargetSpec, fsWrPerm, &refNum) != noErr) + return NS_ERROR_FILE_ACCESS_DENIED; + + err = ::SetEOF(refNum, aNewLength); + + // Close the file unless we got an error that it was already closed + if (err != fnOpnErr) + (void)::FSClose(refNum); + + if (err != noErr) + return MacErrorMapper(err); + + return MacErrorMapper(err); +} + +NS_IMETHODIMP +nsLocalFile::GetFileSizeOfLink(PRInt64 *aFileSize) +{ + NS_ENSURE_ARG(aFileSize); + + StFollowLinksState followState(this, PR_FALSE); + return GetFileSize(aFileSize); +} + +NS_IMETHODIMP +nsLocalFile::GetDiskSpaceAvailable(PRInt64 *aDiskSpaceAvailable) +{ + NS_ENSURE_ARG(aDiskSpaceAvailable); + + PRInt64 space64Bits; + + LL_I2L(space64Bits , LONG_MAX); + + nsresult rv = ResolveAndStat(); + if (NS_FAILED(rv)) + return rv; + + XVolumeParam pb; + pb.ioCompletion = nsnull; + pb.ioVolIndex = 0; + pb.ioNamePtr = nsnull; + pb.ioVRefNum = mFollowLinks ? mTargetSpec.vRefNum : mSpec.vRefNum; + + // we should check if this call is available + OSErr err = ::PBXGetVolInfoSync(&pb); + + if (err == noErr) + { + const UnsignedWide& freeBytes = UInt64ToUnsignedWide(pb.ioVFreeBytes); +#ifdef HAVE_LONG_LONG + space64Bits = UnsignedWideToUInt64(freeBytes); +#else + space64Bits.lo = freeBytes.lo; + space64Bits.hi = freeBytes.hi; +#endif + } + + *aDiskSpaceAvailable = space64Bits; + + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::GetParent(nsIFile * *aParent) +{ + NS_ENSURE_ARG_POINTER(aParent); + *aParent = nsnull; + + nsresult rv = NS_OK; + PRInt32 offset; + + nsCOMPtr localFile; + PRInt32 appendedLen = mAppendedPath.Length(); + OSErr err; + + if (!appendedLen || (appendedLen == 1 && mAppendedPath.CharAt(0) == ':')) + { + rv = ResolveAndStat(); + //if the file does not exist, does not mean that the parent does not. + if (NS_FAILED(rv) && rv != NS_ERROR_FILE_NOT_FOUND) + return rv; + + CInfoPBRec pBlock = {0}; + FSSpec parentFolderSpec; + parentFolderSpec.name[0] = 0; + + pBlock.dirInfo.ioVRefNum = mSpec.vRefNum; + pBlock.dirInfo.ioDrDirID = mSpec.parID; + pBlock.dirInfo.ioNamePtr = (StringPtr)parentFolderSpec.name; + pBlock.dirInfo.ioFDirIndex = -1; //get info on parID + err = PBGetCatInfoSync(&pBlock); + if (err != noErr) + return MacErrorMapper(err); + parentFolderSpec.vRefNum = mSpec.vRefNum; + parentFolderSpec.parID = pBlock.dirInfo.ioDrParID; + + localFile = new nsLocalFile; + if (!localFile) + return NS_ERROR_OUT_OF_MEMORY; + rv = localFile->InitWithFSSpec(&parentFolderSpec); + if (NS_FAILED(rv)) + return rv; + } + else + { + // trim off the last component of the appended path + // construct a new file from our spec + trimmed path + + nsCAutoString parentAppendage(mAppendedPath); + + if (parentAppendage.Last() == ':') + parentAppendage.Truncate(appendedLen - 1); + if ((offset = parentAppendage.RFindChar(':')) != -1) + parentAppendage.Truncate(offset); + else + parentAppendage.Truncate(0); + + localFile = new nsLocalFile(mSpec, parentAppendage); + if (!localFile) + return NS_ERROR_OUT_OF_MEMORY; + } + *aParent = localFile; + NS_ADDREF(*aParent); + + return rv; +} + + +NS_IMETHODIMP +nsLocalFile::Exists(PRBool *_retval) +{ + NS_ENSURE_ARG(_retval); + *_retval = PR_FALSE; + + nsresult rv = ResolveAndStat(); + if (NS_SUCCEEDED(rv)) { + if (NS_SUCCEEDED(UpdateCachedCatInfo(PR_TRUE))) + *_retval = PR_TRUE; + } + + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::IsPackage(PRBool *outIsPackage) +{ + NS_ENSURE_ARG(outIsPackage); + *outIsPackage = PR_FALSE; + + // Note: IsDirectory() calls ResolveAndStat() & UpdateCachedCatInfo + PRBool isDir; + nsresult rv = IsDirectory(&isDir); + if (NS_FAILED(rv)) return rv; + + *outIsPackage = ((mCachedCatInfo.dirInfo.ioFlAttrib & kioFlAttribDirMask) && + (mCachedCatInfo.dirInfo.ioDrUsrWds.frFlags & kHasBundle)); + + if ((!*outIsPackage) && isDir) + { + // Believe it or not, folders ending with ".app" are also considered + // to be packages, even if the top-level folder doesn't have bundle set + nsCAutoString name; + if (NS_SUCCEEDED(rv = GetNativeLeafName(name))) + { + const char *extPtr = strrchr(name.get(), '.'); + if (extPtr) + { + if (!nsCRT::strcasecmp(extPtr, ".app")) + { + *outIsPackage = PR_TRUE; + } + } + } + } + + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::IsWritable(PRBool *outIsWritable) +{ + NS_ENSURE_ARG(outIsWritable); + *outIsWritable = PR_TRUE; + + nsresult rv = ResolveAndStat(); + if (NS_FAILED(rv)) return rv; + + rv = UpdateCachedCatInfo(PR_TRUE); + if (NS_FAILED(rv)) return rv; + + *outIsWritable = !(mCachedCatInfo.hFileInfo.ioFlAttrib & kioFlAttribLockedMask); + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::IsReadable(PRBool *_retval) +{ + NS_ENSURE_ARG(_retval); + + // is it ever not readable on Mac? + *_retval = PR_TRUE; + return NS_OK; +} + + +NS_IMETHODIMP +nsLocalFile::IsExecutable(PRBool *outIsExecutable) +{ + NS_ENSURE_ARG(outIsExecutable); + *outIsExecutable = PR_FALSE; // Assume failure + + nsresult rv = ResolveAndStat(); + if (NS_FAILED(rv)) return rv; + +#if TARGET_CARBON + // If we're running under OS X ask LaunchServices if we're executable + if (sRunningOSX) + { + if ( (UInt32)LSCopyItemInfoForRef != (UInt32)kUnresolvedCFragSymbolAddress ) + { + FSRef theRef; + LSRequestedInfo theInfoRequest = kLSRequestAllInfo; + LSItemInfoRecord theInfo; + + if (::FSpMakeFSRef(&mTargetSpec, &theRef) == noErr) + { + if (::LSCopyItemInfoForRef(&theRef, theInfoRequest, &theInfo) == noErr) + { + if ((theInfo.flags & kLSItemInfoIsApplication) != 0) + *outIsExecutable = PR_TRUE; + } + } + } + } + else +#endif + { + OSType fileType; + rv = GetFileType(&fileType); + if (NS_FAILED(rv)) return rv; + + *outIsExecutable = (fileType == 'APPL' || fileType == 'appe' || fileType == 'FNDR'); + } + + return NS_OK; +} + + +NS_IMETHODIMP +nsLocalFile::IsDirectory(PRBool *outIsDir) +{ + NS_ENSURE_ARG(outIsDir); + *outIsDir = PR_FALSE; + + nsresult rv = ResolveAndStat(); + if (NS_FAILED(rv)) return rv; + + rv = UpdateCachedCatInfo(PR_FALSE); + if (NS_FAILED(rv)) return rv; + + *outIsDir = (mCachedCatInfo.hFileInfo.ioFlAttrib & ioDirMask) != 0; + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::IsFile(PRBool *outIsFile) +{ + NS_ENSURE_ARG(outIsFile); + *outIsFile = PR_FALSE; + + nsresult rv = ResolveAndStat(); + if (NS_FAILED(rv)) return rv; + + rv = UpdateCachedCatInfo(PR_FALSE); + if (NS_FAILED(rv)) return rv; + + *outIsFile = (mCachedCatInfo.hFileInfo.ioFlAttrib & ioDirMask) == 0; + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::IsHidden(PRBool *_retval) +{ + NS_ENSURE_ARG(_retval); + *_retval = PR_FALSE; + + nsresult rv = ResolveAndStat(); + if (NS_FAILED(rv)) return rv; + + rv = UpdateCachedCatInfo(PR_FALSE); + if (NS_FAILED(rv)) return rv; + + *_retval = (mCachedCatInfo.hFileInfo.ioFlFndrInfo.fdFlags & kIsInvisible) != 0; + + if (sRunningOSX) + { + // on Mac OS X, also follow Unix "convention" where files + // beginning with a period are considered to be hidden + nsCAutoString name; + if (NS_SUCCEEDED(rv = GetNativeLeafName(name))) + { + if (name.First() == '.') + { + *_retval = PR_TRUE; + } + } + } + + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::IsSymlink(PRBool *_retval) +{ + NS_ENSURE_ARG(_retval); + *_retval = PR_FALSE; + + nsresult rv = ResolveAndStat(); + if (NS_FAILED(rv)) return rv; + + Boolean isAlias, isFolder; + if (::IsAliasFile(&mSpec, &isAlias, &isFolder) == noErr) + *_retval = isAlias; + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::Equals(nsIFile *inFile, PRBool *_retval) +{ + NS_ENSURE_ARG(inFile); + NS_ENSURE_ARG(_retval); + *_retval = PR_FALSE; + + // Building paths is expensive. If we can get the FSSpecs of + // both (they or their parents exist) just compare the specs. + nsCOMPtr inMacFile(do_QueryInterface(inFile)); + FSSpec fileSpec, inFileSpec; + if (NS_SUCCEEDED(GetFSSpec(&fileSpec)) && inMacFile && NS_SUCCEEDED(inMacFile->GetFSSpec(&inFileSpec))) + *_retval = IsEqualFSSpec(fileSpec, inFileSpec); + else + { + nsCAutoString filePath; + GetNativePath(filePath); + + nsXPIDLCString inFilePath; + inFile->GetNativePath(inFilePath); + + if (nsCRT::strcasecmp(inFilePath.get(), filePath.get()) == 0) + *_retval = PR_TRUE; + } + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::Contains(nsIFile *inFile, PRBool recur, PRBool *outContains) +{ + /* Note here that we make no attempt to deal with the problem + of folder aliases. Doing a 'Contains' test and dealing with + folder aliases is Hard. Think about it. + */ + *outContains = PR_FALSE; + + PRBool isDir; + nsresult rv = IsDirectory(&isDir); // need to cache this + if (NS_FAILED(rv)) return rv; + if (!isDir) return NS_OK; // must be a dir to contain someone + + nsCOMPtr macFile(do_QueryInterface(inFile)); + if (!macFile) return NS_OK; // trying to compare non-local with local file + + FSSpec mySpec = mSpec; + FSSpec compareSpec; + + // NOTE: we're not resolving inFile if it was an alias + StFollowLinksState followState(macFile, PR_FALSE); + rv = macFile->GetFSSpec(&compareSpec); + if (NS_FAILED(rv)) return rv; + + // if they are on different volumes, bail + if (mSpec.vRefNum != compareSpec.vRefNum) + return NS_OK; + + // if recur == true, test every parent, otherwise just test the first one + // (yes, recur does not get set in this loop) + OSErr err = noErr; + do + { + FSSpec parentFolderSpec; + err = GetParentFolderSpec(compareSpec, parentFolderSpec); + if (err != noErr) break; // we reached the top + + if (IsEqualFSSpec(parentFolderSpec, mySpec)) + { + *outContains = PR_TRUE; + break; + } + + compareSpec = parentFolderSpec; + } while (recur); + + return NS_OK; +} + + + +NS_IMETHODIMP +nsLocalFile::GetNativeTarget(nsACString &_retval) +{ + _retval.Truncate(); + + PRBool symLink; + + nsresult rv = IsSymlink(&symLink); + if (NS_FAILED(rv)) + return rv; + + if (!symLink) + return NS_ERROR_FILE_INVALID_PATH; + + StFollowLinksState followState(this, PR_TRUE); + return GetNativePath(_retval); +} + +NS_IMETHODIMP +nsLocalFile::GetTarget(nsAString &_retval) +{ + nsresult rv; + nsCAutoString fsStr; + + if (NS_SUCCEEDED(rv = GetNativeTarget(fsStr))) { + rv = NS_CopyNativeToUnicode(fsStr, _retval); + } + return rv; +} + +NS_IMETHODIMP +nsLocalFile::GetDirectoryEntries(nsISimpleEnumerator * *entries) +{ + nsresult rv; + + *entries = nsnull; + + PRBool isDir; + rv = IsDirectory(&isDir); + if (NS_FAILED(rv)) + return rv; + if (!isDir) + return NS_ERROR_FILE_NOT_DIRECTORY; + + nsDirEnumerator* dirEnum = new nsDirEnumerator(); + if (dirEnum == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + NS_ADDREF(dirEnum); + rv = dirEnum->Init(this); + if (NS_FAILED(rv)) + { + NS_RELEASE(dirEnum); + return rv; + } + + *entries = dirEnum; + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::GetPersistentDescriptor(nsACString &aPersistentDescriptor) +{ + aPersistentDescriptor.Truncate(); + + nsresult rv = ResolveAndStat(); + if ( NS_FAILED( rv ) ) + return rv; + + AliasHandle aliasH; + OSErr err = ::NewAlias(nil, &mTargetSpec, &aliasH); + if (err != noErr) + return MacErrorMapper(err); + + PRUint32 bytes = ::GetHandleSize((Handle) aliasH); + HLock((Handle) aliasH); + char* buf = PL_Base64Encode((const char*)*aliasH, bytes, nsnull); // Passing nsnull for dest makes NULL-term string + ::DisposeHandle((Handle) aliasH); + NS_ENSURE_TRUE(buf, NS_ERROR_OUT_OF_MEMORY); + + aPersistentDescriptor = buf; + PR_Free(buf); + + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::SetPersistentDescriptor(const nsACString &aPersistentDescriptor) +{ + if (aPersistentDescriptor.IsEmpty()) + return NS_ERROR_INVALID_ARG; + + nsresult rv = NS_OK; + + PRUint32 dataSize = aPersistentDescriptor.Length(); + char* decodedData = PL_Base64Decode(PromiseFlatCString(aPersistentDescriptor).get(), dataSize, nsnull); + // Cast to an alias record and resolve. + AliasHandle aliasH = nsnull; + if (::PtrToHand(decodedData, &(Handle)aliasH, (dataSize * 3) / 4) != noErr) + rv = NS_ERROR_OUT_OF_MEMORY; + PR_Free(decodedData); + NS_ENSURE_SUCCESS(rv, rv); + + Boolean changed; + FSSpec resolvedSpec; + OSErr err; + err = ::ResolveAlias(nsnull, aliasH, &resolvedSpec, &changed); + if (err == fnfErr) // resolvedSpec is valid in this case + err = noErr; + rv = MacErrorMapper(err); + DisposeHandle((Handle) aliasH); + NS_ENSURE_SUCCESS(rv, rv); + + return InitWithFSSpec(&resolvedSpec); +} + +#pragma mark - + +// a stack-based, exception safe class for an AEDesc + +#pragma mark +class StAEDesc: public AEDesc +{ +public: + StAEDesc() + { + descriptorType = typeNull; + dataHandle = nil; + } + + ~StAEDesc() + { + ::AEDisposeDesc(this); + } + + void Clear() + { + ::AEDisposeDesc(this); + descriptorType = typeNull; + dataHandle = nil; + } + +private: + // disallow copies and assigns + StAEDesc(const StAEDesc& rhs); // copy constructor + StAEDesc& operator= (const StAEDesc&rhs); // throws OSErrs + +}; + +#pragma mark - +#pragma mark [Utility methods] + + +nsresult nsLocalFile::UpdateCachedCatInfo(PRBool forceUpdate) +{ + if (!mCatInfoDirty && !forceUpdate) + return NS_OK; + + FSSpec spectoUse = mFollowLinks ? mTargetSpec : mSpec; + mCachedCatInfo.hFileInfo.ioCompletion = nsnull; + mCachedCatInfo.hFileInfo.ioFDirIndex = 0; // use dirID and name + mCachedCatInfo.hFileInfo.ioVRefNum = spectoUse.vRefNum; + mCachedCatInfo.hFileInfo.ioDirID = spectoUse.parID; + mCachedCatInfo.hFileInfo.ioNamePtr = spectoUse.name; + + OSErr err = ::PBGetCatInfoSync(&mCachedCatInfo); + if (err == noErr) + { + mCatInfoDirty = PR_FALSE; + return NS_OK; + } + return MacErrorMapper(err); +} + + +nsresult nsLocalFile::FindRunningAppBySignature (OSType aAppSig, FSSpec& outSpec, ProcessSerialNumber& outPsn) +{ + ProcessInfoRec info; + FSSpec tempFSSpec; + OSErr err = noErr; + + outPsn.highLongOfPSN = 0; + outPsn.lowLongOfPSN = kNoProcess; + + while (PR_TRUE) + { + err = ::GetNextProcess(&outPsn); + if (err == procNotFound) break; + if (err != noErr) return NS_ERROR_FAILURE; + info.processInfoLength = sizeof(ProcessInfoRec); + info.processName = nil; + info.processAppSpec = &tempFSSpec; + err = ::GetProcessInformation(&outPsn, &info); + if (err != noErr) return NS_ERROR_FAILURE; + + if (info.processSignature == aAppSig) + { + outSpec = tempFSSpec; + return NS_OK; + } + } + + return NS_ERROR_FILE_NOT_FOUND; // really process not found +} + + +nsresult nsLocalFile::FindRunningAppByFSSpec(const FSSpec& appSpec, ProcessSerialNumber& outPsn) +{ + ProcessInfoRec info; + FSSpec tempFSSpec; + OSErr err = noErr; + + outPsn.highLongOfPSN = 0; + outPsn.lowLongOfPSN = kNoProcess; + + while (PR_TRUE) + { + err = ::GetNextProcess(&outPsn); + if (err == procNotFound) break; + if (err != noErr) return NS_ERROR_FAILURE; + info.processInfoLength = sizeof(ProcessInfoRec); + info.processName = nil; + info.processAppSpec = &tempFSSpec; + err = ::GetProcessInformation(&outPsn, &info); + if (err != noErr) return NS_ERROR_FAILURE; + + if (IsEqualFSSpec(appSpec, *info.processAppSpec)) + { + return NS_OK; + } + } + + return NS_ERROR_FILE_NOT_FOUND; // really process not found +} + + +nsresult nsLocalFile::FindAppOnLocalVolumes(OSType sig, FSSpec &outSpec) +{ + OSErr err; + + // get the system volume + long systemFolderDirID; + short sysVRefNum; + err = FindFolder(kOnSystemDisk, kSystemFolderType, false, &sysVRefNum, &systemFolderDirID); + if (err != noErr) return NS_ERROR_FAILURE; + + short vRefNum = sysVRefNum; + short index = 0; + + while (true) + { + if (index == 0 || vRefNum != sysVRefNum) + { + // should we avoid AppleShare volumes? + + Boolean hasDesktopDB; + err = VolHasDesktopDB(vRefNum, &hasDesktopDB); + if (err != noErr) return err; + if (hasDesktopDB) + { + err = FindAppOnVolume(sig, vRefNum, &outSpec); + if (err != afpItemNotFound) return err; + } + } + index++; + err = GetIndVolume(index, &vRefNum); + if (err == nsvErr) return fnfErr; + if (err != noErr) return err; + } + + return NS_OK; +} + +#define aeSelectionKeyword 'fsel' +#define kAEOpenSelection 'sope' +#define kAERevealSelection 'srev' +#define kFinderType 'FNDR' + +NS_IMETHODIMP nsLocalFile::Launch() +{ + AppleEvent aeEvent = {0, nil}; + AppleEvent aeReply = {0, nil}; + StAEDesc aeDirDesc, listElem, myAddressDesc, fileList; + FSSpec dirSpec, appSpec; + AliasHandle DirAlias, FileAlias; + OSErr errorResult = noErr; + ProcessSerialNumber process; + + // for launching a file, we'll use mTargetSpec (which is both a resolved spec and a resolved alias) + ResolveAndStat(); + +#if TARGET_CARBON + if (sRunningOSX) + { // We're running under Mac OS X, LaunchServices here we come + + // First we make sure the LaunchServices routine we want is implemented + if ( (UInt32)LSOpenFSRef != (UInt32)kUnresolvedCFragSymbolAddress ) + { + FSRef theRef; + if (::FSpMakeFSRef(&mTargetSpec, &theRef) == noErr) + { + (void)::LSOpenFSRef(&theRef, NULL); + } + } + } + else +#endif + { // We're running under Mac OS 8.x/9.x, use the Finder Luke + nsresult rv = FindRunningAppBySignature ('MACS', appSpec, process); + if (NS_SUCCEEDED(rv)) + { + errorResult = AECreateDesc(typeProcessSerialNumber, (Ptr)&process, sizeof(process), &myAddressDesc); + if (errorResult == noErr) + { + /* Create the FinderEvent */ + errorResult = AECreateAppleEvent(kFinderType, kAEOpenSelection, &myAddressDesc, kAutoGenerateReturnID, kAnyTransactionID, + &aeEvent); + if (errorResult == noErr) + { + errorResult = FSMakeFSSpec(mTargetSpec.vRefNum, mTargetSpec.parID, nil, &dirSpec); + NewAlias(nil, &dirSpec, &DirAlias); + /* Create alias for file */ + NewAlias(nil, &mTargetSpec, &FileAlias); + + /* Create the file list */ + errorResult = AECreateList(nil, 0, false, &fileList); + /* create the folder descriptor */ + HLock((Handle)DirAlias); + errorResult = AECreateDesc(typeAlias, (Ptr)*DirAlias, GetHandleSize((Handle)DirAlias), &aeDirDesc); + HUnlock((Handle)DirAlias); + if (errorResult == noErr) + { + errorResult = AEPutParamDesc(&aeEvent, keyDirectObject, &aeDirDesc); + if ( errorResult == noErr) + { + /* create the file descriptor and add to aliasList */ + HLock((Handle)FileAlias); + errorResult = AECreateDesc(typeAlias, (Ptr)*FileAlias, GetHandleSize((Handle)FileAlias), &listElem); + HLock((Handle)FileAlias); + if (errorResult == noErr) + { + errorResult = AEPutDesc(&fileList, 0, &listElem); + if (errorResult == noErr) + { + /* Add the file alias list to the event */ + errorResult = AEPutParamDesc(&aeEvent, aeSelectionKeyword, &fileList); + if (errorResult == noErr) + AESend(&aeEvent, &aeReply, kAEWaitReply + kAENeverInteract + + kAECanSwitchLayer, kAEHighPriority, kAEDefaultTimeout, nil, nil); + } + } + } + } + } + } + } + } + + return NS_OK; +} + +NS_IMETHODIMP nsLocalFile::Reveal() +{ + FSSpec specToReveal; + AppleEvent aeEvent = {0, nil}; + AppleEvent aeReply = {0, nil}; + StAEDesc aeDirDesc, listElem, myAddressDesc, fileList; + OSErr errorResult = noErr; + ProcessSerialNumber process; + FSSpec appSpec; + + nsresult rv = ResolveAndStat(); + if (NS_FAILED(rv)) + return rv; + rv = GetFSSpec(&specToReveal); // Pay attention to followLinks + if (NS_FAILED(rv)) + return rv; + + rv = FindRunningAppBySignature ('MACS', appSpec, process); + if (NS_SUCCEEDED(rv)) + { + errorResult = AECreateDesc(typeProcessSerialNumber, (Ptr)&process, sizeof(process), &myAddressDesc); + if (errorResult == noErr) + { + /* Create the FinderEvent */ +#if TARGET_CARBON + // The Finder under OS X uses a different event to reveal + if (sRunningOSX) + errorResult = AECreateAppleEvent(kAEMiscStandards, kAEMakeObjectsVisible, &myAddressDesc, kAutoGenerateReturnID, kAnyTransactionID, + &aeEvent); + else +#endif + errorResult = AECreateAppleEvent(kFinderType, kAERevealSelection, &myAddressDesc, kAutoGenerateReturnID, kAnyTransactionID, + &aeEvent); + if (errorResult == noErr) + { + /* Create the file list */ + errorResult = AECreateList(nil, 0, false, &fileList); + if (errorResult == noErr) + { + errorResult = AEPutPtr(&fileList, 0, typeFSS, &specToReveal, sizeof(FSSpec)); + + if (errorResult == noErr) + { +#if TARGET_CARBON + // When we're sending the event under OS X the FSSpec must be a keyDirectObject + if (sRunningOSX) + errorResult = AEPutParamDesc(&aeEvent, keyDirectObject, &fileList); + else +#endif + errorResult = AEPutParamDesc(&aeEvent,keySelection, &fileList); + + if (errorResult == noErr) + { + errorResult = AESend(&aeEvent, &aeReply, kAENoReply, kAENormalPriority, kAEDefaultTimeout, nil, nil); + if (errorResult == noErr) + SetFrontProcess(&process); + } + } + } + } + } + } + + return NS_OK; +} + +nsresult nsLocalFile::MyLaunchAppWithDoc(const FSSpec& appSpec, const FSSpec* aDocToLoad, PRBool aLaunchInBackground) +{ + ProcessSerialNumber thePSN = {0}; + StAEDesc target; + StAEDesc docDesc; + StAEDesc launchDesc; + StAEDesc docList; + AppleEvent theEvent = {0, nil}; + AppleEvent theReply = {0, nil}; + OSErr err = noErr; + Boolean autoParamValue = false; + Boolean running = false; + nsresult rv = NS_OK; + +#if TARGET_CARBON + if (sRunningOSX) + { // Under Mac OS X we'll use LaunchServices + + // First we make sure the LaunchServices routine we want is implemented + if ( (UInt32)LSOpenFromRefSpec != (UInt32)kUnresolvedCFragSymbolAddress ) + { + FSRef appRef; + FSRef docRef; + LSLaunchFlags theLaunchFlags = kLSLaunchDefaults; + LSLaunchFSRefSpec thelaunchSpec; + + if (::FSpMakeFSRef(&appSpec, &appRef) != noErr) + return NS_ERROR_FAILURE; + + if (aDocToLoad) + if (::FSpMakeFSRef(aDocToLoad, &docRef) != noErr) + return NS_ERROR_FAILURE; + + if (aLaunchInBackground) + theLaunchFlags |= kLSLaunchDontSwitch; + + memset(&thelaunchSpec, 0, sizeof(LSLaunchFSRefSpec)); + + thelaunchSpec.appRef = &appRef; + if (aDocToLoad) + { + thelaunchSpec.numDocs = 1; + thelaunchSpec.itemRefs = &docRef; + } + thelaunchSpec.launchFlags = theLaunchFlags; + + err = ::LSOpenFromRefSpec(&thelaunchSpec, NULL); + NS_ASSERTION((err != noErr), "Error calling LSOpenFromRefSpec"); + if (err != noErr) return NS_ERROR_FAILURE; + } + } + else +#endif + { // The old fashioned way for Mac OS 8.x/9.x + rv = FindRunningAppByFSSpec(appSpec, thePSN); + running = NS_SUCCEEDED(rv); + + err = AECreateDesc(typeProcessSerialNumber, &thePSN, sizeof(thePSN), &target); + if (err != noErr) return NS_ERROR_FAILURE; + + err = AECreateAppleEvent(kCoreEventClass, aDocToLoad ? kAEOpenDocuments : kAEOpenApplication, &target, + kAutoGenerateReturnID, kAnyTransactionID, &theEvent); + if (err != noErr) return NS_ERROR_FAILURE; + + if (aDocToLoad) + { + err = AECreateList(nil, 0, false, &docList); + if (err != noErr) return NS_ERROR_FAILURE; + + err = AECreateDesc(typeFSS, aDocToLoad, sizeof(FSSpec), &docDesc); + if (err != noErr) return NS_ERROR_FAILURE; + + err = AEPutDesc(&docList, 0, &docDesc); + if (err != noErr) return NS_ERROR_FAILURE; + + err = AEPutParamDesc(&theEvent, keyDirectObject, &docList); + if (err != noErr) return NS_ERROR_FAILURE; + } + + if (running) + { + err = AESend(&theEvent, &theReply, kAENoReply, kAENormalPriority, kNoTimeOut, nil, nil); + if (err != noErr) return NS_ERROR_FAILURE; + + if (!aLaunchInBackground) + { + err = ::SetFrontProcess(&thePSN); + if (err != noErr) return NS_ERROR_FAILURE; + } + } + else + { + LaunchParamBlockRec launchThis = {0}; + PRUint16 launchControlFlags = (launchContinue | launchNoFileFlags); + if (aLaunchInBackground) + launchControlFlags |= launchDontSwitch; + + err = AECoerceDesc(&theEvent, typeAppParameters, &launchDesc); + if (err != noErr) return NS_ERROR_FAILURE; + + launchThis.launchAppSpec = (FSSpecPtr)&appSpec; +#if TARGET_CARBON && ACCESSOR_CALLS_ARE_FUNCTIONS + ::AEGetDescData(&launchDesc, &launchThis.launchAppParameters, sizeof(launchThis.launchAppParameters)); +#else + // no need to lock this handle. + launchThis.launchAppParameters = (AppParametersPtr) *(launchDesc.dataHandle); +#endif + launchThis.launchBlockID = extendedBlock; + launchThis.launchEPBLength = extendedBlockLen; + launchThis.launchFileFlags = 0; + launchThis.launchControlFlags = launchControlFlags; + err = ::LaunchApplication(&launchThis); + if (err != noErr) return NS_ERROR_FAILURE; + + // let's be nice and wait until it's running + const PRUint32 kMaxTimeToWait = 60; // wait 1 sec max + PRUint32 endTicks = ::TickCount() + kMaxTimeToWait; + + PRBool foundApp = PR_FALSE; + + do + { + EventRecord theEvent; + (void)WaitNextEvent(nullEvent, &theEvent, 1, NULL); + + ProcessSerialNumber psn; + foundApp = NS_SUCCEEDED(FindRunningAppByFSSpec(appSpec, psn)); + + } while (!foundApp && (::TickCount() <= endTicks)); + + NS_ASSERTION(foundApp, "Failed to find app after launching it"); + } + + if (theEvent.dataHandle != nil) AEDisposeDesc(&theEvent); + if (theReply.dataHandle != nil) AEDisposeDesc(&theReply); + } + + return NS_OK; +} + + +#pragma mark - +#pragma mark [Methods that will not be implemented on Mac] + +NS_IMETHODIMP +nsLocalFile::Normalize() +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsLocalFile::GetPermissions(PRUint32 *aPermissions) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsLocalFile::GetPermissionsOfLink(PRUint32 *aPermissionsOfLink) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + + +NS_IMETHODIMP +nsLocalFile::SetPermissions(PRUint32 aPermissions) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsLocalFile::SetPermissionsOfLink(PRUint32 aPermissions) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsLocalFile::IsSpecial(PRBool *_retval) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +#pragma mark - +#pragma mark [nsILocalFileMac] +// Implementation of Mac specific finctions from nsILocalFileMac + + +NS_IMETHODIMP nsLocalFile::InitWithCFURL(CFURLRef aCFURL) +{ + nsresult rv = NS_ERROR_FAILURE; + +#if TARGET_CARBON + NS_ENSURE_ARG(aCFURL); + + // CFURLGetFSRef can only succeed if the entire path exists. + FSRef fsRef; + if (::CFURLGetFSRef(aCFURL, &fsRef) == PR_TRUE) + rv = InitWithFSRef(&fsRef); + else + { + CFURLRef parentURL = ::CFURLCreateCopyDeletingLastPathComponent(NULL, aCFURL); + if (!parentURL) + return NS_ERROR_FAILURE; + + // Get the FSRef from the parent and the FSSpec from that + FSRef parentFSRef; + FSSpec parentFSSpec; + if ((::CFURLGetFSRef(parentURL, &parentFSRef) == PR_TRUE) && + (::FSGetCatalogInfo(&parentFSRef, kFSCatInfoNone, + nsnull, nsnull, &parentFSSpec, nsnull) == noErr)) + { + // Get the leaf name of the file and turn it into a string HFS can use. + CFStringRef fileNameRef = ::CFURLCopyLastPathComponent(aCFURL); + if (fileNameRef) + { + TextEncoding theEncoding; + if (::UpgradeScriptInfoToTextEncoding(smSystemScript, + kTextLanguageDontCare, + kTextRegionDontCare, + NULL, + &theEncoding) != noErr) + theEncoding = kTextEncodingMacRoman; + + char origName[256]; + char truncBuf[32]; + if (::CFStringGetCString(fileNameRef, origName, sizeof(origName), theEncoding)) + { + MakeDirty(); + mSpec = parentFSSpec; + mAppendedPath = NS_TruncNodeName(origName, truncBuf); + rv = NS_OK; + } + ::CFRelease(fileNameRef); + } + } + ::CFRelease(parentURL); + } +#endif + + return rv; +} + + +NS_IMETHODIMP nsLocalFile::InitWithFSRef(const FSRef * aFSRef) +{ + nsresult rv = NS_ERROR_FAILURE; + +#if TARGET_CARBON + NS_ENSURE_ARG(aFSRef); + + FSSpec fsSpec; + OSErr err = ::FSGetCatalogInfo(aFSRef, kFSCatInfoNone, nsnull, + nsnull, &fsSpec, nsnull); + if (err == noErr) + rv = InitWithFSSpec(&fsSpec); + else + rv = MacErrorMapper(err); +#endif + + return rv; +} + + +NS_IMETHODIMP nsLocalFile::InitWithFSSpec(const FSSpec *fileSpec) +{ + MakeDirty(); + mSpec = *fileSpec; + mTargetSpec = *fileSpec; + mAppendedPath = ""; + return NS_OK; +} + + +NS_IMETHODIMP nsLocalFile::InitToAppWithCreatorCode(OSType aAppCreator) +{ + FSSpec appSpec; + ProcessSerialNumber psn; + +#if TARGET_CARBON + if (sRunningOSX) + { // If we're running under OS X use LaunchServices to determine the app + // corresponding to the creator code + if ( (UInt32)LSFindApplicationForInfo != (UInt32)kUnresolvedCFragSymbolAddress ) + { + FSRef theRef; + if (::LSFindApplicationForInfo(aAppCreator, NULL, NULL, &theRef, NULL) == noErr) + { + FSCatalogInfoBitmap whichInfo = kFSCatInfoNone; + + if (::FSGetCatalogInfo(&theRef, whichInfo, NULL, NULL, &appSpec, NULL) == noErr) + return InitWithFSSpec(&appSpec); + } + + // If we get here we didn't find an app + return NS_ERROR_FILE_NOT_FOUND; + } + } +#endif + + // is the app running? + nsresult rv = FindRunningAppBySignature(aAppCreator, appSpec, psn); + if (rv == NS_ERROR_FILE_NOT_FOUND) + { + // we have to look on disk + rv = FindAppOnLocalVolumes(aAppCreator, appSpec); + if (NS_FAILED(rv)) return rv; + } + else if (NS_FAILED(rv)) + return rv; + + // init with the spec here + return InitWithFSSpec(&appSpec); +} + +NS_IMETHODIMP nsLocalFile::GetCFURL(CFURLRef *_retval) +{ + nsresult rv = NS_ERROR_FAILURE; + +#if TARGET_CARBON + NS_ENSURE_ARG_POINTER(_retval); + *_retval = nsnull; + + PRBool exists; + if (NS_SUCCEEDED(Exists(&exists)) && exists) + { + FSRef fsRef; + FSSpec fsSpec = mFollowLinks ? mTargetSpec : mSpec; + if (::FSpMakeFSRef(&fsSpec, &fsRef) == noErr) + { + *_retval = ::CFURLCreateFromFSRef(NULL, &fsRef); + if (*_retval) + return NS_OK; + } + } + else + { + nsCAutoString tempPath; + if (NS_SUCCEEDED(GetNativePath(tempPath))) + { + CFStringRef pathStrRef = ::CFStringCreateWithCString(NULL, tempPath.get(), kCFStringEncodingMacRoman); + if (!pathStrRef) + return NS_ERROR_FAILURE; + *_retval = ::CFURLCreateWithFileSystemPath(NULL, pathStrRef, kCFURLHFSPathStyle, false); + ::CFRelease(pathStrRef); + if (*_retval) + return NS_OK; + } + } +#endif + + return rv; +} + +NS_IMETHODIMP nsLocalFile::GetFSRef(FSRef *_retval) +{ + nsresult rv = NS_ERROR_FAILURE; + +#if TARGET_CARBON + NS_ENSURE_ARG_POINTER(_retval); + + FSSpec fsSpec; + rv = GetFSSpec(&fsSpec); + if (NS_SUCCEEDED(rv)) + rv = MacErrorMapper(::FSpMakeFSRef(&fsSpec, _retval)); +#endif + + return rv; +} + +NS_IMETHODIMP nsLocalFile::GetFSSpec(FSSpec *fileSpec) +{ + NS_ENSURE_ARG(fileSpec); + nsresult rv = ResolveAndStat(); + if (rv == NS_ERROR_FILE_NOT_FOUND) + rv = NS_OK; + if (NS_SUCCEEDED(rv)) + *fileSpec = mFollowLinks ? mTargetSpec : mSpec; + + return NS_OK; +} + +NS_IMETHODIMP nsLocalFile::GetFileType(OSType *aFileType) +{ + NS_ENSURE_ARG(aFileType); + + FSSpec fileSpec; + (void)GetFSSpec(&fileSpec); + + FInfo info; + OSErr err = ::FSpGetFInfo(&fileSpec, &info); + if (err != noErr) + { + *aFileType = mType; + return NS_ERROR_FILE_NOT_FOUND; + } + + *aFileType = info.fdType; + + return NS_OK; +} + +NS_IMETHODIMP nsLocalFile::SetFileType(OSType aFileType) +{ + mType = aFileType; + + FSSpec fileSpec; + (void)GetFSSpec(&fileSpec); + + FInfo info; + OSErr err = ::FSpGetFInfo(&fileSpec, &info); + if (err != noErr) + return NS_ERROR_FILE_NOT_FOUND; + + info.fdType = aFileType; + err = ::FSpSetFInfo(&fileSpec, &info); + if (err != noErr) + return NS_ERROR_FILE_ACCESS_DENIED; + + return NS_OK; +} + +NS_IMETHODIMP nsLocalFile::GetFileCreator(OSType *aCreator) +{ + NS_ENSURE_ARG(aCreator); + + FSSpec fileSpec; + (void)GetFSSpec(&fileSpec); + + FInfo info; + OSErr err = ::FSpGetFInfo(&fileSpec, &info); + if (err != noErr) + { + *aCreator = mCreator; + return NS_ERROR_FILE_NOT_FOUND; + } + + *aCreator = info.fdCreator; + + return NS_OK; +} + +NS_IMETHODIMP nsLocalFile::SetFileCreator(OSType aCreator) +{ + if (aCreator == CURRENT_PROCESS_CREATOR) + aCreator = sCurrentProcessSignature; + + mCreator = aCreator; + + FSSpec fileSpec; + (void)GetFSSpec(&fileSpec); + + FInfo info; + OSErr err = ::FSpGetFInfo(&fileSpec, &info); + if (err != noErr) + return NS_ERROR_FILE_NOT_FOUND; + + info.fdCreator = aCreator; + err = ::FSpSetFInfo(&fileSpec, &info); + if (err != noErr) + return NS_ERROR_FILE_ACCESS_DENIED; + + return NS_OK; +} + +NS_IMETHODIMP nsLocalFile::SetFileTypeAndCreatorFromExtension(const char *aExtension) +{ + NS_ENSURE_ARG(aExtension); + return SetOSTypeAndCreatorFromExtension(aExtension); +} + +NS_IMETHODIMP nsLocalFile::SetFileTypeAndCreatorFromMIMEType(const char *aMIMEType) +{ + NS_ENSURE_ARG(aMIMEType); + + nsresult rv; + nsCOMPtr icService(do_GetService + (NS_INTERNETCONFIGSERVICE_CONTRACTID, &rv)); + + if (NS_SUCCEEDED(rv)) + { + nsCOMPtr mimeInfo; + PRUint32 fileType = 'TEXT'; + PRUint32 fileCreator = nsILocalFileMac::CURRENT_PROCESS_CREATOR; + + rv = icService->FillInMIMEInfo(aMIMEType, + nsnull, getter_AddRefs(mimeInfo)); + if (NS_SUCCEEDED(rv)) + rv = mimeInfo->GetMacType(&fileType); + if (NS_SUCCEEDED(rv)) + rv = mimeInfo->GetMacCreator(&fileCreator); + if (NS_SUCCEEDED(rv)) + rv = SetFileType(fileType); + if (NS_SUCCEEDED(rv)) + rv = SetFileCreator(fileCreator); + } + + return rv; +} + +NS_IMETHODIMP +nsLocalFile::GetFileSizeWithResFork(PRInt64 *aFileSize) +{ + NS_ENSURE_ARG(aFileSize); + + *aFileSize = LL_Zero(); + + ResolveAndStat(); + + long dataSize = 0; + long resSize = 0; + + OSErr err = FSpGetFileSize(&mTargetSpec, &dataSize, &resSize); + + if (err != noErr) + return MacErrorMapper(err); + + // For now we've only got 32 bits of file size info + PRInt64 dataInt64 = LL_Zero(); + PRInt64 resInt64 = LL_Zero(); + + // Combine the size of the resource and data forks + LL_I2L(resInt64, resSize); + LL_I2L(dataInt64, dataSize); + LL_ADD((*aFileSize), dataInt64, resInt64); + + return NS_OK; +} + + +// this nsLocalFile points to the app. We want to launch it, optionally with the document. +NS_IMETHODIMP +nsLocalFile::LaunchWithDoc(nsILocalFile* aDocToLoad, PRBool aLaunchInBackground) +{ + // are we launchable? + PRBool isExecutable; + nsresult rv = IsExecutable(&isExecutable); + if (NS_FAILED(rv)) return rv; + if (!isExecutable) return NS_ERROR_FILE_EXECUTION_FAILED; + + FSSpec docSpec; + FSSpecPtr docSpecPtr = nsnull; + + nsCOMPtr macDoc = do_QueryInterface(aDocToLoad); + if (macDoc) + { + rv = macDoc->GetFSSpec(&docSpec); // XXX GetTargetFSSpec + if (NS_FAILED(rv)) return rv; + + docSpecPtr = &docSpec; + } + + FSSpec appSpec; + rv = GetFSSpec(&appSpec); // XXX GetResolvedFSSpec + if (NS_FAILED(rv)) return rv; + + rv = MyLaunchAppWithDoc(appSpec, docSpecPtr, aLaunchInBackground); + return rv; +} + + +NS_IMETHODIMP +nsLocalFile::OpenDocWithApp(nsILocalFile* aAppToOpenWith, PRBool aLaunchInBackground) +{ + // if aAppToOpenWith is nil, we have to find the app from the creator code + // of the document + nsresult rv = NS_OK; + + FSSpec appSpec; + + if (aAppToOpenWith) + { + nsCOMPtr appFileMac = do_QueryInterface(aAppToOpenWith, &rv); + if (!appFileMac) return rv; + + rv = appFileMac->GetFSSpec(&appSpec); // XXX GetTargetFSSpec + if (NS_FAILED(rv)) return rv; + + // is it launchable? + PRBool isExecutable; + rv = aAppToOpenWith->IsExecutable(&isExecutable); + if (NS_FAILED(rv)) return rv; + if (!isExecutable) return NS_ERROR_FILE_EXECUTION_FAILED; + } + else + { + // look for one + OSType fileCreator; + rv = GetFileCreator(&fileCreator); + if (NS_FAILED(rv)) return rv; + + // just make one on the stack + nsLocalFile localAppFile; + rv = localAppFile.InitToAppWithCreatorCode(fileCreator); + if (NS_FAILED(rv)) return rv; + + rv = localAppFile.GetFSSpec(&appSpec); // GetTargetFSSpec + if (NS_FAILED(rv)) return rv; + } + + FSSpec docSpec; + rv = GetFSSpec(&docSpec); // XXX GetResolvedFSSpec + if (NS_FAILED(rv)) return rv; + + rv = MyLaunchAppWithDoc(appSpec, &docSpec, aLaunchInBackground); + return rv; +} + +nsresult nsLocalFile::SetOSTypeAndCreatorFromExtension(const char* extension) +{ + nsresult rv; + + nsCAutoString localExtBuf; + const char *extPtr; + + if (!extension) + { + rv = GetNativeLeafName(localExtBuf); + extPtr = strrchr(localExtBuf.get(), '.'); + if (!extPtr) + return NS_ERROR_FAILURE; + ++extPtr; + } + else + { + extPtr = extension; + if (*extPtr == '.') + ++extPtr; + } + + nsCOMPtr icService = + do_GetService(NS_INTERNETCONFIGSERVICE_CONTRACTID, &rv); + if (NS_SUCCEEDED(rv)) + { + nsCOMPtr mimeInfo; + rv = icService->GetMIMEInfoFromExtension(extPtr, getter_AddRefs(mimeInfo)); + if (NS_SUCCEEDED(rv)) + { + PRUint32 osType; + rv = mimeInfo->GetMacType(&osType); + if (NS_SUCCEEDED(rv)) + mType = osType; + PRBool skip; + rv = ExtensionIsOnExceptionList(extPtr, &skip); + if (NS_SUCCEEDED(rv) && !skip) + { + rv = mimeInfo->GetMacCreator(&osType); + if (NS_SUCCEEDED(rv)) + mCreator = osType; + } + } + } + return rv; +} + +nsresult nsLocalFile::ExtensionIsOnExceptionList(const char *extension, PRBool *onList) +{ + // Probably want to make a global list somewhere in the future + // for now, just check for "html" and "htm" + + *onList = PR_FALSE; + + if (!nsCRT::strcasecmp(extension, "html") || + !nsCRT::strcasecmp(extension, "htm")) + *onList = PR_TRUE; + return NS_OK; +} + + +void nsLocalFile::InitClassStatics() +{ + OSErr err; + + + if (sCurrentProcessSignature == 0) + { + ProcessSerialNumber psn; + ProcessInfoRec info; + + psn.highLongOfPSN = 0; + psn.lowLongOfPSN = kCurrentProcess; + + info.processInfoLength = sizeof(ProcessInfoRec); + info.processName = nil; + info.processAppSpec = nil; + err = ::GetProcessInformation(&psn, &info); + if (err == noErr) + sCurrentProcessSignature = info.processSignature; + // Try again next time if error + } + + static PRBool didHFSPlusCheck = PR_FALSE; + if (!didHFSPlusCheck) + { + long response; + err = ::Gestalt(gestaltFSAttr, &response); + sHasHFSPlusAPIs = (err == noErr && (response & (1 << gestaltHasHFSPlusAPIs)) != 0); + didHFSPlusCheck = PR_TRUE; + } + + static PRBool didOSXCheck = PR_FALSE; + if (!didOSXCheck) + { + long version; + sRunningOSX = (::Gestalt(gestaltSystemVersion, &version) == noErr && version >= 0x00001000); + didOSXCheck = PR_TRUE; + } +} + + +#pragma mark - + +// Handy dandy utility create routine for something or the other +nsresult +NS_NewNativeLocalFile(const nsACString &path, PRBool followLinks, nsILocalFile* *result) +{ + nsLocalFile* file = new nsLocalFile(); + if (file == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + NS_ADDREF(file); + + file->SetFollowLinks(followLinks); + + if (!path.IsEmpty()) { + nsresult rv = file->InitWithNativePath(path); + if (NS_FAILED(rv)) { + NS_RELEASE(file); + return rv; + } + } + *result = file; + return NS_OK; +} + +nsresult +NS_NewLocalFile(const nsAString &path, PRBool followLinks, nsILocalFile* *result) +{ + nsCAutoString fsCharSetStr; + nsresult rv = NS_CopyUnicodeToNative(path, fsCharSetStr); + if (NS_FAILED(rv)) + return rv; + return NS_NewNativeLocalFile(fsCharSetStr, followLinks, result); +} + +nsresult +NS_NewLocalFileWithFSSpec(const FSSpec* inSpec, PRBool followLinks, nsILocalFileMac* *result) +{ + nsLocalFile* file = new nsLocalFile(); + if (file == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + NS_ADDREF(file); + + file->SetFollowLinks(followLinks); + + nsresult rv = file->InitWithFSSpec(inSpec); + if (NS_FAILED(rv)) { + NS_RELEASE(file); + return rv; + } + *result = file; + return NS_OK; +} + +void +nsLocalFile::GlobalInit() +{ +} + +void +nsLocalFile::GlobalShutdown() +{ +} diff --git a/src/libs/xpcom18a4/xpcom/io/nsLocalFileMac.h b/src/libs/xpcom18a4/xpcom/io/nsLocalFileMac.h new file mode 100644 index 00000000..42eb2556 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsLocalFileMac.h @@ -0,0 +1,137 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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 Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Steve Dagley + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +#ifndef _nsLocalFileMAC_H_ +#define _nsLocalFileMAC_H_ + +#include "nscore.h" +#include "nsError.h" +#include "nsString.h" +#include "nsCRT.h" +#include "nsIFile.h" +#include "nsILocalFileMac.h" +#include "nsIFactory.h" + +#include + +class NS_COM nsLocalFile : public nsILocalFileMac +{ +public: + NS_DEFINE_STATIC_CID_ACCESSOR(NS_LOCAL_FILE_CID) + + nsLocalFile(); + + static NS_METHOD nsLocalFileConstructor(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr); + + // nsISupports interface + NS_DECL_ISUPPORTS + + // nsIFile interface + NS_DECL_NSIFILE + + // nsILocalFile interface + NS_DECL_NSILOCALFILE + + // nsILocalFileMac interface + NS_DECL_NSILOCALFILEMAC + +public: + + static void GlobalInit(); + static void GlobalShutdown(); + +private: + ~nsLocalFile() {} + +protected: + void MakeDirty(); + nsresult ResolveAndStat(); + nsresult UpdateCachedCatInfo(PRBool forceUpdate); + + nsresult FindAppOnLocalVolumes(OSType sig, FSSpec &outSpec); + + nsresult FindRunningAppBySignature(OSType sig, FSSpec& outSpec, ProcessSerialNumber& outPsn); + nsresult FindRunningAppByFSSpec(const FSSpec& appSpec, ProcessSerialNumber& outPsn); + + nsresult MyLaunchAppWithDoc(const FSSpec& appSpec, const FSSpec* aDocToLoad, PRBool aLaunchInBackground); + + nsresult TestFinderFlag(PRUint16 flagMask, PRBool *outFlagSet, PRBool testTargetSpec = PR_TRUE); + + nsresult MoveCopy( nsIFile* newParentDir, const nsACString &newName, PRBool isCopy, PRBool followLinks ); + + // Passing nsnull for the extension uses leaf name + nsresult SetOSTypeAndCreatorFromExtension(const char* extension = nsnull); + + nsresult ExtensionIsOnExceptionList(const char *extension, PRBool *onList); + +private: + nsLocalFile(const nsLocalFile& srcFile); + nsLocalFile(const FSSpec& aSpec, const nsACString& aAppendedPath); + + // Copies all members except mRefCnt, copies mCachedCatInfo only if it's valid. + nsLocalFile& operator=(const nsLocalFile& rhs); + + PRPackedBool mFollowLinks; + PRPackedBool mFollowLinksDirty; + + // The object we specify is always: mSpec + mAppendedPath. + // mSpec is a valid spec in that its parent is known to exist. + // Appending nodes with Append() will update mSpec immediately + // if the appended node exists. If not, appended nodes are stored + // in mAppendedPath. + + PRPackedBool mSpecDirty; + FSSpec mSpec; + nsCString mAppendedPath; + FSSpec mTargetSpec; // If mSpec is an alias, this is the resolved alias. + + CInfoPBRec mCachedCatInfo; // cached file info, for the GetFSSpec() spec + PRPackedBool mCatInfoDirty; // does this need to be updated? + + OSType mType, mCreator; + + static void InitClassStatics(); + + static OSType sCurrentProcessSignature; + static PRBool sHasHFSPlusAPIs; + static PRBool sRunningOSX; +}; + +#endif + diff --git a/src/libs/xpcom18a4/xpcom/io/nsLocalFileOS2.cpp b/src/libs/xpcom18a4/xpcom/io/nsLocalFileOS2.cpp new file mode 100644 index 00000000..269a13d0 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsLocalFileOS2.cpp @@ -0,0 +1,1742 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Henry Sobotka + * IBM Corp. + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsCOMPtr.h" +#include "nsMemory.h" + +#include "nsLocalFile.h" +#include "nsNativeCharsetUtils.h" + +#include "nsISimpleEnumerator.h" +#include "nsIComponentManager.h" +#include "prtypes.h" +#include "prio.h" + +#include // needed for toupper +#include + +#include "nsXPIDLString.h" +#include "nsReadableUtils.h" +#include "prproces.h" +#include "prthread.h" + + +static unsigned char* PR_CALLBACK +_mbschr( const unsigned char* stringToSearch, int charToSearchFor); +extern unsigned char* +_mbsrchr( const unsigned char* stringToSearch, int charToSearchFor); +static nsresult PR_CALLBACK +CreateDirectoryA( PSZ path, PEAOP2 ppEABuf); +static int isleadbyte(int c); + +#include +#include + + +static nsresult ConvertOS2Error(int err) +{ + nsresult rv; + + switch (err) + { + case ERROR_FILE_NOT_FOUND: + case ERROR_PATH_NOT_FOUND: + case ERROR_INVALID_DRIVE: + rv = NS_ERROR_FILE_NOT_FOUND; + break; + case ERROR_ACCESS_DENIED: + case ERROR_NOT_SAME_DEVICE: + rv = NS_ERROR_FILE_ACCESS_DENIED; + break; + case ERROR_NOT_ENOUGH_MEMORY: + case ERROR_INVALID_BLOCK: + case ERROR_INVALID_HANDLE: + case ERROR_ARENA_TRASHED: + rv = NS_ERROR_OUT_OF_MEMORY; + break; + case ERROR_CURRENT_DIRECTORY: + rv = NS_ERROR_FILE_DIR_NOT_EMPTY; + break; + case ERROR_WRITE_PROTECT: + rv = NS_ERROR_FILE_READ_ONLY; + break; + case ERROR_HANDLE_DISK_FULL: + rv = NS_ERROR_FILE_TOO_BIG; + break; + case ERROR_FILE_EXISTS: + case ERROR_ALREADY_EXISTS: + case ERROR_CANNOT_MAKE: + rv = NS_ERROR_FILE_ALREADY_EXISTS; + break; + case 0: + rv = NS_OK; + break; + default: + rv = NS_ERROR_FAILURE; + break; + } + return rv; +} + +static void +myLL_L2II(PRInt64 result, PRInt32 *hi, PRInt32 *lo ) +{ + PRInt64 a64, b64; // probably could have been done with + // only one PRInt64, but these are macros, + // and I am a wimp. + + // shift the hi word to the low word, then push it into a long. + LL_SHR(a64, result, 32); + LL_L2I(*hi, a64); + + // shift the low word to the hi word first, then shift it back. + LL_SHL(b64, result, 32); + LL_SHR(a64, b64, 32); + LL_L2I(*lo, a64); +} + + +class nsDirEnumerator : public nsISimpleEnumerator +{ + public: + + NS_DECL_ISUPPORTS + + nsDirEnumerator() : mDir(nsnull) + { + } + + nsresult Init(nsILocalFile* parent) + { + nsCAutoString filepath; + parent->GetNativeTarget(filepath); + + if (filepath.IsEmpty()) + { + parent->GetNativePath(filepath); + } + + if (filepath.IsEmpty()) + { + return NS_ERROR_UNEXPECTED; + } + + mDir = PR_OpenDir(filepath.get()); + if (mDir == nsnull) // not a directory? + return NS_ERROR_FAILURE; + + mParent = parent; + return NS_OK; + } + + NS_IMETHOD HasMoreElements(PRBool *result) + { + nsresult rv; + if (mNext == nsnull && mDir) + { + PRDirEntry* entry = PR_ReadDir(mDir, PR_SKIP_BOTH); + if (entry == nsnull) + { + // end of dir entries + + PRStatus status = PR_CloseDir(mDir); + if (status != PR_SUCCESS) + return NS_ERROR_FAILURE; + mDir = nsnull; + + *result = PR_FALSE; + return NS_OK; + } + + nsCOMPtr file; + rv = mParent->Clone(getter_AddRefs(file)); + if (NS_FAILED(rv)) + return rv; + + rv = file->AppendNative(nsDependentCString(entry->name)); + if (NS_FAILED(rv)) + return rv; + + // make sure the thing exists. If it does, try the next one. + PRBool exists; + rv = file->Exists(&exists); + if (NS_FAILED(rv) || !exists) + { + return HasMoreElements(result); + } + + mNext = do_QueryInterface(file); + } + *result = mNext != nsnull; + return NS_OK; + } + + NS_IMETHOD GetNext(nsISupports **result) + { + nsresult rv; + PRBool hasMore; + rv = HasMoreElements(&hasMore); + if (NS_FAILED(rv)) return rv; + + *result = mNext; // might return nsnull + NS_IF_ADDREF(*result); + + mNext = nsnull; + return NS_OK; + } + + private: + ~nsDirEnumerator() + { + if (mDir) + { + PRStatus status = PR_CloseDir(mDir); + NS_ASSERTION(status == PR_SUCCESS, "close failed"); + } + } + + protected: + PRDir* mDir; + nsCOMPtr mParent; + nsCOMPtr mNext; +}; + +NS_IMPL_ISUPPORTS1(nsDirEnumerator, nsISimpleEnumerator) + + +nsLocalFile::nsLocalFile() +{ + MakeDirty(); +} + +nsLocalFile::nsLocalFile(const nsLocalFile& other) + : mDirty(other.mDirty) + , mWorkingPath(other.mWorkingPath) + , mFileInfo64(other.mFileInfo64) +{ +} + +/* nsISupports interface implementation. */ +NS_IMPL_THREADSAFE_ISUPPORTS2(nsLocalFile, nsILocalFile, nsIFile) + +NS_METHOD +nsLocalFile::nsLocalFileConstructor(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr) +{ + NS_ENSURE_ARG_POINTER(aInstancePtr); + NS_ENSURE_NO_AGGREGATION(outer); + + nsLocalFile* inst = new nsLocalFile(); + if (inst == NULL) + return NS_ERROR_OUT_OF_MEMORY; + + nsresult rv = inst->QueryInterface(aIID, aInstancePtr); + if (NS_FAILED(rv)) + { + delete inst; + return rv; + } + return NS_OK; +} + +// This function resets any cached information about the file. +void +nsLocalFile::MakeDirty() +{ + mDirty = PR_TRUE; +} + +nsresult +nsLocalFile::Stat() +{ + if (!mDirty) + return NS_OK; + + char temp[4]; + const char* workingFilePath = mWorkingPath.get(); + const char* nsprPath = workingFilePath; + + if (mWorkingPath.Length() == 2 && mWorkingPath.CharAt(1) == ':') { + temp[0] = workingFilePath[0]; + temp[1] = workingFilePath[1]; + temp[2] = '\\'; + temp[3] = '\0'; + nsprPath = temp; + } + + DosError(FERR_DISABLEHARDERR); + PRStatus status = PR_GetFileInfo64(nsprPath, &mFileInfo64); + DosError(FERR_ENABLEHARDERR); + if ( status == PR_SUCCESS ) + return NS_OK; + + return NS_ERROR_FILE_NOT_FOUND; +} + +NS_IMETHODIMP +nsLocalFile::Clone(nsIFile **file) +{ + // Just copy-construct ourselves + *file = new nsLocalFile(*this); + if (!*file) + return NS_ERROR_OUT_OF_MEMORY; + + NS_ADDREF(*file); + + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::InitWithNativePath(const nsACString &filePath) +{ + MakeDirty(); + + nsACString::const_iterator begin, end; + filePath.BeginReading(begin); + filePath.EndReading(end); + + // input string must not be empty + if (begin == end) + return NS_ERROR_FAILURE; + + char firstChar = *begin; + char secondChar = *(++begin); + + // just do a sanity check. if it has any forward slashes, it is not a Native path + // on windows. Also, it must have a colon at after the first char. + + char *path = nsnull; + PRInt32 pathLen = 0; + + if ( ( (secondChar == ':') && !FindCharInReadable('/', begin, end) ) || // normal path + ( (firstChar == '\\') && (secondChar == '\\') ) ) // network path + { + // This is a native path + path = ToNewCString(filePath); + pathLen = filePath.Length(); + } + + if (path == nsnull) + return NS_ERROR_FILE_UNRECOGNIZED_PATH; + + // kill any trailing '\' provided it isn't the second char of DBCS + PRInt32 len = pathLen - 1; + if (path[len] == '\\' && !::isleadbyte(path[len-1])) + { + path[len] = '\0'; + pathLen = len; + } + + mWorkingPath.Adopt(path, pathLen); + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::OpenNSPRFileDesc(PRInt32 flags, PRInt32 mode, PRFileDesc **_retval) +{ + nsresult rv = Stat(); + if (NS_FAILED(rv) && rv != NS_ERROR_FILE_NOT_FOUND) + return rv; + + *_retval = PR_Open(mWorkingPath.get(), flags, mode); + + if (*_retval) + return NS_OK; + + return NS_ErrorAccordingToNSPR(); +} + + +NS_IMETHODIMP +nsLocalFile::OpenANSIFileDesc(const char *mode, FILE * *_retval) +{ + nsresult rv = Stat(); + if (NS_FAILED(rv) && rv != NS_ERROR_FILE_NOT_FOUND) + return rv; + + *_retval = fopen(mWorkingPath.get(), mode); + + if (*_retval) + return NS_OK; + + return NS_ERROR_FAILURE; +} + + + +NS_IMETHODIMP +nsLocalFile::Create(PRUint32 type, PRUint32 attributes) +{ + if (type != NORMAL_FILE_TYPE && type != DIRECTORY_TYPE) + return NS_ERROR_FILE_UNKNOWN_TYPE; + + nsresult rv = Stat(); + if (NS_FAILED(rv) && rv != NS_ERROR_FILE_NOT_FOUND) + return rv; + + // create nested directories to target + unsigned char* slash = _mbschr((const unsigned char*) mWorkingPath.get(), '\\'); + + + if (slash) + { + // skip the first '\\' + ++slash; + slash = _mbschr(slash, '\\'); + + while (slash) + { + *slash = '\0'; + + rv = CreateDirectoryA(NS_CONST_CAST(char*, mWorkingPath.get()), NULL); + if (rv) { + rv = ConvertOS2Error(rv); + if (rv != NS_ERROR_FILE_ALREADY_EXISTS) return rv; + } + *slash = '\\'; + ++slash; + slash = _mbschr(slash, '\\'); + } + } + + if (type == NORMAL_FILE_TYPE) + { + PRFileDesc* file = PR_Open(mWorkingPath.get(), PR_RDONLY | PR_CREATE_FILE | PR_APPEND | PR_EXCL, attributes); + if (!file) return NS_ERROR_FILE_ALREADY_EXISTS; + + PR_Close(file); + return NS_OK; + } + + if (type == DIRECTORY_TYPE) + { + rv = CreateDirectoryA(NS_CONST_CAST(char*, mWorkingPath.get()), NULL); + if (rv) + return ConvertOS2Error(rv); + else + return NS_OK; + } + + return NS_ERROR_FILE_UNKNOWN_TYPE; +} + +NS_IMETHODIMP +nsLocalFile::AppendNative(const nsACString &node) +{ + if (node.IsEmpty()) + return NS_OK; + + // Append only one component. Check for subdirs. + // XXX can we avoid the PromiseFlatCString call? + if (_mbschr((const unsigned char*) PromiseFlatCString(node).get(), '\\') != nsnull) + return NS_ERROR_FILE_UNRECOGNIZED_PATH; + + return AppendRelativeNativePath(node); +} + +NS_IMETHODIMP +nsLocalFile::AppendRelativeNativePath(const nsACString &node) +{ + // Cannot start with a / or have .. or have / anywhere + nsACString::const_iterator begin, end; + node.BeginReading(begin); + node.EndReading(end); + if (node.IsEmpty() || FindCharInReadable('/', begin, end)) + { + return NS_ERROR_FILE_UNRECOGNIZED_PATH; + } + MakeDirty(); + mWorkingPath.Append(NS_LITERAL_CSTRING("\\") + node); + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::Normalize() +{ + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::GetNativeLeafName(nsACString &aLeafName) +{ + aLeafName.Truncate(); + + const char* temp = mWorkingPath.get(); + if(temp == nsnull) + return NS_ERROR_FILE_UNRECOGNIZED_PATH; + + const char* leaf = (const char*) _mbsrchr((const unsigned char*) temp, '\\'); + + // if the working path is just a node without any lashes. + if (leaf == nsnull) + leaf = temp; + else + leaf++; + + aLeafName.Assign(leaf); + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::SetNativeLeafName(const nsACString &aLeafName) +{ + MakeDirty(); + + const unsigned char* temp = (const unsigned char*) mWorkingPath.get(); + if(temp == nsnull) + return NS_ERROR_FILE_UNRECOGNIZED_PATH; + + // cannot use nsCString::RFindChar() due to 0x5c problem + PRInt32 offset = (PRInt32) (_mbsrchr(temp, '\\') - temp); + if (offset) + { + mWorkingPath.Truncate(offset+1); + } + mWorkingPath.Append(aLeafName); + + return NS_OK; +} + + +NS_IMETHODIMP +nsLocalFile::GetNativePath(nsACString &_retval) +{ + _retval = mWorkingPath; + return NS_OK; +} + +nsresult +nsLocalFile::CopySingleFile(nsIFile *sourceFile, nsIFile *destParent, const nsACString &newName, PRBool move) +{ + nsresult rv; + nsCAutoString filePath; + + nsCAutoString destPath; + destParent->GetNativeTarget(destPath); + + destPath.Append("\\"); + + if (newName.IsEmpty()) + { + nsCAutoString aFileName; + sourceFile->GetNativeLeafName(aFileName); + destPath.Append(aFileName); + } + else + { + destPath.Append(newName); + } + + rv = sourceFile->GetNativePath(filePath); + + if (NS_FAILED(rv)) + return rv; + + APIRET rc = NO_ERROR; + + if( move ) + { + rc = DosMove(filePath.get(), (PSZ)NS_CONST_CAST(char*, destPath.get())); + } + + if (!move || rc == ERROR_NOT_SAME_DEVICE || rc == ERROR_ACCESS_DENIED) { + /* will get an error if the destination and source files aren't on the + * same drive. "MoveFile()" on Windows will go ahead and move the + * file without error, so we need to do the same IBM-AKR + */ + do { + rc = DosCopy(filePath.get(), (PSZ)NS_CONST_CAST(char*, destPath.get()), DCPY_EXISTING); + if (rc == ERROR_TOO_MANY_OPEN_FILES) { + ULONG CurMaxFH = 0; + LONG ReqCount = 20; + APIRET rc2; + rc2 = DosSetRelMaxFH(&ReqCount, &CurMaxFH); + if (rc2 != NO_ERROR) { + break; + } + } + } while (rc == ERROR_TOO_MANY_OPEN_FILES); + + /* WSOD2 HACK */ + if (rc == 65) { // NETWORK_ACCESS_DENIED + CHAR achProgram[CCHMAXPATH]; // buffer for program name, parameters + RESULTCODES rescResults; // buffer for results of dosexecpgm + + strcpy(achProgram, "CMD.EXE /C "); + strcat(achProgram, """COPY "); + strcat(achProgram, filePath.get()); + strcat(achProgram, " "); + strcat(achProgram, (PSZ)NS_CONST_CAST(char*, destPath.get())); + strcat(achProgram, """"); + achProgram[strlen(achProgram) + 1] = '\0'; + achProgram[7] = '\0'; + DosExecPgm(NULL, 0, + EXEC_SYNC, achProgram, (PSZ)NULL, + &rescResults, achProgram); + rc = 0; // Assume it worked + + } /* rc == 65 */ + /* moving the file is supposed to act like a rename, so delete the + * original file if we got this far without error + */ + if( move && (rc == NO_ERROR) ) + { + DosDelete( filePath.get() ); + } + } /* !move or ERROR */ + + if (rc) + rv = ConvertOS2Error(rc); + + return rv; +} + + +nsresult +nsLocalFile::CopyMove(nsIFile *aParentDir, const nsACString &newName, PRBool move) +{ + nsCOMPtr newParentDir = aParentDir; + + nsresult rv = Stat(); + if (NS_FAILED(rv)) + return rv; + + if (!newParentDir) + { + // no parent was specified. We must rename. + + if (newName.IsEmpty()) + return NS_ERROR_INVALID_ARG; + + rv = GetParent(getter_AddRefs(newParentDir)); + if (NS_FAILED(rv)) + return rv; + } + + if (!newParentDir) + return NS_ERROR_FILE_DESTINATION_NOT_DIR; + + // make sure it exists and is a directory. Create it if not there. + PRBool exists; + newParentDir->Exists(&exists); + if (exists == PR_FALSE) + { + rv = newParentDir->Create(DIRECTORY_TYPE, 0644); // TODO, what permissions should we use + if (NS_FAILED(rv)) + return rv; + } + else + { + PRBool isDir; + newParentDir->IsDirectory(&isDir); + if (isDir == PR_FALSE) + { + return NS_ERROR_FILE_DESTINATION_NOT_DIR; + } + } + + // check to see if we are a directory, if so enumerate it. + + PRBool isDir; + IsDirectory(&isDir); + + if (!isDir) + { + rv = CopySingleFile(this, newParentDir, newName, move); + if (NS_FAILED(rv)) + return rv; + } + else + { + // create a new target destination in the new parentDir; + nsCOMPtr target; + rv = newParentDir->Clone(getter_AddRefs(target)); + + if (NS_FAILED(rv)) + return rv; + + nsCAutoString allocatedNewName; + if (newName.IsEmpty()) + { + GetNativeLeafName(allocatedNewName);// this should be the leaf name of the + } + else + { + allocatedNewName = newName; + } + + rv = target->AppendNative(allocatedNewName); + if (NS_FAILED(rv)) + return rv; + + allocatedNewName.Truncate(); + + target->Create(DIRECTORY_TYPE, 0644); // TODO, what permissions should we use + if (NS_FAILED(rv)) + return rv; + + nsDirEnumerator* dirEnum = new nsDirEnumerator(); + if (!dirEnum) + return NS_ERROR_OUT_OF_MEMORY; + + rv = dirEnum->Init(this); + + nsCOMPtr iterator = do_QueryInterface(dirEnum); + + PRBool more; + iterator->HasMoreElements(&more); + while (more) + { + nsCOMPtr item; + nsCOMPtr file; + iterator->GetNext(getter_AddRefs(item)); + file = do_QueryInterface(item); + PRBool isDir, isLink; + + file->IsDirectory(&isDir); + + if (move) + { + rv = file->MoveToNative(target, nsCString()); + } + else + { + rv = file->CopyToNative(target, nsCString()); + } + + iterator->HasMoreElements(&more); + } + // we've finished moving all the children of this directory + // in the new directory. so now delete the directory + // note, we don't need to do a recursive delete. + // MoveTo() is recursive. At this point, + // we've already moved the children of the current folder + // to the new location. nothing should be left in the folder. + if (move) + { + rv = Remove(PR_FALSE); + NS_ENSURE_SUCCESS(rv,rv); + } + } + + + // If we moved, we want to adjust this. + if (move) + { + MakeDirty(); + + nsCAutoString newParentPath; + newParentDir->GetNativePath(newParentPath); + + if (newParentPath.IsEmpty()) + return NS_ERROR_FAILURE; + + if (newName.IsEmpty()) + { + nsCAutoString aFileName; + GetNativeLeafName(aFileName); + + InitWithNativePath(newParentPath); + AppendNative(aFileName); + } + else + { + InitWithNativePath(newParentPath); + AppendNative(newName); + } + } + + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::CopyToNative(nsIFile *newParentDir, const nsACString &newName) +{ + return CopyMove(newParentDir, newName, PR_FALSE); +} + +NS_IMETHODIMP +nsLocalFile::CopyToFollowingLinksNative(nsIFile *newParentDir, const nsACString &newName) +{ + return CopyMove(newParentDir, newName, PR_FALSE); +} + +NS_IMETHODIMP +nsLocalFile::MoveToNative(nsIFile *newParentDir, const nsACString &newName) +{ + return CopyMove(newParentDir, newName, PR_TRUE); +} + +NS_IMETHODIMP +nsLocalFile::Load(PRLibrary * *_retval) +{ + PRBool isFile; + nsresult rv = IsFile(&isFile); + + if (NS_FAILED(rv)) + return rv; + + if (! isFile) + return NS_ERROR_FILE_IS_DIRECTORY; + + *_retval = PR_LoadLibrary(mWorkingPath.get()); + + if (*_retval) + return NS_OK; + + return NS_ERROR_NULL_POINTER; +} + +NS_IMETHODIMP +nsLocalFile::Remove(PRBool recursive) +{ + PRBool isDir; + + nsresult rv = IsDirectory(&isDir); + if (NS_FAILED(rv)) + return rv; + + const char *filePath = mWorkingPath.get(); + + if (isDir) + { + if (recursive) + { + nsDirEnumerator* dirEnum = new nsDirEnumerator(); + if (dirEnum == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + + rv = dirEnum->Init(this); + + nsCOMPtr iterator = do_QueryInterface(dirEnum); + + PRBool more; + iterator->HasMoreElements(&more); + while (more) + { + nsCOMPtr item; + nsCOMPtr file; + iterator->GetNext(getter_AddRefs(item)); + file = do_QueryInterface(item); + + file->Remove(recursive); + + iterator->HasMoreElements(&more); + } + } + rv = rmdir(filePath) == -1 ? NSRESULT_FOR_ERRNO() : NS_OK; + } + else + { + rv = remove(filePath) == -1 ? NSRESULT_FOR_ERRNO() : NS_OK; + } + + MakeDirty(); + return rv; +} + +NS_IMETHODIMP +nsLocalFile::GetLastModifiedTime(PRInt64 *aLastModifiedTime) +{ + NS_ENSURE_ARG(aLastModifiedTime); + + *aLastModifiedTime = 0; + + nsresult rv = Stat(); + + if (NS_FAILED(rv)) + return rv; + + // microseconds -> milliseconds + *aLastModifiedTime = mFileInfo64.modifyTime / PR_USEC_PER_MSEC; + return NS_OK; +} + + +NS_IMETHODIMP +nsLocalFile::GetLastModifiedTimeOfLink(PRInt64 *aLastModifiedTime) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + + +NS_IMETHODIMP +nsLocalFile::SetLastModifiedTime(PRInt64 aLastModifiedTime) +{ + return nsLocalFile::SetModDate(aLastModifiedTime); +} + + +NS_IMETHODIMP +nsLocalFile::SetLastModifiedTimeOfLink(PRInt64 aLastModifiedTime) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +nsresult +nsLocalFile::SetModDate(PRInt64 aLastModifiedTime) +{ + nsresult rv = Stat(); + + if (NS_FAILED(rv)) + return rv; + + const char *filePath = mWorkingPath.get(); + + PRExplodedTime pret; + FILESTATUS3 pathInfo; + + rv = DosQueryPathInfo(filePath, + FIL_STANDARD, // Level 1 info + &pathInfo, + sizeof(pathInfo)); + + if (NS_FAILED(rv)) + { + rv = ConvertOS2Error(rv); + return rv; + } + + // PR_ExplodeTime expects usecs... + PR_ExplodeTime(aLastModifiedTime * PR_USEC_PER_MSEC, PR_LocalTimeParameters, &pret); + /* fdateLastWrite.year is based off of 1980 */ + if (pret.tm_year >= 1980) + pathInfo.fdateLastWrite.year = pret.tm_year-1980; + else + pathInfo.fdateLastWrite.year = pret.tm_year; + pathInfo.fdateLastWrite.month = pret.tm_month + 1; // Convert start offset -- Win32: Jan=1; NSPR: Jan=0 +// ???? OS2TODO st.wDayOfWeek = pret.tm_wday; + pathInfo.fdateLastWrite.day = pret.tm_mday; + pathInfo.ftimeLastWrite.hours = pret.tm_hour; + pathInfo.ftimeLastWrite.minutes = pret.tm_min; + pathInfo.ftimeLastWrite.twosecs = pret.tm_sec / 2; // adjust for twosecs? +// ??? OS2TODO st.wMilliseconds = pret.tm_usec/1000; + + rv = DosSetPathInfo(filePath, + FIL_STANDARD, // Level 1 info + &pathInfo, + sizeof(pathInfo), + 0UL); + + if (NS_FAILED(rv)) + return rv; + + MakeDirty(); + return rv; +} + +NS_IMETHODIMP +nsLocalFile::GetPermissions(PRUint32 *aPermissions) +{ + nsresult rv = Stat(); + + if (NS_FAILED(rv)) + return rv; + + const char *filePath = mWorkingPath.get(); + + + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::GetPermissionsOfLink(PRUint32 *aPermissionsOfLink) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + + +NS_IMETHODIMP +nsLocalFile::SetPermissions(PRUint32 aPermissions) +{ + nsresult rv = Stat(); + + if (NS_FAILED(rv)) + return rv; + + const char *filePath = mWorkingPath.get(); + if( chmod(filePath, aPermissions) == -1 ) + return NS_ERROR_FAILURE; + + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::SetPermissionsOfLink(PRUint32 aPermissions) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + + +NS_IMETHODIMP +nsLocalFile::GetFileSize(PRInt64 *aFileSize) +{ + NS_ENSURE_ARG(aFileSize); + + *aFileSize = 0; + + nsresult rv = Stat(); + + if (NS_FAILED(rv)) + return rv; + + + *aFileSize = mFileInfo64.size; + return NS_OK; +} + + +NS_IMETHODIMP +nsLocalFile::SetFileSize(PRInt64 aFileSize) +{ + + nsresult rv = Stat(); + + if (NS_FAILED(rv)) + return rv; + + const char *filePath = mWorkingPath.get(); + + + APIRET rc; + HFILE hFile; + ULONG actionTaken; + + rc = DosOpen(filePath, + &hFile, + &actionTaken, + 0, + FILE_NORMAL, + OPEN_ACTION_FAIL_IF_NEW | OPEN_ACTION_OPEN_IF_EXISTS, + OPEN_SHARE_DENYREADWRITE | OPEN_ACCESS_READWRITE, + NULL); + + if (rc != NO_ERROR) + { + MakeDirty(); + return NS_ERROR_FAILURE; + } + + // Seek to new, desired end of file + PRInt32 hi, lo; + myLL_L2II(aFileSize, &hi, &lo ); + + rc = DosSetFileSize(hFile, lo); + if (rc == NO_ERROR) + DosClose(hFile); + else + goto error; + + MakeDirty(); + return NS_OK; + + error: + MakeDirty(); + DosClose(hFile); + return NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +nsLocalFile::GetFileSizeOfLink(PRInt64 *aFileSize) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsLocalFile::GetDiskSpaceAvailable(PRInt64 *aDiskSpaceAvailable) +{ + NS_ENSURE_ARG(aDiskSpaceAvailable); + + ULONG ulDriveNo = toupper(mWorkingPath.CharAt(0)) + 1 - 'A'; + FSALLOCATE fsAllocate; + APIRET rc = DosQueryFSInfo(ulDriveNo, + FSIL_ALLOC, + &fsAllocate, + sizeof(fsAllocate)); + + if (rc != NO_ERROR) + return NS_ERROR_FAILURE; + + *aDiskSpaceAvailable = fsAllocate.cUnitAvail; + *aDiskSpaceAvailable *= fsAllocate.cSectorUnit; + *aDiskSpaceAvailable *= fsAllocate.cbSector; + + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::GetParent(nsIFile * *aParent) +{ + NS_ENSURE_ARG_POINTER(aParent); + + nsCAutoString parentPath(mWorkingPath); + + // cannot use nsCString::RFindChar() due to 0x5c problem + PRInt32 offset = (PRInt32) (_mbsrchr((const unsigned char *) parentPath.get(), '\\') + - (const unsigned char *) parentPath.get()); + if (offset < 0) + return NS_ERROR_FILE_UNRECOGNIZED_PATH; + + parentPath.Truncate(offset); + + nsCOMPtr localFile; + nsresult rv = NS_NewNativeLocalFile(parentPath, PR_TRUE, getter_AddRefs(localFile)); + + if(NS_SUCCEEDED(rv) && localFile) + { + return CallQueryInterface(localFile, aParent); + } + return rv; +} + +NS_IMETHODIMP +nsLocalFile::Exists(PRBool *_retval) +{ + NS_ENSURE_ARG(_retval); + + MakeDirty(); + *_retval = NS_SUCCEEDED(Stat()); + + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::IsWritable(PRBool *_retval) +{ + NS_ENSURE_ARG(_retval); + *_retval = PR_FALSE; + + nsresult rv = Stat(); + + if (NS_FAILED(rv)) + return rv; + + const char *workingFilePath = mWorkingPath.get(); + + APIRET rc; + FILESTATUS3 pathInfo; + + rc = DosQueryPathInfo(workingFilePath, + FIL_STANDARD, // Level 1 info + &pathInfo, + sizeof(pathInfo)); + + if (rc != NO_ERROR) + { + rc = ConvertOS2Error(rc); + return rc; + } + + *_retval = !((pathInfo.attrFile & FILE_READONLY) != 0); + + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::IsReadable(PRBool *_retval) +{ + NS_ENSURE_ARG(_retval); + *_retval = PR_FALSE; + + nsresult rv = Stat(); + if (NS_FAILED(rv)) + return rv; + + *_retval = PR_TRUE; + return NS_OK; +} + + +NS_IMETHODIMP +nsLocalFile::IsExecutable(PRBool *_retval) +{ + NS_ENSURE_ARG(_retval); + *_retval = PR_FALSE; + + nsresult rv = Stat(); + if (NS_FAILED(rv)) + return rv; + + nsCAutoString path; + GetNativeTarget(path); + + const char* leaf = (const char*) _mbsrchr((const unsigned char*) path.get(), '\\'); + + if ( (strstr(leaf, ".bat") != nsnull) || + (strstr(leaf, ".exe") != nsnull) || + (strstr(leaf, ".cmd") != nsnull) || + (strstr(leaf, ".com") != nsnull) ) { + *_retval = PR_TRUE; + } else { + *_retval = PR_FALSE; + } + + return NS_OK; +} + + +NS_IMETHODIMP +nsLocalFile::IsDirectory(PRBool *_retval) +{ + NS_ENSURE_ARG(_retval); + *_retval = PR_FALSE; + + nsresult rv = Stat(); + + if (NS_FAILED(rv)) + return rv; + + *_retval = (mFileInfo64.type == PR_FILE_DIRECTORY); + + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::IsFile(PRBool *_retval) +{ + NS_ENSURE_ARG(_retval); + *_retval = PR_FALSE; + + nsresult rv = Stat(); + + if (NS_FAILED(rv)) + return rv; + + *_retval = (mFileInfo64.type == PR_FILE_FILE); + return rv; +} + +NS_IMETHODIMP +nsLocalFile::IsHidden(PRBool *_retval) +{ + NS_ENSURE_ARG(_retval); + *_retval = PR_FALSE; + + nsresult rv = Stat(); + + if (NS_FAILED(rv)) + return rv; + + const char *workingFilePath = mWorkingPath.get(); + + APIRET rc; + FILESTATUS3 pathInfo; + + rc = DosQueryPathInfo(workingFilePath, + FIL_STANDARD, // Level 1 info + &pathInfo, + sizeof(pathInfo)); + + if (rc != NO_ERROR) + { + rc = ConvertOS2Error(rc); + return rc; + } + + *_retval = ((pathInfo.attrFile & FILE_HIDDEN) != 0); + + return NS_OK; +} + + +NS_IMETHODIMP +nsLocalFile::IsSymlink(PRBool *_retval) +{ + NS_ENSURE_ARG_POINTER(_retval); + // No Symlinks on OS/2 + *_retval = PR_FALSE; + + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::IsSpecial(PRBool *_retval) +{ + NS_ENSURE_ARG(_retval); + *_retval = PR_FALSE; + + nsresult rv = Stat(); + + if (NS_FAILED(rv)) + return rv; + + const char *workingFilePath = mWorkingPath.get(); + + APIRET rc; + FILESTATUS3 pathInfo; + + rc = DosQueryPathInfo(workingFilePath, + FIL_STANDARD, // Level 1 info + &pathInfo, + sizeof(pathInfo)); + + if (rc != NO_ERROR) + { + rc = ConvertOS2Error(rc); + return rc; + } + + *_retval = ((pathInfo.attrFile & FILE_SYSTEM) != 0); + + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::Equals(nsIFile *inFile, PRBool *_retval) +{ + NS_ENSURE_ARG(inFile); + NS_ENSURE_ARG(_retval); + *_retval = PR_FALSE; + + nsCAutoString inFilePath; + inFile->GetNativePath(inFilePath); + + *_retval = inFilePath.Equals(mWorkingPath); + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::Contains(nsIFile *inFile, PRBool recur, PRBool *_retval) +{ + *_retval = PR_FALSE; + + nsCAutoString myFilePath; + if ( NS_FAILED(GetNativeTarget(myFilePath))) + GetNativePath(myFilePath); + + PRInt32 myFilePathLen = myFilePath.Length(); + + nsCAutoString inFilePath; + if ( NS_FAILED(inFile->GetNativeTarget(inFilePath))) + inFile->GetNativePath(inFilePath); + + if ( strnicmp( myFilePath.get(), inFilePath.get(), myFilePathLen) == 0) + { + // now make sure that the |inFile|'s path has a trailing + // separator. + + if (inFilePath[myFilePathLen] == '\\') + { + *_retval = PR_TRUE; + } + + } + + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::GetNativeTarget(nsACString &_retval) +{ + _retval = mWorkingPath; + return NS_OK; +} + +/* attribute PRBool followLinks; */ +NS_IMETHODIMP +nsLocalFile::GetFollowLinks(PRBool *aFollowLinks) +{ + *aFollowLinks = PR_TRUE; + return NS_OK; +} +NS_IMETHODIMP +nsLocalFile::SetFollowLinks(PRBool aFollowLinks) +{ + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::GetDirectoryEntries(nsISimpleEnumerator * *entries) +{ + nsresult rv; + + *entries = nsnull; + + PRBool isDir; + rv = IsDirectory(&isDir); + if (NS_FAILED(rv)) + return rv; + if (!isDir) + return NS_ERROR_FILE_NOT_DIRECTORY; + + nsDirEnumerator* dirEnum = new nsDirEnumerator(); + if (dirEnum == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + NS_ADDREF(dirEnum); + rv = dirEnum->Init(this); + if (NS_FAILED(rv)) + { + NS_RELEASE(dirEnum); + return rv; + } + + *entries = dirEnum; + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::GetPersistentDescriptor(nsACString &aPersistentDescriptor) +{ + return GetNativePath(aPersistentDescriptor); +} + +NS_IMETHODIMP +nsLocalFile::SetPersistentDescriptor(const nsACString &aPersistentDescriptor) +{ + return InitWithNativePath(aPersistentDescriptor); +} + +#ifndef OPEN_DEFAULT +#define OPEN_DEFAULT 0 +#define OPEN_CONTENTS 1 +#endif + + +NS_IMETHODIMP +nsLocalFile::Reveal() +{ + PRBool isDirectory = PR_FALSE; + nsCAutoString path; + + IsDirectory(&isDirectory); + if (isDirectory) + { + GetNativePath(path); + } + else + { + nsCOMPtr parent; + GetParent(getter_AddRefs(parent)); + if (parent) + parent->GetNativePath(path); + } + + HOBJECT hobject = WinQueryObject(path.get()); + WinSetFocus(HWND_DESKTOP, HWND_DESKTOP); + WinOpenObject( hobject, OPEN_CONTENTS, TRUE); + + // we don't care if it succeeded or failed. + return NS_OK; +} + + +NS_IMETHODIMP +nsLocalFile::Launch() +{ + HOBJECT hobject = WinQueryObject(mWorkingPath.get()); + WinSetFocus(HWND_DESKTOP, HWND_DESKTOP); + WinOpenObject( hobject, OPEN_DEFAULT, TRUE); + + // we don't care if it succeeded or failed. + return NS_OK; +} + +nsresult +NS_NewNativeLocalFile(const nsACString &path, PRBool followLinks, nsILocalFile* *result) +{ + nsLocalFile* file = new nsLocalFile(); + if (file == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + NS_ADDREF(file); + + if (!path.IsEmpty()) { + nsresult rv = file->InitWithNativePath(path); + if (NS_FAILED(rv)) { + NS_RELEASE(file); + return rv; + } + } + + *result = file; + return NS_OK; +} + +// Locates the first occurrence of charToSearchFor in the stringToSearch +static unsigned char* PR_CALLBACK +_mbschr( const unsigned char* stringToSearch, int charToSearchFor) +{ + const unsigned char* p = stringToSearch; + do { + if (*p == charToSearchFor) + break; + p = (const unsigned char*)WinNextChar(0,0,0,(char*)p); + } while (*p); /* enddo */ + // Result is p or NULL + return *p ? (unsigned char*)p : NULL; +} + +// Locates last occurence of charToSearchFor in the stringToSearch +extern unsigned char* +_mbsrchr( const unsigned char* stringToSearch, int charToSearchFor) +{ + int length = strlen((const char*)stringToSearch); + const unsigned char* p = stringToSearch+length; + do { + if (*p == charToSearchFor) + break; + p = (const unsigned char*)WinPrevChar(0,0,0,(char*)stringToSearch,(char*)p); + } while (p > stringToSearch); /* enddo */ + // Result is p or NULL + return (*p == charToSearchFor) ? (unsigned char*)p : NULL; +} + +// Implement equivalent of Win32 CreateDirectoryA +static nsresult PR_CALLBACK +CreateDirectoryA( PSZ path, PEAOP2 ppEABuf) +{ + APIRET rc; + nsresult rv; + FILESTATUS3 pathInfo; + + rc = DosCreateDir( path, ppEABuf ); + if (rc != NO_ERROR) { + rv = ConvertOS2Error(rc); + + // Check if directory already exists and if so, reflect that in the return value + rc = DosQueryPathInfo(path, + FIL_STANDARD, // Level 1 info + &pathInfo, + sizeof(pathInfo)); + if (rc == NO_ERROR) + rv = ERROR_FILE_EXISTS; + } + else + rv = rc; + + return rv; +} + +static int isleadbyte(int c) +{ + static BOOL bDBCSFilled=FALSE; + static BYTE DBCSInfo[12] = { 0 }; /* According to the Control Program Guide&Ref, + 12 bytes is sufficient */ + BYTE *curr; + BOOL retval = FALSE; + + if( !bDBCSFilled ) { + COUNTRYCODE ctrycodeInfo = { 0 }; + APIRET rc = NO_ERROR; + ctrycodeInfo.country = 0; /* Current Country */ + ctrycodeInfo.codepage = 0; /* Current Codepage */ + + rc = DosQueryDBCSEnv( sizeof( DBCSInfo ), + &ctrycodeInfo, + DBCSInfo ); + if( rc != NO_ERROR ) { + /* we had an error, do something? */ + return FALSE; + } + bDBCSFilled=TRUE; + } + + curr = DBCSInfo; + /* DBCSInfo returned by DosQueryDBCSEnv is terminated with two '0' bytes in a row */ + while(( *curr != 0 ) && ( *(curr+1) != 0)) { + if(( c >= *curr ) && ( c <= *(curr+1) )) { + retval=TRUE; + break; + } + curr+=2; + } + + return retval; +} + +NS_IMETHODIMP +nsLocalFile::InitWithPath(const nsAString &filePath) +{ + if (filePath.IsEmpty()) + return InitWithNativePath(nsCString()); + + nsCAutoString tmp; + nsresult rv = NS_CopyUnicodeToNative(filePath, tmp); + + if (NS_SUCCEEDED(rv)) + return InitWithNativePath(tmp); + + return rv; +} + +NS_IMETHODIMP +nsLocalFile::Append(const nsAString &node) +{ + if (node.IsEmpty()) + return NS_OK; + + nsCAutoString tmp; + nsresult rv = NS_CopyUnicodeToNative(node, tmp); + + if (NS_SUCCEEDED(rv)) + return AppendNative(tmp); + + return rv; +} + +NS_IMETHODIMP +nsLocalFile::AppendRelativePath(const nsAString &node) +{ + if (node.IsEmpty()) + return NS_OK; + + nsCAutoString tmp; + nsresult rv = NS_CopyUnicodeToNative(node, tmp); + + if (NS_SUCCEEDED(rv)) + return AppendRelativeNativePath(tmp); + + return rv; +} + +NS_IMETHODIMP +nsLocalFile::GetLeafName(nsAString &aLeafName) +{ + nsCAutoString tmp; + nsresult rv = GetNativeLeafName(tmp); + + if (NS_SUCCEEDED(rv)) + rv = NS_CopyNativeToUnicode(tmp, aLeafName); + + return rv; +} + +NS_IMETHODIMP +nsLocalFile::SetLeafName(const nsAString &aLeafName) +{ + if (aLeafName.IsEmpty()) + return SetNativeLeafName(nsCString()); + + nsCAutoString tmp; + nsresult rv = NS_CopyUnicodeToNative(aLeafName, tmp); + + if (NS_SUCCEEDED(rv)) + return SetNativeLeafName(tmp); + + return rv; +} + +NS_IMETHODIMP +nsLocalFile::GetPath(nsAString &_retval) +{ + return NS_CopyNativeToUnicode(mWorkingPath, _retval); +} + +NS_IMETHODIMP +nsLocalFile::CopyTo(nsIFile *newParentDir, const nsAString &newName) +{ + if (newName.IsEmpty()) + return CopyToNative(newParentDir, nsCString()); + + nsCAutoString tmp; + nsresult rv = NS_CopyUnicodeToNative(newName, tmp); + + if (NS_SUCCEEDED(rv)) + return CopyToNative(newParentDir, tmp); + + return rv; +} + +NS_IMETHODIMP +nsLocalFile::CopyToFollowingLinks(nsIFile *newParentDir, const nsAString &newName) +{ + if (newName.IsEmpty()) + return CopyToFollowingLinksNative(newParentDir, nsCString()); + + nsCAutoString tmp; + nsresult rv = NS_CopyUnicodeToNative(newName, tmp); + + if (NS_SUCCEEDED(rv)) + return CopyToFollowingLinksNative(newParentDir, tmp); + + return rv; +} + +NS_IMETHODIMP +nsLocalFile::MoveTo(nsIFile *newParentDir, const nsAString &newName) +{ + if (newName.IsEmpty()) + return MoveToNative(newParentDir, nsCString()); + + nsCAutoString tmp; + nsresult rv = NS_CopyUnicodeToNative(newName, tmp); + + if (NS_SUCCEEDED(rv)) + return MoveToNative(newParentDir, tmp); + + return rv; +} + +NS_IMETHODIMP +nsLocalFile::GetTarget(nsAString &_retval) +{ + nsCAutoString tmp; + nsresult rv = GetNativeTarget(tmp); + + if (NS_SUCCEEDED(rv)) + rv = NS_CopyNativeToUnicode(tmp, _retval); + + return rv; +} + +nsresult +NS_NewLocalFile(const nsAString &path, PRBool followLinks, nsILocalFile* *result) +{ + nsCAutoString buf; + nsresult rv = NS_CopyUnicodeToNative(path, buf); + if (NS_FAILED(rv)) { + *result = nsnull; + return rv; + } + return NS_NewNativeLocalFile(buf, followLinks, result); +} + +//---------------------------------------------------------------------------- +// global init/shutdown +//---------------------------------------------------------------------------- + +void +nsLocalFile::GlobalInit() +{ +} + +void +nsLocalFile::GlobalShutdown() +{ +} diff --git a/src/libs/xpcom18a4/xpcom/io/nsLocalFileOS2.h b/src/libs/xpcom18a4/xpcom/io/nsLocalFileOS2.h new file mode 100644 index 00000000..72f3127a --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsLocalFileOS2.h @@ -0,0 +1,113 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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 Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** + * + * This Original Code has been modified by IBM Corporation. Modifications made by IBM + * described herein are Copyright (c) International Business Machines Corporation, 2000. + * Modifications to Mozilla code or documentation identified per MPL Section 3.3 + * + * Date Modified by Description of modification + * 05/26/2000 IBM Corp. Make more like Windows. + */ + +#ifndef _nsLocalFileOS2_H_ +#define _nsLocalFileOS2_H_ + +#include "nscore.h" +#include "nsError.h" +#include "nsString.h" +#include "nsCRT.h" +#include "nsIFile.h" +#include "nsIFactory.h" + +#define INCL_DOSFILEMGR +#define INCL_DOSERRORS +#define INCL_DOSPROCESS +#define INCL_DOSSESMGR +#define INCL_DOSMODULEMGR +#define INCL_DOSNLS +#define INCL_DOSMISC +#define INCL_WINCOUNTRY +#define INCL_WINWORKPLACE + +#include + +class NS_COM nsLocalFile : public nsILocalFile +{ +public: + NS_DEFINE_STATIC_CID_ACCESSOR(NS_LOCAL_FILE_CID) + + nsLocalFile(); + + static NS_METHOD nsLocalFileConstructor(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr); + + // nsISupports interface + NS_DECL_ISUPPORTS + + // nsIFile interface + NS_DECL_NSIFILE + + // nsILocalFile interface + NS_DECL_NSILOCALFILE + +public: + static void GlobalInit(); + static void GlobalShutdown(); + +private: + ~nsLocalFile() {} + + nsLocalFile(const nsLocalFile& other); + + // this is the flag which indicates if I can used cached information about the file + PRPackedBool mDirty; + + // this string will alway be in native format! + nsCString mWorkingPath; + + PRFileInfo64 mFileInfo64; + + void MakeDirty(); + nsresult Stat(); + + nsresult CopyMove(nsIFile *newParentDir, const nsACString &newName, PRBool move); + nsresult CopySingleFile(nsIFile *source, nsIFile* dest, const nsACString &newName, PRBool move); + + nsresult SetModDate(PRInt64 aLastModifiedTime); +}; + +#endif diff --git a/src/libs/xpcom18a4/xpcom/io/nsLocalFileOSX.cpp b/src/libs/xpcom18a4/xpcom/io/nsLocalFileOSX.cpp new file mode 100644 index 00000000..dfc431d8 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsLocalFileOSX.cpp @@ -0,0 +1,2542 @@ +/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2001, 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Conrad Carlen + * Jungshik Shin + * Asaf Romano + * Mark Mentovai + * + * 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 "nsLocalFile.h" +#include "nsDirectoryServiceDefs.h" + +#include "nsString.h" +#include "nsReadableUtils.h" +#include "nsIDirectoryEnumerator.h" +#include "nsISimpleEnumerator.h" +#include "nsITimelineService.h" +#include "nsVoidArray.h" + +#include "plbase64.h" +#include "prmem.h" +#include "nsCRT.h" +#include "nsHashKeys.h" + +#include "MoreFilesX.h" +#include "FSCopyObject.h" +#include "nsAutoBuffer.h" +#include "nsTraceRefcntImpl.h" + +// Mac Includes +#include + +// Unix Includes +#include +#include +#include + +#if !defined(MAC_OS_X_VERSION_10_4) || MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_4 +#define GetAliasSizeFromRecord(aliasRecord) aliasRecord.aliasSize +#else +#define GetAliasSizeFromRecord(aliasRecord) GetAliasSizeFromPtr(&aliasRecord) +#endif + +#define CHECK_mBaseRef() \ + PR_BEGIN_MACRO \ + if (!mBaseRef) \ + return NS_ERROR_NOT_INITIALIZED; \ + PR_END_MACRO + +//***************************************************************************** +// Static Function Prototypes +//***************************************************************************** + +static nsresult MacErrorMapper(OSErr inErr); +static OSErr FindRunningAppBySignature(OSType aAppSig, ProcessSerialNumber& outPsn); +static void CopyUTF8toUTF16NFC(const nsACString& aSrc, nsAString& aResult); + +//***************************************************************************** +// Local Helper Classes +//***************************************************************************** + +#pragma mark - +#pragma mark [FSRef operator==] + +bool operator==(const FSRef& lhs, const FSRef& rhs) +{ + return (::FSCompareFSRefs(&lhs, &rhs) == noErr); +} + +#pragma mark - +#pragma mark [StFollowLinksState] + +class StFollowLinksState +{ + public: + StFollowLinksState(nsLocalFile& aFile) : + mFile(aFile) + { + mFile.GetFollowLinks(&mSavedState); + } + + StFollowLinksState(nsLocalFile& aFile, PRBool followLinksState) : + mFile(aFile) + { + mFile.GetFollowLinks(&mSavedState); + mFile.SetFollowLinks(followLinksState); + } + + ~StFollowLinksState() + { + mFile.SetFollowLinks(mSavedState); + } + + private: + nsLocalFile& mFile; + PRBool mSavedState; +}; + +#pragma mark - +#pragma mark [nsDirEnumerator] + +class nsDirEnumerator : public nsISimpleEnumerator, + public nsIDirectoryEnumerator +{ + public: + + NS_DECL_ISUPPORTS + + nsDirEnumerator() : + mIterator(nsnull), + mFSRefsArray(nsnull), + mArrayCnt(0), mArrayIndex(0) + { + } + + nsresult Init(nsILocalFileMac* parent) + { + NS_ENSURE_ARG(parent); + + OSErr err; + nsresult rv; + FSRef parentRef; + + rv = parent->GetFSRef(&parentRef); + if (NS_FAILED(rv)) + return rv; + + mFSRefsArray = (FSRef *)nsMemory::Alloc(sizeof(FSRef) + * kRequestCountPerIteration); + if (!mFSRefsArray) + return NS_ERROR_OUT_OF_MEMORY; + + err = ::FSOpenIterator(&parentRef, kFSIterateFlat, &mIterator); + if (err != noErr) + return MacErrorMapper(err); + + return NS_OK; + } + + NS_IMETHOD HasMoreElements(PRBool *result) + { + if (mNext == nsnull) { + if (mArrayIndex >= mArrayCnt) { + ItemCount actualCnt; + OSErr err = ::FSGetCatalogInfoBulk(mIterator, + kRequestCountPerIteration, + &actualCnt, + nsnull, + kFSCatInfoNone, + nsnull, + mFSRefsArray, + nsnull, + nsnull); + + if (err == noErr || err == errFSNoMoreItems) { + mArrayCnt = actualCnt; + mArrayIndex = 0; + } + } + if (mArrayIndex < mArrayCnt) { + nsLocalFile *newFile = new nsLocalFile; + if (!newFile) + return NS_ERROR_OUT_OF_MEMORY; + FSRef fsRef = mFSRefsArray[mArrayIndex]; + if (NS_FAILED(newFile->InitWithFSRef(&fsRef))) + return NS_ERROR_FAILURE; + mArrayIndex++; + mNext = newFile; + } + } + *result = mNext != nsnull; + if (!*result) + Close(); + return NS_OK; + } + + NS_IMETHOD GetNext(nsISupports **result) + { + NS_ENSURE_ARG_POINTER(result); + *result = nsnull; + + nsresult rv; + PRBool hasMore; + rv = HasMoreElements(&hasMore); + if (NS_FAILED(rv)) return rv; + + *result = mNext; // might return nsnull + NS_IF_ADDREF(*result); + + mNext = nsnull; + return NS_OK; + } + + NS_IMETHOD GetNextFile(nsIFile **result) + { + *result = nsnull; + PRBool hasMore = PR_FALSE; + nsresult rv = HasMoreElements(&hasMore); + if (NS_FAILED(rv) || !hasMore) + return rv; + *result = mNext; + NS_IF_ADDREF(*result); + mNext = nsnull; + return NS_OK; + } + + NS_IMETHOD Close() + { + if (mIterator) { + ::FSCloseIterator(mIterator); + mIterator = nsnull; + } + if (mFSRefsArray) { + nsMemory::Free(mFSRefsArray); + mFSRefsArray = nsnull; + } + return NS_OK; + } + + private: + ~nsDirEnumerator() + { + Close(); + } + + protected: + // According to Apple doc, request the number of objects + // per call that will fit in 4 VM pages. + enum { + kRequestCountPerIteration = ((4096 * 4) / sizeof(FSRef)) + }; + + nsCOMPtr mNext; + + FSIterator mIterator; + FSRef *mFSRefsArray; + PRInt32 mArrayCnt, mArrayIndex; +}; + +NS_IMPL_ISUPPORTS2(nsDirEnumerator, nsISimpleEnumerator, nsIDirectoryEnumerator) + +#pragma mark - +#pragma mark [StAEDesc] + +class StAEDesc: public AEDesc +{ +public: + StAEDesc() + { + descriptorType = typeNull; + dataHandle = nil; + } + + ~StAEDesc() + { + ::AEDisposeDesc(this); + } +}; + +#define FILENAME_BUFFER_SIZE 512 + +//***************************************************************************** +// nsLocalFile +//***************************************************************************** + +const char nsLocalFile::kPathSepChar = '/'; +const PRUnichar nsLocalFile::kPathSepUnichar = '/'; + +// The HFS+ epoch is Jan. 1, 1904 GMT - differs from HFS in which times were local +// The NSPR epoch is Jan. 1, 1970 GMT +// 2082844800 is the difference in seconds between those dates +const PRInt64 nsLocalFile::kJanuaryFirst1970Seconds = 2082844800LL; + +#pragma mark - +#pragma mark [CTORs/DTOR] + +nsLocalFile::nsLocalFile() : + mBaseRef(nsnull), + mTargetRef(nsnull), + mCachedFSRefValid(PR_FALSE), + mFollowLinks(PR_TRUE), + mFollowLinksDirty(PR_TRUE) +{ +} + +nsLocalFile::nsLocalFile(const nsLocalFile& src) : + mBaseRef(src.mBaseRef), + mTargetRef(src.mTargetRef), + mCachedFSRef(src.mCachedFSRef), + mCachedFSRefValid(src.mCachedFSRefValid), + mFollowLinks(src.mFollowLinks), + mFollowLinksDirty(src.mFollowLinksDirty) +{ + // A CFURLRef is immutable so no need to copy, just retain. + if (mBaseRef) + ::CFRetain(mBaseRef); + if (mTargetRef) + ::CFRetain(mTargetRef); +} + +nsLocalFile::~nsLocalFile() +{ + if (mBaseRef) + ::CFRelease(mBaseRef); + if (mTargetRef) + ::CFRelease(mTargetRef); +} + + +//***************************************************************************** +// nsLocalFile::nsISupports +//***************************************************************************** +#pragma mark - +#pragma mark [nsISupports] + +NS_IMPL_THREADSAFE_ISUPPORTS4(nsLocalFile, + nsILocalFileMac, + nsILocalFile, + nsIFile, + nsIHashable) + +NS_METHOD nsLocalFile::nsLocalFileConstructor(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr) +{ + NS_ENSURE_ARG_POINTER(aInstancePtr); + NS_ENSURE_NO_AGGREGATION(outer); + + nsLocalFile* inst = new nsLocalFile(); + if (inst == NULL) + return NS_ERROR_OUT_OF_MEMORY; + + nsresult rv = inst->QueryInterface(aIID, aInstancePtr); + if (NS_FAILED(rv)) + { + delete inst; + return rv; + } + return NS_OK; +} + + +//***************************************************************************** +// nsLocalFile::nsIFile +//***************************************************************************** +#pragma mark - +#pragma mark [nsIFile] + +/* void append (in AString node); */ +NS_IMETHODIMP nsLocalFile::Append(const nsAString& aNode) +{ + return AppendNative(NS_ConvertUTF16toUTF8(aNode)); +} + +/* [noscript] void appendNative (in ACString node); */ +NS_IMETHODIMP nsLocalFile::AppendNative(const nsACString& aNode) +{ + // Check we are correctly initialized. + CHECK_mBaseRef(); + + nsACString::const_iterator start, end; + aNode.BeginReading(start); + aNode.EndReading(end); + if (FindCharInReadable(kPathSepChar, start, end)) + return NS_ERROR_FILE_UNRECOGNIZED_PATH; + + CFStringRef nodeStrRef = ::CFStringCreateWithCString(kCFAllocatorDefault, + PromiseFlatCString(aNode).get(), + kCFStringEncodingUTF8); + if (nodeStrRef) { + CFURLRef newRef = ::CFURLCreateCopyAppendingPathComponent(kCFAllocatorDefault, + mBaseRef, nodeStrRef, PR_FALSE); + ::CFRelease(nodeStrRef); + if (newRef) { + SetBaseRef(newRef); + ::CFRelease(newRef); + return NS_OK; + } + } + return NS_ERROR_FAILURE; +} + +/* void normalize (); */ +NS_IMETHODIMP nsLocalFile::Normalize() +{ + // Check we are correctly initialized. + CHECK_mBaseRef(); + + // CFURL doesn't doesn't seem to resolve paths containing relative + // components, so we'll nick the stdlib code from nsLocalFileUnix + UInt8 path[PATH_MAX] = ""; + Boolean success; + success = ::CFURLGetFileSystemRepresentation(mBaseRef, true, path, PATH_MAX); + if (!success) + return NS_ERROR_FAILURE; + + char resolved_path[PATH_MAX] = ""; + char *resolved_path_ptr = nsnull; + resolved_path_ptr = realpath((char*)path, resolved_path); + + // if there is an error, the return is null. + if (!resolved_path_ptr) + return NSRESULT_FOR_ERRNO(); + + // Need to know whether we're a directory to create a new CFURLRef + PRBool isDirectory; + nsresult rv = IsDirectory(&isDirectory); + NS_ENSURE_SUCCESS(rv, rv); + + rv = NS_ERROR_FAILURE; + CFStringRef pathStrRef = + ::CFStringCreateWithCString(kCFAllocatorDefault, + resolved_path, + kCFStringEncodingUTF8); + if (pathStrRef) { + CFURLRef newURLRef = + ::CFURLCreateWithFileSystemPath(kCFAllocatorDefault, pathStrRef, + kCFURLPOSIXPathStyle, isDirectory); + if (newURLRef) { + SetBaseRef(newURLRef); + ::CFRelease(newURLRef); + rv = NS_OK; + } + ::CFRelease(pathStrRef); + } + + return rv; +} + +/* void create (in unsigned long type, in unsigned long permissions); */ +NS_IMETHODIMP nsLocalFile::Create(PRUint32 type, PRUint32 permissions) +{ + if (type != NORMAL_FILE_TYPE && type != DIRECTORY_TYPE) + return NS_ERROR_FILE_UNKNOWN_TYPE; + + // Check we are correctly initialized. + CHECK_mBaseRef(); + + nsStringArray nonExtantNodes; + CFURLRef pathURLRef = mBaseRef; + FSRef pathFSRef; + CFStringRef leafStrRef = nsnull; + nsAutoBuffer buffer; + Boolean success; + + // Work backwards through the path to find the last node which + // exists. Place the nodes which don't exist in an array and we'll + // create those below. + while ((success = ::CFURLGetFSRef(pathURLRef, &pathFSRef)) == false) { + leafStrRef = ::CFURLCopyLastPathComponent(pathURLRef); + if (!leafStrRef) + break; + CFIndex leafLen = ::CFStringGetLength(leafStrRef); + if (!buffer.EnsureElemCapacity(leafLen + 1)) + break; + ::CFStringGetCharacters(leafStrRef, CFRangeMake(0, leafLen), buffer.get()); + buffer.get()[leafLen] = '\0'; + nonExtantNodes.AppendString(nsString(nsDependentString(buffer.get()))); + ::CFRelease(leafStrRef); + leafStrRef = nsnull; + + // Get the parent of the leaf for the next go round + CFURLRef parent = ::CFURLCreateCopyDeletingLastPathComponent(NULL, pathURLRef); + if (!parent) + break; + if (pathURLRef != mBaseRef) + ::CFRelease(pathURLRef); + pathURLRef = parent; + } + if (pathURLRef != mBaseRef) + ::CFRelease(pathURLRef); + if (leafStrRef != nsnull) + ::CFRelease(leafStrRef); + if (!success) + return NS_ERROR_FAILURE; + PRInt32 nodesToCreate = nonExtantNodes.Count(); + if (nodesToCreate == 0) + return NS_ERROR_FILE_ALREADY_EXISTS; + + OSErr err; + nsAutoString nextNodeName; + for (PRInt32 i = nodesToCreate - 1; i > 0; i--) { + nonExtantNodes.StringAt(i, nextNodeName); + err = ::FSCreateDirectoryUnicode(&pathFSRef, + nextNodeName.Length(), + (const UniChar *)nextNodeName.get(), + kFSCatInfoNone, + nsnull, &pathFSRef, nsnull, nsnull); + if (err != noErr) + return MacErrorMapper(err); + } + nonExtantNodes.StringAt(0, nextNodeName); + if (type == NORMAL_FILE_TYPE) { + err = ::FSCreateFileUnicode(&pathFSRef, + nextNodeName.Length(), + (const UniChar *)nextNodeName.get(), + kFSCatInfoNone, + nsnull, nsnull, nsnull); + } + else { + err = ::FSCreateDirectoryUnicode(&pathFSRef, + nextNodeName.Length(), + (const UniChar *)nextNodeName.get(), + kFSCatInfoNone, + nsnull, nsnull, nsnull, nsnull); + } + + return MacErrorMapper(err); +} + +/* attribute AString leafName; */ +NS_IMETHODIMP nsLocalFile::GetLeafName(nsAString& aLeafName) +{ + nsCAutoString nativeString; + nsresult rv = GetNativeLeafName(nativeString); + if (NS_FAILED(rv)) + return rv; + CopyUTF8toUTF16NFC(nativeString, aLeafName); + return NS_OK; +} + +NS_IMETHODIMP nsLocalFile::SetLeafName(const nsAString& aLeafName) +{ + return SetNativeLeafName(NS_ConvertUTF16toUTF8(aLeafName)); +} + +/* [noscript] attribute ACString nativeLeafName; */ +NS_IMETHODIMP nsLocalFile::GetNativeLeafName(nsACString& aNativeLeafName) +{ + // Check we are correctly initialized. + CHECK_mBaseRef(); + + nsresult rv = NS_ERROR_FAILURE; + CFStringRef leafStrRef = ::CFURLCopyLastPathComponent(mBaseRef); + if (leafStrRef) { + rv = CFStringReftoUTF8(leafStrRef, aNativeLeafName); + ::CFRelease(leafStrRef); + } + return rv; +} + +NS_IMETHODIMP nsLocalFile::SetNativeLeafName(const nsACString& aNativeLeafName) +{ + // Check we are correctly initialized. + CHECK_mBaseRef(); + + nsresult rv = NS_ERROR_FAILURE; + CFURLRef parentURLRef = ::CFURLCreateCopyDeletingLastPathComponent(kCFAllocatorDefault, mBaseRef); + if (parentURLRef) { + CFStringRef nodeStrRef = ::CFStringCreateWithCString(kCFAllocatorDefault, + PromiseFlatCString(aNativeLeafName).get(), + kCFStringEncodingUTF8); + + if (nodeStrRef) { + CFURLRef newURLRef = ::CFURLCreateCopyAppendingPathComponent(kCFAllocatorDefault, + parentURLRef, nodeStrRef, PR_FALSE); + if (newURLRef) { + SetBaseRef(newURLRef); + ::CFRelease(newURLRef); + rv = NS_OK; + } + ::CFRelease(nodeStrRef); + } + ::CFRelease(parentURLRef); + } + return rv; +} + +/* void copyTo (in nsIFile newParentDir, in AString newName); */ +NS_IMETHODIMP nsLocalFile::CopyTo(nsIFile *newParentDir, const nsAString& newName) +{ + return CopyInternal(newParentDir, newName, PR_FALSE); +} + +/* [noscrpit] void CopyToNative (in nsIFile newParentDir, in ACString newName); */ +NS_IMETHODIMP nsLocalFile::CopyToNative(nsIFile *newParentDir, const nsACString& newName) +{ + return CopyInternal(newParentDir, NS_ConvertUTF8toUTF16(newName), PR_FALSE); +} + +/* void copyToFollowingLinks (in nsIFile newParentDir, in AString newName); */ +NS_IMETHODIMP nsLocalFile::CopyToFollowingLinks(nsIFile *newParentDir, const nsAString& newName) +{ + return CopyInternal(newParentDir, newName, PR_TRUE); +} + +/* [noscript] void copyToFollowingLinksNative (in nsIFile newParentDir, in ACString newName); */ +NS_IMETHODIMP nsLocalFile::CopyToFollowingLinksNative(nsIFile *newParentDir, const nsACString& newName) +{ + return CopyInternal(newParentDir, NS_ConvertUTF8toUTF16(newName), PR_TRUE); +} + +/* void moveTo (in nsIFile newParentDir, in AString newName); */ +NS_IMETHODIMP nsLocalFile::MoveTo(nsIFile *newParentDir, const nsAString& newName) +{ + return MoveToNative(newParentDir, NS_ConvertUTF16toUTF8(newName)); +} + +/* [noscript] void moveToNative (in nsIFile newParentDir, in ACString newName); */ +NS_IMETHODIMP nsLocalFile::MoveToNative(nsIFile *newParentDir, const nsACString& newName) +{ + // Check we are correctly initialized. + CHECK_mBaseRef(); + + StFollowLinksState followLinks(*this, PR_FALSE); + + PRBool isDirectory; + nsresult rv = IsDirectory(&isDirectory); + if (NS_FAILED(rv)) + return rv; + + // Get the source path. + nsCAutoString srcPath; + rv = GetNativePath(srcPath); + if (NS_FAILED(rv)) + return rv; + + // Build the destination path. + nsCOMPtr parentDir = newParentDir; + if (!parentDir) { + if (newName.IsEmpty()) + return NS_ERROR_INVALID_ARG; + rv = GetParent(getter_AddRefs(parentDir)); + if (NS_FAILED(rv)) + return rv; + } + else { + PRBool exists; + rv = parentDir->Exists(&exists); + if (NS_FAILED(rv)) + return rv; + if (!exists) { + rv = parentDir->Create(nsIFile::DIRECTORY_TYPE, 0777); + if (NS_FAILED(rv)) + return rv; + } + } + + nsCAutoString destPath; + rv = parentDir->GetNativePath(destPath); + if (NS_FAILED(rv)) + return rv; + + if (!newName.IsEmpty()) + destPath.Append(NS_LITERAL_CSTRING("/") + newName); + else { + nsCAutoString leafName; + rv = GetNativeLeafName(leafName); + if (NS_FAILED(rv)) + return rv; + destPath.Append(NS_LITERAL_CSTRING("/") + leafName); + } + + // Perform the move. + if (rename(srcPath.get(), destPath.get()) != 0) { + if (errno == EXDEV) { + // Can't move across volume (device) boundaries. Copy and remove. + rv = CopyToNative(parentDir, newName); + if (NS_SUCCEEDED(rv)) { + // Permit removal failure. + Remove(PR_TRUE); + } + } + else + rv = NSRESULT_FOR_ERRNO(); + + if (NS_FAILED(rv)) + return rv; + } + + // Update |this| to refer to the moved file. + CFURLRef newBaseRef = + ::CFURLCreateFromFileSystemRepresentation(NULL, (UInt8*)destPath.get(), + destPath.Length(), isDirectory); + if (!newBaseRef) + return NS_ERROR_FAILURE; + SetBaseRef(newBaseRef); + ::CFRelease(newBaseRef); + + return rv; +} + +/* void remove (in boolean recursive); */ +NS_IMETHODIMP nsLocalFile::Remove(PRBool recursive) +{ + // Check we are correctly initialized. + CHECK_mBaseRef(); + + // XXX If we're an alias, never remove target + StFollowLinksState followLinks(*this, PR_FALSE); + + PRBool isDirectory; + nsresult rv = IsDirectory(&isDirectory); + if (NS_FAILED(rv)) + return rv; + + if (recursive && isDirectory) { + FSRef fsRef; + rv = GetFSRefInternal(fsRef); + if (NS_FAILED(rv)) + return rv; + + // Call MoreFilesX to do a recursive removal. + OSStatus err = ::FSDeleteContainer(&fsRef); + rv = MacErrorMapper(err); + } + else { + nsCAutoString path; + rv = GetNativePath(path); + if (NS_FAILED(rv)) + return rv; + + const char* pathPtr = path.get(); + int status; + if (isDirectory) + status = rmdir(pathPtr); + else + status = unlink(pathPtr); + + if (status != 0) + rv = NSRESULT_FOR_ERRNO(); + } + + mCachedFSRefValid = PR_FALSE; + return rv; +} + +/* attribute unsigned long permissions; */ +NS_IMETHODIMP nsLocalFile::GetPermissions(PRUint32 *aPermissions) +{ + NS_ENSURE_ARG_POINTER(aPermissions); + + FSRef fsRef; + nsresult rv = GetFSRefInternal(fsRef); + if (NS_FAILED(rv)) + return rv; + + FSCatalogInfo catalogInfo; + OSErr err = ::FSGetCatalogInfo(&fsRef, kFSCatInfoPermissions, &catalogInfo, + nsnull, nsnull, nsnull); + if (err != noErr) + return MacErrorMapper(err); + FSPermissionInfo *permPtr = (FSPermissionInfo*)catalogInfo.permissions; + *aPermissions = permPtr->mode; + return NS_OK; +} + +NS_IMETHODIMP nsLocalFile::SetPermissions(PRUint32 aPermissions) +{ + FSRef fsRef; + nsresult rv = GetFSRefInternal(fsRef); + if (NS_FAILED(rv)) + return rv; + + FSCatalogInfo catalogInfo; + OSErr err = ::FSGetCatalogInfo(&fsRef, kFSCatInfoPermissions, &catalogInfo, + nsnull, nsnull, nsnull); + if (err != noErr) + return MacErrorMapper(err); + FSPermissionInfo *permPtr = (FSPermissionInfo*)catalogInfo.permissions; + permPtr->mode = (UInt16)aPermissions; + err = ::FSSetCatalogInfo(&fsRef, kFSCatInfoPermissions, &catalogInfo); + return MacErrorMapper(err); +} + +/* attribute unsigned long permissionsOfLink; */ +NS_IMETHODIMP nsLocalFile::GetPermissionsOfLink(PRUint32 *aPermissionsOfLink) +{ + NS_ERROR("NS_ERROR_NOT_IMPLEMENTED"); + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP nsLocalFile::SetPermissionsOfLink(PRUint32 aPermissionsOfLink) +{ + NS_ERROR("NS_ERROR_NOT_IMPLEMENTED"); + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* attribute PRInt64 lastModifiedTime; */ +NS_IMETHODIMP nsLocalFile::GetLastModifiedTime(PRInt64 *aLastModifiedTime) +{ + // Check we are correctly initialized. + CHECK_mBaseRef(); + + NS_ENSURE_ARG_POINTER(aLastModifiedTime); + + FSRef fsRef; + nsresult rv = GetFSRefInternal(fsRef); + if (NS_FAILED(rv)) + return rv; + + FSCatalogInfo catalogInfo; + OSErr err = ::FSGetCatalogInfo(&fsRef, kFSCatInfoContentMod, &catalogInfo, + nsnull, nsnull, nsnull); + if (err != noErr) + return MacErrorMapper(err); + *aLastModifiedTime = HFSPlustoNSPRTime(catalogInfo.contentModDate); + return NS_OK; +} + +NS_IMETHODIMP nsLocalFile::SetLastModifiedTime(PRInt64 aLastModifiedTime) +{ + // Check we are correctly initialized. + CHECK_mBaseRef(); + + OSErr err; + nsresult rv; + FSRef fsRef; + FSCatalogInfo catalogInfo; + + rv = GetFSRefInternal(fsRef); + if (NS_FAILED(rv)) + return rv; + + FSRef parentRef; + PRBool notifyParent; + + /* Get the node flags, the content modification date and time, and the parent ref */ + err = ::FSGetCatalogInfo(&fsRef, kFSCatInfoNodeFlags + kFSCatInfoContentMod, + &catalogInfo, NULL, NULL, &parentRef); + if (err != noErr) + return MacErrorMapper(err); + + /* Notify the parent if this is a file */ + notifyParent = (0 == (catalogInfo.nodeFlags & kFSNodeIsDirectoryMask)); + + NSPRtoHFSPlusTime(aLastModifiedTime, catalogInfo.contentModDate); + err = ::FSSetCatalogInfo(&fsRef, kFSCatInfoContentMod, &catalogInfo); + if (err != noErr) + return MacErrorMapper(err); + + /* Send a notification for the parent of the file, or for the directory */ + err = FNNotify(notifyParent ? &parentRef : &fsRef, kFNDirectoryModifiedMessage, kNilOptions); + if (err != noErr) + return MacErrorMapper(err); + + return NS_OK; +} + +/* attribute PRInt64 lastModifiedTimeOfLink; */ +NS_IMETHODIMP nsLocalFile::GetLastModifiedTimeOfLink(PRInt64 *aLastModifiedTimeOfLink) +{ + NS_ERROR("NS_ERROR_NOT_IMPLEMENTED"); + return NS_ERROR_NOT_IMPLEMENTED; +} +NS_IMETHODIMP nsLocalFile::SetLastModifiedTimeOfLink(PRInt64 aLastModifiedTimeOfLink) +{ + NS_ERROR("NS_ERROR_NOT_IMPLEMENTED"); + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* attribute PRInt64 fileSize; */ +NS_IMETHODIMP nsLocalFile::GetFileSize(PRInt64 *aFileSize) +{ + NS_ENSURE_ARG_POINTER(aFileSize); + *aFileSize = 0; + + FSRef fsRef; + nsresult rv = GetFSRefInternal(fsRef); + if (NS_FAILED(rv)) + return rv; + + FSCatalogInfo catalogInfo; + OSErr err = ::FSGetCatalogInfo(&fsRef, kFSCatInfoNodeFlags + kFSCatInfoDataSizes, &catalogInfo, + nsnull, nsnull, nsnull); + if (err != noErr) + return MacErrorMapper(err); + + // FSGetCatalogInfo can return a bogus size for directories sometimes, so only + // rely on the answer for files + if ((catalogInfo.nodeFlags & kFSNodeIsDirectoryMask) == 0) + *aFileSize = catalogInfo.dataLogicalSize; + return NS_OK; +} + +NS_IMETHODIMP nsLocalFile::SetFileSize(PRInt64 aFileSize) +{ + // Check we are correctly initialized. + CHECK_mBaseRef(); + + FSRef fsRef; + nsresult rv = GetFSRefInternal(fsRef); + if (NS_FAILED(rv)) + return rv; + + SInt16 refNum; + OSErr err = ::FSOpenFork(&fsRef, 0, nsnull, fsWrPerm, &refNum); + if (err != noErr) + return MacErrorMapper(err); + err = ::FSSetForkSize(refNum, fsFromStart, aFileSize); + ::FSCloseFork(refNum); + + return MacErrorMapper(err); +} + +/* readonly attribute PRInt64 fileSizeOfLink; */ +NS_IMETHODIMP nsLocalFile::GetFileSizeOfLink(PRInt64 *aFileSizeOfLink) +{ + // Check we are correctly initialized. + CHECK_mBaseRef(); + + NS_ENSURE_ARG_POINTER(aFileSizeOfLink); + + StFollowLinksState followLinks(*this, PR_FALSE); + return GetFileSize(aFileSizeOfLink); +} + +/* readonly attribute AString target; */ +NS_IMETHODIMP nsLocalFile::GetTarget(nsAString& aTarget) +{ + NS_ERROR("NS_ERROR_NOT_IMPLEMENTED"); + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* [noscript] readonly attribute ACString nativeTarget; */ +NS_IMETHODIMP nsLocalFile::GetNativeTarget(nsACString& aNativeTarget) +{ + NS_ERROR("NS_ERROR_NOT_IMPLEMENTED"); + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* readonly attribute AString path; */ +NS_IMETHODIMP nsLocalFile::GetPath(nsAString& aPath) +{ + nsCAutoString nativeString; + nsresult rv = GetNativePath(nativeString); + if (NS_FAILED(rv)) + return rv; + CopyUTF8toUTF16NFC(nativeString, aPath); + return NS_OK; +} + +/* [noscript] readonly attribute ACString nativePath; */ +NS_IMETHODIMP nsLocalFile::GetNativePath(nsACString& aNativePath) +{ + // Check we are correctly initialized. + CHECK_mBaseRef(); + + nsresult rv = NS_ERROR_FAILURE; + CFStringRef pathStrRef = ::CFURLCopyFileSystemPath(mBaseRef, kCFURLPOSIXPathStyle); + if (pathStrRef) { + rv = CFStringReftoUTF8(pathStrRef, aNativePath); + ::CFRelease(pathStrRef); + } + return rv; +} + +/* boolean exists (); */ +NS_IMETHODIMP nsLocalFile::Exists(PRBool *_retval) +{ + // Check we are correctly initialized. + CHECK_mBaseRef(); + + NS_ENSURE_ARG_POINTER(_retval); + *_retval = PR_FALSE; + + FSRef fsRef; + if (NS_SUCCEEDED(GetFSRefInternal(fsRef, PR_TRUE))) { + *_retval = PR_TRUE; + } + + return NS_OK; +} + +/* boolean isWritable (); */ +NS_IMETHODIMP nsLocalFile::IsWritable(PRBool *_retval) +{ + // Check we are correctly initialized. + CHECK_mBaseRef(); + + NS_ENSURE_ARG_POINTER(_retval); + *_retval = PR_FALSE; + + FSRef fsRef; + nsresult rv = GetFSRefInternal(fsRef); + if (NS_FAILED(rv)) + return rv; + if (::FSCheckLock(&fsRef) == noErr) { + PRUint32 permissions; + rv = GetPermissions(&permissions); + if (NS_FAILED(rv)) + return rv; + *_retval = ((permissions & S_IWUSR) != 0); + } + return NS_OK; +} + +/* boolean isReadable (); */ +NS_IMETHODIMP nsLocalFile::IsReadable(PRBool *_retval) +{ + // Check we are correctly initialized. + CHECK_mBaseRef(); + + NS_ENSURE_ARG_POINTER(_retval); + *_retval = PR_FALSE; + + PRUint32 permissions; + nsresult rv = GetPermissions(&permissions); + if (NS_FAILED(rv)) + return rv; + *_retval = ((permissions & S_IRUSR) != 0); + return NS_OK; +} + +/* boolean isExecutable (); */ +NS_IMETHODIMP nsLocalFile::IsExecutable(PRBool *_retval) +{ + // Check we are correctly initialized. + CHECK_mBaseRef(); + + NS_ENSURE_ARG_POINTER(_retval); + *_retval = PR_FALSE; + + FSRef fsRef; + nsresult rv = GetFSRefInternal(fsRef); + if (NS_FAILED(rv)) + return rv; + + LSRequestedInfo theInfoRequest = kLSRequestAllInfo; + LSItemInfoRecord theInfo; + if (::LSCopyItemInfoForRef(&fsRef, theInfoRequest, &theInfo) == noErr) { + if ((theInfo.flags & kLSItemInfoIsApplication) != 0) + *_retval = PR_TRUE; + } + return NS_OK; +} + +/* boolean isHidden (); */ +NS_IMETHODIMP nsLocalFile::IsHidden(PRBool *_retval) +{ + NS_ENSURE_ARG_POINTER(_retval); + *_retval = PR_FALSE; + + FSRef fsRef; + nsresult rv = GetFSRefInternal(fsRef); + if (NS_FAILED(rv)) + return rv; + + FSCatalogInfo catalogInfo; + HFSUniStr255 leafName; + OSErr err = ::FSGetCatalogInfo(&fsRef, kFSCatInfoFinderInfo, &catalogInfo, + &leafName, nsnull, nsnull); + if (err != noErr) + return MacErrorMapper(err); + + FileInfo *fInfoPtr = (FileInfo *)(catalogInfo.finderInfo); // Finder flags are in the same place whether we use FileInfo or FolderInfo + if ((fInfoPtr->finderFlags & kIsInvisible) != 0) { + *_retval = PR_TRUE; + } + else { + // If the leaf name begins with a '.', consider it invisible + if (leafName.length >= 1 && leafName.unicode[0] == UniChar('.')) + *_retval = PR_TRUE; + } + return NS_OK; +} + +/* boolean isDirectory (); */ +NS_IMETHODIMP nsLocalFile::IsDirectory(PRBool *_retval) +{ + NS_ENSURE_ARG_POINTER(_retval); + *_retval = PR_FALSE; + + FSRef fsRef; + nsresult rv = GetFSRefInternal(fsRef, PR_FALSE); + if (NS_FAILED(rv)) + return rv; + + FSCatalogInfo catalogInfo; + OSErr err = ::FSGetCatalogInfo(&fsRef, kFSCatInfoNodeFlags, &catalogInfo, + nsnull, nsnull, nsnull); + if (err != noErr) + return MacErrorMapper(err); + *_retval = ((catalogInfo.nodeFlags & kFSNodeIsDirectoryMask) != 0); + return NS_OK; +} + +/* boolean isFile (); */ +NS_IMETHODIMP nsLocalFile::IsFile(PRBool *_retval) +{ + NS_ENSURE_ARG_POINTER(_retval); + *_retval = PR_FALSE; + + FSRef fsRef; + nsresult rv = GetFSRefInternal(fsRef, PR_FALSE); + if (NS_FAILED(rv)) + return rv; + + FSCatalogInfo catalogInfo; + OSErr err = ::FSGetCatalogInfo(&fsRef, kFSCatInfoNodeFlags, &catalogInfo, + nsnull, nsnull, nsnull); + if (err != noErr) + return MacErrorMapper(err); + *_retval = ((catalogInfo.nodeFlags & kFSNodeIsDirectoryMask) == 0); + return NS_OK; +} + +/* boolean isSymlink (); */ +NS_IMETHODIMP nsLocalFile::IsSymlink(PRBool *_retval) +{ + // Check we are correctly initialized. + CHECK_mBaseRef(); + + NS_ENSURE_ARG(_retval); + *_retval = PR_FALSE; + + // Check we are correctly initialized. + CHECK_mBaseRef(); + + FSRef fsRef; + if (::CFURLGetFSRef(mBaseRef, &fsRef)) { + Boolean isAlias, isFolder; + if (::FSIsAliasFile(&fsRef, &isAlias, &isFolder) == noErr) + *_retval = isAlias; + } + return NS_OK; +} + +/* boolean isSpecial (); */ +NS_IMETHODIMP nsLocalFile::IsSpecial(PRBool *_retval) +{ + NS_ERROR("NS_ERROR_NOT_IMPLEMENTED"); + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* nsIFile clone (); */ +NS_IMETHODIMP nsLocalFile::Clone(nsIFile **_retval) +{ + // Just copy-construct ourselves + *_retval = new nsLocalFile(*this); + if (!*_retval) + return NS_ERROR_OUT_OF_MEMORY; + + NS_ADDREF(*_retval); + + return NS_OK; +} + +/* boolean equals (in nsIFile inFile); */ +NS_IMETHODIMP nsLocalFile::Equals(nsIFile *inFile, PRBool *_retval) +{ + return EqualsInternal(inFile, PR_TRUE, _retval); +} + +nsresult +nsLocalFile::EqualsInternal(nsISupports* inFile, PRBool aUpdateCache, + PRBool *_retval) +{ + NS_ENSURE_ARG_POINTER(_retval); + *_retval = PR_FALSE; + + nsCOMPtr inMacFile(do_QueryInterface(inFile)); + if (!inFile) + return NS_OK; + + nsLocalFile* inLF = + static_cast((nsILocalFileMac*) inMacFile); + + // If both exist, compare FSRefs + FSRef thisFSRef, inFSRef; + nsresult rv1 = GetFSRefInternal(thisFSRef, aUpdateCache); + nsresult rv2 = inLF->GetFSRefInternal(inFSRef, aUpdateCache); + if (NS_SUCCEEDED(rv1) && NS_SUCCEEDED(rv2)) { + *_retval = (thisFSRef == inFSRef); + return NS_OK; + } + // If one exists and the other doesn't, not equal + if (rv1 != rv2) + return NS_OK; + + // Arg, we have to get their paths and compare + nsCAutoString thisPath, inPath; + if (NS_FAILED(GetNativePath(thisPath))) + return NS_ERROR_FAILURE; + if (NS_FAILED(inMacFile->GetNativePath(inPath))) + return NS_ERROR_FAILURE; + *_retval = thisPath.Equals(inPath); + + return NS_OK; +} + +/* boolean contains (in nsIFile inFile, in boolean recur); */ +NS_IMETHODIMP nsLocalFile::Contains(nsIFile *inFile, PRBool recur, PRBool *_retval) +{ + // Check we are correctly initialized. + CHECK_mBaseRef(); + + NS_ENSURE_ARG_POINTER(_retval); + *_retval = PR_FALSE; + + PRBool isDir; + nsresult rv = IsDirectory(&isDir); + if (NS_FAILED(rv)) + return rv; + if (!isDir) + return NS_OK; // must be a dir to contain someone + + nsCAutoString thisPath, inPath; + if (NS_FAILED(GetNativePath(thisPath)) || NS_FAILED(inFile->GetNativePath(inPath))) + return NS_ERROR_FAILURE; + size_t thisPathLen = thisPath.Length(); + if ((inPath.Length() > thisPathLen + 1) && (strncasecmp(thisPath.get(), inPath.get(), thisPathLen) == 0)) { + // Now make sure that the |inFile|'s path has a separator at thisPathLen, + // and there's at least one more character after that. + if (inPath[thisPathLen] == kPathSepChar) + *_retval = PR_TRUE; + } + return NS_OK; +} + +/* readonly attribute nsIFile parent; */ +NS_IMETHODIMP nsLocalFile::GetParent(nsIFile * *aParent) +{ + NS_ENSURE_ARG_POINTER(aParent); + *aParent = nsnull; + + // Check we are correctly initialized. + CHECK_mBaseRef(); + + nsLocalFile *newFile = nsnull; + + // If it can be determined without error that a file does not + // have a parent, return nsnull for the parent and NS_OK as the result. + // See bug 133617. + nsresult rv = NS_OK; + CFURLRef parentURLRef = ::CFURLCreateCopyDeletingLastPathComponent(kCFAllocatorDefault, mBaseRef); + if (parentURLRef) { + // If the parent path is longer than file's path then + // CFURLCreateCopyDeletingLastPathComponent must have simply added + // two dots at the end - in this case indicate that there is no parent. + // See bug 332389. + CFStringRef path = ::CFURLGetString(mBaseRef); + CFStringRef newPath = ::CFURLGetString(parentURLRef); + if (::CFStringGetLength(newPath) < ::CFStringGetLength(path)) { + rv = NS_ERROR_FAILURE; + newFile = new nsLocalFile; + if (newFile) { + rv = newFile->InitWithCFURL(parentURLRef); + if (NS_SUCCEEDED(rv)) { + NS_ADDREF(*aParent = newFile); + rv = NS_OK; + } + } + } + ::CFRelease(parentURLRef); + } + return rv; +} + +/* readonly attribute nsISimpleEnumerator directoryEntries; */ +NS_IMETHODIMP nsLocalFile::GetDirectoryEntries(nsISimpleEnumerator **aDirectoryEntries) +{ + NS_ENSURE_ARG_POINTER(aDirectoryEntries); + *aDirectoryEntries = nsnull; + + nsresult rv; + PRBool isDir; + rv = IsDirectory(&isDir); + if (NS_FAILED(rv)) + return rv; + if (!isDir) + return NS_ERROR_FILE_NOT_DIRECTORY; + + nsDirEnumerator* dirEnum = new nsDirEnumerator; + if (dirEnum == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + NS_ADDREF(dirEnum); + rv = dirEnum->Init(this); + if (NS_FAILED(rv)) { + NS_RELEASE(dirEnum); + return rv; + } + *aDirectoryEntries = dirEnum; + + return NS_OK; +} + + +//***************************************************************************** +// nsLocalFile::nsILocalFile +//***************************************************************************** +#pragma mark - +#pragma mark [nsILocalFile] + +/* void initWithPath (in AString filePath); */ +NS_IMETHODIMP nsLocalFile::InitWithPath(const nsAString& filePath) +{ + return InitWithNativePath(NS_ConvertUTF16toUTF8(filePath)); +} + +/* [noscript] void initWithNativePath (in ACString filePath); */ +NS_IMETHODIMP nsLocalFile::InitWithNativePath(const nsACString& filePath) +{ + nsCAutoString fixedPath; + if (Substring(filePath, 0, 2).EqualsLiteral("~/")) { + nsCOMPtr homeDir; + nsCAutoString homePath; + nsresult rv = NS_GetSpecialDirectory(NS_OS_HOME_DIR, + getter_AddRefs(homeDir)); + NS_ENSURE_SUCCESS(rv, rv); + rv = homeDir->GetNativePath(homePath); + NS_ENSURE_SUCCESS(rv, rv); + + fixedPath = homePath + Substring(filePath, 1, filePath.Length() - 1); + } + else if (filePath.IsEmpty() || filePath.First() != '/') + return NS_ERROR_FILE_UNRECOGNIZED_PATH; + else + fixedPath.Assign(filePath); + + // A path with consecutive '/'s which are not between + // nodes crashes CFURLGetFSRef(). Consecutive '/'s which + // are between actual nodes are OK. So, convert consecutive + // '/'s to a single one. + fixedPath.ReplaceSubstring("//", "/"); + +#if 1 // bird: hack to fix RegistryLocationForSpec issues with /path/to/./components + fixedPath.ReplaceSubstring("/./", "/"); + size_t len = fixedPath.Length(); + while (len > 2) + { + size_t choplen = 0; + if (!strcmp(fixedPath.get() + len - 2, "/.")) + choplen = 2; + else if (!strcmp(fixedPath.get() + len - 1, "/")) + choplen = 1; + else + break; + fixedPath = StringHead(fixedPath, len - choplen); + } + // bird: another hack for the issue with VirtualBoxVM and symlinks... + char tmpBuf[PATH_MAX]; + if (realpath(fixedPath.get(), tmpBuf)) + fixedPath = tmpBuf; +#endif + + // On 10.2, huge paths also crash CFURLGetFSRef() + if (fixedPath.Length() > PATH_MAX) + return NS_ERROR_FILE_NAME_TOO_LONG; + + CFStringRef pathAsCFString; + CFURLRef pathAsCFURL; + + pathAsCFString = ::CFStringCreateWithCString(nsnull, fixedPath.get(), kCFStringEncodingUTF8); + if (!pathAsCFString) + return NS_ERROR_FAILURE; + pathAsCFURL = ::CFURLCreateWithFileSystemPath(nsnull, pathAsCFString, kCFURLPOSIXPathStyle, PR_FALSE); + if (!pathAsCFURL) { + ::CFRelease(pathAsCFString); + return NS_ERROR_FAILURE; + } + SetBaseRef(pathAsCFURL); + ::CFRelease(pathAsCFURL); + ::CFRelease(pathAsCFString); + return NS_OK; +} + +/* void initWithFile (in nsILocalFile aFile); */ +NS_IMETHODIMP nsLocalFile::InitWithFile(nsILocalFile *aFile) +{ + NS_ENSURE_ARG(aFile); + + nsCOMPtr aFileMac(do_QueryInterface(aFile)); + if (!aFileMac) + return NS_ERROR_UNEXPECTED; + CFURLRef urlRef; + nsresult rv = aFileMac->GetCFURL(&urlRef); + if (NS_FAILED(rv)) + return rv; + rv = InitWithCFURL(urlRef); + ::CFRelease(urlRef); + return rv; +} + +/* attribute PRBool followLinks; */ +NS_IMETHODIMP nsLocalFile::GetFollowLinks(PRBool *aFollowLinks) +{ + NS_ENSURE_ARG_POINTER(aFollowLinks); + + *aFollowLinks = mFollowLinks; + return NS_OK; +} + +NS_IMETHODIMP nsLocalFile::SetFollowLinks(PRBool aFollowLinks) +{ + if (aFollowLinks != mFollowLinks) { + mFollowLinks = aFollowLinks; + UpdateTargetRef(); + } + return NS_OK; +} + +/* [noscript] PRFileDescStar openNSPRFileDesc (in long flags, in long mode); */ +NS_IMETHODIMP nsLocalFile::OpenNSPRFileDesc(PRInt32 flags, PRInt32 mode, PRFileDesc **_retval) +{ + NS_ENSURE_ARG_POINTER(_retval); + + nsCAutoString path; + nsresult rv = GetPathInternal(path); + if (NS_FAILED(rv)) + return rv; + + *_retval = PR_Open(path.get(), flags, mode); + if (! *_retval) + return NS_ErrorAccordingToNSPR(); + + return NS_OK; +} + +/* [noscript] FILE openANSIFileDesc (in string mode); */ +NS_IMETHODIMP nsLocalFile::OpenANSIFileDesc(const char *mode, FILE **_retval) +{ + NS_ENSURE_ARG_POINTER(_retval); + + nsCAutoString path; + nsresult rv = GetPathInternal(path); + if (NS_FAILED(rv)) + return rv; + + *_retval = fopen(path.get(), mode); + if (! *_retval) + return NS_ERROR_FAILURE; + + return NS_OK; +} + +/* [noscript] PRLibraryStar load (); */ +NS_IMETHODIMP nsLocalFile::Load(PRLibrary **_retval) +{ + // Check we are correctly initialized. + CHECK_mBaseRef(); + + NS_ENSURE_ARG_POINTER(_retval); + + NS_TIMELINE_START_TIMER("PR_LoadLibrary"); + + nsCAutoString path; + nsresult rv = GetPathInternal(path); + if (NS_FAILED(rv)) + return rv; + +#ifdef NS_BUILD_REFCNT_LOGGING + nsTraceRefcntImpl::SetActivityIsLegal(PR_FALSE); +#endif + + *_retval = PR_LoadLibrary(path.get()); + +#ifdef NS_BUILD_REFCNT_LOGGING + nsTraceRefcntImpl::SetActivityIsLegal(PR_TRUE); +#endif + + NS_TIMELINE_STOP_TIMER("PR_LoadLibrary"); + NS_TIMELINE_MARK_TIMER1("PR_LoadLibrary", path.get()); + + if (!*_retval) + return NS_ERROR_FAILURE; + + return NS_OK; +} + +/* readonly attribute PRInt64 diskSpaceAvailable; */ +NS_IMETHODIMP nsLocalFile::GetDiskSpaceAvailable(PRInt64 *aDiskSpaceAvailable) +{ + // Check we are correctly initialized. + CHECK_mBaseRef(); + + NS_ENSURE_ARG_POINTER(aDiskSpaceAvailable); + + FSRef fsRef; + nsresult rv = GetFSRefInternal(fsRef); + if (NS_FAILED(rv)) + return rv; + + OSErr err; + FSCatalogInfo catalogInfo; + err = ::FSGetCatalogInfo(&fsRef, kFSCatInfoVolume, &catalogInfo, + nsnull, nsnull, nsnull); + if (err != noErr) + return MacErrorMapper(err); + + FSVolumeInfo volumeInfo; + err = ::FSGetVolumeInfo(catalogInfo.volume, 0, nsnull, kFSVolInfoSizes, + &volumeInfo, nsnull, nsnull); + if (err != noErr) + return MacErrorMapper(err); + + *aDiskSpaceAvailable = volumeInfo.freeBytes; + return NS_OK; +} + +/* void appendRelativePath (in AString relativeFilePath); */ +NS_IMETHODIMP nsLocalFile::AppendRelativePath(const nsAString& relativeFilePath) +{ + return AppendRelativeNativePath(NS_ConvertUTF16toUTF8(relativeFilePath)); +} + +/* [noscript] void appendRelativeNativePath (in ACString relativeFilePath); */ +NS_IMETHODIMP nsLocalFile::AppendRelativeNativePath(const nsACString& relativeFilePath) +{ + if (relativeFilePath.IsEmpty()) + return NS_OK; + // No leading '/' + if (relativeFilePath.First() == '/') + return NS_ERROR_FILE_UNRECOGNIZED_PATH; + + // Parse the nodes and call Append() for each + nsACString::const_iterator nodeBegin, pathEnd; + relativeFilePath.BeginReading(nodeBegin); + relativeFilePath.EndReading(pathEnd); + nsACString::const_iterator nodeEnd(nodeBegin); + + while (nodeEnd != pathEnd) { + FindCharInReadable(kPathSepChar, nodeEnd, pathEnd); + nsresult rv = AppendNative(Substring(nodeBegin, nodeEnd)); + if (NS_FAILED(rv)) + return rv; + if (nodeEnd != pathEnd) // If there's more left in the string, inc over the '/' nodeEnd is on. + ++nodeEnd; + nodeBegin = nodeEnd; + } + return NS_OK; +} + +/* attribute ACString persistentDescriptor; */ +NS_IMETHODIMP nsLocalFile::GetPersistentDescriptor(nsACString& aPersistentDescriptor) +{ + FSRef fsRef; + nsresult rv = GetFSRefInternal(fsRef); + if (NS_FAILED(rv)) + return rv; + + AliasHandle aliasH; + OSErr err = ::FSNewAlias(nsnull, &fsRef, &aliasH); + if (err != noErr) + return MacErrorMapper(err); + + PRUint32 bytes = ::GetHandleSize((Handle) aliasH); + ::HLock((Handle) aliasH); + // Passing nsnull for dest makes NULL-term string + char* buf = PL_Base64Encode((const char*)*aliasH, bytes, nsnull); + ::DisposeHandle((Handle) aliasH); + NS_ENSURE_TRUE(buf, NS_ERROR_OUT_OF_MEMORY); + + aPersistentDescriptor = buf; + PR_Free(buf); + + return NS_OK; +} + +NS_IMETHODIMP nsLocalFile::SetPersistentDescriptor(const nsACString& aPersistentDescriptor) +{ + if (aPersistentDescriptor.IsEmpty()) + return NS_ERROR_INVALID_ARG; + + // Support pathnames as user-supplied descriptors if they begin with '/' + // or '~'. These characters do not collide with the base64 set used for + // encoding alias records. + char first = aPersistentDescriptor.First(); + if (first == '/' || first == '~') + return InitWithNativePath(aPersistentDescriptor); + + nsresult rv = NS_OK; + + PRUint32 dataSize = aPersistentDescriptor.Length(); + char* decodedData = PL_Base64Decode(PromiseFlatCString(aPersistentDescriptor).get(), dataSize, nsnull); + if (!decodedData) { + NS_ERROR("SetPersistentDescriptor was given bad data"); + return NS_ERROR_FAILURE; + } + + // Cast to an alias record and resolve. + AliasRecord aliasHeader = *(AliasPtr)decodedData; + PRInt32 aliasSize = GetAliasSizeFromRecord(aliasHeader); + if (aliasSize > ((PRInt32)dataSize * 3) / 4) { // be paranoid about having too few data + PR_Free(decodedData); + return NS_ERROR_FAILURE; + } + + // Move the now-decoded data into the Handle. + // The size of the decoded data is 3/4 the size of the encoded data. See plbase64.h + Handle newHandle = nsnull; + if (::PtrToHand(decodedData, &newHandle, aliasSize) != noErr) + rv = NS_ERROR_OUT_OF_MEMORY; + PR_Free(decodedData); + if (NS_FAILED(rv)) + return rv; + + Boolean changed; + FSRef resolvedFSRef; + OSErr err = ::FSResolveAlias(nsnull, (AliasHandle)newHandle, &resolvedFSRef, &changed); + + rv = MacErrorMapper(err); + DisposeHandle(newHandle); + if (NS_FAILED(rv)) + return rv; + + return InitWithFSRef(&resolvedFSRef); +} + +/* void reveal (); */ +NS_IMETHODIMP nsLocalFile::Reveal() +{ + FSRef fsRefToReveal; + AppleEvent aeEvent = {0, nil}; + AppleEvent aeReply = {0, nil}; + StAEDesc aeDirDesc, listElem, myAddressDesc, fileList; + OSErr err; + ProcessSerialNumber process; + + nsresult rv = GetFSRefInternal(fsRefToReveal); + if (NS_FAILED(rv)) + return rv; + + err = ::FindRunningAppBySignature ('MACS', process); + if (err == noErr) { + err = ::AECreateDesc(typeProcessSerialNumber, (Ptr)&process, sizeof(process), &myAddressDesc); + if (err == noErr) { + // Create the FinderEvent + err = ::AECreateAppleEvent(kAEMiscStandards, kAEMakeObjectsVisible, &myAddressDesc, + kAutoGenerateReturnID, kAnyTransactionID, &aeEvent); + if (err == noErr) { + // Create the file list + err = ::AECreateList(nil, 0, false, &fileList); + if (err == noErr) { + FSSpec fsSpecToReveal; + err = ::FSRefMakeFSSpec(&fsRefToReveal, &fsSpecToReveal); + if (err == noErr) { + err = ::AEPutPtr(&fileList, 0, typeFSS, &fsSpecToReveal, sizeof(FSSpec)); + if (err == noErr) { + err = ::AEPutParamDesc(&aeEvent, keyDirectObject, &fileList); + if (err == noErr) { + err = ::AESend(&aeEvent, &aeReply, kAENoReply, kAENormalPriority, kAEDefaultTimeout, nil, nil); + if (err == noErr) + ::SetFrontProcess(&process); + } + } + } + } + } + } + } + + return NS_OK; +} + +/* void launch (); */ +NS_IMETHODIMP nsLocalFile::Launch() +{ + FSRef fsRef; + nsresult rv = GetFSRefInternal(fsRef); + if (NS_FAILED(rv)) + return rv; + + OSErr err = ::LSOpenFSRef(&fsRef, NULL); + return MacErrorMapper(err); +} + + +//***************************************************************************** +// nsLocalFile::nsILocalFileMac +//***************************************************************************** +#pragma mark - +#pragma mark [nsILocalFileMac] + +/* void initWithCFURL (in CFURLRef aCFURL); */ +NS_IMETHODIMP nsLocalFile::InitWithCFURL(CFURLRef aCFURL) +{ + NS_ENSURE_ARG(aCFURL); + + SetBaseRef(aCFURL); + return NS_OK; +} + +/* void initWithFSRef ([const] in FSRefPtr aFSRef); */ +NS_IMETHODIMP nsLocalFile::InitWithFSRef(const FSRef *aFSRef) +{ + NS_ENSURE_ARG(aFSRef); + nsresult rv = NS_ERROR_FAILURE; + + CFURLRef newURLRef = ::CFURLCreateFromFSRef(kCFAllocatorDefault, aFSRef); + if (newURLRef) { + SetBaseRef(newURLRef); + ::CFRelease(newURLRef); + rv = NS_OK; + } + return rv; +} + +/* void initWithFSSpec ([const] in FSSpecPtr aFileSpec); */ +NS_IMETHODIMP nsLocalFile::InitWithFSSpec(const FSSpec *aFileSpec) +{ + NS_ENSURE_ARG(aFileSpec); + + FSRef fsRef; + OSErr err = ::FSpMakeFSRef(aFileSpec, &fsRef); + if (err == noErr) + return InitWithFSRef(&fsRef); + else if (err == fnfErr) { + CInfoPBRec pBlock; + FSSpec parentDirSpec; + + memset(&pBlock, 0, sizeof(CInfoPBRec)); + parentDirSpec.name[0] = 0; + pBlock.dirInfo.ioVRefNum = aFileSpec->vRefNum; + pBlock.dirInfo.ioDrDirID = aFileSpec->parID; + pBlock.dirInfo.ioNamePtr = (StringPtr)parentDirSpec.name; + pBlock.dirInfo.ioFDirIndex = -1; //get info on parID + err = ::PBGetCatInfoSync(&pBlock); + if (err != noErr) + return MacErrorMapper(err); + + parentDirSpec.vRefNum = aFileSpec->vRefNum; + parentDirSpec.parID = pBlock.dirInfo.ioDrParID; + err = ::FSpMakeFSRef(&parentDirSpec, &fsRef); + if (err != noErr) + return MacErrorMapper(err); + HFSUniStr255 unicodeName; + err = ::HFSNameGetUnicodeName(aFileSpec->name, kTextEncodingUnknown, &unicodeName); + if (err != noErr) + return MacErrorMapper(err); + nsresult rv = InitWithFSRef(&fsRef); + if (NS_FAILED(rv)) + return rv; + return Append(nsDependentString(unicodeName.unicode, unicodeName.length)); + } + return MacErrorMapper(err); +} + +/* void initToAppWithCreatorCode (in OSType aAppCreator); */ +NS_IMETHODIMP nsLocalFile::InitToAppWithCreatorCode(OSType aAppCreator) +{ + FSRef fsRef; + OSErr err = ::LSFindApplicationForInfo(aAppCreator, nsnull, nsnull, &fsRef, nsnull); + if (err != noErr) + return MacErrorMapper(err); + return InitWithFSRef(&fsRef); +} + +/* CFURLRef getCFURL (); */ +NS_IMETHODIMP nsLocalFile::GetCFURL(CFURLRef *_retval) +{ + NS_ENSURE_ARG_POINTER(_retval); + CFURLRef whichURLRef = mFollowLinks ? mTargetRef : mBaseRef; + if (whichURLRef) + ::CFRetain(whichURLRef); + *_retval = whichURLRef; + return whichURLRef ? NS_OK : NS_ERROR_FAILURE; +} + +/* FSRef getFSRef (); */ +NS_IMETHODIMP nsLocalFile::GetFSRef(FSRef *_retval) +{ + NS_ENSURE_ARG_POINTER(_retval); + return GetFSRefInternal(*_retval); +} + +/* FSSpec getFSSpec (); */ +NS_IMETHODIMP nsLocalFile::GetFSSpec(FSSpec *_retval) +{ + NS_ENSURE_ARG_POINTER(_retval); + + // Check we are correctly initialized. + CHECK_mBaseRef(); + + OSErr err; + FSRef fsRef; + nsresult rv = GetFSRefInternal(fsRef); + if (NS_SUCCEEDED(rv)) { + // If the leaf node exists, things are simple. + err = ::FSGetCatalogInfo(&fsRef, kFSCatInfoNone, + nsnull, nsnull, _retval, nsnull); + return MacErrorMapper(err); + } + else if (rv == NS_ERROR_FILE_NOT_FOUND) { + // If the parent of the leaf exists, make an FSSpec from that. + CFURLRef parentURLRef = ::CFURLCreateCopyDeletingLastPathComponent(kCFAllocatorDefault, mBaseRef); + if (!parentURLRef) + return NS_ERROR_FAILURE; + + err = fnfErr; + if (::CFURLGetFSRef(parentURLRef, &fsRef)) { + FSCatalogInfo catalogInfo; + if ((err = ::FSGetCatalogInfo(&fsRef, + kFSCatInfoVolume + kFSCatInfoNodeID + kFSCatInfoTextEncoding, + &catalogInfo, nsnull, nsnull, nsnull)) == noErr) { + nsAutoString leafName; + if (NS_SUCCEEDED(GetLeafName(leafName))) { + Str31 hfsName; + if ((err = ::UnicodeNameGetHFSName(leafName.Length(), + leafName.get(), + catalogInfo.textEncodingHint, + catalogInfo.nodeID == fsRtDirID, + hfsName)) == noErr) + err = ::FSMakeFSSpec(catalogInfo.volume, catalogInfo.nodeID, hfsName, _retval); + } + } + } + ::CFRelease(parentURLRef); + rv = MacErrorMapper(err); + } + return rv; +} + +/* readonly attribute PRInt64 fileSizeWithResFork; */ +NS_IMETHODIMP nsLocalFile::GetFileSizeWithResFork(PRInt64 *aFileSizeWithResFork) +{ + NS_ENSURE_ARG_POINTER(aFileSizeWithResFork); + + FSRef fsRef; + nsresult rv = GetFSRefInternal(fsRef); + if (NS_FAILED(rv)) + return rv; + + FSCatalogInfo catalogInfo; + OSErr err = ::FSGetCatalogInfo(&fsRef, kFSCatInfoDataSizes + kFSCatInfoRsrcSizes, + &catalogInfo, nsnull, nsnull, nsnull); + if (err != noErr) + return MacErrorMapper(err); + + *aFileSizeWithResFork = catalogInfo.dataLogicalSize + catalogInfo.rsrcLogicalSize; + return NS_OK; +} + +/* attribute OSType fileType; */ +NS_IMETHODIMP nsLocalFile::GetFileType(OSType *aFileType) +{ + NS_ENSURE_ARG_POINTER(aFileType); + + FSRef fsRef; + nsresult rv = GetFSRefInternal(fsRef); + if (NS_FAILED(rv)) + return rv; + + FinderInfo fInfo; + OSErr err = ::FSGetFinderInfo(&fsRef, &fInfo, nsnull, nsnull); + if (err != noErr) + return MacErrorMapper(err); + *aFileType = fInfo.file.fileType; + return NS_OK; +} + +NS_IMETHODIMP nsLocalFile::SetFileType(OSType aFileType) +{ + FSRef fsRef; + nsresult rv = GetFSRefInternal(fsRef); + if (NS_FAILED(rv)) + return rv; + + OSErr err = ::FSChangeCreatorType(&fsRef, 0, aFileType); + return MacErrorMapper(err); +} + +/* attribute OSType fileCreator; */ +NS_IMETHODIMP nsLocalFile::GetFileCreator(OSType *aFileCreator) +{ + NS_ENSURE_ARG_POINTER(aFileCreator); + + FSRef fsRef; + nsresult rv = GetFSRefInternal(fsRef); + if (NS_FAILED(rv)) + return rv; + + FinderInfo fInfo; + OSErr err = ::FSGetFinderInfo(&fsRef, &fInfo, nsnull, nsnull); + if (err != noErr) + return MacErrorMapper(err); + *aFileCreator = fInfo.file.fileCreator; + return NS_OK; +} + +NS_IMETHODIMP nsLocalFile::SetFileCreator(OSType aFileCreator) +{ + FSRef fsRef; + nsresult rv = GetFSRefInternal(fsRef); + if (NS_FAILED(rv)) + return rv; + + OSErr err = ::FSChangeCreatorType(&fsRef, aFileCreator, 0); + return MacErrorMapper(err); +} + +/* void setFileTypeAndCreatorFromMIMEType (in string aMIMEType); */ +NS_IMETHODIMP nsLocalFile::SetFileTypeAndCreatorFromMIMEType(const char *aMIMEType) +{ + // XXX - This should be cut from the API. Would create an evil dependency. + NS_ERROR("NS_ERROR_NOT_IMPLEMENTED"); + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* void setFileTypeAndCreatorFromExtension (in string aExtension); */ +NS_IMETHODIMP nsLocalFile::SetFileTypeAndCreatorFromExtension(const char *aExtension) +{ + // XXX - This should be cut from the API. Would create an evil dependency. + NS_ERROR("NS_ERROR_NOT_IMPLEMENTED"); + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* void launchWithDoc (in nsILocalFile aDocToLoad, in boolean aLaunchInBackground); */ +NS_IMETHODIMP nsLocalFile::LaunchWithDoc(nsILocalFile *aDocToLoad, PRBool aLaunchInBackground) +{ + PRBool isExecutable; + nsresult rv = IsExecutable(&isExecutable); + if (NS_FAILED(rv)) + return rv; + if (!isExecutable) + return NS_ERROR_FILE_EXECUTION_FAILED; + + FSRef appFSRef, docFSRef; + rv = GetFSRefInternal(appFSRef); + if (NS_FAILED(rv)) + return rv; + + if (aDocToLoad) { + nsCOMPtr macDoc = do_QueryInterface(aDocToLoad); + rv = macDoc->GetFSRef(&docFSRef); + if (NS_FAILED(rv)) + return rv; + } + + LSLaunchFlags theLaunchFlags = kLSLaunchDefaults; + LSLaunchFSRefSpec thelaunchSpec; + + if (aLaunchInBackground) + theLaunchFlags |= kLSLaunchDontSwitch; + memset(&thelaunchSpec, 0, sizeof(LSLaunchFSRefSpec)); + + thelaunchSpec.appRef = &appFSRef; + if (aDocToLoad) { + thelaunchSpec.numDocs = 1; + thelaunchSpec.itemRefs = &docFSRef; + } + thelaunchSpec.launchFlags = theLaunchFlags; + + OSErr err = ::LSOpenFromRefSpec(&thelaunchSpec, NULL); + if (err != noErr) + return MacErrorMapper(err); + + return NS_OK; +} + +/* void openDocWithApp (in nsILocalFile aAppToOpenWith, in boolean aLaunchInBackground); */ +NS_IMETHODIMP nsLocalFile::OpenDocWithApp(nsILocalFile *aAppToOpenWith, PRBool aLaunchInBackground) +{ + nsresult rv; + OSErr err; + + FSRef docFSRef, appFSRef; + rv = GetFSRefInternal(docFSRef); + if (NS_FAILED(rv)) + return rv; + + if (aAppToOpenWith) { + nsCOMPtr appFileMac = do_QueryInterface(aAppToOpenWith, &rv); + if (!appFileMac) + return rv; + + PRBool isExecutable; + rv = appFileMac->IsExecutable(&isExecutable); + if (NS_FAILED(rv)) + return rv; + if (!isExecutable) + return NS_ERROR_FILE_EXECUTION_FAILED; + + rv = appFileMac->GetFSRef(&appFSRef); + if (NS_FAILED(rv)) + return rv; + } + else { + OSType fileCreator; + rv = GetFileCreator(&fileCreator); + if (NS_FAILED(rv)) + return rv; + + err = ::LSFindApplicationForInfo(fileCreator, nsnull, nsnull, &appFSRef, nsnull); + if (err != noErr) + return MacErrorMapper(err); + } + + LSLaunchFlags theLaunchFlags = kLSLaunchDefaults; + LSLaunchFSRefSpec thelaunchSpec; + + if (aLaunchInBackground) + theLaunchFlags |= kLSLaunchDontSwitch; + memset(&thelaunchSpec, 0, sizeof(LSLaunchFSRefSpec)); + + thelaunchSpec.appRef = &appFSRef; + thelaunchSpec.numDocs = 1; + thelaunchSpec.itemRefs = &docFSRef; + thelaunchSpec.launchFlags = theLaunchFlags; + + err = ::LSOpenFromRefSpec(&thelaunchSpec, NULL); + if (err != noErr) + return MacErrorMapper(err); + + return NS_OK; +} + +/* boolean isPackage (); */ +NS_IMETHODIMP nsLocalFile::IsPackage(PRBool *_retval) +{ + NS_ENSURE_ARG(_retval); + *_retval = PR_FALSE; + + FSRef fsRef; + nsresult rv = GetFSRefInternal(fsRef); + if (NS_FAILED(rv)) + return rv; + + FSCatalogInfo catalogInfo; + OSErr err = ::FSGetCatalogInfo(&fsRef, kFSCatInfoNodeFlags + kFSCatInfoFinderInfo, + &catalogInfo, nsnull, nsnull, nsnull); + if (err != noErr) + return MacErrorMapper(err); + if ((catalogInfo.nodeFlags & kFSNodeIsDirectoryMask) != 0) { + FileInfo *fInfoPtr = (FileInfo *)(catalogInfo.finderInfo); + if ((fInfoPtr->finderFlags & kHasBundle) != 0) { + *_retval = PR_TRUE; + } + else { + // Folders ending with ".app" are also considered to + // be packages, even if the top-level folder doesn't have bundle set + nsCAutoString name; + if (NS_SUCCEEDED(rv = GetNativeLeafName(name))) { + const char *extPtr = strrchr(name.get(), '.'); + if (extPtr) { + if ((nsCRT::strcasecmp(extPtr, ".app") == 0)) + *_retval = PR_TRUE; + } + } + } + } + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::GetBundleDisplayName(nsAString& outBundleName) +{ + PRBool isPackage = PR_FALSE; + nsresult rv = IsPackage(&isPackage); + if (NS_FAILED(rv) || !isPackage) + return NS_ERROR_FAILURE; + + nsAutoString name; + rv = GetLeafName(name); + if (NS_FAILED(rv)) + return rv; + + PRInt32 length = name.Length(); + if (Substring(name, length - 4, length).EqualsLiteral(".app")) { + // 4 characters in ".app" + outBundleName = Substring(name, 0, length - 4); + } + else + outBundleName = name; + + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::GetBundleIdentifier(nsACString& outBundleIdentifier) +{ + nsresult rv = NS_ERROR_FAILURE; + + CFURLRef urlRef; + if (NS_SUCCEEDED(GetCFURL(&urlRef))) { + CFBundleRef bundle = ::CFBundleCreate(NULL, urlRef); + if (bundle) { + CFStringRef bundleIdentifier = ::CFBundleGetIdentifier(bundle); + if (bundleIdentifier) + rv = CFStringReftoUTF8(bundleIdentifier, outBundleIdentifier); + + ::CFRelease(bundle); + } + ::CFRelease(urlRef); + } + + return rv; +} + + +//***************************************************************************** +// nsLocalFile Methods +//***************************************************************************** +#pragma mark - +#pragma mark [Protected Methods] + +nsresult nsLocalFile::SetBaseRef(CFURLRef aCFURLRef) +{ + NS_ENSURE_ARG(aCFURLRef); + + ::CFRetain(aCFURLRef); + if (mBaseRef) + ::CFRelease(mBaseRef); + mBaseRef = aCFURLRef; + + mFollowLinksDirty = PR_TRUE; + UpdateTargetRef(); + mCachedFSRefValid = PR_FALSE; + return NS_OK; +} + +nsresult nsLocalFile::UpdateTargetRef() +{ + // Check we are correctly initialized. + CHECK_mBaseRef(); + + if (mFollowLinksDirty) { + if (mTargetRef) { + ::CFRelease(mTargetRef); + mTargetRef = nsnull; + } + if (mFollowLinks) { + mTargetRef = mBaseRef; + ::CFRetain(mTargetRef); + + FSRef fsRef; + if (::CFURLGetFSRef(mBaseRef, &fsRef)) { + Boolean targetIsFolder, wasAliased; + if (FSResolveAliasFile(&fsRef, true /*resolveAliasChains*/, + &targetIsFolder, &wasAliased) == noErr && wasAliased) { + ::CFRelease(mTargetRef); + mTargetRef = CFURLCreateFromFSRef(NULL, &fsRef); + if (!mTargetRef) + return NS_ERROR_FAILURE; + } + } + mFollowLinksDirty = PR_FALSE; + } + } + return NS_OK; +} + +nsresult nsLocalFile::GetFSRefInternal(FSRef& aFSRef, PRBool bForceUpdateCache) +{ + if (bForceUpdateCache || !mCachedFSRefValid) { + mCachedFSRefValid = PR_FALSE; + CFURLRef whichURLRef = mFollowLinks ? mTargetRef : mBaseRef; + NS_ENSURE_TRUE(whichURLRef, NS_ERROR_NULL_POINTER); + if (::CFURLGetFSRef(whichURLRef, &mCachedFSRef)) + mCachedFSRefValid = PR_TRUE; + } + if (mCachedFSRefValid) { + aFSRef = mCachedFSRef; + return NS_OK; + } + // CFURLGetFSRef only returns a Boolean for success, + // so we have to assume what the error was. This is + // the only probable cause. + return NS_ERROR_FILE_NOT_FOUND; +} + +nsresult nsLocalFile::GetPathInternal(nsACString& path) +{ + nsresult rv = NS_ERROR_FAILURE; + + CFURLRef whichURLRef = mFollowLinks ? mTargetRef : mBaseRef; + NS_ENSURE_TRUE(whichURLRef, NS_ERROR_NULL_POINTER); + + CFStringRef pathStrRef = ::CFURLCopyFileSystemPath(whichURLRef, kCFURLPOSIXPathStyle); + if (pathStrRef) { + rv = CFStringReftoUTF8(pathStrRef, path); + ::CFRelease(pathStrRef); + } + return rv; +} + +nsresult nsLocalFile::CopyInternal(nsIFile* aParentDir, + const nsAString& newName, + PRBool followLinks) +{ + // Check we are correctly initialized. + CHECK_mBaseRef(); + + StFollowLinksState srcFollowState(*this, followLinks); + + nsresult rv; + OSErr err; + FSRef srcFSRef, newFSRef; + + rv = GetFSRefInternal(srcFSRef); + if (NS_FAILED(rv)) + return rv; + + nsCOMPtr newParentDir = aParentDir; + + if (!newParentDir) { + if (newName.IsEmpty()) + return NS_ERROR_INVALID_ARG; + rv = GetParent(getter_AddRefs(newParentDir)); + if (NS_FAILED(rv)) + return rv; + } + + // If newParentDir does not exist, create it + PRBool exists; + rv = newParentDir->Exists(&exists); + if (NS_FAILED(rv)) + return rv; + if (!exists) { + rv = newParentDir->Create(nsIFile::DIRECTORY_TYPE, 0777); + if (NS_FAILED(rv)) + return rv; + } + + FSRef destFSRef; + nsCOMPtr newParentDirMac(do_QueryInterface(newParentDir)); + if (!newParentDirMac) + return NS_ERROR_NO_INTERFACE; + rv = newParentDirMac->GetFSRef(&destFSRef); + if (NS_FAILED(rv)) + return rv; + + err = + ::FSCopyObject(&srcFSRef, &destFSRef, newName.Length(), + newName.Length() ? PromiseFlatString(newName).get() : NULL, + 0, kFSCatInfoNone, false, false, NULL, NULL, &newFSRef); + + return MacErrorMapper(err); +} + +const PRInt64 kMillisecsPerSec = 1000LL; +const PRInt64 kUTCDateTimeFractionDivisor = 65535LL; + +PRInt64 nsLocalFile::HFSPlustoNSPRTime(const UTCDateTime& utcTime) +{ + // Start with seconds since Jan. 1, 1904 GMT + PRInt64 result = ((PRInt64)utcTime.highSeconds << 32) + (PRInt64)utcTime.lowSeconds; + // Subtract to convert to NSPR epoch of 1970 + result -= kJanuaryFirst1970Seconds; + // Convert to millisecs + result *= kMillisecsPerSec; + // Convert the fraction to millisecs and add it + result += ((PRInt64)utcTime.fraction * kMillisecsPerSec) / kUTCDateTimeFractionDivisor; + + return result; +} + +void nsLocalFile::NSPRtoHFSPlusTime(PRInt64 nsprTime, UTCDateTime& utcTime) +{ + PRInt64 fraction = nsprTime % kMillisecsPerSec; + PRInt64 seconds = (nsprTime / kMillisecsPerSec) + kJanuaryFirst1970Seconds; + utcTime.highSeconds = (UInt16)((PRUint64)seconds >> 32); + utcTime.lowSeconds = (UInt32)seconds; + utcTime.fraction = (UInt16)((fraction * kUTCDateTimeFractionDivisor) / kMillisecsPerSec); +} + +nsresult nsLocalFile::CFStringReftoUTF8(CFStringRef aInStrRef, nsACString& aOutStr) +{ + nsresult rv = NS_ERROR_FAILURE; + CFIndex usedBufLen, inStrLen = ::CFStringGetLength(aInStrRef); + CFIndex charsConverted = ::CFStringGetBytes(aInStrRef, CFRangeMake(0, inStrLen), + kCFStringEncodingUTF8, 0, PR_FALSE, nsnull, 0, &usedBufLen); + if (charsConverted == inStrLen) { +#if 0 /* bird: too new? */ + aOutStr.SetLength(usedBufLen); + if (aOutStr.Length() != (unsigned int)usedBufLen) + return NS_ERROR_OUT_OF_MEMORY; + UInt8 *buffer = (UInt8*) aOutStr.BeginWriting(); + + ::CFStringGetBytes(aInStrRef, CFRangeMake(0, inStrLen), + kCFStringEncodingUTF8, 0, false, buffer, usedBufLen, &usedBufLen); + rv = NS_OK; +#else + nsAutoBuffer buffer; + if (buffer.EnsureElemCapacity(usedBufLen + 1)) { + ::CFStringGetBytes(aInStrRef, CFRangeMake(0, inStrLen), + kCFStringEncodingUTF8, 0, false, buffer.get(), usedBufLen, &usedBufLen); + buffer.get()[usedBufLen] = '\0'; + aOutStr.Assign(nsDependentCString((char*)buffer.get())); + rv = NS_OK; + } +#endif + } + return rv; +} + +// nsIHashable + +NS_IMETHODIMP +nsLocalFile::Equals(nsIHashable* aOther, PRBool *aResult) +{ + return EqualsInternal(aOther, PR_FALSE, aResult); +} + +NS_IMETHODIMP +nsLocalFile::GetHashCode(PRUint32 *aResult) +{ + CFStringRef pathStrRef = ::CFURLCopyFileSystemPath(mBaseRef, kCFURLPOSIXPathStyle); + nsCAutoString path; + CFStringReftoUTF8(pathStrRef, path); + ::CFRelease(pathStrRef); + *aResult = HashString(path); + return NS_OK; +} + +//***************************************************************************** +// Global Functions +//***************************************************************************** +#pragma mark - +#pragma mark [Global Functions] + +void nsLocalFile::GlobalInit() +{ +} + +void nsLocalFile::GlobalShutdown() +{ +} + +nsresult NS_NewLocalFile(const nsAString& path, PRBool followLinks, nsILocalFile* *result) +{ + nsLocalFile* file = new nsLocalFile; + if (file == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + NS_ADDREF(file); + + file->SetFollowLinks(followLinks); + + if (!path.IsEmpty()) { + nsresult rv = file->InitWithPath(path); + if (NS_FAILED(rv)) { + NS_RELEASE(file); + return rv; + } + } + *result = file; + return NS_OK; +} + +nsresult NS_NewNativeLocalFile(const nsACString& path, PRBool followLinks, nsILocalFile **result) +{ + return NS_NewLocalFile(NS_ConvertUTF8toUTF16(path), followLinks, result); +} + +nsresult NS_NewLocalFileWithFSSpec(const FSSpec* inSpec, PRBool followLinks, nsILocalFileMac **result) +{ + nsLocalFile* file = new nsLocalFile(); + if (file == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + NS_ADDREF(file); + + file->SetFollowLinks(followLinks); + + nsresult rv = file->InitWithFSSpec(inSpec); + if (NS_FAILED(rv)) { + NS_RELEASE(file); + return rv; + } + *result = file; + return NS_OK; +} + +nsresult NS_NewLocalFileWithFSRef(const FSRef* aFSRef, PRBool aFollowLinks, nsILocalFileMac** result) +{ + nsLocalFile* file = new nsLocalFile(); + if (file == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + NS_ADDREF(file); + + file->SetFollowLinks(aFollowLinks); + + nsresult rv = file->InitWithFSRef(aFSRef); + if (NS_FAILED(rv)) { + NS_RELEASE(file); + return rv; + } + *result = file; + return NS_OK; +} + +//***************************************************************************** +// Static Functions +//***************************************************************************** + +static nsresult MacErrorMapper(OSErr inErr) +{ + nsresult outErr; + + switch (inErr) + { + case noErr: + outErr = NS_OK; + break; + + case fnfErr: + case afpObjectNotFound: + case afpDirNotFound: + outErr = NS_ERROR_FILE_NOT_FOUND; + break; + + case dupFNErr: + case afpObjectExists: + outErr = NS_ERROR_FILE_ALREADY_EXISTS; + break; + + case dskFulErr: + case afpDiskFull: + outErr = NS_ERROR_FILE_DISK_FULL; + break; + + case fLckdErr: + case afpVolLocked: + outErr = NS_ERROR_FILE_IS_LOCKED; + break; + + case afpAccessDenied: + outErr = NS_ERROR_FILE_ACCESS_DENIED; + break; + + case afpDirNotEmpty: + outErr = NS_ERROR_FILE_DIR_NOT_EMPTY; + break; + + // Can't find good map for some + case bdNamErr: + outErr = NS_ERROR_FAILURE; + break; + + default: + outErr = NS_ERROR_FAILURE; + break; + } + return outErr; +} + +static OSErr FindRunningAppBySignature(OSType aAppSig, ProcessSerialNumber& outPsn) +{ + ProcessInfoRec info; + OSErr err = noErr; + + outPsn.highLongOfPSN = 0; + outPsn.lowLongOfPSN = kNoProcess; + + while (PR_TRUE) + { + err = ::GetNextProcess(&outPsn); + if (err == procNotFound) + break; + if (err != noErr) + return err; + info.processInfoLength = sizeof(ProcessInfoRec); + info.processName = nil; + info.processAppSpec = nil; + err = ::GetProcessInformation(&outPsn, &info); + if (err != noErr) + return err; + + if (info.processSignature == aAppSig) + return noErr; + } + return procNotFound; +} + +// Convert a UTF-8 string to a UTF-16 string while normalizing to +// Normalization Form C (composed Unicode). We need this because +// Mac OS X file system uses NFD (Normalization Form D : decomposed Unicode) +// while most other OS', server-side programs usually expect NFC. + +typedef void (*UnicodeNormalizer) (CFMutableStringRef, CFStringNormalizationForm); +static void CopyUTF8toUTF16NFC(const nsACString& aSrc, nsAString& aResult) +{ + static PRBool sChecked = PR_FALSE; + static UnicodeNormalizer sUnicodeNormalizer = NULL; + + // CFStringNormalize was not introduced until Mac OS 10.2 + if (!sChecked) { + CFBundleRef carbonBundle = + CFBundleGetBundleWithIdentifier(CFSTR("com.apple.Carbon")); + if (carbonBundle) + sUnicodeNormalizer = (UnicodeNormalizer) + ::CFBundleGetFunctionPointerForName(carbonBundle, + CFSTR("CFStringNormalize")); + sChecked = PR_TRUE; + } + + if (!sUnicodeNormalizer) { // OS X 10.2 or earlier + CopyUTF8toUTF16(aSrc, aResult); + return; + } + + const nsAFlatCString &inFlatSrc = PromiseFlatCString(aSrc); + + // The number of 16bit code units in a UTF-16 string will never be + // larger than the number of bytes in the corresponding UTF-8 string. + CFMutableStringRef inStr = + ::CFStringCreateMutable(NULL, inFlatSrc.Length()); + + if (!inStr) { + CopyUTF8toUTF16(aSrc, aResult); + return; + } + + ::CFStringAppendCString(inStr, inFlatSrc.get(), kCFStringEncodingUTF8); + + sUnicodeNormalizer(inStr, kCFStringNormalizationFormC); + + CFIndex length = CFStringGetLength(inStr); + const UniChar* chars = CFStringGetCharactersPtr(inStr); + + if (chars) + aResult.Assign(chars, length); + else { + nsAutoBuffer buffer; + if (!buffer.EnsureElemCapacity(length)) + CopyUTF8toUTF16(aSrc, aResult); + else { + CFStringGetCharacters(inStr, CFRangeMake(0, length), buffer.get()); + aResult.Assign(buffer.get(), length); + } + } + CFRelease(inStr); +} diff --git a/src/libs/xpcom18a4/xpcom/io/nsLocalFileOSX.h b/src/libs/xpcom18a4/xpcom/io/nsLocalFileOSX.h new file mode 100644 index 00000000..b6d74521 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsLocalFileOSX.h @@ -0,0 +1,119 @@ +/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2001, 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Conrad Carlen + * + * 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 ***** */ + +#ifndef nsLocalFileMac_h__ +#define nsLocalFileMac_h__ + +#include "nsILocalFileMac.h" +#include "nsString.h" +#include "nsIHashable.h" + +class nsDirEnumerator; + +//***************************************************************************** +// nsLocalFile +// +// The native charset of this implementation is UTF-8. The Unicode used by the +// Mac OS file system is decomposed, so "Native" versions of these routines will +// always use decomposed Unicode (NFD). Their "non-Native" counterparts are +// intended to be simple wrappers which call the "Native" version and convert +// between UTF-8 and UTF-16. All the work is done on the "Native" side except +// for the conversion to NFC (composed Unicode) done in "non-Native" getters. +//***************************************************************************** + +class NS_COM nsLocalFile : public nsILocalFileMac, + public nsIHashable +{ + friend class nsDirEnumerator; + +public: + NS_DEFINE_STATIC_CID_ACCESSOR(NS_LOCAL_FILE_CID) + + nsLocalFile(); + + static NS_METHOD nsLocalFileConstructor(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr); + + NS_DECL_ISUPPORTS + NS_DECL_NSIFILE + NS_DECL_NSILOCALFILE + NS_DECL_NSILOCALFILEMAC + NS_DECL_NSIHASHABLE + +public: + + static void GlobalInit(); + static void GlobalShutdown(); + +private: + ~nsLocalFile(); + +protected: + nsLocalFile(const nsLocalFile& src); + + nsresult SetBaseRef(CFURLRef aCFURLRef); // Does CFRetain on aCFURLRef + nsresult UpdateTargetRef(); + + nsresult GetFSRefInternal(FSRef& aFSSpec, PRBool bForceUpdateCache = PR_TRUE); + nsresult GetPathInternal(nsACString& path); // Returns path WRT mFollowLinks + nsresult EqualsInternal(nsISupports* inFile, + PRBool aUpdateCache, PRBool *_retval); + + nsresult CopyInternal(nsIFile* newParentDir, + const nsAString& newName, + PRBool followLinks); + + static PRInt64 HFSPlustoNSPRTime(const UTCDateTime& utcTime); + static void NSPRtoHFSPlusTime(PRInt64 nsprTime, UTCDateTime& utcTime); + static nsresult CFStringReftoUTF8(CFStringRef aInStrRef, nsACString& aOutStr); + +protected: + CFURLRef mBaseRef; // The FS object we represent + CFURLRef mTargetRef; // If mBaseRef is an alias, its target + + FSRef mCachedFSRef; + PRPackedBool mCachedFSRefValid; + + PRPackedBool mFollowLinks; + PRPackedBool mFollowLinksDirty; + + static const char kPathSepChar; + static const PRUnichar kPathSepUnichar; + static const PRInt64 kJanuaryFirst1970Seconds; +}; + +#endif // nsLocalFileMac_h__ diff --git a/src/libs/xpcom18a4/xpcom/io/nsLocalFileUnicode.h b/src/libs/xpcom18a4/xpcom/io/nsLocalFileUnicode.h new file mode 100644 index 00000000..90bc9c07 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsLocalFileUnicode.h @@ -0,0 +1,47 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Henry Sobotka + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +#ifndef _NS_LOCALFILEUNICODE_H_ + +extern void NS_ShutdownLocalFileUnicode(); + +extern "C" NS_EXPORT nsresult +NS_NewUnicodeLocalFile(const PRUnichar *, PRBool, nsILocalFile **); + +#endif // _NS_LOCALFILEUNICODE_H_ + diff --git a/src/libs/xpcom18a4/xpcom/io/nsLocalFileUnix.cpp b/src/libs/xpcom18a4/xpcom/io/nsLocalFileUnix.cpp new file mode 100644 index 00000000..eef17bde --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsLocalFileUnix.cpp @@ -0,0 +1,1724 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mike Shaver + * Christopher Blizzard + * Jason Eager + * Stuart Parmenter + * Brendan Eich + * Pete Collins + * Paul Ashford + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/** + * Implementation of nsIFile for ``Unixy'' systems. + */ + +// We're going to need some autoconf loving, I can just tell. +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef XP_BEOS + #include + #include + #include +#endif +#if defined(VMS) + #include +#endif + +#include "nsDirectoryServiceDefs.h" +#include "nsCRT.h" +#include "nsCOMPtr.h" +#include "nsMemory.h" +#include "nsIFile.h" +#include "nsString.h" +#include "nsReadableUtils.h" +#include "nsLocalFile.h" +#include "nsIComponentManager.h" +#include "nsXPIDLString.h" +#include "prproces.h" +#include "nsISimpleEnumerator.h" +#include "nsITimelineService.h" + +#include "nsNativeCharsetUtils.h" + +// On some platforms file/directory name comparisons need to +// be case-blind. +#if defined(VMS) + #define FILE_STRCMP strcasecmp + #define FILE_STRNCMP strncasecmp +#else + #define FILE_STRCMP strcmp + #define FILE_STRNCMP strncmp +#endif + +#define VALIDATE_STAT_CACHE() \ + PR_BEGIN_MACRO \ + if (!mHaveCachedStat) { \ + FillStatCache(); \ + if (!mHaveCachedStat) \ + return NSRESULT_FOR_ERRNO(); \ + } \ + PR_END_MACRO + +#define CHECK_mPath() \ + PR_BEGIN_MACRO \ + if (mPath.IsEmpty()) \ + return NS_ERROR_NOT_INITIALIZED; \ + PR_END_MACRO + +/* directory enumerator */ +class NS_COM +nsDirEnumeratorUnix : public nsISimpleEnumerator +{ + public: + nsDirEnumeratorUnix(); + + // nsISupports interface + NS_DECL_ISUPPORTS + + // nsISimpleEnumerator interface + NS_DECL_NSISIMPLEENUMERATOR + + NS_IMETHOD Init(nsLocalFile *parent, PRBool ignored); + + private: + ~nsDirEnumeratorUnix(); + + protected: + NS_IMETHOD GetNextEntry(); + + DIR *mDir; + struct dirent *mEntry; + nsCString mParentPath; +}; + +nsDirEnumeratorUnix::nsDirEnumeratorUnix() : + mDir(nsnull), + mEntry(nsnull) +{ +} + +nsDirEnumeratorUnix::~nsDirEnumeratorUnix() +{ + if (mDir) + closedir(mDir); +} + +NS_IMPL_ISUPPORTS1(nsDirEnumeratorUnix, nsISimpleEnumerator) + +NS_IMETHODIMP +nsDirEnumeratorUnix::Init(nsLocalFile *parent, PRBool resolveSymlinks /*ignored*/) +{ + nsCAutoString dirPath; + if (NS_FAILED(parent->GetNativePath(dirPath)) || + dirPath.IsEmpty()) { + return NS_ERROR_FILE_INVALID_PATH; + } + + if (NS_FAILED(parent->GetNativePath(mParentPath))) + return NS_ERROR_FAILURE; + + mDir = opendir(dirPath.get()); + if (!mDir) + return NSRESULT_FOR_ERRNO(); + return GetNextEntry(); +} + +NS_IMETHODIMP +nsDirEnumeratorUnix::HasMoreElements(PRBool *result) +{ + *result = mDir && mEntry; + return NS_OK; +} + +NS_IMETHODIMP +nsDirEnumeratorUnix::GetNext(nsISupports **_retval) +{ + nsresult rv; + if (!mDir || !mEntry) { + *_retval = nsnull; + return NS_OK; + } + + nsLocalFile* file = new nsLocalFile(); + if (!file) + return NS_ERROR_OUT_OF_MEMORY; + + if (NS_FAILED(rv = file->InitWithNativePath(mParentPath)) || + NS_FAILED(rv = file->AppendNative(nsDependentCString(mEntry->d_name)))) { + return rv; + } + *_retval = NS_STATIC_CAST(nsISupports *, file); + NS_ADDREF(*_retval); + return GetNextEntry(); +} + +NS_IMETHODIMP +nsDirEnumeratorUnix::GetNextEntry() +{ + do { + errno = 0; + mEntry = readdir(mDir); + + // end of dir or error + if (!mEntry) + return NSRESULT_FOR_ERRNO(); + + // keep going past "." and ".." + } while (mEntry->d_name[0] == '.' && + (mEntry->d_name[1] == '\0' || // .\0 + (mEntry->d_name[1] == '.' && + mEntry->d_name[2] == '\0'))); // ..\0 + return NS_OK; +} + +nsLocalFile::nsLocalFile() : + mHaveCachedStat(PR_FALSE) +{ +} + +nsLocalFile::nsLocalFile(const nsLocalFile& other) + : mCachedStat(other.mCachedStat) + , mPath(other.mPath) + , mHaveCachedStat(other.mHaveCachedStat) +{ +} + +NS_IMPL_THREADSAFE_ISUPPORTS2(nsLocalFile, + nsIFile, + nsILocalFile) + +nsresult +nsLocalFile::nsLocalFileConstructor(nsISupports *outer, + const nsIID &aIID, + void **aInstancePtr) +{ + NS_ENSURE_ARG_POINTER(aInstancePtr); + NS_ENSURE_NO_AGGREGATION(outer); + + *aInstancePtr = nsnull; + + nsCOMPtr inst = new nsLocalFile(); + if (!inst) + return NS_ERROR_OUT_OF_MEMORY; + return inst->QueryInterface(aIID, aInstancePtr); +} + +nsresult +nsLocalFile::FillStatCache() { + if (stat(mPath.get(), &mCachedStat) == -1) { + // try lstat it may be a symlink + if (lstat(mPath.get(), &mCachedStat) == -1) { + return NSRESULT_FOR_ERRNO(); + } + } + mHaveCachedStat = PR_TRUE; + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::Clone(nsIFile **file) +{ + // Just copy-construct ourselves + *file = new nsLocalFile(*this); + if (!*file) + return NS_ERROR_OUT_OF_MEMORY; + + NS_ADDREF(*file); + + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::InitWithNativePath(const nsACString &filePath) +{ + if (Substring(filePath, 0, 2).EqualsLiteral("~/")) { + nsCOMPtr homeDir; + nsCAutoString homePath; + if (NS_FAILED(NS_GetSpecialDirectory(NS_OS_HOME_DIR, + getter_AddRefs(homeDir))) || + NS_FAILED(homeDir->GetNativePath(homePath))) { + return NS_ERROR_FAILURE; + } + + mPath = homePath + Substring(filePath, 1, filePath.Length() - 1); + } else if (filePath.IsEmpty() || filePath.First() != '/') { + NS_ERROR("Relative paths not allowed"); + return NS_ERROR_FILE_UNRECOGNIZED_PATH; + } else { + mPath = filePath; + } + + // trim off trailing slashes + ssize_t len = mPath.Length(); + while ((len > 1) && (mPath[len - 1] == '/')) + --len; + mPath.SetLength(len); + + InvalidateCache(); + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::CreateAllAncestors(PRUint32 permissions) +{ + // I promise to play nice + char *buffer = mPath.BeginWriting(), + *slashp = buffer; + +#ifdef DEBUG_NSIFILE + fprintf(stderr, "nsIFile: before: %s\n", buffer); +#endif + + while ((slashp = strchr(slashp + 1, '/'))) { + /* + * Sequences of '/' are equivalent to a single '/'. + */ + if (slashp[1] == '/') + continue; + + /* + * If the path has a trailing slash, don't make the last component, + * because we'll get EEXIST in Create when we try to build the final + * component again, and it's easier to condition the logic here than + * there. + */ + if (slashp[1] == '\0') + break; + + /* Temporarily NUL-terminate here */ + *slashp = '\0'; +#ifdef DEBUG_NSIFILE + fprintf(stderr, "nsIFile: mkdir(\"%s\")\n", buffer); +#endif + int mkdir_result = mkdir(buffer, permissions); + int mkdir_errno = errno; + if (mkdir_result == -1) { + /* + * Always set |errno| to EEXIST if the dir already exists + * (we have to do this here since the errno value is not consistent + * in all cases - various reasons like different platform, + * automounter-controlled dir, etc. can affect it (see bug 125489 + * for details)). + */ + if (access(buffer, F_OK) == 0) { + mkdir_errno = EEXIST; + } + } + + /* Put the / back before we (maybe) return */ + *slashp = '/'; + + /* + * We could get EEXIST for an existing file -- not directory -- + * with the name of one of our ancestors, but that's OK: we'll get + * ENOTDIR when we try to make the next component in the path, + * either here on back in Create, and error out appropriately. + */ + if (mkdir_result == -1 && mkdir_errno != EEXIST) + return nsresultForErrno(mkdir_errno); + } + +#ifdef DEBUG_NSIFILE + fprintf(stderr, "nsIFile: after: %s\n", buffer); +#endif + + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::OpenNSPRFileDesc(PRInt32 flags, PRInt32 mode, PRFileDesc **_retval) +{ + *_retval = PR_Open(mPath.get(), flags, mode); + if (! *_retval) + return NS_ErrorAccordingToNSPR(); + + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::OpenANSIFileDesc(const char *mode, FILE **_retval) +{ + *_retval = fopen(mPath.get(), mode); + if (! *_retval) + return NS_ERROR_FAILURE; + + return NS_OK; +} + +static int +do_create(const char *path, PRIntn flags, mode_t mode, PRFileDesc **_retval) +{ + *_retval = PR_Open(path, flags, mode); + return *_retval ? 0 : -1; +} + +static int +do_mkdir(const char *path, PRIntn flags, mode_t mode, PRFileDesc **_retval) +{ + *_retval = nsnull; + return mkdir(path, mode); +} + +nsresult +nsLocalFile::CreateAndKeepOpen(PRUint32 type, PRIntn flags, + PRUint32 permissions, PRFileDesc **_retval) +{ + if (type != NORMAL_FILE_TYPE && type != DIRECTORY_TYPE) + return NS_ERROR_FILE_UNKNOWN_TYPE; + + int result; + int (*createFunc)(const char *, PRIntn, mode_t, PRFileDesc **) = + (type == NORMAL_FILE_TYPE) ? do_create : do_mkdir; + + result = createFunc(mPath.get(), flags, permissions, _retval); + if (result == -1 && errno == ENOENT) { + /* + * If we failed because of missing ancestor components, try to create + * them and then retry the original creation. + * + * Ancestor directories get the same permissions as the file we're + * creating, with the X bit set for each of (user,group,other) with + * an R bit in the original permissions. If you want to do anything + * fancy like setgid or sticky bits, do it by hand. + */ + int dirperm = permissions; + if (permissions & S_IRUSR) + dirperm |= S_IXUSR; + if (permissions & S_IRGRP) + dirperm |= S_IXGRP; + if (permissions & S_IROTH) + dirperm |= S_IXOTH; + +#ifdef DEBUG_NSIFILE + fprintf(stderr, "nsIFile: perm = %o, dirperm = %o\n", permissions, + dirperm); +#endif + + if (NS_FAILED(CreateAllAncestors(dirperm))) + return NS_ERROR_FAILURE; + +#ifdef DEBUG_NSIFILE + fprintf(stderr, "nsIFile: Create(\"%s\") again\n", mPath.get()); +#endif + result = createFunc(mPath.get(), flags, permissions, _retval); + } + + return NSRESULT_FOR_RETURN(result); +} + +NS_IMETHODIMP +nsLocalFile::Create(PRUint32 type, PRUint32 permissions) +{ + PRFileDesc *junk = nsnull; + nsresult rv = CreateAndKeepOpen(type, + PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE | + PR_EXCL, + permissions, + &junk); + if (junk) + PR_Close(junk); + return rv; +} + +NS_IMETHODIMP +nsLocalFile::AppendNative(const nsACString &fragment) +{ + if (fragment.IsEmpty()) + return NS_OK; + + // only one component of path can be appended + nsACString::const_iterator begin, end; + if (FindCharInReadable('/', fragment.BeginReading(begin), + fragment.EndReading(end))) + return NS_ERROR_FILE_UNRECOGNIZED_PATH; + + return AppendRelativeNativePath(fragment); +} + +NS_IMETHODIMP +nsLocalFile::AppendRelativeNativePath(const nsACString &fragment) +{ + if (fragment.IsEmpty()) + return NS_OK; + + // No leading '/' + if (fragment.First() == '/') + return NS_ERROR_FILE_UNRECOGNIZED_PATH; + + if (mPath.EqualsLiteral("/")) + mPath.Append(fragment); + else + mPath.Append(NS_LITERAL_CSTRING("/") + fragment); + + InvalidateCache(); + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::Normalize() +{ + char resolved_path[PATH_MAX] = ""; + char *resolved_path_ptr = nsnull; + +#ifdef XP_BEOS + BEntry be_e(mPath.get(), true); + BPath be_p; + status_t err; + if ((err = be_e.GetPath(&be_p)) == B_OK) { + resolved_path_ptr = (char *)be_p.Path(); + PL_strncpyz(resolved_path, resolved_path_ptr, PATH_MAX - 1); + } +#else + resolved_path_ptr = realpath(mPath.get(), resolved_path); +#endif + // if there is an error, the return is null. + if (!resolved_path_ptr) + return NSRESULT_FOR_ERRNO(); + + mPath = resolved_path; + return NS_OK; +} + +void +nsLocalFile::LocateNativeLeafName(nsACString::const_iterator &begin, + nsACString::const_iterator &end) +{ + // XXX perhaps we should cache this?? + + mPath.BeginReading(begin); + mPath.EndReading(end); + + nsACString::const_iterator it = end; + nsACString::const_iterator stop = begin; + --stop; + while (--it != stop) { + if (*it == '/') { + begin = ++it; + return; + } + } + // else, the entire path is the leaf name (which means this + // isn't an absolute path... unexpected??) +} + +NS_IMETHODIMP +nsLocalFile::GetNativeLeafName(nsACString &aLeafName) +{ + nsACString::const_iterator begin, end; + LocateNativeLeafName(begin, end); + aLeafName = Substring(begin, end); + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::SetNativeLeafName(const nsACString &aLeafName) +{ + nsACString::const_iterator begin, end; + LocateNativeLeafName(begin, end); + mPath.Replace(begin.get() - mPath.get(), Distance(begin, end), aLeafName); + InvalidateCache(); + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::GetNativePath(nsACString &_retval) +{ + _retval = mPath; + return NS_OK; +} + +nsresult +nsLocalFile::GetNativeTargetPathName(nsIFile *newParent, + const nsACString &newName, + nsACString &_retval) +{ + nsresult rv; + nsCOMPtr oldParent; + + if (!newParent) { + if (NS_FAILED(rv = GetParent(getter_AddRefs(oldParent)))) + return rv; + newParent = oldParent.get(); + } else { + // check to see if our target directory exists + PRBool targetExists; + if (NS_FAILED(rv = newParent->Exists(&targetExists))) + return rv; + + if (!targetExists) { + // XXX create the new directory with some permissions + rv = newParent->Create(DIRECTORY_TYPE, 0700); + if (NS_FAILED(rv)) + return rv; + } else { + // make sure that the target is actually a directory + PRBool targetIsDirectory; + if (NS_FAILED(rv = newParent->IsDirectory(&targetIsDirectory))) + return rv; + if (!targetIsDirectory) + return NS_ERROR_FILE_DESTINATION_NOT_DIR; + } + } + + nsACString::const_iterator nameBegin, nameEnd; + if (!newName.IsEmpty()) { + newName.BeginReading(nameBegin); + newName.EndReading(nameEnd); + } + else + LocateNativeLeafName(nameBegin, nameEnd); + + nsCAutoString dirName; + if (NS_FAILED(rv = newParent->GetNativePath(dirName))) + return rv; + + _retval = dirName + + NS_LITERAL_CSTRING("/") + + Substring(nameBegin, nameEnd); + return NS_OK; +} + +nsresult +nsLocalFile::CopyDirectoryTo(nsIFile *newParent) +{ + nsresult rv; + /* + * dirCheck is used for various boolean test results such as from Equals, + * Exists, isDir, etc. + */ + PRBool dirCheck, isSymlink; + PRUint32 oldPerms; + + if (NS_FAILED((rv = IsDirectory(&dirCheck)))) + return rv; + if (!dirCheck) + return CopyToNative(newParent, EmptyCString()); + + if (NS_FAILED(rv = Equals(newParent, &dirCheck))) + return rv; + if (dirCheck) { + // can't copy dir to itself + return NS_ERROR_INVALID_ARG; + } + + if (NS_FAILED(rv = newParent->Exists(&dirCheck))) + return rv; + // get the dirs old permissions + if (NS_FAILED(rv = GetPermissions(&oldPerms))) + return rv; + if (!dirCheck) { + if (NS_FAILED(rv = newParent->Create(DIRECTORY_TYPE, oldPerms))) + return rv; + } else { // dir exists lets try to use leaf + nsCAutoString leafName; + if (NS_FAILED(rv = GetNativeLeafName(leafName))) + return rv; + if (NS_FAILED(rv = newParent->AppendNative(leafName))) + return rv; + if (NS_FAILED(rv = newParent->Exists(&dirCheck))) + return rv; + if (dirCheck) + return NS_ERROR_FILE_ALREADY_EXISTS; // dest exists + if (NS_FAILED(rv = newParent->Create(DIRECTORY_TYPE, oldPerms))) + return rv; + } + + nsCOMPtr dirIterator; + if (NS_FAILED(rv = GetDirectoryEntries(getter_AddRefs(dirIterator)))) + return rv; + + PRBool hasMore = PR_FALSE; + while (dirIterator->HasMoreElements(&hasMore), hasMore) { + nsCOMPtr entry; + rv = dirIterator->GetNext((nsISupports**)getter_AddRefs(entry)); + if (NS_FAILED(rv)) + continue; + if (NS_FAILED(rv = entry->IsSymlink(&isSymlink))) + return rv; + if (NS_FAILED(rv = entry->IsDirectory(&dirCheck))) + return rv; + if (dirCheck && !isSymlink) { + nsCOMPtr destClone; + rv = newParent->Clone(getter_AddRefs(destClone)); + if (NS_SUCCEEDED(rv)) { + nsCOMPtr newDir(do_QueryInterface(destClone)); + if (NS_FAILED(rv = entry->CopyToNative(newDir, EmptyCString()))) { +#ifdef DEBUG + nsresult rv2; + nsCAutoString pathName; + if (NS_FAILED(rv2 = entry->GetNativePath(pathName))) + return rv2; + printf("Operation not supported: %s\n", pathName.get()); +#endif + if (rv == NS_ERROR_OUT_OF_MEMORY) + return rv; + continue; + } + } + } else { + if (NS_FAILED(rv = entry->CopyToNative(newParent, EmptyCString()))) { +#ifdef DEBUG + nsresult rv2; + nsCAutoString pathName; + if (NS_FAILED(rv2 = entry->GetNativePath(pathName))) + return rv2; + printf("Operation not supported: %s\n", pathName.get()); +#endif + if (rv == NS_ERROR_OUT_OF_MEMORY) + return rv; + continue; + } + } + } + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::CopyToNative(nsIFile *newParent, const nsACString &newName) +{ + nsresult rv; + // check to make sure that this has been initialized properly + CHECK_mPath(); + + // we copy the parent here so 'newParent' remains immutable + nsCOMPtr workParent; + if (newParent) { + if (NS_FAILED(rv = newParent->Clone(getter_AddRefs(workParent)))) + return rv; + } else { + if (NS_FAILED(rv = GetParent(getter_AddRefs(workParent)))) + return rv; + } + + // check to see if we are a directory or if we are a file + PRBool isDirectory; + if (NS_FAILED(rv = IsDirectory(&isDirectory))) + return rv; + + nsCAutoString newPathName; + if (isDirectory) { + if (!newName.IsEmpty()) { + if (NS_FAILED(rv = workParent->AppendNative(newName))) + return rv; + } else { + if (NS_FAILED(rv = GetNativeLeafName(newPathName))) + return rv; + if (NS_FAILED(rv = workParent->AppendNative(newPathName))) + return rv; + } + if (NS_FAILED(rv = CopyDirectoryTo(workParent))) + return rv; + } else { + rv = GetNativeTargetPathName(workParent, newName, newPathName); + if (NS_FAILED(rv)) + return rv; + +#ifdef DEBUG_blizzard + printf("nsLocalFile::CopyTo() %s -> %s\n", mPath.get(), newPathName.get()); +#endif + + // actually create the file. + nsLocalFile *newFile = new nsLocalFile(); + if (!newFile) + return NS_ERROR_OUT_OF_MEMORY; + + nsCOMPtr fileRef(newFile); // release on exit + + rv = newFile->InitWithNativePath(newPathName); + if (NS_FAILED(rv)) + return rv; + + // get the old permissions + PRUint32 myPerms; + GetPermissions(&myPerms); + + // Create the new file with the old file's permissions, even if write + // permission is missing. We can't create with write permission and + // then change back to myPerm on all filesystems (FAT on Linux, e.g.). + // But we can write to a read-only file on all Unix filesystems if we + // open it successfully for writing. + + PRFileDesc *newFD; + rv = newFile->CreateAndKeepOpen(NORMAL_FILE_TYPE, + PR_WRONLY|PR_CREATE_FILE|PR_TRUNCATE, + myPerms, + &newFD); + if (NS_FAILED(rv)) + return rv; + + // open the old file, too + PRBool specialFile; + if (NS_FAILED(rv = IsSpecial(&specialFile))) { + PR_Close(newFD); + return rv; + } + if (specialFile) { +#ifdef DEBUG + printf("Operation not supported: %s\n", mPath.get()); +#endif + // make sure to clean up properly + PR_Close(newFD); + return NS_OK; + } + + PRFileDesc *oldFD; + rv = OpenNSPRFileDesc(PR_RDONLY, myPerms, &oldFD); + if (NS_FAILED(rv)) { + // make sure to clean up properly + PR_Close(newFD); + return rv; + } + +#ifdef DEBUG_blizzard + PRInt32 totalRead = 0; + PRInt32 totalWritten = 0; +#endif + char buf[BUFSIZ]; + PRInt32 bytesRead; + + while ((bytesRead = PR_Read(oldFD, buf, BUFSIZ)) > 0) { +#ifdef DEBUG_blizzard + totalRead += bytesRead; +#endif + + // PR_Write promises never to do a short write + PRInt32 bytesWritten = PR_Write(newFD, buf, bytesRead); + if (bytesWritten < 0) { + bytesRead = -1; + break; + } + NS_ASSERTION(bytesWritten == bytesRead, "short PR_Write?"); + +#ifdef DEBUG_blizzard + totalWritten += bytesWritten; +#endif + } + +#ifdef DEBUG_blizzard + printf("read %d bytes, wrote %d bytes\n", + totalRead, totalWritten); +#endif + + // close the files + PR_Close(newFD); + PR_Close(oldFD); + + // check for read (or write) error after cleaning up + if (bytesRead < 0) + return NS_ERROR_OUT_OF_MEMORY; + } + return rv; +} + +NS_IMETHODIMP +nsLocalFile::CopyToFollowingLinksNative(nsIFile *newParent, const nsACString &newName) +{ + return CopyToNative(newParent, newName); +} + +NS_IMETHODIMP +nsLocalFile::MoveToNative(nsIFile *newParent, const nsACString &newName) +{ + nsresult rv; + + // check to make sure that this has been initialized properly + CHECK_mPath(); + + // check to make sure that we have a new parent + nsCAutoString newPathName; + rv = GetNativeTargetPathName(newParent, newName, newPathName); + if (NS_FAILED(rv)) + return rv; + + // try for atomic rename, falling back to copy/delete + if (rename(mPath.get(), newPathName.get()) < 0) { +#ifdef VMS + if (errno == EXDEV || errno == ENXIO) { +#else + if (errno == EXDEV) { +#endif + rv = CopyToNative(newParent, newName); + if (NS_SUCCEEDED(rv)) + rv = Remove(PR_TRUE); + } else { + rv = NSRESULT_FOR_ERRNO(); + } + } + return rv; +} + +NS_IMETHODIMP +nsLocalFile::Remove(PRBool recursive) +{ + CHECK_mPath(); + + VALIDATE_STAT_CACHE(); + PRBool isSymLink, isDir; + + nsresult rv = IsSymlink(&isSymLink); + if (NS_FAILED(rv)) + return rv; + + if (!recursive && isSymLink) + return NSRESULT_FOR_RETURN(unlink(mPath.get())); + + isDir = S_ISDIR(mCachedStat.st_mode); + InvalidateCache(); + if (isDir) { + if (recursive) { + nsDirEnumeratorUnix *dir = new nsDirEnumeratorUnix(); + if (!dir) + return NS_ERROR_OUT_OF_MEMORY; + + nsCOMPtr dirRef(dir); // release on exit + + rv = dir->Init(this, PR_FALSE); + if (NS_FAILED(rv)) + return rv; + + PRBool more; + while (dir->HasMoreElements(&more), more) { + nsCOMPtr item; + rv = dir->GetNext(getter_AddRefs(item)); + if (NS_FAILED(rv)) + return NS_ERROR_FAILURE; + + nsCOMPtr file = do_QueryInterface(item, &rv); + if (NS_FAILED(rv)) + return NS_ERROR_FAILURE; + if (NS_FAILED(rv = file->Remove(recursive))) + return rv; + } + } + + if (rmdir(mPath.get()) == -1) + return NSRESULT_FOR_ERRNO(); + } else { + if (unlink(mPath.get()) == -1) + return NSRESULT_FOR_ERRNO(); + } + + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::GetLastModifiedTime(PRInt64 *aLastModTime) +{ + CHECK_mPath(); + NS_ENSURE_ARG(aLastModTime); + + PRFileInfo64 info; + if (PR_GetFileInfo64(mPath.get(), &info) != PR_SUCCESS) + return NSRESULT_FOR_ERRNO(); + + // PRTime is a 64 bit value + // microseconds -> milliseconds + PRInt64 usecPerMsec; + LL_I2L(usecPerMsec, PR_USEC_PER_MSEC); + LL_DIV(*aLastModTime, info.modifyTime, usecPerMsec); + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::SetLastModifiedTime(PRInt64 aLastModTime) +{ + CHECK_mPath(); + + int result; + if (! LL_IS_ZERO(aLastModTime)) { + VALIDATE_STAT_CACHE(); + struct utimbuf ut; + ut.actime = mCachedStat.st_atime; + + // convert milliseconds to seconds since the unix epoch + double dTime; + LL_L2D(dTime, aLastModTime); + ut.modtime = (time_t) (dTime / PR_MSEC_PER_SEC); + result = utime(mPath.get(), &ut); + } else { + result = utime(mPath.get(), nsnull); + } + InvalidateCache(); + return NSRESULT_FOR_RETURN(result); +} + +NS_IMETHODIMP +nsLocalFile::GetLastModifiedTimeOfLink(PRInt64 *aLastModTimeOfLink) +{ + CHECK_mPath(); + NS_ENSURE_ARG(aLastModTimeOfLink); + + struct stat sbuf; + if (lstat(mPath.get(), &sbuf) == -1) + return NSRESULT_FOR_ERRNO(); + LL_I2L(*aLastModTimeOfLink, (PRInt32)sbuf.st_mtime); + + // lstat returns st_mtime in seconds + PRInt64 msecPerSec; + LL_I2L(msecPerSec, PR_MSEC_PER_SEC); + LL_MUL(*aLastModTimeOfLink, *aLastModTimeOfLink, msecPerSec); + + return NS_OK; +} + +/* + * utime(2) may or may not dereference symlinks, joy. + */ +NS_IMETHODIMP +nsLocalFile::SetLastModifiedTimeOfLink(PRInt64 aLastModTimeOfLink) +{ + return SetLastModifiedTime(aLastModTimeOfLink); +} + +/* + * Only send back permissions bits: maybe we want to send back the whole + * mode_t to permit checks against other file types? + */ + +#define NORMALIZE_PERMS(mode) ((mode)& (S_IRWXU | S_IRWXG | S_IRWXO)) + +NS_IMETHODIMP +nsLocalFile::GetPermissions(PRUint32 *aPermissions) +{ + NS_ENSURE_ARG(aPermissions); + VALIDATE_STAT_CACHE(); + *aPermissions = NORMALIZE_PERMS(mCachedStat.st_mode); + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::GetPermissionsOfLink(PRUint32 *aPermissionsOfLink) +{ + CHECK_mPath(); + NS_ENSURE_ARG(aPermissionsOfLink); + + struct stat sbuf; + if (lstat(mPath.get(), &sbuf) == -1) + return NSRESULT_FOR_ERRNO(); + *aPermissionsOfLink = NORMALIZE_PERMS(sbuf.st_mode); + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::SetPermissions(PRUint32 aPermissions) +{ + CHECK_mPath(); + + InvalidateCache(); + + /* + * Race condition here: we should use fchmod instead, there's no way to + * guarantee the name still refers to the same file. + */ + if (chmod(mPath.get(), aPermissions) < 0) + return NSRESULT_FOR_ERRNO(); + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::SetPermissionsOfLink(PRUint32 aPermissions) +{ + return SetPermissions(aPermissions); +} + +NS_IMETHODIMP +nsLocalFile::GetFileSize(PRInt64 *aFileSize) +{ + NS_ENSURE_ARG_POINTER(aFileSize); + *aFileSize = LL_ZERO; + VALIDATE_STAT_CACHE(); + +#if defined(VMS) + /* Only two record formats can report correct file content size */ + if ((mCachedStat.st_fab_rfm != FAB$C_STMLF) && + (mCachedStat.st_fab_rfm != FAB$C_STMCR)) { + return NS_ERROR_FAILURE; + } +#endif + + /* XXX autoconf for and use stat64 if available */ + if (!S_ISDIR(mCachedStat.st_mode)) { + LL_UI2L(*aFileSize, (PRUint32)mCachedStat.st_size); + } + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::SetFileSize(PRInt64 aFileSize) +{ + CHECK_mPath(); + + PRInt32 size; + LL_L2I(size, aFileSize); + /* XXX truncate64? */ + InvalidateCache(); + if (truncate(mPath.get(), (off_t)size) == -1) + return NSRESULT_FOR_ERRNO(); + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::GetFileSizeOfLink(PRInt64 *aFileSize) +{ + CHECK_mPath(); + NS_ENSURE_ARG(aFileSize); + + struct stat sbuf; + if (lstat(mPath.get(), &sbuf) == -1) + return NSRESULT_FOR_ERRNO(); + /* XXX autoconf for and use lstat64 if available */ + LL_UI2L(*aFileSize, (PRUint32)sbuf.st_size); + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::GetDiskSpaceAvailable(PRInt64 *aDiskSpaceAvailable) +{ + NS_ENSURE_ARG_POINTER(aDiskSpaceAvailable); + + // These systems have the operations necessary to check disk space. + +#if defined(HAVE_SYS_STATFS_H) || defined(HAVE_SYS_STATVFS_H) + + // check to make sure that mPath is properly initialized + CHECK_mPath(); + + struct STATFS fs_buf; + + /* + * Members of the STATFS struct that you should know about: + * f_bsize = block size on disk. + * f_bavail = number of free blocks available to a non-superuser. + * f_bfree = number of total free blocks in file system. + */ + + if (STATFS(mPath.get(), &fs_buf) < 0) { + // The call to STATFS failed. +#ifdef DEBUG + printf("ERROR: GetDiskSpaceAvailable: STATFS call FAILED. \n"); +#endif + return NS_ERROR_FAILURE; + } +#ifdef DEBUG_DISK_SPACE + printf("DiskSpaceAvailable: %d bytes\n", + fs_buf.f_bsize * (fs_buf.f_bavail - 1)); +#endif + + /* + * The number of bytes free == The number of free blocks available to + * a non-superuser, minus one as a fudge factor, multiplied by the size + * of the aforementioned blocks. + */ + PRInt64 bsize, bavail; + + LL_I2L(bsize, fs_buf.f_bsize); + LL_I2L(bavail, fs_buf.f_bavail - 1); + LL_MUL(*aDiskSpaceAvailable, bsize, bavail); + return NS_OK; + +#else + /* + * This platform doesn't have statfs or statvfs. I'm sure that there's + * a way to check for free disk space on platforms that don't have statfs + * (I'm SURE they have df, for example). + * + * Until we figure out how to do that, lets be honest and say that this + * command isn't implemented properly for these platforms yet. + */ +#ifdef DEBUG + printf("ERROR: GetDiskSpaceAvailable: Not implemented for plaforms without statfs.\n"); +#endif + return NS_ERROR_NOT_IMPLEMENTED; + +#endif /* HAVE_SYS_STATFS_H or HAVE_SYS_STATVFS_H */ + +} + +NS_IMETHODIMP +nsLocalFile::GetParent(nsIFile **aParent) +{ + CHECK_mPath(); + NS_ENSURE_ARG_POINTER(aParent); + *aParent = nsnull; + + // if '/' we are at the top of the volume, return null + if (mPath.Equals("/")) + return NS_OK; + + // I promise to play nice + char *buffer = mPath.BeginWriting(), + *slashp = buffer; + + // find the last significant slash in buffer + slashp = strrchr(buffer, '/'); + NS_ASSERTION(slashp, "non-canonical mPath?"); + if (!slashp) + return NS_ERROR_FILE_INVALID_PATH; + + // for the case where we are at '/' + if (slashp == buffer) + slashp++; + + // temporarily terminate buffer at the last significant slash + char c = *slashp; + *slashp = '\0'; + + nsCOMPtr localFile; + nsresult rv = NS_NewNativeLocalFile(nsDependentCString(buffer), PR_TRUE, + getter_AddRefs(localFile)); + + // make buffer whole again + *slashp = c; + + if (NS_SUCCEEDED(rv) && localFile) + rv = CallQueryInterface(localFile, aParent); + return rv; +} + +/* + * The results of Exists, isWritable and isReadable are not cached. + */ + +NS_IMETHODIMP +nsLocalFile::Exists(PRBool *_retval) +{ + CHECK_mPath(); + NS_ENSURE_ARG_POINTER(_retval); + + *_retval = (access(mPath.get(), F_OK) == 0); + return NS_OK; +} + +#ifdef XP_BEOS +// access() is buggy in BeOS POSIX implementation, at least for BFS, using stat() instead +NS_IMETHODIMP +nsLocalFile::IsWritable(PRBool *_retval) +{ + CHECK_mPath(); + NS_ENSURE_ARG_POINTER(_retval); + struct stat buf; + *_retval = (stat(mPath.get(), &buf) == 0); + *_retval = *_retval && (buf.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH )); + if (*_retval || errno == EACCES) + return NS_OK; + return NSRESULT_FOR_ERRNO(); +} + +NS_IMETHODIMP +nsLocalFile::IsReadable(PRBool *_retval) +{ + CHECK_mPath(); + NS_ENSURE_ARG_POINTER(_retval); + struct stat buf; + *_retval = (stat(mPath.get(), &buf) == 0); + *_retval = *_retval && (buf.st_mode & (S_IRUSR | S_IRGRP | S_IROTH )); + if (*_retval || errno == EACCES) + return NS_OK; + return NSRESULT_FOR_ERRNO(); +} + +NS_IMETHODIMP +nsLocalFile::IsExecutable(PRBool *_retval) +{ + CHECK_mPath(); + NS_ENSURE_ARG_POINTER(_retval); + struct stat buf; + *_retval = (stat(mPath.get(), &buf) == 0); + *_retval = *_retval && (buf.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH )); + if (*_retval || errno == EACCES) + return NS_OK; + return NSRESULT_FOR_ERRNO(); +} +#else +NS_IMETHODIMP +nsLocalFile::IsWritable(PRBool *_retval) +{ + CHECK_mPath(); + NS_ENSURE_ARG_POINTER(_retval); + + *_retval = (access(mPath.get(), W_OK) == 0); + if (*_retval || errno == EACCES) + return NS_OK; + return NSRESULT_FOR_ERRNO(); +} + +NS_IMETHODIMP +nsLocalFile::IsReadable(PRBool *_retval) +{ + CHECK_mPath(); + NS_ENSURE_ARG_POINTER(_retval); + + *_retval = (access(mPath.get(), R_OK) == 0); + if (*_retval || errno == EACCES) + return NS_OK; + return NSRESULT_FOR_ERRNO(); +} + +NS_IMETHODIMP +nsLocalFile::IsExecutable(PRBool *_retval) +{ + CHECK_mPath(); + NS_ENSURE_ARG_POINTER(_retval); + + *_retval = (access(mPath.get(), X_OK) == 0); + if (*_retval || errno == EACCES) + return NS_OK; + return NSRESULT_FOR_ERRNO(); +} +#endif +NS_IMETHODIMP +nsLocalFile::IsDirectory(PRBool *_retval) +{ + NS_ENSURE_ARG_POINTER(_retval); + *_retval = PR_FALSE; + VALIDATE_STAT_CACHE(); + *_retval = S_ISDIR(mCachedStat.st_mode); + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::IsFile(PRBool *_retval) +{ + NS_ENSURE_ARG_POINTER(_retval); + *_retval = PR_FALSE; + VALIDATE_STAT_CACHE(); + *_retval = S_ISREG(mCachedStat.st_mode); + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::IsHidden(PRBool *_retval) +{ + NS_ENSURE_ARG_POINTER(_retval); + nsACString::const_iterator begin, end; + LocateNativeLeafName(begin, end); + *_retval = (*begin == '.'); + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::IsSymlink(PRBool *_retval) +{ + NS_ENSURE_ARG_POINTER(_retval); + CHECK_mPath(); + + struct stat symStat; + lstat(mPath.get(), &symStat); + *_retval=S_ISLNK(symStat.st_mode); + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::IsSpecial(PRBool *_retval) +{ + NS_ENSURE_ARG_POINTER(_retval); + VALIDATE_STAT_CACHE(); + *_retval = S_ISCHR(mCachedStat.st_mode) || + S_ISBLK(mCachedStat.st_mode) || +#ifdef S_ISSOCK + S_ISSOCK(mCachedStat.st_mode) || +#endif + S_ISFIFO(mCachedStat.st_mode); + + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::Equals(nsIFile *inFile, PRBool *_retval) +{ + NS_ENSURE_ARG(inFile); + NS_ENSURE_ARG_POINTER(_retval); + *_retval = PR_FALSE; + + nsresult rv; + nsCAutoString inPath; + + if (NS_FAILED(rv = inFile->GetNativePath(inPath))) + return rv; + + *_retval = !FILE_STRCMP(inPath.get(), mPath.get()); + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::Contains(nsIFile *inFile, PRBool recur, PRBool *_retval) +{ + CHECK_mPath(); + NS_ENSURE_ARG(inFile); + NS_ENSURE_ARG_POINTER(_retval); + + nsCAutoString inPath; + nsresult rv; + + if (NS_FAILED(rv = inFile->GetNativePath(inPath))) + return rv; + + *_retval = PR_FALSE; + + ssize_t len = mPath.Length(); + if (FILE_STRNCMP(mPath.get(), inPath.get(), len) == 0) { + // Now make sure that the |inFile|'s path has a separator at len, + // which implies that it has more components after len. + if (inPath[len] == '/') + *_retval = PR_TRUE; + } + + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::GetNativeTarget(nsACString &_retval) +{ + CHECK_mPath(); + _retval.Truncate(); + + struct stat symStat; + lstat(mPath.get(), &symStat); + if (!S_ISLNK(symStat.st_mode)) + return NS_ERROR_FILE_INVALID_PATH; + + PRInt64 targetSize64; + if (NS_FAILED(GetFileSizeOfLink(&targetSize64))) + return NS_ERROR_FAILURE; + + PRInt32 size; + LL_L2I(size, targetSize64); + char *target = (char *)nsMemory::Alloc(size + 1); + if (!target) + return NS_ERROR_OUT_OF_MEMORY; + + if (readlink(mPath.get(), target, (size_t)size) < 0) { + nsMemory::Free(target); + return NSRESULT_FOR_ERRNO(); + } + target[size] = '\0'; + + nsresult rv; + PRBool isSymlink; + nsCOMPtr self(this); + nsCOMPtr parent; + while (NS_SUCCEEDED(rv = self->GetParent(getter_AddRefs(parent)))) { + NS_ASSERTION(parent != nsnull, "no parent?!"); + + if (target[0] != '/') { + nsCOMPtr localFile(do_QueryInterface(parent, &rv)); + if (NS_FAILED(rv)) + break; + if (NS_FAILED(rv = localFile->AppendRelativeNativePath(nsDependentCString(target)))) + break; + if (NS_FAILED(rv = localFile->GetNativePath(_retval))) + break; + if (NS_FAILED(rv = parent->IsSymlink(&isSymlink))) + break; + self = parent; + } else { + nsCOMPtr localFile; + rv = NS_NewNativeLocalFile(nsDependentCString(target), PR_TRUE, + getter_AddRefs(localFile)); + if (NS_FAILED(rv)) + break; + if (NS_FAILED(rv = localFile->IsSymlink(&isSymlink))) + break; + _retval = target; // XXX can we avoid this buffer copy? + self = do_QueryInterface(localFile); + } + if (NS_FAILED(rv) || !isSymlink) + break; + + const nsPromiseFlatCString &flatRetval = PromiseFlatCString(_retval); + + // strip off any and all trailing '/' + PRInt32 len = strlen(target); + while (target[len-1] == '/' && len > 1) + target[--len] = '\0'; + if (lstat(flatRetval.get(), &symStat) < 0) { + rv = NSRESULT_FOR_ERRNO(); + break; + } + if (!S_ISLNK(symStat.st_mode)) { + rv = NS_ERROR_FILE_INVALID_PATH; + break; + } + size = symStat.st_size; + if (readlink(flatRetval.get(), target, size) < 0) { + rv = NSRESULT_FOR_ERRNO(); + break; + } + target[size] = '\0'; + + _retval.Truncate(); + } + + nsMemory::Free(target); + + if (NS_FAILED(rv)) + _retval.Truncate(); + return rv; +} + +/* attribute PRBool followLinks; */ +NS_IMETHODIMP +nsLocalFile::GetFollowLinks(PRBool *aFollowLinks) +{ + *aFollowLinks = PR_TRUE; + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::SetFollowLinks(PRBool aFollowLinks) +{ + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::GetDirectoryEntries(nsISimpleEnumerator **entries) +{ + nsDirEnumeratorUnix *dir = new nsDirEnumeratorUnix(); + if (!dir) + return NS_ERROR_OUT_OF_MEMORY; + + NS_ADDREF(dir); + nsresult rv = dir->Init(this, PR_FALSE); + if (NS_FAILED(rv)) { + *entries = nsnull; + NS_RELEASE(dir); + } else { + *entries = dir; // transfer reference + } + + return rv; +} + +NS_IMETHODIMP +nsLocalFile::Load(PRLibrary **_retval) +{ + CHECK_mPath(); + NS_ENSURE_ARG_POINTER(_retval); + + NS_TIMELINE_START_TIMER("PR_LoadLibrary"); + + *_retval = PR_LoadLibrary(mPath.get()); + + NS_TIMELINE_STOP_TIMER("PR_LoadLibrary"); + NS_TIMELINE_MARK_TIMER1("PR_LoadLibrary", mPath.get()); + + if (!*_retval) + return NS_ERROR_FAILURE; + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::GetPersistentDescriptor(nsACString &aPersistentDescriptor) +{ + return GetNativePath(aPersistentDescriptor); +} + +NS_IMETHODIMP +nsLocalFile::SetPersistentDescriptor(const nsACString &aPersistentDescriptor) +{ + return InitWithNativePath(aPersistentDescriptor); +} + +#ifdef XP_BEOS +NS_IMETHODIMP +nsLocalFile::Reveal() +{ + BPath bPath(mPath.get()); + bPath.GetParent(&bPath); + entry_ref ref; + get_ref_for_path(bPath.Path(),&ref); + BMessage message(B_REFS_RECEIVED); + message.AddRef("refs",&ref); + BMessenger messenger("application/x-vnd.Be-TRAK"); + messenger.SendMessage(&message); + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::Launch() +{ + entry_ref ref; + get_ref_for_path (mPath.get(), &ref); + be_roster->Launch (&ref); + + return NS_OK; +} +#else +NS_IMETHODIMP +nsLocalFile::Reveal() +{ + return NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +nsLocalFile::Launch() +{ + return NS_ERROR_FAILURE; +} +#endif + +nsresult +NS_NewNativeLocalFile(const nsACString &path, PRBool followSymlinks, nsILocalFile **result) +{ + nsLocalFile *file = new nsLocalFile(); + if (!file) + return NS_ERROR_OUT_OF_MEMORY; + NS_ADDREF(file); + + if (!path.IsEmpty()) { + nsresult rv = file->InitWithNativePath(path); + if (NS_FAILED(rv)) { + NS_RELEASE(file); + return rv; + } + } + *result = file; + return NS_OK; +} + +//----------------------------------------------------------------------------- +// unicode support +//----------------------------------------------------------------------------- + +#define SET_UCS(func, ucsArg) \ + { \ + nsCAutoString buf; \ + nsresult rv = NS_CopyUnicodeToNative(ucsArg, buf); \ + if (NS_FAILED(rv)) \ + return rv; \ + return (func)(buf); \ + } + +#define GET_UCS(func, ucsArg) \ + { \ + nsCAutoString buf; \ + nsresult rv = (func)(buf); \ + if (NS_FAILED(rv)) return rv; \ + return NS_CopyNativeToUnicode(buf, ucsArg); \ + } + +#define SET_UCS_2ARGS_2(func, opaqueArg, ucsArg) \ + { \ + nsCAutoString buf; \ + nsresult rv = NS_CopyUnicodeToNative(ucsArg, buf); \ + if (NS_FAILED(rv)) \ + return rv; \ + return (func)(opaqueArg, buf); \ + } + +// Unicode interface Wrapper +nsresult +nsLocalFile::InitWithPath(const nsAString &filePath) +{ + SET_UCS(InitWithNativePath, filePath); +} +nsresult +nsLocalFile::Append(const nsAString &node) +{ + SET_UCS(AppendNative, node); +} +nsresult +nsLocalFile::AppendRelativePath(const nsAString &node) +{ + SET_UCS(AppendRelativeNativePath, node); +} +nsresult +nsLocalFile::GetLeafName(nsAString &aLeafName) +{ + GET_UCS(GetNativeLeafName, aLeafName); +} +nsresult +nsLocalFile::SetLeafName(const nsAString &aLeafName) +{ + SET_UCS(SetNativeLeafName, aLeafName); +} +nsresult +nsLocalFile::GetPath(nsAString &_retval) +{ + return NS_CopyNativeToUnicode(mPath, _retval); +} +nsresult +nsLocalFile::CopyTo(nsIFile *newParentDir, const nsAString &newName) +{ + SET_UCS_2ARGS_2(CopyToNative , newParentDir, newName); +} +nsresult +nsLocalFile::CopyToFollowingLinks(nsIFile *newParentDir, const nsAString &newName) +{ + SET_UCS_2ARGS_2(CopyToFollowingLinksNative , newParentDir, newName); +} +nsresult +nsLocalFile::MoveTo(nsIFile *newParentDir, const nsAString &newName) +{ + SET_UCS_2ARGS_2(MoveToNative, newParentDir, newName); +} +nsresult +nsLocalFile::GetTarget(nsAString &_retval) +{ + GET_UCS(GetNativeTarget, _retval); +} +nsresult +NS_NewLocalFile(const nsAString &path, PRBool followLinks, nsILocalFile* *result) +{ + nsCAutoString buf; + nsresult rv = NS_CopyUnicodeToNative(path, buf); + if (NS_FAILED(rv)) + return rv; + return NS_NewNativeLocalFile(buf, followLinks, result); +} + +//----------------------------------------------------------------------------- +// global init/shutdown +//----------------------------------------------------------------------------- + +void +nsLocalFile::GlobalInit() +{ +} + +void +nsLocalFile::GlobalShutdown() +{ +} diff --git a/src/libs/xpcom18a4/xpcom/io/nsLocalFileUnix.h b/src/libs/xpcom18a4/xpcom/io/nsLocalFileUnix.h new file mode 100644 index 00000000..a994e1a1 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsLocalFileUnix.h @@ -0,0 +1,132 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mike Shaver + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* + * Implementation of nsIFile for ``Unixy'' systems. + */ + +#ifndef _nsLocalFileUNIX_H_ +#define _nsLocalFileUNIX_H_ + +#include +#include +#include + +#include "nscore.h" +#include "nsString.h" +#include "nsReadableUtils.h" + +/** + * we need these for statfs() + */ +#ifdef HAVE_SYS_STATVFS_H + #if defined(__osf__) && defined(__DECCXX) + extern "C" int statvfs(const char *, struct statvfs *); + #endif + #include +#endif + +#ifdef HAVE_SYS_STATFS_H + #include +#endif + +#ifdef HAVE_STATVFS + #define STATFS statvfs +#else + #define STATFS statfs +#endif + +// so we can statfs on freebsd +#if defined(__FreeBSD__) + #define HAVE_SYS_STATFS_H + #define STATFS statfs + #include + #include +#endif + +class NS_COM nsLocalFile : public nsILocalFile +{ +public: + NS_DEFINE_STATIC_CID_ACCESSOR(NS_LOCAL_FILE_CID) + + nsLocalFile(); + + static NS_METHOD nsLocalFileConstructor(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr); + + // nsISupports + NS_DECL_ISUPPORTS + + // nsIFile + NS_DECL_NSIFILE + + // nsILocalFile + NS_DECL_NSILOCALFILE + +public: + static void GlobalInit(); + static void GlobalShutdown(); + +private: + nsLocalFile(const nsLocalFile& other); + ~nsLocalFile() {} + +protected: + struct stat mCachedStat; + nsCString mPath; + PRPackedBool mHaveCachedStat; + + void LocateNativeLeafName(nsACString::const_iterator &, + nsACString::const_iterator &); + + nsresult CopyDirectoryTo(nsIFile *newParent); + nsresult CreateAllAncestors(PRUint32 permissions); + nsresult GetNativeTargetPathName(nsIFile *newParent, + const nsACString &newName, + nsACString &_retval); + + void InvalidateCache() { + mHaveCachedStat = PR_FALSE; + } + nsresult FillStatCache(); + + nsresult CreateAndKeepOpen(PRUint32 type, PRIntn flags, + PRUint32 permissions, PRFileDesc **_retval); +}; + +#endif /* _nsLocalFileUNIX_H_ */ diff --git a/src/libs/xpcom18a4/xpcom/io/nsLocalFileWin.cpp b/src/libs/xpcom18a4/xpcom/io/nsLocalFileWin.cpp new file mode 100644 index 00000000..63414fc3 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsLocalFileWin.cpp @@ -0,0 +1,2440 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Doug Turner + * Dean Tessman + * Brodie Thiesfield + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsCOMPtr.h" +#include "nsMemory.h" + +#include "nsLocalFile.h" +#include "nsNativeCharsetUtils.h" + +#include "nsISimpleEnumerator.h" +#include "nsIComponentManager.h" +#include "prtypes.h" +#include "prio.h" + +#include "nsXPIDLString.h" +#include "nsReadableUtils.h" + +#include +#include + +#include "shellapi.h" +#include "shlguid.h" + +#include +#include +#include +#include + +#include "nsXPIDLString.h" +#include "prproces.h" +#include "nsITimelineService.h" + +#include "nsAutoLock.h" +#include "SpecialSystemDirectory.h" + +// _mbsstr isn't declared in w32api headers but it's there in the libs +#ifdef __MINGW32__ +extern "C" { +unsigned char *_mbsstr( const unsigned char *str, + const unsigned char *substr ); +} +#endif + +class nsDriveEnumerator : public nsISimpleEnumerator +{ +public: + nsDriveEnumerator(); + virtual ~nsDriveEnumerator(); + NS_DECL_ISUPPORTS + NS_DECL_NSISIMPLEENUMERATOR + nsresult Init(); +private: + /* mDrives and mLetter share data + * Init sets them. + * HasMoreElements reads mLetter. + * GetNext advances mLetter. + */ + nsCString mDrives; + const char *mLetter; +}; + +//---------------------------------------------------------------------------- +// short cut resolver +//---------------------------------------------------------------------------- + +class ShortcutResolver +{ +public: + ShortcutResolver(); + // nonvirtual since we're not subclassed + ~ShortcutResolver(); + + nsresult Init(); + nsresult Resolve(const WCHAR* in, char* out); + +private: + PRLock* mLock; + IPersistFile* mPersistFile; + IShellLink* mShellLink; +}; + +ShortcutResolver::ShortcutResolver() +{ + mLock = nsnull; + mPersistFile = nsnull; + mShellLink = nsnull; +} + +ShortcutResolver::~ShortcutResolver() +{ + if (mLock) + PR_DestroyLock(mLock); + + // Release the pointer to the IPersistFile interface. + if (mPersistFile) + mPersistFile->Release(); + + // Release the pointer to the IShellLink interface. + if(mShellLink) + mShellLink->Release(); + + CoUninitialize(); +} + +nsresult +ShortcutResolver::Init() +{ + CoInitialize(NULL); // FIX: we should probably move somewhere higher up during startup + + mLock = PR_NewLock(); + if (!mLock) + return NS_ERROR_FAILURE; + + HRESULT hres = CoCreateInstance(CLSID_ShellLink, + NULL, + CLSCTX_INPROC_SERVER, + IID_IShellLink, + (void**)&mShellLink); + if (SUCCEEDED(hres)) + { + // Get a pointer to the IPersistFile interface. + hres = mShellLink->QueryInterface(IID_IPersistFile, (void**)&mPersistFile); + } + + if (mPersistFile == nsnull || mShellLink == nsnull) + return NS_ERROR_FAILURE; + + return NS_OK; +} + +// |out| must be an allocated buffer of size MAX_PATH +nsresult +ShortcutResolver::Resolve(const WCHAR* in, char* out) +{ + nsAutoLock lock(mLock); + + // see if we can Load the path. + HRESULT hres = mPersistFile->Load(in, STGM_READ); + + if (FAILED(hres)) + return NS_ERROR_FAILURE; + + // Resolve the link. + hres = mShellLink->Resolve(nsnull, SLR_NO_UI ); + + if (FAILED(hres)) + return NS_ERROR_FAILURE; + + WIN32_FIND_DATA wfd; + // Get the path to the link target. + hres = mShellLink->GetPath( out, MAX_PATH, &wfd, SLGP_UNCPRIORITY ); + if (FAILED(hres)) + return NS_ERROR_FAILURE; + return NS_OK; +} + +static ShortcutResolver * gResolver = nsnull; + +static nsresult NS_CreateShortcutResolver() +{ + gResolver = new ShortcutResolver(); + if (!gResolver) + return NS_ERROR_OUT_OF_MEMORY; + + return gResolver->Init(); +} + +static void NS_DestroyShortcutResolver() +{ + delete gResolver; + gResolver = nsnull; +} + + +//----------------------------------------------------------------------------- +// static helper functions +//----------------------------------------------------------------------------- + +// certainly not all the error that can be +// encountered, but many of them common ones +static nsresult ConvertWinError(DWORD winErr) +{ + nsresult rv; + + switch (winErr) + { + case ERROR_FILE_NOT_FOUND: + case ERROR_PATH_NOT_FOUND: + case ERROR_INVALID_DRIVE: + rv = NS_ERROR_FILE_NOT_FOUND; + break; + case ERROR_ACCESS_DENIED: + case ERROR_NOT_SAME_DEVICE: + rv = NS_ERROR_FILE_ACCESS_DENIED; + break; + case ERROR_NOT_ENOUGH_MEMORY: + case ERROR_INVALID_BLOCK: + case ERROR_INVALID_HANDLE: + case ERROR_ARENA_TRASHED: + rv = NS_ERROR_OUT_OF_MEMORY; + break; + case ERROR_CURRENT_DIRECTORY: + rv = NS_ERROR_FILE_DIR_NOT_EMPTY; + break; + case ERROR_WRITE_PROTECT: + rv = NS_ERROR_FILE_READ_ONLY; + break; + case ERROR_HANDLE_DISK_FULL: + rv = NS_ERROR_FILE_TOO_BIG; + break; + case ERROR_FILE_EXISTS: + case ERROR_ALREADY_EXISTS: + case ERROR_CANNOT_MAKE: + rv = NS_ERROR_FILE_ALREADY_EXISTS; + break; + case 0: + rv = NS_OK; + break; + default: + rv = NS_ERROR_FAILURE; + break; + } + return rv; +} + +// definition of INVALID_SET_FILE_POINTER from VC.NET header files +// it doesn't appear to be defined by VC6 +#ifndef INVALID_SET_FILE_POINTER +# define INVALID_SET_FILE_POINTER ((DWORD)-1) +#endif +// same goes for INVALID_FILE_ATTRIBUTES +#ifndef INVALID_FILE_ATTRIBUTES +# define INVALID_FILE_ATTRIBUTES ((DWORD)-1) +#endif + +// as suggested in the MSDN documentation on SetFilePointer +static __int64 +MyFileSeek64(HANDLE aHandle, __int64 aDistance, DWORD aMoveMethod) +{ + LARGE_INTEGER li; + + li.QuadPart = aDistance; + li.LowPart = SetFilePointer(aHandle, li.LowPart, &li.HighPart, aMoveMethod); + if (li.LowPart == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR) + { + li.QuadPart = -1; + } + + return li.QuadPart; +} + +static PRBool +IsShortcutPath(const char *path) +{ + // Under Windows, the shortcuts are just files with a ".lnk" extension. + // Note also that we don't resolve links in the middle of paths. + // i.e. "c:\foo.lnk\bar.txt" is invalid. + NS_ABORT_IF_FALSE(path, "don't pass nulls"); + const char * ext = (const char *) _mbsrchr((const unsigned char *)path, '.'); + if (!ext || 0 != stricmp(ext + 1, "lnk")) + return PR_FALSE; + return PR_TRUE; +} + +//----------------------------------------------------------------------------- +// nsDirEnumerator +//----------------------------------------------------------------------------- + +class nsDirEnumerator : public nsISimpleEnumerator +{ + public: + + NS_DECL_ISUPPORTS + + nsDirEnumerator() : mDir(nsnull) + { + } + + nsresult Init(nsILocalFile* parent) + { + nsCAutoString filepath; + parent->GetNativeTarget(filepath); + + if (filepath.IsEmpty()) + { + parent->GetNativePath(filepath); + } + + if (filepath.IsEmpty()) + { + return NS_ERROR_UNEXPECTED; + } + + mDir = PR_OpenDir(filepath.get()); + if (mDir == nsnull) // not a directory? + return NS_ERROR_FAILURE; + + mParent = parent; + return NS_OK; + } + + NS_IMETHOD HasMoreElements(PRBool *result) + { + nsresult rv; + if (mNext == nsnull && mDir) + { + PRDirEntry* entry = PR_ReadDir(mDir, PR_SKIP_BOTH); + if (entry == nsnull) + { + // end of dir entries + + PRStatus status = PR_CloseDir(mDir); + if (status != PR_SUCCESS) + return NS_ERROR_FAILURE; + mDir = nsnull; + + *result = PR_FALSE; + return NS_OK; + } + + nsCOMPtr file; + rv = mParent->Clone(getter_AddRefs(file)); + if (NS_FAILED(rv)) + return rv; + + rv = file->AppendNative(nsDependentCString(entry->name)); + if (NS_FAILED(rv)) + return rv; + + // make sure the thing exists. If it does, try the next one. + PRBool exists; + rv = file->Exists(&exists); + if (NS_FAILED(rv) || !exists) + { + return HasMoreElements(result); + } + + mNext = do_QueryInterface(file); + } + *result = mNext != nsnull; + return NS_OK; + } + + NS_IMETHOD GetNext(nsISupports **result) + { + nsresult rv; + PRBool hasMore; + rv = HasMoreElements(&hasMore); + if (NS_FAILED(rv)) return rv; + + *result = mNext; // might return nsnull + NS_IF_ADDREF(*result); + + mNext = nsnull; + return NS_OK; + } + + // dtor can be non-virtual since there are no subclasses, but must be + // public to use the class on the stack. + ~nsDirEnumerator() + { + if (mDir) + { + PRStatus status = PR_CloseDir(mDir); + NS_ASSERTION(status == PR_SUCCESS, "close failed"); + } + } + + protected: + PRDir* mDir; + nsCOMPtr mParent; + nsCOMPtr mNext; +}; + +NS_IMPL_ISUPPORTS1(nsDirEnumerator, nsISimpleEnumerator) + + +//----------------------------------------------------------------------------- +// nsLocalFile +//----------------------------------------------------------------------------- + +nsLocalFile::nsLocalFile() + : mFollowSymlinks(PR_FALSE) +{ + MakeDirty(); + memset(&mFileInfo64, 0, sizeof(mFileInfo64)); +} + +NS_METHOD +nsLocalFile::nsLocalFileConstructor(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr) +{ + NS_ENSURE_ARG_POINTER(aInstancePtr); + NS_ENSURE_NO_AGGREGATION(outer); + + nsLocalFile* inst = new nsLocalFile(); + if (inst == NULL) + return NS_ERROR_OUT_OF_MEMORY; + + nsresult rv = inst->QueryInterface(aIID, aInstancePtr); + if (NS_FAILED(rv)) + { + delete inst; + return rv; + } + return NS_OK; +} + + +//----------------------------------------------------------------------------- +// nsLocalFile::nsISupports +//----------------------------------------------------------------------------- + +NS_IMPL_THREADSAFE_ISUPPORTS2(nsLocalFile, nsILocalFile, nsIFile) + + +//----------------------------------------------------------------------------- +// nsLocalFile +//----------------------------------------------------------------------------- + +nsLocalFile::nsLocalFile(const nsLocalFile& other) + : mDirty(other.mDirty) + , mFollowSymlinks(other.mFollowSymlinks) + , mWorkingPath(other.mWorkingPath) + , mResolvedPath(other.mResolvedPath) + , mFileInfo64(other.mFileInfo64) +{ +} + +// Resolve the shortcut file from mWorkingPath and write the path +// it points to into mResolvedPath. +nsresult +nsLocalFile::ResolveShortcut() +{ + // we can't do anything without the resolver + if (!gResolver) + return NS_ERROR_FAILURE; + + // allocate the memory for the result of the resolution + nsAutoString ucsBuf; + NS_CopyNativeToUnicode(mWorkingPath, ucsBuf); + + mResolvedPath.SetLength(MAX_PATH); + char *resolvedPath = mResolvedPath.BeginWriting(); + + // resolve this shortcut + nsresult rv = gResolver->Resolve(ucsBuf.get(), resolvedPath); + + size_t len = NS_FAILED(rv) ? 0 : strlen(resolvedPath); + mResolvedPath.SetLength(len); + + return rv; +} + +// Resolve any shortcuts and stat the resolved path. After a successful return +// the path is guaranteed valid and the members of mFileInfo64 can be used. +nsresult +nsLocalFile::ResolveAndStat() +{ + // if we aren't dirty then we are already done + if (!mDirty) + return NS_OK; + + // we can't resolve/stat anything that isn't a valid NSPR addressable path + if (mWorkingPath.IsEmpty()) + return NS_ERROR_FILE_INVALID_PATH; + + // this is usually correct + mResolvedPath.Assign(mWorkingPath); + + // slutty hack designed to work around bug 134796 until it is fixed + char temp[4]; + const char *nsprPath = mWorkingPath.get(); + if (mWorkingPath.Length() == 2 && mWorkingPath.CharAt(1) == ':') + { + temp[0] = mWorkingPath[0]; + temp[1] = mWorkingPath[1]; + temp[2] = '\\'; + temp[3] = '\0'; + nsprPath = temp; + } + + // first we will see if the working path exists. If it doesn't then + // there is nothing more that can be done + PRStatus status = PR_GetFileInfo64(nsprPath, &mFileInfo64); + if (status != PR_SUCCESS) + return NS_ERROR_FILE_NOT_FOUND; + + // if this isn't a shortcut file or we aren't following symlinks then we're done + if (!mFollowSymlinks + || mFileInfo64.type != PR_FILE_FILE + || !IsShortcutPath(mWorkingPath.get())) + { + mDirty = PR_FALSE; + return NS_OK; + } + + // we need to resolve this shortcut to what it points to, this will + // set mResolvedPath. Even if it fails we need to have the resolved + // path equal to working path for those functions that always use + // the resolved path. + nsresult rv = ResolveShortcut(); + if (NS_FAILED(rv)) + { + mResolvedPath.Assign(mWorkingPath); + return rv; + } + + // get the details of the resolved path + status = PR_GetFileInfo64(mResolvedPath.get(), &mFileInfo64); + if (status != PR_SUCCESS) + return NS_ERROR_FILE_NOT_FOUND; + + mDirty = PR_FALSE; + return NS_OK; +} + + +//----------------------------------------------------------------------------- +// nsLocalFile::nsIFile,nsILocalFile +//----------------------------------------------------------------------------- + +NS_IMETHODIMP +nsLocalFile::Clone(nsIFile **file) +{ + // Just copy-construct ourselves + *file = new nsLocalFile(*this); + if (!*file) + return NS_ERROR_OUT_OF_MEMORY; + + NS_ADDREF(*file); + + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::InitWithNativePath(const nsACString &filePath) +{ + MakeDirty(); + + nsACString::const_iterator begin, end; + filePath.BeginReading(begin); + filePath.EndReading(end); + + // input string must not be empty + if (begin == end) + return NS_ERROR_FAILURE; + + char firstChar = *begin; + char secondChar = *(++begin); + + // just do a sanity check. if it has any forward slashes, it is not a Native path + // on windows. Also, it must have a colon at after the first char. + + char *path = nsnull; + PRInt32 pathLen = 0; + + if ( ( (secondChar == ':') && !FindCharInReadable('/', begin, end) ) || // normal path + ( (firstChar == '\\') && (secondChar == '\\') ) ) // network path + { + // This is a native path + path = ToNewCString(filePath); + pathLen = filePath.Length(); + } + + if (path == nsnull) + return NS_ERROR_FILE_UNRECOGNIZED_PATH; + + // kill any trailing '\' provided it isn't the second char of DBCS + PRInt32 len = pathLen - 1; + if (path[len] == '\\' && + (!::IsDBCSLeadByte(path[len-1]) || + _mbsrchr((const unsigned char *)path, '\\') == (const unsigned char *)path+len)) + { + path[len] = '\0'; + pathLen = len; + } + + mWorkingPath.Adopt(path, pathLen); + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::OpenNSPRFileDesc(PRInt32 flags, PRInt32 mode, PRFileDesc **_retval) +{ + nsresult rv = ResolveAndStat(); + if (NS_FAILED(rv) && rv != NS_ERROR_FILE_NOT_FOUND) + return rv; + + *_retval = PR_Open(mResolvedPath.get(), flags, mode); + if (*_retval) + return NS_OK; + + return NS_ErrorAccordingToNSPR(); +} + + +NS_IMETHODIMP +nsLocalFile::OpenANSIFileDesc(const char *mode, FILE * *_retval) +{ + nsresult rv = ResolveAndStat(); + if (NS_FAILED(rv) && rv != NS_ERROR_FILE_NOT_FOUND) + return rv; + + *_retval = fopen(mResolvedPath.get(), mode); + if (*_retval) + return NS_OK; + + return NS_ERROR_FAILURE; +} + + + +NS_IMETHODIMP +nsLocalFile::Create(PRUint32 type, PRUint32 attributes) +{ + if (type != NORMAL_FILE_TYPE && type != DIRECTORY_TYPE) + return NS_ERROR_FILE_UNKNOWN_TYPE; + + nsresult rv = ResolveAndStat(); + if (NS_FAILED(rv) && rv != NS_ERROR_FILE_NOT_FOUND) + return rv; + + // create directories to target + // + // A given local file can be either one of these forms: + // + // - normal: X:\some\path\on\this\drive + // ^--- start here + // + // - UNC path: \\machine\volume\some\path\on\this\drive + // ^--- start here + // + // Skip the first 'X:\' for the first form, and skip the first full + // '\\machine\volume\' segment for the second form. + + const unsigned char* path = (const unsigned char*) mResolvedPath.get(); + if (path[0] == '\\' && path[1] == '\\') + { + // dealing with a UNC path here; skip past '\\machine\' + path = _mbschr(path + 2, '\\'); + if (!path) + return NS_ERROR_FILE_INVALID_PATH; + ++path; + } + + // search for first slash after the drive (or volume) name + unsigned char* slash = _mbschr(path, '\\'); + + if (slash) + { + // skip the first '\\' + ++slash; + slash = _mbschr(slash, '\\'); + + while (slash) + { + *slash = '\0'; + + if (!CreateDirectoryA(mResolvedPath.get(), NULL)) { + rv = ConvertWinError(GetLastError()); + // perhaps the base path already exists, or perhaps we don't have + // permissions to create the directory. NOTE: access denied could + // occur on a parent directory even though it exists. + if (rv != NS_ERROR_FILE_ALREADY_EXISTS && + rv != NS_ERROR_FILE_ACCESS_DENIED) + return rv; + } + *slash = '\\'; + ++slash; + slash = _mbschr(slash, '\\'); + } + } + + if (type == NORMAL_FILE_TYPE) + { + PRFileDesc* file = PR_Open(mResolvedPath.get(), PR_RDONLY | PR_CREATE_FILE | PR_APPEND | PR_EXCL, attributes); + if (!file) return NS_ERROR_FILE_ALREADY_EXISTS; + + PR_Close(file); + return NS_OK; + } + + if (type == DIRECTORY_TYPE) + { + if (!CreateDirectoryA(mResolvedPath.get(), NULL)) + return ConvertWinError(GetLastError()); + else + return NS_OK; + } + + return NS_ERROR_FILE_UNKNOWN_TYPE; +} + +NS_IMETHODIMP +nsLocalFile::AppendNative(const nsACString &node) +{ + // append this path, multiple components are not permitted + return AppendNativeInternal(PromiseFlatCString(node), PR_FALSE); +} + +NS_IMETHODIMP +nsLocalFile::AppendRelativeNativePath(const nsACString &node) +{ + // append this path, multiple components are permitted + return AppendNativeInternal(PromiseFlatCString(node), PR_TRUE); +} + +nsresult +nsLocalFile::AppendNativeInternal(const nsAFlatCString &node, PRBool multipleComponents) +{ + if (node.IsEmpty()) + return NS_OK; + + // check the relative path for validity + const unsigned char * nodePath = (const unsigned char *) node.get(); + if (*nodePath == '\\' // can't start with an '\' + || _mbschr(nodePath, '/') // can't contain / + || node.Equals("..")) // can't be .. + return NS_ERROR_FILE_UNRECOGNIZED_PATH; + + if (multipleComponents) + { + // can't contain .. as a path component. Ensure that the valid components + // "foo..foo", "..foo", and "foo.." are not falsely detected, but the invalid + // paths "..\", "foo\..", "foo\..\foo", "..\foo", etc are. + unsigned char * doubleDot = _mbsstr(nodePath, (unsigned char *)"\\.."); + while (doubleDot) + { + doubleDot += 3; + if (*doubleDot == '\0' || *doubleDot == '\\') + return NS_ERROR_FILE_UNRECOGNIZED_PATH; + doubleDot = _mbsstr(doubleDot, (unsigned char *)"\\.."); + } + if (0 == _mbsncmp(nodePath, (unsigned char *)"..\\", 3)) // catches the remaining cases of prefixes + return NS_ERROR_FILE_UNRECOGNIZED_PATH; + } + else if (_mbschr(nodePath, '\\')) // single components can't contain '\' + return NS_ERROR_FILE_UNRECOGNIZED_PATH; + + MakeDirty(); + + mWorkingPath.Append(NS_LITERAL_CSTRING("\\") + node); + + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::Normalize() +{ + // XXX See bug 187957 comment 18 for possible problems with this implementation. + + if (mWorkingPath.IsEmpty()) + return NS_OK; + + // work in unicode for ease + nsAutoString path; + NS_CopyNativeToUnicode(mWorkingPath, path); + + // find the index of the root backslash for the path. Everything before + // this is considered fully normalized and cannot be ascended beyond + // using ".." For a local drive this is the first slash (e.g. "c:\"). + // For a UNC path it is the slash following the share name + // (e.g. "\\server\share\"). + PRInt32 rootIdx = 2; // default to local drive + if (path.First() == '\\') // if a share then calculate the rootIdx + { + rootIdx = path.FindChar('\\', 2); // skip \\ in front of the server + if (rootIdx == kNotFound) + return NS_OK; // already normalized + rootIdx = path.FindChar('\\', rootIdx+1); + if (rootIdx == kNotFound) + return NS_OK; // already normalized + } + else if (path.CharAt(rootIdx) != '\\') + { + // The path has been specified relative to the current working directory + // for that drive. To normalize it, the current working directory for + // that drive needs to be inserted before the supplied relative path + // which will provide an absolute path (and the rootIdx will still be 2). + char cwd[MAX_PATH]; + char * pcwd = cwd; + int drive = toupper(path.First()) - 'A' + 1; + if (!_getdcwd(drive, pcwd, MAX_PATH)) + pcwd = _getdcwd(drive, 0, 0); + if (!pcwd) + return NS_ERROR_OUT_OF_MEMORY; + + nsAutoString currentDir; + NS_CopyNativeToUnicode(nsDependentCString(pcwd), currentDir); + if (pcwd != cwd) + free(pcwd); + + if (currentDir.Last() == '\\') + path.Replace(0, 2, currentDir); + else + path.Replace(0, 2, currentDir + NS_LITERAL_STRING("\\")); + } + NS_POSTCONDITION(0 < rootIdx && rootIdx < (PRInt32)path.Length(), "rootIdx is invalid"); + NS_POSTCONDITION(path.CharAt(rootIdx) == '\\', "rootIdx is invalid"); + + // if there is nothing following the root path then it is already normalized + if (rootIdx + 1 == (PRInt32)path.Length()) + return NS_OK; + + // assign the root + nsAutoString normal; + const PRUnichar * pathBuffer = path.get(); // simplify access to the buffer + normal.SetCapacity(path.Length()); // it won't ever grow longer + normal.Assign(pathBuffer, rootIdx); + + // Normalize the path components. The actions taken are: + // + // "\\" condense to single backslash + // "." remove from path + // ".." up a directory + // "..." remove from path (any number of dots > 2) + // + // The last form is something that Windows 95 and 98 supported and + // is a shortcut for changing up multiple directories. Windows XP + // and ilk ignore it in a path, as is done here. + PRInt32 len, begin, end = rootIdx; + while (end < (PRInt32)path.Length()) + { + // find the current segment (text between the backslashes) to + // be examined, this will set the following variables: + // begin == index of first char in segment + // end == index 1 char after last char in segment + // len == length of segment + begin = end + 1; + end = path.FindChar('\\', begin); + if (end == kNotFound) + end = path.Length(); + len = end - begin; + + // ignore double backslashes + if (len == 0) + continue; + + // len != 0, and interesting paths always begin with a dot + if (pathBuffer[begin] == '.') + { + // ignore single dots + if (len == 1) + continue; + + // handle multiple dots + if (len >= 2 && pathBuffer[begin+1] == '.') + { + // back up a path component on double dot + if (len == 2) + { + PRInt32 prev = normal.RFindChar('\\'); + if (prev >= rootIdx) + normal.Truncate(prev); + continue; + } + + // length is > 2 and the first two characters are dots. + // if the rest of the string is dots, then ignore it. + int idx = len - 1; + for (; idx >= 2; --idx) + { + if (pathBuffer[begin+idx] != '.') + break; + } + + // this is true if the loop above didn't break + // and all characters in this segment are dots. + if (idx < 2) + continue; + } + } + + // add the current component to the path, including the preceding backslash + normal.Append(pathBuffer + begin - 1, len + 1); + } + + NS_CopyUnicodeToNative(normal, mWorkingPath); + MakeDirty(); + + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::GetNativeLeafName(nsACString &aLeafName) +{ + aLeafName.Truncate(); + + const char* temp = mWorkingPath.get(); + if(temp == nsnull) + return NS_ERROR_FILE_UNRECOGNIZED_PATH; + + const char* leaf = (const char*) _mbsrchr((const unsigned char*) temp, '\\'); + + // if the working path is just a node without any lashes. + if (leaf == nsnull) + leaf = temp; + else + leaf++; + + aLeafName.Assign(leaf); + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::SetNativeLeafName(const nsACString &aLeafName) +{ + MakeDirty(); + + const unsigned char* temp = (const unsigned char*) mWorkingPath.get(); + if(temp == nsnull) + return NS_ERROR_FILE_UNRECOGNIZED_PATH; + + // cannot use nsCString::RFindChar() due to 0x5c problem + PRInt32 offset = (PRInt32) (_mbsrchr(temp, '\\') - temp); + if (offset) + { + mWorkingPath.Truncate(offset+1); + } + mWorkingPath.Append(aLeafName); + + return NS_OK; +} + + +NS_IMETHODIMP +nsLocalFile::GetNativePath(nsACString &_retval) +{ + _retval = mWorkingPath; + return NS_OK; +} + +nsresult +nsLocalFile::CopySingleFile(nsIFile *sourceFile, nsIFile *destParent, const nsACString &newName, + PRBool followSymlinks, PRBool move) +{ + nsresult rv; + nsCAutoString filePath; + + // get the path that we are going to copy to. + // Since windows does not know how to auto + // resolve shortcuts, we must work with the + // target. + nsCAutoString destPath; + destParent->GetNativeTarget(destPath); + + destPath.Append("\\"); + + if (newName.IsEmpty()) + { + nsCAutoString aFileName; + sourceFile->GetNativeLeafName(aFileName); + destPath.Append(aFileName); + } + else + { + destPath.Append(newName); + } + + + if (followSymlinks) + { + rv = sourceFile->GetNativeTarget(filePath); + if (filePath.IsEmpty()) + rv = sourceFile->GetNativePath(filePath); + } + else + { + rv = sourceFile->GetNativePath(filePath); + } + + if (NS_FAILED(rv)) + return rv; + + int copyOK; + + if (!move) + copyOK = CopyFile(filePath.get(), destPath.get(), PR_TRUE); + else + { + // What we have to do is check to see if the destPath exists. If it + // does, we have to move it out of the say so that MoveFile will + // succeed. However, we don't want to just remove it since MoveFile + // can fail leaving us without a file. + + nsCAutoString backup; + PRFileInfo64 fileInfo64; + PRStatus status = PR_GetFileInfo64(destPath.get(), &fileInfo64); + if (status == PR_SUCCESS) + { + + // the file exists. Check to make sure it is not a directory, + // then move it out of the way. + if (fileInfo64.type == PR_FILE_FILE) + { + backup.Append(destPath); + backup.Append(".moztmp"); + + // remove any existing backup file that we may already have. + // maybe we should be doing some kind of unique naming here, + // but why bother. + remove(backup.get()); + + // move destination file to backup file + copyOK = MoveFile(destPath.get(), backup.get()); + if (!copyOK) + { + // I guess we can't do the backup copy, so return. + rv = ConvertWinError(GetLastError()); + return rv; + } + } + } + // move source file to destination file + copyOK = MoveFile(filePath.get(), destPath.get()); + + if (!backup.IsEmpty()) + { + if (copyOK) + { + // remove the backup copy. + remove(backup.get()); + } + else + { + // restore backup + int backupOk = MoveFile(backup.get(), destPath.get()); + NS_ASSERTION(backupOk, "move backup failed"); + } + } + } + if (!copyOK) // CopyFile and MoveFile returns non-zero if succeeds (backward if you ask me). + rv = ConvertWinError(GetLastError()); + + return rv; +} + + +nsresult +nsLocalFile::CopyMove(nsIFile *aParentDir, const nsACString &newName, PRBool followSymlinks, PRBool move) +{ + nsCOMPtr newParentDir = aParentDir; + // check to see if this exists, otherwise return an error. + // we will check this by resolving. If the user wants us + // to follow links, then we are talking about the target, + // hence we can use the |followSymlinks| parameter. + nsresult rv = ResolveAndStat(); + if (NS_FAILED(rv)) + return rv; + + if (!newParentDir) + { + // no parent was specified. We must rename. + + if (newName.IsEmpty()) + return NS_ERROR_INVALID_ARG; + + rv = GetParent(getter_AddRefs(newParentDir)); + if (NS_FAILED(rv)) + return rv; + } + + if (!newParentDir) + return NS_ERROR_FILE_DESTINATION_NOT_DIR; + + // make sure it exists and is a directory. Create it if not there. + PRBool exists; + newParentDir->Exists(&exists); + if (!exists) + { + rv = newParentDir->Create(DIRECTORY_TYPE, 0644); // TODO, what permissions should we use + if (NS_FAILED(rv)) + return rv; + } + else + { + PRBool isDir; + newParentDir->IsDirectory(&isDir); + if (isDir == PR_FALSE) + { + if (followSymlinks) + { + PRBool isLink; + newParentDir->IsSymlink(&isLink); + if (isLink) + { + nsCAutoString target; + newParentDir->GetNativeTarget(target); + + nsCOMPtr realDest = new nsLocalFile(); + if (realDest == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + + rv = realDest->InitWithNativePath(target); + + if (NS_FAILED(rv)) + return rv; + + return CopyMove(realDest, newName, followSymlinks, move); + } + } + else + { + return NS_ERROR_FILE_DESTINATION_NOT_DIR; + } + } + } + + // check to see if we are a directory, if so enumerate it. + + PRBool isDir; + IsDirectory(&isDir); + PRBool isSymlink; + IsSymlink(&isSymlink); + + if (!isDir || (isSymlink && !followSymlinks)) + { + rv = CopySingleFile(this, newParentDir, newName, followSymlinks, move); + if (NS_FAILED(rv)) + return rv; + } + else + { + // create a new target destination in the new parentDir; + nsCOMPtr target; + rv = newParentDir->Clone(getter_AddRefs(target)); + + if (NS_FAILED(rv)) + return rv; + + nsCAutoString allocatedNewName; + if (newName.IsEmpty()) + { + PRBool isLink; + IsSymlink(&isLink); + if (isLink) + { + nsCAutoString temp; + GetNativeTarget(temp); + const char* leaf = (const char*) _mbsrchr((const unsigned char*) temp.get(), '\\'); + if (leaf[0] == '\\') + leaf++; + allocatedNewName = leaf; + } + else + { + GetNativeLeafName(allocatedNewName);// this should be the leaf name of the + } + } + else + { + allocatedNewName = newName; + } + + rv = target->AppendNative(allocatedNewName); + if (NS_FAILED(rv)) + return rv; + + allocatedNewName.Truncate(); + + // check if the destination directory already exists + target->Exists(&exists); + if (!exists) + { + // if the destination directory cannot be created, return an error + rv = target->Create(DIRECTORY_TYPE, 0644); // TODO, what permissions should we use + if (NS_FAILED(rv)) + return rv; + } + else + { + // check if the destination directory is writable and empty + PRBool isWritable; + + target->IsWritable(&isWritable); + if (!isWritable) + return NS_ERROR_FILE_ACCESS_DENIED; + + nsCOMPtr targetIterator; + rv = target->GetDirectoryEntries(getter_AddRefs(targetIterator)); + + PRBool more; + targetIterator->HasMoreElements(&more); + // return error if target directory is not empty + if (more) + return NS_ERROR_FILE_DIR_NOT_EMPTY; + } + + nsDirEnumerator dirEnum; + + rv = dirEnum.Init(this); + if (NS_FAILED(rv)) { + NS_WARNING("dirEnum initalization failed"); + return rv; + } + + PRBool more; + while (NS_SUCCEEDED(dirEnum.HasMoreElements(&more)) && more) + { + nsCOMPtr item; + nsCOMPtr file; + dirEnum.GetNext(getter_AddRefs(item)); + file = do_QueryInterface(item); + if (file) + { + PRBool isDir, isLink; + + file->IsDirectory(&isDir); + file->IsSymlink(&isLink); + + if (move) + { + if (followSymlinks) + return NS_ERROR_FAILURE; + + rv = file->MoveToNative(target, nsCString()); + NS_ENSURE_SUCCESS(rv,rv); + } + else + { + if (followSymlinks) + rv = file->CopyToFollowingLinksNative(target, nsCString()); + else + rv = file->CopyToNative(target, nsCString()); + NS_ENSURE_SUCCESS(rv,rv); + } + } + } + // we've finished moving all the children of this directory + // in the new directory. so now delete the directory + // note, we don't need to do a recursive delete. + // MoveTo() is recursive. At this point, + // we've already moved the children of the current folder + // to the new location. nothing should be left in the folder. + if (move) + { + rv = Remove(PR_FALSE /* recursive */); + NS_ENSURE_SUCCESS(rv,rv); + } + } + + + // If we moved, we want to adjust this. + if (move) + { + MakeDirty(); + + nsCAutoString newParentPath; + newParentDir->GetNativePath(newParentPath); + + if (newParentPath.IsEmpty()) + return NS_ERROR_FAILURE; + + if (newName.IsEmpty()) + { + nsCAutoString aFileName; + GetNativeLeafName(aFileName); + + InitWithNativePath(newParentPath); + AppendNative(aFileName); + } + else + { + InitWithNativePath(newParentPath); + AppendNative(newName); + } + } + + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::CopyToNative(nsIFile *newParentDir, const nsACString &newName) +{ + return CopyMove(newParentDir, newName, PR_FALSE, PR_FALSE); +} + +NS_IMETHODIMP +nsLocalFile::CopyToFollowingLinksNative(nsIFile *newParentDir, const nsACString &newName) +{ + return CopyMove(newParentDir, newName, PR_TRUE, PR_FALSE); +} + +NS_IMETHODIMP +nsLocalFile::MoveToNative(nsIFile *newParentDir, const nsACString &newName) +{ + return CopyMove(newParentDir, newName, PR_FALSE, PR_TRUE); +} + +NS_IMETHODIMP +nsLocalFile::Load(PRLibrary * *_retval) +{ + PRBool isFile; + nsresult rv = IsFile(&isFile); + + if (NS_FAILED(rv)) + return rv; + + if (! isFile) + return NS_ERROR_FILE_IS_DIRECTORY; + + NS_TIMELINE_START_TIMER("PR_LoadLibrary"); + *_retval = PR_LoadLibrary(mResolvedPath.get()); + NS_TIMELINE_STOP_TIMER("PR_LoadLibrary"); + NS_TIMELINE_MARK_TIMER1("PR_LoadLibrary", mResolvedPath.get()); + + if (*_retval) + return NS_OK; + + return NS_ERROR_NULL_POINTER; +} + +NS_IMETHODIMP +nsLocalFile::Remove(PRBool recursive) +{ + // NOTE: + // + // if the working path points to a shortcut, then we will only + // delete the shortcut itself. even if the shortcut points to + // a directory, we will not recurse into that directory or + // delete that directory itself. likewise, if the shortcut + // points to a normal file, we will not delete the real file. + // this is done to be consistent with the other platforms that + // behave this way. we do this even if the followLinks attribute + // is set to true. this helps protect against misuse that could + // lead to security bugs (e.g., bug 210588). + // + // Since shortcut files are no longer permitted to be used as unix-like + // symlinks interspersed in the path (e.g. "c:/file.lnk/foo/bar.txt") + // this processing is a lot simpler. Even if the shortcut file is + // pointing to a directory, only the mWorkingPath value is used and so + // only the shortcut file will be deleted. + + PRBool isDir, isLink; + nsresult rv; + + isDir = PR_FALSE; + rv = IsSymlink(&isLink); + if (NS_FAILED(rv)) + return rv; + + // only check to see if we have a directory if it isn't a link + if (!isLink) + { + rv = IsDirectory(&isDir); + if (NS_FAILED(rv)) + return rv; + } + + if (isDir) + { + if (recursive) + { + nsDirEnumerator dirEnum; + + rv = dirEnum.Init(this); + if (NS_FAILED(rv)) + return rv; + + PRBool more; + while (NS_SUCCEEDED(dirEnum.HasMoreElements(&more)) && more) + { + nsCOMPtr item; + dirEnum.GetNext(getter_AddRefs(item)); + nsCOMPtr file = do_QueryInterface(item); + if (file) + file->Remove(recursive); + } + } + rv = rmdir(mWorkingPath.get()); + } + else + { + rv = remove(mWorkingPath.get()); + } + + // fixup error code if necessary... + if (rv == (nsresult)-1) + rv = NSRESULT_FOR_ERRNO(); + + MakeDirty(); + return rv; +} + +NS_IMETHODIMP +nsLocalFile::GetLastModifiedTime(PRInt64 *aLastModifiedTime) +{ + NS_ENSURE_ARG(aLastModifiedTime); + + // get the modified time of the target as determined by mFollowSymlinks + // If PR_TRUE, then this will be for the target of the shortcut file, + // otherwise it will be for the shortcut file itself (i.e. the same + // results as GetLastModifiedTimeOfLink) + + nsresult rv = ResolveAndStat(); + if (NS_FAILED(rv)) + return rv; + + // microseconds -> milliseconds + PRInt64 usecPerMsec; + LL_I2L(usecPerMsec, PR_USEC_PER_MSEC); + LL_DIV(*aLastModifiedTime, mFileInfo64.modifyTime, usecPerMsec); + return NS_OK; +} + + +NS_IMETHODIMP +nsLocalFile::GetLastModifiedTimeOfLink(PRInt64 *aLastModifiedTime) +{ + NS_ENSURE_ARG(aLastModifiedTime); + + // The caller is assumed to have already called IsSymlink + // and to have found that this file is a link. + + PRFileInfo64 info; + if (PR_GetFileInfo64(mWorkingPath.get(), &info) != PR_SUCCESS) + return NSRESULT_FOR_ERRNO(); + + // microseconds -> milliseconds + PRInt64 usecPerMsec; + LL_I2L(usecPerMsec, PR_USEC_PER_MSEC); + LL_DIV(*aLastModifiedTime, info.modifyTime, usecPerMsec); + return NS_OK; +} + + +NS_IMETHODIMP +nsLocalFile::SetLastModifiedTime(PRInt64 aLastModifiedTime) +{ + nsresult rv = ResolveAndStat(); + if (NS_FAILED(rv)) + return rv; + + // set the modified time of the target as determined by mFollowSymlinks + // If PR_TRUE, then this will be for the target of the shortcut file, + // otherwise it will be for the shortcut file itself (i.e. the same + // results as SetLastModifiedTimeOfLink) + + rv = SetModDate(aLastModifiedTime, mResolvedPath.get()); + if (NS_SUCCEEDED(rv)) + MakeDirty(); + + return rv; +} + + +NS_IMETHODIMP +nsLocalFile::SetLastModifiedTimeOfLink(PRInt64 aLastModifiedTime) +{ + // The caller is assumed to have already called IsSymlink + // and to have found that this file is a link. + + nsresult rv = SetModDate(aLastModifiedTime, mWorkingPath.get()); + if (NS_SUCCEEDED(rv)) + MakeDirty(); + + return rv; +} + +nsresult +nsLocalFile::SetModDate(PRInt64 aLastModifiedTime, const char *filePath) +{ + HANDLE file = CreateFile(filePath, // pointer to name of the file + GENERIC_WRITE, // access (write) mode + 0, // share mode + NULL, // pointer to security attributes + OPEN_EXISTING, // how to create + 0, // file attributes + NULL); + if (file == INVALID_HANDLE_VALUE) + { + return ConvertWinError(GetLastError()); + } + + FILETIME lft, ft; + SYSTEMTIME st; + PRExplodedTime pret; + + // PR_ExplodeTime expects usecs... + PR_ExplodeTime(aLastModifiedTime * PR_USEC_PER_MSEC, PR_LocalTimeParameters, &pret); + st.wYear = pret.tm_year; + st.wMonth = pret.tm_month + 1; // Convert start offset -- Win32: Jan=1; NSPR: Jan=0 + st.wDayOfWeek = pret.tm_wday; + st.wDay = pret.tm_mday; + st.wHour = pret.tm_hour; + st.wMinute = pret.tm_min; + st.wSecond = pret.tm_sec; + st.wMilliseconds = pret.tm_usec/1000; + + nsresult rv = NS_OK; + if ( 0 != SystemTimeToFileTime(&st, &lft) + || 0 != LocalFileTimeToFileTime(&lft, &ft) + || 0 != SetFileTime(file, NULL, &ft, &ft) ) + { + rv = ConvertWinError(GetLastError()); + } + + CloseHandle(file); + return rv; +} + +NS_IMETHODIMP +nsLocalFile::GetPermissions(PRUint32 *aPermissions) +{ + NS_ENSURE_ARG(aPermissions); + + // get the permissions of the target as determined by mFollowSymlinks + // If PR_TRUE, then this will be for the target of the shortcut file, + // otherwise it will be for the shortcut file itself (i.e. the same + // results as GetPermissionsOfLink) + nsresult rv = ResolveAndStat(); + if (NS_FAILED(rv)) + return rv; + + PRBool isWritable, isExecutable; + IsWritable(&isWritable); + IsExecutable(&isExecutable); + + *aPermissions = PR_IRUSR|PR_IRGRP|PR_IROTH; // all read + if (isWritable) + *aPermissions |= PR_IWUSR|PR_IWGRP|PR_IWOTH; // all write + if (isExecutable) + *aPermissions |= PR_IXUSR|PR_IXGRP|PR_IXOTH; // all execute + + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::GetPermissionsOfLink(PRUint32 *aPermissions) +{ + NS_ENSURE_ARG(aPermissions); + + // The caller is assumed to have already called IsSymlink + // and to have found that this file is a link. It is not + // possible for a link file to be executable. + + DWORD word = GetFileAttributes(mWorkingPath.get()); + if (word == INVALID_FILE_ATTRIBUTES) + return NS_ERROR_FILE_INVALID_PATH; + + PRBool isWritable = !(word & FILE_ATTRIBUTE_READONLY); + *aPermissions = PR_IRUSR|PR_IRGRP|PR_IROTH; // all read + if (isWritable) + *aPermissions |= PR_IWUSR|PR_IWGRP|PR_IWOTH; // all write + + return NS_OK; +} + + +NS_IMETHODIMP +nsLocalFile::SetPermissions(PRUint32 aPermissions) +{ + // set the permissions of the target as determined by mFollowSymlinks + // If PR_TRUE, then this will be for the target of the shortcut file, + // otherwise it will be for the shortcut file itself (i.e. the same + // results as SetPermissionsOfLink) + nsresult rv = ResolveAndStat(); + if (NS_FAILED(rv)) + return rv; + + // windows only knows about the following permissions + int mode = 0; + if (aPermissions & (PR_IRUSR|PR_IRGRP|PR_IROTH)) // any read + mode |= _S_IREAD; + if (aPermissions & (PR_IWUSR|PR_IWGRP|PR_IWOTH)) // any write + mode |= _S_IWRITE; + + if (chmod(mResolvedPath.get(), mode) == -1) + return NS_ERROR_FAILURE; + + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::SetPermissionsOfLink(PRUint32 aPermissions) +{ + // The caller is assumed to have already called IsSymlink + // and to have found that this file is a link. + + // windows only knows about the following permissions + int mode = 0; + if (aPermissions & (PR_IRUSR|PR_IRGRP|PR_IROTH)) // any read + mode |= _S_IREAD; + if (aPermissions & (PR_IWUSR|PR_IWGRP|PR_IWOTH)) // any write + mode |= _S_IWRITE; + + if (chmod(mWorkingPath.get(), mode) == -1) + return NS_ERROR_FAILURE; + + return NS_OK; +} + + +NS_IMETHODIMP +nsLocalFile::GetFileSize(PRInt64 *aFileSize) +{ + NS_ENSURE_ARG(aFileSize); + + nsresult rv = ResolveAndStat(); + if (NS_FAILED(rv)) + return rv; + + *aFileSize = mFileInfo64.size; + return NS_OK; +} + + +NS_IMETHODIMP +nsLocalFile::GetFileSizeOfLink(PRInt64 *aFileSize) +{ + NS_ENSURE_ARG(aFileSize); + + // The caller is assumed to have already called IsSymlink + // and to have found that this file is a link. + + PRFileInfo64 info; + if (!PR_GetFileInfo64(mWorkingPath.get(), &info)) + return NS_ERROR_FILE_INVALID_PATH; + + *aFileSize = info.size; + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::SetFileSize(PRInt64 aFileSize) +{ + nsresult rv = ResolveAndStat(); + if (NS_FAILED(rv)) + return rv; + + HANDLE hFile = CreateFile(mResolvedPath.get(), // pointer to name of the file + GENERIC_WRITE, // access (write) mode + FILE_SHARE_READ, // share mode + NULL, // pointer to security attributes + OPEN_EXISTING, // how to create + FILE_ATTRIBUTE_NORMAL, // file attributes + NULL); + if (hFile == INVALID_HANDLE_VALUE) + { + return ConvertWinError(GetLastError()); + } + + // seek the file pointer to the new, desired end of file + // and then truncate the file at that position + rv = NS_ERROR_FAILURE; + aFileSize = MyFileSeek64(hFile, aFileSize, FILE_BEGIN); + if (aFileSize != -1 && SetEndOfFile(hFile)) + { + MakeDirty(); + rv = NS_OK; + } + + CloseHandle(hFile); + return rv; +} + +typedef BOOL (WINAPI *fpGetDiskFreeSpaceExA)(LPCTSTR lpDirectoryName, + PULARGE_INTEGER lpFreeBytesAvailableToCaller, + PULARGE_INTEGER lpTotalNumberOfBytes, + PULARGE_INTEGER lpTotalNumberOfFreeBytes); + +NS_IMETHODIMP +nsLocalFile::GetDiskSpaceAvailable(PRInt64 *aDiskSpaceAvailable) +{ + NS_ENSURE_ARG(aDiskSpaceAvailable); + + ResolveAndStat(); + + // Attempt to check disk space using the GetDiskFreeSpaceExA function. + // --- FROM MSDN --- + // The GetDiskFreeSpaceEx function is available beginning with Windows 95 OEM Service + // Release 2 (OSR2). To determine whether GetDiskFreeSpaceEx is available, call + // GetModuleHandle to get the handle to Kernel32.dll. Then you can call GetProcAddress. + // It is not necessary to call LoadLibrary on Kernel32.dll because it is already loaded + // into every process address space. + fpGetDiskFreeSpaceExA pGetDiskFreeSpaceExA = (fpGetDiskFreeSpaceExA) + GetProcAddress(GetModuleHandle("kernel32.dll"), "GetDiskFreeSpaceExA"); + if (pGetDiskFreeSpaceExA) + { + ULARGE_INTEGER liFreeBytesAvailableToCaller, liTotalNumberOfBytes; + if (pGetDiskFreeSpaceExA(mResolvedPath.get(), &liFreeBytesAvailableToCaller, + &liTotalNumberOfBytes, NULL)) + { + *aDiskSpaceAvailable = liFreeBytesAvailableToCaller.QuadPart; + return NS_OK; + } + } + + // use the old method of getting available disk space + char aDrive[_MAX_DRIVE + 2]; + _splitpath( mResolvedPath.get(), aDrive, NULL, NULL, NULL); + strcat(aDrive, "\\"); + + DWORD dwSecPerClus, dwBytesPerSec, dwFreeClus, dwTotalClus; + if (GetDiskFreeSpace(aDrive, &dwSecPerClus, &dwBytesPerSec, &dwFreeClus, &dwTotalClus)) + { + __int64 bytes = dwFreeClus; + bytes *= dwSecPerClus; + bytes *= dwBytesPerSec; + + *aDiskSpaceAvailable = bytes; + return NS_OK; + } + + return NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +nsLocalFile::GetParent(nsIFile * *aParent) +{ + NS_ENSURE_ARG_POINTER(aParent); + + nsCAutoString parentPath(mWorkingPath); + + // cannot use nsCString::RFindChar() due to 0x5c problem + PRInt32 offset = (PRInt32) (_mbsrchr((const unsigned char *) parentPath.get(), '\\') + - (const unsigned char *) parentPath.get()); + // adding this offset check that was removed in bug 241708 fixes mail + // directories that aren't relative to/underneath the profile dir. + // e.g., on a different drive. Before you remove them, please make + // sure local mail directories that aren't underneath the profile dir work. + if (offset < 0) + return NS_ERROR_FILE_UNRECOGNIZED_PATH; + + if (offset == 1 && parentPath[0] == '\\') { + aParent = nsnull; + return NS_OK; + } + if (offset > 0) + parentPath.Truncate(offset); + else + parentPath.AssignLiteral("\\\\."); + + nsCOMPtr localFile; + nsresult rv = NS_NewNativeLocalFile(parentPath, mFollowSymlinks, getter_AddRefs(localFile)); + + if(NS_SUCCEEDED(rv) && localFile) + { + return CallQueryInterface(localFile, aParent); + } + return rv; +} + +NS_IMETHODIMP +nsLocalFile::Exists(PRBool *_retval) +{ + NS_ENSURE_ARG(_retval); + *_retval = PR_FALSE; + + MakeDirty(); + nsresult rv = ResolveAndStat(); + *_retval = NS_SUCCEEDED(rv); + + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::IsWritable(PRBool *aIsWritable) +{ + //TODO: extend to support NTFS file permissions + + // The read-only attribute on a FAT directory only means that it can't + // be deleted. It is still possible to modify the contents of the directory. + nsresult rv = IsDirectory(aIsWritable); + if (NS_FAILED(rv)) + return rv; + if (*aIsWritable) + return NS_OK; + + // writable if the file doesn't have the readonly attribute + rv = HasFileAttribute(FILE_ATTRIBUTE_READONLY, aIsWritable); + if (NS_FAILED(rv)) + return rv; + *aIsWritable = !*aIsWritable; + + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::IsReadable(PRBool *_retval) +{ + NS_ENSURE_ARG(_retval); + *_retval = PR_FALSE; + + nsresult rv = ResolveAndStat(); + if (NS_FAILED(rv)) + return rv; + + *_retval = PR_TRUE; + return NS_OK; +} + + +NS_IMETHODIMP +nsLocalFile::IsExecutable(PRBool *_retval) +{ + NS_ENSURE_ARG(_retval); + *_retval = PR_FALSE; + + nsresult rv; + + // only files can be executables + PRBool isFile; + rv = IsFile(&isFile); + if (NS_FAILED(rv)) + return rv; + if (!isFile) + return NS_OK; + + //TODO: shouldn't we be checking mFollowSymlinks here? + PRBool symLink; + rv = IsSymlink(&symLink); + if (NS_FAILED(rv)) + return rv; + + nsCAutoString path; + if (symLink) + GetNativeTarget(path); + else + GetNativePath(path); + + // Get extension. + char * ext = (char *) _mbsrchr((unsigned char *)path.BeginWriting(), '.'); + if ( ext ) { + // Convert extension to lower case. + for( unsigned char *p = (unsigned char *)ext; *p; p++ ) + *p = _mbctolower( *p ); + + // Search for any of the set of executable extensions. + const char * const executableExts[] = { + ".ad", + ".adp", + ".asp", + ".bas", + ".bat", + ".chm", + ".cmd", + ".com", + ".cpl", + ".crt", + ".exe", + ".hlp", + ".hta", + ".inf", + ".ins", + ".isp", + ".js", + ".jse", + ".lnk", + ".mdb", + ".mde", + ".msc", + ".msi", + ".msp", + ".mst", + ".pcd", + ".pif", + ".reg", + ".scr", + ".sct", + ".shb", + ".shs", + ".url", + ".vb", + ".vbe", + ".vbs", + ".vsd", + ".vss", + ".vst", + ".vsw", + ".ws", + ".wsc", + ".wsf", + ".wsh", + 0 }; + for ( int i = 0; executableExts[i]; i++ ) { + if ( ::strcmp( executableExts[i], ext ) == 0 ) { + // Found a match. Set result and quit. + *_retval = PR_TRUE; + break; + } + } + } + + return NS_OK; +} + + +NS_IMETHODIMP +nsLocalFile::IsDirectory(PRBool *_retval) +{ + NS_ENSURE_ARG(_retval); + + nsresult rv = ResolveAndStat(); + if (NS_FAILED(rv)) + return rv; + + *_retval = (mFileInfo64.type == PR_FILE_DIRECTORY); + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::IsFile(PRBool *_retval) +{ + NS_ENSURE_ARG(_retval); + + nsresult rv = ResolveAndStat(); + if (NS_FAILED(rv)) + return rv; + + *_retval = (mFileInfo64.type == PR_FILE_FILE); + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::IsHidden(PRBool *_retval) +{ + return HasFileAttribute(FILE_ATTRIBUTE_HIDDEN, _retval); +} + +nsresult +nsLocalFile::HasFileAttribute(DWORD fileAttrib, PRBool *_retval) +{ + NS_ENSURE_ARG(_retval); + + nsresult rv = ResolveAndStat(); + if (NS_FAILED(rv)) + return rv; + + // get the file attributes for the correct item depending on following symlinks + const char *filePath = mFollowSymlinks ? mResolvedPath.get() : mWorkingPath.get(); + DWORD word = GetFileAttributes(filePath); + + *_retval = ((word & fileAttrib) != 0); + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::IsSymlink(PRBool *_retval) +{ + NS_ENSURE_ARG(_retval); + + // unless it is a valid shortcut path it's not a symlink + if (!IsShortcutPath(mWorkingPath.get())) + { + *_retval = PR_FALSE; + return NS_OK; + } + + // we need to know if this is a file or directory + nsresult rv = ResolveAndStat(); + if (NS_FAILED(rv)) + return rv; + + // it's only a shortcut if it is a file + *_retval = (mFileInfo64.type == PR_FILE_FILE); + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::IsSpecial(PRBool *_retval) +{ + return HasFileAttribute(FILE_ATTRIBUTE_SYSTEM, _retval); +} + +NS_IMETHODIMP +nsLocalFile::Equals(nsIFile *inFile, PRBool *_retval) +{ + NS_ENSURE_ARG(inFile); + NS_ENSURE_ARG(_retval); + + nsCAutoString inFilePath; + inFile->GetNativePath(inFilePath); + + *_retval = inFilePath.Equals(mWorkingPath); + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::Contains(nsIFile *inFile, PRBool recur, PRBool *_retval) +{ + *_retval = PR_FALSE; + + nsCAutoString myFilePath; + if ( NS_FAILED(GetNativeTarget(myFilePath))) + GetNativePath(myFilePath); + + PRInt32 myFilePathLen = myFilePath.Length(); + + nsCAutoString inFilePath; + if ( NS_FAILED(inFile->GetNativeTarget(inFilePath))) + inFile->GetNativePath(inFilePath); + + if ( strnicmp( myFilePath.get(), inFilePath.get(), myFilePathLen) == 0) + { + // now make sure that the |inFile|'s path has a trailing + // separator. + + if (inFilePath[myFilePathLen] == '\\') + { + *_retval = PR_TRUE; + } + + } + + return NS_OK; +} + + + +NS_IMETHODIMP +nsLocalFile::GetNativeTarget(nsACString &_retval) +{ + _retval.Truncate(); +#if STRICT_FAKE_SYMLINKS + PRBool symLink; + + nsresult rv = IsSymlink(&symLink); + if (NS_FAILED(rv)) + return rv; + + if (!symLink) + { + return NS_ERROR_FILE_INVALID_PATH; + } +#endif + ResolveAndStat(); + + _retval = mResolvedPath; + return NS_OK; +} + + +/* attribute PRBool followLinks; */ +NS_IMETHODIMP +nsLocalFile::GetFollowLinks(PRBool *aFollowLinks) +{ + *aFollowLinks = mFollowSymlinks; + return NS_OK; +} +NS_IMETHODIMP +nsLocalFile::SetFollowLinks(PRBool aFollowLinks) +{ + MakeDirty(); + mFollowSymlinks = aFollowLinks; + return NS_OK; +} + + +NS_IMETHODIMP +nsLocalFile::GetDirectoryEntries(nsISimpleEnumerator * *entries) +{ + nsresult rv; + + *entries = nsnull; + if (mWorkingPath.EqualsLiteral("\\\\.")) { + nsDriveEnumerator *drives = new nsDriveEnumerator; + if (!drives) + return NS_ERROR_OUT_OF_MEMORY; + NS_ADDREF(drives); + rv = drives->Init(); + if (NS_FAILED(rv)) { + NS_RELEASE(drives); + return rv; + } + *entries = drives; + return NS_OK; + } + + PRBool isDir; + rv = IsDirectory(&isDir); + if (NS_FAILED(rv)) + return rv; + if (!isDir) + return NS_ERROR_FILE_NOT_DIRECTORY; + + nsDirEnumerator* dirEnum = new nsDirEnumerator(); + if (dirEnum == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + NS_ADDREF(dirEnum); + rv = dirEnum->Init(this); + if (NS_FAILED(rv)) + { + NS_RELEASE(dirEnum); + return rv; + } + + *entries = dirEnum; + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::GetPersistentDescriptor(nsACString &aPersistentDescriptor) +{ + return GetNativePath(aPersistentDescriptor); +} + +NS_IMETHODIMP +nsLocalFile::SetPersistentDescriptor(const nsACString &aPersistentDescriptor) +{ + return InitWithNativePath(aPersistentDescriptor); +} + +NS_IMETHODIMP +nsLocalFile::Reveal() +{ + // make sure mResolvedPath is set + nsresult rv = ResolveAndStat(); + if (NS_FAILED(rv) && rv != NS_ERROR_FILE_NOT_FOUND) + return rv; + + // use the full path to explorer for security + nsCOMPtr winDir; + rv = GetSpecialSystemDirectory(Win_WindowsDirectory, getter_AddRefs(winDir)); + NS_ENSURE_SUCCESS(rv, rv); + nsCAutoString explorerPath; + rv = winDir->GetNativePath(explorerPath); + NS_ENSURE_SUCCESS(rv, rv); + explorerPath.Append("\\explorer.exe"); + + // Always open a new window for files because Win2K doesn't appear to select + // the file if a window showing that folder was already open. If the resolved + // path is a directory then instead of opening the parent and selecting it, + // we open the directory itself. + nsCAutoString explorerParams; + if (mFileInfo64.type != PR_FILE_DIRECTORY) // valid because we ResolveAndStat above + explorerParams.Append("/n,/select,"); + explorerParams.Append('\"'); + explorerParams.Append(mResolvedPath); + explorerParams.Append('\"'); + + if (::ShellExecute(NULL, "open", explorerPath.get(), explorerParams.get(), + NULL, SW_SHOWNORMAL) <= (HINSTANCE) 32) + return NS_ERROR_FAILURE; + + return NS_OK; +} + + +NS_IMETHODIMP +nsLocalFile::Launch() +{ + const nsCString &path = mWorkingPath; + + // use the app registry name to launch a shell execute.... + LONG r = (LONG) ::ShellExecute( NULL, NULL, path.get(), NULL, NULL, SW_SHOWNORMAL); + + // if the file has no association, we launch windows' "what do you want to do" dialog + if (r == SE_ERR_NOASSOC) { + nsCAutoString shellArg; + shellArg.Assign(NS_LITERAL_CSTRING("shell32.dll,OpenAs_RunDLL ") + path); + r = (LONG) ::ShellExecute(NULL, NULL, "RUNDLL32.EXE", shellArg.get(), + NULL, SW_SHOWNORMAL); + } + if (r < 32) { + switch (r) { + case 0: + case SE_ERR_OOM: + return NS_ERROR_OUT_OF_MEMORY; + case ERROR_FILE_NOT_FOUND: + return NS_ERROR_FILE_NOT_FOUND; + case ERROR_PATH_NOT_FOUND: + return NS_ERROR_FILE_UNRECOGNIZED_PATH; + case ERROR_BAD_FORMAT: + return NS_ERROR_FILE_CORRUPTED; + case SE_ERR_ACCESSDENIED: + return NS_ERROR_FILE_ACCESS_DENIED; + case SE_ERR_ASSOCINCOMPLETE: + case SE_ERR_NOASSOC: + return NS_ERROR_UNEXPECTED; + case SE_ERR_DDEBUSY: + case SE_ERR_DDEFAIL: + case SE_ERR_DDETIMEOUT: + return NS_ERROR_NOT_AVAILABLE; + case SE_ERR_DLLNOTFOUND: + return NS_ERROR_FAILURE; + case SE_ERR_SHARE: + return NS_ERROR_FILE_IS_LOCKED; + default: + return NS_ERROR_FILE_EXECUTION_FAILED; + } + } + return NS_OK; +} + +nsresult +NS_NewNativeLocalFile(const nsACString &path, PRBool followLinks, nsILocalFile* *result) +{ + nsLocalFile* file = new nsLocalFile(); + if (file == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + NS_ADDREF(file); + + file->SetFollowLinks(followLinks); + + if (!path.IsEmpty()) { + nsresult rv = file->InitWithNativePath(path); + if (NS_FAILED(rv)) { + NS_RELEASE(file); + return rv; + } + } + + *result = file; + return NS_OK; +} + +//----------------------------------------------------------------------------- +// UCS2 interface +//----------------------------------------------------------------------------- + +nsresult +nsLocalFile::InitWithPath(const nsAString &filePath) +{ + nsCAutoString tmp; + nsresult rv = NS_CopyUnicodeToNative(filePath, tmp); + if (NS_SUCCEEDED(rv)) + return InitWithNativePath(tmp); + + return rv; +} + +nsresult +nsLocalFile::Append(const nsAString &node) +{ + nsCAutoString tmp; + nsresult rv = NS_CopyUnicodeToNative(node, tmp); + if (NS_SUCCEEDED(rv)) + return AppendNative(tmp); + + return rv; +} + +nsresult +nsLocalFile::AppendRelativePath(const nsAString &node) +{ + nsCAutoString tmp; + nsresult rv = NS_CopyUnicodeToNative(node, tmp); + if (NS_SUCCEEDED(rv)) + return AppendRelativeNativePath(tmp); + return rv; +} + +nsresult +nsLocalFile::GetLeafName(nsAString &aLeafName) +{ + nsCAutoString tmp; + nsresult rv = GetNativeLeafName(tmp); + if (NS_SUCCEEDED(rv)) + rv = NS_CopyNativeToUnicode(tmp, aLeafName); + + return rv; +} + +nsresult +nsLocalFile::SetLeafName(const nsAString &aLeafName) +{ + nsCAutoString tmp; + nsresult rv = NS_CopyUnicodeToNative(aLeafName, tmp); + if (NS_SUCCEEDED(rv)) + return SetNativeLeafName(tmp); + + return rv; +} + +nsresult +nsLocalFile::GetPath(nsAString &_retval) +{ + return NS_CopyNativeToUnicode(mWorkingPath, _retval); +} + +nsresult +nsLocalFile::CopyTo(nsIFile *newParentDir, const nsAString &newName) +{ + if (newName.IsEmpty()) + return CopyToNative(newParentDir, nsCString()); + + nsCAutoString tmp; + nsresult rv = NS_CopyUnicodeToNative(newName, tmp); + if (NS_SUCCEEDED(rv)) + return CopyToNative(newParentDir, tmp); + + return rv; +} + +nsresult +nsLocalFile::CopyToFollowingLinks(nsIFile *newParentDir, const nsAString &newName) +{ + if (newName.IsEmpty()) + return CopyToFollowingLinksNative(newParentDir, nsCString()); + + nsCAutoString tmp; + nsresult rv = NS_CopyUnicodeToNative(newName, tmp); + if (NS_SUCCEEDED(rv)) + return CopyToFollowingLinksNative(newParentDir, tmp); + + return rv; +} + +nsresult +nsLocalFile::MoveTo(nsIFile *newParentDir, const nsAString &newName) +{ + if (newName.IsEmpty()) + return MoveToNative(newParentDir, nsCString()); + + nsCAutoString tmp; + nsresult rv = NS_CopyUnicodeToNative(newName, tmp); + if (NS_SUCCEEDED(rv)) + return MoveToNative(newParentDir, tmp); + + return rv; +} + +nsresult +nsLocalFile::GetTarget(nsAString &_retval) +{ + nsCAutoString tmp; + nsresult rv = GetNativeTarget(tmp); + if (NS_SUCCEEDED(rv)) + rv = NS_CopyNativeToUnicode(tmp, _retval); + + return rv; +} + +nsresult +NS_NewLocalFile(const nsAString &path, PRBool followLinks, nsILocalFile* *result) +{ + nsCAutoString buf; + nsresult rv = NS_CopyUnicodeToNative(path, buf); + if (NS_FAILED(rv)) { + *result = nsnull; + return rv; + } + return NS_NewNativeLocalFile(buf, followLinks, result); +} + +//----------------------------------------------------------------------------- +// nsLocalFile +//----------------------------------------------------------------------------- + +void +nsLocalFile::GlobalInit() +{ + nsresult rv = NS_CreateShortcutResolver(); + NS_ASSERTION(NS_SUCCEEDED(rv), "Shortcut resolver could not be created"); +} + +void +nsLocalFile::GlobalShutdown() +{ + NS_DestroyShortcutResolver(); +} + +NS_IMPL_ISUPPORTS1(nsDriveEnumerator, nsISimpleEnumerator) + +nsDriveEnumerator::nsDriveEnumerator() + : mLetter(0) +{ +} + +nsDriveEnumerator::~nsDriveEnumerator() +{ +} + +nsresult nsDriveEnumerator::Init() +{ + /* If the length passed to GetLogicalDriveStrings is smaller + * than the length of the string it would return, it returns + * the length required for the string. */ + DWORD length = GetLogicalDriveStrings(0, 0); + /* The string is null terminated */ + mDrives.SetLength(length+1); + if (!GetLogicalDriveStrings(length, mDrives.BeginWriting())) + return NS_ERROR_FAILURE; + mLetter = mDrives.get(); + return NS_OK; +} + +NS_IMETHODIMP nsDriveEnumerator::HasMoreElements(PRBool *aHasMore) +{ + *aHasMore = *mLetter != '\0'; + return NS_OK; +} + +NS_IMETHODIMP nsDriveEnumerator::GetNext(nsISupports **aNext) +{ + /* GetLogicalDrives stored in mLetter is a concatenation + * of null terminated strings, followed by a null terminator. */ + if (!*mLetter) { + *aNext = nsnull; + return NS_OK; + } + const char *drive = mLetter; + mLetter += strlen(drive) + 1; + nsILocalFile *file; + nsresult rv = + NS_NewNativeLocalFile(nsDependentCString(drive), PR_FALSE, &file); + + *aNext = file; + return rv; +} diff --git a/src/libs/xpcom18a4/xpcom/io/nsLocalFileWin.h b/src/libs/xpcom18a4/xpcom/io/nsLocalFileWin.h new file mode 100644 index 00000000..0ef1d9f0 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsLocalFileWin.h @@ -0,0 +1,113 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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 Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Doug Turner + * Brodie Thiesfield + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +#ifndef _nsLocalFileWIN_H_ +#define _nsLocalFileWIN_H_ + +#include "nscore.h" +#include "nsError.h" +#include "nsString.h" +#include "nsCRT.h" +#include "nsIFile.h" +#include "nsIFactory.h" + +#include "windows.h" + +// For older version (<6.0) of the VC Compiler +#if (_MSC_VER == 1100) +#include +DEFINE_OLEGUID(IID_IPersistFile, 0x0000010BL, 0, 0); +#endif + +#include "shlobj.h" + +#include + +class nsLocalFile : public nsILocalFile +{ +public: + NS_DEFINE_STATIC_CID_ACCESSOR(NS_LOCAL_FILE_CID) + + nsLocalFile(); + + static NS_METHOD nsLocalFileConstructor(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr); + + // nsISupports interface + NS_DECL_ISUPPORTS + + // nsIFile interface + NS_DECL_NSIFILE + + // nsILocalFile interface + NS_DECL_NSILOCALFILE + +public: + static void GlobalInit(); + static void GlobalShutdown(); + +private: + nsLocalFile(const nsLocalFile& other); + ~nsLocalFile() {} + + PRPackedBool mDirty; // cached information can only be used when this is PR_FALSE + PRPackedBool mFollowSymlinks; // should we follow symlinks when working on this file + + // this string will always be in native format! + nsCString mWorkingPath; + + // this will be the resolved path of shortcuts, it will *NEVER* be returned to the user + nsCString mResolvedPath; + + PRFileInfo64 mFileInfo64; + + void MakeDirty() { mDirty = PR_TRUE; } + + nsresult ResolveAndStat(); + nsresult ResolveShortcut(); + + nsresult CopyMove(nsIFile *newParentDir, const nsACString &newName, PRBool followSymlinks, PRBool move); + nsresult CopySingleFile(nsIFile *source, nsIFile* dest, const nsACString &newName, PRBool followSymlinks, PRBool move); + + nsresult SetModDate(PRInt64 aLastModifiedTime, const char *filePath); + nsresult HasFileAttribute(DWORD fileAttrib, PRBool *_retval); + nsresult AppendNativeInternal(const nsAFlatCString &node, PRBool multipleComponents); +}; + +#endif diff --git a/src/libs/xpcom18a4/xpcom/io/nsMultiplexInputStream.cpp b/src/libs/xpcom18a4/xpcom/io/nsMultiplexInputStream.cpp new file mode 100644 index 00000000..ba04a842 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsMultiplexInputStream.cpp @@ -0,0 +1,389 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 frightening to behold. + * + * The Initial Developer of the Original Code is + * Jonas Sicking. + * Portions created by the Initial Developer are Copyright (C) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Jonas Sicking + * + * 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 ***** */ + +/** + * The multiplex stream concatenates a list of input streams into a single + * stream. + */ + +#include "nsMultiplexInputStream.h" +#include "nsIMultiplexInputStream.h" +#include "nsISeekableStream.h" +#include "nsSupportsArray.h" +#include "nsInt64.h" + +class nsMultiplexInputStream : public nsIMultiplexInputStream, + public nsISeekableStream +{ +public: + nsMultiplexInputStream(); + + NS_DECL_ISUPPORTS + NS_DECL_NSIINPUTSTREAM + NS_DECL_NSIMULTIPLEXINPUTSTREAM + NS_DECL_NSISEEKABLESTREAM + + static NS_METHOD Create(nsISupports *outer, REFNSIID iid, void **result); + +private: + ~nsMultiplexInputStream() {} + + + struct ReadSegmentsState { + nsIInputStream* mThisStream; + PRUint32 mOffset; + nsWriteSegmentFun mWriter; + void* mClosure; + PRBool mDone; + }; + + static NS_METHOD ReadSegCb(nsIInputStream* aIn, void* aClosure, + const char* aFromRawSegment, PRUint32 aToOffset, + PRUint32 aCount, PRUint32 *aWriteCount); + + nsSupportsArray mStreams; + PRUint32 mCurrentStream; + PRBool mStartedReadingCurrent; +}; + + +NS_IMPL_THREADSAFE_ISUPPORTS3(nsMultiplexInputStream, + nsIMultiplexInputStream, + nsIInputStream, + nsISeekableStream) + +nsMultiplexInputStream::nsMultiplexInputStream() + : mCurrentStream(0), + mStartedReadingCurrent(PR_FALSE) +{ +} + +/* readonly attribute unsigned long count; */ +NS_IMETHODIMP +nsMultiplexInputStream::GetCount(PRUint32 *aCount) +{ + mStreams.Count(aCount); + return NS_OK; +} + +/* void appendStream (in nsIInputStream stream); */ +NS_IMETHODIMP +nsMultiplexInputStream::AppendStream(nsIInputStream *aStream) +{ + return mStreams.AppendElement(aStream); +} + +/* void insertStream (in nsIInputStream stream, in unsigned long index); */ +NS_IMETHODIMP +nsMultiplexInputStream::InsertStream(nsIInputStream *aStream, PRUint32 aIndex) +{ + nsresult rv = mStreams.InsertElementAt(aStream, aIndex); + NS_ENSURE_SUCCESS(rv, rv); + if (mCurrentStream > aIndex || + (mCurrentStream == aIndex && mStartedReadingCurrent)) + ++mCurrentStream; + return rv; +} + +/* void removeStream (in unsigned long index); */ +NS_IMETHODIMP +nsMultiplexInputStream::RemoveStream(PRUint32 aIndex) +{ + nsresult rv = mStreams.RemoveElementAt(aIndex); + NS_ENSURE_SUCCESS(rv, rv); + if (mCurrentStream > aIndex) + --mCurrentStream; + else if (mCurrentStream == aIndex) + mStartedReadingCurrent = PR_FALSE; + + return rv; +} + +/* nsIInputStream getStream (in unsigned long index); */ +NS_IMETHODIMP +nsMultiplexInputStream::GetStream(PRUint32 aIndex, nsIInputStream **_retval) +{ + return mStreams.QueryElementAt(aIndex, + NS_GET_IID(nsIInputStream), + (void**)_retval); +} + +/* void close (); */ +NS_IMETHODIMP +nsMultiplexInputStream::Close() +{ + PRUint32 len, i; + nsresult rv = NS_OK; + + mStreams.Count(&len); + for (i = 0; i < len; ++i) { + nsCOMPtr stream(do_QueryElementAt(&mStreams, i)); + nsresult rv2 = stream->Close(); + // We still want to close all streams, but we should return an error + if (NS_FAILED(rv2)) + rv = rv2; + } + return rv; +} + +/* unsigned long available (); */ +NS_IMETHODIMP +nsMultiplexInputStream::Available(PRUint32 *_retval) +{ + nsresult rv; + PRUint32 i, len, avail = 0; + + mStreams.Count(&len); + for (i = mCurrentStream; i < len; i++) { + nsCOMPtr stream(do_QueryElementAt(&mStreams, i)); + + PRUint32 streamAvail; + rv = stream->Available(&streamAvail); + NS_ENSURE_SUCCESS(rv, rv); + avail += streamAvail; + } + *_retval = avail; + return NS_OK; +} + +/* [noscript] unsigned long read (in charPtr buf, in unsigned long count); */ +NS_IMETHODIMP +nsMultiplexInputStream::Read(char * aBuf, PRUint32 aCount, PRUint32 *_retval) +{ + nsresult rv = NS_OK; + PRUint32 len, read; + + *_retval = 0; + + mStreams.Count(&len); + while (mCurrentStream < len && aCount) { + nsCOMPtr stream(do_QueryElementAt(&mStreams, + mCurrentStream)); + rv = stream->Read(aBuf, aCount, &read); + + // XXX some streams return NS_BASE_STREAM_CLOSED to indicate EOF. + if (rv == NS_BASE_STREAM_CLOSED) { + rv = NS_OK; + read = 0; + } + else if (NS_FAILED(rv)) + break; + + if (read == 0) { + ++mCurrentStream; + mStartedReadingCurrent = PR_FALSE; + } + else { + NS_ASSERTION(aCount >= read, "Read more than requested"); + *_retval += read; + aCount -= read; + aBuf += read; + mStartedReadingCurrent = PR_TRUE; + } + } + return *_retval ? NS_OK : rv; +} + +/* [noscript] unsigned long readSegments (in nsWriteSegmentFun writer, + * in voidPtr closure, + * in unsigned long count); */ +NS_IMETHODIMP +nsMultiplexInputStream::ReadSegments(nsWriteSegmentFun aWriter, void *aClosure, + PRUint32 aCount, PRUint32 *_retval) +{ + NS_ASSERTION(aWriter, "missing aWriter"); + + nsresult rv = NS_OK; + ReadSegmentsState state; + state.mThisStream = this; + state.mOffset = 0; + state.mWriter = aWriter; + state.mClosure = aClosure; + state.mDone = PR_FALSE; + + PRUint32 len; + mStreams.Count(&len); + while (mCurrentStream < len && aCount) { + nsCOMPtr stream(do_QueryElementAt(&mStreams, + mCurrentStream)); + PRUint32 read; + rv = stream->ReadSegments(ReadSegCb, &state, aCount, &read); + + // XXX some streams return NS_BASE_STREAM_CLOSED to indicate EOF. + if (rv == NS_BASE_STREAM_CLOSED) { + rv = NS_OK; + read = 0; + } + + // if |aWriter| decided to stop reading segments... + if (state.mDone || NS_FAILED(rv)) + break; + + // if stream is empty, then advance to the next stream. + if (read == 0) { + ++mCurrentStream; + mStartedReadingCurrent = PR_FALSE; + } + else { + NS_ASSERTION(aCount >= read, "Read more than requested"); + state.mOffset += read; + aCount -= read; + mStartedReadingCurrent = PR_TRUE; + } + } + + // if we successfully read some data, then this call succeeded. + *_retval = state.mOffset; + return state.mOffset ? NS_OK : rv; +} + +NS_METHOD +nsMultiplexInputStream::ReadSegCb(nsIInputStream* aIn, void* aClosure, + const char* aFromRawSegment, + PRUint32 aToOffset, PRUint32 aCount, + PRUint32 *aWriteCount) +{ + nsresult rv; + ReadSegmentsState* state = (ReadSegmentsState*)aClosure; + rv = (state->mWriter)(state->mThisStream, + state->mClosure, + aFromRawSegment, + aToOffset + state->mOffset, + aCount, + aWriteCount); + if (NS_FAILED(rv)) + state->mDone = PR_TRUE; + return rv; +} + +/* readonly attribute boolean nonBlocking; */ +NS_IMETHODIMP +nsMultiplexInputStream::IsNonBlocking(PRBool *aNonBlocking) +{ + nsresult rv; + PRUint32 i, len; + + mStreams.Count(&len); + for (i = 0; i < len; ++i) { + nsCOMPtr stream(do_QueryElementAt(&mStreams, i)); + rv = stream->IsNonBlocking(aNonBlocking); + NS_ENSURE_SUCCESS(rv, rv); + // If one is non-blocking the entire stream becomes non-blocking + if (*aNonBlocking) + return NS_OK; + } + return NS_OK; +} + +/* void seek (in PRInt32 whence, in PRInt32 offset); */ +NS_IMETHODIMP +nsMultiplexInputStream::Seek(PRInt32 aWhence, PRInt64 aOffset) +{ + nsresult rv; + + // rewinding to start is easy, and should be the most common case + if (aWhence == NS_SEEK_SET && aOffset == 0) + { + PRUint32 i, last; + last = mStartedReadingCurrent ? mCurrentStream+1 : mCurrentStream; + for (i = 0; i < last; ++i) { + nsCOMPtr stream(do_QueryElementAt(&mStreams, i)); + NS_ENSURE_TRUE(stream, NS_ERROR_NO_INTERFACE); + + rv = stream->Seek(NS_SEEK_SET, 0); + NS_ENSURE_SUCCESS(rv, rv); + } + mCurrentStream = 0; + mStartedReadingCurrent = PR_FALSE; + return NS_OK; + } + + // other Seeks not implemented yet + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* PRUint32 tell (); */ +NS_IMETHODIMP +nsMultiplexInputStream::Tell(PRInt64 *_retval) +{ + nsresult rv; + nsInt64 ret64 = 0; + PRUint32 i, last; + last = mStartedReadingCurrent ? mCurrentStream+1 : mCurrentStream; + for (i = 0; i < last; ++i) { + nsCOMPtr stream(do_QueryElementAt(&mStreams, i)); + NS_ENSURE_TRUE(stream, NS_ERROR_NO_INTERFACE); + + PRInt64 pos; + rv = stream->Tell(&pos); + NS_ENSURE_SUCCESS(rv, rv); + ret64 += pos; + } + *_retval = ret64; + + return NS_OK; +} + +/* void setEOF (); */ +NS_IMETHODIMP +nsMultiplexInputStream::SetEOF() +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_METHOD +nsMultiplexInputStreamConstructor(nsISupports *outer, + REFNSIID iid, + void **result) +{ + *result = nsnull; + + if (outer) + return NS_ERROR_NO_AGGREGATION; + + nsMultiplexInputStream *inst; + NS_NEWXPCOM(inst, nsMultiplexInputStream); + if (!inst) + return NS_ERROR_OUT_OF_MEMORY; + + NS_ADDREF(inst); + nsresult rv = inst->QueryInterface(iid, result); + NS_RELEASE(inst); + + return rv; +} diff --git a/src/libs/xpcom18a4/xpcom/io/nsMultiplexInputStream.h b/src/libs/xpcom18a4/xpcom/io/nsMultiplexInputStream.h new file mode 100644 index 00000000..32d3026d --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsMultiplexInputStream.h @@ -0,0 +1,63 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 frightening to behold. + * + * The Initial Developer of the Original Code is + * Jonas Sicking. + * Portions created by the Initial Developer are Copyright (C) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Jonas Sicking + * + * 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 ***** */ + +/** + * The multiplex stream concatinates a list of input streams into a single + * stream. + */ + +#ifndef _nsMultiplexInputStream_h_ +#define _nsMultiplexInputStream_h_ + +#include "nsIMultiplexInputStream.h" + +#define NS_MULTIPLEXINPUTSTREAM_CLASSNAME "nsMultiplexInputStream" +#define NS_MULTIPLEXINPUTSTREAM_CONTRACTID "@mozilla.org/io/multiplex-input-stream;1" +#define NS_MULTIPLEXINPUTSTREAM_CID \ +{ /* 565e3a2c-1dd2-11b2-8da1-b4cef17e568d */ \ + 0x565e3a2c, \ + 0x1dd2, \ + 0x11b2, \ + {0x8d, 0xa1, 0xb4, 0xce, 0xf1, 0x7e, 0x56, 0x8d} \ +} + +extern NS_METHOD nsMultiplexInputStreamConstructor(nsISupports *outer, + REFNSIID iid, + void **result); + +#endif // _nsMultiplexInputStream_h_ diff --git a/src/libs/xpcom18a4/xpcom/io/nsNativeCharsetUtils.cpp b/src/libs/xpcom18a4/xpcom/io/nsNativeCharsetUtils.cpp new file mode 100644 index 00000000..55b5c63c --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsNativeCharsetUtils.cpp @@ -0,0 +1,1280 @@ +/* ***** 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 + * Brian Stell + * Frank Tang + * Brendan Eich + * Sergei Dolgov + * + * 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 "xpcom-private.h" + +//----------------------------------------------------------------------------- +// XP_UNIX +//----------------------------------------------------------------------------- +#if defined(XP_UNIX) + +#include // mbtowc, wctomb +#include // setlocale +#include "nscore.h" +#include "prlock.h" +#include "nsAString.h" +#include "nsReadableUtils.h" + +// +// choose a conversion library. we used to use mbrtowc/wcrtomb under Linux, +// but that doesn't work for non-BMP characters whether we use '-fshort-wchar' +// or not (see bug 206811 and +// news://news.mozilla.org:119/bajml3$fvr1@ripley.netscape.com). we now use +// iconv for all platforms where nltypes.h and nllanginfo.h are present +// along with iconv. +// +#if defined(HAVE_ICONV) && defined(HAVE_NL_TYPES_H) && defined(HAVE_LANGINFO_CODESET) +#define USE_ICONV 1 +#else +#define USE_STDCONV 1 +#endif + +static void +isolatin1_to_utf16(const char **input, PRUint32 *inputLeft, PRUnichar **output, PRUint32 *outputLeft) +{ + while (*inputLeft && *outputLeft) { + **output = (unsigned char) **input; + (*input)++; + (*inputLeft)--; + (*output)++; + (*outputLeft)--; + } +} + +static void +utf16_to_isolatin1(const PRUnichar **input, PRUint32 *inputLeft, char **output, PRUint32 *outputLeft) +{ + while (*inputLeft && *outputLeft) { + **output = (unsigned char) **input; + (*input)++; + (*inputLeft)--; + (*output)++; + (*outputLeft)--; + } +} + +//----------------------------------------------------------------------------- +// conversion using iconv +//----------------------------------------------------------------------------- +#if defined(USE_ICONV) +#include // CODESET +#include // nl_langinfo +#include // iconv_open, iconv, iconv_close +#include + +#if defined(HAVE_ICONV_WITH_CONST_INPUT) +#define ICONV_INPUT(x) (x) +#else +#define ICONV_INPUT(x) ((char **)x) +#endif + +// solaris definitely needs this, but we'll enable it by default +// just in case... but we know for sure that iconv(3) in glibc +// doesn't need this. +#if !defined(__GLIBC__) +#define ENABLE_UTF8_FALLBACK_SUPPORT +#endif + +#define INVALID_ICONV_T ((iconv_t) -1) + +static inline size_t +xp_iconv(iconv_t converter, + const char **input, + size_t *inputLeft, + char **output, + size_t *outputLeft) +{ + size_t res, outputAvail = outputLeft ? *outputLeft : 0; + res = iconv(converter, ICONV_INPUT(input), inputLeft, output, outputLeft); + if (res == (size_t) -1) { + // on some platforms (e.g., linux) iconv will fail with + // E2BIG if it cannot convert _all_ of its input. it'll + // still adjust all of the in/out params correctly, so we + // can ignore this error. the assumption is that we will + // be called again to complete the conversion. + if ((errno == E2BIG) && (*outputLeft < outputAvail)) + res = 0; + } + return res; +} + +static inline void +xp_iconv_reset(iconv_t converter) +{ + // NOTE: the man pages on Solaris claim that you can pass NULL + // for all parameter to reset the converter, but beware the + // evil Solaris crash if you go down this route >:-) + + const char *zero_char_in_ptr = NULL; + char *zero_char_out_ptr = NULL; + size_t zero_size_in = 0, + zero_size_out = 0; + + xp_iconv(converter, &zero_char_in_ptr, + &zero_size_in, + &zero_char_out_ptr, + &zero_size_out); +} + +static inline iconv_t +xp_iconv_open(const char **to_list, const char **from_list) +{ + iconv_t res; + const char **from_name; + const char **to_name; + + // try all possible combinations to locate a converter. + to_name = to_list; + while (*to_name) { + if (**to_name) { + from_name = from_list; + while (*from_name) { + if (**from_name) { + res = iconv_open(*to_name, *from_name); + if (res != INVALID_ICONV_T) + return res; + } + from_name++; + } + } + to_name++; + } + + return INVALID_ICONV_T; +} + +/* + * PRUnichar[] is NOT a UCS-2 array BUT a UTF-16 string. Therefore, we + * have to use UTF-16 with iconv(3) on platforms where it's supported. + * However, the way UTF-16 and UCS-2 are interpreted varies across platforms + * and implementations of iconv(3). On Tru64, it also depends on the environment + * variable. To avoid the trouble arising from byte-swapping + * (bug 208809), we have to try UTF-16LE/BE and UCS-2LE/BE before falling + * back to UTF-16 and UCS-2 and variants. We assume that UTF-16 and UCS-2 + * on systems without UTF-16LE/BE and UCS-2LE/BE have the native endianness, + * which isn't the case of glibc 2.1.x, for which we use 'UNICODELITTLE' + * and 'UNICODEBIG'. It's also not true of Tru64 V4 when the environment + * variable ICONV_BYTEORDER is set to 'big-endian', about which not much + * can be done other than adding a note in the release notes. (bug 206811) + */ +static const char *UTF_16_NAMES[] = { +#if defined(IS_LITTLE_ENDIAN) + "UTF-16LE", +#if defined(__GLIBC__) + "UNICODELITTLE", +#endif + "UCS-2LE", +#else + "UTF-16BE", +#if defined(__GLIBC__) + "UNICODEBIG", +#endif + "UCS-2BE", +#endif + "UTF-16", + "UCS-2", + "UCS2", + "UCS_2", + "ucs-2", + "ucs2", + "ucs_2", + NULL +}; + +#if defined(ENABLE_UTF8_FALLBACK_SUPPORT) +static const char *UTF_8_NAMES[] = { + "UTF-8", + "UTF8", + "UTF_8", + "utf-8", + "utf8", + "utf_8", + NULL +}; +#endif + +static const char *ISO_8859_1_NAMES[] = { + "ISO-8859-1", +#if !defined(__GLIBC__) + "ISO8859-1", + "ISO88591", + "ISO_8859_1", + "ISO8859_1", + "iso-8859-1", + "iso8859-1", + "iso88591", + "iso_8859_1", + "iso8859_1", +#endif + NULL +}; + +class nsNativeCharsetConverter +{ +public: + nsNativeCharsetConverter(); + ~nsNativeCharsetConverter(); + + nsresult NativeToUnicode(const char **input , PRUint32 *inputLeft, + PRUnichar **output, PRUint32 *outputLeft); + nsresult UnicodeToNative(const PRUnichar **input , PRUint32 *inputLeft, + char **output, PRUint32 *outputLeft); + + static void GlobalInit(); + static void GlobalShutdown(); + +private: + static iconv_t gNativeToUnicode; + static iconv_t gUnicodeToNative; +#if defined(ENABLE_UTF8_FALLBACK_SUPPORT) + static iconv_t gNativeToUTF8; + static iconv_t gUTF8ToNative; + static iconv_t gUnicodeToUTF8; + static iconv_t gUTF8ToUnicode; +#endif + static PRLock *gLock; + static PRBool gInitialized; + + static void LazyInit(); + + static void Lock() { if (gLock) PR_Lock(gLock); } + static void Unlock() { if (gLock) PR_Unlock(gLock); } +}; + +iconv_t nsNativeCharsetConverter::gNativeToUnicode = INVALID_ICONV_T; +iconv_t nsNativeCharsetConverter::gUnicodeToNative = INVALID_ICONV_T; +#if defined(ENABLE_UTF8_FALLBACK_SUPPORT) +iconv_t nsNativeCharsetConverter::gNativeToUTF8 = INVALID_ICONV_T; +iconv_t nsNativeCharsetConverter::gUTF8ToNative = INVALID_ICONV_T; +iconv_t nsNativeCharsetConverter::gUnicodeToUTF8 = INVALID_ICONV_T; +iconv_t nsNativeCharsetConverter::gUTF8ToUnicode = INVALID_ICONV_T; +#endif +PRLock *nsNativeCharsetConverter::gLock = nsnull; +PRBool nsNativeCharsetConverter::gInitialized = PR_FALSE; + +void +nsNativeCharsetConverter::LazyInit() +{ + const char *blank_list[] = { "", NULL }; + const char **native_charset_list = blank_list; + const char *native_charset = nl_langinfo(CODESET); + if (native_charset == nsnull) { + NS_ERROR("native charset is unknown"); + // fallback to ISO-8859-1 + native_charset_list = ISO_8859_1_NAMES; + } + else + native_charset_list[0] = native_charset; + + gNativeToUnicode = xp_iconv_open(UTF_16_NAMES, native_charset_list); + gUnicodeToNative = xp_iconv_open(native_charset_list, UTF_16_NAMES); + +#if defined(ENABLE_UTF8_FALLBACK_SUPPORT) + if (gNativeToUnicode == INVALID_ICONV_T) { + gNativeToUTF8 = xp_iconv_open(UTF_8_NAMES, native_charset_list); + gUTF8ToUnicode = xp_iconv_open(UTF_16_NAMES, UTF_8_NAMES); + NS_ASSERTION(gNativeToUTF8 != INVALID_ICONV_T, "no native to utf-8 converter"); + NS_ASSERTION(gUTF8ToUnicode != INVALID_ICONV_T, "no utf-8 to utf-16 converter"); + } + if (gUnicodeToNative == INVALID_ICONV_T) { + gUnicodeToUTF8 = xp_iconv_open(UTF_8_NAMES, UTF_16_NAMES); + gUTF8ToNative = xp_iconv_open(native_charset_list, UTF_8_NAMES); + NS_ASSERTION(gUnicodeToUTF8 != INVALID_ICONV_T, "no utf-16 to utf-8 converter"); + NS_ASSERTION(gUTF8ToNative != INVALID_ICONV_T, "no utf-8 to native converter"); + } +#else + NS_ASSERTION(gNativeToUnicode != INVALID_ICONV_T, "no native to utf-16 converter"); + NS_ASSERTION(gUnicodeToNative != INVALID_ICONV_T, "no utf-16 to native converter"); +#endif + + /* + * On Solaris 8 (and newer?), the iconv modules converting to UCS-2 + * prepend a byte order mark unicode character (BOM, u+FEFF) during + * the first use of the iconv converter. The same is the case of + * glibc 2.2.9x and Tru64 V5 (see bug 208809) when 'UTF-16' is used. + * However, we use 'UTF-16LE/BE' in both cases, instead so that we + * should be safe. But just in case... + * + * This dummy conversion gets rid of the BOMs and fixes bug 153562. + */ + char dummy_input[1] = { ' ' }; + char dummy_output[4]; + + if (gNativeToUnicode != INVALID_ICONV_T) { + const char *input = dummy_input; + size_t input_left = sizeof(dummy_input); + char *output = dummy_output; + size_t output_left = sizeof(dummy_output); + + xp_iconv(gNativeToUnicode, &input, &input_left, &output, &output_left); + } +#if defined(ENABLE_UTF8_FALLBACK_SUPPORT) + if (gUTF8ToUnicode != INVALID_ICONV_T) { + const char *input = dummy_input; + size_t input_left = sizeof(dummy_input); + char *output = dummy_output; + size_t output_left = sizeof(dummy_output); + + xp_iconv(gUTF8ToUnicode, &input, &input_left, &output, &output_left); + } +#endif + + gInitialized = PR_TRUE; +} + +void +nsNativeCharsetConverter::GlobalInit() +{ + gLock = PR_NewLock(); + NS_ASSERTION(gLock, "lock creation failed"); +} + +void +nsNativeCharsetConverter::GlobalShutdown() +{ + if (gLock) { + PR_DestroyLock(gLock); + gLock = nsnull; + } + + if (gNativeToUnicode != INVALID_ICONV_T) { + iconv_close(gNativeToUnicode); + gNativeToUnicode = INVALID_ICONV_T; + } + + if (gUnicodeToNative != INVALID_ICONV_T) { + iconv_close(gUnicodeToNative); + gUnicodeToNative = INVALID_ICONV_T; + } + +#if defined(ENABLE_UTF8_FALLBACK_SUPPORT) + if (gNativeToUTF8 != INVALID_ICONV_T) { + iconv_close(gNativeToUTF8); + gNativeToUTF8 = INVALID_ICONV_T; + } + if (gUTF8ToNative != INVALID_ICONV_T) { + iconv_close(gUTF8ToNative); + gUTF8ToNative = INVALID_ICONV_T; + } + if (gUnicodeToUTF8 != INVALID_ICONV_T) { + iconv_close(gUnicodeToUTF8); + gUnicodeToUTF8 = INVALID_ICONV_T; + } + if (gUTF8ToUnicode != INVALID_ICONV_T) { + iconv_close(gUTF8ToUnicode); + gUTF8ToUnicode = INVALID_ICONV_T; + } +#endif + + gInitialized = PR_FALSE; +} + +nsNativeCharsetConverter::nsNativeCharsetConverter() +{ + Lock(); + if (!gInitialized) + LazyInit(); +} + +nsNativeCharsetConverter::~nsNativeCharsetConverter() +{ + // reset converters for next time + if (gNativeToUnicode != INVALID_ICONV_T) + xp_iconv_reset(gNativeToUnicode); + if (gUnicodeToNative != INVALID_ICONV_T) + xp_iconv_reset(gUnicodeToNative); +#if defined(ENABLE_UTF8_FALLBACK_SUPPORT) + if (gNativeToUTF8 != INVALID_ICONV_T) + xp_iconv_reset(gNativeToUTF8); + if (gUTF8ToNative != INVALID_ICONV_T) + xp_iconv_reset(gUTF8ToNative); + if (gUnicodeToUTF8 != INVALID_ICONV_T) + xp_iconv_reset(gUnicodeToUTF8); + if (gUTF8ToUnicode != INVALID_ICONV_T) + xp_iconv_reset(gUTF8ToUnicode); +#endif + Unlock(); +} + +nsresult +nsNativeCharsetConverter::NativeToUnicode(const char **input, + PRUint32 *inputLeft, + PRUnichar **output, + PRUint32 *outputLeft) +{ + size_t res = 0; + size_t inLeft = (size_t) *inputLeft; + size_t outLeft = (size_t) *outputLeft * 2; + + if (gNativeToUnicode != INVALID_ICONV_T) { + + res = xp_iconv(gNativeToUnicode, input, &inLeft, (char **) output, &outLeft); + + *inputLeft = inLeft; + *outputLeft = outLeft / 2; + if (res != (size_t) -1) + return NS_OK; + + NS_WARNING("conversion from native to utf-16 failed"); + + // reset converter + xp_iconv_reset(gNativeToUnicode); + } +#if defined(ENABLE_UTF8_FALLBACK_SUPPORT) + else if ((gNativeToUTF8 != INVALID_ICONV_T) && + (gUTF8ToUnicode != INVALID_ICONV_T)) { + // convert first to UTF8, then from UTF8 to UCS2 + const char *in = *input; + + char ubuf[1024]; + + // we assume we're always called with enough space in |output|, + // so convert many chars at a time... + while (inLeft) { + char *p = ubuf; + size_t n = sizeof(ubuf); + res = xp_iconv(gNativeToUTF8, &in, &inLeft, &p, &n); + if (res == (size_t) -1) { + NS_ERROR("conversion from native to utf-8 failed"); + break; + } + NS_ASSERTION(outLeft > 0, "bad assumption"); + p = ubuf; + n = sizeof(ubuf) - n; + res = xp_iconv(gUTF8ToUnicode, (const char **) &p, &n, (char **) output, &outLeft); + if (res == (size_t) -1) { + NS_ERROR("conversion from utf-8 to utf-16 failed"); + break; + } + } + + (*input) += (*inputLeft - inLeft); + *inputLeft = inLeft; + *outputLeft = outLeft / 2; + + if (res != (size_t) -1) + return NS_OK; + + // reset converters + xp_iconv_reset(gNativeToUTF8); + xp_iconv_reset(gUTF8ToUnicode); + } +#endif + + // fallback: zero-pad and hope for the best + // XXX This is lame and we have to do better. + isolatin1_to_utf16(input, inputLeft, output, outputLeft); + + return NS_OK; +} + +nsresult +nsNativeCharsetConverter::UnicodeToNative(const PRUnichar **input, + PRUint32 *inputLeft, + char **output, + PRUint32 *outputLeft) +{ + size_t res = 0; + size_t inLeft = (size_t) *inputLeft * 2; + size_t outLeft = (size_t) *outputLeft; + + if (gUnicodeToNative != INVALID_ICONV_T) { + res = xp_iconv(gUnicodeToNative, (const char **) input, &inLeft, output, &outLeft); + + if (res != (size_t) -1) { + *inputLeft = inLeft / 2; + *outputLeft = outLeft; + return NS_OK; + } + + NS_ERROR("iconv failed"); + + // reset converter + xp_iconv_reset(gUnicodeToNative); + } +#if defined(ENABLE_UTF8_FALLBACK_SUPPORT) + else if ((gUnicodeToUTF8 != INVALID_ICONV_T) && + (gUTF8ToNative != INVALID_ICONV_T)) { + const char *in = (const char *) *input; + + char ubuf[6]; // max utf-8 char length (really only needs to be 4 bytes) + + // convert one uchar at a time... + while (inLeft && outLeft) { + char *p = ubuf; + size_t n = sizeof(ubuf), one_uchar = sizeof(PRUnichar); + res = xp_iconv(gUnicodeToUTF8, &in, &one_uchar, &p, &n); + if (res == (size_t) -1) { + NS_ERROR("conversion from utf-16 to utf-8 failed"); + break; + } + p = ubuf; + n = sizeof(ubuf) - n; + res = xp_iconv(gUTF8ToNative, (const char **) &p, &n, output, &outLeft); + if (res == (size_t) -1) { + if (errno == E2BIG) { + // not enough room for last uchar... back up and return. + in -= sizeof(PRUnichar); + res = 0; + } + else + NS_ERROR("conversion from utf-8 to native failed"); + break; + } + inLeft -= sizeof(PRUnichar); + } + + if (res != (size_t) -1) { + (*input) += (*inputLeft - inLeft/2); + *inputLeft = inLeft/2; + *outputLeft = outLeft; + return NS_OK; + } + + // reset converters + xp_iconv_reset(gUnicodeToUTF8); + xp_iconv_reset(gUTF8ToNative); + } +#endif + + // fallback: truncate and hope for the best + utf16_to_isolatin1(input, inputLeft, output, outputLeft); + + return NS_OK; +} + +#endif // USE_ICONV + +//----------------------------------------------------------------------------- +// conversion using mb[r]towc/wc[r]tomb +//----------------------------------------------------------------------------- +#if defined(USE_STDCONV) +#if defined(HAVE_WCRTOMB) || defined(HAVE_MBRTOWC) +#include // mbrtowc, wcrtomb +#endif + +class nsNativeCharsetConverter +{ +public: + nsNativeCharsetConverter(); + + nsresult NativeToUnicode(const char **input , PRUint32 *inputLeft, + PRUnichar **output, PRUint32 *outputLeft); + nsresult UnicodeToNative(const PRUnichar **input , PRUint32 *inputLeft, + char **output, PRUint32 *outputLeft); + + static void GlobalInit(); + static void GlobalShutdown() { } + +private: + static PRBool gWCharIsUnicode; + +#if defined(HAVE_WCRTOMB) || defined(HAVE_MBRTOWC) + mbstate_t ps; +#endif +}; + +PRBool nsNativeCharsetConverter::gWCharIsUnicode = PR_FALSE; + +nsNativeCharsetConverter::nsNativeCharsetConverter() +{ +#if defined(HAVE_WCRTOMB) || defined(HAVE_MBRTOWC) + memset(&ps, 0, sizeof(ps)); +#endif +} + +void +nsNativeCharsetConverter::GlobalInit() +{ + // verify that wchar_t for the current locale is actually unicode. + // if it is not, then we should avoid calling mbtowc/wctomb and + // just fallback on zero-pad/truncation conversion. + // + // this test cannot be done at build time because the encoding of + // wchar_t may depend on the runtime locale. sad, but true!! + // + // so, if wchar_t is unicode then converting an ASCII character + // to wchar_t should not change its numeric value. we'll just + // check what happens with the ASCII 'a' character. + // + // this test is not perfect... obviously, it could yield false + // positives, but then at least ASCII text would be converted + // properly (or maybe just the 'a' character) -- oh well :( + + char a = 'a'; + unsigned int w = 0; + + int res = mbtowc((wchar_t *) &w, &a, 1); + + gWCharIsUnicode = (res != -1 && w == 'a'); + +#ifdef DEBUG + if (!gWCharIsUnicode) + NS_WARNING("wchar_t is not unicode (unicode conversion will be lossy)"); +#endif +} + +nsresult +nsNativeCharsetConverter::NativeToUnicode(const char **input, + PRUint32 *inputLeft, + PRUnichar **output, + PRUint32 *outputLeft) +{ + if (gWCharIsUnicode) { + int incr; + + // cannot use wchar_t here since it may have been redefined (e.g., + // via -fshort-wchar). hopefully, sizeof(tmp) is sufficient XP. + unsigned int tmp = 0; + while (*inputLeft && *outputLeft) { +#ifdef HAVE_MBRTOWC + incr = (int) mbrtowc((wchar_t *) &tmp, *input, *inputLeft, &ps); +#else + // XXX is this thread-safe? + incr = (int) mbtowc((wchar_t *) &tmp, *input, *inputLeft); +#endif + if (incr < 0) { + NS_WARNING("mbtowc failed: possible charset mismatch"); + // zero-pad and hope for the best + tmp = (unsigned char) **input; + incr = 1; + } + **output = (PRUnichar) tmp; + (*input) += incr; + (*inputLeft) -= incr; + (*output)++; + (*outputLeft)--; + } + } + else { + // wchar_t isn't unicode, so the best we can do is treat the + // input as if it is isolatin1 :( + isolatin1_to_utf16(input, inputLeft, output, outputLeft); + } + + return NS_OK; +} + +nsresult +nsNativeCharsetConverter::UnicodeToNative(const PRUnichar **input, + PRUint32 *inputLeft, + char **output, + PRUint32 *outputLeft) +{ + if (gWCharIsUnicode) { + int incr; + + while (*inputLeft && *outputLeft >= MB_CUR_MAX) { +#ifdef HAVE_WCRTOMB + incr = (int) wcrtomb(*output, (wchar_t) **input, &ps); +#else + // XXX is this thread-safe? + incr = (int) wctomb(*output, (wchar_t) **input); +#endif + if (incr < 0) { + NS_WARNING("mbtowc failed: possible charset mismatch"); + **output = (unsigned char) **input; // truncate + incr = 1; + } + // most likely we're dead anyways if this assertion should fire + NS_ASSERTION(PRUint32(incr) <= *outputLeft, "wrote beyond end of string"); + (*output) += incr; + (*outputLeft) -= incr; + (*input)++; + (*inputLeft)--; + } + } + else { + // wchar_t isn't unicode, so the best we can do is treat the + // input as if it is isolatin1 :( + utf16_to_isolatin1(input, inputLeft, output, outputLeft); + } + + return NS_OK; +} + +#endif // USE_STDCONV + +//----------------------------------------------------------------------------- +// API implementation +//----------------------------------------------------------------------------- + +NS_COM nsresult +NS_CopyNativeToUnicode(const nsACString &input, nsAString &output) +{ + output.Truncate(); + + PRUint32 inputLen = input.Length(); + + nsACString::const_iterator iter; + input.BeginReading(iter); + + // + // OPTIMIZATION: preallocate space for largest possible result; convert + // directly into the result buffer to avoid intermediate buffer copy. + // + // this will generally result in a larger allocation, but that seems + // better than an extra buffer copy. + // + output.SetLength(inputLen); + nsAString::iterator out_iter; + output.BeginWriting(out_iter); + + PRUnichar *result = out_iter.get(); + PRUint32 resultLeft = inputLen; + + const char *buf = iter.get(); + PRUint32 bufLeft = inputLen; + + nsNativeCharsetConverter conv; + nsresult rv = conv.NativeToUnicode(&buf, &bufLeft, &result, &resultLeft); + if (NS_SUCCEEDED(rv)) { + NS_ASSERTION(bufLeft == 0, "did not consume entire input buffer"); + output.SetLength(inputLen - resultLeft); + } + return rv; +} + +NS_COM nsresult +NS_CopyUnicodeToNative(const nsAString &input, nsACString &output) +{ + output.Truncate(); + + nsAString::const_iterator iter, end; + input.BeginReading(iter); + input.EndReading(end); + + // cannot easily avoid intermediate buffer copy. + char temp[4096]; + + nsNativeCharsetConverter conv; + + const PRUnichar *buf = iter.get(); + PRUint32 bufLeft = Distance(iter, end); + while (bufLeft) { + char *p = temp; + PRUint32 tempLeft = sizeof(temp); + + nsresult rv = conv.UnicodeToNative(&buf, &bufLeft, &p, &tempLeft); + if (NS_FAILED(rv)) return rv; + + if (tempLeft < sizeof(temp)) + output.Append(temp, sizeof(temp) - tempLeft); + } + return NS_OK; +} + +void +NS_StartupNativeCharsetUtils() +{ + // + // need to initialize the locale or else charset conversion will fail. + // better not delay this in case some other component alters the locale + // settings. + // + // XXX we assume that we are called early enough that we should + // always be the first to care about the locale's charset. + // + setlocale(LC_CTYPE, ""); + + nsNativeCharsetConverter::GlobalInit(); +} + +void +NS_ShutdownNativeCharsetUtils() +{ + nsNativeCharsetConverter::GlobalShutdown(); +} + +//----------------------------------------------------------------------------- +// XP_BEOS +//----------------------------------------------------------------------------- +#elif defined(XP_BEOS) + +#include "nsAString.h" +#include "nsReadableUtils.h" +#include "nsString.h" + +NS_COM nsresult +NS_CopyNativeToUnicode(const nsACString &input, nsAString &output) +{ + CopyUTF8toUTF16(input, output); + return NS_OK; +} + +NS_COM nsresult +NS_CopyUnicodeToNative(const nsAString &input, nsACString &output) +{ + CopyUTF16toUTF8(input, output); + return NS_OK; +} + +void +NS_StartupNativeCharsetUtils() +{ +} + +void +NS_ShutdownNativeCharsetUtils() +{ +} + +//----------------------------------------------------------------------------- +// XP_WIN +//----------------------------------------------------------------------------- +#elif defined(XP_WIN) + +#include +#include "nsAString.h" + +NS_COM nsresult +NS_CopyNativeToUnicode(const nsACString &input, nsAString &output) +{ + PRUint32 inputLen = input.Length(); + + nsACString::const_iterator iter; + input.BeginReading(iter); + + const char *buf = iter.get(); + + // determine length of result + PRUint32 resultLen = 0; + int n = ::MultiByteToWideChar(CP_ACP, 0, buf, inputLen, NULL, 0); + if (n > 0) + resultLen += n; + + // allocate sufficient space + output.SetLength(resultLen); + if (resultLen > 0) { + nsAString::iterator out_iter; + output.BeginWriting(out_iter); + + PRUnichar *result = out_iter.get(); + + ::MultiByteToWideChar(CP_ACP, 0, buf, inputLen, result, resultLen); + } + return NS_OK; +} + +NS_COM nsresult +NS_CopyUnicodeToNative(const nsAString &input, nsACString &output) +{ + PRUint32 inputLen = input.Length(); + + nsAString::const_iterator iter; + input.BeginReading(iter); + + const PRUnichar *buf = iter.get(); + + // determine length of result + PRUint32 resultLen = 0; + + int n = ::WideCharToMultiByte(CP_ACP, 0, buf, inputLen, NULL, 0, NULL, NULL); + if (n > 0) + resultLen += n; + + // allocate sufficient space + output.SetLength(resultLen); + if (resultLen > 0) { + nsACString::iterator out_iter; + output.BeginWriting(out_iter); + + // default "defaultChar" is '?', which is an illegal character on windows + // file system. That will cause file uncreatable. Change it to '_' + const char defaultChar = '_'; + + char *result = out_iter.get(); + + ::WideCharToMultiByte(CP_ACP, 0, buf, inputLen, result, resultLen, + &defaultChar, NULL); + } + return NS_OK; +} + +void +NS_StartupNativeCharsetUtils() +{ +} + +void +NS_ShutdownNativeCharsetUtils() +{ +} + +//----------------------------------------------------------------------------- +// XP_OS2 +//----------------------------------------------------------------------------- +#elif defined(XP_OS2) + +#define INCL_DOS +#include +#include +#include "nsAString.h" +#include +#include "nsNativeCharsetUtils.h" + +static UconvObject UnicodeConverter = NULL; + +NS_COM nsresult +NS_CopyNativeToUnicode(const nsACString &input, nsAString &output) +{ + PRUint32 inputLen = input.Length(); + + nsACString::const_iterator iter; + input.BeginReading(iter); + const char *inputStr = iter.get(); + + // determine length of result + PRUint32 resultLen = inputLen; + output.SetLength(resultLen); + + nsAString::iterator out_iter; + output.BeginWriting(out_iter); + UniChar *result = (UniChar*)out_iter.get(); + + size_t cSubs = 0; + size_t resultLeft = resultLen; + + if (!UnicodeConverter) + NS_StartupNativeCharsetUtils(); + + int unirc = ::UniUconvToUcs(UnicodeConverter, (void**)&inputStr, &inputLen, + &result, &resultLeft, &cSubs); + + NS_ASSERTION(unirc != UCONV_E2BIG, "Path too big"); + + if (unirc != ULS_SUCCESS) { + output.Truncate(); + return NS_ERROR_FAILURE; + } + + // Need to update string length to reflect how many bytes were actually + // written. + output.Truncate(resultLen - resultLeft); + return NS_OK; +} + +NS_COM nsresult +NS_CopyUnicodeToNative(const nsAString &input, nsACString &output) +{ + size_t inputLen = input.Length(); + + nsAString::const_iterator iter; + input.BeginReading(iter); + UniChar* inputStr = (UniChar*) NS_CONST_CAST(PRUnichar*, iter.get()); + + // maximum length of unicode string of length x converted to native + // codepage is x*2 + size_t resultLen = inputLen * 2; + output.SetLength(resultLen); + + nsACString::iterator out_iter; + output.BeginWriting(out_iter); + char *result = out_iter.get(); + + size_t cSubs = 0; + size_t resultLeft = resultLen; + + if (!UnicodeConverter) + NS_StartupNativeCharsetUtils(); + + int unirc = ::UniUconvFromUcs(UnicodeConverter, &inputStr, &inputLen, + (void**)&result, &resultLeft, &cSubs); + + NS_ASSERTION(unirc != UCONV_E2BIG, "Path too big"); + + if (unirc != ULS_SUCCESS) { + output.Truncate(); + return NS_ERROR_FAILURE; + } + + // Need to update string length to reflect how many bytes were actually + // written. + output.Truncate(resultLen - resultLeft); + return NS_OK; +} + +void +NS_StartupNativeCharsetUtils() +{ + ULONG ulLength; + ULONG ulCodePage; + DosQueryCp(sizeof(ULONG), &ulCodePage, &ulLength); + + UniChar codepage[20]; + int unirc = ::UniMapCpToUcsCp(ulCodePage, codepage, 20); + if (unirc == ULS_SUCCESS) { + unirc = ::UniCreateUconvObject(codepage, &UnicodeConverter); + if (unirc == ULS_SUCCESS) { + uconv_attribute_t attr; + ::UniQueryUconvObject(UnicodeConverter, &attr, sizeof(uconv_attribute_t), + NULL, NULL, NULL); + attr.options = UCONV_OPTION_SUBSTITUTE_BOTH; + attr.subchar_len=1; + attr.subchar[0]='_'; + ::UniSetUconvObject(UnicodeConverter, &attr); + } + } +} + +void +NS_ShutdownNativeCharsetUtils() +{ + ::UniFreeUconvObject(UnicodeConverter); +} + +//----------------------------------------------------------------------------- +// XP_MAC +//----------------------------------------------------------------------------- +#elif defined(XP_MAC) + +#include +#include +#include +#include +#include "nsAString.h" + +class nsFSStringConversionMac { +public: + static nsresult UCSToFS(const nsAString& aIn, nsACString& aOut); + static nsresult FSToUCS(const nsACString& ain, nsAString& aOut); + + static void CleanUp(); + +private: + static TextEncoding GetSystemEncoding(); + static nsresult PrepareEncoder(); + static nsresult PrepareDecoder(); + + static UnicodeToTextInfo sEncoderInfo; + static TextToUnicodeInfo sDecoderInfo; +}; + +UnicodeToTextInfo nsFSStringConversionMac::sEncoderInfo = nsnull; +TextToUnicodeInfo nsFSStringConversionMac::sDecoderInfo = nsnull; + +nsresult nsFSStringConversionMac::UCSToFS(const nsAString& aIn, nsACString& aOut) +{ + nsresult rv = PrepareEncoder(); + if (NS_FAILED(rv)) return rv; + + OSStatus err = noErr; + char stackBuffer[512]; + + aOut.Truncate(); + + // for each chunk of |aIn|... + nsReadingIterator iter; + aIn.BeginReading(iter); + + PRUint32 fragmentLength = PRUint32(iter.size_forward()); + UInt32 bytesLeft = fragmentLength * sizeof(UniChar); + + do { + UInt32 bytesRead = 0, bytesWritten = 0; + err = ::ConvertFromUnicodeToText(sEncoderInfo, + bytesLeft, + (const UniChar*)iter.get(), + kUnicodeUseFallbacksMask | kUnicodeLooseMappingsMask, + 0, nsnull, nsnull, nsnull, + sizeof(stackBuffer), + &bytesRead, + &bytesWritten, + stackBuffer); + if (err == kTECUsedFallbacksStatus) + err = noErr; + else if (err == kTECOutputBufferFullStatus) { + bytesLeft -= bytesRead; + iter.advance(bytesRead / sizeof(UniChar)); + } + aOut.Append(stackBuffer, bytesWritten); + } + while (err == kTECOutputBufferFullStatus); + + return (err == noErr) ? NS_OK : NS_ERROR_FAILURE; +} + +nsresult nsFSStringConversionMac::FSToUCS(const nsACString& aIn, nsAString& aOut) +{ + nsresult rv = PrepareDecoder(); + if (NS_FAILED(rv)) return rv; + + OSStatus err = noErr; + UniChar stackBuffer[512]; + + aOut.Truncate(0); + + // for each chunk of |aIn|... + nsReadingIterator iter; + aIn.BeginReading(iter); + + PRUint32 fragmentLength = PRUint32(iter.size_forward()); + UInt32 bytesLeft = fragmentLength; + + do { + UInt32 bytesRead = 0, bytesWritten = 0; + err = ::ConvertFromTextToUnicode(sDecoderInfo, + bytesLeft, + iter.get(), + kUnicodeUseFallbacksMask | kUnicodeLooseMappingsMask, + 0, nsnull, nsnull, nsnull, + sizeof(stackBuffer), + &bytesRead, + &bytesWritten, + stackBuffer); + if (err == kTECUsedFallbacksStatus) + err = noErr; + else if (err == kTECOutputBufferFullStatus) { + bytesLeft -= bytesRead; + iter.advance(bytesRead); + } + aOut.Append((PRUnichar *)stackBuffer, bytesWritten / sizeof(PRUnichar)); + } + while (err == kTECOutputBufferFullStatus); + + return (err == noErr) ? NS_OK : NS_ERROR_FAILURE; +} + +void nsFSStringConversionMac::CleanUp() +{ + if (sDecoderInfo) { + ::DisposeTextToUnicodeInfo(&sDecoderInfo); + sDecoderInfo = nsnull; + } + if (sEncoderInfo) { + ::DisposeUnicodeToTextInfo(&sEncoderInfo); + sEncoderInfo = nsnull; + } +} + +TextEncoding nsFSStringConversionMac::GetSystemEncoding() +{ + OSStatus err; + TextEncoding theEncoding; + + err = ::UpgradeScriptInfoToTextEncoding(smSystemScript, kTextLanguageDontCare, + kTextRegionDontCare, NULL, &theEncoding); + + if (err != noErr) + theEncoding = kTextEncodingMacRoman; + + return theEncoding; +} + +nsresult nsFSStringConversionMac::PrepareEncoder() +{ + nsresult rv = NS_OK; + if (!sEncoderInfo) { + OSStatus err; + err = ::CreateUnicodeToTextInfoByEncoding(GetSystemEncoding(), &sEncoderInfo); + if (err) + rv = NS_ERROR_FAILURE; + } + return rv; +} + +nsresult nsFSStringConversionMac::PrepareDecoder() +{ + nsresult rv = NS_OK; + if (!sDecoderInfo) { + OSStatus err; + err = ::CreateTextToUnicodeInfoByEncoding(GetSystemEncoding(), &sDecoderInfo); + if (err) + rv = NS_ERROR_FAILURE; + } + return rv; +} + +NS_COM nsresult +NS_CopyNativeToUnicode(const nsACString &input, nsAString &output) +{ + return nsFSStringConversionMac::FSToUCS(input, output); +} + +NS_COM nsresult +NS_CopyUnicodeToNative(const nsAString &input, nsACString &output) +{ + return nsFSStringConversionMac::UCSToFS(input, output); +} + +void +NS_StartupNativeCharsetUtils() +{ +} + +void +NS_ShutdownNativeCharsetUtils() +{ + nsFSStringConversionMac::CleanUp(); +} + +//----------------------------------------------------------------------------- +// default : truncate/zeropad +//----------------------------------------------------------------------------- +#else + +#include "nsReadableUtils.h" + +NS_COM nsresult +NS_CopyNativeToUnicode(const nsACString &input, nsAString &output) +{ + CopyASCIItoUCS2(input, output); + return NS_OK; +} + +NS_COM nsresult +NS_CopyUnicodeToNative(const nsAString &input, nsACString &output) +{ + CopyUCS2toASCII(input, output); + return NS_OK; +} + +void +NS_StartupNativeCharsetUtils() +{ +} + +void +NS_ShutdownNativeCharsetUtils() +{ +} + +#endif diff --git a/src/libs/xpcom18a4/xpcom/io/nsNativeCharsetUtils.h b/src/libs/xpcom18a4/xpcom/io/nsNativeCharsetUtils.h new file mode 100644 index 00000000..539fa37f --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsNativeCharsetUtils.h @@ -0,0 +1,66 @@ +/* ***** 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 ***** */ + +#ifndef nsNativeCharsetUtils_h__ +#define nsNativeCharsetUtils_h__ + + +/*****************************************************************************\ + * * + * **** NOTICE **** * + * * + * *** THESE ARE NOT GENERAL PURPOSE CONVERTERS *** * + * * + * NS_CopyNativeToUnicode / NS_CopyUnicodeToNative should only be used * + * for converting *FILENAMES* between native and unicode. They are not * + * designed or tested for general encoding converter use. * + * * +\*****************************************************************************/ + +/** + * thread-safe conversion routines that do not depend on uconv libraries. + */ +NS_COM nsresult NS_CopyNativeToUnicode(const nsACString &input, nsAString &output); +NS_COM nsresult NS_CopyUnicodeToNative(const nsAString &input, nsACString &output); + +/** + * internal + */ +void NS_StartupNativeCharsetUtils(); +void NS_ShutdownNativeCharsetUtils(); + +#endif // nsNativeCharsetUtils_h__ diff --git a/src/libs/xpcom18a4/xpcom/io/nsPipe3.cpp b/src/libs/xpcom18a4/xpcom/io/nsPipe3.cpp new file mode 100644 index 00000000..be06179f --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsPipe3.cpp @@ -0,0 +1,1276 @@ +/* ***** 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 "nsIPipe.h" +#include "nsIEventTarget.h" +#include "nsISeekableStream.h" +#include "nsSegmentedBuffer.h" +#include "nsStreamUtils.h" +#include "nsAutoLock.h" +#include "nsCOMPtr.h" +#include "nsCRT.h" +#include "prlog.h" +#include "nsInt64.h" + +#if defined(PR_LOGGING) +// +// set NSPR_LOG_MODULES=nsPipe:5 +// +static PRLogModuleInfo *gPipeLog = nsnull; +#define LOG(args) PR_LOG(gPipeLog, PR_LOG_DEBUG, args) +#else +#define LOG(args) +#endif + +#define DEFAULT_SEGMENT_SIZE 4096 +#define DEFAULT_SEGMENT_COUNT 16 + +class nsPipe; +class nsPipeEvents; +class nsPipeInputStream; +class nsPipeOutputStream; + +//----------------------------------------------------------------------------- + +// this class is used to delay notifications until the end of a particular +// scope. it helps avoid the complexity of issuing callbacks while inside +// a critical section. +class nsPipeEvents +{ +public: + nsPipeEvents() { } + ~nsPipeEvents(); + + inline void NotifyInputReady(nsIAsyncInputStream *stream, + nsIInputStreamCallback *callback) + { + NS_ASSERTION(!mInputCallback, "already have an input event"); + mInputStream = stream; + mInputCallback = callback; + } + + inline void NotifyOutputReady(nsIAsyncOutputStream *stream, + nsIOutputStreamCallback *callback) + { + NS_ASSERTION(!mOutputCallback, "already have an output event"); + mOutputStream = stream; + mOutputCallback = callback; + } + +private: + nsCOMPtr mInputStream; + nsCOMPtr mInputCallback; + nsCOMPtr mOutputStream; + nsCOMPtr mOutputCallback; +}; + +//----------------------------------------------------------------------------- + +// the input end of a pipe (allocated as a member of the pipe). +class nsPipeInputStream : public nsIAsyncInputStream + , public nsISeekableStream + , public nsISearchableInputStream +{ +public: + // since this class will be allocated as a member of the pipe, we do not + // need our own ref count. instead, we share the lifetime (the ref count) + // of the entire pipe. this macro is just convenience since it does not + // declare a mRefCount variable; however, don't let the name fool you... + // we are not inheriting from nsPipe ;-) + NS_DECL_ISUPPORTS_INHERITED + + NS_DECL_NSIINPUTSTREAM + NS_DECL_NSIASYNCINPUTSTREAM + NS_DECL_NSISEEKABLESTREAM + NS_DECL_NSISEARCHABLEINPUTSTREAM + + nsPipeInputStream(nsPipe *pipe) + : mPipe(pipe) + , mReaderRefCnt(0) + , mLogicalOffset(0) + , mBlocking(PR_TRUE) + , mBlocked(PR_FALSE) + , mAvailable(0) + , mCallbackFlags(0) + { } + + nsresult Fill(); + void SetNonBlocking(PRBool aNonBlocking) { mBlocking = !aNonBlocking; } + + PRUint32 Available() { return mAvailable; } + void ReduceAvailable(PRUint32 avail) { mAvailable -= avail; } + + // synchronously wait for the pipe to become readable. + nsresult Wait(); + + // these functions return true to indicate that the pipe's monitor should + // be notified, to wake up a blocked reader if any. + PRBool OnInputReadable(PRUint32 bytesWritten, nsPipeEvents &); + PRBool OnInputException(nsresult, nsPipeEvents &); + +private: + nsPipe *mPipe; + + // separate refcnt so that we know when to close the consumer + nsrefcnt mReaderRefCnt; + nsInt64 mLogicalOffset; + PRPackedBool mBlocking; + + // these variables can only be accessed while inside the pipe's monitor + PRPackedBool mBlocked; + PRUint32 mAvailable; + nsCOMPtr mCallback; + PRUint32 mCallbackFlags; +}; + +//----------------------------------------------------------------------------- + +// the output end of a pipe (allocated as a member of the pipe). +class nsPipeOutputStream : public nsIAsyncOutputStream + , public nsISeekableStream +{ +public: + // since this class will be allocated as a member of the pipe, we do not + // need our own ref count. instead, we share the lifetime (the ref count) + // of the entire pipe. this macro is just convenience since it does not + // declare a mRefCount variable; however, don't let the name fool you... + // we are not inheriting from nsPipe ;-) + NS_DECL_ISUPPORTS_INHERITED + + NS_DECL_NSIOUTPUTSTREAM + NS_DECL_NSIASYNCOUTPUTSTREAM + NS_DECL_NSISEEKABLESTREAM + + nsPipeOutputStream(nsPipe *pipe) + : mPipe(pipe) + , mWriterRefCnt(0) + , mLogicalOffset(0) + , mBlocking(PR_TRUE) + , mBlocked(PR_FALSE) + , mWritable(PR_TRUE) + , mCallbackFlags(0) + { } + + void SetNonBlocking(PRBool aNonBlocking) { mBlocking = !aNonBlocking; } + void SetWritable(PRBool writable) { mWritable = writable; } + + // synchronously wait for the pipe to become writable. + nsresult Wait(); + + // these functions return true to indicate that the pipe's monitor should + // be notified, to wake up a blocked writer if any. + PRBool OnOutputWritable(nsPipeEvents &); + PRBool OnOutputException(nsresult, nsPipeEvents &); + +private: + nsPipe *mPipe; + + // separate refcnt so that we know when to close the producer + nsrefcnt mWriterRefCnt; + nsInt64 mLogicalOffset; + PRPackedBool mBlocking; + + // these variables can only be accessed while inside the pipe's monitor + PRPackedBool mBlocked; + PRPackedBool mWritable; + nsCOMPtr mCallback; + PRUint32 mCallbackFlags; +}; + +//----------------------------------------------------------------------------- + +class nsPipe : public nsIPipe +{ +public: + friend class nsPipeInputStream; + friend class nsPipeOutputStream; + + NS_DECL_ISUPPORTS + NS_DECL_NSIPIPE + + // nsPipe methods: + nsPipe(); + +private: + ~nsPipe(); + +public: + // + // methods below may only be called while inside the pipe's monitor + // + + void PeekSegment(PRUint32 n, char *&cursor, char *&limit); + + // + // methods below may be called while outside the pipe's monitor + // + + nsresult GetReadSegment(const char *&segment, PRUint32 &segmentLen); + void AdvanceReadCursor(PRUint32 count); + + nsresult GetWriteSegment(char *&segment, PRUint32 &segmentLen); + void AdvanceWriteCursor(PRUint32 count); + + void OnPipeException(nsresult reason, PRBool outputOnly = PR_FALSE); + +protected: + // We can't inherit from both nsIInputStream and nsIOutputStream + // because they collide on their Close method. Consequently we nest their + // implementations to avoid the extra object allocation. + nsPipeInputStream mInput; + nsPipeOutputStream mOutput; + + PRMonitor* mMonitor; + nsSegmentedBuffer mBuffer; + + char* mReadCursor; + char* mReadLimit; + + PRInt32 mWriteSegment; + char* mWriteCursor; + char* mWriteLimit; + + nsresult mStatus; +}; + +// +// NOTES on buffer architecture: +// +// +-----------------+ - - mBuffer.GetSegment(0) +// | | +// + - - - - - - - - + - - mReadCursor +// |/////////////////| +// |/////////////////| +// |/////////////////| +// |/////////////////| +// +-----------------+ - - mReadLimit +// | +// +-----------------+ +// |/////////////////| +// |/////////////////| +// |/////////////////| +// |/////////////////| +// |/////////////////| +// |/////////////////| +// +-----------------+ +// | +// +-----------------+ - - mBuffer.GetSegment(mWriteSegment) +// |/////////////////| +// |/////////////////| +// |/////////////////| +// + - - - - - - - - + - - mWriteCursor +// | | +// | | +// +-----------------+ - - mWriteLimit +// +// (shaded region contains data) +// +// NOTE: on some systems (notably OS/2), the heap allocator uses an arena for +// small allocations (e.g., 64 byte allocations). this means that buffers may +// be allocated back-to-back. in the diagram above, for example, mReadLimit +// would actually be pointing at the beginning of the next segment. when +// making changes to this file, please keep this fact in mind. +// + +//----------------------------------------------------------------------------- +// nsPipe methods: +//----------------------------------------------------------------------------- + +nsPipe::nsPipe() + : mInput(this) + , mOutput(this) + , mMonitor(nsnull) + , mReadCursor(nsnull) + , mReadLimit(nsnull) + , mWriteSegment(-1) + , mWriteCursor(nsnull) + , mWriteLimit(nsnull) + , mStatus(NS_OK) +{ +} + +nsPipe::~nsPipe() +{ + if (mMonitor) + PR_DestroyMonitor(mMonitor); +} + +NS_IMPL_THREADSAFE_ISUPPORTS1(nsPipe, nsIPipe) + +NS_IMETHODIMP +nsPipe::Init(PRBool nonBlockingIn, + PRBool nonBlockingOut, + PRUint32 segmentSize, + PRUint32 segmentCount, + nsIMemory *segmentAlloc) +{ + mMonitor = PR_NewMonitor(); + if (!mMonitor) + return NS_ERROR_OUT_OF_MEMORY; + + if (segmentSize == 0) + segmentSize = DEFAULT_SEGMENT_SIZE; + if (segmentCount == 0) + segmentCount = DEFAULT_SEGMENT_COUNT; + + // protect against overflow + PRUint32 maxCount = PRUint32(-1) / segmentSize; + if (segmentCount > maxCount) + segmentCount = maxCount; + + nsresult rv = mBuffer.Init(segmentSize, segmentSize * segmentCount, segmentAlloc); + if (NS_FAILED(rv)) + return rv; + + mInput.SetNonBlocking(nonBlockingIn); + mOutput.SetNonBlocking(nonBlockingOut); + return NS_OK; +} + +NS_IMETHODIMP +nsPipe::GetInputStream(nsIAsyncInputStream **aInputStream) +{ + NS_ADDREF(*aInputStream = &mInput); + return NS_OK; +} + +NS_IMETHODIMP +nsPipe::GetOutputStream(nsIAsyncOutputStream **aOutputStream) +{ + NS_ADDREF(*aOutputStream = &mOutput); + return NS_OK; +} + +void +nsPipe::PeekSegment(PRUint32 index, char *&cursor, char *&limit) +{ + if (index == 0) { + NS_ASSERTION(!mReadCursor || mBuffer.GetSegmentCount(), "unexpected state"); + cursor = mReadCursor; + limit = mReadLimit; + } + else { + PRUint32 numSegments = mBuffer.GetSegmentCount(); + if (index >= numSegments) + cursor = limit = nsnull; + else { + cursor = mBuffer.GetSegment(index); + if (mWriteSegment == (PRInt32) index) + limit = mWriteCursor; + else + limit = cursor + mBuffer.GetSegmentSize(); + } + } +} + +nsresult +nsPipe::GetReadSegment(const char *&segment, PRUint32 &segmentLen) +{ + nsAutoMonitor mon(mMonitor); + + if (mReadCursor == mReadLimit) + return NS_FAILED(mStatus) ? mStatus : NS_BASE_STREAM_WOULD_BLOCK; + + segment = mReadCursor; + segmentLen = mReadLimit - mReadCursor; + return NS_OK; +} + +void +nsPipe::AdvanceReadCursor(PRUint32 bytesRead) +{ + NS_ASSERTION(bytesRead, "dont call if no bytes read"); + + nsPipeEvents events; + { + nsAutoMonitor mon(mMonitor); + + LOG(("III advancing read cursor by %u\n", bytesRead)); + NS_ASSERTION(bytesRead <= mBuffer.GetSegmentSize(), "read too much"); + + mReadCursor += bytesRead; + NS_ASSERTION(mReadCursor <= mReadLimit, "read cursor exceeds limit"); + + mInput.ReduceAvailable(bytesRead); + + if (mReadCursor == mReadLimit) { + // we've reached the limit of how much we can read from this segment. + // if at the end of this segment, then we must discard this segment. + + // if still writing in this segment then bail because we're not done + // with the segment and have to wait for now... + if (mWriteSegment == 0 && mWriteLimit > mWriteCursor) { + NS_ASSERTION(mReadLimit == mWriteCursor, "unexpected state"); + return; + } + + // shift write segment index (-1 indicates an empty buffer). + --mWriteSegment; + + // done with this segment + mBuffer.DeleteFirstSegment(); + LOG(("III deleting first segment\n")); + + if (mWriteSegment == -1) { + // buffer is completely empty + mReadCursor = nsnull; + mReadLimit = nsnull; + mWriteCursor = nsnull; + mWriteLimit = nsnull; + } + else { + // advance read cursor and limit to next buffer segment + mReadCursor = mBuffer.GetSegment(0); + if (mWriteSegment == 0) + mReadLimit = mWriteCursor; + else + mReadLimit = mReadCursor + mBuffer.GetSegmentSize(); + } + + // we've free'd up a segment, so notify output stream that pipe has + // room for a new segment. + if (mOutput.OnOutputWritable(events)) + mon.Notify(); + } + } +} + +nsresult +nsPipe::GetWriteSegment(char *&segment, PRUint32 &segmentLen) +{ + nsAutoMonitor mon(mMonitor); + + if (NS_FAILED(mStatus)) + return mStatus; + + // write cursor and limit may both be null indicating an empty buffer. + if (mWriteCursor == mWriteLimit) { + char *seg = mBuffer.AppendNewSegment(); + // pipe is full + if (seg == nsnull) + return NS_BASE_STREAM_WOULD_BLOCK; + LOG(("OOO appended new segment\n")); + mWriteCursor = seg; + mWriteLimit = mWriteCursor + mBuffer.GetSegmentSize(); + ++mWriteSegment; + } + + // make sure read cursor is initialized + if (mReadCursor == nsnull) { + NS_ASSERTION(mWriteSegment == 0, "unexpected null read cursor"); + mReadCursor = mReadLimit = mWriteCursor; + } + + // check to see if we can roll-back our read and write cursors to the + // beginning of the current/first segment. this is purely an optimization. + if (mReadCursor == mWriteCursor && mWriteSegment == 0) { + char *head = mBuffer.GetSegment(0); + LOG(("OOO rolling back write cursor %u bytes\n", mWriteCursor - head)); + mWriteCursor = mReadCursor = mReadLimit = head; + } + + segment = mWriteCursor; + segmentLen = mWriteLimit - mWriteCursor; + return NS_OK; +} + +void +nsPipe::AdvanceWriteCursor(PRUint32 bytesWritten) +{ + NS_ASSERTION(bytesWritten, "dont call if no bytes written"); + + nsPipeEvents events; + { + nsAutoMonitor mon(mMonitor); + + LOG(("OOO advancing write cursor by %u\n", bytesWritten)); + + char *newWriteCursor = mWriteCursor + bytesWritten; + NS_ASSERTION(newWriteCursor <= mWriteLimit, "write cursor exceeds limit"); + + // update read limit if reading in the same segment + if (mWriteSegment == 0 && mReadLimit == mWriteCursor) + mReadLimit = newWriteCursor; + + mWriteCursor = newWriteCursor; + + NS_ASSERTION(mReadCursor != mWriteCursor, "read cursor is bad"); + + // update the writable flag on the output stream + if (mWriteCursor == mWriteLimit) { + if (mBuffer.GetSize() >= mBuffer.GetMaxSize()) + mOutput.SetWritable(PR_FALSE); + } + + // notify input stream that pipe now contains additional data + if (mInput.OnInputReadable(bytesWritten, events)) + mon.Notify(); + } +} + +void +nsPipe::OnPipeException(nsresult reason, PRBool outputOnly) +{ + LOG(("PPP nsPipe::OnPipeException [reason=%x output-only=%d]\n", + reason, outputOnly)); + + nsPipeEvents events; + { + nsAutoMonitor mon(mMonitor); + + // if we've already hit an exception, then ignore this one. + if (NS_FAILED(mStatus)) + return; + + mStatus = reason; + + // an output-only exception applies to the input end if the pipe has + // zero bytes available. + if (outputOnly && !mInput.Available()) + outputOnly = PR_FALSE; + + if (!outputOnly) + if (mInput.OnInputException(reason, events)) + mon.Notify(); + + if (mOutput.OnOutputException(reason, events)) + mon.Notify(); + } +} + +//----------------------------------------------------------------------------- +// nsPipeEvents methods: +//----------------------------------------------------------------------------- + +nsPipeEvents::~nsPipeEvents() +{ + // dispatch any pending events + + if (mInputCallback) { + mInputCallback->OnInputStreamReady(mInputStream); + mInputCallback = 0; + mInputStream = 0; + } + if (mOutputCallback) { + mOutputCallback->OnOutputStreamReady(mOutputStream); + mOutputCallback = 0; + mOutputStream = 0; + } +} + +//----------------------------------------------------------------------------- +// nsPipeInputStream methods: +//----------------------------------------------------------------------------- + +nsresult +nsPipeInputStream::Wait() +{ + NS_ASSERTION(mBlocking, "wait on non-blocking pipe input stream"); + + nsAutoMonitor mon(mPipe->mMonitor); + + while (NS_SUCCEEDED(mPipe->mStatus) && (mAvailable == 0)) { + LOG(("III pipe input: waiting for data\n")); + + mBlocked = PR_TRUE; + mon.Wait(); + mBlocked = PR_FALSE; + + LOG(("III pipe input: woke up [pipe-status=%x available=%u]\n", + mPipe->mStatus, mAvailable)); + } + + return mPipe->mStatus == NS_BASE_STREAM_CLOSED ? NS_OK : mPipe->mStatus; +} + +PRBool +nsPipeInputStream::OnInputReadable(PRUint32 bytesWritten, nsPipeEvents &events) +{ + PRBool result = PR_FALSE; + + mAvailable += bytesWritten; + + if (mCallback && !(mCallbackFlags & WAIT_CLOSURE_ONLY)) { + events.NotifyInputReady(this, mCallback); + mCallback = 0; + mCallbackFlags = 0; + } + else if (mBlocked) + result = PR_TRUE; + + return result; +} + +PRBool +nsPipeInputStream::OnInputException(nsresult reason, nsPipeEvents &events) +{ + LOG(("nsPipeInputStream::OnInputException [this=%x reason=%x]\n", + this, reason)); + + PRBool result = PR_FALSE; + + NS_ASSERTION(NS_FAILED(reason), "huh? successful exception"); + + // force count of available bytes to zero. + mAvailable = 0; + + if (mCallback) { + events.NotifyInputReady(this, mCallback); + mCallback = 0; + mCallbackFlags = 0; + } + else if (mBlocked) + result = PR_TRUE; + + return result; +} + +NS_IMETHODIMP_(nsrefcnt) +nsPipeInputStream::AddRef(void) +{ + ++mReaderRefCnt; + return mPipe->AddRef(); +} + +NS_IMETHODIMP_(nsrefcnt) +nsPipeInputStream::Release(void) +{ + if (--mReaderRefCnt == 0) + Close(); + return mPipe->Release(); +} + +NS_IMPL_QUERY_INTERFACE4(nsPipeInputStream, + nsIInputStream, + nsIAsyncInputStream, + nsISeekableStream, + nsISearchableInputStream) + +NS_IMETHODIMP +nsPipeInputStream::CloseWithStatus(nsresult reason) +{ + LOG(("III CloseWithStatus [this=%x reason=%x]\n", this, reason)); + + if (NS_SUCCEEDED(reason)) + reason = NS_BASE_STREAM_CLOSED; + + mPipe->OnPipeException(reason); + return NS_OK; +} + +NS_IMETHODIMP +nsPipeInputStream::Close() +{ + return CloseWithStatus(NS_BASE_STREAM_CLOSED); +} + +NS_IMETHODIMP +nsPipeInputStream::Available(PRUint32 *result) +{ + nsAutoMonitor mon(mPipe->mMonitor); + + // return error if pipe closed + if (!mAvailable && NS_FAILED(mPipe->mStatus)) + return mPipe->mStatus; + + *result = mAvailable; + return NS_OK; +} + +NS_IMETHODIMP +nsPipeInputStream::ReadSegments(nsWriteSegmentFun writer, + void *closure, + PRUint32 count, + PRUint32 *readCount) +{ + LOG(("III ReadSegments [this=%x count=%u]\n", this, count)); + + nsresult rv = NS_OK; + + const char *segment; + PRUint32 segmentLen; + + *readCount = 0; + while (count) { + rv = mPipe->GetReadSegment(segment, segmentLen); + if (NS_FAILED(rv)) { + // ignore this error if we've already read something. + if (*readCount > 0) { + rv = NS_OK; + break; + } + if (rv == NS_BASE_STREAM_WOULD_BLOCK) { + // pipe is empty + if (!mBlocking) + break; + // wait for some data to be written to the pipe + rv = Wait(); + if (NS_SUCCEEDED(rv)) + continue; + } + // ignore this error, just return. + if (rv == NS_BASE_STREAM_CLOSED) { + rv = NS_OK; + break; + } + mPipe->OnPipeException(rv); + break; + } + + // read no more than count + if (segmentLen > count) + segmentLen = count; + + PRUint32 writeCount, originalLen = segmentLen; + while (segmentLen) { + writeCount = 0; + + rv = writer(this, closure, segment, *readCount, segmentLen, &writeCount); + + if (NS_FAILED(rv) || writeCount == 0) { + count = 0; + // any errors returned from the writer end here: do not + // propogate to the caller of ReadSegments. + rv = NS_OK; + break; + } + + NS_ASSERTION(writeCount <= segmentLen, "wrote more than expected"); + segment += writeCount; + segmentLen -= writeCount; + count -= writeCount; + *readCount += writeCount; + mLogicalOffset += writeCount; + } + + if (segmentLen < originalLen) + mPipe->AdvanceReadCursor(originalLen - segmentLen); + } + + return rv; +} + +static NS_METHOD +nsWriteToRawBuffer(nsIInputStream* inStr, + void *closure, + const char *fromRawSegment, + PRUint32 offset, + PRUint32 count, + PRUint32 *writeCount) +{ + char *toBuf = (char*)closure; + memcpy(&toBuf[offset], fromRawSegment, count); + *writeCount = count; + return NS_OK; +} + +NS_IMETHODIMP +nsPipeInputStream::Read(char* toBuf, PRUint32 bufLen, PRUint32 *readCount) +{ + return ReadSegments(nsWriteToRawBuffer, toBuf, bufLen, readCount); +} + +NS_IMETHODIMP +nsPipeInputStream::IsNonBlocking(PRBool *aNonBlocking) +{ + *aNonBlocking = !mBlocking; + return NS_OK; +} + +NS_IMETHODIMP +nsPipeInputStream::AsyncWait(nsIInputStreamCallback *callback, + PRUint32 flags, + PRUint32 requestedCount, + nsIEventTarget *target) +{ + LOG(("III AsyncWait [this=%x]\n", this)); + + nsPipeEvents pipeEvents; + { + nsAutoMonitor mon(mPipe->mMonitor); + + // replace a pending callback + mCallback = 0; + mCallbackFlags = 0; + + nsCOMPtr proxy; + if (target) { + nsresult rv = NS_NewInputStreamReadyEvent(getter_AddRefs(proxy), + callback, target); + if (NS_FAILED(rv)) return rv; + callback = proxy; + } + + if (NS_FAILED(mPipe->mStatus) || + (mAvailable && !(flags & WAIT_CLOSURE_ONLY))) { + // stream is already closed or readable; post event. + pipeEvents.NotifyInputReady(this, callback); + } + else { + // queue up callback object to be notified when data becomes available + mCallback = callback; + mCallbackFlags = flags; + } + } + return NS_OK; +} + +NS_IMETHODIMP +nsPipeInputStream::Seek(PRInt32 whence, PRInt64 offset) +{ + NS_NOTREACHED("nsPipeInputStream::Seek"); + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsPipeInputStream::Tell(PRInt64 *offset) +{ + *offset = mLogicalOffset; + return NS_OK; +} + +NS_IMETHODIMP +nsPipeInputStream::SetEOF() +{ + NS_NOTREACHED("nsPipeInputStream::SetEOF"); + return NS_ERROR_NOT_IMPLEMENTED; +} + +#define COMPARE(s1, s2, i) \ + (ignoreCase \ + ? nsCRT::strncasecmp((const char *)s1, (const char *)s2, (PRUint32)i) \ + : nsCRT::strncmp((const char *)s1, (const char *)s2, (PRUint32)i)) + +NS_IMETHODIMP +nsPipeInputStream::Search(const char *forString, + PRBool ignoreCase, + PRBool *found, + PRUint32 *offsetSearchedTo) +{ + LOG(("III Search [for=%s ic=%u]\n", forString, ignoreCase)); + + nsAutoMonitor mon(mPipe->mMonitor); + + char *cursor1, *limit1; + PRUint32 index = 0, offset = 0; + PRUint32 strLen = strlen(forString); + + mPipe->PeekSegment(0, cursor1, limit1); + if (cursor1 == limit1) { + *found = PR_FALSE; + *offsetSearchedTo = 0; + LOG((" result [found=%u offset=%u]\n", *found, *offsetSearchedTo)); + return NS_OK; + } + + while (PR_TRUE) { + PRUint32 i, len1 = limit1 - cursor1; + + // check if the string is in the buffer segment + for (i = 0; i < len1 - strLen + 1; i++) { + if (COMPARE(&cursor1[i], forString, strLen) == 0) { + *found = PR_TRUE; + *offsetSearchedTo = offset + i; + LOG((" result [found=%u offset=%u]\n", *found, *offsetSearchedTo)); + return NS_OK; + } + } + + // get the next segment + char *cursor2, *limit2; + PRUint32 len2; + + index++; + offset += len1; + + mPipe->PeekSegment(index, cursor2, limit2); + if (cursor2 == limit2) { + *found = PR_FALSE; + *offsetSearchedTo = offset - strLen + 1; + LOG((" result [found=%u offset=%u]\n", *found, *offsetSearchedTo)); + return NS_OK; + } + len2 = limit2 - cursor2; + + // check if the string is straddling the next buffer segment + PRUint32 lim = PR_MIN(strLen, len2 + 1); + for (i = 0; i < lim; ++i) { + PRUint32 strPart1Len = strLen - i - 1; + PRUint32 strPart2Len = strLen - strPart1Len; + const char* strPart2 = &forString[strLen - strPart2Len]; + PRUint32 bufSeg1Offset = len1 - strPart1Len; + if (COMPARE(&cursor1[bufSeg1Offset], forString, strPart1Len) == 0 && + COMPARE(cursor2, strPart2, strPart2Len) == 0) { + *found = PR_TRUE; + *offsetSearchedTo = offset - strPart1Len; + LOG((" result [found=%u offset=%u]\n", *found, *offsetSearchedTo)); + return NS_OK; + } + } + + // finally continue with the next buffer + cursor1 = cursor2; + limit1 = limit2; + } + + NS_NOTREACHED("can't get here"); + return NS_ERROR_UNEXPECTED; // keep compiler happy +} + +//----------------------------------------------------------------------------- +// nsPipeOutputStream methods: +//----------------------------------------------------------------------------- + +nsresult +nsPipeOutputStream::Wait() +{ + NS_ASSERTION(mBlocking, "wait on non-blocking pipe output stream"); + + nsAutoMonitor mon(mPipe->mMonitor); + + if (NS_SUCCEEDED(mPipe->mStatus) && !mWritable) { + LOG(("OOO pipe output: waiting for space\n")); + mBlocked = PR_TRUE; + mon.Wait(); + mBlocked = PR_FALSE; + LOG(("OOO pipe output: woke up [pipe-status=%x writable=%u]\n", + mPipe->mStatus, mWritable == PR_TRUE)); + } + + return mPipe->mStatus == NS_BASE_STREAM_CLOSED ? NS_OK : mPipe->mStatus; +} + +PRBool +nsPipeOutputStream::OnOutputWritable(nsPipeEvents &events) +{ + PRBool result = PR_FALSE; + + mWritable = PR_TRUE; + + if (mCallback && !(mCallbackFlags & WAIT_CLOSURE_ONLY)) { + events.NotifyOutputReady(this, mCallback); + mCallback = 0; + mCallbackFlags = 0; + } + else if (mBlocked) + result = PR_TRUE; + + return result; +} + +PRBool +nsPipeOutputStream::OnOutputException(nsresult reason, nsPipeEvents &events) +{ + LOG(("nsPipeOutputStream::OnOutputException [this=%x reason=%x]\n", + this, reason)); + + nsresult result = PR_FALSE; + + NS_ASSERTION(NS_FAILED(reason), "huh? successful exception"); + mWritable = PR_FALSE; + + if (mCallback) { + events.NotifyOutputReady(this, mCallback); + mCallback = 0; + mCallbackFlags = 0; + } + else if (mBlocked) + result = PR_TRUE; + + return result; +} + + +NS_IMETHODIMP_(nsrefcnt) +nsPipeOutputStream::AddRef() +{ + mWriterRefCnt++; + return mPipe->AddRef(); +} + +NS_IMETHODIMP_(nsrefcnt) +nsPipeOutputStream::Release() +{ + if (--mWriterRefCnt == 0) + Close(); + return mPipe->Release(); +} + +NS_IMPL_QUERY_INTERFACE2(nsPipeOutputStream, + nsIOutputStream, + nsIAsyncOutputStream) + +NS_IMETHODIMP +nsPipeOutputStream::CloseWithStatus(nsresult reason) +{ + LOG(("OOO CloseWithStatus [this=%x reason=%x]\n", this, reason)); + + if (NS_SUCCEEDED(reason)) + reason = NS_BASE_STREAM_CLOSED; + + // input stream may remain open + mPipe->OnPipeException(reason, PR_TRUE); + return NS_OK; +} + +NS_IMETHODIMP +nsPipeOutputStream::Close() +{ + return CloseWithStatus(NS_BASE_STREAM_CLOSED); +} + +NS_IMETHODIMP +nsPipeOutputStream::WriteSegments(nsReadSegmentFun reader, + void* closure, + PRUint32 count, + PRUint32 *writeCount) +{ + LOG(("OOO WriteSegments [this=%x count=%u]\n", this, count)); + + nsresult rv = NS_OK; + + char *segment; + PRUint32 segmentLen; + + *writeCount = 0; + while (count) { + rv = mPipe->GetWriteSegment(segment, segmentLen); + if (NS_FAILED(rv)) { + if (rv == NS_BASE_STREAM_WOULD_BLOCK) { + // pipe is full + if (!mBlocking) { + // ignore this error if we've already written something + if (*writeCount > 0) + rv = NS_OK; + break; + } + // wait for the pipe to have an empty segment. + rv = Wait(); + if (NS_SUCCEEDED(rv)) + continue; + } + mPipe->OnPipeException(rv); + break; + } + + // write no more than count + if (segmentLen > count) + segmentLen = count; + + PRUint32 readCount, originalLen = segmentLen; + while (segmentLen) { + readCount = 0; + + rv = reader(this, closure, segment, *writeCount, segmentLen, &readCount); + + if (NS_FAILED(rv) || readCount == 0) { + count = 0; + // any errors returned from the reader end here: do not + // propogate to the caller of WriteSegments. + rv = NS_OK; + break; + } + + NS_ASSERTION(readCount <= segmentLen, "read more than expected"); + segment += readCount; + segmentLen -= readCount; + count -= readCount; + *writeCount += readCount; + mLogicalOffset += readCount; + } + + if (segmentLen < originalLen) + mPipe->AdvanceWriteCursor(originalLen - segmentLen); + } + + return rv; +} + +static NS_METHOD +nsReadFromRawBuffer(nsIOutputStream* outStr, + void* closure, + char* toRawSegment, + PRUint32 offset, + PRUint32 count, + PRUint32 *readCount) +{ + const char* fromBuf = (const char*)closure; + memcpy(toRawSegment, &fromBuf[offset], count); + *readCount = count; + return NS_OK; +} + +NS_IMETHODIMP +nsPipeOutputStream::Write(const char* fromBuf, + PRUint32 bufLen, + PRUint32 *writeCount) +{ + return WriteSegments(nsReadFromRawBuffer, (void*)fromBuf, bufLen, writeCount); +} + +NS_IMETHODIMP +nsPipeOutputStream::Flush(void) +{ + // nothing to do + return NS_OK; +} + +static NS_METHOD +nsReadFromInputStream(nsIOutputStream* outStr, + void* closure, + char* toRawSegment, + PRUint32 offset, + PRUint32 count, + PRUint32 *readCount) +{ + nsIInputStream* fromStream = (nsIInputStream*)closure; + return fromStream->Read(toRawSegment, count, readCount); +} + +NS_IMETHODIMP +nsPipeOutputStream::WriteFrom(nsIInputStream* fromStream, + PRUint32 count, + PRUint32 *writeCount) +{ + return WriteSegments(nsReadFromInputStream, fromStream, count, writeCount); +} + +NS_IMETHODIMP +nsPipeOutputStream::IsNonBlocking(PRBool *aNonBlocking) +{ + *aNonBlocking = !mBlocking; + return NS_OK; +} + +NS_IMETHODIMP +nsPipeOutputStream::AsyncWait(nsIOutputStreamCallback *callback, + PRUint32 flags, + PRUint32 requestedCount, + nsIEventTarget *target) +{ + LOG(("OOO AsyncWait [this=%x]\n", this)); + + nsPipeEvents pipeEvents; + { + nsAutoMonitor mon(mPipe->mMonitor); + + // replace a pending callback + mCallback = 0; + mCallbackFlags = 0; + + nsCOMPtr proxy; + if (target) { + nsresult rv = NS_NewOutputStreamReadyEvent(getter_AddRefs(proxy), + callback, target); + if (NS_FAILED(rv)) return rv; + callback = proxy; + } + + if (NS_FAILED(mPipe->mStatus) || + (mWritable && !(flags & WAIT_CLOSURE_ONLY))) { + // stream is already closed or writable; post event. + pipeEvents.NotifyOutputReady(this, callback); + } + else { + // queue up callback object to be notified when data becomes available + mCallback = callback; + mCallbackFlags = flags; + } + } + return NS_OK; +} + +NS_IMETHODIMP +nsPipeOutputStream::Seek(PRInt32 whence, PRInt64 offset) +{ + NS_NOTREACHED("nsPipeOutputStream::Seek"); + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsPipeOutputStream::Tell(PRInt64 *offset) +{ + *offset = mLogicalOffset; + return NS_OK; +} + +NS_IMETHODIMP +nsPipeOutputStream::SetEOF() +{ + NS_NOTREACHED("nsPipeOutputStream::SetEOF"); + return NS_ERROR_NOT_IMPLEMENTED; +} + +//////////////////////////////////////////////////////////////////////////////// + +NS_COM nsresult +NS_NewPipe2(nsIAsyncInputStream **pipeIn, + nsIAsyncOutputStream **pipeOut, + PRBool nonBlockingInput, + PRBool nonBlockingOutput, + PRUint32 segmentSize, + PRUint32 segmentCount, + nsIMemory *segmentAlloc) +{ + nsresult rv; + +#if defined(PR_LOGGING) + if (!gPipeLog) + gPipeLog = PR_NewLogModule("nsPipe"); +#endif + + nsPipe *pipe = new nsPipe(); + if (!pipe) + return NS_ERROR_OUT_OF_MEMORY; + + rv = pipe->Init(nonBlockingInput, + nonBlockingOutput, + segmentSize, + segmentCount, + segmentAlloc); + if (NS_FAILED(rv)) { + NS_ADDREF(pipe); + NS_RELEASE(pipe); + return rv; + } + + pipe->GetInputStream(pipeIn); + pipe->GetOutputStream(pipeOut); + return NS_OK; +} + +//////////////////////////////////////////////////////////////////////////////// diff --git a/src/libs/xpcom18a4/xpcom/io/nsScriptableInputStream.cpp b/src/libs/xpcom18a4/xpcom/io/nsScriptableInputStream.cpp new file mode 100644 index 00000000..5458b1b7 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsScriptableInputStream.cpp @@ -0,0 +1,102 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsScriptableInputStream.h" +#include "nsMemory.h" + +NS_IMPL_ISUPPORTS1(nsScriptableInputStream, nsIScriptableInputStream) + +// nsIBaseStream methods +NS_IMETHODIMP +nsScriptableInputStream::Close(void) { + if (!mInputStream) return NS_ERROR_NOT_INITIALIZED; + return mInputStream->Close(); +} + +// nsIScriptableInputStream methods +NS_IMETHODIMP +nsScriptableInputStream::Init(nsIInputStream *aInputStream) { + if (!aInputStream) return NS_ERROR_NULL_POINTER; + mInputStream = aInputStream; + return NS_OK; +} + +NS_IMETHODIMP +nsScriptableInputStream::Available(PRUint32 *_retval) { + if (!mInputStream) return NS_ERROR_NOT_INITIALIZED; + return mInputStream->Available(_retval); +} + +NS_IMETHODIMP +nsScriptableInputStream::Read(PRUint32 aCount, char **_retval) { + nsresult rv = NS_OK; + PRUint32 count = 0; + char *buffer = nsnull; + + if (!mInputStream) return NS_ERROR_NOT_INITIALIZED; + + rv = mInputStream->Available(&count); + if (NS_FAILED(rv)) return rv; + + count = PR_MIN(count, aCount); + buffer = (char*)nsMemory::Alloc(count+1); // make room for '\0' + if (!buffer) return NS_ERROR_OUT_OF_MEMORY; + + PRUint32 amtRead = 0; + rv = mInputStream->Read(buffer, count, &amtRead); + if (NS_FAILED(rv)) { + nsMemory::Free(buffer); + return rv; + } + + buffer[amtRead] = '\0'; + *_retval = buffer; + return NS_OK; +} + +NS_METHOD +nsScriptableInputStream::Create(nsISupports *aOuter, REFNSIID aIID, void **aResult) { + if (aOuter) return NS_ERROR_NO_AGGREGATION; + + nsScriptableInputStream *sis = new nsScriptableInputStream(); + if (!sis) return NS_ERROR_OUT_OF_MEMORY; + + NS_ADDREF(sis); + nsresult rv = sis->QueryInterface(aIID, aResult); + NS_RELEASE(sis); + return rv; +} diff --git a/src/libs/xpcom18a4/xpcom/io/nsScriptableInputStream.h b/src/libs/xpcom18a4/xpcom/io/nsScriptableInputStream.h new file mode 100644 index 00000000..b9976176 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsScriptableInputStream.h @@ -0,0 +1,71 @@ +/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +#ifndef ___nsscriptableinputstream___h_ +#define ___nsscriptableinputstream___h_ + +#include "nsIScriptableInputStream.h" +#include "nsIInputStream.h" +#include "nsCOMPtr.h" + +#define NS_SCRIPTABLEINPUTSTREAM_CID \ +{ 0x7225c040, 0xa9bf, 0x11d3, { 0xa1, 0x97, 0x0, 0x50, 0x4, 0x1c, 0xaf, 0x44 } } + +#define NS_SCRIPTABLEINPUTSTREAM_CONTRACTID "@mozilla.org/scriptableinputstream;1" +#define NS_SCRIPTABLEINPUTSTREAM_CLASSNAME "Scriptable Input Stream" + +class nsScriptableInputStream : public nsIScriptableInputStream { +public: + // nsISupports methods + NS_DECL_ISUPPORTS + + // nsIScriptableInputStream methods + NS_DECL_NSISCRIPTABLEINPUTSTREAM + + // nsScriptableInputStream methods + nsScriptableInputStream() {}; + + static NS_METHOD + Create(nsISupports *aOuter, REFNSIID aIID, void **aResult); + +private: + ~nsScriptableInputStream() {}; + + nsCOMPtr mInputStream; +}; + +#endif // ___nsscriptableinputstream___h_ diff --git a/src/libs/xpcom18a4/xpcom/io/nsSegmentedBuffer.cpp b/src/libs/xpcom18a4/xpcom/io/nsSegmentedBuffer.cpp new file mode 100644 index 00000000..f6a1c15d --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsSegmentedBuffer.cpp @@ -0,0 +1,207 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsSegmentedBuffer.h" +#include "nsCRT.h" + +nsresult +nsSegmentedBuffer::Init(PRUint32 segmentSize, PRUint32 maxSize, + nsIMemory* allocator) +{ + if (mSegmentArrayCount != 0) + return NS_ERROR_FAILURE; // initialized more than once + mSegmentSize = segmentSize; + mMaxSize = maxSize; + mSegAllocator = allocator; + if (mSegAllocator == nsnull) { + mSegAllocator = nsMemory::GetGlobalMemoryService(); + } + else { + NS_ADDREF(mSegAllocator); + } +#if 0 // testing... + mSegmentArrayCount = 2; +#else + mSegmentArrayCount = NS_SEGMENTARRAY_INITIAL_COUNT; +#endif + return NS_OK; +} + +char* +nsSegmentedBuffer::AppendNewSegment() +{ + if (GetSize() >= mMaxSize) + return nsnull; + + if (mSegmentArray == nsnull) { + PRUint32 bytes = mSegmentArrayCount * sizeof(char*); + mSegmentArray = (char**)nsMemory::Alloc(bytes); + if (mSegmentArray == nsnull) + return nsnull; + memset(mSegmentArray, 0, bytes); + } + + if (IsFull()) { + PRUint32 newArraySize = mSegmentArrayCount * 2; + PRUint32 bytes = newArraySize * sizeof(char*); + char** newSegArray = (char**)nsMemory::Realloc(mSegmentArray, bytes); + if (newSegArray == nsnull) + return nsnull; + mSegmentArray = newSegArray; + // copy wrapped content to new extension + if (mFirstSegmentIndex > mLastSegmentIndex) { + // deal with wrap around case + memcpy(&mSegmentArray[mSegmentArrayCount], + mSegmentArray, + mLastSegmentIndex * sizeof(char*)); + memset(mSegmentArray, 0, mLastSegmentIndex * sizeof(char*)); + mLastSegmentIndex += mSegmentArrayCount; + memset(&mSegmentArray[mLastSegmentIndex], 0, + (newArraySize - mLastSegmentIndex) * sizeof(char*)); + } + else { + memset(&mSegmentArray[mLastSegmentIndex], 0, + (newArraySize - mLastSegmentIndex) * sizeof(char*)); + } + mSegmentArrayCount = newArraySize; + } + + char* seg = (char*)mSegAllocator->Alloc(mSegmentSize); + if (seg == nsnull) { + return nsnull; + } + mSegmentArray[mLastSegmentIndex] = seg; + mLastSegmentIndex = ModSegArraySize(mLastSegmentIndex + 1); + return seg; +} + +PRBool +nsSegmentedBuffer::DeleteFirstSegment() +{ + NS_ASSERTION(mSegmentArray[mFirstSegmentIndex] != nsnull, "deleting bad segment"); + (void)mSegAllocator->Free(mSegmentArray[mFirstSegmentIndex]); + mSegmentArray[mFirstSegmentIndex] = nsnull; + PRInt32 last = ModSegArraySize(mLastSegmentIndex - 1); + if (mFirstSegmentIndex == last) { + mLastSegmentIndex = last; + return PR_TRUE; + } + else { + mFirstSegmentIndex = ModSegArraySize(mFirstSegmentIndex + 1); + return PR_FALSE; + } +} + +PRBool +nsSegmentedBuffer::DeleteLastSegment() +{ + PRInt32 last = ModSegArraySize(mLastSegmentIndex - 1); + NS_ASSERTION(mSegmentArray[last] != nsnull, "deleting bad segment"); + (void)mSegAllocator->Free(mSegmentArray[last]); + mSegmentArray[last] = nsnull; + mLastSegmentIndex = last; + return (PRBool)(mLastSegmentIndex == mFirstSegmentIndex); +} + +PRBool +nsSegmentedBuffer::ReallocLastSegment(size_t newSize) +{ + PRInt32 last = ModSegArraySize(mLastSegmentIndex - 1); + NS_ASSERTION(mSegmentArray[last] != nsnull, "realloc'ing bad segment"); + char *newSegment = + (char*)mSegAllocator->Realloc(mSegmentArray[last], newSize); + if (newSegment) { + mSegmentArray[last] = newSegment; + return PR_TRUE; + } else { + return PR_FALSE; + } +} + +void +nsSegmentedBuffer::Empty() +{ + if (mSegmentArray) { + for (PRUint32 i = 0; i < mSegmentArrayCount; i++) { + if (mSegmentArray[i]) + mSegAllocator->Free(mSegmentArray[i]); + } + nsMemory::Free(mSegmentArray); + mSegmentArray = nsnull; + } + mSegmentArrayCount = NS_SEGMENTARRAY_INITIAL_COUNT; + mFirstSegmentIndex = mLastSegmentIndex = 0; +} + +#ifdef DEBUG +NS_COM void +TestSegmentedBuffer() +{ + nsSegmentedBuffer* buf = new nsSegmentedBuffer(); + NS_ASSERTION(buf, "out of memory"); + buf->Init(4, 16); + char* seg; + PRBool empty; + seg = buf->AppendNewSegment(); + NS_ASSERTION(seg, "AppendNewSegment failed"); + seg = buf->AppendNewSegment(); + NS_ASSERTION(seg, "AppendNewSegment failed"); + seg = buf->AppendNewSegment(); + NS_ASSERTION(seg, "AppendNewSegment failed"); + empty = buf->DeleteFirstSegment(); + NS_ASSERTION(!empty, "DeleteFirstSegment failed"); + empty = buf->DeleteFirstSegment(); + NS_ASSERTION(!empty, "DeleteFirstSegment failed"); + seg = buf->AppendNewSegment(); + NS_ASSERTION(seg, "AppendNewSegment failed"); + seg = buf->AppendNewSegment(); + NS_ASSERTION(seg, "AppendNewSegment failed"); + seg = buf->AppendNewSegment(); + NS_ASSERTION(seg, "AppendNewSegment failed"); + empty = buf->DeleteFirstSegment(); + NS_ASSERTION(!empty, "DeleteFirstSegment failed"); + empty = buf->DeleteFirstSegment(); + NS_ASSERTION(!empty, "DeleteFirstSegment failed"); + empty = buf->DeleteFirstSegment(); + NS_ASSERTION(!empty, "DeleteFirstSegment failed"); + empty = buf->DeleteFirstSegment(); + NS_ASSERTION(empty, "DeleteFirstSegment failed"); + delete buf; +} +#endif + +//////////////////////////////////////////////////////////////////////////////// diff --git a/src/libs/xpcom18a4/xpcom/io/nsSegmentedBuffer.h b/src/libs/xpcom18a4/xpcom/io/nsSegmentedBuffer.h new file mode 100644 index 00000000..43620632 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsSegmentedBuffer.h @@ -0,0 +1,125 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +#ifndef nsSegmentedBuffer_h__ +#define nsSegmentedBuffer_h__ + +#include "nsMemory.h" +#include "prclist.h" + +class nsSegmentedBuffer +{ +public: + nsSegmentedBuffer() + : mSegmentSize(0), mMaxSize(0), + mSegAllocator(nsnull), mSegmentArray(nsnull), + mSegmentArrayCount(0), + mFirstSegmentIndex(0), mLastSegmentIndex(0) {} + + ~nsSegmentedBuffer() { + Empty(); + NS_IF_RELEASE(mSegAllocator); + } + + + NS_COM nsresult Init(PRUint32 segmentSize, PRUint32 maxSize, + nsIMemory* allocator = nsnull); + + NS_COM char* AppendNewSegment(); // pushes at end + + // returns true if no more segments remain: + PRBool DeleteFirstSegment(); // pops from beginning + + // returns true if no more segments remain: + PRBool DeleteLastSegment(); // pops from beginning + + // Call Realloc() on last segment. This is used to reduce memory + // consumption when data is not an exact multiple of segment size. + PRBool ReallocLastSegment(size_t newSize); + + NS_COM void Empty(); // frees all segments + + inline PRUint32 GetSegmentCount() { + if (mFirstSegmentIndex <= mLastSegmentIndex) + return mLastSegmentIndex - mFirstSegmentIndex; + else + return mSegmentArrayCount + mLastSegmentIndex - mFirstSegmentIndex; + } + + inline PRUint32 GetSegmentSize() { return mSegmentSize; } + inline PRUint32 GetMaxSize() { return mMaxSize; } + inline PRUint32 GetSize() { return GetSegmentCount() * mSegmentSize; } + + inline char* GetSegment(PRUint32 indx) { + NS_ASSERTION(indx < GetSegmentCount(), "index out of bounds"); + PRInt32 i = ModSegArraySize(mFirstSegmentIndex + (PRInt32)indx); + return mSegmentArray[i]; + } + +protected: + inline PRInt32 ModSegArraySize(PRInt32 n) { + PRUint32 result = n & (mSegmentArrayCount - 1); + NS_ASSERTION(result == n % mSegmentArrayCount, + "non-power-of-2 mSegmentArrayCount"); + return result; + } + + inline PRBool IsFull() { + return ModSegArraySize(mLastSegmentIndex + 1) == mFirstSegmentIndex; + } + +protected: + PRUint32 mSegmentSize; + PRUint32 mMaxSize; + nsIMemory* mSegAllocator; + char** mSegmentArray; + PRUint32 mSegmentArrayCount; + PRInt32 mFirstSegmentIndex; + PRInt32 mLastSegmentIndex; +}; + +// NS_SEGMENTARRAY_INITIAL_SIZE: This number needs to start out as a +// power of 2 given how it gets used. We double the segment array +// when we overflow it, and use that fact that it's a power of 2 +// to compute a fast modulus operation in IsFull. +// +// 32 segment array entries can accommodate 128k of data if segments +// are 4k in size. That seems like a reasonable amount that will avoid +// needing to grow the segment array. +#define NS_SEGMENTARRAY_INITIAL_COUNT 32 + +#endif // nsSegmentedBuffer_h__ diff --git a/src/libs/xpcom18a4/xpcom/io/nsStorageStream.cpp b/src/libs/xpcom18a4/xpcom/io/nsStorageStream.cpp new file mode 100644 index 00000000..2a6b0166 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsStorageStream.cpp @@ -0,0 +1,563 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * ***** 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 Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Pierre Phaneuf + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* + * The storage stream provides an internal buffer that can be filled by a + * client using a single output stream. One or more independent input streams + * can be created to read the data out non-destructively. The implementation + * uses a segmented buffer internally to avoid realloc'ing of large buffers, + * with the attendant performance loss and heap fragmentation. + */ + +#include "nsStorageStream.h" +#include "nsSegmentedBuffer.h" +#include "nsCOMPtr.h" +#include "prbit.h" +#include "nsIInputStream.h" +#include "nsISeekableStream.h" +#include "prlog.h" +#include "nsInt64.h" +#if defined(PR_LOGGING) +// +// Log module for StorageStream logging... +// +// To enable logging (see prlog.h for full details): +// +// set NSPR_LOG_MODULES=StorageStreamLog:5 +// set NSPR_LOG_FILE=nspr.log +// +// this enables PR_LOG_DEBUG level information and places all output in +// the file nspr.log +// +PRLogModuleInfo* StorageStreamLog = nsnull; + +#endif /* PR_LOGGING */ + +nsStorageStream::nsStorageStream() + : mSegmentedBuffer(0), mSegmentSize(0), mWriteInProgress(PR_FALSE), + mLastSegmentNum(-1), mWriteCursor(0), mSegmentEnd(0), mLogicalLength(0) +{ +#if defined(PR_LOGGING) + // + // Initialize the global PRLogModule for socket transport logging + // if necessary... + // + if (nsnull == StorageStreamLog) { + StorageStreamLog = PR_NewLogModule("StorageStreamLog"); + } +#endif /* PR_LOGGING */ + + PR_LOG(StorageStreamLog, PR_LOG_DEBUG, + ("Creating nsStorageStream [%x].\n", this)); +} + +nsStorageStream::~nsStorageStream() +{ + if (mSegmentedBuffer) + delete mSegmentedBuffer; +} + +NS_IMPL_THREADSAFE_ISUPPORTS2(nsStorageStream, + nsIStorageStream, + nsIOutputStream) + +NS_IMETHODIMP +nsStorageStream::Init(PRUint32 segmentSize, PRUint32 maxSize, + nsIMemory *segmentAllocator) +{ + mSegmentedBuffer = new nsSegmentedBuffer(); + if (!mSegmentedBuffer) + return NS_ERROR_OUT_OF_MEMORY; + + mSegmentSize = segmentSize; + mSegmentSizeLog2 = PR_FloorLog2(segmentSize); + + // Segment size must be a power of two + if (mSegmentSize != ((PRUint32)1 << mSegmentSizeLog2)) + return NS_ERROR_INVALID_ARG; + + return mSegmentedBuffer->Init(segmentSize, maxSize, segmentAllocator); +} + +NS_IMETHODIMP +nsStorageStream::GetOutputStream(PRInt32 aStartingOffset, + nsIOutputStream * *aOutputStream) +{ + NS_ENSURE_ARG(aOutputStream); + if (mWriteInProgress) + return NS_ERROR_NOT_AVAILABLE; + + nsresult rv = Seek(aStartingOffset); + if (NS_FAILED(rv)) return rv; + + // Enlarge the last segment in the buffer so that it is the same size as + // all the other segments in the buffer. (It may have been realloc'ed + // smaller in the Close() method.) + if (mLastSegmentNum >= 0) + mSegmentedBuffer->ReallocLastSegment(mSegmentSize); + + // Need to re-Seek, since realloc might have changed segment base pointer + rv = Seek(aStartingOffset); + if (NS_FAILED(rv)) return rv; + + NS_ADDREF(this); + *aOutputStream = NS_STATIC_CAST(nsIOutputStream*, this); + mWriteInProgress = PR_TRUE; + return NS_OK; +} + +NS_IMETHODIMP +nsStorageStream::Close() +{ + mWriteInProgress = PR_FALSE; + + PRInt32 segmentOffset = SegOffset(mLogicalLength); + + // Shrink the final segment in the segmented buffer to the minimum size + // needed to contain the data, so as to conserve memory. + if (segmentOffset) + mSegmentedBuffer->ReallocLastSegment(segmentOffset); + + mWriteCursor = 0; + mSegmentEnd = 0; + + PR_LOG(StorageStreamLog, PR_LOG_DEBUG, + ("nsStorageStream [%x] Close mWriteCursor=%x mSegmentEnd=%x\n", + this, mWriteCursor, mSegmentEnd)); + + return NS_OK; +} + +NS_IMETHODIMP +nsStorageStream::Flush() +{ + return NS_OK; +} + +NS_IMETHODIMP +nsStorageStream::Write(const char *aBuffer, PRUint32 aCount, PRUint32 *aNumWritten) +{ + const char* readCursor; + PRUint32 count, availableInSegment, remaining; + nsresult rv = NS_OK; + + NS_ENSURE_ARG_POINTER(aNumWritten); + NS_ENSURE_ARG(aBuffer); + + PR_LOG(StorageStreamLog, PR_LOG_DEBUG, + ("nsStorageStream [%x] Write mWriteCursor=%x mSegmentEnd=%x aCount=%d\n", + this, mWriteCursor, mSegmentEnd, aCount)); + + remaining = aCount; + readCursor = aBuffer; + while (remaining) { + availableInSegment = mSegmentEnd - mWriteCursor; + if (!availableInSegment) { + mWriteCursor = mSegmentedBuffer->AppendNewSegment(); + if (!mWriteCursor) { + mSegmentEnd = 0; + rv = NS_ERROR_OUT_OF_MEMORY; + goto out; + } + mLastSegmentNum++; + mSegmentEnd = mWriteCursor + mSegmentSize; + availableInSegment = mSegmentEnd - mWriteCursor; + PR_LOG(StorageStreamLog, PR_LOG_DEBUG, + ("nsStorageStream [%x] Write (new seg) mWriteCursor=%x mSegmentEnd=%x\n", + this, mWriteCursor, mSegmentEnd)); + } + + count = PR_MIN(availableInSegment, remaining); + memcpy(mWriteCursor, readCursor, count); + remaining -= count; + readCursor += count; + mWriteCursor += count; + PR_LOG(StorageStreamLog, PR_LOG_DEBUG, + ("nsStorageStream [%x] Writing mWriteCursor=%x mSegmentEnd=%x count=%d\n", + this, mWriteCursor, mSegmentEnd, count)); + }; + + out: + *aNumWritten = aCount - remaining; + mLogicalLength += *aNumWritten; + + PR_LOG(StorageStreamLog, PR_LOG_DEBUG, + ("nsStorageStream [%x] Wrote mWriteCursor=%x mSegmentEnd=%x numWritten=%d\n", + this, mWriteCursor, mSegmentEnd, *aNumWritten)); + return rv; +} + +NS_IMETHODIMP +nsStorageStream::WriteFrom(nsIInputStream *inStr, PRUint32 count, PRUint32 *_retval) +{ + NS_NOTREACHED("WriteFrom"); + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsStorageStream::WriteSegments(nsReadSegmentFun reader, void * closure, PRUint32 count, PRUint32 *_retval) +{ + NS_NOTREACHED("WriteSegments"); + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsStorageStream::IsNonBlocking(PRBool *aNonBlocking) +{ + *aNonBlocking = PR_TRUE; + return NS_OK; +} + +NS_IMETHODIMP +nsStorageStream::GetLength(PRUint32 *aLength) +{ + NS_ENSURE_ARG(aLength); + *aLength = mLogicalLength; + return NS_OK; +} + +// Truncate the buffer by deleting the end segments +NS_IMETHODIMP +nsStorageStream::SetLength(PRUint32 aLength) +{ + if (mWriteInProgress) + return NS_ERROR_NOT_AVAILABLE; + + if (aLength > mLogicalLength) + return NS_ERROR_INVALID_ARG; + + PRInt32 newLastSegmentNum = SegNum(aLength); + PRInt32 segmentOffset = SegOffset(aLength); + if (segmentOffset == 0) + newLastSegmentNum--; + + while (newLastSegmentNum < mLastSegmentNum) { + mSegmentedBuffer->DeleteLastSegment(); + mLastSegmentNum--; + } + + mLogicalLength = aLength; + return NS_OK; +} + +NS_IMETHODIMP +nsStorageStream::GetWriteInProgress(PRBool *aWriteInProgress) +{ + NS_ENSURE_ARG(aWriteInProgress); + + *aWriteInProgress = mWriteInProgress; + return NS_OK; +} + +NS_METHOD +nsStorageStream::Seek(PRInt32 aPosition) +{ + // An argument of -1 means "seek to end of stream" + if (aPosition == -1) + aPosition = mLogicalLength; + + // Seeking beyond the buffer end is illegal + if ((PRUint32)aPosition > mLogicalLength) + return NS_ERROR_INVALID_ARG; + + // Seeking backwards in the write stream results in truncation + SetLength(aPosition); + + // Special handling for seek to start-of-buffer + if (aPosition == 0) { + mWriteCursor = 0; + mSegmentEnd = 0; + PR_LOG(StorageStreamLog, PR_LOG_DEBUG, + ("nsStorageStream [%x] Seek mWriteCursor=%x mSegmentEnd=%x\n", + this, mWriteCursor, mSegmentEnd)); + return NS_OK; + } + + // Segment may have changed, so reset pointers + mWriteCursor = mSegmentedBuffer->GetSegment(mLastSegmentNum); + NS_ASSERTION(mWriteCursor, "null mWriteCursor"); + mSegmentEnd = mWriteCursor + mSegmentSize; + PRInt32 segmentOffset = SegOffset(aPosition); + mWriteCursor += segmentOffset; + + PR_LOG(StorageStreamLog, PR_LOG_DEBUG, + ("nsStorageStream [%x] Seek mWriteCursor=%x mSegmentEnd=%x\n", + this, mWriteCursor, mSegmentEnd)); + return NS_OK; +} + +//////////////////////////////////////////////////////////////////////////////// + +// There can be many nsStorageInputStreams for a single nsStorageStream +class nsStorageInputStream : public nsIInputStream + , public nsISeekableStream +{ +public: + nsStorageInputStream(nsStorageStream *aStorageStream, PRUint32 aSegmentSize) + : mStorageStream(aStorageStream), mReadCursor(0), + mSegmentEnd(0), mSegmentNum(0), + mSegmentSize(aSegmentSize), mLogicalCursor(0) + { + NS_ADDREF(mStorageStream); + } + + NS_DECL_ISUPPORTS + NS_DECL_NSIINPUTSTREAM + NS_DECL_NSISEEKABLESTREAM + +private: + ~nsStorageInputStream() + { + NS_IF_RELEASE(mStorageStream); + } + +protected: + NS_METHOD Seek(PRUint32 aPosition); + + friend class nsStorageStream; + +private: + nsStorageStream* mStorageStream; + const char* mReadCursor; // Next memory location to read byte, or NULL + const char* mSegmentEnd; // One byte past end of current buffer segment + PRUint32 mSegmentNum; // Segment number containing read cursor + PRUint32 mSegmentSize; // All segments, except the last, are of this size + PRUint32 mLogicalCursor; // Logical offset into stream + + PRUint32 SegNum(PRUint32 aPosition) {return aPosition >> mStorageStream->mSegmentSizeLog2;} + PRUint32 SegOffset(PRUint32 aPosition) {return aPosition & (mSegmentSize - 1);} +}; + +NS_IMPL_THREADSAFE_ISUPPORTS2(nsStorageInputStream, + nsIInputStream, + nsISeekableStream) + +NS_IMETHODIMP +nsStorageStream::NewInputStream(PRInt32 aStartingOffset, nsIInputStream* *aInputStream) +{ + nsStorageInputStream *inputStream = new nsStorageInputStream(this, mSegmentSize); + if (!inputStream) + return NS_ERROR_OUT_OF_MEMORY; + + NS_ADDREF(inputStream); + + nsresult rv = inputStream->Seek(aStartingOffset); + if (NS_FAILED(rv)) { + NS_RELEASE(inputStream); + return rv; + } + + *aInputStream = inputStream; + return NS_OK; +} + +NS_IMETHODIMP +nsStorageInputStream::Close() +{ + return NS_OK; +} + +NS_IMETHODIMP +nsStorageInputStream::Available(PRUint32 *aAvailable) +{ + *aAvailable = mStorageStream->mLogicalLength - mLogicalCursor; + return NS_OK; +} + +NS_IMETHODIMP +nsStorageInputStream::Read(char* aBuffer, PRUint32 aCount, PRUint32 *aNumRead) +{ + char* writeCursor; + PRUint32 count, availableInSegment, remainingCapacity; + + remainingCapacity = aCount; + writeCursor = aBuffer; + while (remainingCapacity) { + availableInSegment = mSegmentEnd - mReadCursor; + if (!availableInSegment) { + PRUint32 available = mStorageStream->mLogicalLength - mLogicalCursor; + if (!available) + goto out; + + mReadCursor = mStorageStream->mSegmentedBuffer->GetSegment(++mSegmentNum); + mSegmentEnd = mReadCursor + PR_MIN(mSegmentSize, available); + } + + count = PR_MIN(availableInSegment, remainingCapacity); + memcpy(writeCursor, mReadCursor, count); + remainingCapacity -= count; + mReadCursor += count; + writeCursor += count; + mLogicalCursor += count; + }; + + out: + *aNumRead = aCount - remainingCapacity; + + PRBool isWriteInProgress = PR_FALSE; + if (NS_FAILED(mStorageStream->GetWriteInProgress(&isWriteInProgress))) + isWriteInProgress = PR_FALSE; + + if (*aNumRead == 0 && isWriteInProgress) + return NS_BASE_STREAM_WOULD_BLOCK; + else + return NS_OK; +} + +NS_IMETHODIMP +nsStorageInputStream::ReadSegments(nsWriteSegmentFun writer, void * closure, PRUint32 aCount, PRUint32 *aNumRead) +{ + PRUint32 count, availableInSegment, remainingCapacity, bytesConsumed; + nsresult rv; + + remainingCapacity = aCount; + while (remainingCapacity) { + availableInSegment = mSegmentEnd - mReadCursor; + if (!availableInSegment) { + PRUint32 available = mStorageStream->mLogicalLength - mLogicalCursor; + if (!available) + goto out; + + mReadCursor = mStorageStream->mSegmentedBuffer->GetSegment(++mSegmentNum); + mSegmentEnd = mReadCursor + PR_MIN(mSegmentSize, available); + availableInSegment = mSegmentEnd - mReadCursor; + } + + count = PR_MIN(availableInSegment, remainingCapacity); + rv = writer(this, closure, mReadCursor, mLogicalCursor, count, &bytesConsumed); + if (NS_FAILED(rv) || (bytesConsumed == 0)) + break; + remainingCapacity -= bytesConsumed; + mReadCursor += bytesConsumed; + mLogicalCursor += bytesConsumed; + }; + + out: + *aNumRead = aCount - remainingCapacity; + + PRBool isWriteInProgress = PR_FALSE; + if (NS_FAILED(mStorageStream->GetWriteInProgress(&isWriteInProgress))) + isWriteInProgress = PR_FALSE; + + if (*aNumRead == 0 && isWriteInProgress) + return NS_BASE_STREAM_WOULD_BLOCK; + else + return NS_OK; +} + +NS_IMETHODIMP +nsStorageInputStream::IsNonBlocking(PRBool *aNonBlocking) +{ + *aNonBlocking = PR_TRUE; + return NS_OK; +} + +NS_IMETHODIMP +nsStorageInputStream::Seek(PRInt32 aWhence, PRInt64 aOffset) +{ + nsInt64 pos = aOffset; + + switch (aWhence) { + case NS_SEEK_SET: + break; + case NS_SEEK_CUR: + pos += mLogicalCursor; + break; + case NS_SEEK_END: + pos += mStorageStream->mLogicalLength; + break; + default: + NS_NOTREACHED("unexpected whence value"); + return NS_ERROR_UNEXPECTED; + } + nsInt64 logicalCursor(mLogicalCursor); + if (pos == logicalCursor) + return NS_OK; + + return Seek(pos); +} + +NS_IMETHODIMP +nsStorageInputStream::Tell(PRInt64 *aResult) +{ + LL_UI2L(*aResult, mLogicalCursor); + return NS_OK; +} + +NS_IMETHODIMP +nsStorageInputStream::SetEOF() +{ + NS_NOTREACHED("nsStorageInputStream::SetEOF"); + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_METHOD +nsStorageInputStream::Seek(PRUint32 aPosition) +{ + PRUint32 length = mStorageStream->mLogicalLength; + if (aPosition >= length) + return NS_ERROR_INVALID_ARG; + + mSegmentNum = SegNum(aPosition); + PRUint32 segmentOffset = SegOffset(aPosition); + mReadCursor = mStorageStream->mSegmentedBuffer->GetSegment(mSegmentNum) + + segmentOffset; + PRUint32 available = length - aPosition; + mSegmentEnd = mReadCursor + PR_MIN(mSegmentSize - segmentOffset, available); + mLogicalCursor = aPosition; + return NS_OK; +} + +NS_COM nsresult +NS_NewStorageStream(PRUint32 segmentSize, PRUint32 maxSize, nsIStorageStream **result) +{ + NS_ENSURE_ARG(result); + + nsStorageStream* storageStream = new nsStorageStream(); + if (!storageStream) return NS_ERROR_OUT_OF_MEMORY; + + NS_ADDREF(storageStream); + nsresult rv = storageStream->Init(segmentSize, maxSize, nsnull); + if (NS_FAILED(rv)) { + NS_RELEASE(storageStream); + return rv; + } + *result = storageStream; + return NS_OK; +} diff --git a/src/libs/xpcom18a4/xpcom/io/nsStorageStream.h b/src/libs/xpcom18a4/xpcom/io/nsStorageStream.h new file mode 100644 index 00000000..0729c01c --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsStorageStream.h @@ -0,0 +1,98 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * ***** 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 Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* + * The storage stream provides an internal buffer that can be filled by a + * client using a single output stream. One or more independent input streams + * can be created to read the data out non-destructively. The implementation + * uses a segmented buffer internally to avoid realloc'ing of large buffers, + * with the attendant performance loss and heap fragmentation. + */ + +#ifndef _nsStorageStream_h_ +#define _nsStorageStream_h_ + +#include "nsIStorageStream.h" +#include "nsIOutputStream.h" +#include "nsMemory.h" + +#define NS_STORAGESTREAM_CID \ +{ /* 669a9795-6ff7-4ed4-9150-c34ce2971b63 */ \ + 0x669a9795, \ + 0x6ff7, \ + 0x4ed4, \ + {0x91, 0x50, 0xc3, 0x4c, 0xe2, 0x97, 0x1b, 0x63} \ +} + +#define NS_STORAGESTREAM_CONTRACTID "@mozilla.org/storagestream;1" +#define NS_STORAGESTREAM_CLASSNAME "Storage Stream" + +class nsSegmentedBuffer; + +class nsStorageStream : public nsIStorageStream, + public nsIOutputStream +{ +public: + nsStorageStream(); + + NS_DECL_ISUPPORTS + NS_DECL_NSISTORAGESTREAM + NS_DECL_NSIOUTPUTSTREAM + + friend class nsStorageInputStream; + +private: + ~nsStorageStream(); + + nsSegmentedBuffer* mSegmentedBuffer; + PRUint32 mSegmentSize; // All segments, except possibly the last, are of this size + // Must be power-of-2 + PRUint32 mSegmentSizeLog2; // log2(mSegmentSize) + PRBool mWriteInProgress; // true, if an un-Close'ed output stream exists + PRInt32 mLastSegmentNum; // Last segment # in use, -1 initially + char* mWriteCursor; // Pointer to next byte to be written + char* mSegmentEnd; // Pointer to one byte after end of segment + // containing the write cursor + PRUint32 mLogicalLength; // Number of bytes written to stream + + NS_METHOD Seek(PRInt32 aPosition); + PRUint32 SegNum(PRUint32 aPosition) {return aPosition >> mSegmentSizeLog2;} + PRUint32 SegOffset(PRUint32 aPosition) {return aPosition & (mSegmentSize - 1);} +}; + +#endif // _nsStorageStream_h_ diff --git a/src/libs/xpcom18a4/xpcom/io/nsStreamUtils.cpp b/src/libs/xpcom18a4/xpcom/io/nsStreamUtils.cpp new file mode 100644 index 00000000..aeb52b2a --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsStreamUtils.cpp @@ -0,0 +1,583 @@ +/* ***** 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 "nsStreamUtils.h" +#include "nsCOMPtr.h" +#include "nsIPipe.h" +#include "nsIEventTarget.h" +#include "nsAutoLock.h" + +//----------------------------------------------------------------------------- + +class nsInputStreamReadyEvent : public PLEvent + , public nsIInputStreamCallback +{ +public: + NS_DECL_ISUPPORTS + + nsInputStreamReadyEvent(nsIInputStreamCallback *callback, + nsIEventTarget *target) + : mCallback(callback) + , mTarget(target) + { + } + +private: + ~nsInputStreamReadyEvent() + { + if (mCallback) { + nsresult rv; + // + // whoa!! looks like we never posted this event. take care to + // release mCallback on the correct thread. if mTarget lives on the + // calling thread, then we are ok. otherwise, we have to try to + // proxy the Release over the right thread. if that thread is dead, + // then there's nothing we can do... better to leak than crash. + // + PRBool val; + rv = mTarget->IsOnCurrentThread(&val); + if (NS_FAILED(rv) || !val) { + nsCOMPtr event; + NS_NewInputStreamReadyEvent(getter_AddRefs(event), mCallback, mTarget); + mCallback = 0; + if (event) { + rv = event->OnInputStreamReady(nsnull); + if (NS_FAILED(rv)) { + NS_NOTREACHED("leaking stream event"); + nsISupports *sup = event; + NS_ADDREF(sup); + } + } + } + } + } + +public: + NS_IMETHOD OnInputStreamReady(nsIAsyncInputStream *stream) + { + mStream = stream; + + // will be released when event is handled + NS_ADDREF_THIS(); + + PL_InitEvent(this, nsnull, EventHandler, EventCleanup); + + if (NS_FAILED(mTarget->PostEvent(this))) { + NS_WARNING("PostEvent failed"); + NS_RELEASE_THIS(); + return NS_ERROR_FAILURE; + } + + return NS_OK; + } + +private: + nsCOMPtr mStream; + nsCOMPtr mCallback; + nsCOMPtr mTarget; + + PR_STATIC_CALLBACK(void *) EventHandler(PLEvent *plevent) + { + nsInputStreamReadyEvent *ev = (nsInputStreamReadyEvent *) plevent; + // bypass event delivery if this is a cleanup event... + if (ev->mCallback) + ev->mCallback->OnInputStreamReady(ev->mStream); + ev->mCallback = 0; + return NULL; + } + + PR_STATIC_CALLBACK(void) EventCleanup(PLEvent *plevent) + { + nsInputStreamReadyEvent *ev = (nsInputStreamReadyEvent *) plevent; + NS_RELEASE(ev); + } +}; + +NS_IMPL_THREADSAFE_ISUPPORTS1(nsInputStreamReadyEvent, + nsIInputStreamCallback) + +//----------------------------------------------------------------------------- + +class nsOutputStreamReadyEvent : public PLEvent + , public nsIOutputStreamCallback +{ +public: + NS_DECL_ISUPPORTS + + nsOutputStreamReadyEvent(nsIOutputStreamCallback *callback, + nsIEventTarget *target) + : mCallback(callback) + , mTarget(target) + { + } + +private: + ~nsOutputStreamReadyEvent() + { + if (mCallback) { + nsresult rv; + // + // whoa!! looks like we never posted this event. take care to + // release mCallback on the correct thread. if mTarget lives on the + // calling thread, then we are ok. otherwise, we have to try to + // proxy the Release over the right thread. if that thread is dead, + // then there's nothing we can do... better to leak than crash. + // + PRBool val; + rv = mTarget->IsOnCurrentThread(&val); + if (NS_FAILED(rv) || !val) { + nsCOMPtr event; + NS_NewOutputStreamReadyEvent(getter_AddRefs(event), mCallback, mTarget); + mCallback = 0; + if (event) { + rv = event->OnOutputStreamReady(nsnull); + if (NS_FAILED(rv)) { + NS_NOTREACHED("leaking stream event"); + nsISupports *sup = event; + NS_ADDREF(sup); + } + } + } + } + } + +public: + void Init(nsIOutputStreamCallback *callback, nsIEventTarget *target) + { + mCallback = callback; + mTarget = target; + + PL_InitEvent(this, nsnull, EventHandler, EventCleanup); + } + + NS_IMETHOD OnOutputStreamReady(nsIAsyncOutputStream *stream) + { + mStream = stream; + + // this will be released when the event is handled + NS_ADDREF_THIS(); + + PL_InitEvent(this, nsnull, EventHandler, EventCleanup); + + if (NS_FAILED(mTarget->PostEvent(this))) { + NS_WARNING("PostEvent failed"); + NS_RELEASE_THIS(); + return NS_ERROR_FAILURE; + } + + return NS_OK; + } + +private: + nsCOMPtr mStream; + nsCOMPtr mCallback; + nsCOMPtr mTarget; + + PR_STATIC_CALLBACK(void *) EventHandler(PLEvent *plevent) + { + nsOutputStreamReadyEvent *ev = (nsOutputStreamReadyEvent *) plevent; + if (ev->mCallback) + ev->mCallback->OnOutputStreamReady(ev->mStream); + ev->mCallback = 0; + return NULL; + } + + PR_STATIC_CALLBACK(void) EventCleanup(PLEvent *ev) + { + nsOutputStreamReadyEvent *event = (nsOutputStreamReadyEvent *) ev; + NS_RELEASE(event); + } +}; + +NS_IMPL_THREADSAFE_ISUPPORTS1(nsOutputStreamReadyEvent, + nsIOutputStreamCallback) + +//----------------------------------------------------------------------------- + +NS_COM nsresult +NS_NewInputStreamReadyEvent(nsIInputStreamCallback **event, + nsIInputStreamCallback *callback, + nsIEventTarget *target) +{ + nsInputStreamReadyEvent *ev = new nsInputStreamReadyEvent(callback, target); + if (!ev) + return NS_ERROR_OUT_OF_MEMORY; + NS_ADDREF(*event = ev); + return NS_OK; +} + +NS_COM nsresult +NS_NewOutputStreamReadyEvent(nsIOutputStreamCallback **event, + nsIOutputStreamCallback *callback, + nsIEventTarget *target) +{ + nsOutputStreamReadyEvent *ev = new nsOutputStreamReadyEvent(callback, target); + if (!ev) + return NS_ERROR_OUT_OF_MEMORY; + NS_ADDREF(*event = ev); + return NS_OK; +} + +//----------------------------------------------------------------------------- +// NS_AsyncCopy implementation + +// abstract stream copier... +class nsAStreamCopier : public nsIInputStreamCallback + , public nsIOutputStreamCallback +{ +public: + NS_DECL_ISUPPORTS + + nsAStreamCopier() + : mLock(nsnull) + , mCallback(nsnull) + , mClosure(nsnull) + , mChunkSize(0) + , mEventInProcess(PR_FALSE) + , mEventIsPending(PR_FALSE) + { + } + + // virtual since subclasses call superclass Release() + virtual ~nsAStreamCopier() + { + if (mLock) + PR_DestroyLock(mLock); + } + + // kick off the async copy... + nsresult Start(nsIInputStream *source, + nsIOutputStream *sink, + nsIEventTarget *target, + nsAsyncCopyCallbackFun callback, + void *closure, + PRUint32 chunksize) + { + mSource = source; + mSink = sink; + mTarget = target; + mCallback = callback; + mClosure = closure; + mChunkSize = chunksize; + + mLock = PR_NewLock(); + if (!mLock) + return NS_ERROR_OUT_OF_MEMORY; + + mAsyncSource = do_QueryInterface(mSource); + mAsyncSink = do_QueryInterface(mSink); + + return PostContinuationEvent(); + } + + // implemented by subclasses, returns number of bytes copied and + // sets source and sink condition before returning. + virtual PRUint32 DoCopy(nsresult *sourceCondition, nsresult *sinkCondition) = 0; + + void Process() + { + if (!mSource || !mSink) + return; + + nsresult sourceCondition, sinkCondition; + + // ok, copy data from source to sink. + for (;;) { + PRUint32 n = DoCopy(&sourceCondition, &sinkCondition); + if (NS_FAILED(sourceCondition) || NS_FAILED(sinkCondition) || n == 0) { + if (sourceCondition == NS_BASE_STREAM_WOULD_BLOCK && mAsyncSource) { + // need to wait for more data from source. while waiting for + // more source data, be sure to observe failures on output end. + mAsyncSource->AsyncWait(this, 0, 0, nsnull); + + if (mAsyncSink) + mAsyncSink->AsyncWait(this, + nsIAsyncOutputStream::WAIT_CLOSURE_ONLY, + 0, nsnull); + } + else if (sinkCondition == NS_BASE_STREAM_WOULD_BLOCK && mAsyncSink) { + // need to wait for more room in the sink. while waiting for + // more room in the sink, be sure to observer failures on the + // input end. + mAsyncSink->AsyncWait(this, 0, 0, nsnull); + + if (mAsyncSource) + mAsyncSource->AsyncWait(this, + nsIAsyncInputStream::WAIT_CLOSURE_ONLY, + 0, nsnull); + } + else { + // close source + if (mAsyncSource) + mAsyncSource->CloseWithStatus(sinkCondition); + else + mSource->Close(); + mAsyncSource = nsnull; + mSource = nsnull; + + // close sink + if (mAsyncSink) + mAsyncSink->CloseWithStatus(sourceCondition); + else + mSink->Close(); + mAsyncSink = nsnull; + mSink = nsnull; + + // notify state complete... + if (mCallback) { + nsresult status = sourceCondition; + if (NS_SUCCEEDED(status)) + status = sinkCondition; + if (status == NS_BASE_STREAM_CLOSED) + status = NS_OK; + mCallback(mClosure, status); + } + } + break; + } + } + } + + NS_IMETHOD OnInputStreamReady(nsIAsyncInputStream *source) + { + PostContinuationEvent(); + return NS_OK; + } + + NS_IMETHOD OnOutputStreamReady(nsIAsyncOutputStream *sink) + { + PostContinuationEvent(); + return NS_OK; + } + + PR_STATIC_CALLBACK(void*) HandleContinuationEvent(PLEvent *event) + { + nsAStreamCopier *self = (nsAStreamCopier *) event->owner; + self->Process(); + + // clear "in process" flag and post any pending continuation event + nsAutoLock lock(self->mLock); + self->mEventInProcess = PR_FALSE; + if (self->mEventIsPending) { + self->mEventIsPending = PR_FALSE; + self->PostContinuationEvent_Locked(); + } + return nsnull; + } + + PR_STATIC_CALLBACK(void) DestroyContinuationEvent(PLEvent *event) + { + nsAStreamCopier *self = (nsAStreamCopier *) event->owner; + NS_RELEASE(self); + delete event; + } + + nsresult PostContinuationEvent() + { + // we cannot post a continuation event if there is currently + // an event in process. doing so could result in Process being + // run simultaneously on multiple threads, so we mark the event + // as pending, and if an event is already in process then we + // just let that existing event take care of posting the real + // continuation event. + + nsAutoLock lock(mLock); + return PostContinuationEvent_Locked(); + } + + nsresult PostContinuationEvent_Locked() + { + nsresult rv = NS_OK; + if (mEventInProcess) + mEventIsPending = PR_TRUE; + else { + PLEvent *event = new PLEvent; + if (!event) + rv = NS_ERROR_OUT_OF_MEMORY; + else { + NS_ADDREF_THIS(); + PL_InitEvent(event, this, + HandleContinuationEvent, + DestroyContinuationEvent); + + rv = mTarget->PostEvent(event); + if (NS_SUCCEEDED(rv)) + mEventInProcess = PR_TRUE; + else { + NS_ERROR("unable to post continuation event"); + PL_DestroyEvent(event); + } + } + } + return rv; + } + +protected: + nsCOMPtr mSource; + nsCOMPtr mSink; + nsCOMPtr mAsyncSource; + nsCOMPtr mAsyncSink; + nsCOMPtr mTarget; + PRLock *mLock; + nsAsyncCopyCallbackFun mCallback; + void *mClosure; + PRUint32 mChunkSize; + PRPackedBool mEventInProcess; + PRPackedBool mEventIsPending; +}; + +NS_IMPL_THREADSAFE_ISUPPORTS2(nsAStreamCopier, + nsIInputStreamCallback, + nsIOutputStreamCallback) + +class nsStreamCopierIB : public nsAStreamCopier +{ +public: + nsStreamCopierIB() : nsAStreamCopier() {} + virtual ~nsStreamCopierIB() {} + + struct ReadSegmentsState { + nsIOutputStream *mSink; + nsresult mSinkCondition; + }; + + static NS_METHOD ConsumeInputBuffer(nsIInputStream *inStr, + void *closure, + const char *buffer, + PRUint32 offset, + PRUint32 count, + PRUint32 *countWritten) + { + ReadSegmentsState *state = (ReadSegmentsState *) closure; + + nsresult rv = state->mSink->Write(buffer, count, countWritten); + if (NS_FAILED(rv)) + state->mSinkCondition = rv; + else if (*countWritten == 0) + state->mSinkCondition = NS_BASE_STREAM_CLOSED; + + return state->mSinkCondition; + } + + PRUint32 DoCopy(nsresult *sourceCondition, nsresult *sinkCondition) + { + ReadSegmentsState state; + state.mSink = mSink; + state.mSinkCondition = NS_OK; + + PRUint32 n; + *sourceCondition = + mSource->ReadSegments(ConsumeInputBuffer, &state, mChunkSize, &n); + *sinkCondition = state.mSinkCondition; + return n; + } +}; + +class nsStreamCopierOB : public nsAStreamCopier +{ +public: + nsStreamCopierOB() : nsAStreamCopier() {} + virtual ~nsStreamCopierOB() {} + + struct WriteSegmentsState { + nsIInputStream *mSource; + nsresult mSourceCondition; + }; + + static NS_METHOD FillOutputBuffer(nsIOutputStream *outStr, + void *closure, + char *buffer, + PRUint32 offset, + PRUint32 count, + PRUint32 *countRead) + { + WriteSegmentsState *state = (WriteSegmentsState *) closure; + + nsresult rv = state->mSource->Read(buffer, count, countRead); + if (NS_FAILED(rv)) + state->mSourceCondition = rv; + else if (*countRead == 0) + state->mSourceCondition = NS_BASE_STREAM_CLOSED; + + return state->mSourceCondition; + } + + PRUint32 DoCopy(nsresult *sourceCondition, nsresult *sinkCondition) + { + WriteSegmentsState state; + state.mSource = mSource; + state.mSourceCondition = NS_OK; + + PRUint32 n; + *sinkCondition = + mSink->WriteSegments(FillOutputBuffer, &state, mChunkSize, &n); + *sourceCondition = state.mSourceCondition; + return n; + } +}; + +//----------------------------------------------------------------------------- + +NS_COM nsresult +NS_AsyncCopy(nsIInputStream *source, + nsIOutputStream *sink, + nsIEventTarget *target, + nsAsyncCopyMode mode, + PRUint32 chunkSize, + nsAsyncCopyCallbackFun callback, + void *closure) +{ + NS_ASSERTION(target, "non-null target required"); + + nsresult rv; + nsAStreamCopier *copier; + + if (mode == NS_ASYNCCOPY_VIA_READSEGMENTS) + copier = new nsStreamCopierIB(); + else + copier = new nsStreamCopierOB(); + + if (!copier) + return NS_ERROR_OUT_OF_MEMORY; + + // Start() takes an owning ref to the copier... + NS_ADDREF(copier); + rv = copier->Start(source, sink, target, callback, closure, chunkSize); + NS_RELEASE(copier); + + return rv; +} diff --git a/src/libs/xpcom18a4/xpcom/io/nsStreamUtils.h b/src/libs/xpcom18a4/xpcom/io/nsStreamUtils.h new file mode 100644 index 00000000..3d33f1c1 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsStreamUtils.h @@ -0,0 +1,111 @@ +/* ***** 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 ***** */ + +#ifndef nsStreamUtils_h__ +#define nsStreamUtils_h__ + +#include "nscore.h" + +class nsIInputStream; +class nsIOutputStream; +class nsIInputStreamCallback; +class nsIOutputStreamCallback; +class nsIEventTarget; + +/** + * A "one-shot" proxy of the OnInputStreamReady callback. The resulting + * proxy object's OnInputStreamReady function may only be called once! The + * proxy object ensures that the real notify object will be free'd on the + * thread corresponding to the given event target regardless of what thread + * the proxy object is destroyed on. + * + * This function is designed to be used to implement AsyncWait when the + * aEventTarget parameter is non-null. + */ +extern NS_COM nsresult +NS_NewInputStreamReadyEvent(nsIInputStreamCallback **aEvent, + nsIInputStreamCallback *aNotify, + nsIEventTarget *aEventTarget); + +/** + * A "one-shot" proxy of the OnOutputStreamReady callback. The resulting + * proxy object's OnOutputStreamReady function may only be called once! The + * proxy object ensures that the real notify object will be free'd on the + * thread corresponding to the given event target regardless of what thread + * the proxy object is destroyed on. + * + * This function is designed to be used to implement AsyncWait when the + * aEventTarget parameter is non-null. + */ +extern NS_COM nsresult +NS_NewOutputStreamReadyEvent(nsIOutputStreamCallback **aEvent, + nsIOutputStreamCallback *aNotify, + nsIEventTarget *aEventTarget); + +/* ------------------------------------------------------------------------- */ + +enum nsAsyncCopyMode { + NS_ASYNCCOPY_VIA_READSEGMENTS, + NS_ASYNCCOPY_VIA_WRITESEGMENTS +}; + +/** + * This function is called when the async copy process completes. The reported + * status is NS_OK on success and some error code on failure. + */ +typedef void (* nsAsyncCopyCallbackFun)(void *closure, nsresult status); + +/** + * This function asynchronously copies data from the source to the sink. All + * data transfer occurs on the thread corresponding to the given event target. + * A null event target is not permitted. + * + * The copier handles blocking or non-blocking streams transparently. If a + * stream operation returns NS_BASE_STREAM_WOULD_BLOCK, then the stream will + * be QI'd to nsIAsync{In,Out}putStream and its AsyncWait method will be used + * to determine when to resume copying. + */ +extern NS_COM nsresult +NS_AsyncCopy(nsIInputStream *aSource, + nsIOutputStream *aSink, + nsIEventTarget *aEventTarget, + nsAsyncCopyMode aMode = NS_ASYNCCOPY_VIA_READSEGMENTS, + PRUint32 aChunkSize = 4096, + nsAsyncCopyCallbackFun aCallbackFun = nsnull, + void *aCallbackClosure = nsnull); + +#endif // !nsStreamUtils_h__ diff --git a/src/libs/xpcom18a4/xpcom/io/nsStringIO.h b/src/libs/xpcom18a4/xpcom/io/nsStringIO.h new file mode 100644 index 00000000..beca1d19 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsStringIO.h @@ -0,0 +1,86 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Scott Collins + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +#ifndef nsStringIO_h___ +#define nsStringIO_h___ + +#include "nsAString.h" +#include + + +template +class nsFileCharSink + { + public: + typedef CharT value_type; + + public: + nsFileCharSink( FILE* aOutputFile ) : mOutputFile(aOutputFile) { } + + PRUint32 + write( const value_type* s, PRUint32 n ) + { + return fwrite(s, sizeof(CharT), n, mOutputFile); + } + + private: + FILE* mOutputFile; + }; + + +template +inline +void +fprint_string( FILE* aFile, const basic_nsAString& aString ) + { + nsReadingIterator fromBegin, fromEnd; + nsFileCharSink toBegin(aFile); + copy_string(aString.BeginReading(fromBegin), aString.EndReading(fromEnd), toBegin); + } + + +template +inline +void +print_string( const basic_nsAString& aString ) + { + fprint_string(stdout, aString); + } + + +#endif // !defined(nsStringIO_h___) diff --git a/src/libs/xpcom18a4/xpcom/io/nsStringStream.cpp b/src/libs/xpcom18a4/xpcom/io/nsStringStream.cpp new file mode 100644 index 00000000..536eab11 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsStringStream.cpp @@ -0,0 +1,457 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * mcmullen@netscape.com (original author) + * warren@netscape.com + * alecf@netscape.com + * scc@mozilla.org + * david.gardiner@unisa.edu.au + * fur@netscape.com + * norris@netscape.com + * pinkerton@netscape.com + * davidm@netscape.com + * sfraser@netscape.com + * darin@netscape.com + * bzbarsky@mit.edu + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/** + * Based on original code from nsIStringStream.cpp + */ + +#include "nsStringStream.h" + +#include "prerror.h" +#include "plstr.h" +#include "nsReadableUtils.h" +#include "nsCRT.h" +#include "nsISeekableStream.h" +#include "nsInt64.h" + +#define NS_FILE_RESULT(x) ns_file_convert_result((PRInt32)x) +#define NS_FILE_FAILURE NS_FILE_RESULT(-1) + +static nsresult ns_file_convert_result(PRInt32 nativeErr) +{ + return nativeErr ? + NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_FILES,((nativeErr)&0xFFFF)) + : NS_OK; +} + +//----------------------------------------------------------------------------- +// nsIStringInputStream implementation +//----------------------------------------------------------------------------- + +class nsStringInputStream : public nsIStringInputStream + , public nsIRandomAccessStore + +{ +public: + nsStringInputStream() + : mOffset(0) + , mLastResult(NS_OK) + , mEOF(PR_FALSE) + , mOwned(PR_FALSE) + , mConstString(nsnull) + , mLength(0) + {} + +private: + ~nsStringInputStream() + { + if (mOwned) + nsMemory::Free((char*)mConstString); + } + +public: + NS_DECL_ISUPPORTS + + NS_DECL_NSISTRINGINPUTSTREAM + NS_DECL_NSIINPUTSTREAM + + // nsIRandomAccessStore interface + NS_IMETHOD GetAtEOF(PRBool* outAtEOF); + NS_IMETHOD SetAtEOF(PRBool inAtEOF); + + NS_DECL_NSISEEKABLESTREAM + +protected: + PRInt32 LengthRemaining() const + { + return mLength - mOffset; + } + + void Clear() + { + NS_ASSERTION(mConstString || !mOwned, + "Can't have mOwned set and have a null string!"); + if (mOwned) + nsMemory::Free((char*)mConstString); + + // We're about to get a new string; clear the members that + // would no longer have valid values. + mOffset = 0; + mLastResult = NS_OK; + mEOF = PR_FALSE; + } + + PRInt32 mOffset; + nsresult mLastResult; + PRPackedBool mEOF; + PRPackedBool mOwned; + const char* mConstString; + PRInt32 mLength; +}; + +NS_IMPL_THREADSAFE_ISUPPORTS4(nsStringInputStream, + nsIStringInputStream, + nsIInputStream, + nsIRandomAccessStore, + nsISeekableStream) + +///////// +// nsIStringInputStream implementation +///////// +NS_IMETHODIMP +nsStringInputStream::SetData(const char *data, PRInt32 dataLen) +{ + if (dataLen < 0) + dataLen = strlen(data); + + return AdoptData(nsCRT::strndup(data, dataLen), dataLen); +} + +NS_IMETHODIMP +nsStringInputStream::AdoptData(char *data, PRInt32 dataLen) +{ + NS_ENSURE_ARG_POINTER(data); + + if (dataLen < 0) + dataLen = strlen(data); + + Clear(); + + mConstString = (const char *) data; + mLength = dataLen; + mOwned = PR_TRUE; + return NS_OK; +} + +NS_IMETHODIMP +nsStringInputStream::ShareData(const char *data, PRInt32 dataLen) +{ + NS_ENSURE_ARG_POINTER(data); + + if (dataLen < 0) + dataLen = strlen(data); + + Clear(); + + mConstString = data; + mLength = dataLen; + mOwned = PR_FALSE; + return NS_OK; +} + +///////// +// nsIInputStream implementation +///////// +NS_IMETHODIMP nsStringInputStream::Close() +{ + return NS_OK; +} + +NS_IMETHODIMP nsStringInputStream::Available(PRUint32 *aLength) +{ + NS_PRECONDITION(aLength != nsnull, "null ptr"); + if (!aLength) + return NS_ERROR_NULL_POINTER; + *aLength = LengthRemaining(); + return NS_OK; +} + +NS_IMETHODIMP nsStringInputStream::Read(char* aBuf, PRUint32 aCount, + PRUint32 *aReadCount) +{ + NS_PRECONDITION(aBuf != nsnull, "null ptr"); + if (!aBuf) + return NS_ERROR_NULL_POINTER; + NS_PRECONDITION(aReadCount != nsnull, "null ptr"); + if (!aReadCount) + return NS_ERROR_NULL_POINTER; + if (NS_FAILED(mLastResult)) + return mLastResult; + + PRInt32 bytesRead; + PRInt32 maxCount = mLength - mOffset; + if ((PRInt32)aCount > maxCount) + bytesRead = maxCount; + else + bytesRead = aCount; + + memcpy(aBuf, mConstString + mOffset, bytesRead); + mOffset += bytesRead; + + *aReadCount = bytesRead; + if (bytesRead < (PRInt32)aCount) + SetAtEOF(PR_TRUE); + return NS_OK; +} + + +NS_IMETHODIMP +nsStringInputStream::ReadSegments(nsWriteSegmentFun writer, void * closure, + PRUint32 aCount, PRUint32 * result) +{ + nsresult rv; + PRInt32 maxCount = mLength - mOffset; + if (maxCount == 0) { + *result = 0; + return NS_OK; + } + if ((PRInt32)aCount > maxCount) + aCount = maxCount; + rv = writer(this, closure, mConstString + mOffset, + 0, aCount, result); + if (NS_SUCCEEDED(rv)) + mOffset += *result; + // errors returned from the writer end here! + return NS_OK; +} + +NS_IMETHODIMP +nsStringInputStream::IsNonBlocking(PRBool *aNonBlocking) +{ + *aNonBlocking = PR_TRUE; + return NS_OK; +} + + +///////// +// nsISeekableStream implementation +///////// +NS_IMETHODIMP nsStringInputStream::Seek(PRInt32 whence, PRInt64 offset) +{ + mLastResult = NS_OK; // reset on a seek. + const nsInt64 maxUint32 = PR_UINT32_MAX; + nsInt64 offset64(offset); + PRInt32 offset32; + LL_L2I(offset32, offset); + + NS_ASSERTION(maxUint32 > offset64, "string streams only support 32 bit offsets"); + mEOF = PR_FALSE; // reset on a seek. + PRInt32 fileSize = LengthRemaining(); + PRInt32 newPosition=-1; + switch (whence) + { + case NS_SEEK_CUR: newPosition = mOffset + offset32; break; + case NS_SEEK_SET: newPosition = offset32; break; + case NS_SEEK_END: newPosition = fileSize + offset32; break; + } + if (newPosition < 0) + { + newPosition = 0; + mLastResult = NS_FILE_RESULT(PR_FILE_SEEK_ERROR); + } + if (newPosition >= fileSize) + { + newPosition = fileSize; + mEOF = PR_TRUE; + } + mOffset = newPosition; + return NS_OK; +} + + +NS_IMETHODIMP nsStringInputStream::Tell(PRInt64* outWhere) +{ + *outWhere = mOffset; + return NS_OK; +} + +NS_IMETHODIMP nsStringInputStream::SetEOF() +{ + NS_NOTYETIMPLEMENTED("nsStringInputStream::SetEOF"); + return NS_ERROR_NOT_IMPLEMENTED; +} + +///////// +// nsIRandomAccessStore implementation +///////// +NS_IMETHODIMP nsStringInputStream::GetAtEOF(PRBool* outAtEOF) +{ + *outAtEOF = mEOF; + return NS_OK; +} + +NS_IMETHODIMP nsStringInputStream::SetAtEOF(PRBool inAtEOF) +{ + mEOF = inAtEOF; + return NS_OK; +} + +// Factory method to get an nsInputStream from an nsAString. Result will +// implement nsIStringInputStream and nsIRandomAccessStore +extern "C" NS_COM nsresult +NS_NewStringInputStream(nsIInputStream** aStreamResult, + const nsAString& aStringToRead) +{ + NS_PRECONDITION(aStreamResult, "null out ptr"); + + char* data = ToNewCString(aStringToRead); + if (!data) + return NS_ERROR_OUT_OF_MEMORY; + + nsStringInputStream* stream = new nsStringInputStream(); + if (! stream) { + nsMemory::Free(data); + return NS_ERROR_OUT_OF_MEMORY; + } + + NS_ADDREF(stream); + + nsresult rv = stream->AdoptData(data, aStringToRead.Length()); + if (NS_FAILED(rv)) { + nsMemory::Free(data); + NS_RELEASE(stream); + return rv; + } + + *aStreamResult = stream; + return NS_OK; +} + +// Factory method to get an nsInputStream from an nsACString. Result will +// implement nsIStringInputStream and nsIRandomAccessStore +extern "C" NS_COM nsresult +NS_NewCStringInputStream(nsIInputStream** aStreamResult, + const nsACString& aStringToRead) +{ + NS_PRECONDITION(aStreamResult, "null out ptr"); + + char* data = ToNewCString(aStringToRead); + if (!data) + return NS_ERROR_OUT_OF_MEMORY; + + nsStringInputStream* stream = new nsStringInputStream(); + if (! stream) { + nsMemory::Free(data); + return NS_ERROR_OUT_OF_MEMORY; + } + + NS_ADDREF(stream); + + nsresult rv = stream->AdoptData(data, aStringToRead.Length()); + if (NS_FAILED(rv)) { + nsMemory::Free(data); + NS_RELEASE(stream); + return rv; + } + + *aStreamResult = stream; + return NS_OK; +} + +// Factory method to get an nsInputStream from a C string. Result will +// implement nsIStringInputStream and nsIRandomAccessStore +extern "C" NS_COM nsresult +NS_NewCharInputStream(nsIInputStream** aStreamResult, + const char* aStringToRead) +{ + NS_PRECONDITION(aStreamResult, "null out ptr"); + + nsStringInputStream* stream = new nsStringInputStream(); + if (! stream) + return NS_ERROR_OUT_OF_MEMORY; + + NS_ADDREF(stream); + + nsresult rv = stream->ShareData(aStringToRead, -1); + + if (NS_FAILED(rv)) { + NS_RELEASE(stream); + return rv; + } + + *aStreamResult = stream; + return NS_OK; +} + +// Factory method to get an nsInputStream from a byte array. Result will +// implement nsIStringInputStream and nsIRandomAccessStore +extern "C" NS_COM nsresult +NS_NewByteInputStream(nsIInputStream** aStreamResult, + const char* aStringToRead, + PRInt32 aLength) +{ + NS_PRECONDITION(aStreamResult, "null out ptr"); + + nsStringInputStream* stream = new nsStringInputStream(); + if (! stream) + return NS_ERROR_OUT_OF_MEMORY; + + NS_ADDREF(stream); + + nsresult rv = stream->ShareData(aStringToRead, aLength); + + if (NS_FAILED(rv)) { + NS_RELEASE(stream); + return rv; + } + + *aStreamResult = stream; + return NS_OK; +} + +// factory method for constructing a nsStringInputStream object +NS_METHOD +nsStringInputStreamConstructor(nsISupports *outer, REFNSIID iid, void **result) +{ + *result = nsnull; + + if (outer) + return NS_ERROR_NO_AGGREGATION; + + nsStringInputStream *inst; + NS_NEWXPCOM(inst, nsStringInputStream); + if (!inst) + return NS_ERROR_OUT_OF_MEMORY; + + NS_ADDREF(inst); + nsresult rv = inst->QueryInterface(iid, result); + NS_RELEASE(inst); + + return rv; +} diff --git a/src/libs/xpcom18a4/xpcom/io/nsStringStream.h b/src/libs/xpcom18a4/xpcom/io/nsStringStream.h new file mode 100644 index 00000000..6f2f7f20 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsStringStream.h @@ -0,0 +1,84 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * darin@netscape.com (original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +#ifndef nsStringStream_h__ +#define nsStringStream_h__ + +#include "nsISeekableStream.h" + +/* a6cf90e8-15b3-11d2-932e-00805f8add32 */ +#define NS_IRANDOMACCESS_IID \ +{ 0xa6cf90eb, 0x15b3, 0x11d2, \ + {0x93, 0x2e, 0x00, 0x80, 0x5f, 0x8a, 0xdd, 0x32} } + +//======================================================================================== +class nsIRandomAccessStore +// Supports Seek, Tell etc. +//======================================================================================== +: public nsISeekableStream +{ +public: + NS_DEFINE_STATIC_IID_ACCESSOR(NS_IRANDOMACCESS_IID) + +/* "PROTECTED" */ + NS_IMETHOD GetAtEOF(PRBool* outAtEOF) = 0; + NS_IMETHOD SetAtEOF(PRBool inAtEOF) = 0; +}; // class nsIRandomAccessStore + +#include "nsIStringStream.h" + +/** + * nsStringInputStream : nsIStringInputStream + * , nsIInputStream + * , nsISeekableStream + * , nsIRandomAccessStore + */ +#define NS_STRINGINPUTSTREAM_CLASSNAME "nsStringInputStream" +#define NS_STRINGINPUTSTREAM_CONTRACTID "@mozilla.org/io/string-input-stream;1" +#define NS_STRINGINPUTSTREAM_CID \ +{ /* 0abb0835-5000-4790-af28-61b3ba17c295 */ \ + 0x0abb0835, \ + 0x5000, \ + 0x4790, \ + {0xaf, 0x28, 0x61, 0xb3, 0xba, 0x17, 0xc2, 0x95} \ +} +extern NS_METHOD nsStringInputStreamConstructor(nsISupports *, REFNSIID, void **); + + + +#endif // nsStringStream_h__ diff --git a/src/libs/xpcom18a4/xpcom/io/nsUnicharInputStream.cpp b/src/libs/xpcom18a4/xpcom/io/nsUnicharInputStream.cpp new file mode 100644 index 00000000..99e9364a --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsUnicharInputStream.cpp @@ -0,0 +1,415 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsIUnicharInputStream.h" +#include "nsIByteBuffer.h" +#include "nsIUnicharBuffer.h" +#include "nsIServiceManager.h" +#include "nsString.h" +#include "nsCRT.h" +#include "nsUTF8Utils.h" +#include +#if defined(NS_WIN32) +#include +#else +#include +#endif + +class StringUnicharInputStream : public nsIUnicharInputStream { +public: + StringUnicharInputStream(nsString* aString); + + NS_DECL_ISUPPORTS + + NS_IMETHOD Read(PRUnichar* aBuf, + PRUint32 aCount, + PRUint32 *aReadCount); + NS_IMETHOD ReadSegments(nsWriteUnicharSegmentFun aWriter, + void* aClosure, + PRUint32 aCount, PRUint32* aReadCount); + NS_IMETHOD Close(); + + nsString* mString; + PRUint32 mPos; + PRUint32 mLen; + +private: + ~StringUnicharInputStream(); +}; + +StringUnicharInputStream::StringUnicharInputStream(nsString* aString) +{ + mString = aString; + mPos = 0; + mLen = aString->Length(); +} + +StringUnicharInputStream::~StringUnicharInputStream() +{ + if (nsnull != mString) { + delete mString; + } +} + +NS_IMETHODIMP +StringUnicharInputStream::Read(PRUnichar* aBuf, + PRUint32 aCount, + PRUint32 *aReadCount) +{ + if (mPos >= mLen) { + *aReadCount = 0; + return NS_OK; + } + const PRUnichar* us = mString->get(); + NS_ASSERTION(mLen >= mPos, "unsigned madness"); + PRUint32 amount = mLen - mPos; + if (amount > aCount) { + amount = aCount; + } + memcpy(aBuf, us + mPos, sizeof(PRUnichar) * amount); + mPos += amount; + *aReadCount = amount; + return NS_OK; +} + +NS_IMETHODIMP +StringUnicharInputStream::ReadSegments(nsWriteUnicharSegmentFun aWriter, + void* aClosure, + PRUint32 aCount, PRUint32 *aReadCount) +{ + PRUint32 bytesWritten; + PRUint32 totalBytesWritten = 0; + + nsresult rv; + aCount = PR_MIN(mString->Length() - mPos, aCount); + + while (aCount) { + rv = aWriter(this, aClosure, mString->get() + mPos, + totalBytesWritten, aCount, &bytesWritten); + + if (NS_FAILED(rv)) { + // don't propagate errors to the caller + break; + } + + aCount -= bytesWritten; + totalBytesWritten += bytesWritten; + mPos += bytesWritten; + } + + *aReadCount = totalBytesWritten; + + return NS_OK; +} + +nsresult StringUnicharInputStream::Close() +{ + mPos = mLen; + if (nsnull != mString) { + delete mString; + mString = 0; + } + return NS_OK; +} + +NS_IMPL_ISUPPORTS1(StringUnicharInputStream, nsIUnicharInputStream) + +NS_COM nsresult +NS_NewStringUnicharInputStream(nsIUnicharInputStream** aInstancePtrResult, + nsString* aString) +{ + NS_PRECONDITION(nsnull != aString, "null ptr"); + NS_PRECONDITION(nsnull != aInstancePtrResult, "null ptr"); + if ((nsnull == aString) || (nsnull == aInstancePtrResult)) { + return NS_ERROR_NULL_POINTER; + } + + StringUnicharInputStream* it = new StringUnicharInputStream(aString); + if (nsnull == it) { + return NS_ERROR_OUT_OF_MEMORY; + } + + return it->QueryInterface(NS_GET_IID(nsIUnicharInputStream), + (void**) aInstancePtrResult); +} + +//---------------------------------------------------------------------- + +class UTF8InputStream : public nsIUnicharInputStream { +public: + UTF8InputStream(); + nsresult Init(nsIInputStream* aStream, PRUint32 aBufSize); + + NS_DECL_ISUPPORTS + NS_IMETHOD Read(PRUnichar* aBuf, + PRUint32 aCount, + PRUint32 *aReadCount); + NS_IMETHOD ReadSegments(nsWriteUnicharSegmentFun aWriter, + void* aClosure, + PRUint32 aCount, + PRUint32 *aReadCount); + NS_IMETHOD Close(); + +private: + ~UTF8InputStream(); + +protected: + PRInt32 Fill(nsresult * aErrorCode); + + static void CountValidUTF8Bytes(const char *aBuf, PRUint32 aMaxBytes, PRUint32& aValidUTF8bytes, PRUint32& aValidUCS2bytes); + + nsCOMPtr mInput; + nsCOMPtr mByteData; + nsCOMPtr mUnicharData; + + PRUint32 mByteDataOffset; + PRUint32 mUnicharDataOffset; + PRUint32 mUnicharDataLength; +}; + +UTF8InputStream::UTF8InputStream() : + mByteDataOffset(0), + mUnicharDataOffset(0), + mUnicharDataLength(0) +{ +} + +nsresult +UTF8InputStream::Init(nsIInputStream* aStream, PRUint32 aBufferSize) +{ + if (aBufferSize == 0) { + aBufferSize = 8192; + } + + nsresult rv = NS_NewByteBuffer(getter_AddRefs(mByteData), nsnull, aBufferSize); + if (NS_FAILED(rv)) return rv; + rv = NS_NewUnicharBuffer(getter_AddRefs(mUnicharData), nsnull, aBufferSize); + if (NS_FAILED(rv)) return rv; + + mInput = aStream; + + return NS_OK; +} + +NS_IMPL_ISUPPORTS1(UTF8InputStream,nsIUnicharInputStream) + +UTF8InputStream::~UTF8InputStream() +{ + Close(); +} + +nsresult UTF8InputStream::Close() +{ + mInput = nsnull; + mByteData = nsnull; + mUnicharData = nsnull; + + return NS_OK; +} + +nsresult UTF8InputStream::Read(PRUnichar* aBuf, + PRUint32 aCount, + PRUint32 *aReadCount) +{ + NS_ASSERTION(mUnicharDataLength >= mUnicharDataOffset, "unsigned madness"); + PRUint32 rv = mUnicharDataLength - mUnicharDataOffset; + nsresult errorCode; + if (0 == rv) { + // Fill the unichar buffer + rv = Fill(&errorCode); + if (rv <= 0) { + *aReadCount = 0; + return errorCode; + } + } + if (rv > aCount) { + rv = aCount; + } + memcpy(aBuf, mUnicharData->GetBuffer() + mUnicharDataOffset, + rv * sizeof(PRUnichar)); + mUnicharDataOffset += rv; + *aReadCount = rv; + return NS_OK; +} + +NS_IMETHODIMP +UTF8InputStream::ReadSegments(nsWriteUnicharSegmentFun aWriter, + void* aClosure, + PRUint32 aCount, PRUint32 *aReadCount) +{ + NS_ASSERTION(mUnicharDataLength >= mUnicharDataOffset, "unsigned madness"); + PRUint32 bytesToWrite = mUnicharDataLength - mUnicharDataOffset; + nsresult rv = NS_OK; + if (0 == bytesToWrite) { + // Fill the unichar buffer + bytesToWrite = Fill(&rv); + if (bytesToWrite <= 0) { + *aReadCount = 0; + return rv; + } + } + + if (bytesToWrite > aCount) + bytesToWrite = aCount; + + PRUint32 bytesWritten; + PRUint32 totalBytesWritten = 0; + + while (bytesToWrite) { + rv = aWriter(this, aClosure, + mUnicharData->GetBuffer() + mUnicharDataOffset, + totalBytesWritten, bytesToWrite, &bytesWritten); + + if (NS_FAILED(rv)) { + // don't propagate errors to the caller + break; + } + + bytesToWrite -= bytesWritten; + totalBytesWritten += bytesWritten; + mUnicharDataOffset += bytesWritten; + } + + *aReadCount = totalBytesWritten; + + return NS_OK; +} + +PRInt32 UTF8InputStream::Fill(nsresult * aErrorCode) +{ + if (nsnull == mInput) { + // We already closed the stream! + *aErrorCode = NS_BASE_STREAM_CLOSED; + return -1; + } + + NS_ASSERTION(mByteData->GetLength() >= mByteDataOffset, "unsigned madness"); + PRUint32 remainder = mByteData->GetLength() - mByteDataOffset; + mByteDataOffset = remainder; + PRInt32 nb = mByteData->Fill(aErrorCode, mInput, remainder); + if (nb <= 0) { + // Because we assume a many to one conversion, the lingering data + // in the byte buffer must be a partial conversion + // fragment. Because we know that we have recieved no more new + // data to add to it, we can't convert it. Therefore, we discard + // it. + return nb; + } + NS_ASSERTION(remainder + nb == mByteData->GetLength(), "bad nb"); + + // Now convert as much of the byte buffer to unicode as possible + PRUint32 srcLen, dstLen; + CountValidUTF8Bytes(mByteData->GetBuffer(),remainder + nb, srcLen, dstLen); + + // the number of UCS2 characters should always be <= the number of + // UTF8 chars + NS_ASSERTION( (remainder+nb >= srcLen), "cannot be longer than out buffer"); + NS_ASSERTION(PRInt32(dstLen) <= mUnicharData->GetBufferSize(), + "Ouch. I would overflow my buffer if I wasn't so careful."); + if (PRInt32(dstLen) > mUnicharData->GetBufferSize()) return 0; + + ConvertUTF8toUTF16 converter(mUnicharData->GetBuffer()); + + nsASingleFragmentCString::const_char_iterator start = mByteData->GetBuffer(); + nsASingleFragmentCString::const_char_iterator end = mByteData->GetBuffer() + srcLen; + + copy_string(start, end, converter); + NS_ASSERTION(converter.Length() == dstLen, "length mismatch"); + + mUnicharDataOffset = 0; + mUnicharDataLength = dstLen; + mByteDataOffset = srcLen; + + return dstLen; +} + +void +UTF8InputStream::CountValidUTF8Bytes(const char* aBuffer, PRUint32 aMaxBytes, PRUint32& aValidUTF8bytes, PRUint32& aValidUCS2chars) +{ + const char *c = aBuffer; + const char *end = aBuffer + aMaxBytes; + const char *lastchar = c; // pre-initialize in case of 0-length buffer + PRUint32 ucs2bytes = 0; + while (c < end && *c) { + lastchar = c; + ucs2bytes++; + + if (UTF8traits::isASCII(*c)) + c++; + else if (UTF8traits::is2byte(*c)) + c += 2; + else if (UTF8traits::is3byte(*c)) + c += 3; + else if (UTF8traits::is4byte(*c)) + c += 4; + else if (UTF8traits::is5byte(*c)) + c += 5; + else if (UTF8traits::is6byte(*c)) + c += 6; + else { + NS_WARNING("Unrecognized UTF8 string in UTF8InputStream::CountValidUTF8Bytes()"); + break; // Otherwise we go into an infinite loop. But what happens now? + } + } + if (c > end) { + c = lastchar; + ucs2bytes--; + } + + aValidUTF8bytes = c - aBuffer; + aValidUCS2chars = ucs2bytes; +} + +NS_COM nsresult +NS_NewUTF8ConverterStream(nsIUnicharInputStream** aInstancePtrResult, + nsIInputStream* aStreamToWrap, + PRInt32 aBufferSize) +{ + // Create converter input stream + UTF8InputStream* it = new UTF8InputStream(); + if (nsnull == it) { + return NS_ERROR_OUT_OF_MEMORY; + } + + nsresult rv = it->Init(aStreamToWrap, aBufferSize); + if (NS_FAILED(rv)) + return rv; + + return it->QueryInterface(NS_GET_IID(nsIUnicharInputStream), + (void **) aInstancePtrResult); +} diff --git a/src/libs/xpcom18a4/xpcom/libxpt/xptcall/porting.html b/src/libs/xpcom18a4/xpcom/libxpt/xptcall/porting.html new file mode 100644 index 00000000..38cadb40 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/libxpt/xptcall/porting.html @@ -0,0 +1,13 @@ + + +Document Moved! + + + + + \ No newline at end of file diff --git a/src/libs/xpcom18a4/xpcom/libxpt/xptcall/status.html b/src/libs/xpcom18a4/xpcom/libxpt/xptcall/status.html new file mode 100644 index 00000000..22532119 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/libxpt/xptcall/status.html @@ -0,0 +1,13 @@ + + +Document Moved! + + +
The xptcall status document has been moved to: +

+http://lxr.mozilla.org/mozilla/source/xpcom/reflect/xptcall/status.html +

+Please update your links. +

+ + diff --git a/src/libs/xpcom18a4/xpcom/obsolete/Makefile.in b/src/libs/xpcom18a4/xpcom/obsolete/Makefile.in new file mode 100644 index 00000000..5f8cd041 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/obsolete/Makefile.in @@ -0,0 +1,130 @@ +# +# ***** 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.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of 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 ***** + +DEPTH = ../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = xpcom_obsolete +LIBRARY_NAME = xpcom_compat +ifneq ($(OS_ARCH),WINNT) +SHORT_LIBNAME = xpcomct +endif + +GRE_MODULE = 1 +PACKAGE_FILE = xpcomobsolete.pkg + +DIRS = component + +REQUIRES = xpcom \ + string \ + $(NULL) + +# pull in MoreFiles for MacOSX +ifneq (,$(filter mac cocoa,$(MOZ_WIDGET_TOOLKIT))) +REQUIRES += macmorefiles +endif + +CPPSRCS = \ + nsFileSpec.cpp \ + nsFileStream.cpp \ + nsIFileStream.cpp \ + nsFileSpecImpl.cpp \ + nsSpecialSystemDirectory.cpp \ + $(NULL) + +ifeq ($(OS_ARCH),WINNT) +REQUIRES += libreg +CPPSRCS += dlldeps.cpp +endif + +EXPORTS = \ + xpcomobsolete.h \ + nsFileSpec.h \ + nsFileStream.h \ + nsIFileStream.h \ + nsSpecialSystemDirectory.h \ + nsIRegistryUtils.h \ + $(NULL) + +LOCAL_INCLUDES = \ + -I.. \ + -I$(srcdir)/../io \ + $(NULL) + +XPIDLSRCS = nsIFileSpec.idl \ + nsIRegistry.idl \ + $(NULL) +# Force use of PIC +FORCE_USE_PIC = 1 + +SHARED_LIBRARY_LIBS = \ + $(DIST)/lib/$(LIB_PREFIX)mozreg_s.$(LIB_SUFFIX) \ + $(NULL) + +# due to symbol conflicts on win32, this needs to be shared +FORCE_SHARED_LIB = 1 + +include $(topsrcdir)/config/rules.mk + +DEFINES += -D_IMPL_NS_COM_OBSOLETE + + +EXTRA_DSO_LDOPTS += $(MOZ_COMPONENT_LIBS) + +ifneq (,$(filter mac cocoa,$(MOZ_WIDGET_TOOLKIT))) +CXXFLAGS += $(TK_CFLAGS) +EXTRA_DSO_LDOPTS += $(TK_LIBS) +endif + +ifeq ($(OS_ARCH),BeOS) +EXTRA_DSO_LDOPTS += -lbe +endif + +ifeq ($(OS_ARCH),WINNT) +EXTRA_DSO_LDOPTS += $(call EXPAND_LIBNAME, shell32 ole32) +ifneq (,$(MOZ_DEBUG)$(NS_TRACE_MALLOC)) +EXTRA_DSO_LDOPTS += $(call EXPAND_LIBNAME, imagehlp) +endif +ifdef GNU_CXX +DSO_LDOPTS += -Wl,--export-all-symbols +endif +endif # WINNT + diff --git a/src/libs/xpcom18a4/xpcom/obsolete/component/Makefile.in b/src/libs/xpcom18a4/xpcom/obsolete/component/Makefile.in new file mode 100644 index 00000000..a8bec32d --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/obsolete/component/Makefile.in @@ -0,0 +1,81 @@ +# +# ***** 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.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of 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 ***** + +DEPTH = ../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = xpcom_compat_c +MODULE_NAME = xpcomObsoleteModule +LIBRARY_NAME = xpcom_compat_c +ifneq ($(OS_ARCH),WINNT) +SHORT_LIBNAME = xpcomctc +endif + +ifndef MINIMO +EXPORT_LIBRARY = 1 +endif +IS_COMPONENT = 1 +GRE_MODULE = 1 + +PACKAGE_FILE = xpcomobsoletec.pkg + +REQUIRES = xpcom \ + xpcom_obsolete \ + string \ + libreg \ + $(NULL) + +CPPSRCS = \ + nsXPCOMObsolete.cpp \ + nsRegistry.cpp \ + $(NULL) + + +LOCAL_INCLUDES = \ + -I$(srcdir)/../ \ + $(NULL) + +EXTRA_DSO_LDOPTS += $(MOZ_COMPONENT_LIBS) \ + $(MOZ_XPCOM_OBSOLETE_LIBS) \ + $(NULL) + + +include $(topsrcdir)/config/rules.mk diff --git a/src/libs/xpcom18a4/xpcom/obsolete/component/nsFileSpecImpl.cpp b/src/libs/xpcom18a4/xpcom/obsolete/component/nsFileSpecImpl.cpp new file mode 100644 index 00000000..7f51cdca --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/obsolete/component/nsFileSpecImpl.cpp @@ -0,0 +1,857 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Pierre Phaneuf + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsFileSpecImpl.h"// Always first, to ensure that it compiles alone. + +#include "nsIFileStream.h" +#include "nsFileStream.h" + +#include "nsILocalFile.h" + +#include "prmem.h" + +NS_IMPL_THREADSAFE_ISUPPORTS1(nsFileSpecImpl, nsIFileSpec) + +#ifdef NS_DEBUG +#define TEST_OUT_PTR(p) \ + if (!(p)) \ + return NS_ERROR_NULL_POINTER; +#else +#define TEST_OUT_PTR(p) +#endif + +//---------------------------------------------------------------------------------------- +nsFileSpecImpl::nsFileSpecImpl() +//---------------------------------------------------------------------------------------- + : mInputStream(nsnull) + , mOutputStream(nsnull) +{ +// NS_ASSERTION(0, "nsFileSpec is unsupported - use nsIFile!"); + +} + +//---------------------------------------------------------------------------------------- +nsFileSpecImpl::nsFileSpecImpl(const nsFileSpec& inSpec) +//---------------------------------------------------------------------------------------- + : mFileSpec(inSpec) + , mInputStream(nsnull) + , mOutputStream(nsnull) +{ +// NS_ASSERTION(0, "nsFileSpec is unsupported - use nsIFile!"); + +} + +//---------------------------------------------------------------------------------------- +nsFileSpecImpl::~nsFileSpecImpl() +//---------------------------------------------------------------------------------------- +{ + CloseStream(); +} + +//---------------------------------------------------------------------------------------- +/* static */ +nsresult nsFileSpecImpl::MakeInterface(const nsFileSpec& inSpec, nsIFileSpec** result) +//---------------------------------------------------------------------------------------- +{ + nsFileSpecImpl* it = new nsFileSpecImpl(inSpec); + if (!it) + return NS_ERROR_OUT_OF_MEMORY; + return it->QueryInterface(NS_GET_IID(nsIFileSpec), (void **) result); +} // nsFileSpecImpl::MakeInterface + +#define FILESPEC(ifilespec) ((nsFileSpecImpl*)ifilespec)->mFileSpec + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::FromFileSpec(const nsIFileSpec *original) +//---------------------------------------------------------------------------------------- +{ + if (original) { + nsresult rv = ((nsIFileSpec *)original)->GetFileSpec( &mFileSpec); + if (NS_SUCCEEDED( rv)) + return mFileSpec.Error(); + else + return( rv); + } + else + return( NS_ERROR_FAILURE); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::IsChildOf(nsIFileSpec *possibleParent, + PRBool *_retval) +{ + *_retval = mFileSpec.IsChildOf(FILESPEC(possibleParent)); + return mFileSpec.Error(); +} +//---------------------------------------------------------------------------------------- + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::GetURLString(char * *aURLString) +//---------------------------------------------------------------------------------------- +{ + TEST_OUT_PTR(aURLString) + if (mFileSpec.Failed()) + return mFileSpec.Error(); + nsFileURL url(mFileSpec); + *aURLString = nsCRT::strdup(url.GetURLString()); + if (!*aURLString) + return NS_ERROR_OUT_OF_MEMORY; + return NS_OK; +} // nsFileSpecImpl::GetURLString + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::SetURLString(const char * aURLString) +//---------------------------------------------------------------------------------------- +{ + mFileSpec = nsFileURL(aURLString); + return NS_OK; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::GetUnixStyleFilePath(char * *aUnixStyleFilePath) +//---------------------------------------------------------------------------------------- +{ + TEST_OUT_PTR(aUnixStyleFilePath) + if (mFileSpec.Failed()) + return mFileSpec.Error(); + nsFilePath path(mFileSpec); + *aUnixStyleFilePath = nsCRT::strdup((const char*) path); + if (!*aUnixStyleFilePath) + return NS_ERROR_OUT_OF_MEMORY; + return NS_OK; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::SetUnixStyleFilePath(const char * aUnixStyleFilePath) +//---------------------------------------------------------------------------------------- +{ + mFileSpec = nsFilePath(aUnixStyleFilePath); + return NS_OK; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::GetPersistentDescriptorString(char * *aPersistentDescriptorString) +//---------------------------------------------------------------------------------------- +{ + TEST_OUT_PTR(aPersistentDescriptorString) + if (mFileSpec.Failed()) + return mFileSpec.Error(); + nsPersistentFileDescriptor desc(mFileSpec); + nsCAutoString data; + desc.GetData(data); + *aPersistentDescriptorString = ToNewCString(data); + if (!*aPersistentDescriptorString) + return NS_ERROR_OUT_OF_MEMORY; + return NS_OK; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::SetPersistentDescriptorString(const char * aPersistentDescriptorString) +//---------------------------------------------------------------------------------------- +{ + nsPersistentFileDescriptor desc(mFileSpec); + desc.SetData(nsDependentCString(aPersistentDescriptorString)); + mFileSpec = desc; + return NS_OK; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::GetNativePath(char * *aNativePath) +//---------------------------------------------------------------------------------------- +{ + TEST_OUT_PTR(aNativePath) + if (mFileSpec.Failed()) + return mFileSpec.Error(); + *aNativePath = nsCRT::strdup(mFileSpec.GetNativePathCString()); + if (!*aNativePath) + return NS_ERROR_OUT_OF_MEMORY; + return NS_OK; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::SetNativePath(const char * aNativePath) +//---------------------------------------------------------------------------------------- +{ + mFileSpec = aNativePath; + return NS_OK; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::GetNSPRPath(char * *aNSPRPath) +//---------------------------------------------------------------------------------------- +{ + TEST_OUT_PTR(aNSPRPath) + if (mFileSpec.Failed()) + return mFileSpec.Error(); + nsNSPRPath path(mFileSpec); + *aNSPRPath = nsCRT::strdup((const char*) path); + if (!*aNSPRPath) + return NS_ERROR_OUT_OF_MEMORY; + return NS_OK; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::Error() +//---------------------------------------------------------------------------------------- +{ + return mFileSpec.Error(); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::IsValid(PRBool *_retval) +//---------------------------------------------------------------------------------------- +{ + TEST_OUT_PTR(_retval) + *_retval = mFileSpec.Valid(); + return NS_OK; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::Failed(PRBool *_retval) +//---------------------------------------------------------------------------------------- +{ + *_retval = mFileSpec.Failed(); + return NS_OK; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::GetLeafName(char * *aLeafName) +//---------------------------------------------------------------------------------------- +{ + TEST_OUT_PTR(aLeafName) + *aLeafName = mFileSpec.GetLeafName(); + return mFileSpec.Error(); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::SetLeafName(const char * aLeafName) +//---------------------------------------------------------------------------------------- +{ + mFileSpec.SetLeafName(aLeafName); + return mFileSpec.Error(); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::GetParent(nsIFileSpec * *aParent) +//---------------------------------------------------------------------------------------- +{ + TEST_OUT_PTR(aParent) + nsFileSpec parent; + mFileSpec.GetParent(parent); + return MakeInterface(parent, aParent); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::MakeUnique() +//---------------------------------------------------------------------------------------- +{ + mFileSpec.MakeUnique(); + return mFileSpec.Error(); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::MakeUniqueWithSuggestedName(const char *suggestedName) +//---------------------------------------------------------------------------------------- +{ + mFileSpec.MakeUnique(suggestedName); + return mFileSpec.Error(); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::GetModDate(PRUint32 *aModDate) +//---------------------------------------------------------------------------------------- +{ + TEST_OUT_PTR(aModDate) + nsFileSpec::TimeStamp stamp; + mFileSpec.GetModDate(stamp); + *aModDate = stamp; + return mFileSpec.Error(); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::ModDateChanged(PRUint32 oldStamp, PRBool *_retval) +//---------------------------------------------------------------------------------------- +{ + TEST_OUT_PTR(_retval) + *_retval = mFileSpec.ModDateChanged(oldStamp); + return mFileSpec.Error(); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::IsDirectory(PRBool *_retval) +//---------------------------------------------------------------------------------------- +{ + TEST_OUT_PTR(_retval) + *_retval = mFileSpec.IsDirectory(); + return mFileSpec.Error(); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::IsFile(PRBool *_retval) +//---------------------------------------------------------------------------------------- +{ + TEST_OUT_PTR(_retval) + *_retval = mFileSpec.IsFile(); + return mFileSpec.Error(); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::Exists(PRBool *_retval) +//---------------------------------------------------------------------------------------- +{ + TEST_OUT_PTR(_retval) + *_retval = mFileSpec.Exists(); + return mFileSpec.Error(); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::IsHidden(PRBool *_retval) +//---------------------------------------------------------------------------------------- +{ + TEST_OUT_PTR(_retval) + *_retval = mFileSpec.IsHidden(); + return mFileSpec.Error(); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::IsSymlink(PRBool *_retval) +//---------------------------------------------------------------------------------------- +{ + TEST_OUT_PTR(_retval) + *_retval = mFileSpec.IsSymlink(); + return mFileSpec.Error(); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::ResolveSymlink() +//---------------------------------------------------------------------------------------- +{ + PRBool ignore; + return mFileSpec.ResolveSymlink(ignore); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::GetFileSize(PRUint32 *aFileSize) +//---------------------------------------------------------------------------------------- +{ + TEST_OUT_PTR(aFileSize) + *aFileSize = mFileSpec.GetFileSize(); + return mFileSpec.Error(); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::GetDiskSpaceAvailable(PRInt64 *aDiskSpaceAvailable) +//---------------------------------------------------------------------------------------- +{ + TEST_OUT_PTR(aDiskSpaceAvailable) + *aDiskSpaceAvailable = mFileSpec.GetDiskSpaceAvailable(); + return mFileSpec.Error(); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::AppendRelativeUnixPath(const char *relativePath) +//---------------------------------------------------------------------------------------- +{ + mFileSpec += relativePath; + return mFileSpec.Error(); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::Touch() +//---------------------------------------------------------------------------------------- +{ + // create an empty file, like the UNIX touch command. + nsresult rv; + rv = OpenStreamForWriting(); + if (NS_FAILED(rv)) return rv; + rv = CloseStream(); + return rv; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::CreateDir() +//---------------------------------------------------------------------------------------- +{ + mFileSpec.CreateDir(); + return mFileSpec.Error(); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::Delete(PRBool aRecursive) +//---------------------------------------------------------------------------------------- +{ + mFileSpec.Delete(aRecursive); + return mFileSpec.Error(); +} +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::Truncate(PRInt32 aNewLength) +//---------------------------------------------------------------------------------------- +{ + return mFileSpec.Truncate(aNewLength); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::Rename(const char *newLeafName) +//---------------------------------------------------------------------------------------- +{ + return mFileSpec.Rename(newLeafName); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::CopyToDir(const nsIFileSpec *newParentDir) +//---------------------------------------------------------------------------------------- +{ + return mFileSpec.CopyToDir(FILESPEC(newParentDir)); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::MoveToDir(const nsIFileSpec *newParentDir) +//---------------------------------------------------------------------------------------- +{ + return mFileSpec.MoveToDir(FILESPEC(newParentDir)); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::Execute(const char *args) +//---------------------------------------------------------------------------------------- +{ + return mFileSpec.Execute(args); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::OpenStreamForReading() +//---------------------------------------------------------------------------------------- +{ + if (mInputStream || mOutputStream) + return NS_ERROR_FAILURE; + return NS_NewTypicalInputFileStream((nsISupports**)&mInputStream, mFileSpec); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::OpenStreamForWriting() +//---------------------------------------------------------------------------------------- +{ + if (mInputStream || mOutputStream) + return NS_ERROR_FAILURE; + return NS_NewTypicalOutputFileStream((nsISupports**)&mOutputStream, mFileSpec); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::OpenStreamForReadingAndWriting() +//---------------------------------------------------------------------------------------- +{ + if (mInputStream || mOutputStream) + return NS_ERROR_FAILURE; + nsresult result = NS_NewTypicalInputFileStream((nsISupports**)&mInputStream, mFileSpec); + if (NS_SUCCEEDED(result)) + result = NS_NewTypicalOutputFileStream((nsISupports**)&mOutputStream, mFileSpec); + return result; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::CloseStream() +//---------------------------------------------------------------------------------------- +{ + NS_IF_RELEASE(mInputStream); + NS_IF_RELEASE(mOutputStream); + return NS_OK; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::IsStreamOpen(PRBool *_retval) +//---------------------------------------------------------------------------------------- +{ + TEST_OUT_PTR(_retval) + *_retval = (mInputStream || mOutputStream); + return NS_OK; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::GetInputStream(nsIInputStream** _retval) +//---------------------------------------------------------------------------------------- +{ + TEST_OUT_PTR(_retval) + if (!mInputStream) { + nsresult rv = OpenStreamForReading(); + if (NS_FAILED(rv)) return rv; + } + *_retval = mInputStream; + NS_IF_ADDREF(mInputStream); + return NS_OK; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::GetOutputStream(nsIOutputStream** _retval) +//---------------------------------------------------------------------------------------- +{ + TEST_OUT_PTR(_retval) + if (!mOutputStream) { + nsresult rv = OpenStreamForWriting(); + if (NS_FAILED(rv)) return rv; + } + *_retval = mOutputStream; + NS_IF_ADDREF(mOutputStream); + return NS_OK; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::SetFileContents(const char* inString) +//---------------------------------------------------------------------------------------- +{ + nsresult rv = OpenStreamForWriting(); + if (NS_FAILED(rv)) return rv; + PRInt32 count; + rv = Write(inString, PL_strlen(inString), &count); + nsresult rv2 = CloseStream(); + return NS_FAILED(rv) ? rv : rv2; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::GetFileContents(char** _retval) +//---------------------------------------------------------------------------------------- +{ + TEST_OUT_PTR(_retval) + *_retval = nsnull; + nsresult rv = OpenStreamForReading(); + if (NS_FAILED(rv)) return rv; + PRInt32 theSize; + rv = GetFileSize((PRUint32*)&theSize); + if (NS_SUCCEEDED(rv)) + rv = Read(_retval, theSize, &theSize); + if (NS_SUCCEEDED(rv)) + (*_retval)[theSize] = 0; + nsresult rv2 = CloseStream(); + return NS_FAILED(rv) ? rv : rv2; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::GetFileSpec(nsFileSpec *aFileSpec) +//---------------------------------------------------------------------------------------- +{ + TEST_OUT_PTR(aFileSpec) + *aFileSpec = mFileSpec; + return NS_OK; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::Equals(nsIFileSpec *spec, PRBool *result) +//---------------------------------------------------------------------------------------- +{ + nsresult rv; + + if (!result || !spec) return NS_ERROR_NULL_POINTER; + + nsFileSpec otherSpec; + + rv = spec->GetFileSpec(&otherSpec); + if (NS_FAILED(rv)) return rv; + + if (mFileSpec == otherSpec) { + *result = PR_TRUE; + } + else { + *result = PR_FALSE; + } + + return NS_OK; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::SetFromFileSpec(const nsFileSpec& aFileSpec) +//---------------------------------------------------------------------------------------- +{ + mFileSpec = aFileSpec; + return NS_OK; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::Eof(PRBool *_retval) +//---------------------------------------------------------------------------------------- +{ + TEST_OUT_PTR(_retval) + if (!mInputStream) + return NS_ERROR_NULL_POINTER; + nsInputFileStream s(mInputStream); + *_retval = s.eof(); + return NS_OK; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::Read(char** buffer, PRInt32 requestedCount, PRInt32 *_retval) +//---------------------------------------------------------------------------------------- +{ + TEST_OUT_PTR(_retval) + TEST_OUT_PTR(buffer) + if (!mInputStream) { + nsresult rv = OpenStreamForReading(); + if (NS_FAILED(rv)) return rv; + } + if (!*buffer) + *buffer = (char*)PR_Malloc(requestedCount + 1); + if (!mInputStream) + return NS_ERROR_NULL_POINTER; + nsInputFileStream s(mInputStream); + *_retval = s.read(*buffer, requestedCount); + return s.error(); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::ReadLine(char** line, PRInt32 bufferSize, PRBool *wasTruncated) +//---------------------------------------------------------------------------------------- +{ + TEST_OUT_PTR(wasTruncated) + TEST_OUT_PTR(line) + if (!mInputStream) { + nsresult rv = OpenStreamForReading(); + if (NS_FAILED(rv)) return rv; + } + if (!*line) + *line = (char*)PR_Malloc(bufferSize + 1); + if (!mInputStream) + return NS_ERROR_NULL_POINTER; + nsInputFileStream s(mInputStream); + *wasTruncated = !s.readline(*line, bufferSize); + return s.error(); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::Write(const char * data, PRInt32 requestedCount, PRInt32 *_retval) +//---------------------------------------------------------------------------------------- +{ + TEST_OUT_PTR(_retval) + //if (!mOutputStream) + // return NS_ERROR_NULL_POINTER; + if (!mOutputStream) { + nsresult rv = OpenStreamForWriting(); + if (NS_FAILED(rv)) + return rv; + } + nsOutputFileStream s(mOutputStream); + *_retval = s.write(data, requestedCount); + return s.error(); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::Flush() +//---------------------------------------------------------------------------------------- +{ + if (!mOutputStream) + return NS_ERROR_NULL_POINTER; + nsOutputFileStream s(mOutputStream); + s.flush(); + return s.error(); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::Seek(PRInt32 offset) +//---------------------------------------------------------------------------------------- +{ + nsresult result = NS_OK; + if (mOutputStream) + { + nsOutputFileStream os(mOutputStream); + os.seek(offset); + result = os.error(); + } + if (NS_SUCCEEDED(result) && mInputStream) + { + nsInputFileStream is(mInputStream); + is.seek(offset); + result = is.error(); + } + return result; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::Tell(PRInt32 *_retval) +//---------------------------------------------------------------------------------------- +{ + TEST_OUT_PTR(_retval) + if (!mInputStream) + return NS_ERROR_NULL_POINTER; + nsInputFileStream s(mInputStream); + *_retval = s.tell(); + return s.error(); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::EndLine() +//---------------------------------------------------------------------------------------- +{ + nsOutputFileStream s(mOutputStream); + s << nsEndl; + return s.error(); +} + +NS_IMPL_ISUPPORTS1(nsDirectoryIteratorImpl, nsIDirectoryIterator) + +//---------------------------------------------------------------------------------------- +nsDirectoryIteratorImpl::nsDirectoryIteratorImpl() +//---------------------------------------------------------------------------------------- + : mDirectoryIterator(nsnull) +{ +} + +//---------------------------------------------------------------------------------------- +nsDirectoryIteratorImpl::~nsDirectoryIteratorImpl() +//---------------------------------------------------------------------------------------- +{ + delete mDirectoryIterator; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsDirectoryIteratorImpl::Init(nsIFileSpec *parent, PRBool resolveSymlink) +//---------------------------------------------------------------------------------------- +{ + delete mDirectoryIterator; + mDirectoryIterator = new nsDirectoryIterator(FILESPEC(parent), resolveSymlink); + if (!mDirectoryIterator) + return NS_ERROR_OUT_OF_MEMORY; + return NS_OK; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsDirectoryIteratorImpl::Exists(PRBool *_retval) +//---------------------------------------------------------------------------------------- +{ + TEST_OUT_PTR(_retval) + if (!mDirectoryIterator) + return NS_ERROR_NULL_POINTER; + *_retval = mDirectoryIterator->Exists(); + return NS_OK; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsDirectoryIteratorImpl::Next() +//---------------------------------------------------------------------------------------- +{ + if (!mDirectoryIterator) + return NS_ERROR_NULL_POINTER; + (*mDirectoryIterator)++; + return NS_OK; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsDirectoryIteratorImpl::GetCurrentSpec(nsIFileSpec * *aCurrentSpec) +//---------------------------------------------------------------------------------------- +{ + if (!mDirectoryIterator) + return NS_ERROR_NULL_POINTER; + return nsFileSpecImpl::MakeInterface(mDirectoryIterator->Spec(), aCurrentSpec); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsDirectoryIteratorImpl::Create(nsISupports* outer, const nsIID& aIID, void* *aIFileSpec) +//---------------------------------------------------------------------------------------- +{ + if (aIFileSpec == NULL) + return NS_ERROR_NULL_POINTER; + + nsDirectoryIteratorImpl* it = new nsDirectoryIteratorImpl; + if (!it) + return NS_ERROR_OUT_OF_MEMORY; + + nsresult rv = it->QueryInterface(aIID, aIFileSpec); + if (NS_FAILED(rv)) + { + delete it; + return rv; + } + return rv; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::Create(nsISupports* outer, const nsIID& aIID, void* *aIFileSpec) +//---------------------------------------------------------------------------------------- +{ + if (aIFileSpec == NULL) + return NS_ERROR_NULL_POINTER; + + nsFileSpecImpl* it = new nsFileSpecImpl; + if (!it) + return NS_ERROR_OUT_OF_MEMORY; + + nsresult rv = it->QueryInterface(aIID, aIFileSpec); + if (NS_FAILED(rv)) + { + delete it; + return rv; + } + return rv; +} + +//---------------------------------------------------------------------------------------- +nsresult NS_NewFileSpecWithSpec(const nsFileSpec& aSrcFileSpec, nsIFileSpec **result) +//---------------------------------------------------------------------------------------- +{ + if (!result) + return NS_ERROR_NULL_POINTER; + + return nsFileSpecImpl::MakeInterface(aSrcFileSpec, result); +} + +//---------------------------------------------------------------------------------------- +nsresult NS_NewFileSpec(nsIFileSpec** result) +//---------------------------------------------------------------------------------------- +{ + return nsFileSpecImpl::Create(nsnull, NS_GET_IID(nsIFileSpec), (void**)result); +} + +//---------------------------------------------------------------------------------------- +nsresult NS_NewFileSpecFromIFile(nsIFile *aFile, nsIFileSpec **result) +//---------------------------------------------------------------------------------------- +{ + nsresult rv = nsFileSpecImpl::Create(nsnull, NS_GET_IID(nsIFileSpec), (void**)result); + if (NS_FAILED(rv)) return rv; + + nsCAutoString path; + rv = aFile->GetNativePath(path); + if (NS_FAILED(rv)) return rv; + + rv = (*result)->SetNativePath(path.get()); + if (NS_FAILED(rv)) + NS_RELEASE(*result); + return rv; +} + +//---------------------------------------------------------------------------------------- +nsresult NS_NewDirectoryIterator(nsIDirectoryIterator** result) +//---------------------------------------------------------------------------------------- +{ + return nsDirectoryIteratorImpl::Create(nsnull, NS_GET_IID(nsIDirectoryIterator), (void**)result); +} diff --git a/src/libs/xpcom18a4/xpcom/obsolete/component/nsFileSpecImpl.h b/src/libs/xpcom18a4/xpcom/obsolete/component/nsFileSpecImpl.h new file mode 100644 index 00000000..502e254f --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/obsolete/component/nsFileSpecImpl.h @@ -0,0 +1,116 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +#ifndef _FILESPECIMPL_H_ +#define _FILESPECIMPL_H_ + +#include "nscore.h" +#include "nsIFileSpec.h" +#include "nsFileSpec.h" + +//======================================================================================== +class nsFileSpecImpl +//======================================================================================== + : public nsIFileSpec +{ + + public: + + NS_DECL_ISUPPORTS + + NS_DECL_NSIFILESPEC + + //---------------------- + // COM Cruft + //---------------------- + + static NS_METHOD Create(nsISupports* outer, const nsIID& aIID, void* *aIFileSpec); + + //---------------------- + // Implementation + //---------------------- + + nsFileSpecImpl(); + nsFileSpecImpl(const nsFileSpec& inSpec); + static nsresult MakeInterface(const nsFileSpec& inSpec, nsIFileSpec** outSpec); + + //---------------------- + // Data + //---------------------- + + nsFileSpec mFileSpec; + nsIInputStream* mInputStream; + nsIOutputStream* mOutputStream; + +private: + ~nsFileSpecImpl(); +}; // class nsFileSpecImpl + +//======================================================================================== +class nsDirectoryIteratorImpl +//======================================================================================== + : public nsIDirectoryIterator +{ + +public: + + nsDirectoryIteratorImpl(); + + NS_DECL_ISUPPORTS + + NS_IMETHOD Init(nsIFileSpec *parent, PRBool resolveSymlink); + + NS_IMETHOD Exists(PRBool *_retval); + + NS_IMETHOD Next(); + + NS_IMETHOD GetCurrentSpec(nsIFileSpec * *aCurrentSpec); + + //---------------------- + // COM Cruft + //---------------------- + + static NS_METHOD Create(nsISupports* outer, const nsIID& aIID, void* *aIFileSpec); + +private: + ~nsDirectoryIteratorImpl(); + +protected: + nsDirectoryIterator* mDirectoryIterator; +}; // class nsDirectoryIteratorImpl + +#endif // _FILESPECIMPL_H_ diff --git a/src/libs/xpcom18a4/xpcom/obsolete/component/nsIRegistry.idl b/src/libs/xpcom18a4/xpcom/obsolete/component/nsIRegistry.idl new file mode 100644 index 00000000..bc9990e2 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/obsolete/component/nsIRegistry.idl @@ -0,0 +1,186 @@ +/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org Code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsISupports.idl" +#include "nsIEnumerator.idl" + +interface nsIFile; + +typedef PRUint32 nsRegistryKey; +typedef long nsWellKnownRegistry; + +[scriptable,uuid(5D41A440-8E37-11d2-8059-00600811A9C3)] +interface nsIRegistry : nsISupports +{ + const long None = 0; + const long Users = 1; + const long Common = 2; + const long CurrentUser = 3; + + const long ApplicationComponentRegistry = 1; + const long ApplicationRegistry = 2; + + // Dont use this one. This for internal use only. + const long ApplicationCustomRegistry = -1; + + void open(in nsIFile regFile); + void openWellKnownRegistry(in nsWellKnownRegistry regid); + + void flush(); + boolean isOpen(); + + nsRegistryKey addKey(in nsRegistryKey baseKey, in wstring keyname); + nsRegistryKey getKey(in nsRegistryKey baseKey, in wstring keyname); + void removeKey(in nsRegistryKey baseKey, in wstring keyname); + + wstring getString(in nsRegistryKey baseKey, in wstring valname); + void setString(in nsRegistryKey baseKey, in wstring valname, in wstring value); + + string getStringUTF8(in nsRegistryKey baseKey, in string path); + void setStringUTF8(in nsRegistryKey baseKey, in string path, in string value); + + void getBytesUTF8(in nsRegistryKey baseKey, in string path, out PRUint32 length, [retval, array, size_is(length)] out PRUint8 valueArray); + void setBytesUTF8(in nsRegistryKey baseKey, in string path, in PRUint32 length, [array, size_is(length)] in PRUint8 valueArray); + PRInt32 getInt(in nsRegistryKey baseKey, in string path); + void setInt(in nsRegistryKey baseKey, in string path, in PRInt32 value); + PRInt64 getLongLong(in nsRegistryKey baseKey, in string path); + void setLongLong(in nsRegistryKey baseKey, in string path, inout PRInt64 value); + + /** + * addSubtree() and friends need to be renamed to addKeyUTF8(). + * If you are using these forms make sure you pass UTF8 data + */ + nsRegistryKey addSubtree(in nsRegistryKey baseKey, in string path); + void removeSubtree(in nsRegistryKey baseKey, in string path); + nsRegistryKey getSubtree(in nsRegistryKey baseKey, in string path); + + nsRegistryKey addSubtreeRaw(in nsRegistryKey baseKey, in string path); + void removeSubtreeRaw(in nsRegistryKey baseKey, in string path); + nsRegistryKey getSubtreeRaw(in nsRegistryKey baseKey, in string path); + + nsIEnumerator enumerateSubtrees(in nsRegistryKey baseKey); + nsIEnumerator enumerateAllSubtrees(in nsRegistryKey baseKey); + nsIEnumerator enumerateValues(in nsRegistryKey baseKey); + + const unsigned long String = 1; + const unsigned long Int32 = 2; + const unsigned long Bytes = 3; + const unsigned long File = 4; + + unsigned long getValueType(in nsRegistryKey baseKey, in string path); + PRUint32 getValueLength(in nsRegistryKey baseKey, in string path); + void deleteValue(in nsRegistryKey baseKey, in string path); + + /** + * escapeKey() takes arbitrary binary data and converts it into + * valid ASCII which can be used as registry key or value names + */ + void escapeKey([array, size_is(length)] in PRUint8 key, in PRUint32 terminator, inout PRUint32 length, [retval, array, size_is(length)] out PRUint8 escaped); + void unescapeKey([array, size_is(length)] in PRUint8 escaped, in PRUint32 terminator, inout PRUint32 length, [retval, array, size_is(length)] out PRUint8 key); + + attribute string currentUserName; + + void pack(); +}; + +[scriptable, uuid(8cecf236-1dd2-11b2-893c-f9848956eaec)] +interface nsIRegistryEnumerator : nsIEnumerator +{ + void currentItemInPlaceUTF8(out nsRegistryKey key, + [shared, retval] out string item); +}; + +[scriptable, uuid(D1B54831-AC07-11d2-805E-00600811A9C3)] +interface nsIRegistryNode : nsISupports +{ + readonly attribute string nameUTF8; + readonly attribute wstring name; + readonly attribute nsRegistryKey key; +}; + +[scriptable,uuid(5316C380-B2F8-11d2-A374-0080C6F80E4B)] +interface nsIRegistryValue : nsISupports +{ + readonly attribute wstring name; + readonly attribute string nameUTF8; + readonly attribute unsigned long type; + readonly attribute PRUint32 length; +}; + +[uuid(3A15FC88-7A61-4Ab4-8E58-31E95fAB3DA8)] +/** + * It sucks that nsIRegistry has to always allocate and return + * strings. nsIRegistryGetter adds in interfaces for non allocating getters + * to registry values. + */ +interface nsIRegistryGetter : nsISupports +{ + /** + * Get a string value of attribute valname in widestring or utf8 format + * + * @return + * NS_OK on success. + * buf has the string value copied into it. length is NOT changed. + * NS_ERROR_REG_BUFFER_TOO_SMALL if not enough buffer space. + * length is updated to actual length in chars including + * terminating NULL and buf will be unchanged. + * NS_ERROR_FAILURE if an unknown error happened. state of buf and + * length undefined. + * various failure codes otherwise. buf and length wont be updated. + */ + void getStringUTF8IntoBuffer(in nsRegistryKey baseKey, in string path, + inout char buf, inout PRUint32 length); + + /** + * Get a a byte array value of attribute valname + * + * @return + * NS_OK on success. buf has the string value copied into it. + * length is updated to actual number of bytes copied into buf. + * NS_ERROR_REG_BUFFER_TOO_SMALL if not enough buffer space. + * length is updated to actual length in PRUint8s including + * terminating NULL and buf will be unchanged. + * NS_ERROR_FAILURE if an unknown error happened. state of buf and + * length undefined. + * various other failure codes otherwise. buf and length wont be updated. + */ + void getBytesUTF8IntoBuffer(in nsRegistryKey baseKey, in string path, + inout PRUint8 buf, inout PRUint32 length); +}; + +%{ C++ +#include "nsIRegistryUtils.h" +%} diff --git a/src/libs/xpcom18a4/xpcom/obsolete/component/nsIRegistryUtils.h b/src/libs/xpcom18a4/xpcom/obsolete/component/nsIRegistryUtils.h new file mode 100644 index 00000000..a3d74d7a --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/obsolete/component/nsIRegistryUtils.h @@ -0,0 +1,63 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ +#ifndef __nsIRegistryUtils_h +#define __nsIRegistryUtils_h + +#define NS_REGISTRY_CONTRACTID "@mozilla.org/registry;1" +#define NS_REGISTRY_CLASSNAME "Mozilla Registry" +/* be761f00-a3b0-11d2-996c-0080c7cb1081 */ +#define NS_REGISTRY_CID \ +{ \ + 0xbe761f00, \ + 0xa3b0, \ + 0x11d2, \ + {0x99, 0x6c, 0x00, 0x80, 0xc7, 0xcb, 0x10, 0x81} \ +} + +/*------------------------------- Error Codes ---------------------------------- +------------------------------------------------------------------------------*/ +#define NS_ERROR_REG_BADTYPE NS_ERROR_GENERATE_FAILURE( NS_ERROR_MODULE_REG, 1 ) +#define NS_ERROR_REG_NO_MORE NS_ERROR_GENERATE_SUCCESS( NS_ERROR_MODULE_REG, 2 ) +#define NS_ERROR_REG_NOT_FOUND NS_ERROR_GENERATE_FAILURE( NS_ERROR_MODULE_REG, 3 ) +#define NS_ERROR_REG_NOFILE NS_ERROR_GENERATE_FAILURE( NS_ERROR_MODULE_REG, 4 ) +#define NS_ERROR_REG_BUFFER_TOO_SMALL NS_ERROR_GENERATE_FAILURE( NS_ERROR_MODULE_REG, 5 ) +#define NS_ERROR_REG_NAME_TOO_LONG NS_ERROR_GENERATE_FAILURE( NS_ERROR_MODULE_REG, 6 ) +#define NS_ERROR_REG_NO_PATH NS_ERROR_GENERATE_FAILURE( NS_ERROR_MODULE_REG, 7 ) +#define NS_ERROR_REG_READ_ONLY NS_ERROR_GENERATE_FAILURE( NS_ERROR_MODULE_REG, 8 ) +#define NS_ERROR_REG_BAD_UTF8 NS_ERROR_GENERATE_FAILURE( NS_ERROR_MODULE_REG, 9 ) + +#endif diff --git a/src/libs/xpcom18a4/xpcom/obsolete/component/nsRegistry.cpp b/src/libs/xpcom18a4/xpcom/obsolete/component/nsRegistry.cpp new file mode 100644 index 00000000..d3ecfe62 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/obsolete/component/nsRegistry.cpp @@ -0,0 +1,2019 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +#ifdef MOZ_LOGGING +#define FORCE_PR_LOG /* Allow logging in the release build */ +#endif + +#include "nsIGenericFactory.h" + +#include "nsRegistry.h" +#include "nsIEnumerator.h" +#include "nsDirectoryService.h" +#include "nsDirectoryServiceDefs.h" +#include "nsAppDirectoryServiceDefs.h" +#include "NSReg.h" +#include "prmem.h" +#include "prlock.h" +#include "prlog.h" +#include "prprf.h" +#include "nsCRT.h" +#include "nsMemory.h" + +#include "nsCOMPtr.h" +#include "nsILocalFile.h" +#include "nsIServiceManager.h" +#include "nsTextFormatter.h" + +#ifdef XP_BEOS +#include +#include +#endif + +/* extra locking for the paranoid */ +/* #define EXTRA_THREADSAFE */ +#ifndef EXTRA_THREADSAFE +#define PR_Lock(x) (void)0 +#define PR_Unlock(x) (void)0 +#endif + +// Logging of debug output +extern PRLogModuleInfo *nsComponentManagerLog; + +PRUnichar widestrFormat[] = { PRUnichar('%'),PRUnichar('s'),PRUnichar(0)}; + +/*-------------------------------- nsRegistry ---------------------------------- +| This class implements the nsIRegistry interface using the functions | +| provided by libreg (as declared in mozilla/modules/libreg/include/NSReg.h). | +| | +| Since that interface is designed to match the libreg function, this class | +| is implemented with each member function being a simple wrapper for the | +| corresponding libreg function. | +| | +| #define EXTRA_THREADSAFE if you are worried about libreg thread safety. | +| It should not be necessary, but I'll leave in the code for the paranoid. | +------------------------------------------------------------------------------*/ + +#define NS_MOZILLA_DIR_PERMISSION 00700 + +#include "nsRegistry.h" +/* +struct nsRegistry : public nsIRegistry { + // This class implements the nsISupports interface functions. + NS_DECL_ISUPPORTS + + // This class implements the nsIRegistry interface functions. + NS_DECL_NSIREGISTRY + + // ctor/dtor + nsRegistry(); + +private: + ~nsRegistry(); + +protected: + HREG mReg; // Registry handle. +#ifdef EXTRA_THREADSAFE + PRLock *mregLock; // libreg isn't threadsafe. Use locks to synchronize. +#endif + char *mCurRegFile; // these are to prevent open from opening the registry again + nsWellKnownRegistry mCurRegID; + + NS_IMETHOD Close(); +}; // nsRegistry +*/ + +#include "nsIFactory.h" +/*----------------------------- nsRegistryFactory ------------------------------ +| Class factory for nsRegistry objects. | +------------------------------------------------------------------------------*/ +struct nsRegistryFactory : public nsIFactory { + // This class implements the nsISupports interface functions. + NS_DECL_ISUPPORTS + + // nsIFactory methods + NS_IMETHOD CreateInstance(nsISupports *,const nsIID &,void **); + NS_IMETHOD LockFactory(PRBool aLock); + + // ctor + nsRegistryFactory(); +}; + + +/*--------------------------- nsRegSubtreeEnumerator --------------------------- +| This class implements the nsIEnumerator interface and is used to implement | +| the nsRegistry EnumerateSubtrees and EnumerateAllSubtrees functions. | +------------------------------------------------------------------------------*/ +struct nsRegSubtreeEnumerator : public nsIRegistryEnumerator { + // This class implements the nsISupports interface functions. + NS_DECL_ISUPPORTS + + // This class implements the nsIEnumerator interface functions. + NS_DECL_NSIENUMERATOR + + // And our magic behind-the-back fast-path thing. + NS_DECL_NSIREGISTRYENUMERATOR + + // ctor/dtor + nsRegSubtreeEnumerator( HREG hReg, RKEY rKey, PRBool all ); + // virtual dtor since subclasses call our Release() + virtual ~nsRegSubtreeEnumerator(); + +protected: + NS_IMETHOD advance(); // Implementation file; does appropriate NR_RegEnum call. + HREG mReg; // Handle to registry we're affiliated with. + RKEY mKey; // Base key being enumerated. + char mName[MAXREGPATHLEN]; // The name of the current key which is in mNext + REGENUM mEnum; // Corresponding libreg "enumerator". + REGENUM mNext; // Lookahead value. + PRUint32 mStyle; // Style (indicates all or some); + PRBool mDone; // Done flag. +#ifdef EXTRA_THREADSAFE + PRLock *mregLock; +#endif +}; // nsRegSubtreeEnumerator + + +/*--------------------------- nsRegValueEnumerator ----------------------------- +| This class is a variation on nsRegSubtreeEnumerator that allocates | +| nsRegistryValue objects rather than nsRegistryNode objects. It also | +| overrides certain functions to make sure the "value" oriented libreg | +| functions used rather than the subtree oriented ones. | +------------------------------------------------------------------------------*/ +struct nsRegValueEnumerator : public nsRegSubtreeEnumerator { + // Override CurrentItem to allocate nsRegistryValue objects. + NS_IMETHOD CurrentItem( nsISupports **result ); + + // Override advance() to use proper NR_RegEnumEntries. + NS_IMETHOD advance(); + + // ctor/dtor + nsRegValueEnumerator( HREG hReg, RKEY rKey ); +}; // nsRegValueEnumerator + +/*------------------------------ nsRegistryNode -------------------------------- +| This class implements the nsIRegistryNode interface. Instances are | +| allocated by nsRegSubtreeEnumerator::CurrentItem. | +------------------------------------------------------------------------------*/ +struct nsRegistryNode : public nsIRegistryNode { + // This class implements the nsISupports interface functions. + NS_DECL_ISUPPORTS + + // This class implements the nsIRegistryNode interface functions. + NS_DECL_NSIREGISTRYNODE + + // ctor + nsRegistryNode( HREG hReg, char *name, RKEY childKey ); + +private: + ~nsRegistryNode(); + +protected: + HREG mReg; // Handle to registry this node is part of. + char mName[MAXREGPATHLEN]; // Buffer to hold name. + RKEY mChildKey; // Key corresponding to mName +#ifdef EXTRA_THREADSAFE + PRLock *mregLock; +#endif +}; // nsRegistryNode + + +/*------------------------------ nsRegistryValue ------------------------------- +| This class implements the nsIRegistryValue interface. Instances are | +| allocated by nsRegValueEnumerator::CurrentItem. | +------------------------------------------------------------------------------*/ +struct nsRegistryValue : public nsIRegistryValue { + // This class implements the nsISupports interface functions. + NS_DECL_ISUPPORTS + + // This class implements the nsIRegistryValue interface functions. + NS_DECL_NSIREGISTRYVALUE + + // ctor + nsRegistryValue( HREG hReg, RKEY key, REGENUM slot ); + +private: + ~nsRegistryValue(); + +protected: + nsresult getInfo(); // Get registry info. + HREG mReg; // Handle to registry this node is part of. + RKEY mKey; // Key this node is under. + REGENUM mEnum; // Copy of corresponding content of parent enumerator. + REGINFO mInfo; // Value info. + char mName[MAXREGNAMELEN]; // Buffer to hold name. + REGERR mErr; // XXX This causes this class to be NON THREAD SAFE +#ifdef EXTRA_THREADSAFE + PRLock *mregLock; +#endif +}; // nsRegistryValue + + +/*----------------------------- regerr2nsresult -------------------------------- +| This utility function maps a REGERR value to a corresponding nsresult | +| error code. | +------------------------------------------------------------------------------*/ +static nsresult regerr2nsresult( REGERR err ) { + nsresult rv = NS_ERROR_UNEXPECTED; + switch( err ) { + case REGERR_OK: + rv = NS_OK; + break; + + case REGERR_FAIL: + rv = NS_ERROR_FAILURE; + break; + + case REGERR_NOMORE: + rv = NS_ERROR_REG_NO_MORE; + break; + + case REGERR_NOFIND: + rv = NS_ERROR_REG_NOT_FOUND; + break; + + case REGERR_PARAM: + case REGERR_BADTYPE: + case REGERR_BADNAME: + rv = NS_ERROR_INVALID_ARG; + break; + + case REGERR_NOFILE: + rv = NS_ERROR_REG_NOFILE; + break; + + case REGERR_MEMORY: + rv = NS_ERROR_OUT_OF_MEMORY; + break; + + case REGERR_BUFTOOSMALL: + rv = NS_ERROR_REG_BUFFER_TOO_SMALL; + break; + + case REGERR_NAMETOOLONG: + rv = NS_ERROR_REG_NAME_TOO_LONG; + break; + + case REGERR_NOPATH: + rv = NS_ERROR_REG_NO_PATH; + break; + + case REGERR_READONLY: + rv = NS_ERROR_REG_READ_ONLY; + break; + + case REGERR_BADUTF8: + rv = NS_ERROR_REG_BAD_UTF8; + break; + + } + return rv; +} + +/*----------------------------- reginfo2DataType ------------------------------- +| This utility function converts the type field in the REGINFO structure to | +| the corresponding nsIRegistry::DataType value. | +------------------------------------------------------------------------------*/ +static void reginfo2DataType( const REGINFO &in, PRUint32 &out ) { + // Transfer information, based on entry type. + switch( in.entryType ) { + case REGTYPE_ENTRY_STRING_UTF: + out = nsIRegistry::String; + //out.length = in.entryLength; + break; + + case REGTYPE_ENTRY_INT32_ARRAY: + out = nsIRegistry::Int32; + // Convert length in bytes to array dimension. + //out.length = in.entryLength / sizeof(PRInt32); + break; + + case REGTYPE_ENTRY_BYTES: + out = nsIRegistry::Bytes; + //out.length = in.entryLength; + break; + + case REGTYPE_ENTRY_FILE: + out = nsIRegistry::File; + //out.length = in.entryLength; + break; + } +} + +/*----------------------------- reginfo2DataType ------------------------------- +| This utility function converts the length field in the REGINFO structure to | +| the proper units (if type==Int32 array, we divide by sizeof(PRInt32)). | +------------------------------------------------------------------------------*/ +static void reginfo2Length( const REGINFO &in, PRUint32 &out ) { + // Transfer information, based on entry type. + switch( in.entryType ) { + case REGTYPE_ENTRY_STRING_UTF: + out = in.entryLength; + break; + + case REGTYPE_ENTRY_INT32_ARRAY: + // Convert length in bytes to array dimension. + out = in.entryLength / sizeof(PRInt32); + break; + + case REGTYPE_ENTRY_BYTES: + out = in.entryLength; + break; + + case REGTYPE_ENTRY_FILE: + out = in.entryLength; + break; + } +} + +/*------------------------ nsISupports Implementation -------------------------- +| This code generates the implementation of the nsISupports member functions | +| for each class implemented in this file. | +------------------------------------------------------------------------------*/ +NS_IMPL_THREADSAFE_ISUPPORTS2(nsRegistry, nsIRegistry, nsIRegistryGetter) +NS_IMPL_ISUPPORTS2( nsRegSubtreeEnumerator, nsIEnumerator, + nsIRegistryEnumerator) +NS_IMPL_ISUPPORTS1( nsRegistryNode, nsIRegistryNode ) +NS_IMPL_ISUPPORTS1( nsRegistryValue, nsIRegistryValue ) + +/*-------------------------- nsRegistry::nsRegistry ---------------------------- +| Vanilla nsRegistry constructor. | +------------------------------------------------------------------------------*/ +nsRegistry::nsRegistry() + : mReg(0), mCurRegID(0) { +#ifdef EXTRA_THREADSAFE + mregLock = PR_NewLock(); +#endif + NR_StartupRegistry(); + return; +} + +/*------------------------- nsRegistry::~nsRegistry ---------------------------- +| The dtor closes the registry file(if open). | +------------------------------------------------------------------------------*/ +nsRegistry::~nsRegistry() { + if( mReg ) { + Close(); + } +#ifdef EXTRA_THREADSAFE + if (mregLock) { + PR_DestroyLock(mregLock); + } +#endif + NR_ShutdownRegistry(); + return; +} + +/*----------------------------- nsRegistry::Open ------------------------------- +| If the argument is null, delegate to OpenDefault, else open the registry | +| file. We first check to see if a registry file is already open and close | +| it if so. | +------------------------------------------------------------------------------*/ +NS_IMETHODIMP nsRegistry::Open( nsIFile *regFile ) { + REGERR err = REGERR_OK; + + // Check for default. + if( !regFile ) { + return OpenWellKnownRegistry(nsIRegistry::ApplicationRegistry); + } + + nsCAutoString regPath; + nsresult rv = regFile->GetNativePath(regPath); + if (NS_FAILED(rv)) return rv; + +#ifdef DEBUG_dp + printf("nsRegistry: Opening registry %s\n", regPath.get()); +#endif /* DEBUG_dp */ + + if (mCurRegID != nsIRegistry::None && mCurRegID != nsIRegistry::ApplicationCustomRegistry) + { + // Cant open another registry without closing explictly. + return NS_ERROR_INVALID_ARG; + } + + // Do we have an open registry ? + if (mCurRegID != nsIRegistry::None) + { + PRBool equals; + if (mCurRegFile && NS_SUCCEEDED(mCurRegFile->Equals(regFile, &equals)) && equals) + { + // The right one is already open + return NS_OK; + } + else + { + // Opening a new registry without closing an already open one. + // This is an error. + return NS_ERROR_FAILURE; + } + } + + // Open specified registry. + PR_Lock(mregLock); + err = NR_RegOpen(NS_CONST_CAST(char*,regPath.get()), &mReg); + PR_Unlock(mregLock); + + mCurRegID = nsIRegistry::ApplicationCustomRegistry; + + // No error checking for no mem. Trust me. + if (NS_FAILED(regFile->Clone(getter_AddRefs(mCurRegFile)))) + mCurRegFile = nsnull; // not fatal + + // Convert the result. + return regerr2nsresult( err ); +} + +static void +EnsureDefaultRegistryDirectory() { +#if defined(XP_UNIX) && !defined(XP_MACOSX) + // Create ~/.mozilla as that is the default place for the registry file + + /* The default registry on the unix system is $HOME/.mozilla/registry per + * vr_findGlobalRegName(). vr_findRegFile() will create the registry file + * if it doesn't exist. But it wont create directories. + * + * Hence we need to create the directory if it doesn't exist already. + * + * Why create it here as opposed to the app ? + * ------------------------------------------ + * The app cannot create the directory in main() as most of the registry + * and initialization happens due to use of static variables. + * And we dont want to be dependent on the order in which + * these static stuff happen. + * + * Permission for the $HOME/.mozilla will be Read,Write,Execute + * for user only. Nothing to group and others. + */ + char *home = getenv("HOME"); + if (home != NULL) + { + char dotMozillaDir[1024]; + PR_snprintf(dotMozillaDir, sizeof(dotMozillaDir), + "%s/" MOZ_USER_DIR, home); + if (PR_Access(dotMozillaDir, PR_ACCESS_EXISTS) != PR_SUCCESS) + { + PR_MkDir(dotMozillaDir, NS_MOZILLA_DIR_PERMISSION); + PR_LOG(nsComponentManagerLog, PR_LOG_ALWAYS, + ("nsComponentManager: Creating Directory %s", dotMozillaDir)); + } + } +#endif /* XP_UNIX */ + +#ifdef XP_BEOS + BPath p; + const char *settings = "/boot/home/config/settings"; + if(find_directory(B_USER_SETTINGS_DIRECTORY, &p) == B_OK) + settings = p.Path(); + char settingsMozillaDir[1024]; + PR_snprintf(settingsMozillaDir, sizeof(settingsMozillaDir), + "%s/" MOZ_USER_DIR, settings); + if (PR_Access(settingsMozillaDir, PR_ACCESS_EXISTS) != PR_SUCCESS) { + PR_MkDir(settingsMozillaDir, NS_MOZILLA_DIR_PERMISSION); + PR_LOG(nsComponentManagerLog, PR_LOG_ALWAYS, + ("nsComponentManager: Creating Directory %s", settingsMozillaDir)); + } +#endif +} + +/*----------------------------- nsRegistry::OpenWellKnownRegistry -------------- +| Takes a registry id and maps that to a file name for opening. We first check | +| to see if a registry file is already open and close it if so. | +------------------------------------------------------------------------------*/ +NS_IMETHODIMP nsRegistry::OpenWellKnownRegistry( nsWellKnownRegistry regid ) +{ + REGERR err = REGERR_OK; + + if (mCurRegID != nsIRegistry::None && mCurRegID != regid) + { + // Cant open another registry without closing explictly. + return NS_ERROR_INVALID_ARG; + } + + if (mCurRegID == regid) + { + // Already opened. + return NS_OK; + } + + nsresult rv; + nsCOMPtr registryLocation; + + PRBool foundReg = PR_FALSE; + nsCAutoString regFile; + + switch ( (nsWellKnownRegistry) regid ) { + case ApplicationComponentRegistry: + NS_WARNING("ApplicationComponentRegistry is unsupported!"); + break; + case ApplicationRegistry: + { + EnsureDefaultRegistryDirectory(); + nsCOMPtr directoryService = do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv); + if (NS_FAILED(rv)) return rv; + directoryService->Get(NS_APP_APPLICATION_REGISTRY_FILE, NS_GET_IID(nsIFile), + getter_AddRefs(registryLocation)); + + if (registryLocation) + { + foundReg = PR_TRUE; + rv = registryLocation->GetNativePath(regFile); // dougt fix... + // dveditz needs to fix his registry so that I can pass an + // nsIFile interface and not hack + if (NS_FAILED(rv)) + return rv; + } + } + break; + + default: + break; + } + + if (foundReg == PR_FALSE) { + return NS_ERROR_REG_BADTYPE; + } + +#ifdef DEBUG_dp + printf("nsRegistry: Opening std registry %s\n", regFile.get()); +#endif /* DEBUG_dp */ + + PR_Lock(mregLock); + err = NR_RegOpen(NS_CONST_CAST(char*, regFile.get()), &mReg ); + PR_Unlock(mregLock); + + // Store the registry that was opened for optimizing future opens. + mCurRegID = regid; + + // Convert the result. + return regerr2nsresult( err ); +} + +#if 0 +/*-------------------------- nsRegistry::OpenDefault --------------------------- +| Open the "default" registry; in the case of this libreg-based implementation | +| that is done by passing a null file name pointer to NR_RegOpen. | +------------------------------------------------------------------------------*/ +NS_IMETHODIMP nsRegistry::OpenDefault() { + return OpenWellKnownRegistry(nsIRegistry::ApplicationRegistry); +} +#endif + +/*----------------------------- nsRegistry::Close ------------------------------ +| Tests the mReg handle and if non-null, closes the registry via NR_RegClose. | +------------------------------------------------------------------------------*/ +NS_IMETHODIMP nsRegistry::Close() { + REGERR err = REGERR_OK; + if( mReg ) { + PR_Lock(mregLock); + err = NR_RegClose( mReg ); + PR_Unlock(mregLock); + mReg = 0; + mCurRegFile = nsnull; + mCurRegID = 0; + } + return regerr2nsresult( err ); +} + +/*----------------------------- nsRegistry::Flush ------------------------------ +| Flushes the registry via NR_RegFlush. | +------------------------------------------------------------------------------*/ +NS_IMETHODIMP nsRegistry::Flush() { + REGERR err = REGERR_FAIL; + if( mReg ) { + PR_Lock(mregLock); + err = NR_RegFlush( mReg ); + PR_Unlock(mregLock); + } + return regerr2nsresult( err ); +} + +/*----------------------------- nsRegistry::IsOpen ----------------------------- +| Tests the mReg handle and returns whether the registry is open or not. | +------------------------------------------------------------------------------*/ +NS_IMETHODIMP nsRegistry::IsOpen( PRBool *result ) { + *result = ( mReg != 0 ); + return NS_OK; +} + + +/*--------------------------- nsRegistry::AddKey ------------------------------- +| Add a key into the registry or find an existing one. This is generally used | +| instead of GetKey unless it's an error for the key not to exist already i +------------------------------------------------------------------------------*/ +NS_IMETHODIMP nsRegistry::AddKey( nsRegistryKey baseKey, const PRUnichar *keyname, nsRegistryKey *_retval) +{ + if ( !keyname ) + return NS_ERROR_NULL_POINTER; + + return AddSubtree( baseKey, NS_ConvertUCS2toUTF8(keyname).get(), _retval ); +} + +/*--------------------------- nsRegistry::GetKey ------------------------------- +| returns the nsRegistryKey associated with a given node in the registry | +------------------------------------------------------------------------------*/ +NS_IMETHODIMP nsRegistry::GetKey(nsRegistryKey baseKey, const PRUnichar *keyname, nsRegistryKey *_retval) +{ + if ( !keyname || !_retval ) + return NS_ERROR_NULL_POINTER; + + return GetSubtree( baseKey, NS_ConvertUCS2toUTF8(keyname).get(), _retval ); +} + +/*--------------------------- nsRegistry::RemoveKey ---------------------------- +| Delete a key from the registry | +------------------------------------------------------------------------------*/ +NS_IMETHODIMP nsRegistry::RemoveKey(nsRegistryKey baseKey, const PRUnichar *keyname) +{ + if ( !keyname ) + return NS_ERROR_NULL_POINTER; + + return RemoveSubtree( baseKey, NS_ConvertUCS2toUTF8(keyname).get() ); +} + +NS_IMETHODIMP nsRegistry::GetString(nsRegistryKey baseKey, const PRUnichar *valname, PRUnichar **_retval) +{ + // Make sure caller gave us place for result. + if ( !valname || !_retval ) + return NS_ERROR_NULL_POINTER; + + // initialize the return value + *_retval = nsnull; + nsXPIDLCString tmpstr; + + nsresult rv = GetStringUTF8( baseKey, NS_ConvertUCS2toUTF8(valname).get(), getter_Copies(tmpstr) ); + + if (NS_SUCCEEDED(rv)) + { + *_retval = nsTextFormatter::smprintf( widestrFormat, tmpstr.get() ); + if ( *_retval == nsnull ) + rv = NS_ERROR_OUT_OF_MEMORY; + } + + return rv; +} + +NS_IMETHODIMP nsRegistry::SetString(nsRegistryKey baseKey, const PRUnichar *valname, const PRUnichar *value) +{ + if ( !valname || ! value ) + return NS_ERROR_NULL_POINTER; + + return SetStringUTF8( baseKey, + NS_ConvertUCS2toUTF8(valname).get(), + NS_ConvertUCS2toUTF8(value).get() ); +} + +/*--------------------------- nsRegistry::GetString ---------------------------- +| First, look for the entry using GetValueInfo. If found, and it's a string, | +| allocate space for it and fetch the value. | +------------------------------------------------------------------------------*/ +NS_IMETHODIMP nsRegistry::GetStringUTF8( nsRegistryKey baseKey, const char *path, char **result ) { + nsresult rv = NS_OK; + REGERR err = REGERR_OK; + + // Make sure caller gave us place for result. + if ( !result ) + return NS_ERROR_NULL_POINTER; + + char regStr[MAXREGPATHLEN]; + + // initialize the return value + *result = 0; + + // Attempt to get string into our fixed buffer + PR_Lock(mregLock); + err = NR_RegGetEntryString( mReg,(RKEY)baseKey,(char*)path, regStr, + sizeof(regStr) ); + PR_Unlock(mregLock); + + if ( err == REGERR_OK ) + { + *result = nsCRT::strdup(regStr); + if (!*result) + rv = NS_ERROR_OUT_OF_MEMORY; + } + else if ( err == REGERR_BUFTOOSMALL ) + { + // find the real size and malloc it + PRUint32 length; + rv = GetValueLength( baseKey, path, &length ); + // See if that worked. + if( rv == NS_OK ) + { + *result =(char*)nsMemory::Alloc( length + 1 ); + if( *result ) + { + // Get string from registry into result buffer. + PR_Lock(mregLock); + err = NR_RegGetEntryString( mReg,(RKEY)baseKey,(char*)path, *result, length+1 ); + PR_Unlock(mregLock); + + // Convert status. + rv = regerr2nsresult( err ); + if ( rv != NS_OK ) + { + // Didn't get result, free buffer + nsCRT::free( *result ); + *result = 0; + } + } + else + { + rv = NS_ERROR_OUT_OF_MEMORY; + } + } + } + else + { + // Convert status. + rv = regerr2nsresult( err ); + NS_ASSERTION(NS_FAILED(rv), "returning success code on failure"); + } + + return rv; +} + +NS_IMETHODIMP +nsRegistry::GetStringUTF8IntoBuffer( nsRegistryKey baseKey, const char *path, + char *buf, PRUint32 *length ) +{ + REGERR err = REGERR_OK; + + // Attempt to get string into our fixed buffer + PR_Lock(mregLock); + err = NR_RegGetEntryString( mReg,(RKEY)baseKey,(char*)path, buf, *length ); + PR_Unlock(mregLock); + + // Convert status. + nsresult rv = regerr2nsresult( err ); + + if (rv == NS_ERROR_REG_BUFFER_TOO_SMALL) { + // fill length with the actual length + nsresult rv1 = GetValueLength( baseKey, path, length ); + if(NS_FAILED(rv1)) + return rv1; + } + + return rv; +} + +/*--------------------------- nsRegistry::SetString ---------------------------- +| Simply sets the registry contents using NR_RegSetEntryString. | +------------------------------------------------------------------------------*/ +NS_IMETHODIMP nsRegistry::SetStringUTF8( nsRegistryKey baseKey, const char *path, const char *value ) { + REGERR err = REGERR_OK; + // Set the contents. + PR_Lock(mregLock); + err = NR_RegSetEntryString( mReg,(RKEY)baseKey,(char*)path,(char*)value ); + PR_Unlock(mregLock); + // Convert result. + return regerr2nsresult( err ); +} + +/*---------------------------- nsRegistry::GetBytesUTF8 ------------------------------ +| This function is just shorthand for fetching a char array. We | +| implement it "manually" using NR_RegGetEntry | +------------------------------------------------------------------------------*/ +NS_IMETHODIMP nsRegistry::GetBytesUTF8( nsRegistryKey baseKey, const char *path, PRUint32* length, PRUint8** result) { + nsresult rv = NS_OK; + REGERR err = REGERR_OK; + + if ( !result ) + return NS_ERROR_NULL_POINTER; + + char regStr[MAXREGPATHLEN]; + + // initialize the return value + *length = 0; + *result = 0; + + // Get info about the requested entry. + PRUint32 type; + rv = GetValueType( baseKey, path, &type ); + // See if that worked. + if( rv == NS_OK ) + { + // Make sure the entry is an PRInt8 array. + if( type == Bytes ) + { + // Attempt to get string into our fixed buffer + PR_Lock(mregLock); + uint32 length2 = sizeof regStr; + err = NR_RegGetEntry( mReg,(RKEY)baseKey,NS_CONST_CAST(char*,path), regStr, &length2); + PR_Unlock(mregLock); + + if ( err == REGERR_OK ) + { + *length = length2; + *result = (PRUint8*)(nsCRT::strdup(regStr)); + if (!*result) + { + rv = NS_ERROR_OUT_OF_MEMORY; + *length = 0; + } + else + { + *length = length2; + } + } + else if ( err == REGERR_BUFTOOSMALL ) + { + // find the real size and malloc it + rv = GetValueLength( baseKey, path, length ); + // See if that worked. + if( rv == NS_OK ) + { + *result = NS_REINTERPRET_CAST(PRUint8*,nsMemory::Alloc( *length )); + if( *result ) + { + // Get bytes from registry into result field. + PR_Lock(mregLock); + length2 = *length; + err = NR_RegGetEntry( mReg,(RKEY)baseKey,NS_CONST_CAST(char*,path), *result, &length2); + *length = length2; + PR_Unlock(mregLock); + // Convert status. + rv = regerr2nsresult( err ); + if ( rv != NS_OK ) + { + // Didn't get result, free buffer + nsCRT::free( NS_REINTERPRET_CAST(char*, *result) ); + *result = 0; + *length = 0; + } + } + else + { + rv = NS_ERROR_OUT_OF_MEMORY; + } + } + } + } + else + { + // They asked for the wrong type of value. + rv = NS_ERROR_REG_BADTYPE; + } + } + return rv; +} + +NS_IMETHODIMP +nsRegistry::GetBytesUTF8IntoBuffer( nsRegistryKey baseKey, const char *path, + PRUint8 *buf, PRUint32* length ) +{ + REGERR err = REGERR_OK; + + // Get info about the requested entry. + PRUint32 type; + nsresult rv = GetValueType( baseKey, path, &type ); + // See if that worked. + if(NS_FAILED(rv)) + return rv; + // Make sure we are dealing with bytes + if (type != Bytes) + return NS_ERROR_REG_BADTYPE; + + // Attempt to get bytes into our fixed buffer + PR_Lock(mregLock); + err = NR_RegGetEntry( mReg,(RKEY)baseKey,NS_CONST_CAST(char*,path), + buf, (uint32 *)length ); + PR_Unlock(mregLock); + + rv = regerr2nsresult(rv); + + if (rv == NS_ERROR_REG_BUFFER_TOO_SMALL) { + // fill length with the actual length + nsresult rv1 = GetValueLength( baseKey, path, length ); + if(NS_FAILED(rv1)) + return rv1; + } + + + return rv; +} + +/*---------------------------- nsRegistry::GetInt ------------------------------ +| This function is just shorthand for fetching a 1-element PRInt32 array. We | +| implement it "manually" using NR_RegGetEntry | +------------------------------------------------------------------------------*/ +NS_IMETHODIMP nsRegistry::GetInt( nsRegistryKey baseKey, const char *path, PRInt32 *result ) { + nsresult rv = NS_OK; + REGERR err = REGERR_OK; + + // Make sure caller gave us place for result. + if( result ) { + // Get info about the requested entry. + PRUint32 type; + rv = GetValueType( baseKey, path, &type ); + // See if that worked. + if( rv == NS_OK ) { + // Make sure the entry is an PRInt32 array. + if( type == Int32 ) { + uint32 len = sizeof *result; + // Get int from registry into result field. + PR_Lock(mregLock); + err = NR_RegGetEntry( mReg,(RKEY)baseKey,(char*)path, result, &len ); + PR_Unlock(mregLock); + // Convert status. + rv = regerr2nsresult( err ); + } else { + // They asked for the wrong type of value. + rv = NS_ERROR_REG_BADTYPE; + } + } + } else { + rv = NS_ERROR_NULL_POINTER; + } + return rv; +} + + +/*---------------------------- nsRegistry::GetLongLong-------------------------- +| This function is just shorthand for fetching a 1-element PRInt64 array. We | +| implement it "manually" using NR_RegGetEntry | +------------------------------------------------------------------------------*/ +NS_IMETHODIMP nsRegistry::GetLongLong( nsRegistryKey baseKey, const char *path, PRInt64 *result ) { + REGERR err = REGERR_OK; + + PR_Lock(mregLock); + + uint32 length = sizeof(PRInt64); + err = NR_RegGetEntry( mReg,(RKEY)baseKey,(char*)path,(void*)result,&length); + + PR_Unlock(mregLock); + + // Convert status. + return regerr2nsresult( err ); +} +/*---------------------------- nsRegistry::SetBytesUTF8 ------------------------------ +| Write out the value as a char array, using NR_RegSetEntry. | +------------------------------------------------------------------------------*/ +NS_IMETHODIMP nsRegistry::SetBytesUTF8( nsRegistryKey baseKey, const char *path, PRUint32 length, PRUint8* value) { + REGERR err = REGERR_OK; + // Set the contents. + PR_Lock(mregLock); + err = NR_RegSetEntry( mReg, + (RKEY)baseKey, + (char*)path, + REGTYPE_ENTRY_BYTES, + (char*)value, + length); + PR_Unlock(mregLock); + // Convert result. + return regerr2nsresult( err ); +} + +/*---------------------------- nsRegistry::SetInt ------------------------------ +| Write out the value as a one-element PRInt32 array, using NR_RegSetEntry. | +------------------------------------------------------------------------------*/ +NS_IMETHODIMP nsRegistry::SetInt( nsRegistryKey baseKey, const char *path, PRInt32 value ) { + REGERR err = REGERR_OK; + // Set the contents. + PR_Lock(mregLock); + err = NR_RegSetEntry( mReg, + (RKEY)baseKey, + (char*)path, + REGTYPE_ENTRY_INT32_ARRAY, + &value, + sizeof value ); + PR_Unlock(mregLock); + // Convert result. + return regerr2nsresult( err ); +} + + + +/*---------------------------- nsRegistry::SetLongLong--------------------------- +| Write out the value as a one-element PRInt64 array, using NR_RegSetEntry. | +------------------------------------------------------------------------------*/ +NS_IMETHODIMP nsRegistry::SetLongLong( nsRegistryKey baseKey, const char *path, PRInt64* value ) { + REGERR err = REGERR_OK; + // Set the contents. + PR_Lock(mregLock); + + err = NR_RegSetEntry( mReg, + (RKEY)baseKey, + (char*)path, + REGTYPE_ENTRY_BYTES, + (void*)value, + sizeof(PRInt64) ); + + PR_Unlock(mregLock); + // Convert result. + return regerr2nsresult( err ); +} + +/*-------------------------- nsRegistry::AddSubtree ---------------------------- +| Add a new registry subkey with the specified name, using NR_RegAddKey. | +------------------------------------------------------------------------------*/ +NS_IMETHODIMP nsRegistry::AddSubtree( nsRegistryKey baseKey, const char *path, nsRegistryKey *result ) { + REGERR err = REGERR_OK; + // Add the subkey. + PR_Lock(mregLock); + err = NR_RegAddKey( mReg,(RKEY)baseKey,(char*)path,(RKEY*)result ); + PR_Unlock(mregLock); + // Convert result. + return regerr2nsresult( err ); +} + +/*-------------------------- nsRegistry::AddSubtreeRaw-------------------------- +| Add a new registry subkey with the specified name, using NR_RegAddKeyRaw | +------------------------------------------------------------------------------*/ +NS_IMETHODIMP nsRegistry::AddSubtreeRaw( nsRegistryKey baseKey, const char *path, nsRegistryKey *result ) { + REGERR err = REGERR_OK; + // Add the subkey. + PR_Lock(mregLock); + err = NR_RegAddKeyRaw( mReg,(RKEY)baseKey,(char*)path,(RKEY*)result ); + PR_Unlock(mregLock); + // Convert result. + return regerr2nsresult( err ); +} + + +/*------------------------- nsRegistry::RemoveSubtree -------------------------- +| Deletes the subtree at a given location using NR_RegDeleteKey. | +------------------------------------------------------------------------------*/ +NS_IMETHODIMP nsRegistry::RemoveSubtree( nsRegistryKey baseKey, const char *path ) { + nsresult rv = NS_OK; + REGERR err = REGERR_OK; + + // libreg doesn't delete keys if there are subkeys under the key + // Hence we have to recurse through to delete the subtree + + RKEY key; + + PR_Lock(mregLock); + err = NR_RegGetKey(mReg, baseKey, (char *)path, &key); + PR_Unlock(mregLock); + if (err != REGERR_OK) + { + rv = regerr2nsresult( err ); + return rv; + } + + // Now recurse through and delete all keys under hierarchy + + char subkeyname[MAXREGPATHLEN+1]; + REGENUM state = 0; + subkeyname[0] = '\0'; + while (NR_RegEnumSubkeys(mReg, key, &state, subkeyname, sizeof(subkeyname), + REGENUM_NORMAL) == REGERR_OK) + { +#ifdef DEBUG_dp + printf("...recursing into %s\n", subkeyname); +#endif /* DEBUG_dp */ + // Even though this is not a "Raw" API the subkeys may still, in fact, + // *be* raw. Since we're recursively deleting this will work either way. + // If we were guaranteed none would be raw then a depth-first enumeration + // would be much more efficient. + err = RemoveSubtreeRaw(key, subkeyname); + if (err != REGERR_OK) break; + } + + // If success in deleting all subkeys, delete this key too + if (err == REGERR_OK) + { +#ifdef DEBUG_dp + printf("...deleting %s\n", path); +#endif /* DEBUG_dp */ + PR_Lock(mregLock); + err = NR_RegDeleteKey(mReg, baseKey, (char *)path); + PR_Unlock(mregLock); + } + + // Convert result. + rv = regerr2nsresult( err ); + return rv; +} + + +/*------------------------- nsRegistry::RemoveSubtreeRaw ----------------------- +| Deletes the subtree at a given location using NR_RegDeleteKeyRaw | +------------------------------------------------------------------------------*/ +NS_IMETHODIMP nsRegistry::RemoveSubtreeRaw( nsRegistryKey baseKey, const char *keyname ) { + nsresult rv = NS_OK; + REGERR err = REGERR_OK; + + // libreg doesn't delete keys if there are subkeys under the key + // Hence we have to recurse through to delete the subtree + + RKEY key; + char subkeyname[MAXREGPATHLEN+1]; + int n = sizeof(subkeyname); + REGENUM state = 0; + + PR_Lock(mregLock); + err = NR_RegGetKeyRaw(mReg, baseKey, (char *)keyname, &key); + PR_Unlock(mregLock); + if (err != REGERR_OK) + { + rv = regerr2nsresult( err ); + return rv; + } + + // Now recurse through and delete all keys under hierarchy + + subkeyname[0] = '\0'; + while (NR_RegEnumSubkeys(mReg, key, &state, subkeyname, n, REGENUM_NORMAL) == REGERR_OK) + { +#ifdef DEBUG_dp + printf("...recursing into %s\n", subkeyname); +#endif /* DEBUG_dp */ + err = RemoveSubtreeRaw(key, subkeyname); + if (err != REGERR_OK) break; + } + + // If success in deleting all subkeys, delete this key too + if (err == REGERR_OK) + { +#ifdef DEBUG_dp + printf("...deleting %s\n", keyname); +#endif /* DEBUG_dp */ + PR_Lock(mregLock); + err = NR_RegDeleteKeyRaw(mReg, baseKey, (char *)keyname); + PR_Unlock(mregLock); + } + + // Convert result. + rv = regerr2nsresult( err ); + return rv; +} +/*-------------------------- nsRegistry::GetSubtree ---------------------------- +| Returns a nsRegistryKey(RKEY) for a given key/path. The key is | +| obtained using NR_RegGetKey. | +------------------------------------------------------------------------------*/ +NS_IMETHODIMP nsRegistry::GetSubtree( nsRegistryKey baseKey, const char *path, nsRegistryKey *result ) { + nsresult rv = NS_OK; + REGERR err = REGERR_OK; + // Make sure we have a place for the result. + if( result ) { + // Get key. + PR_Lock(mregLock); + err = NR_RegGetKey( mReg,(RKEY)baseKey,(char*)path,(RKEY*)result ); + PR_Unlock(mregLock); + // Convert result. + rv = regerr2nsresult( err ); + } else { + rv = NS_ERROR_NULL_POINTER; + } + return rv; +} + +/*-------------------------- nsRegistry::GetSubtreeRaw-------------------------- +| Returns a nsRegistryKey(RKEY) for a given key/path. The key is | +| obtained using NR_RegGetKeyRaw. | +------------------------------------------------------------------------------*/ +NS_IMETHODIMP nsRegistry::GetSubtreeRaw( nsRegistryKey baseKey, const char *path, nsRegistryKey *result ) { + nsresult rv = NS_OK; + REGERR err = REGERR_OK; + // Make sure we have a place for the result. + if( result ) { + // Get key. + PR_Lock(mregLock); + err = NR_RegGetKeyRaw( mReg,(RKEY)baseKey,(char*)path,(RKEY*)result ); + PR_Unlock(mregLock); + // Convert result. + rv = regerr2nsresult( err ); + } else { + rv = NS_ERROR_NULL_POINTER; + } + return rv; +} + + +/*----------------------- nsRegistry::EnumerateSubtrees ------------------------ +| Allocate a nsRegSubtreeEnumerator object and return it to the caller. | +| We construct the enumerator using the registry handle from this registry | +| object, the user-specified registry key, and indicate that we don't want | +| to recurse down subtrees. No libreg functions are invoked at this point | +|(that will happen when the enumerator member functions are called). | +------------------------------------------------------------------------------*/ +NS_IMETHODIMP nsRegistry::EnumerateSubtrees( nsRegistryKey baseKey, nsIEnumerator **result ) { + nsresult rv = NS_OK; + // Make sure we have a place to put the result. + if( result ) { + *result = new nsRegSubtreeEnumerator( mReg,(RKEY)baseKey, PR_FALSE ); + // Check for success. + if( *result ) { + // Bump refcnt on behalf of caller. + NS_ADDREF(*result); + } else { + // Unable to allocate space for the enumerator object. + rv = NS_ERROR_OUT_OF_MEMORY; + } + } else { + rv = NS_ERROR_NULL_POINTER; + } + return rv; +} + +/*--------------------- nsRegistry::EnumerateAllSubtrees ----------------------- +| Same as EnumerateSubtrees but we pass PR_TRUE to request that the | +| enumerator object descend subtrees when it is used. | +------------------------------------------------------------------------------*/ +NS_IMETHODIMP nsRegistry::EnumerateAllSubtrees( nsRegistryKey baseKey, nsIEnumerator **result ) { + nsresult rv = NS_OK; + // Make sure we have a place to put the result. + if( result ) { + *result = new nsRegSubtreeEnumerator( mReg,(RKEY)baseKey, PR_TRUE ); + // Check for success. + if( *result ) { + // Bump refcnt on behalf of caller. + NS_ADDREF(*result); + } else { + // Unable to allocate space for the enumerator object. + rv = NS_ERROR_OUT_OF_MEMORY; + } + } else { + rv = NS_ERROR_NULL_POINTER; + } + return rv; +} + +/*------------------------- nsRegistry::GetValueType --------------------------- +| Gets the type from the registry using the NR_GetEntryInfo libreg API. | +| The result is transferred to the PRUint32 value passed in (with conversion | +| to the appropriate nsIRegistry::DataType value). | +------------------------------------------------------------------------------*/ +NS_IMETHODIMP nsRegistry::GetValueType( nsRegistryKey baseKey, const char *path, PRUint32 *result ) { + nsresult rv = NS_OK; + REGERR err = REGERR_OK; + // Make sure we have a place to put the result. + if( result ) { + // Get registry info into local structure. + REGINFO info = { sizeof info, 0, 0 }; + PR_Lock(mregLock); + err = NR_RegGetEntryInfo( mReg,(RKEY)baseKey,(char*)path, &info ); + PR_Unlock(mregLock); + if( err == REGERR_OK ) { + // Copy info to user's result value. + reginfo2DataType( info, *result ); + } else { + rv = regerr2nsresult( err ); + } + } else { + rv = NS_ERROR_NULL_POINTER; + } + return rv; +} + +/*------------------------ nsRegistry::GetValueLength -------------------------- +| Gets the registry value info via NR_RegGetEntryInfo. The length is | +| converted to the proper "units" via reginfo2Length. | +------------------------------------------------------------------------------*/ +NS_IMETHODIMP nsRegistry::GetValueLength( nsRegistryKey baseKey, const char *path, PRUint32 *result ) { + nsresult rv = NS_OK; + REGERR err = REGERR_OK; + // Make sure we have a place to put the result. + if( result ) { + // Get registry info into local structure. + REGINFO info = { sizeof info, 0, 0 }; + PR_Lock(mregLock); + err = NR_RegGetEntryInfo( mReg,(RKEY)baseKey,(char*)path, &info ); + PR_Unlock(mregLock); + if( err == REGERR_OK ) { + // Copy info to user's result value. + reginfo2Length( info, *result ); + } else { + rv = regerr2nsresult( err ); + } + } else { + rv = NS_ERROR_NULL_POINTER; + } + return rv; +} + +/*-------------------------- nsRegistry::DeleteValue --------------------------- +| Remove the registry value with the specified name | +------------------------------------------------------------------------------*/ +NS_IMETHODIMP nsRegistry::DeleteValue( nsRegistryKey baseKey, const char *path) +{ + REGERR err = REGERR_OK; + // Delete the value + PR_Lock(mregLock); + err = NR_RegDeleteEntry( mReg,(RKEY)baseKey,(char*)path ); + PR_Unlock(mregLock); + // Convert result. + return regerr2nsresult( err ); +} + +/*------------------------ nsRegistry::EnumerateValues ------------------------- +| Allocates and returns an instance of nsRegValueEnumerator constructed in | +| a similar fashion as the nsRegSubtreeEnumerator is allocated/returned by | +| EnumerateSubtrees. | +------------------------------------------------------------------------------*/ +NS_IMETHODIMP nsRegistry::EnumerateValues( nsRegistryKey baseKey, nsIEnumerator **result ) { + nsresult rv = NS_OK; + // Make sure we have a place to put the result. + if( result ) { + *result = new nsRegValueEnumerator( mReg,(RKEY)baseKey ); + // Check for success. + if( *result ) { + // Bump refcnt on behalf of caller. + NS_ADDREF(*result); + } else { + // Unable to allocate space for the enumerator object. + rv = NS_ERROR_OUT_OF_MEMORY; + } + } else { + rv = NS_ERROR_NULL_POINTER; + } + return rv; +} + +/*---------------------- nsRegistry::GetCurrentUserName ------------------------ +| Simple wrapper for NR_RegGetUsername. | +------------------------------------------------------------------------------*/ +NS_IMETHODIMP nsRegistry::GetCurrentUserName( char **result ) { + nsresult rv = NS_OK; + REGERR err = REGERR_OK; + // Make sure we have a place to put the result. + if( result ) { + // Get the user name. + PR_Lock(mregLock); + err = NR_RegGetUsername( result ); + PR_Unlock(mregLock); + // Convert the result. + rv = regerr2nsresult( err ); + } else { + rv = NS_ERROR_NULL_POINTER; + } + return rv; +} + +/*---------------------- nsRegistry::SetCurrentUserName ------------------------ +| Simple wrapper for NR_RegSetUsername. | +------------------------------------------------------------------------------*/ +NS_IMETHODIMP nsRegistry::SetCurrentUserName( const char *name ) { + nsresult rv = NS_OK; + REGERR err = REGERR_OK; + // Set the user name. + PR_Lock(mregLock); + err = NR_RegSetUsername( name ); + PR_Unlock(mregLock); + // Convert result. + rv = regerr2nsresult( err ); + return rv; +} + +/*----------------------------- nsRegistry::Pack ------------------------------- +| Simple wrapper for NR_RegPack. We don't set up any callback. | +------------------------------------------------------------------------------*/ +NS_IMETHODIMP nsRegistry::Pack() { + nsresult rv = NS_OK; + REGERR err = REGERR_OK; + // Pack the registry. + PR_Lock(mregLock); + err = NR_RegPack( mReg, 0, 0 ); + PR_Unlock(mregLock); + // Convert result. + rv = regerr2nsresult( err ); + return rv; +} + +/*----------------------------- nsRegistry::EscapeKey ------------------------------- +| Escape a binary key so that the registry works OK, since it expects UTF8 +| with no slashes or control characters. This is probably better than raw. +| If no escaping is required, then the method is successful and a null is +| returned, indicating that the caller should use the original string. +------------------------------------------------------------------------------*/ +static const char sEscapeKeyHex[] = "0123456789abcdef0123456789ABCDEF"; +NS_IMETHODIMP nsRegistry::EscapeKey(PRUint8* key, PRUint32 termination, PRUint32* length, PRUint8** escaped) +{ + nsresult rv = NS_OK; + char* value = (char*)key; + char* b = value; + char* e = b + *length; + int escapees = 0; + while (b < e) // Count characters outside legal range or slash + { + int c = *b++; + if (c <= ' ' + || c > '~' + || c == '/' + || c == '%') + { + escapees++; + } + } + if (escapees == 0) // If no escapees, then no results + { + *length = 0; + *escaped = nsnull; + return NS_OK; + } + // New length includes two extra chars for escapees. + *length += escapees * 2; + *escaped = (PRUint8*)nsMemory::Alloc(*length + termination); + if (*escaped == nsnull) + { + *length = 0; + *escaped = nsnull; + return NS_ERROR_OUT_OF_MEMORY; + } + char* n = (char*)*escaped; + b = value; + while (escapees && b < e) + { + char c = *b++; + if (c < ' ' + || c > '~' + || c == '/' + || c == '%') + { + *(n++) = '%'; + *(n++) = sEscapeKeyHex[ 0xF & (c >> 4) ]; + *(n++) = sEscapeKeyHex[ 0xF & c ]; + escapees--; + } + else + { + *(n++) = c; + } + } + e += termination; + if (b < e) + { + strncpy(n, b, e - b); + } + return rv; +} + +/*----------------------------- nsRegistry::UnescapeKey ------------------------------- +| Unscape a binary key so that the registry works OK, since it expects UTF8 +| with no slashes or control characters. This is probably better than raw. +| If no escaping is required, then the method is successful and a null is +| returned, indicating that the caller should use the original string. +------------------------------------------------------------------------------*/ +NS_IMETHODIMP nsRegistry::UnescapeKey(PRUint8* escaped, PRUint32 termination, PRUint32* length, PRUint8** key) +{ + nsresult rv = NS_OK; + char* value = (char*)escaped; + char* b = value; + char* e = b + *length; + int escapees = 0; + while (b < e) // Count characters outside legal range or slash + { + if (*b++ == '%') + { + escapees++; + } + } + if (escapees == 0) // If no escapees, then no results + { + *length = 0; + *key = nsnull; + return NS_OK; + } + // New length includes two extra chars for escapees. + *length -= escapees * 2; + *key = (PRUint8*)nsMemory::Alloc(*length + termination); + if (*key == nsnull) + { + *length = 0; + *key = nsnull; + return NS_ERROR_OUT_OF_MEMORY; + } + char* n = (char*)*key; + b = value; + while (escapees && b < e) + { + char c = *(b++); + if (c == '%') + { + if (e - b >= 2) + { + const char* c1 = strchr(sEscapeKeyHex, *(b++)); + const char* c2 = strchr(sEscapeKeyHex, *(b++)); + if (c1 != nsnull + && c2 != nsnull) + { + *(n++) = ((c2 - sEscapeKeyHex) & 0xF) + | (((c1 - sEscapeKeyHex) & 0xF) << 4); + } + else + { + escapees = -1; + } + } + else + { + escapees = -1; + } + escapees--; + } + else + { + *(n++) = c; + } + } + if (escapees < 0) + { + nsMemory::Free(*key); + *length = 0; + *key = nsnull; + return NS_ERROR_INVALID_ARG; + } + e += termination; + if (b < e) + { + strncpy(n, b, e - b); + } + return rv; +} + + +/*-------------- nsRegistry::SetBufferSize------------------------------------- +| Sets the size of the file used for the registry's buffer size. | +------------------------------------------------------------------------------*/ +int nsRegistry::SetBufferSize( int bufsize ) +{ + int newSize; + // set the file buffer size + PR_Lock(mregLock); + newSize = NR_RegSetBufferSize( mReg, bufsize ); + PR_Unlock(mregLock); + return newSize; +} + + +/*-------------- nsRegSubtreeEnumerator::nsRegSubtreeEnumerator ---------------- +| The ctor simply stashes all the information that will be needed to enumerate | +| the subkeys. | +------------------------------------------------------------------------------*/ +nsRegSubtreeEnumerator::nsRegSubtreeEnumerator( HREG hReg, RKEY rKey, PRBool all ) + : mReg( hReg ), mKey( rKey ), mEnum( 0 ), mNext( 0 ), + mStyle( all ? REGENUM_DESCEND : REGENUM_CHILDREN ), mDone( PR_FALSE ) { + + mName[0] = '\0'; + +#ifdef EXTRA_THREADSAFE + // Create a registry lock + mregLock = PR_NewLock(); +#endif + return; +} + +nsRegSubtreeEnumerator::~nsRegSubtreeEnumerator() +{ +#ifdef EXTRA_THREADSAFE + if (mregLock) { + PR_DestroyLock(mregLock); + } +#endif +} + +/*----------------------- nsRegSubtreeEnumerator::First ------------------------ +| Set mEnum to 0; this will cause the next NR_RegEnum call to go to | +| the beginning. We then do a Next() call in order to do a "lookahead" to | +| properly detect an empty list (i.e., set the mDone flag). | +------------------------------------------------------------------------------*/ +NS_IMETHODIMP +nsRegSubtreeEnumerator::First() { + nsresult rv = NS_OK; + // Reset "done" flag. + mDone = PR_FALSE; + // Clear Name + mName[0] = '\0'; + // Go to beginning. + mEnum = mNext = 0; + // Lookahead so mDone flag gets set for empty list. + rv = Next(); + return rv; +} + +/*----------------------- nsRegSubtreeEnumerator::Next ------------------------- +| First, we check if we've already advanced to the end by checking the mDone | +| flag. | +| | +| We advance mEnum to the next enumeration value which is in the mNext | +| lookahead buffer. We must then call advance to lookahead and properly set | +| the isDone flag. | +------------------------------------------------------------------------------*/ +NS_IMETHODIMP +nsRegSubtreeEnumerator::Next() { + nsresult rv = NS_OK; + // Check for at end. + if ( !mDone ) { + // Advance to next spot. + mEnum = mNext; + // Lookahead so mDone is properly set (and to update mNext). + rv = advance(); + } else { + // Set result accordingly. + rv = regerr2nsresult( REGERR_NOMORE ); + } + return rv; +} + +/*---------------------- nsRegSubtreeEnumerator::advance ----------------------- +| Advance mNext to next subkey using NR_RegEnumSubkeys. We set mDone if | +| there are no more subkeys. | +------------------------------------------------------------------------------*/ +NS_IMETHODIMP nsRegSubtreeEnumerator::advance() { + REGERR err = REGERR_OK; + PR_Lock(mregLock); + err = NR_RegEnumSubkeys( mReg, mKey, &mNext, mName, sizeof mName, mStyle ); + // See if we ran off end. + if( err == REGERR_NOMORE ) { + // Remember we've run off end. + mDone = PR_TRUE; + } + PR_Unlock(mregLock); + // Convert result. + nsresult rv = regerr2nsresult( err ); + return rv; +} + +/*-------------------- nsRegSubtreeEnumerator::CurrentItem --------------------- +| Allocates and returns a new instance of class nsRegistryNode. The node | +| object will hold the curent mEnum value so it can obtain its name from | +| the registry when asked. | +------------------------------------------------------------------------------*/ +NS_IMETHODIMP +nsRegSubtreeEnumerator::CurrentItem( nsISupports **result) { + nsresult rv = NS_OK; + // Make sure there is a place to put the result. + if( result ) { + *result = new nsRegistryNode( mReg, mName, (RKEY) mNext ); + if( *result ) { + NS_ADDREF(*result); + } else { + rv = NS_ERROR_OUT_OF_MEMORY; + } + } else { + rv = NS_ERROR_NULL_POINTER; + } + return rv; +} + +/*--------------nsRegSubtreeEnumerator::CurrentItemInPlaceUTF8----------------- +| An ugly name for an ugly function. Hands back a shared pointer to the | +| name (encoded as UTF-8), and the subkey identifier. | +-----------------------------------------------------------------------------*/ +NS_IMETHODIMP +nsRegSubtreeEnumerator::CurrentItemInPlaceUTF8( nsRegistryKey *childKey , + const char **name ) +{ + *childKey = mNext; + /* [shared] */ + *name = mName; + return NS_OK; +} + +/*---------------------- nsRegSubtreeEnumerator::IsDone ------------------------ +| Simply return mDone. | +------------------------------------------------------------------------------*/ +NS_IMETHODIMP +nsRegSubtreeEnumerator::IsDone() { + nsresult rv = mDone ? NS_OK : NS_ENUMERATOR_FALSE; + return rv; +} + + +/*---------------- nsRegValueEnumerator::nsRegValueEnumerator ------------------ +| Delegates everything to the base class constructor. | +------------------------------------------------------------------------------*/ +nsRegValueEnumerator::nsRegValueEnumerator( HREG hReg, RKEY rKey ) + : nsRegSubtreeEnumerator( hReg, rKey, PR_FALSE ) { + return; +} + + +/*--------------------- nsRegValueEnumerator::CurrentItem ---------------------- +| As the nsRegSubtreeEnumerator counterpart, but allocates an object of | +| class nsRegistryValue. | +------------------------------------------------------------------------------*/ +NS_IMETHODIMP +nsRegValueEnumerator::CurrentItem( nsISupports **result ) { + nsresult rv = NS_OK; + // Make sure there is a place to put the result. + if( result ) { + *result = new nsRegistryValue( mReg, mKey, mEnum ); + if( *result ) { + NS_ADDREF(*result); + } else { + rv = NS_ERROR_OUT_OF_MEMORY; + } + } else { + rv = NS_ERROR_NULL_POINTER; + } + return rv; +} + +/*----------------------- nsRegValueEnumerator::advance ------------------------ +| Advance mNext to next subkey using NR_RegEnumEntries. We set mDone if | +| there are no more entries. | +------------------------------------------------------------------------------*/ +NS_IMETHODIMP nsRegValueEnumerator::advance() { + REGERR err = REGERR_OK; + char name[MAXREGNAMELEN]; + PRUint32 len = sizeof name; + REGINFO info = { sizeof info, 0, 0 }; + PR_Lock(mregLock); + err = NR_RegEnumEntries( mReg, mKey, &mNext, name, len, &info ); + // See if we ran off end. + if( err == REGERR_NOMORE ) { + // Remember we've run off end. + mDone = PR_TRUE; + } + PR_Unlock(mregLock); + // Convert result. + nsresult rv = regerr2nsresult( err ); + return rv; +} + + +/*---------------------- nsRegistryNode::nsRegistryNode ------------------------ +| Store the arguments in the corresponding data members and initialize | +| the other data members. We defer the libreg calls till we're asked for | +| our name. We use mErr==-1 to indicate we haven't fetched the name yet. | +------------------------------------------------------------------------------*/ +nsRegistryNode::nsRegistryNode( HREG hReg, char *name, RKEY childKey ) + : mReg( hReg ), mChildKey( childKey ) { + + PR_ASSERT(name != nsnull); + strcpy(mName, name); + +#ifdef EXTRA_THREADSAFE + mregLock = PR_NewLock(); +#endif + + return; +} + +nsRegistryNode::~nsRegistryNode() +{ +#ifdef EXTRA_THREADSAFE + if (mregLock) { + PR_DestroyLock(mregLock); + } +#endif +} + +/*-------------------------- nsRegistryNode::GetName --------------------------- +| If we haven't fetched it yet, get the name of the corresponding subkey now, | +| using NR_RegEnumSubkeys. | +------------------------------------------------------------------------------*/ +NS_IMETHODIMP nsRegistryNode::GetName( PRUnichar **result ) { + if (result == nsnull) return NS_ERROR_NULL_POINTER; + // Make sure there is a place to put the result. + *result = nsTextFormatter::smprintf( widestrFormat, mName ); + if ( !*result ) return NS_ERROR_OUT_OF_MEMORY; + return NS_OK; +} + +/*-------------------------- nsRegistryNode::GetNameUTF8 ----------------------- +| If we haven't fetched it yet, get the name of the corresponding subkey now, | +| using NR_RegEnumSubkeys. | +------------------------------------------------------------------------------*/ +NS_IMETHODIMP nsRegistryNode::GetNameUTF8( char **result ) { + if (result == nsnull) return NS_ERROR_NULL_POINTER; + // Make sure there is a place to put the result. + *result = nsCRT::strdup( mName ); + if ( !*result ) return NS_ERROR_OUT_OF_MEMORY; + return NS_OK; +} + +/*-------------------------- nsRegistryNode::GetKey ---------------------------- +| Get the subkey corresponding to this node | +| using NR_RegEnumSubkeys. | +------------------------------------------------------------------------------*/ +NS_IMETHODIMP nsRegistryNode::GetKey( nsRegistryKey *r_key ) { + nsresult rv = NS_OK; + if (r_key == nsnull) return NS_ERROR_NULL_POINTER; + *r_key = mChildKey; + return rv; +} + + + +/*--------------------- nsRegistryValue::nsRegistryValue ----------------------- +| Implemented the same way as the nsRegistryNode ctor. | +------------------------------------------------------------------------------*/ +nsRegistryValue::nsRegistryValue( HREG hReg, RKEY key, REGENUM slot ) + : mReg( hReg ), mKey( key ), mEnum( slot ), mErr( -1 ) { +#ifdef EXTRA_THREADSAFE + mregLock = PR_NewLock(); +#endif + mInfo.size = sizeof(REGINFO); +} + +nsRegistryValue::~nsRegistryValue() +{ +#ifdef EXTRA_THREADSAFE + if (mregLock) { + PR_DestroyLock(mregLock); + } +#endif +} + +/*------------------------- nsRegistryValue::GetName --------------------------- +| See nsRegistryNode::GetName; we use NR_RegEnumEntries in this case. | +------------------------------------------------------------------------------*/ +NS_IMETHODIMP nsRegistryValue::GetName( PRUnichar **result ) { + nsresult rv = NS_OK; + // Make sure we have a place to put the result. + if( result ) { + // Ensure we've got the info we need. + rv = getInfo(); + if( rv == NS_OK || rv == NS_ERROR_REG_NO_MORE ) { + // worked, return actual result. + *result = nsTextFormatter::smprintf( widestrFormat, mName ); + if ( *result ) { + rv = NS_OK; + } else { + rv = NS_ERROR_OUT_OF_MEMORY; + } + } + } else { + rv = NS_ERROR_NULL_POINTER; + } + return rv; +} + +/*------------------------- nsRegistryValue::GetNameUTF8 ----------------------- +| See nsRegistryNode::GetName; we use NR_RegEnumEntries in this case. | +------------------------------------------------------------------------------*/ +NS_IMETHODIMP nsRegistryValue::GetNameUTF8( char **result ) { + nsresult rv = NS_OK; + // Make sure we have a place to put the result. + if( result ) { + // Ensure we've got the info we need. + rv = getInfo(); + if( rv == NS_OK || rv == NS_ERROR_REG_NO_MORE ) { + // worked, return actual result. + *result = nsCRT::strdup( mName ); + if ( *result ) { + rv = NS_OK; + } else { + rv = NS_ERROR_OUT_OF_MEMORY; + } + } + } else { + rv = NS_ERROR_NULL_POINTER; + } + return rv; +} + +/*----------------------- nsRegistryValue::GetType ------------------------ +| We test if we've got the info already. If not, we git it by calling | +| getInfo. We calculate the result by converting the REGINFO type field to | +| a nsIRegistry::DataType value (using reginfo2DataType). | +------------------------------------------------------------------------------*/ +NS_IMETHODIMP nsRegistryValue::GetType( PRUint32 *result ) { + nsresult rv = NS_OK; + // Make sure we have room for th result. + if( result ) { + // Make sure we've got the info we need. + rv = getInfo(); + // Check if it worked. + if( rv == NS_OK ) { + // Convert result from REGINFO to nsIRegistry::ValueInfo. + reginfo2DataType( mInfo, *result ); + } + } else { + rv = NS_ERROR_NULL_POINTER; + } + return rv; +} + +/*---------------------- nsRegistryValue::GetLength ----------------------- +| We test if we've got the info already. If not, we git it by calling | +| getInfo. We calculate the result by converting the REGINFO type field to | +| a nsIRegistry::DataType value (using reginfo2Length). | +------------------------------------------------------------------------------*/ +NS_IMETHODIMP nsRegistryValue::GetLength( PRUint32 *result ) { + nsresult rv = NS_OK; + // Make sure we have room for th result. + if( result ) { + // Make sure we've got the info we need. + rv = getInfo(); + // Check if it worked. + if( rv == NS_OK ) { + // Convert result from REGINFO to length. + reginfo2Length( mInfo, *result ); + } + } else { + rv = NS_ERROR_NULL_POINTER; + } + return rv; +} + +/*------------------------- nsRegistryValue::getInfo --------------------------- +| Call NR_RegEnumEntries to set the mInfo/mName data members. | +------------------------------------------------------------------------------*/ +nsresult nsRegistryValue::getInfo() { + nsresult rv = NS_OK; + // Test whether we haven't tried to get it yet. + if( mErr == -1 ) { + REGENUM temp = mEnum; + // Get name and info. + PR_Lock(mregLock); + mErr = NR_RegEnumEntries( mReg, mKey, &temp, mName, sizeof mName, &mInfo ); + // Convert result. + rv = regerr2nsresult( mErr ); + PR_Unlock(mregLock); + } + return rv; +} + + +nsRegistryFactory::nsRegistryFactory() { +} + +NS_IMPL_ISUPPORTS1(nsRegistryFactory, nsIFactory) + +NS_IMETHODIMP +nsRegistryFactory::CreateInstance(nsISupports *aOuter, + const nsIID &aIID, + void **aResult) { + nsresult rv = NS_OK; + nsRegistry* newRegistry; + + if(aResult == nsnull) { + return NS_ERROR_NULL_POINTER; + } else { + *aResult = nsnull; + } + + if(0 != aOuter) { + return NS_ERROR_NO_AGGREGATION; + } + + NS_NEWXPCOM(newRegistry, nsRegistry); + + if(newRegistry == nsnull) { + return NS_ERROR_OUT_OF_MEMORY; + } + + NS_ADDREF(newRegistry); + rv = newRegistry->QueryInterface(aIID, aResult); + NS_RELEASE(newRegistry); + + return rv; +} + +nsresult +nsRegistryFactory::LockFactory(PRBool aLock) +{ + // Not implemented in simplest case. + return NS_OK; +} + +// This is a temporary hack; needs work to support dynamic binding +// via nsComponentManager and support for multiple factories per DLL. +extern "C" NS_EXPORT nsresult +NS_RegistryGetFactory(nsIFactory** aFactory ) { + nsresult rv = NS_OK; + + if( aFactory == 0 ) { + return NS_ERROR_NULL_POINTER; + } else { + *aFactory = 0; + } + + nsIFactory* inst = new nsRegistryFactory(); + if(0 == inst) { + rv = NS_ERROR_OUT_OF_MEMORY; + } else { + NS_ADDREF(inst); + *aFactory = inst; + } + + return rv; +} diff --git a/src/libs/xpcom18a4/xpcom/obsolete/component/nsRegistry.h b/src/libs/xpcom18a4/xpcom/obsolete/component/nsRegistry.h new file mode 100644 index 00000000..8b59db36 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/obsolete/component/nsRegistry.h @@ -0,0 +1,77 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Edward Kandrot + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + + +#ifndef nsRegistry_h__ +#define nsRegistry_h__ + +#include "nsIRegistry.h" +#include "NSReg.h" +#include "nsIFile.h" +#include "nsCOMPtr.h" + +struct nsRegistry : public nsIRegistry, nsIRegistryGetter { + // This class implements the nsISupports interface functions. + NS_DECL_ISUPPORTS + + // This class implements the nsIRegistry interface functions. + NS_DECL_NSIREGISTRY + + // Fast registry getters + NS_DECL_NSIREGISTRYGETTER + + int SetBufferSize( int bufsize ); // changes the file buffer size for this registry + + // ctor/dtor + nsRegistry(); + +private: + ~nsRegistry(); + +protected: + HREG mReg; // Registry handle. +#ifdef EXTRA_THREADSAFE + PRLock *mregLock; // libreg isn't threadsafe. Use locks to synchronize. +#endif + nsCOMPtr mCurRegFile; // these are to prevent open from opening the registry again + nsWellKnownRegistry mCurRegID; + + NS_IMETHOD Close(); +}; // nsRegistry + +#endif diff --git a/src/libs/xpcom18a4/xpcom/obsolete/component/nsXPCOMObsolete.cpp b/src/libs/xpcom18a4/xpcom/obsolete/component/nsXPCOMObsolete.cpp new file mode 100644 index 00000000..9a71a916 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/obsolete/component/nsXPCOMObsolete.cpp @@ -0,0 +1,57 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsXPCOM.h" +#include "nsIGenericFactory.h" + +#include "nsFileSpecImpl.h" +#include "nsRegistry.h" + +#define COMPONENT(NAME, Ctor) \ + { NS_##NAME##_CLASSNAME, NS_##NAME##_CID, NS_##NAME##_CONTRACTID, Ctor } + +NS_GENERIC_FACTORY_CONSTRUCTOR(nsRegistry) + +static const nsModuleComponentInfo components[] = +{ + COMPONENT(FILESPEC, nsFileSpecImpl::Create), + COMPONENT(DIRECTORYITERATOR, nsDirectoryIteratorImpl::Create), + COMPONENT(REGISTRY, nsRegistryConstructor), +}; + +NS_IMPL_NSGETMODULE(xpcomObsoleteModule, components) + diff --git a/src/libs/xpcom18a4/xpcom/obsolete/component/regExport.cpp b/src/libs/xpcom18a4/xpcom/obsolete/component/regExport.cpp new file mode 100644 index 00000000..d1b2f85e --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/obsolete/component/regExport.cpp @@ -0,0 +1,357 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 + +#include "nsIServiceManager.h" +#include "nsIComponentManager.h" +#include "nsCOMPtr.h" +#include "nsIRegistry.h" +#include "nsIEnumerator.h" +#include "nsILocalFile.h" +#include "nsDependentString.h" +#include "prmem.h" +#include "plstr.h" +#include "nsMemory.h" + +static void display( nsIRegistry *reg, nsRegistryKey root, const char *name ); +static void displayValues( nsIRegistry *reg, nsRegistryKey root ); +static void printString( const char *value, int indent ); + +int main( int argc, char *argv[] ) { + + +#ifdef __MWERKS__ + // Hack in some arguments. A NULL registry name is supposed to tell libreg + // to use the default registry (which does seem to work). + argc = 1; + const char* myArgs[] = + { + "regExport" + }; + argv = const_cast(myArgs); +#endif + + nsresult rv; + + // Initialize XPCOM + nsIServiceManager *servMgr = NULL; + rv = NS_InitXPCOM2(&servMgr, NULL, NULL); + if (NS_FAILED(rv)) + { + // Cannot initialize XPCOM + printf("Cannot initialize XPCOM. Exit. [rv=0x%08X]\n", (int)rv); + exit(-1); + } + { + // Get the component manager + static NS_DEFINE_CID(kComponentManagerCID, NS_COMPONENTMANAGER_CID); + nsCOMPtr compMgr = do_GetService(kComponentManagerCID, &rv); + if (NS_FAILED(rv)) + { + // Cant get component manager + printf("Cannot get component manager from service manager.. Exit. [rv=0x%08X]\n", (int)rv); + exit(-1); + } + + nsIRegistry *reg; + + if (argc>1) { + // Create the registry + rv = compMgr->CreateInstanceByContractID(NS_REGISTRY_CONTRACTID, NULL, + NS_GET_IID(nsIRegistry), + (void **) ®); + // Check result. + if ( NS_FAILED(rv) ) + { + printf( "Error opening registry file %s, rv=0x%08X\n", argv[1] , (int)rv ); + return rv; + } + // Open it against the input file name. + nsCOMPtr regFile; + rv = NS_NewNativeLocalFile( nsDependentCString(argv[1]), PR_FALSE, getter_AddRefs(regFile) ); + if ( NS_FAILED(rv) ) { + printf( "Error instantiating local file for %s, rv=0x%08X\n", argv[1], (int)rv ); + return rv; + } + + rv = reg->Open( regFile ); + + if ( rv == NS_OK ) + { + printf( "Registry %s opened OK.\n", argv[1] ); + + // Recurse over all 3 branches. + display( reg, nsIRegistry::Common, "nsRegistry::Common" ); + display( reg, nsIRegistry::Users, "nsRegistry::Users" ); + } + NS_RELEASE(reg); + } + else + { + // Called with no arguments. Print both the default registry and + // the components registry. We already printed the default regsitry. + // So just do the component registry. + rv = compMgr->CreateInstanceByContractID(NS_REGISTRY_CONTRACTID, NULL, + NS_GET_IID(nsIRegistry), + (void **) ®); + + // Check result. + if ( NS_FAILED(rv) ) + { + printf( "Error opening creating registry instance, rv=0x%08X\n", (int)rv ); + return rv; + } + rv = reg->OpenWellKnownRegistry(nsIRegistry::ApplicationComponentRegistry); + if ( rv == NS_ERROR_REG_BADTYPE ) { + printf( "\n\n\nThere is no \n" ); + } + else if ( rv == NS_OK ) { + + printf( "\n\n\nRegistry %s opened OK.\n", "\n" ); + + // Recurse over all 3 branches. + display( reg, nsIRegistry::Common, "nsRegistry::Common" ); + display( reg, nsIRegistry::Users, "nsRegistry::Users" ); + } + NS_RELEASE(reg); + } + } + NS_ShutdownXPCOM( servMgr ); + + return rv; +} + +void display( nsIRegistry *reg, nsRegistryKey root, const char *rootName ) { + // Print out key name. + printf( "%s\n", rootName ); + + // Make sure it isn't a "root" key. + if ( root != nsIRegistry::Common + && + root != nsIRegistry::Users + && + root != nsIRegistry::CurrentUser ) { + // Print values stored under this key. + displayValues( reg, root ); + } + + // Enumerate all subkeys (immediately) under the given node. + nsIEnumerator *keys; + nsresult rv = reg->EnumerateSubtrees( root, &keys ); + + // Check result. + if ( rv == NS_OK ) { + // Set enumerator to beginning. + rv = keys->First(); + // Enumerate subkeys till done. + while( NS_SUCCEEDED( rv ) && (NS_OK != keys->IsDone()) ) { + nsISupports *base; + rv = keys->CurrentItem( &base ); + // Test result. + if ( rv == NS_OK ) { + // Get specific interface. + nsIRegistryNode *node; + nsIID nodeIID = NS_IREGISTRYNODE_IID; + rv = base->QueryInterface( nodeIID, (void**)&node ); + // Test that result. + if ( rv == NS_OK ) { + // Get node name. + char *name; + rv = node->GetNameUTF8( &name ); + // Test result. + if ( rv == NS_OK ) { + // Build complete name. + char *fullName = new char[ PL_strlen(rootName) + PL_strlen(name) + 5 ]; + PL_strcpy( fullName, rootName ); + PL_strcat( fullName, " - " ); + PL_strcat( fullName, name ); + // Display contents under this subkey. + nsRegistryKey key; + rv = reg->GetSubtreeRaw( root, name, &key ); + if ( rv == NS_OK ) { + display( reg, key, fullName ); + printf( "\n" ); + } else { + printf( "Error getting key, rv=0x%08X\n", (int)rv ); + } + delete [] fullName; + } else { + printf( "Error getting subtree name, rv=0x%08X\n", (int)rv ); + } + // Release node. + node->Release(); + } else { + printf( "Error converting base node ptr to nsIRegistryNode, rv=0x%08X\n", (int)rv ); + } + // Release item. + base->Release(); + + // Advance to next key. + rv = keys->Next(); + // Check result. + if ( NS_SUCCEEDED( rv ) ) { + } else { + printf( "Error advancing enumerator, rv=0x%08X\n", (int)rv ); + } + } else { + printf( "Error getting current item, rv=0x%08X\n", (int)rv ); + } + } + // Release key enumerator. + keys->Release(); + } else { + printf( "Error creating enumerator for %s, root=0x%08X, rv=0x%08X\n", + rootName, (int)root, (int)rv ); + } + return; +} + +static void displayValues( nsIRegistry *reg, nsRegistryKey root ) { + // Emumerate values at this registry location. + nsIEnumerator *values; + nsresult rv = reg->EnumerateValues( root, &values ); + + // Check result. + if ( rv == NS_OK ) { + // Go to beginning. + rv = values->First(); + + // Enumerate values till done. + while( rv == NS_OK && (NS_OK != values->IsDone()) ) { + nsISupports *base; + rv = values->CurrentItem( &base ); + // Test result. + if ( rv == NS_OK ) { + // Get specific interface. + nsIRegistryValue *value; + nsIID valueIID = NS_IREGISTRYVALUE_IID; + rv = base->QueryInterface( valueIID, (void**)&value ); + // Test that result. + if ( rv == NS_OK ) { + // Get node name. + char *name; + rv = value->GetNameUTF8( &name ); + // Test result. + if ( rv == NS_OK ) { + // Print name: + printf( "\t\t%s", name ); + // Get info about this value. + PRUint32 type; + rv = reg->GetValueType( root, name, &type ); + if ( rv == NS_OK ) { + // Print value contents. + switch ( type ) { + case nsIRegistry::String: { + char *strValue; + rv = reg->GetStringUTF8( root, name, &strValue ); + if ( rv == NS_OK ) { + printString( strValue, strlen(name) ); + nsMemory::Free( strValue ); + } else { + printf( "\t Error getting string value, rv=0x%08X", (int)rv ); + } + } + break; + + case nsIRegistry::Int32: + { + PRInt32 val = 0; + rv = reg->GetInt( root, name, &val ); + if (NS_SUCCEEDED(rv)) { + printf( "\t= Int32 [%d, 0x%x]", val, val); + } + else { + printf( "\t Error getting int32 value, rv=%08X", (int)rv); + } + } + break; + + case nsIRegistry::Bytes: + printf( "\t= Bytes" ); + break; + + case nsIRegistry::File: + printf( "\t= File (?)" ); + break; + + default: + printf( "\t= ? (unknown type=0x%02X)", (int)type ); + break; + } + } else { + printf( "\t= ? (error getting value, rv=0x%08X)", (int)rv ); + } + printf("\n"); + nsMemory::Free( name ); + } else { + printf( "Error getting value name, rv=0x%08X\n", (int)rv ); + } + // Release node. + value->Release(); + } else { + printf( "Error converting base node ptr to nsIRegistryNode, rv=0x%08X\n", (int)rv ); + } + // Release item. + base->Release(); + + // Advance to next key. + rv = values->Next(); + // Check result. + if ( NS_SUCCEEDED( rv ) ) { + } else { + printf( "Error advancing enumerator, rv=0x%08X\n", (int)rv ); + break; + } + } else { + printf( "Error getting current item, rv=0x%08X\n", (int)rv ); + break; + } + } + + values->Release(); + } else { + printf( "\t\tError enumerating values, rv=0x%08X\n", (int)rv ); + } + return; +} + +static void printString( const char *value, int /*indent*/ ) { + // For now, just dump contents. + printf( "\t = %s", value ); + return; +} diff --git a/src/libs/xpcom18a4/xpcom/obsolete/component/xpcomobsoletec.pkg b/src/libs/xpcom18a4/xpcom/obsolete/component/xpcomobsoletec.pkg new file mode 100644 index 00000000..88cbf236 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/obsolete/component/xpcomobsoletec.pkg @@ -0,0 +1,6 @@ +[gecko xpi-bootstrap] +#if SHARED_LIBRARY +dist/bin/components/@SHARED_LIBRARY@ +#else +!staticcomp @LIBRARY@ @MODULE_NAME@ +#endif diff --git a/src/libs/xpcom18a4/xpcom/obsolete/dlldeps.cpp b/src/libs/xpcom18a4/xpcom/obsolete/dlldeps.cpp new file mode 100644 index 00000000..d904e071 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/obsolete/dlldeps.cpp @@ -0,0 +1,50 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2003 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +// Force references to all of the symbols that we want exported from +// the dll that are located in the .lib files we link with + +#include "nsFileSpec.h" +#include "NSReg.h" + +void XXXNeverCalled() +{ + nsFileURL(NULL); + nsFileSpec s; + + NR_RegSetBufferSize(NULL, 0); +} diff --git a/src/libs/xpcom18a4/xpcom/obsolete/nsFileSpec.cpp b/src/libs/xpcom18a4/xpcom/obsolete/nsFileSpec.cpp new file mode 100644 index 00000000..9be29eb9 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/obsolete/nsFileSpec.cpp @@ -0,0 +1,1367 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsFileSpec.h" + +#include "nsDebug.h" +#include "nsEscape.h" +#include "nsMemory.h" + +#include "prtypes.h" +#include "plstr.h" +#include "plbase64.h" +#include "prmem.h" + +#include "nsCOMPtr.h" +#include "nsIServiceManager.h" +#include "nsILocalFile.h" + +#include +#include + +#if defined(XP_WIN) +#include +#endif + +#ifdef XP_OS2 +extern unsigned char* _mbsrchr( const unsigned char*, int); +#endif + +// return pointer to last instance of the given separator +static inline char *GetLastSeparator(const char *str, char sep) +{ +#if defined(XP_WIN) || defined(XP_OS2) + return (char*) _mbsrchr((const unsigned char *) str, sep); +#else + return (char*) strrchr(str, sep); +#endif +} + +#if defined(XP_MACOSX) +#include +#endif + +#if defined(XP_MAC) || defined(XP_MACOSX) +#include +#include +#endif + +//======================================================================================== +// class nsSimpleCharString +//======================================================================================== + +//---------------------------------------------------------------------------------------- +nsSimpleCharString::nsSimpleCharString() +//---------------------------------------------------------------------------------------- +: mData(nsnull) +{ + +} // nsSimpleCharString::nsSimpleCharString + +//---------------------------------------------------------------------------------------- +nsSimpleCharString::nsSimpleCharString(const char* inString) +//---------------------------------------------------------------------------------------- +: mData(nsnull) +{ + if (inString) + CopyFrom(inString, strlen(inString)); +} // nsSimpleCharString::nsSimpleCharString + +//---------------------------------------------------------------------------------------- +nsSimpleCharString::nsSimpleCharString(const nsString& inString) +//---------------------------------------------------------------------------------------- +: mData(nsnull) +{ + *this = inString; +} // nsSimpleCharString::nsSimpleCharString + +//---------------------------------------------------------------------------------------- +nsSimpleCharString::nsSimpleCharString(const nsSimpleCharString& inOther) +//---------------------------------------------------------------------------------------- +{ + mData = inOther.mData; + AddRefData(); +} // nsSimpleCharString::nsSimpleCharString + +//---------------------------------------------------------------------------------------- +nsSimpleCharString::nsSimpleCharString(const char* inData, PRUint32 inLength) +//---------------------------------------------------------------------------------------- +: mData(nsnull) +{ + CopyFrom(inData, inLength); +} // nsSimpleCharString::nsSimpleCharString + +//---------------------------------------------------------------------------------------- +nsSimpleCharString::~nsSimpleCharString() +//---------------------------------------------------------------------------------------- +{ + ReleaseData(); +} // nsSimpleCharString::nsSimpleCharString + +//---------------------------------------------------------------------------------------- +void nsSimpleCharString::operator = (const char* inString) +//---------------------------------------------------------------------------------------- +{ + if (inString) + CopyFrom(inString, strlen(inString)); + else + SetToEmpty(); +} // nsSimpleCharString::operator = + +//---------------------------------------------------------------------------------------- +void nsSimpleCharString::operator = (const nsString& inString) +//---------------------------------------------------------------------------------------- +{ + PRUint32 len = inString.Length(); + ReallocData(len); + if (!mData) + return; + inString.ToCString(mData->mString, len + 1); +} // nsSimpleCharString::operator = + +//---------------------------------------------------------------------------------------- +void nsSimpleCharString::operator = (const nsSimpleCharString& inOther) +//---------------------------------------------------------------------------------------- +{ + if (mData == inOther.mData) + return; + ReleaseData(); + mData = inOther.mData; + AddRefData(); +} // nsSimpleCharString::operator = + +//---------------------------------------------------------------------------------------- +void nsSimpleCharString::operator += (const char* inOther) +//---------------------------------------------------------------------------------------- +{ + if (!inOther) + return; + int newLength = Length() + strlen(inOther); + ReallocData(newLength); + strcat(mData->mString, inOther); +} // nsSimpleCharString::operator = + +//---------------------------------------------------------------------------------------- +nsSimpleCharString nsSimpleCharString::operator + (const char* inOther) const +//---------------------------------------------------------------------------------------- +{ + nsSimpleCharString result(*this); + result += inOther; + return result; +} // nsSimpleCharString::operator = + +//---------------------------------------------------------------------------------------- +void nsSimpleCharString::Catenate(const char* inString1, const char* inString2) +//---------------------------------------------------------------------------------------- +{ + if (!inString2) + { + *this += inString1; + return; + } + int newLength = Length() + strlen(inString1) + strlen(inString2); + ReallocData(newLength); + strcat(mData->mString, inString1); + strcat(mData->mString, inString2); +} // nsSimpleCharString::operator = + +//---------------------------------------------------------------------------------------- +void nsSimpleCharString::CopyFrom(const char* inData, PRUint32 inLength) +//---------------------------------------------------------------------------------------- +{ + if (!inData) + return; + ReallocData(inLength); + if (!mData) + return; + if (inLength != 0) { + memcpy(mData->mString, inData, inLength); + } + mData->mString[inLength] = '\0'; +} // nsSimpleCharString::CopyFrom + +//---------------------------------------------------------------------------------------- +void nsSimpleCharString::SetToEmpty() +//---------------------------------------------------------------------------------------- +{ + ReleaseData(); +} // nsSimpleCharString::SetToEmpty + +//---------------------------------------------------------------------------------------- +void nsSimpleCharString::Unescape() +//---------------------------------------------------------------------------------------- +{ + if (!mData) + return; + ReallocData(mData->mLength); + if (!mData) + return; + nsUnescape(mData->mString); + mData->mLength = strlen(mData->mString); +} // nsSimpleCharString::Unescape + + +//---------------------------------------------------------------------------------------- +void nsSimpleCharString::AddRefData() +//---------------------------------------------------------------------------------------- +{ + if (mData) + ++mData->mRefCount; +} // nsSimpleCharString::AddRefData + +//---------------------------------------------------------------------------------------- +void nsSimpleCharString::ReleaseData() +//---------------------------------------------------------------------------------------- +{ + if (!mData) + return; + NS_ASSERTION(mData->mRefCount > 0, "String deleted too many times!"); + if (--mData->mRefCount == 0) + PR_Free(mData); + mData = nsnull; +} // nsSimpleCharString::ReleaseData + +//---------------------------------------------------------------------------------------- +inline PRUint32 CalculateAllocLength(PRUint32 logicalLength) +// Round up to the next multiple of 256. +//---------------------------------------------------------------------------------------- +{ + return ((1 + (logicalLength >> 8)) << 8); +} + +//---------------------------------------------------------------------------------------- +void nsSimpleCharString::ReallocData(PRUint32 inLength) +// Reallocate mData to a new length. Since this presumably precedes a change to the string, +// we want to detach ourselves if the data is shared by another string, even if the length +// requested would not otherwise require a reallocation. +//---------------------------------------------------------------------------------------- +{ + PRUint32 newAllocLength = CalculateAllocLength(inLength); + PRUint32 oldAllocLength = CalculateAllocLength(Length()); + if (mData) + { + NS_ASSERTION(mData->mRefCount > 0, "String deleted too many times!"); + if (mData->mRefCount == 1) + { + // We are the sole owner, so just change its length, if necessary. + if (newAllocLength > oldAllocLength) + mData = (Data*)PR_Realloc(mData, newAllocLength + sizeof(Data)); + mData->mLength = inLength; + mData->mString[inLength] = '\0'; // we may be truncating + return; + } + } + PRUint32 copyLength = Length(); + if (inLength < copyLength) + copyLength = inLength; + Data* newData = (Data*)PR_Malloc(newAllocLength + sizeof(Data)); + // If data was already allocated when we get to here, then we are cloning the data + // from a shared pointer. + if (mData) + { + memcpy(newData, mData, sizeof(Data) + copyLength); + mData->mRefCount--; // Say goodbye + } + else + newData->mString[0] = '\0'; + + mData = newData; + mData->mRefCount = 1; + mData->mLength = inLength; +} // nsSimpleCharString::ReleaseData + + +//======================================================================================== +NS_NAMESPACE nsFileSpecHelpers +//======================================================================================== +{ + enum + { kMaxFilenameLength = 31 // should work on Macintosh, Unix, and Win32. + , kMaxAltDigitLength = 5 + , kMaxCoreLeafNameLength = (kMaxFilenameLength - (kMaxAltDigitLength + 1)) + }; +#if !defined(XP_MAC) + NS_NAMESPACE_PROTOTYPE void Canonify(nsSimpleCharString& ioPath, PRBool inMakeDirs); + NS_NAMESPACE_PROTOTYPE void MakeAllDirectories(const char* inPath, int mode); +#endif +#if defined(XP_WIN) || defined(XP_OS2) + NS_NAMESPACE_PROTOTYPE void NativeToUnix(nsSimpleCharString& ioPath); + NS_NAMESPACE_PROTOTYPE void UnixToNative(nsSimpleCharString& ioPath); +#endif +} NS_NAMESPACE_END + +//---------------------------------------------------------------------------------------- +nsresult ns_file_convert_result(PRInt32 nativeErr) +//---------------------------------------------------------------------------------------- +{ + return nativeErr ? + NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_FILES,((nativeErr)&0xFFFF)) + : NS_OK; +} + +//---------------------------------------------------------------------------------------- +void nsSimpleCharString::LeafReplace(char inSeparator, const char* inLeafName) +//---------------------------------------------------------------------------------------- +{ + // Find the existing leaf name + if (IsEmpty()) + return; + if (!inLeafName) + { + SetToEmpty(); + return; + } + char* chars = mData->mString; + char* lastSeparator = GetLastSeparator(chars, inSeparator); + int oldLength = Length(); + PRBool trailingSeparator = (lastSeparator + 1 == chars + oldLength); + if (trailingSeparator) + { + char savedCh = *lastSeparator; + char *savedLastSeparator = lastSeparator; + *lastSeparator = '\0'; + lastSeparator = GetLastSeparator(chars, inSeparator); + *savedLastSeparator = savedCh; + } + if (lastSeparator) + lastSeparator++; // point at the trailing string + else + lastSeparator = chars; // the full monty + + PRUint32 savedLastSeparatorOffset = (lastSeparator - chars); + int newLength = + (lastSeparator - chars) + strlen(inLeafName) + (trailingSeparator != 0); + ReallocData(newLength); + + chars = mData->mString; // it might have moved. + chars[savedLastSeparatorOffset] = '\0'; // strip the current leaf name + + strcat(chars, inLeafName); + if (trailingSeparator) + { + // If the original ended in a slash, then the new one should, too. + char sepStr[2] = "/"; + *sepStr = inSeparator; + strcat(chars, sepStr); + } +} // nsSimpleCharString::LeafReplace + +//---------------------------------------------------------------------------------------- +char* nsSimpleCharString::GetLeaf(char inSeparator) const +// Returns a pointer to an allocated string representing the leaf. +//---------------------------------------------------------------------------------------- +{ + if (IsEmpty()) + return nsnull; + + char* chars = mData->mString; + const char* lastSeparator = GetLastSeparator(chars, inSeparator); + // If there was no separator, then return a copy of our path. + if (!lastSeparator) + return nsCRT::strdup(*this); + + // So there's at least one separator. What's just after it? + // If the separator was not the last character, return the trailing string. + const char* leafPointer = lastSeparator + 1; + if (*leafPointer) + return nsCRT::strdup(leafPointer); + + // So now, separator was the last character. Poke in a null instead. + *(char*)lastSeparator = '\0'; // Should use const_cast, but Unix has old compiler. + leafPointer = GetLastSeparator(chars, inSeparator); + char* result = leafPointer ? nsCRT::strdup(++leafPointer) : nsCRT::strdup(chars); + // Restore the poked null before returning. + *(char*)lastSeparator = inSeparator; +#if defined(XP_WIN) || defined(XP_OS2) + // If it's a drive letter use the colon notation. + if (!leafPointer && result[1] == '|' && result[2] == 0) + result[1] = ':'; +#endif + return result; +} // nsSimpleCharString::GetLeaf + + +#if 0 +#pragma mark - +#endif + +#if (defined(XP_UNIX) || defined(XP_WIN) || defined(XP_OS2) || defined(XP_BEOS)) + +//---------------------------------------------------------------------------------------- +void nsFileSpecHelpers::MakeAllDirectories(const char* inPath, int mode) +// Make the path a valid one by creating all the intermediate directories. Does NOT +// make the leaf into a directory. This should be a unix path. +//---------------------------------------------------------------------------------------- +{ + if (!inPath) + return; + + char* pathCopy = nsCRT::strdup( inPath ); + if (!pathCopy) + return; + + const char kSeparator = '/'; // I repeat: this should be a unix-style path. + const int kSkipFirst = 1; + +#if defined(XP_WIN) || defined(XP_OS2) + // Either this is a relative path, or we ensure that it has + // a drive letter specifier. + NS_ASSERTION( pathCopy[0] != '/' || (pathCopy[1] && (pathCopy[2] == '|' || pathCopy[2] == '/')), + "Not a UNC path and no drive letter!" ); +#endif + char* currentStart = pathCopy; + char* currentEnd = strchr(currentStart + kSkipFirst, kSeparator); + if (currentEnd) + { + nsFileSpec spec; + *currentEnd = '\0'; + +#if defined(XP_WIN) || defined(XP_OS2) + /* + if we have a drive letter path, we must make sure that the inital path has a '/' on it, or + Canonify will turn "/c|" into a path relative to the running executable. + */ + if (pathCopy[0] == '/' && pathCopy[1] && pathCopy[2] == '|') + { + char* startDir = (char*)PR_Malloc(strlen(pathCopy) + 2); + strcpy(startDir, pathCopy); + strcat(startDir, "/"); + + spec = nsFilePath(startDir, PR_FALSE); + + PR_Free(startDir); + } + else + { + // move after server name and share name in UNC path + if (pathCopy[0] == '/' && + currentEnd == currentStart+kSkipFirst) + { + *currentEnd = '/'; + currentStart = strchr(pathCopy+2, kSeparator); + currentStart = strchr(currentStart+1, kSeparator); + currentEnd = strchr(currentStart+1, kSeparator); + if (currentEnd) + *currentEnd = '\0'; + } + spec = nsFilePath(pathCopy, PR_FALSE); + } +#else + spec = nsFilePath(pathCopy, PR_FALSE); +#endif + do + { + // If the node doesn't exist, and it is not the initial node in a full path, + // then make a directory (We cannot make the initial (volume) node). + if (!spec.Exists() && *currentStart != kSeparator) + spec.CreateDirectory(mode); + + currentStart = ++currentEnd; + currentEnd = strchr(currentStart, kSeparator); + if (!currentEnd) + break; + + *currentEnd = '\0'; + + spec += currentStart; // "lengthen" the path, adding the next node. + } while (currentEnd); + } + nsCRT::free(pathCopy); +} // nsFileSpecHelpers::MakeAllDirectories + +#endif // XP_UNIX || XP_WIN || XP_OS2 || XP_BEOS + +#if 0 +#pragma mark - +#endif + +#if defined(XP_WIN) +#include "nsFileSpecWin.cpp" // Windows-specific implementations +#elif defined(XP_MAC) +//#include "nsFileSpecMac.cpp" // Macintosh-specific implementations +// we include the .cpp file in the project now. +#elif defined(XP_BEOS) +#include "nsFileSpecBeOS.cpp" // BeOS-specific implementations +#elif defined(XP_UNIX) || defined(XP_MACOSX) +#include "nsFileSpecUnix.cpp" // Unix-specific implementations +#elif defined(XP_OS2) +#include "nsFileSpecOS2.cpp" // OS/2-specific implementations +#endif + +//======================================================================================== +// nsFileURL implementation +//======================================================================================== + +#if !defined(XP_MAC) +//---------------------------------------------------------------------------------------- +nsFileURL::nsFileURL(const char* inString, PRBool inCreateDirs) +//---------------------------------------------------------------------------------------- +{ + if (!inString) + return; + NS_ASSERTION(strstr(inString, kFileURLPrefix) == inString, "Not a URL!"); + // Make canonical and absolute. Since it's a parameter to this constructor, + // inString is escaped. We want to make an nsFilePath, which requires + // an unescaped string. + nsSimpleCharString unescapedPath(inString + kFileURLPrefixLength); + unescapedPath.Unescape(); + nsFilePath path(unescapedPath, inCreateDirs); + *this = path; +} // nsFileURL::nsFileURL +#endif + +#if !defined(XP_MAC) +//---------------------------------------------------------------------------------------- +nsFileURL::nsFileURL(const nsString& inString, PRBool inCreateDirs) +//---------------------------------------------------------------------------------------- +{ + NS_LossyConvertUCS2toASCII cstring(inString); + if (!inString.Length()) + return; + NS_ASSERTION(strstr(cstring.get(), kFileURLPrefix) == cstring.get(), + "Not a URL!"); + // Make canonical and absolute. Since it's a parameter to this constructor, + // inString is escaped. We want to make an nsFilePath, which requires + // an unescaped string. + nsSimpleCharString unescapedPath(cstring.get() + kFileURLPrefixLength); + unescapedPath.Unescape(); + nsFilePath path(unescapedPath, inCreateDirs); + *this = path; +} // nsFileURL::nsFileURL +#endif + +//---------------------------------------------------------------------------------------- +nsFileURL::nsFileURL(const nsFileURL& inOther) +//---------------------------------------------------------------------------------------- +: mURL(inOther.mURL) +#if defined(XP_MAC) +, mFileSpec(inOther.GetFileSpec()) +#endif +{ +} // nsFileURL::nsFileURL + +#if !defined(XP_MAC) +//---------------------------------------------------------------------------------------- +nsFileURL::nsFileURL(const nsFilePath& inOther) +//---------------------------------------------------------------------------------------- +{ + *this = inOther; +} // nsFileURL::nsFileURL +#endif + +#if !defined(XP_MAC) +//---------------------------------------------------------------------------------------- +nsFileURL::nsFileURL(const nsFileSpec& inOther) +//---------------------------------------------------------------------------------------- +{ + *this = inOther; +} // nsFileURL::nsFileURL +#endif + +//---------------------------------------------------------------------------------------- +nsFileURL::~nsFileURL() +//---------------------------------------------------------------------------------------- +{ +} + +#if !defined(XP_MAC) +//---------------------------------------------------------------------------------------- +void nsFileURL::operator = (const char* inString) +//---------------------------------------------------------------------------------------- +{ + // XXX is this called by nsFileSpecImpl.cpp::SetURLString? + // if so, there's a bug... + + mURL = inString; + NS_ASSERTION(strstr(inString, kFileURLPrefix) == inString, "Not a URL!"); +} // nsFileURL::operator = +#endif + +//---------------------------------------------------------------------------------------- +void nsFileURL::operator +=(const char* inRelativeUnixPath) +//---------------------------------------------------------------------------------------- +{ + char* escapedPath = nsEscape(inRelativeUnixPath, url_Path); + mURL += escapedPath; + nsCRT::free(escapedPath); +#if defined(XP_MAC) + mFileSpec += inRelativeUnixPath; +#endif +} // nsFileURL::operator += + +//---------------------------------------------------------------------------------------- +nsFileURL nsFileURL::operator +(const char* inRelativeUnixPath) const +//---------------------------------------------------------------------------------------- +{ + nsFileURL result(*this); + result += inRelativeUnixPath; + return result; +} // nsFileURL::operator + + +//---------------------------------------------------------------------------------------- +void nsFileURL::operator = (const nsFileURL& inOther) +//---------------------------------------------------------------------------------------- +{ + mURL = inOther.mURL; +#if defined(XP_MAC) + mFileSpec = inOther.GetFileSpec(); +#endif +} // nsFileURL::operator = + +#if !defined(XP_MAC) +//---------------------------------------------------------------------------------------- +void nsFileURL::operator = (const nsFilePath& inOther) +//---------------------------------------------------------------------------------------- +{ + mURL = kFileURLPrefix; + char* original = (char*)(const char*)inOther; // we shall modify, but restore. + if (!original || !*original) return; +#if defined(XP_WIN) || defined(XP_OS2) + // because we don't want to escape the '|' character, change it to a letter. + // Note that a UNC path will not have a '|' character. + char oldchar = original[2]; + original[2] = 'x'; + char* escapedPath = nsEscape(original, url_Path); + original[2] = escapedPath[2] = oldchar; // restore it +#else + char* escapedPath = nsEscape(original, url_Path); +#endif + if (escapedPath) + mURL += escapedPath; + nsCRT::free(escapedPath); +} // nsFileURL::operator = +#endif + +#if !defined(XP_MAC) +//---------------------------------------------------------------------------------------- +void nsFileURL::operator = (const nsFileSpec& inOther) +//---------------------------------------------------------------------------------------- +{ + *this = nsFilePath(inOther); + if (mURL[mURL.Length() - 1] != '/' && inOther.IsDirectory()) + mURL += "/"; +} // nsFileURL::operator = +#endif + +#if 0 +#pragma mark - +#endif + +//======================================================================================== +// nsFilePath implementation +//======================================================================================== + +//---------------------------------------------------------------------------------------- +nsFilePath::nsFilePath(const nsFilePath& inPath) +//---------------------------------------------------------------------------------------- + : mPath(inPath.mPath) +#if defined(XP_MAC) + , mFileSpec(inPath.mFileSpec) +#endif +{ +} + +#if !defined(XP_MAC) +//---------------------------------------------------------------------------------------- +nsFilePath::nsFilePath(const char* inString, PRBool inCreateDirs) +//---------------------------------------------------------------------------------------- +: mPath(inString) +{ + if (mPath.IsEmpty()) + return; + + NS_ASSERTION(strstr(inString, kFileURLPrefix) != inString, "URL passed as path"); + +#if defined(XP_WIN) || defined(XP_OS2) + nsFileSpecHelpers::UnixToNative(mPath); +#endif + // Make canonical and absolute. + nsFileSpecHelpers::Canonify(mPath, inCreateDirs); +#if defined(XP_WIN) || defined(XP_OS2) + // Assert native path is of one of these forms: + // - regular: X:\some\path + // - UNC: \\some_machine\some\path + NS_ASSERTION( mPath[1] == ':' || (mPath[0] == '\\' && mPath[1] == '\\'), + "unexpected canonical path" ); + nsFileSpecHelpers::NativeToUnix(mPath); +#endif +} +#endif + +#if !defined(XP_MAC) +//---------------------------------------------------------------------------------------- +nsFilePath::nsFilePath(const nsString& inString, PRBool inCreateDirs) +//---------------------------------------------------------------------------------------- +: mPath(inString) +{ + if (mPath.IsEmpty()) + return; + + NS_ASSERTION(strstr((const char*)mPath, kFileURLPrefix) != (const char*)mPath, "URL passed as path"); +#if defined(XP_WIN) || defined(XP_OS2) + nsFileSpecHelpers::UnixToNative(mPath); +#endif + // Make canonical and absolute. + nsFileSpecHelpers::Canonify(mPath, inCreateDirs); +#if defined(XP_WIN) || defined(XP_OS2) + NS_ASSERTION( mPath[1] == ':' || (mPath[0] == '\\' && mPath[1] == '\\'), + "unexpected canonical path" ); + nsFileSpecHelpers::NativeToUnix(mPath); +#endif +} +#endif + +#if !defined(XP_MAC) +//---------------------------------------------------------------------------------------- +nsFilePath::nsFilePath(const nsFileURL& inOther) +//---------------------------------------------------------------------------------------- +{ + mPath = (const char*)inOther.mURL + kFileURLPrefixLength; + mPath.Unescape(); +} +#endif + +#if (defined XP_UNIX || defined XP_BEOS) +//---------------------------------------------------------------------------------------- +nsFilePath::nsFilePath(const nsFileSpec& inOther) +//---------------------------------------------------------------------------------------- +: mPath(inOther.mPath) +{ +} +#endif // XP_UNIX + +//---------------------------------------------------------------------------------------- +nsFilePath::~nsFilePath() +//---------------------------------------------------------------------------------------- +{ +} + +#if (defined XP_UNIX || defined XP_BEOS) +//---------------------------------------------------------------------------------------- +void nsFilePath::operator = (const nsFileSpec& inOther) +//---------------------------------------------------------------------------------------- +{ + // XXX bug here, again if. + + mPath = inOther.mPath; +} +#endif // XP_UNIX + +#if !defined(XP_MAC) +//---------------------------------------------------------------------------------------- +void nsFilePath::operator = (const char* inString) +//---------------------------------------------------------------------------------------- +{ + + NS_ASSERTION(strstr(inString, kFileURLPrefix) != inString, "URL passed as path"); + mPath = inString; + if (mPath.IsEmpty()) + return; +#if defined(XP_WIN) || defined(XP_OS2) + nsFileSpecHelpers::UnixToNative(mPath); +#endif + // Make canonical and absolute. + nsFileSpecHelpers::Canonify(mPath, PR_FALSE /* XXX? */); +#if defined(XP_WIN) || defined(XP_OS2) + nsFileSpecHelpers::NativeToUnix(mPath); +#endif +} +#endif // XP_MAC + +#if !defined(XP_MAC) +//---------------------------------------------------------------------------------------- +void nsFilePath::operator = (const nsFileURL& inOther) +//---------------------------------------------------------------------------------------- +{ + mPath = (const char*)nsFilePath(inOther); +} +#endif + +//---------------------------------------------------------------------------------------- +void nsFilePath::operator = (const nsFilePath& inOther) +//---------------------------------------------------------------------------------------- +{ + mPath = inOther.mPath; +#if defined(XP_MAC) + mFileSpec = inOther.GetFileSpec(); +#endif +} + +//---------------------------------------------------------------------------------------- +void nsFilePath::operator +=(const char* inRelativeUnixPath) +//---------------------------------------------------------------------------------------- +{ + NS_ASSERTION(inRelativeUnixPath, "Attempt append relative path with null path"); + + char* escapedPath = nsEscape(inRelativeUnixPath, url_Path); + mPath += escapedPath; + nsCRT::free(escapedPath); +#if defined(XP_MAC) + mFileSpec += inRelativeUnixPath; +#endif +} // nsFilePath::operator += + +//---------------------------------------------------------------------------------------- +nsFilePath nsFilePath::operator +(const char* inRelativeUnixPath) const +//---------------------------------------------------------------------------------------- +{ + NS_ASSERTION(inRelativeUnixPath, "Attempt append relative path with null path"); + + nsFilePath resultPath(*this); + resultPath += inRelativeUnixPath; + return resultPath; +} // nsFilePath::operator + + + +#if 0 +#pragma mark - +#endif + +//======================================================================================== +// nsFileSpec implementation +//======================================================================================== + +#if !defined(XP_MAC) +//---------------------------------------------------------------------------------------- +nsFileSpec::nsFileSpec() +//---------------------------------------------------------------------------------------- +: mError(NS_OK) // XXX shouldn't this be NS_ERROR_NOT_INITIALIZED? +{ +// NS_ASSERTION(0, "nsFileSpec is unsupported - use nsIFile!"); +} + +//---------------------------------------------------------------------------------------- +void nsFileSpec::Clear() +//---------------------------------------------------------------------------------------- +{ + mPath.SetToEmpty(); + mError = NS_ERROR_NOT_INITIALIZED; +} + +#endif + +//---------------------------------------------------------------------------------------- +nsFileSpec::~nsFileSpec() +//---------------------------------------------------------------------------------------- +{ + // mPath cleans itself up +} + +//---------------------------------------------------------------------------------------- +nsFileSpec::nsFileSpec(const nsPersistentFileDescriptor& inDescriptor) +//---------------------------------------------------------------------------------------- +{ + *this = inDescriptor; +} + +//---------------------------------------------------------------------------------------- +nsFileSpec::nsFileSpec(const nsFileURL& inURL) +//---------------------------------------------------------------------------------------- +{ + *this = nsFilePath(inURL); // convert to unix path first +} + +//---------------------------------------------------------------------------------------- +void nsFileSpec::MakeUnique(const char* inSuggestedLeafName) +//---------------------------------------------------------------------------------------- +{ + if (inSuggestedLeafName && *inSuggestedLeafName) + SetLeafName(inSuggestedLeafName); + + MakeUnique(); +} // nsFileSpec::MakeUnique + +//---------------------------------------------------------------------------------------- +void nsFileSpec::MakeUnique() +//---------------------------------------------------------------------------------------- +{ + if (!Exists()) + return; + + char* leafName = GetLeafName(); + if (!leafName) + return; + + char* lastDot = strrchr(leafName, '.'); + char* suffix = ""; + if (lastDot) + { + suffix = nsCRT::strdup(lastDot); // include '.' + *lastDot = '\0'; // strip suffix and dot. + } + const int kMaxRootLength + = nsFileSpecHelpers::kMaxCoreLeafNameLength - strlen(suffix) - 1; + if ((int)strlen(leafName) > (int)kMaxRootLength) + leafName[kMaxRootLength] = '\0'; + for (short indx = 1; indx < 1000 && Exists(); indx++) + { + // start with "Picture-1.jpg" after "Picture.jpg" exists + char newName[nsFileSpecHelpers::kMaxFilenameLength + 1]; + sprintf(newName, "%s-%d%s", leafName, indx, suffix); + SetLeafName(newName); + } + if (*suffix) + nsCRT::free(suffix); + nsCRT::free(leafName); +} // nsFileSpec::MakeUnique + +//---------------------------------------------------------------------------------------- +void nsFileSpec::operator = (const nsFileURL& inURL) +//---------------------------------------------------------------------------------------- +{ + *this = nsFilePath(inURL); // convert to unix path first +} + +//---------------------------------------------------------------------------------------- +void nsFileSpec::operator = (const nsPersistentFileDescriptor& inDescriptor) +//---------------------------------------------------------------------------------------- +{ + + nsCAutoString data; + inDescriptor.GetData(data); + +#if defined (XP_MAC) || defined(XP_MACOSX) + // Decode descriptor into a Handle (which is actually an AliasHandle) + char* decodedData = PL_Base64Decode(data.get(), data.Length(), nsnull); + Handle aliasH = nsnull; + mError = NS_FILE_RESULT(::PtrToHand(decodedData, &aliasH, (data.Length() * 3) / 4)); + PR_Free(decodedData); + if (NS_FAILED(mError)) + return; // not enough memory? +#endif + +#if defined(XP_MAC) + Boolean changed; + mError = NS_FILE_RESULT(::ResolveAlias(nsnull, (AliasHandle)aliasH, &mSpec, &changed)); + DisposeHandle((Handle) aliasH); + mPath.SetToEmpty(); +#elif defined(XP_MACOSX) + Boolean changed; + FSRef fileRef; + mError = NS_FILE_RESULT(::FSResolveAlias(nsnull, (AliasHandle)aliasH, &fileRef, &changed)); + ::DisposeHandle(aliasH); + + UInt8 pathBuf[PATH_MAX]; + mError = NS_FILE_RESULT(::FSRefMakePath(&fileRef, pathBuf, PATH_MAX)); + if (NS_FAILED(mError)) + return; + mPath = (const char*)pathBuf; +#else + mPath = data.get(); + mError = NS_OK; +#endif +} + +//======================================================================================== +// UNIX & WIN nsFileSpec implementation +//======================================================================================== + +#if (defined XP_UNIX || defined XP_BEOS) +//---------------------------------------------------------------------------------------- +nsFileSpec::nsFileSpec(const nsFilePath& inPath) +//---------------------------------------------------------------------------------------- +: mPath((const char*)inPath) +, mError(NS_OK) +{ +// NS_ASSERTION(0, "nsFileSpec is unsupported - use nsIFile!"); +} + +//---------------------------------------------------------------------------------------- +void nsFileSpec::operator = (const nsFilePath& inPath) +//---------------------------------------------------------------------------------------- +{ + mPath = (const char*)inPath; + mError = NS_OK; +} +#endif //XP_UNIX + +#if (defined(XP_UNIX) || defined(XP_WIN) || defined(XP_OS2) || defined(XP_BEOS)) +//---------------------------------------------------------------------------------------- +nsFileSpec::nsFileSpec(const nsFileSpec& inSpec) +//---------------------------------------------------------------------------------------- +: mPath(inSpec.mPath) +, mError(NS_OK) +{ +// NS_ASSERTION(0, "nsFileSpec is unsupported - use nsIFile!"); +} + +//---------------------------------------------------------------------------------------- +nsFileSpec::nsFileSpec(const char* inString, PRBool inCreateDirs) +//---------------------------------------------------------------------------------------- +: mPath(inString) +, mError(NS_OK) +{ +// NS_ASSERTION(0, "nsFileSpec is unsupported - use nsIFile!"); + // Make canonical and absolute. + nsFileSpecHelpers::Canonify(mPath, inCreateDirs); +} + +//---------------------------------------------------------------------------------------- +nsFileSpec::nsFileSpec(const nsString& inString, PRBool inCreateDirs) +//---------------------------------------------------------------------------------------- +: mPath(inString) +, mError(NS_OK) +{ +// NS_ASSERTION(0, "nsFileSpec is unsupported - use nsIFile!"); + // Make canonical and absolute. + nsFileSpecHelpers::Canonify(mPath, inCreateDirs); +} + +//---------------------------------------------------------------------------------------- +void nsFileSpec::operator = (const nsFileSpec& inSpec) +//---------------------------------------------------------------------------------------- +{ + mPath = inSpec.mPath; + mError = inSpec.Error(); +} + +//---------------------------------------------------------------------------------------- +void nsFileSpec::operator = (const char* inString) +//---------------------------------------------------------------------------------------- +{ + mPath = inString; + // Make canonical and absolute. + nsFileSpecHelpers::Canonify(mPath, PR_FALSE /* XXX? */); + mError = NS_OK; +} +#endif //XP_UNIX,XP_WIN,XP_OS2,XP_BEOS + +//---------------------------------------------------------------------------------------- +nsFileSpec nsFileSpec::operator + (const char* inRelativePath) const +//---------------------------------------------------------------------------------------- +{ + NS_ASSERTION(inRelativePath, "Attempt to append name with a null string"); + + nsFileSpec resultSpec = *this; + resultSpec += inRelativePath; + return resultSpec; +} // nsFileSpec::operator + + +//---------------------------------------------------------------------------------------- +PRBool nsFileSpec::operator == (const nsFileSpec& inOther) const +//---------------------------------------------------------------------------------------- +{ + +#if defined(XP_MAC) + if ( inOther.mSpec.vRefNum == mSpec.vRefNum && + inOther.mSpec.parID == mSpec.parID && + EqualString(inOther.mSpec.name, mSpec.name, false, true)) + return PR_TRUE; +#else + PRBool amEmpty = mPath.IsEmpty(); + PRBool heEmpty = inOther.mPath.IsEmpty(); + if (amEmpty) // we're the same if he's empty... + return heEmpty; + if (heEmpty) // ('cuz I'm not...) + return PR_FALSE; + + nsSimpleCharString str = mPath; + nsSimpleCharString inStr = inOther.mPath; + + // Length() is size of buffer, not length of string + PRUint32 strLast = str.Length() - 1, inLast = inStr.Length() - 1; +#if defined(XP_WIN) || defined(XP_OS2) +#define DIR_SEPARATOR '\\' // XXX doesn't NSPR have this? + /* windows does not care about case. */ +#ifdef XP_OS2 +#define DIR_STRCMP strcmp +#else +#define DIR_STRCMP _stricmp +#endif +#else +#define DIR_SEPARATOR '/' +#if defined(VMS) +#define DIR_STRCMP strcasecmp +#else +#define DIR_STRCMP strcmp +#endif +#endif + + if(str[strLast] == DIR_SEPARATOR) + str[strLast] = '\0'; + + if(inStr[inLast] == DIR_SEPARATOR) + inStr[inLast] = '\0'; + + if (DIR_STRCMP(str, inStr ) == 0) + return PR_TRUE; +#undef DIR_SEPARATOR +#undef DIR_STRCMP +#endif + return PR_FALSE; +} + +//---------------------------------------------------------------------------------------- +PRBool nsFileSpec::operator != (const nsFileSpec& inOther) const +//---------------------------------------------------------------------------------------- +{ + return (! (*this == inOther) ); +} + +#if !defined(XP_MAC) +//---------------------------------------------------------------------------------------- +// This is the only automatic conversion to const char* +// that is provided, and it allows the +// path to be "passed" to NSPR file routines. This practice +// is VERY EVIL and should only be used to support legacy +// code. Using it guarantees bugs on Macintosh. The path is NOT allocated, so do +// not even think of deleting (or freeing) it. +const char* nsFileSpec::GetCString() const +//---------------------------------------------------------------------------------------- +{ + return mPath; +} +#endif + +//---------------------------------------------------------------------------------------- +// Is our spec a child of the provided parent? +PRBool nsFileSpec::IsChildOf(nsFileSpec &possibleParent) +//---------------------------------------------------------------------------------------- +{ + nsFileSpec iter = *this, parent; +#ifdef DEBUG + int depth = 0; +#endif + while (1) { +#ifdef DEBUG + // sanity + NS_ASSERTION(depth < 100, "IsChildOf has lost its little mind"); + if (depth > 100) + return PR_FALSE; +#endif + if (iter == possibleParent) + return PR_TRUE; + + iter.GetParent(parent); // shouldn't this be an error on parent? + if (iter.Failed()) + return PR_FALSE; + + if (iter == parent) // hit bottom + return PR_FALSE; + + iter = parent; +#ifdef DEBUG + depth++; +#endif + } + + // not reached, but I bet some compiler will whine + return PR_FALSE; +} + +#if 0 +#pragma mark - +#endif + +//======================================================================================== +// class nsPersistentFileDescriptor +//======================================================================================== + +//---------------------------------------------------------------------------------------- +nsPersistentFileDescriptor::nsPersistentFileDescriptor(const nsPersistentFileDescriptor& inDesc) +//---------------------------------------------------------------------------------------- + : mDescriptorString(inDesc.mDescriptorString) +{ +} // nsPersistentFileDescriptor::nsPersistentFileDescriptor + +//---------------------------------------------------------------------------------------- +void nsPersistentFileDescriptor::operator = (const nsPersistentFileDescriptor& inDesc) +//---------------------------------------------------------------------------------------- +{ + mDescriptorString = inDesc.mDescriptorString; +} // nsPersistentFileDescriptor::operator = + +//---------------------------------------------------------------------------------------- +nsPersistentFileDescriptor::nsPersistentFileDescriptor(const nsFileSpec& inSpec) +//---------------------------------------------------------------------------------------- +{ + *this = inSpec; +} // nsPersistentFileDescriptor::nsPersistentFileDescriptor + +//---------------------------------------------------------------------------------------- +void nsPersistentFileDescriptor::operator = (const nsFileSpec& inSpec) +//---------------------------------------------------------------------------------------- +{ +#if defined(XP_MAC) + if (inSpec.Error()) + return; + AliasHandle aliasH; + OSErr err = NewAlias(nil, inSpec.GetFSSpecPtr(), &aliasH); + if (err != noErr) + return; + + PRUint32 bytes = GetHandleSize((Handle) aliasH); + HLock((Handle) aliasH); + char* buf = PL_Base64Encode((const char*)*aliasH, bytes, nsnull); + DisposeHandle((Handle) aliasH); + + mDescriptorString = buf; + PR_Free(buf); +#elif defined(XP_MACOSX) + if (inSpec.Error()) + return; + + FSRef fileRef; + Boolean isDir; + OSErr err = ::FSPathMakeRef((const UInt8*)inSpec.GetCString(), &fileRef, &isDir); + if (err != noErr) + return; + + AliasHandle aliasH; + err = ::FSNewAlias(nsnull, &fileRef, &aliasH); + if (err != noErr) + return; + + PRUint32 bytes = ::GetHandleSize((Handle) aliasH); + ::HLock((Handle)aliasH); + char* buf = PL_Base64Encode((const char*)*aliasH, bytes, nsnull); + ::DisposeHandle((Handle) aliasH); + + mDescriptorString = buf; + PR_Free(buf); +#else + mDescriptorString = inSpec.GetCString(); +#endif // XP_MAC +} // nsPersistentFileDescriptor::operator = + +//---------------------------------------------------------------------------------------- +nsPersistentFileDescriptor::~nsPersistentFileDescriptor() +//---------------------------------------------------------------------------------------- +{ +} // nsPersistentFileDescriptor::~nsPersistentFileDescriptor + +//---------------------------------------------------------------------------------------- +void nsPersistentFileDescriptor::GetData(nsAFlatCString& outData) const +//---------------------------------------------------------------------------------------- +{ + outData.Assign(mDescriptorString, mDescriptorString.Length()); +} + +//---------------------------------------------------------------------------------------- +void nsPersistentFileDescriptor::SetData(const nsAFlatCString& inData) +//---------------------------------------------------------------------------------------- +{ + mDescriptorString.CopyFrom(inData.get(), inData.Length()); +} + +//---------------------------------------------------------------------------------------- +void nsPersistentFileDescriptor::SetData(const char* inData, PRInt32 inSize) +//---------------------------------------------------------------------------------------- +{ + mDescriptorString.CopyFrom(inData, inSize); +} + +//======================================================================================== +// class nsNSPRPath +//======================================================================================== + +//---------------------------------------------------------------------------------------- +nsNSPRPath::operator const char*() const +// NSPR expects a UNIX path on unix and Macintosh, but a native path on windows. NSPR +// cannot be changed, so we have to do the dirty work. +//---------------------------------------------------------------------------------------- +{ +#if defined(XP_WIN) || defined(XP_OS2) + if (!modifiedNSPRPath) + { + // If this is the first call, initialize modifiedNSPRPath. Start by cloning + // mFilePath, but strip the leading separator, if present + const char* unixPath = (const char*)mFilePath; + if (!unixPath) + return nsnull; + + ((nsNSPRPath*)this)->modifiedNSPRPath + = nsCRT::strdup(*unixPath == '/' ? unixPath + 1: unixPath); + + // Replace the bar + if (modifiedNSPRPath[1] == '|') + modifiedNSPRPath[1] = ':'; + + // Remove the ending separator only if it is not the last separator + int len = strlen(modifiedNSPRPath); + if (modifiedNSPRPath[len - 1 ] == '/' && modifiedNSPRPath[len - 2 ] != ':') + modifiedNSPRPath[len - 1 ] = '\0'; + } + return modifiedNSPRPath; +#else + return (const char*)mFilePath; +#endif +} + +//---------------------------------------------------------------------------------------- +nsNSPRPath::~nsNSPRPath() +//---------------------------------------------------------------------------------------- +{ +#if defined(XP_WIN) || defined(XP_OS2) + if (modifiedNSPRPath) + nsCRT::free(modifiedNSPRPath); +#endif +} + + +nsresult +NS_FileSpecToIFile(nsFileSpec* fileSpec, nsILocalFile* *result) +{ + nsresult rv; + + nsCOMPtr file(do_CreateInstance(NS_LOCAL_FILE_CONTRACTID)); + + if (!file) return NS_ERROR_FAILURE; + +#if defined(XP_MAC) + { + FSSpec spec = fileSpec->GetFSSpec(); + nsCOMPtr psmAppMacFile = do_QueryInterface(file, &rv); + if (NS_FAILED(rv)) return rv; + rv = psmAppMacFile->InitWithFSSpec(&spec); + if (NS_FAILED(rv)) return rv; + file = do_QueryInterface(psmAppMacFile, &rv); + } +#else + // XP_MACOSX: do this for OS X to preserve long filenames + rv = file->InitWithNativePath(nsDependentCString(fileSpec->GetNativePathCString())); +#endif + if (NS_FAILED(rv)) return rv; + + *result = file; + NS_ADDREF(*result); + return NS_OK; +} + + + + diff --git a/src/libs/xpcom18a4/xpcom/obsolete/nsFileSpec.h b/src/libs/xpcom18a4/xpcom/obsolete/nsFileSpec.h new file mode 100644 index 00000000..53fa6c1a --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/obsolete/nsFileSpec.h @@ -0,0 +1,782 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + THESE CLASSES ARE DEPRECATED AND UNSUPPORTED! USE |nsIFile| and |nsILocalFile|. + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + + + + + + + + + + +// First checked in on 98/11/20 by John R. McMullen in the wrong directory. +// Checked in again 98/12/04. +// Polished version 98/12/08. + +//======================================================================================== +// +// Classes defined: +// +// nsFilePath, nsFileURL, nsFileSpec, nsPersistentFileDescriptor +// nsDirectoryIterator. +// +// Q. How should I represent files at run time? +// A. Use nsFileSpec. Using char* will lose information on some platforms. +// +// Q. Then what are nsFilePath and nsFileURL for? +// A. Only when you need a char* parameter for legacy code. +// +// Q. How should I represent files in a persistent way (eg, in a disk file)? +// A. Use nsPersistentFileDescriptor. Convert to and from nsFileSpec at run time. +// +// This suite provides the following services: +// +// 1. Encapsulates all platform-specific file details, so that files can be +// described correctly without any platform #ifdefs +// +// 2. Type safety. This will fix the problems that used to occur because people +// confused file paths. They used to use const char*, which could mean three +// or four different things. Bugs were introduced as people coded, right up +// to the moment Communicator 4.5 shipped. +// +// 3. Used in conjunction with nsFileStream.h (q.v.), this supports all the power +// and readability of the ansi stream syntax. +// +// Basic example: +// +// nsFilePath myPath("/Development/iotest.txt"); +// +// nsOutputFileStream testStream(nsFileSpec(myPath)); +// testStream << "Hello World" << nsEndl; +// +// 4. Handy methods for manipulating file specifiers safely, e.g. MakeUnique(), +// SetLeafName(), Exists(). +// +// 5. Easy cross-conversion. +// +// Examples: +// +// Initialize a URL from a string +// +// nsFileURL fileURL("file:///Development/MPW/MPW%20Shell"); +// +// Initialize a Unix-style path from a URL +// +// nsFilePath filePath(fileURL); +// +// Initialize a file spec from a URL +// +// nsFileSpec fileSpec(fileURL); +// +// Make the spec unique. +// +// fileSpec.MakeUnique(); +// +// Assign the spec to a URL (causing conversion) +// +// fileURL = fileSpec; +// +// Assign a unix path using a string +// +// filePath = "/Development/MPW/SysErrs.err"; +// +// Assign to a file spec using a unix path (causing conversion). +// +// fileSpec = filePath; +// +// Make this unique. +// +// fileSpec.MakeUnique(); +// +// 6. Fixes a bug that have been there for a long time, and +// is inevitable if you use NSPR alone, where files are described as paths. +// +// The problem affects platforms (Macintosh) in which a path does not fully +// specify a file, because two volumes can have the same name. This +// is solved by holding a "private" native file spec inside the +// nsFilePath and nsFileURL classes, which is used when appropriate. +// +//======================================================================================== + +#ifndef _FILESPEC_H_ +#define _FILESPEC_H_ + +#include "xpcomobsolete.h" +#include "nsError.h" +#include "nsString.h" +#include "nsReadableUtils.h" +#include "nsCRT.h" +#include "prtypes.h" + +//======================================================================================== +// Compiler-specific macros, as needed +//======================================================================================== +#if !defined(NS_USING_NAMESPACE) && (defined(__MWERKS__) || defined(_MSC_VER)) +#define NS_USING_NAMESPACE +#endif + +#ifdef NS_USING_NAMESPACE + +#define NS_NAMESPACE_PROTOTYPE +#define NS_NAMESPACE namespace +#define NS_NAMESPACE_END +#define NS_EXPLICIT explicit +#else + +#define NS_NAMESPACE_PROTOTYPE static +#define NS_NAMESPACE struct +#define NS_NAMESPACE_END ; +#define NS_EXPLICIT + +#endif +//=========================== End Compiler-specific macros =============================== + +#include "nsILocalFile.h" +#include "nsCOMPtr.h" + +#if defined(XP_MAC) +#include +#include "nsILocalFileMac.h" +#elif defined(XP_UNIX) || defined(XP_BEOS) +#include +#elif defined(XP_WIN) + +// This clashes with some of the Win32 system headers (specifically, +// winbase.h). Hopefully they'll have been included first; else we may +// have problems. We could include winbase.h before doing this; +// unfortunately, it's bring in too much crap and'd slow stuff down +// more than it's worth doing. +#ifdef CreateDirectory +#undef CreateDirectory +#endif + +#include "prio.h" +#elif defined(XP_OS2) +#define INCL_DOS +#define INCL_DOSERRORS +#define INCL_WIN +#define INCL_GPI +#include +#include "prio.h" +#endif + +//======================================================================================== +// Here are the allowable ways to describe a file. +//======================================================================================== + +class nsFileSpec; // Preferred. For i/o use nsInputFileStream, nsOutputFileStream +class nsFilePath; +class nsFileURL; +class nsNSPRPath; // This can be passed to NSPR file I/O routines, if you must. +class nsPersistentFileDescriptor; // Used for storage across program launches. + +#define kFileURLPrefix "file://" +#define kFileURLPrefixLength (7) + +class nsOutputStream; +class nsInputStream; +class nsIOutputStream; +class nsIInputStream; +class nsOutputFileStream; +class nsInputFileStream; +class nsOutputConsoleStream; + +class nsIUnicodeEncoder; +class nsIUnicodeDecoder; + +//======================================================================================== +// Conversion of native file errors to nsresult values. These are really only for use +// in the file module, clients of this interface shouldn't really need them. +// Error results returned from this interface have, in the low-order 16 bits, +// native errors that are masked to 16 bits. Assumption: a native error of 0 is success +// on all platforms. Note the way we define this using an inline function. This +// avoids multiple evaluation if people go NS_FILE_RESULT(function_call()). +#define NS_FILE_RESULT(x) ns_file_convert_result((PRInt32)x) +nsresult ns_file_convert_result(PRInt32 nativeErr); +#define NS_FILE_FAILURE NS_FILE_RESULT(-1) + +//======================================================================================== +class nsSimpleCharString +// An envelope for char*: reference counted. Used internally by all the nsFileSpec +// classes below. +//======================================================================================== +{ +public: + nsSimpleCharString(); + nsSimpleCharString(const char*); + nsSimpleCharString(const nsString&); + nsSimpleCharString(const nsSimpleCharString&); + nsSimpleCharString(const char* inData, PRUint32 inLength); + + ~nsSimpleCharString(); + + void operator = (const char*); + void operator = (const nsString&); + void operator = (const nsSimpleCharString&); + + operator const char*() const { return mData ? mData->mString : 0; } + operator char* () + { + ReallocData(Length()); // requires detaching if shared... + return mData ? mData->mString : 0; + } + PRBool operator == (const char*); + PRBool operator == (const nsString&); + PRBool operator == (const nsSimpleCharString&); + + void operator += (const char* inString); + nsSimpleCharString operator + (const char* inString) const; + + char operator [](int i) const { return mData ? mData->mString[i] : '\0'; } + char& operator [](int i) + { + if (i >= (int)Length()) + ReallocData((PRUint32)i + 1); + return mData->mString[i]; // caveat appelator + } + char& operator [](unsigned int i) { return (*this)[(int)i]; } + + void Catenate(const char* inString1, const char* inString2); + + void SetToEmpty(); + PRBool IsEmpty() const { return Length() == 0; } + + PRUint32 Length() const { return mData ? mData->mLength : 0; } + void SetLength(PRUint32 inLength) { ReallocData(inLength); } + void CopyFrom(const char* inData, PRUint32 inLength); + void LeafReplace(char inSeparator, const char* inLeafName); + char* GetLeaf(char inSeparator) const; // use PR_Free() + void Unescape(); + +protected: + + void AddRefData(); + void ReleaseData(); + void ReallocData(PRUint32 inLength); + + //-------------------------------------------------- + // Data + //-------------------------------------------------- + +protected: + + struct Data { + int mRefCount; + PRUint32 mLength; + char mString[1]; + }; + Data* mData; +}; // class nsSimpleCharString + +//======================================================================================== +class NS_COM_OBSOLETE nsFileSpec +// This is whatever each platform really prefers to describe files as. Declared first +// because the other two types have an embedded nsFileSpec object. +//======================================================================================== +{ + public: + nsFileSpec(); + + // These two meathods take *native* file paths. + NS_EXPLICIT nsFileSpec(const char* inNativePath, PRBool inCreateDirs = PR_FALSE); + NS_EXPLICIT nsFileSpec(const nsString& inNativePath, PRBool inCreateDirs = PR_FALSE); + + + NS_EXPLICIT nsFileSpec(const nsFilePath& inPath); + NS_EXPLICIT nsFileSpec(const nsFileURL& inURL); + nsFileSpec(const nsFileSpec& inPath); + virtual ~nsFileSpec(); + + // These two operands take *native* file paths. + void operator = (const char* inNativePath); + + void operator = (const nsFilePath& inPath); + void operator = (const nsFileURL& inURL); + void operator = (const nsFileSpec& inOther); + void operator = (const nsPersistentFileDescriptor& inOther); + + PRBool operator ==(const nsFileSpec& inOther) const; + PRBool operator !=(const nsFileSpec& inOther) const; + + + // Returns a native path, and allows the + // path to be "passed" to legacy code. This practice + // is VERY EVIL and should only be used to support legacy + // code. Using it guarantees bugs on Macintosh. + // The path is cached and freed by the nsFileSpec destructor + // so do not delete (or free) it. See also nsNSPRPath below, + // if you really must pass a string to PR_OpenFile(). + // Doing so will introduce two automatic bugs. + const char* GetCString() const; + + // Same as GetCString (please read the comments). + // Do not try to free this! + operator const char* () const { return GetCString(); } + + // Same as GetCString (please read the comments). + // Do not try to free this! + const char* GetNativePathCString() const { return GetCString(); } + + PRBool IsChildOf(nsFileSpec &possibleParent); + +#if defined(XP_MAC) + // For Macintosh people, this is meant to be useful in its own right as a C++ version + // of the FSSpec struct. + nsFileSpec( + short vRefNum, + long parID, + ConstStr255Param name, + PRBool resolveAlias = PR_TRUE); + + nsFileSpec(const FSSpec& inSpec, PRBool resolveAlias = PR_TRUE); + void operator = (const FSSpec& inSpec); + + operator FSSpec* () { return &mSpec; } + operator const FSSpec* const () { return &mSpec; } + operator FSSpec& () { return mSpec; } + operator const FSSpec& () const { return mSpec; } + + const FSSpec& GetFSSpec() const { return mSpec; } + FSSpec& GetFSSpec() { return mSpec; } + ConstFSSpecPtr GetFSSpecPtr() const { return &mSpec; } + FSSpecPtr GetFSSpecPtr() { return &mSpec; } + void MakeAliasSafe(); + void MakeUnique(ConstStr255Param inSuggestedLeafName); + StringPtr GetLeafPName() { return mSpec.name; } + ConstStr255Param GetLeafPName() const { return mSpec.name; } + + OSErr GetCatInfo(CInfoPBRec& outInfo) const; + + OSErr SetFileTypeAndCreator(OSType type, OSType creator); + OSErr GetFileTypeAndCreator(OSType* type, OSType* creator); + +#endif // end of Macintosh utility methods. + + PRBool Valid() const { return NS_SUCCEEDED(Error()); } + nsresult Error() const + { +#if !defined(XP_MAC) + if (mPath.IsEmpty() && NS_SUCCEEDED(mError)) + ((nsFileSpec*)this)->mError = NS_ERROR_NOT_INITIALIZED; +#endif + return mError; + } + PRBool Failed() const { return (PRBool)NS_FAILED(Error()); } + + //-------------------------------------------------- + // Queries and path algebra. These do not modify the disk. + //-------------------------------------------------- + + char* GetLeafName() const; // Allocated. Use nsCRT::free(). + // inLeafName can be a relative path, so this allows + // one kind of concatenation of "paths". + void SetLeafName(const char* inLeafName); + + // Return the filespec of the parent directory. Used + // in conjunction with GetLeafName(), this lets you + // parse a path into a list of node names. Beware, + // however, that the top node is still not a name, + // but a spec. Volumes on Macintosh can have identical + // names. Perhaps could be used for an operator --() ? + void GetParent(nsFileSpec& outSpec) const; + + + // ie nsFileSpec::TimeStamp. This is 32 bits now, + // but might change, eg, to a 64-bit class. So use the + // typedef, and use a streaming operator to convert + // to a string, so that your code won't break. It's + // none of your business what the number means. Don't + // rely on the implementation. + typedef PRUint32 TimeStamp; + + // This will return different values on different + // platforms, even for the same file (eg, on a server). + // But if the platform is constant, it will increase after + // every file modification. + void GetModDate(TimeStamp& outStamp) const; + + PRBool ModDateChanged(const TimeStamp& oldStamp) const + { + TimeStamp newStamp; + GetModDate(newStamp); + return newStamp != oldStamp; + } + + PRUint32 GetFileSize() const; + PRInt64 GetDiskSpaceAvailable() const; + + nsFileSpec operator + (const char* inRelativeUnixPath) const; + + // Concatenate the relative path to this directory. + // Used for constructing the filespec of a descendant. + // This must be a directory for this to work. This differs + // from SetLeafName(), since the latter will work + // starting with a sibling of the directory and throws + // away its leaf information, whereas this one assumes + // this is a directory, and the relative path starts + // "below" this. + void operator += (const char* inRelativeUnixPath); + + + void MakeUnique(); + void MakeUnique(const char* inSuggestedLeafName); + + + PRBool IsDirectory() const; // More stringent than Exists() + PRBool IsFile() const; // More stringent than Exists() + PRBool Exists() const; + + PRBool IsHidden() const; + + PRBool IsSymlink() const; + + //-------------------------------------------------- + // Creation and deletion of objects. These can modify the disk. + //-------------------------------------------------- + + // Called for the spec of an alias. Modifies the spec to + // point to the original. Sets mError. + nsresult ResolveSymlink(PRBool& wasSymlink); + + void CreateDirectory(int mode = 0775 /* for unix */); + void CreateDir(int mode = 0775) { CreateDirectory(mode); } + // workaround for yet another VC++ bug with long identifiers. + void Delete(PRBool inRecursive) const; + nsresult Truncate(PRInt32 aNewLength) const; + void RecursiveCopy(nsFileSpec newDir) const; + + nsresult Rename(const char* inNewName); // not const: gets updated + nsresult CopyToDir(const nsFileSpec& inNewParentDirectory) const; + nsresult MoveToDir(const nsFileSpec& inNewParentDirectory); + nsresult Execute(const char* args) const; + + protected: + + //-------------------------------------------------- + // Data + //-------------------------------------------------- + + protected: + + // Clear the nsFileSpec contents, resetting it + // to the uninitialized state; + void Clear(); + + friend class nsFilePath; + friend class nsFileURL; + friend class nsDirectoryIterator; +#if defined(XP_MAC) + FSSpec mSpec; +#endif + nsSimpleCharString mPath; + nsresult mError; + +private: + NS_EXPLICIT nsFileSpec(const nsPersistentFileDescriptor& inURL); + +}; // class nsFileSpec + +// FOR HISTORICAL REASONS: + +typedef nsFileSpec nsNativeFileSpec; + +//======================================================================================== +class NS_COM_OBSOLETE nsFileURL +// This is an escaped string that looks like "file:///foo/bar/mumble%20fish". Since URLs +// are the standard way of doing things in mozilla, this allows a string constructor, +// which just stashes the string with no conversion. +//======================================================================================== +{ + public: + nsFileURL(const nsFileURL& inURL); + NS_EXPLICIT nsFileURL(const char* inURLString, PRBool inCreateDirs = PR_FALSE); + NS_EXPLICIT nsFileURL(const nsString& inURLString, PRBool inCreateDirs = PR_FALSE); + NS_EXPLICIT nsFileURL(const nsFilePath& inPath); + NS_EXPLICIT nsFileURL(const nsFileSpec& inPath); + virtual ~nsFileURL(); + +// nsString GetString() const { return mPath; } + // may be needed for implementation reasons, + // but should not provide a conversion constructor. + + void operator = (const nsFileURL& inURL); + void operator = (const char* inURLString); + void operator = (const nsString& inURLString) + { + *this = NS_LossyConvertUCS2toASCII(inURLString).get(); + } + void operator = (const nsFilePath& inOther); + void operator = (const nsFileSpec& inOther); + + void operator +=(const char* inRelativeUnixPath); + nsFileURL operator +(const char* inRelativeUnixPath) const; + operator const char* () const { return (const char*)mURL; } // deprecated. + const char* GetURLString() const { return (const char*)mURL; } + // Not allocated, so don't free it. + const char* GetAsString() const { return (const char*)mURL; } + // Not allocated, so don't free it. + +#if defined(XP_MAC) + // Accessor to allow quick assignment to a mFileSpec + const nsFileSpec& GetFileSpec() const { return mFileSpec; } +#endif + + //-------------------------------------------------- + // Data + //-------------------------------------------------- + + protected: + friend class nsFilePath; // to allow construction of nsFilePath + nsSimpleCharString mURL; + +#if defined(XP_MAC) + // Since the path on the macintosh does not uniquely specify a file (volumes + // can have the same name), stash the secret nsFileSpec, too. + nsFileSpec mFileSpec; +#endif +}; // class nsFileURL + +//======================================================================================== +class NS_COM_OBSOLETE nsFilePath +// This is a string that looks like "/foo/bar/mumble fish". Same as nsFileURL, but +// without the "file:// prefix", and NOT %20 ENCODED! Strings passed in must be +// valid unix-style paths in this format. +//======================================================================================== +{ + public: + nsFilePath(const nsFilePath& inPath); + NS_EXPLICIT nsFilePath(const char* inUnixPathString, PRBool inCreateDirs = PR_FALSE); + NS_EXPLICIT nsFilePath(const nsString& inUnixPathString, PRBool inCreateDirs = PR_FALSE); + NS_EXPLICIT nsFilePath(const nsFileURL& inURL); + NS_EXPLICIT nsFilePath(const nsFileSpec& inPath); + virtual ~nsFilePath(); + + + operator const char* () const { return mPath; } + // This will return a UNIX string. If you + // need a string that can be passed into + // NSPR, take a look at the nsNSPRPath class. + + void operator = (const nsFilePath& inPath); + void operator = (const char* inUnixPathString); + void operator = (const nsString& inUnixPathString) + { + *this = NS_LossyConvertUCS2toASCII(inUnixPathString).get(); + } + void operator = (const nsFileURL& inURL); + void operator = (const nsFileSpec& inOther); + + void operator +=(const char* inRelativeUnixPath); + nsFilePath operator +(const char* inRelativeUnixPath) const; + +#if defined(XP_MAC) + public: + // Accessor to allow quick assignment to a mFileSpec + const nsFileSpec& GetFileSpec() const { return mFileSpec; } +#endif + + //-------------------------------------------------- + // Data + //-------------------------------------------------- + + private: + + nsSimpleCharString mPath; +#if defined(XP_MAC) + // Since the path on the macintosh does not uniquely specify a file (volumes + // can have the same name), stash the secret nsFileSpec, too. + nsFileSpec mFileSpec; +#endif +}; // class nsFilePath + +//======================================================================================== +class nsPersistentFileDescriptor +// To save information about a file's location in another file, initialize +// one of these from your nsFileSpec, and then write this out to your output stream. +// To retrieve the info, create one of these, read its value from an input stream. +// and then make an nsFileSpec from it. +//======================================================================================== +{ + public: + nsPersistentFileDescriptor() {} + // For use prior to reading in from a stream + nsPersistentFileDescriptor(const nsPersistentFileDescriptor& inEncodedData); + virtual ~nsPersistentFileDescriptor(); + void operator = (const nsPersistentFileDescriptor& inEncodedData); + + // Conversions + NS_EXPLICIT nsPersistentFileDescriptor(const nsFileSpec& inSpec); + void operator = (const nsFileSpec& inSpec); + + // The following four functions are declared here (as friends). Their implementations + // are in mozilla/base/src/nsFileSpecStreaming.cpp. + + friend nsresult Read(nsIInputStream* aStream, nsPersistentFileDescriptor&); + friend nsresult Write(nsIOutputStream* aStream, const nsPersistentFileDescriptor&); + // writes the data to a file + friend NS_COM_OBSOLETE nsInputStream& operator >> (nsInputStream&, nsPersistentFileDescriptor&); + // reads the data from a file + friend NS_COM_OBSOLETE nsOutputStream& operator << (nsOutputStream&, const nsPersistentFileDescriptor&); + // writes the data to a file + friend class nsFileSpec; + + void GetData(nsAFlatCString& outData) const; + void SetData(const nsAFlatCString& inData); + void SetData(const char* inData, PRInt32 inSize); + + //-------------------------------------------------- + // Data + //-------------------------------------------------- + + protected: + + nsSimpleCharString mDescriptorString; + +}; // class nsPersistentFileDescriptor + +//======================================================================================== +class NS_COM_OBSOLETE nsDirectoryIterator +// Example: +// +// nsFileSpec parentDir(...); // directory over whose children we shall iterate +// for (nsDirectoryIterator i(parentDir, PR_FALSE); i.Exists(); i++) +// { +// // do something with i.Spec() +// } +// +// - or - +// +// for (nsDirectoryIterator i(parentDir, PR_TRUE); i.Exists(); i--) +// { +// // do something with i.Spec() +// } +// This one passed the PR_TRUE flag which will resolve any symlink encountered. +//======================================================================================== +{ + public: + nsDirectoryIterator( const nsFileSpec& parent, + PRBool resoveSymLinks); +#if !defined(XP_MAC) + // Macintosh currently doesn't allocate, so needn't clean up. + virtual ~nsDirectoryIterator(); +#endif + PRBool Exists() const { return mExists; } + nsDirectoryIterator& operator ++(); // moves to the next item, if any. + nsDirectoryIterator& operator ++(int) { return ++(*this); } // post-increment. + nsDirectoryIterator& operator --(); // moves to the previous item, if any. + nsDirectoryIterator& operator --(int) { return --(*this); } // post-decrement. + operator nsFileSpec&() { return mCurrent; } + + nsFileSpec& Spec() { return mCurrent; } + + private: + +#if defined(XP_MAC) + OSErr SetToIndex(); +#endif + + //-------------------------------------------------- + // Data + //-------------------------------------------------- + + private: + + nsFileSpec mCurrent; + PRBool mExists; + PRBool mResoveSymLinks; + +#if (defined(XP_UNIX) || defined(XP_BEOS) || defined (XP_WIN) || defined(XP_OS2)) + nsFileSpec mStarting; +#endif + +#if defined(XP_MAC) + short mVRefNum; + long mParID; + short mIndex; + short mMaxIndex; +#elif defined(XP_UNIX) || defined(XP_BEOS) + DIR* mDir; +#elif defined(XP_WIN) || defined(XP_OS2) + PRDir* mDir; // XXX why not use PRDir for Unix too? +#endif +}; // class nsDirectoryIterator + +//======================================================================================== +class NS_COM_OBSOLETE nsNSPRPath +// This class will allow you to pass any one of the nsFile* classes directly into NSPR +// without the need to worry about whether you have the right kind of filepath or not. +// It will also take care of cleaning up any allocated memory. +//======================================================================================== +{ +public: + NS_EXPLICIT nsNSPRPath(const nsFileSpec& inSpec) + : mFilePath(inSpec), modifiedNSPRPath(nsnull) {} + NS_EXPLICIT nsNSPRPath(const nsFileURL& inURL) + : mFilePath(inURL), modifiedNSPRPath(nsnull) {} + NS_EXPLICIT nsNSPRPath(const nsFilePath& inUnixPath) + : mFilePath(inUnixPath), modifiedNSPRPath(nsnull) {} + + virtual ~nsNSPRPath(); + + operator const char*() const; + // Returns the path + // that NSPR file routines expect on each platform. + // Concerning constness, this can modify + // modifiedNSPRPath, but it's really just "mutable". + + //-------------------------------------------------- + // Data + //-------------------------------------------------- + +private: + + nsFilePath mFilePath; + char* modifiedNSPRPath; // Currently used only on XP_WIN,XP_OS2 +}; // class nsNSPRPath + + +NS_COM_OBSOLETE nsresult NS_FileSpecToIFile(nsFileSpec* fileSpec, nsILocalFile* *result); + +#endif // _FILESPEC_H_ diff --git a/src/libs/xpcom18a4/xpcom/obsolete/nsFileSpecBeOS.cpp b/src/libs/xpcom18a4/xpcom/obsolete/nsFileSpecBeOS.cpp new file mode 100644 index 00000000..20a38f5e --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/obsolete/nsFileSpecBeOS.cpp @@ -0,0 +1,547 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +// This file is included by nsFileSpec.cpp, and includes the Unix-specific +// implementations. + +#include +#include +#include +#include +#include +#include +#include +#include "nsError.h" +#include "prio.h" /* for PR_Rename */ + +// BeOS specific headers +#include +#include +#include + +//---------------------------------------------------------------------------------------- +void nsFileSpecHelpers::Canonify(nsSimpleCharString& ioPath, PRBool inMakeDirs) +// Canonify, make absolute, and check whether directories exist +//---------------------------------------------------------------------------------------- +{ + if (ioPath.IsEmpty()) + return; + if (inMakeDirs) + { + const mode_t mode = 0700; + nsFileSpecHelpers::MakeAllDirectories((const char*)ioPath, mode); + } + char buffer[MAXPATHLEN]; + errno = 0; + *buffer = '\0'; + BEntry e((const char *)ioPath, true); + BPath p; + e.GetPath(&p); + ioPath = p.Path(); +} // nsFileSpecHelpers::Canonify + +//---------------------------------------------------------------------------------------- +void nsFileSpec::SetLeafName(const char* inLeafName) +//---------------------------------------------------------------------------------------- +{ + mPath.LeafReplace('/', inLeafName); +} // nsFileSpec::SetLeafName + +//---------------------------------------------------------------------------------------- +char* nsFileSpec::GetLeafName() const +//---------------------------------------------------------------------------------------- +{ + return mPath.GetLeaf('/'); +} // nsFileSpec::GetLeafName + +//---------------------------------------------------------------------------------------- +PRBool nsFileSpec::Exists() const +//---------------------------------------------------------------------------------------- +{ + struct stat st; + return !mPath.IsEmpty() && 0 == stat(mPath, &st); +} // nsFileSpec::Exists + +//---------------------------------------------------------------------------------------- +void nsFileSpec::GetModDate(TimeStamp& outStamp) const +//---------------------------------------------------------------------------------------- +{ + struct stat st; + if (!mPath.IsEmpty() && stat(mPath, &st) == 0) + outStamp = st.st_mtime; + else + outStamp = 0; +} // nsFileSpec::GetModDate + +//---------------------------------------------------------------------------------------- +PRUint32 nsFileSpec::GetFileSize() const +//---------------------------------------------------------------------------------------- +{ + struct stat st; + if (!mPath.IsEmpty() && stat(mPath, &st) == 0) + return (PRUint32)st.st_size; + return 0; +} // nsFileSpec::GetFileSize + +//---------------------------------------------------------------------------------------- +PRBool nsFileSpec::IsFile() const +//---------------------------------------------------------------------------------------- +{ + struct stat st; + return !mPath.IsEmpty() && stat(mPath, &st) == 0 && S_ISREG(st.st_mode); +} // nsFileSpec::IsFile + +//---------------------------------------------------------------------------------------- +PRBool nsFileSpec::IsDirectory() const +//---------------------------------------------------------------------------------------- +{ + struct stat st; + return !mPath.IsEmpty() && 0 == stat(mPath, &st) && S_ISDIR(st.st_mode); +} // nsFileSpec::IsDirectory + +//---------------------------------------------------------------------------------------- +PRBool nsFileSpec::IsHidden() const +//---------------------------------------------------------------------------------------- +{ + PRBool hidden = PR_TRUE; + char *leafname = GetLeafName(); + if (nsnull != leafname) + { + if ((!strcmp(leafname, ".")) || (!strcmp(leafname, ".."))) + { + hidden = PR_FALSE; + } + nsCRT::free(leafname); + } + return hidden; +} // nsFileSpec::IsHidden + +//---------------------------------------------------------------------------------------- +PRBool nsFileSpec::IsSymlink() const +//---------------------------------------------------------------------------------------- +{ + struct stat st; + if (!mPath.IsEmpty() && stat(mPath, &st) == 0 && S_ISLNK(st.st_mode)) + return PR_TRUE; + + return PR_FALSE; +} // nsFileSpec::IsSymlink + +//---------------------------------------------------------------------------------------- +nsresult nsFileSpec::ResolveSymlink(PRBool& wasAliased) +//---------------------------------------------------------------------------------------- +{ + wasAliased = PR_FALSE; + + char resolvedPath[MAXPATHLEN]; + int charCount = readlink(mPath, (char*)&resolvedPath, MAXPATHLEN); + if (0 < charCount) + { + if (MAXPATHLEN > charCount) + resolvedPath[charCount] = '\0'; + + wasAliased = PR_TRUE; + /* if it's not an absolute path, + replace the leaf with what got resolved */ + if (resolvedPath[0] != '/') { + SetLeafName(resolvedPath); + } + else { + mPath = (char*)resolvedPath; + } + + BEntry e((const char *)mPath, true); // traverse symlink + BPath p; + status_t err; + err = e.GetPath(&p); + NS_ASSERTION(err == B_OK, "realpath failed"); + + const char* canonicalPath = p.Path(); + if(err == B_OK) + mPath = (char*)canonicalPath; + else + return NS_ERROR_FAILURE; + } + return NS_OK; +} // nsFileSpec::ResolveSymlink + +//---------------------------------------------------------------------------------------- +void nsFileSpec::GetParent(nsFileSpec& outSpec) const +//---------------------------------------------------------------------------------------- +{ + outSpec.mPath = mPath; + char* chars = (char*)outSpec.mPath; + chars[outSpec.mPath.Length() - 1] = '\0'; // avoid trailing separator, if any + char* cp = strrchr(chars, '/'); + if (cp++) + outSpec.mPath.SetLength(cp - chars); // truncate. +} // nsFileSpec::GetParent + +//---------------------------------------------------------------------------------------- +void nsFileSpec::operator += (const char* inRelativePath) +//---------------------------------------------------------------------------------------- +{ + if (!inRelativePath || mPath.IsEmpty()) + return; + + char endChar = mPath[(int)(strlen(mPath) - 1)]; + if (endChar == '/') + mPath += "x"; + else + mPath += "/x"; + SetLeafName(inRelativePath); +} // nsFileSpec::operator += + +//---------------------------------------------------------------------------------------- +void nsFileSpec::CreateDirectory(int mode) +//---------------------------------------------------------------------------------------- +{ + // Note that mPath is canonical! + if (mPath.IsEmpty()) + return; + mkdir(mPath, mode); +} // nsFileSpec::CreateDirectory + +//---------------------------------------------------------------------------------------- +void nsFileSpec::Delete(PRBool inRecursive) const +// To check if this worked, call Exists() afterwards, see? +//---------------------------------------------------------------------------------------- +{ + if (IsDirectory()) + { + if (inRecursive) + { + for (nsDirectoryIterator i(*this, PR_FALSE); i.Exists(); i++) + { + nsFileSpec& child = (nsFileSpec&)i; + child.Delete(inRecursive); + } + } + rmdir(mPath); + } + else if (!mPath.IsEmpty()) + remove(mPath); +} // nsFileSpec::Delete + +//---------------------------------------------------------------------------------------- +void nsFileSpec::RecursiveCopy(nsFileSpec newDir) const +//---------------------------------------------------------------------------------------- +{ + if (IsDirectory()) + { + if (!(newDir.Exists())) + { + newDir.CreateDirectory(); + } + + for (nsDirectoryIterator i(*this, PR_FALSE); i.Exists(); i++) + { + nsFileSpec& child = (nsFileSpec&)i; + + if (child.IsDirectory()) + { + nsFileSpec tmpDirSpec(newDir); + + char *leafname = child.GetLeafName(); + tmpDirSpec += leafname; + nsCRT::free(leafname); + + child.RecursiveCopy(tmpDirSpec); + } + else + { + child.RecursiveCopy(newDir); + } + } + } + else if (!mPath.IsEmpty()) + { + nsFileSpec& filePath = (nsFileSpec&) *this; + + if (!(newDir.Exists())) + { + newDir.CreateDirectory(); + } + + filePath.CopyToDir(newDir); + } +} // nsFileSpec::RecursiveCopy + +//---------------------------------------------------------------------------------------- +nsresult nsFileSpec::Truncate(PRInt32 offset) const +//---------------------------------------------------------------------------------------- +{ + char* Path = nsCRT::strdup(mPath); + + int rv = truncate(Path, offset) ; + + nsCRT::free(Path) ; + + if(!rv) + return NS_OK ; + else + return NS_ERROR_FAILURE ; +} // nsFileSpec::Truncate + +//---------------------------------------------------------------------------------------- +nsresult nsFileSpec::Rename(const char* inNewName) +//---------------------------------------------------------------------------------------- +{ + // This function should not be used to move a file on disk. + if (mPath.IsEmpty() || strchr(inNewName, '/')) + return NS_FILE_FAILURE; + + char* oldPath = nsCRT::strdup(mPath); + + SetLeafName(inNewName); + + if (PR_Rename(oldPath, mPath) != NS_OK) + { + // Could not rename, set back to the original. + mPath = oldPath; + return NS_FILE_FAILURE; + } + + nsCRT::free(oldPath); + + return NS_OK; +} // nsFileSpec::Rename + +//---------------------------------------------------------------------------------------- +static int CrudeFileCopy(const char* in, const char* out) +//---------------------------------------------------------------------------------------- +{ + struct stat in_stat; + int stat_result = -1; + + char buf [1024]; + FILE *ifp, *ofp; + int rbytes, wbytes; + + if (!in || !out) + return -1; + + stat_result = stat (in, &in_stat); + + ifp = fopen (in, "r"); + if (!ifp) + { + return -1; + } + + ofp = fopen (out, "w"); + if (!ofp) + { + fclose (ifp); + return -1; + } + + while ((rbytes = fread (buf, 1, sizeof(buf), ifp)) > 0) + { + while (rbytes > 0) + { + if ( (wbytes = fwrite (buf, 1, rbytes, ofp)) < 0 ) + { + fclose (ofp); + fclose (ifp); + unlink(out); + return -1; + } + rbytes -= wbytes; + } + } + fclose (ofp); + fclose (ifp); + + if (stat_result == 0) + chmod (out, in_stat.st_mode & 0777); + + return 0; +} // nsFileSpec::Rename + +//---------------------------------------------------------------------------------------- +nsresult nsFileSpec::CopyToDir(const nsFileSpec& inParentDirectory) const +//---------------------------------------------------------------------------------------- +{ + // We can only copy into a directory, and (for now) can not copy entire directories + nsresult result = NS_FILE_FAILURE; + + if (inParentDirectory.IsDirectory() && (! IsDirectory() ) ) + { + char *leafname = GetLeafName(); + nsSimpleCharString destPath(inParentDirectory.GetCString()); + destPath += "/"; + destPath += leafname; + nsCRT::free(leafname); + result = NS_FILE_RESULT(CrudeFileCopy(GetCString(), destPath)); + } + return result; +} // nsFileSpec::CopyToDir + +//---------------------------------------------------------------------------------------- +nsresult nsFileSpec::MoveToDir(const nsFileSpec& inNewParentDirectory) +//---------------------------------------------------------------------------------------- +{ + // We can only copy into a directory, and (for now) can not copy entire directories + nsresult result = NS_FILE_FAILURE; + + if (inNewParentDirectory.IsDirectory() && !IsDirectory()) + { + char *leafname = GetLeafName(); + nsSimpleCharString destPath(inNewParentDirectory.GetCString()); + destPath += "/"; + destPath += leafname; + nsCRT::free(leafname); + + result = NS_FILE_RESULT(CrudeFileCopy(GetCString(), (const char*)destPath)); + if (result == NS_OK) + { + // cast to fix const-ness + ((nsFileSpec*)this)->Delete(PR_FALSE); + + *this = inNewParentDirectory + GetLeafName(); + } + } + return result; +} + +//---------------------------------------------------------------------------------------- +nsresult nsFileSpec::Execute(const char* inArgs ) const +//---------------------------------------------------------------------------------------- +{ + nsresult result = NS_FILE_FAILURE; + + if (!mPath.IsEmpty() && !IsDirectory()) + { + nsSimpleCharString fileNameWithArgs = mPath + " " + inArgs; + result = NS_FILE_RESULT(system(fileNameWithArgs)); + } + + return result; + +} // nsFileSpec::Execute + +//---------------------------------------------------------------------------------------- +PRInt64 nsFileSpec::GetDiskSpaceAvailable() const +//---------------------------------------------------------------------------------------- +{ + char curdir [MAXPATHLEN]; + if (!mPath || !*mPath) + { + (void) getcwd(curdir, MAXPATHLEN); + if (!curdir) + return ULONGLONG_MAX; /* hope for the best as we did in cheddar */ + } + else + sprintf(curdir, "%.200s", (const char*)mPath); + + BEntry e(curdir); + if(e.InitCheck() != B_OK) + return ULONGLONG_MAX; /* hope for the best as we did in cheddar */ + entry_ref ref; + e.GetRef(&ref); + BVolume v(ref.device); + +#ifdef DEBUG_DISK_SPACE + printf("DiskSpaceAvailable: %d bytes\n", space); +#endif + return v.FreeBytes(); +} // nsFileSpec::GetDiskSpace() + +//======================================================================================== +// nsDirectoryIterator +//======================================================================================== + +//---------------------------------------------------------------------------------------- +nsDirectoryIterator::nsDirectoryIterator( + const nsFileSpec& inDirectory +, PRBool resolveSymlinks) +//---------------------------------------------------------------------------------------- + : mCurrent(inDirectory) + , mStarting(inDirectory) + , mExists(PR_FALSE) + , mDir(nsnull) + , mResoveSymLinks(resolveSymlinks) +{ + mStarting += "sysygy"; // save off the starting directory + mCurrent += "sysygy"; // prepare the path for SetLeafName + mDir = opendir((const char*)nsFilePath(inDirectory)); + ++(*this); +} // nsDirectoryIterator::nsDirectoryIterator + +//---------------------------------------------------------------------------------------- +nsDirectoryIterator::~nsDirectoryIterator() +//---------------------------------------------------------------------------------------- +{ + if (mDir) + closedir(mDir); +} // nsDirectoryIterator::nsDirectoryIterator + +//---------------------------------------------------------------------------------------- +nsDirectoryIterator& nsDirectoryIterator::operator ++ () +//---------------------------------------------------------------------------------------- +{ + mExists = PR_FALSE; + if (!mDir) + return *this; + char* dot = "."; + char* dotdot = ".."; + struct dirent* entry = readdir(mDir); + if (entry && strcmp(entry->d_name, dot) == 0) + entry = readdir(mDir); + if (entry && strcmp(entry->d_name, dotdot) == 0) + entry = readdir(mDir); + if (entry) + { + mExists = PR_TRUE; + mCurrent = mStarting; // restore mCurrent to be the starting directory. ResolveSymlink() may have taken us to another directory + mCurrent.SetLeafName(entry->d_name); + if (mResoveSymLinks) + { + PRBool ignore; + mCurrent.ResolveSymlink(ignore); + } + } + return *this; +} // nsDirectoryIterator::operator ++ + +//---------------------------------------------------------------------------------------- +nsDirectoryIterator& nsDirectoryIterator::operator -- () +//---------------------------------------------------------------------------------------- +{ + return ++(*this); // can't do it backwards. +} // nsDirectoryIterator::operator -- diff --git a/src/libs/xpcom18a4/xpcom/obsolete/nsFileSpecImpl.cpp b/src/libs/xpcom18a4/xpcom/obsolete/nsFileSpecImpl.cpp new file mode 100644 index 00000000..b0e3cc15 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/obsolete/nsFileSpecImpl.cpp @@ -0,0 +1,879 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Pierre Phaneuf + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsFileSpecImpl.h"// Always first, to ensure that it compiles alone. + +#include "nsIFileStream.h" +#include "nsFileStream.h" + +#include "nsILocalFile.h" +#include "nsNativeCharsetUtils.h" + +#include "prmem.h" + +NS_IMPL_THREADSAFE_ISUPPORTS1(nsFileSpecImpl, nsIFileSpec) + +#ifdef NS_DEBUG +#define TEST_OUT_PTR(p) \ + if (!(p)) \ + return NS_ERROR_NULL_POINTER; +#else +#define TEST_OUT_PTR(p) +#endif + +//---------------------------------------------------------------------------------------- +nsFileSpecImpl::nsFileSpecImpl() +//---------------------------------------------------------------------------------------- + : mInputStream(nsnull) + , mOutputStream(nsnull) +{ +// NS_ASSERTION(0, "nsFileSpec is unsupported - use nsIFile!"); + +} + +//---------------------------------------------------------------------------------------- +nsFileSpecImpl::nsFileSpecImpl(const nsFileSpec& inSpec) +//---------------------------------------------------------------------------------------- + : mFileSpec(inSpec) + , mInputStream(nsnull) + , mOutputStream(nsnull) +{ +// NS_ASSERTION(0, "nsFileSpec is unsupported - use nsIFile!"); + +} + +//---------------------------------------------------------------------------------------- +nsFileSpecImpl::~nsFileSpecImpl() +//---------------------------------------------------------------------------------------- +{ + CloseStream(); +} + +//---------------------------------------------------------------------------------------- +/* static */ +nsresult nsFileSpecImpl::MakeInterface(const nsFileSpec& inSpec, nsIFileSpec** result) +//---------------------------------------------------------------------------------------- +{ + nsFileSpecImpl* it = new nsFileSpecImpl(inSpec); + if (!it) + return NS_ERROR_OUT_OF_MEMORY; + return it->QueryInterface(NS_GET_IID(nsIFileSpec), (void **) result); +} // nsFileSpecImpl::MakeInterface + +#define FILESPEC(ifilespec) ((nsFileSpecImpl*)ifilespec)->mFileSpec + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::FromFileSpec(const nsIFileSpec *original) +//---------------------------------------------------------------------------------------- +{ + if (original) { + nsresult rv = ((nsIFileSpec *)original)->GetFileSpec( &mFileSpec); + if (NS_SUCCEEDED( rv)) + return mFileSpec.Error(); + else + return( rv); + } + else + return( NS_ERROR_FAILURE); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::IsChildOf(nsIFileSpec *possibleParent, + PRBool *_retval) +{ + *_retval = mFileSpec.IsChildOf(FILESPEC(possibleParent)); + return mFileSpec.Error(); +} +//---------------------------------------------------------------------------------------- + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::GetURLString(char * *aURLString) +//---------------------------------------------------------------------------------------- +{ + TEST_OUT_PTR(aURLString) + if (mFileSpec.Failed()) + return mFileSpec.Error(); + nsFileURL url(mFileSpec); + *aURLString = nsCRT::strdup(url.GetURLString()); + if (!*aURLString) + return NS_ERROR_OUT_OF_MEMORY; + return NS_OK; +} // nsFileSpecImpl::GetURLString + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::SetURLString(const char * aURLString) +//---------------------------------------------------------------------------------------- +{ + mFileSpec = nsFileURL(aURLString); + return NS_OK; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::GetUnixStyleFilePath(char * *aUnixStyleFilePath) +//---------------------------------------------------------------------------------------- +{ + TEST_OUT_PTR(aUnixStyleFilePath) + if (mFileSpec.Failed()) + return mFileSpec.Error(); + nsFilePath path(mFileSpec); + *aUnixStyleFilePath = nsCRT::strdup((const char*) path); + if (!*aUnixStyleFilePath) + return NS_ERROR_OUT_OF_MEMORY; + return NS_OK; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::SetUnixStyleFilePath(const char * aUnixStyleFilePath) +//---------------------------------------------------------------------------------------- +{ + mFileSpec = nsFilePath(aUnixStyleFilePath); + return NS_OK; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::GetPersistentDescriptorString(char * *aPersistentDescriptorString) +//---------------------------------------------------------------------------------------- +{ + TEST_OUT_PTR(aPersistentDescriptorString) + if (mFileSpec.Failed()) + return mFileSpec.Error(); + nsPersistentFileDescriptor desc(mFileSpec); + nsCAutoString data; + desc.GetData(data); + *aPersistentDescriptorString = ToNewCString(data); + if (!*aPersistentDescriptorString) + return NS_ERROR_OUT_OF_MEMORY; + return NS_OK; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::SetPersistentDescriptorString(const char * aPersistentDescriptorString) +//---------------------------------------------------------------------------------------- +{ + nsPersistentFileDescriptor desc(mFileSpec); + desc.SetData(nsDependentCString(aPersistentDescriptorString)); + mFileSpec = desc; + return NS_OK; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::GetNativePath(char * *aNativePath) +//---------------------------------------------------------------------------------------- +{ + TEST_OUT_PTR(aNativePath) + if (mFileSpec.Failed()) + return mFileSpec.Error(); + *aNativePath = nsCRT::strdup(mFileSpec.GetNativePathCString()); + if (!*aNativePath) + return NS_ERROR_OUT_OF_MEMORY; + return NS_OK; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::SetNativePath(const char * aNativePath) +//---------------------------------------------------------------------------------------- +{ + mFileSpec = aNativePath; + return NS_OK; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::GetUnicodePath(nsAString & aUnicodePath) +//---------------------------------------------------------------------------------------- +{ + nsCAutoString native; + native = mFileSpec.GetNativePathCString(); + NS_CopyNativeToUnicode(native, aUnicodePath); + return NS_OK; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::SetUnicodePath(const nsAString & aUnicodePath) +//---------------------------------------------------------------------------------------- +{ + nsCAutoString native; + + NS_CopyUnicodeToNative(aUnicodePath, native); + mFileSpec = native.get(); + return NS_OK; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::GetNSPRPath(char * *aNSPRPath) +//---------------------------------------------------------------------------------------- +{ + TEST_OUT_PTR(aNSPRPath) + if (mFileSpec.Failed()) + return mFileSpec.Error(); + nsNSPRPath path(mFileSpec); + *aNSPRPath = nsCRT::strdup((const char*) path); + if (!*aNSPRPath) + return NS_ERROR_OUT_OF_MEMORY; + return NS_OK; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::Error() +//---------------------------------------------------------------------------------------- +{ + return mFileSpec.Error(); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::IsValid(PRBool *_retval) +//---------------------------------------------------------------------------------------- +{ + TEST_OUT_PTR(_retval) + *_retval = mFileSpec.Valid(); + return NS_OK; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::Failed(PRBool *_retval) +//---------------------------------------------------------------------------------------- +{ + *_retval = mFileSpec.Failed(); + return NS_OK; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::GetLeafName(char * *aLeafName) +//---------------------------------------------------------------------------------------- +{ + TEST_OUT_PTR(aLeafName) + *aLeafName = mFileSpec.GetLeafName(); + return mFileSpec.Error(); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::SetLeafName(const char * aLeafName) +//---------------------------------------------------------------------------------------- +{ + mFileSpec.SetLeafName(aLeafName); + return mFileSpec.Error(); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::GetParent(nsIFileSpec * *aParent) +//---------------------------------------------------------------------------------------- +{ + TEST_OUT_PTR(aParent) + nsFileSpec parent; + mFileSpec.GetParent(parent); + return MakeInterface(parent, aParent); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::MakeUnique() +//---------------------------------------------------------------------------------------- +{ + mFileSpec.MakeUnique(); + return mFileSpec.Error(); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::MakeUniqueWithSuggestedName(const char *suggestedName) +//---------------------------------------------------------------------------------------- +{ + mFileSpec.MakeUnique(suggestedName); + return mFileSpec.Error(); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::GetModDate(PRUint32 *aModDate) +//---------------------------------------------------------------------------------------- +{ + TEST_OUT_PTR(aModDate) + nsFileSpec::TimeStamp stamp; + mFileSpec.GetModDate(stamp); + *aModDate = stamp; + return mFileSpec.Error(); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::ModDateChanged(PRUint32 oldStamp, PRBool *_retval) +//---------------------------------------------------------------------------------------- +{ + TEST_OUT_PTR(_retval) + *_retval = mFileSpec.ModDateChanged(oldStamp); + return mFileSpec.Error(); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::IsDirectory(PRBool *_retval) +//---------------------------------------------------------------------------------------- +{ + TEST_OUT_PTR(_retval) + *_retval = mFileSpec.IsDirectory(); + return mFileSpec.Error(); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::IsFile(PRBool *_retval) +//---------------------------------------------------------------------------------------- +{ + TEST_OUT_PTR(_retval) + *_retval = mFileSpec.IsFile(); + return mFileSpec.Error(); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::Exists(PRBool *_retval) +//---------------------------------------------------------------------------------------- +{ + TEST_OUT_PTR(_retval) + *_retval = mFileSpec.Exists(); + return mFileSpec.Error(); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::IsHidden(PRBool *_retval) +//---------------------------------------------------------------------------------------- +{ + TEST_OUT_PTR(_retval) + *_retval = mFileSpec.IsHidden(); + return mFileSpec.Error(); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::IsSymlink(PRBool *_retval) +//---------------------------------------------------------------------------------------- +{ + TEST_OUT_PTR(_retval) + *_retval = mFileSpec.IsSymlink(); + return mFileSpec.Error(); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::ResolveSymlink() +//---------------------------------------------------------------------------------------- +{ + PRBool ignore; + return mFileSpec.ResolveSymlink(ignore); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::GetFileSize(PRUint32 *aFileSize) +//---------------------------------------------------------------------------------------- +{ + TEST_OUT_PTR(aFileSize) + *aFileSize = mFileSpec.GetFileSize(); + return mFileSpec.Error(); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::GetDiskSpaceAvailable(PRInt64 *aDiskSpaceAvailable) +//---------------------------------------------------------------------------------------- +{ + TEST_OUT_PTR(aDiskSpaceAvailable) + *aDiskSpaceAvailable = mFileSpec.GetDiskSpaceAvailable(); + return mFileSpec.Error(); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::AppendRelativeUnixPath(const char *relativePath) +//---------------------------------------------------------------------------------------- +{ + mFileSpec += relativePath; + return mFileSpec.Error(); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::Touch() +//---------------------------------------------------------------------------------------- +{ + // create an empty file, like the UNIX touch command. + nsresult rv; + rv = OpenStreamForWriting(); + if (NS_FAILED(rv)) return rv; + rv = CloseStream(); + return rv; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::CreateDir() +//---------------------------------------------------------------------------------------- +{ + mFileSpec.CreateDir(); + return mFileSpec.Error(); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::Delete(PRBool aRecursive) +//---------------------------------------------------------------------------------------- +{ + mFileSpec.Delete(aRecursive); + return mFileSpec.Error(); +} +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::Truncate(PRInt32 aNewLength) +//---------------------------------------------------------------------------------------- +{ + return mFileSpec.Truncate(aNewLength); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::Rename(const char *newLeafName) +//---------------------------------------------------------------------------------------- +{ + return mFileSpec.Rename(newLeafName); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::CopyToDir(const nsIFileSpec *newParentDir) +//---------------------------------------------------------------------------------------- +{ + return mFileSpec.CopyToDir(FILESPEC(newParentDir)); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::MoveToDir(const nsIFileSpec *newParentDir) +//---------------------------------------------------------------------------------------- +{ + return mFileSpec.MoveToDir(FILESPEC(newParentDir)); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::Execute(const char *args) +//---------------------------------------------------------------------------------------- +{ + return mFileSpec.Execute(args); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::OpenStreamForReading() +//---------------------------------------------------------------------------------------- +{ + if (mInputStream || mOutputStream) + return NS_ERROR_FAILURE; + return NS_NewTypicalInputFileStream((nsISupports**)&mInputStream, mFileSpec); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::OpenStreamForWriting() +//---------------------------------------------------------------------------------------- +{ + if (mInputStream || mOutputStream) + return NS_ERROR_FAILURE; + return NS_NewTypicalOutputFileStream((nsISupports**)&mOutputStream, mFileSpec); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::OpenStreamForReadingAndWriting() +//---------------------------------------------------------------------------------------- +{ + if (mInputStream || mOutputStream) + return NS_ERROR_FAILURE; + nsresult result = NS_NewTypicalInputFileStream((nsISupports**)&mInputStream, mFileSpec); + if (NS_SUCCEEDED(result)) + result = NS_NewTypicalOutputFileStream((nsISupports**)&mOutputStream, mFileSpec); + return result; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::CloseStream() +//---------------------------------------------------------------------------------------- +{ + NS_IF_RELEASE(mInputStream); + NS_IF_RELEASE(mOutputStream); + return NS_OK; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::IsStreamOpen(PRBool *_retval) +//---------------------------------------------------------------------------------------- +{ + TEST_OUT_PTR(_retval) + *_retval = (mInputStream || mOutputStream); + return NS_OK; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::GetInputStream(nsIInputStream** _retval) +//---------------------------------------------------------------------------------------- +{ + TEST_OUT_PTR(_retval) + if (!mInputStream) { + nsresult rv = OpenStreamForReading(); + if (NS_FAILED(rv)) return rv; + } + *_retval = mInputStream; + NS_IF_ADDREF(mInputStream); + return NS_OK; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::GetOutputStream(nsIOutputStream** _retval) +//---------------------------------------------------------------------------------------- +{ + TEST_OUT_PTR(_retval) + if (!mOutputStream) { + nsresult rv = OpenStreamForWriting(); + if (NS_FAILED(rv)) return rv; + } + *_retval = mOutputStream; + NS_IF_ADDREF(mOutputStream); + return NS_OK; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::SetFileContents(const char* inString) +//---------------------------------------------------------------------------------------- +{ + nsresult rv = OpenStreamForWriting(); + if (NS_FAILED(rv)) return rv; + PRInt32 count; + rv = Write(inString, PL_strlen(inString), &count); + nsresult rv2 = CloseStream(); + return NS_FAILED(rv) ? rv : rv2; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::GetFileContents(char** _retval) +//---------------------------------------------------------------------------------------- +{ + TEST_OUT_PTR(_retval) + *_retval = nsnull; + nsresult rv = OpenStreamForReading(); + if (NS_FAILED(rv)) return rv; + PRInt32 theSize; + rv = GetFileSize((PRUint32*)&theSize); + if (NS_SUCCEEDED(rv)) + rv = Read(_retval, theSize, &theSize); + if (NS_SUCCEEDED(rv)) + (*_retval)[theSize] = 0; + nsresult rv2 = CloseStream(); + return NS_FAILED(rv) ? rv : rv2; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::GetFileSpec(nsFileSpec *aFileSpec) +//---------------------------------------------------------------------------------------- +{ + TEST_OUT_PTR(aFileSpec) + *aFileSpec = mFileSpec; + return NS_OK; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::Equals(nsIFileSpec *spec, PRBool *result) +//---------------------------------------------------------------------------------------- +{ + nsresult rv; + + if (!result || !spec) return NS_ERROR_NULL_POINTER; + + nsFileSpec otherSpec; + + rv = spec->GetFileSpec(&otherSpec); + if (NS_FAILED(rv)) return rv; + + if (mFileSpec == otherSpec) { + *result = PR_TRUE; + } + else { + *result = PR_FALSE; + } + + return NS_OK; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::SetFromFileSpec(const nsFileSpec& aFileSpec) +//---------------------------------------------------------------------------------------- +{ + mFileSpec = aFileSpec; + return NS_OK; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::Eof(PRBool *_retval) +//---------------------------------------------------------------------------------------- +{ + TEST_OUT_PTR(_retval) + if (!mInputStream) + return NS_ERROR_NULL_POINTER; + nsInputFileStream s(mInputStream); + *_retval = s.eof(); + return NS_OK; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::Read(char** buffer, PRInt32 requestedCount, PRInt32 *_retval) +//---------------------------------------------------------------------------------------- +{ + TEST_OUT_PTR(_retval) + TEST_OUT_PTR(buffer) + if (!mInputStream) { + nsresult rv = OpenStreamForReading(); + if (NS_FAILED(rv)) return rv; + } + if (!*buffer) + *buffer = (char*)PR_Malloc(requestedCount + 1); + if (!mInputStream) + return NS_ERROR_NULL_POINTER; + nsInputFileStream s(mInputStream); + *_retval = s.read(*buffer, requestedCount); + return s.error(); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::ReadLine(char** line, PRInt32 bufferSize, PRBool *wasTruncated) +//---------------------------------------------------------------------------------------- +{ + TEST_OUT_PTR(wasTruncated) + TEST_OUT_PTR(line) + if (!mInputStream) { + nsresult rv = OpenStreamForReading(); + if (NS_FAILED(rv)) return rv; + } + if (!*line) + *line = (char*)PR_Malloc(bufferSize + 1); + if (!mInputStream) + return NS_ERROR_NULL_POINTER; + nsInputFileStream s(mInputStream); + *wasTruncated = !s.readline(*line, bufferSize); + return s.error(); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::Write(const char * data, PRInt32 requestedCount, PRInt32 *_retval) +//---------------------------------------------------------------------------------------- +{ + TEST_OUT_PTR(_retval) + //if (!mOutputStream) + // return NS_ERROR_NULL_POINTER; + if (!mOutputStream) { + nsresult rv = OpenStreamForWriting(); + if (NS_FAILED(rv)) + return rv; + } + nsOutputFileStream s(mOutputStream); + *_retval = s.write(data, requestedCount); + return s.error(); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::Flush() +//---------------------------------------------------------------------------------------- +{ + if (!mOutputStream) + return NS_ERROR_NULL_POINTER; + nsOutputFileStream s(mOutputStream); + s.flush(); + return s.error(); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::Seek(PRInt32 offset) +//---------------------------------------------------------------------------------------- +{ + nsresult result = NS_OK; + if (mOutputStream) + { + nsOutputFileStream os(mOutputStream); + os.seek(offset); + result = os.error(); + } + if (NS_SUCCEEDED(result) && mInputStream) + { + nsInputFileStream is(mInputStream); + is.seek(offset); + result = is.error(); + } + return result; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::Tell(PRInt32 *_retval) +//---------------------------------------------------------------------------------------- +{ + TEST_OUT_PTR(_retval) + if (!mInputStream) + return NS_ERROR_NULL_POINTER; + nsInputFileStream s(mInputStream); + *_retval = s.tell(); + return s.error(); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::EndLine() +//---------------------------------------------------------------------------------------- +{ + nsOutputFileStream s(mOutputStream); + s << nsEndl; + return s.error(); +} + +NS_IMPL_ISUPPORTS1(nsDirectoryIteratorImpl, nsIDirectoryIterator) + +//---------------------------------------------------------------------------------------- +nsDirectoryIteratorImpl::nsDirectoryIteratorImpl() +//---------------------------------------------------------------------------------------- + : mDirectoryIterator(nsnull) +{ +} + +//---------------------------------------------------------------------------------------- +nsDirectoryIteratorImpl::~nsDirectoryIteratorImpl() +//---------------------------------------------------------------------------------------- +{ + delete mDirectoryIterator; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsDirectoryIteratorImpl::Init(nsIFileSpec *parent, PRBool resolveSymlink) +//---------------------------------------------------------------------------------------- +{ + delete mDirectoryIterator; + mDirectoryIterator = new nsDirectoryIterator(FILESPEC(parent), resolveSymlink); + if (!mDirectoryIterator) + return NS_ERROR_OUT_OF_MEMORY; + return NS_OK; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsDirectoryIteratorImpl::Exists(PRBool *_retval) +//---------------------------------------------------------------------------------------- +{ + TEST_OUT_PTR(_retval) + if (!mDirectoryIterator) + return NS_ERROR_NULL_POINTER; + *_retval = mDirectoryIterator->Exists(); + return NS_OK; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsDirectoryIteratorImpl::Next() +//---------------------------------------------------------------------------------------- +{ + if (!mDirectoryIterator) + return NS_ERROR_NULL_POINTER; + (*mDirectoryIterator)++; + return NS_OK; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsDirectoryIteratorImpl::GetCurrentSpec(nsIFileSpec * *aCurrentSpec) +//---------------------------------------------------------------------------------------- +{ + if (!mDirectoryIterator) + return NS_ERROR_NULL_POINTER; + return nsFileSpecImpl::MakeInterface(mDirectoryIterator->Spec(), aCurrentSpec); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsDirectoryIteratorImpl::Create(nsISupports* outer, const nsIID& aIID, void* *aIFileSpec) +//---------------------------------------------------------------------------------------- +{ + if (aIFileSpec == NULL) + return NS_ERROR_NULL_POINTER; + + nsDirectoryIteratorImpl* it = new nsDirectoryIteratorImpl; + if (!it) + return NS_ERROR_OUT_OF_MEMORY; + + nsresult rv = it->QueryInterface(aIID, aIFileSpec); + if (NS_FAILED(rv)) + { + delete it; + return rv; + } + return rv; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::Create(nsISupports* outer, const nsIID& aIID, void* *aIFileSpec) +//---------------------------------------------------------------------------------------- +{ + if (aIFileSpec == NULL) + return NS_ERROR_NULL_POINTER; + + nsFileSpecImpl* it = new nsFileSpecImpl; + if (!it) + return NS_ERROR_OUT_OF_MEMORY; + + nsresult rv = it->QueryInterface(aIID, aIFileSpec); + if (NS_FAILED(rv)) + { + delete it; + return rv; + } + return rv; +} + +//---------------------------------------------------------------------------------------- +nsresult NS_NewFileSpecWithSpec(const nsFileSpec& aSrcFileSpec, nsIFileSpec **result) +//---------------------------------------------------------------------------------------- +{ + if (!result) + return NS_ERROR_NULL_POINTER; + + return nsFileSpecImpl::MakeInterface(aSrcFileSpec, result); +} + +//---------------------------------------------------------------------------------------- +nsresult NS_NewFileSpec(nsIFileSpec** result) +//---------------------------------------------------------------------------------------- +{ + return nsFileSpecImpl::Create(nsnull, NS_GET_IID(nsIFileSpec), (void**)result); +} + +//---------------------------------------------------------------------------------------- +nsresult NS_NewFileSpecFromIFile(nsIFile *aFile, nsIFileSpec **result) +//---------------------------------------------------------------------------------------- +{ + nsresult rv = nsFileSpecImpl::Create(nsnull, NS_GET_IID(nsIFileSpec), (void**)result); + if (NS_FAILED(rv)) return rv; + + nsCAutoString path; + rv = aFile->GetNativePath(path); + if (NS_FAILED(rv)) return rv; + + rv = (*result)->SetNativePath(path.get()); + if (NS_FAILED(rv)) + NS_RELEASE(*result); + return rv; +} + +//---------------------------------------------------------------------------------------- +nsresult NS_NewDirectoryIterator(nsIDirectoryIterator** result) +//---------------------------------------------------------------------------------------- +{ + return nsDirectoryIteratorImpl::Create(nsnull, NS_GET_IID(nsIDirectoryIterator), (void**)result); +} diff --git a/src/libs/xpcom18a4/xpcom/obsolete/nsFileSpecImpl.h b/src/libs/xpcom18a4/xpcom/obsolete/nsFileSpecImpl.h new file mode 100644 index 00000000..811749cb --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/obsolete/nsFileSpecImpl.h @@ -0,0 +1,116 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +#ifndef _FILESPECIMPL_H_ +#define _FILESPECIMPL_H_ + +#include "nscore.h" +#include "nsIFileSpec.h" +#include "nsFileSpec.h" + +//======================================================================================== +class NS_COM_OBSOLETE nsFileSpecImpl +//======================================================================================== + : public nsIFileSpec +{ + + public: + + NS_DECL_ISUPPORTS + + NS_DECL_NSIFILESPEC + + //---------------------- + // COM Cruft + //---------------------- + + static NS_METHOD Create(nsISupports* outer, const nsIID& aIID, void* *aIFileSpec); + + //---------------------- + // Implementation + //---------------------- + + nsFileSpecImpl(); + nsFileSpecImpl(const nsFileSpec& inSpec); + static nsresult MakeInterface(const nsFileSpec& inSpec, nsIFileSpec** outSpec); + + //---------------------- + // Data + //---------------------- + + nsFileSpec mFileSpec; + nsIInputStream* mInputStream; + nsIOutputStream* mOutputStream; + +private: + ~nsFileSpecImpl(); +}; // class nsFileSpecImpl + +//======================================================================================== +class NS_COM_OBSOLETE nsDirectoryIteratorImpl +//======================================================================================== + : public nsIDirectoryIterator +{ + +public: + + nsDirectoryIteratorImpl(); + + NS_DECL_ISUPPORTS + + NS_IMETHOD Init(nsIFileSpec *parent, PRBool resolveSymlink); + + NS_IMETHOD Exists(PRBool *_retval); + + NS_IMETHOD Next(); + + NS_IMETHOD GetCurrentSpec(nsIFileSpec * *aCurrentSpec); + + //---------------------- + // COM Cruft + //---------------------- + + static NS_METHOD Create(nsISupports* outer, const nsIID& aIID, void* *aIFileSpec); + +private: + ~nsDirectoryIteratorImpl(); + +protected: + nsDirectoryIterator* mDirectoryIterator; +}; // class nsDirectoryIteratorImpl + +#endif // _FILESPECIMPL_H_ diff --git a/src/libs/xpcom18a4/xpcom/obsolete/nsFileSpecMac.cpp b/src/libs/xpcom18a4/xpcom/obsolete/nsFileSpecMac.cpp new file mode 100644 index 00000000..fd208fb7 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/obsolete/nsFileSpecMac.cpp @@ -0,0 +1,1471 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +// This file is included by nsFile.cp, and includes the Macintosh-specific +// implementations. + + +#include + +#include "prtypes.h" +#include "nscore.h" + +#include "FullPath.h" +#include "FileCopy.h" +#include "MoreFilesExtras.h" + +#include +#include +#include +#include +#include +#include // ULONG_MAX + +#include "nsFileSpec.h" +#include "nsEscape.h" +#include "nsXPIDLString.h" + + +const unsigned char* kAliasHavenFolderName = "\pnsAliasHaven"; + +//======================================================================================== +namespace MacFileHelpers +//======================================================================================== +{ + inline void PLstrcpy(Str255 dst, ConstStr255Param src) + { + memcpy(dst, src, 1 + src[0]); + } + + void PLstrcpy(Str255 dst, const char* src, int inMaxLen=255); + void PLstrncpy(Str255 dst, const char* src, int inMaxLen); + + void SwapSlashColon(char * s); + OSErr FSSpecFromUnixPath( + const char * unixPath, + FSSpec& ioSpec, + Boolean hexDecode, + Boolean resolveAlias, + Boolean allowPartial = false, + Boolean createDirs = false); + char* MacPathFromUnixPath( + const char* unixPath, + Boolean hexDecode); + char* EncodeMacPath( + char* inPath, // NOT const - gets clobbered + Boolean prependSlash, + Boolean doEscape ); + OSErr FSSpecFromPathname( + const char* inPathNamePtr, + FSSpec& ioSpec, + Boolean inCreateDirs); + char* PathNameFromFSSpec( + const FSSpec& inSpec ); + OSErr CreateFolderInFolder( + short refNum, // Parent directory/volume + long dirID, + ConstStr255Param folderName, // Name of the new folder + short& outRefNum, // Volume of the created folder + long& outDirID); // + + // Some routines to support an "alias haven" directory. Aliases in this directory + // are never resolved. There is a ResolveAlias here that respects that. This is + // to support attaching of aliases in mail. + void EnsureAliasHaven(); + void SetNoResolve(Boolean inResolve); + PRBool IsAliasSafe(const FSSpec& inSpec); + OSErr MakeAliasSafe(FSSpec& inOutSpec); + OSErr ResolveAliasFile(FSSpec& inOutSpec, Boolean& wasAliased); + + Boolean sNoResolve = false; + long sAliasHavenDirID = 0; + short sAliasHavenVRefNum = 0; +} // namespace MacFileHelpers + +//---------------------------------------------------------------------------------------- +void MacFileHelpers::PLstrcpy(Str255 dst, const char* src, int inMax) +//---------------------------------------------------------------------------------------- +{ + int srcLength = strlen(src); + NS_ASSERTION(srcLength <= inMax, "Oops, string is too long!"); + if (srcLength > inMax) + srcLength = inMax; + dst[0] = srcLength; + memcpy(&dst[1], src, srcLength); +} + +//---------------------------------------------------------------------------------------- +void MacFileHelpers::PLstrncpy(Str255 dst, const char* src, int inMax) +//---------------------------------------------------------------------------------------- +{ + int srcLength = strlen(src); + if (srcLength > inMax) + srcLength = inMax; + dst[0] = srcLength; + memcpy(&dst[1], src, srcLength); +} + +//----------------------------------- +void MacFileHelpers::SwapSlashColon(char * s) +//----------------------------------- + +{ + while (*s) + { + if (*s == '/') + *s++ = ':'; + else if (*s == ':') + *s++ = '/'; + else + *s++; + } +} // MacFileHelpers::SwapSlashColon + +//----------------------------------- +char* MacFileHelpers::EncodeMacPath( + char* inPath, // NOT const, gets clobbered + Boolean prependSlash, + Boolean doEscape ) +// Transforms Macintosh style path into Unix one +// Method: Swap ':' and '/', hex escape the result +//----------------------------------- +{ + if (inPath == nsnull) + return nsnull; + int pathSize = strlen(inPath); + + // XP code sometimes chokes if there's a final slash in the unix path. + // Since correct mac paths to folders and volumes will end in ':', strip this + // first. + char* c = inPath + pathSize - 1; + if (*c == ':') + { + *c = 0; + pathSize--; + } + + char * newPath = nsnull; + char * finalPath = nsnull; + + if (prependSlash) + { + newPath = new char[pathSize + 2]; + newPath[0] = ':'; // It will be converted to '/' + memcpy(&newPath[1], inPath, pathSize + 1); + } + else + { + newPath = new char[pathSize + 1]; + strcpy(newPath, inPath); + } + if (newPath) + { + SwapSlashColon( newPath ); + if (doEscape) + { + finalPath = nsEscape(newPath, url_Path); + delete [] newPath; + } + else + finalPath = newPath; + } + delete [] inPath; + return finalPath; +} // MacFileHelpers::EncodeMacPath + +//---------------------------------------------------------------------------------------- +inline void MacFileHelpers::SetNoResolve(Boolean inResolve) +//---------------------------------------------------------------------------------------- +{ + sNoResolve = inResolve; +} // MacFileHelpers::SetNoResolve + +//---------------------------------------------------------------------------------------- +OSErr MacFileHelpers::MakeAliasSafe(FSSpec& inOutSpec) +// Pass in the spec of an alias. This copies the file to the safe haven folder, and +// returns the spec of the copy to the caller +//---------------------------------------------------------------------------------------- +{ + EnsureAliasHaven(); + nsFileSpec dstDirSpec(sAliasHavenVRefNum, sAliasHavenDirID, "\p"); + + // Make sure its name is unique + nsFileSpec havenSpec(sAliasHavenVRefNum, sAliasHavenDirID, "\pG'day"); + if (havenSpec.Valid()) + havenSpec.MakeUnique(inOutSpec.name); + // Copy the file into the haven directory + if (havenSpec.Valid()) + { + OSErr err = ::FSpFileCopy( + &inOutSpec, + dstDirSpec, + havenSpec.GetLeafPName(), + nil, 0, true); + // Return the spec of the copy to the caller. + if (err != noErr) + return err; + inOutSpec = havenSpec; + } + return noErr; +} // MacFileHelpers::MakeAliasSafe + +//---------------------------------------------------------------------------------------- +char* MacFileHelpers::MacPathFromUnixPath(const char* unixPath, Boolean hexDecode) +//---------------------------------------------------------------------------------------- +{ + // Relying on the fact that the unix path is always longer than the mac path: + size_t len = strlen(unixPath); + char* result = new char[len + 2]; // ... but allow for the initial colon in a partial name + // REMEMBER: at the end we call SwapSlashColon, so bear that in mind when you see + // this code using '/' as a separator in what is supposed to be a Macintosh path! + if (result) + { + char* dst = result; + const char* src = unixPath; + if (*src == '/') // * full path + src++; + else if (strchr(src, '/') && *src != '.') + { + // * partial path, and not just a leaf name. The '.' test is there because + // the loop below will add sufficient colons in that case. + *dst++ = '/'; + } + // Copy src to dst, but watch out for .. and . + char c = '/'; + do + { + char cprev = c; // remember the previous char (initially /) + c = *src++; + if (c == '.' && cprev == '/') + { + char* dstSaved = dst; + // Special cases: "." and "..". Convert to ':' and '::' + *dst++ = '/'; // . becomes : + c = *src++; + if (c == '.') + { + *dst++ = '/'; // .. becomes :: + c = *src++; + } + if (c == '/') + { + // ../ becomes :: so just skip the slash + // ./ becomes : " " " " " + src++; + } + else if (c) + { + // Oh. A file called ".foo" or "..foo" + // Back up and just do the normal thing. + src -= (dst - dstSaved); + dst = dstSaved; + // Since c is not '/', we won't do this stuff on the + // next iteration. + } + continue; + } + else if (c == '/' && cprev == '/') + { + // Hmm. A 'run on' path with two slashes right next to each other. + // This is an illegal path, but, hey, we'll be tough and try to + // deal with it (especially since '::' has loaded semantics in + // a Mac path) + continue; + } + *dst++ = c; + } while (c); + if (hexDecode) + nsUnescape(result); // Hex Decode + MacFileHelpers::SwapSlashColon(result); + } + return result; +} // MacFileHelpers::MacPathFromUnixPath + +//---------------------------------------------------------------------------------------- +OSErr MacFileHelpers::FSSpecFromPathname( + const char* inPathNamePtr, + FSSpec& ioSpec, // used as in-parameter for a relative path. + Boolean inCreateDirs) +// FSSpecFromPathname reverses PathNameFromFSSpec. +// It returns a FSSpec given a c string which is a mac pathname. +//---------------------------------------------------------------------------------------- +{ + OSErr err; + // Simplify this routine to use FSMakeFSSpec if length < 255. Otherwise use the MoreFiles + // routine FSpLocationFromFullPath, which allocates memory, to handle longer pathnames. + + short inVRefNum = ioSpec.vRefNum; + long inParID = ioSpec.parID; + + size_t inLength = strlen(inPathNamePtr); + bool isRelative = (strchr(inPathNamePtr, ':') == 0 || *inPathNamePtr == ':'); +#ifdef NS_DEBUG + // Attempt to catch people sending unix paths in to routines that expect native ones. + NS_ASSERTION(strchr(inPathNamePtr, '/') == 0, + "Possible unix path where native path is required"); +#endif + if (inLength < 255) + { + Str255 pascalpath; + MacFileHelpers::PLstrcpy(pascalpath, inPathNamePtr); + if (isRelative) + err = ::FSMakeFSSpec(inVRefNum, inParID, pascalpath, &ioSpec); + else + err = ::FSMakeFSSpec(0, 0, pascalpath, &ioSpec); + } + else if (!isRelative) + err = FSpLocationFromFullPath(inLength, inPathNamePtr, &ioSpec); + else + err = bdNamErr; + + if ((err == dirNFErr || err == bdNamErr) && inCreateDirs) + { + const char* path = inPathNamePtr; + if (isRelative) + { + ioSpec.vRefNum = inVRefNum; + ioSpec.parID = inParID; + } + else + { + ioSpec.vRefNum = 0; + ioSpec.parID = 0; + } + do { + // Locate the colon that terminates the node. + // But if we've a partial path (starting with a colon), find the second one. + const char* nextColon = strchr(path + (*path == ':'), ':'); + // Well, if there are no more colons, point to the end of the string. + if (!nextColon) + nextColon = path + strlen(path); + + // Make a pascal string out of this node. Include initial + // and final colon, if any! + Str255 ppath; + MacFileHelpers::PLstrncpy(ppath, path, nextColon - path + 1); + + // Use this string as a relative path using the directory created + // on the previous round (or directory 0,0 on the first round). + err = ::FSMakeFSSpec(ioSpec.vRefNum, ioSpec.parID, ppath, &ioSpec); + + // If this was the leaf node, then we are done. + if (!*nextColon) + break; + + // Since there's more to go, we have to get the directory ID, which becomes + // the parID for the next round. + if (err == noErr) + { + // The directory (or perhaps a file) exists. Find its dirID. + long dirID; + Boolean isDirectory; + err = ::FSpGetDirectoryID(&ioSpec, &dirID, &isDirectory); + if (!isDirectory) + return dupFNErr; // oops! a file exists with that name. + if (err) + return err; + ioSpec.parID = dirID; + } + else if (err == fnfErr) + { + // If we got "file not found", then + // we need to create a directory. + err = ::FSpDirCreate(&ioSpec, smCurrentScript, &ioSpec.parID); + // For some reason, this usually returns fnfErr, even though it works. + if (err == fnfErr) + err = noErr; + } + if (err != noErr) + return err; + path = nextColon; // next round + } while (1); + } + return err; +} // MacFileHelpers::FSSpecFromPathname + +//---------------------------------------------------------------------------------------- +OSErr MacFileHelpers::CreateFolderInFolder( + short refNum, // Parent directory/volume + long dirID, + ConstStr255Param folderName, // Name of the new folder + short& outRefNum, // Volume of the created folder + long& outDirID) // +// Creates a folder named 'folderName' inside a folder. +// The errors returned are same as PBDirCreate +//---------------------------------------------------------------------------------------- +{ + HFileParam hpb; + hpb.ioVRefNum = refNum; + hpb.ioDirID = dirID; + hpb.ioNamePtr = (StringPtr)&folderName; + + OSErr err = PBDirCreateSync((HParmBlkPtr)&hpb); + if (err == noErr) + { + outRefNum = hpb.ioVRefNum; + outDirID = hpb.ioDirID; + } + else + { + outRefNum = 0; + outDirID = 0; + } + return err; +} // MacFileHelpers::CreateFolderInFolder + +//---------------------------------------------------------------------------------------- +void MacFileHelpers::EnsureAliasHaven() +//---------------------------------------------------------------------------------------- +{ + // Alias Haven is a directory in which we never resolve aliases. + if (sAliasHavenVRefNum != 0) + return; + + + FSSpec temp; + if (FindFolder(0, kTemporaryFolderType, true, & temp.vRefNum, &temp.parID) == noErr) + { + CreateFolderInFolder( + temp.vRefNum, // Parent directory/volume + temp.parID, + kAliasHavenFolderName, // Name of the new folder + sAliasHavenVRefNum, // Volume of the created folder + sAliasHavenDirID); + } +} // MacFileHelpers::EnsureAliasHaven + +//---------------------------------------------------------------------------------------- +PRBool MacFileHelpers::IsAliasSafe(const FSSpec& inSpec) +// Returns true if the alias is in the alias haven directory, or if alias resolution +// has been turned off. +//---------------------------------------------------------------------------------------- +{ + return sNoResolve + || (inSpec.parID == sAliasHavenDirID && inSpec.vRefNum == sAliasHavenVRefNum); +} // MacFileHelpers::IsAliasSafe + +//---------------------------------------------------------------------------------------- +OSErr MacFileHelpers::ResolveAliasFile(FSSpec& inOutSpec, Boolean& wasAliased) +//---------------------------------------------------------------------------------------- +{ + wasAliased = false; + if (IsAliasSafe(inOutSpec)) + return noErr; + Boolean dummy; + return ::ResolveAliasFile(&inOutSpec, TRUE, &dummy, &wasAliased); +} // MacFileHelpers::ResolveAliasFile + +//----------------------------------- +OSErr MacFileHelpers::FSSpecFromUnixPath( + const char * unixPath, + FSSpec& ioSpec, + Boolean hexDecode, + Boolean resolveAlias, + Boolean allowPartial, + Boolean createDirs) +// File spec from URL. Reverses GetURLFromFileSpec +// Its input is only the part of the URL +// JRM 97/01/08 changed this so that if it's a partial path (doesn't start with '/'), +// then it is combined with inOutSpec's vRefNum and parID to form a new spec. +//----------------------------------- +{ + if (unixPath == nsnull) + return badFidErr; + char* macPath = MacPathFromUnixPath(unixPath, hexDecode); + if (!macPath) + return memFullErr; + + OSErr err = noErr; + if (!allowPartial) + { + NS_ASSERTION(*unixPath == '/' /*full path*/, "Not a full Unix path!"); + } + err = FSSpecFromPathname(macPath, ioSpec, createDirs); + if (err == fnfErr) + err = noErr; + Boolean dummy; + if (err == noErr && resolveAlias) // Added + err = MacFileHelpers::ResolveAliasFile(ioSpec, dummy); + delete [] macPath; + NS_ASSERTION(err==noErr||err==fnfErr||err==dirNFErr||err==nsvErr, "Not a path!"); + return err; +} // MacFileHelpers::FSSpecFromLocalUnixPath + +//----------------------------------- +char* MacFileHelpers::PathNameFromFSSpec( const FSSpec& inSpec ) +// Returns a full pathname to the given file +// Returned value is allocated with new [], and must be freed with delete [] +// For consistency and to work under OS X this creates an nsILocalFileMac and has it do the work. +//----------------------------------- +{ + char* result = nil; + nsresult rv; + + FSSpec nonConstSpec = inSpec; + nsCAutoString path; + nsCOMPtr macFile; + + rv = NS_NewLocalFileWithFSSpec(&nonConstSpec, PR_TRUE, getter_AddRefs(macFile)); + if (NS_FAILED(rv)) return nsnull; + nsCOMPtr localFile(do_QueryInterface(macFile, &rv)); + if (NS_FAILED(rv)) return nsnull; + rv = localFile->GetNativePath(path); + if (NS_FAILED(rv)) return nsnull; + PRInt32 strLen = path.Length(); + result = new char [strLen + 1]; + if (!result) return nsnull; + memcpy(result, path.get(), strLen); + result[ strLen ] = 0; + + return result; +} // MacFileHelpers::PathNameFromFSSpec + + +#pragma mark - + +//======================================================================================== +// Macintosh nsFileSpec implementation +//======================================================================================== + +//---------------------------------------------------------------------------------------- +nsFileSpec::nsFileSpec() +//---------------------------------------------------------------------------------------- +{ +// NS_ASSERTION(0, "nsFileSpec is unsupported - use nsIFile!"); + Clear(); +} + +//---------------------------------------------------------------------------------------- +nsFileSpec::nsFileSpec(const FSSpec& inSpec, PRBool resolveAlias) +//---------------------------------------------------------------------------------------- +: mSpec(inSpec) +, mError(NS_OK) +{ +// NS_ASSERTION(0, "nsFileSpec is unsupported - use nsIFile!"); + if (resolveAlias) + { + PRBool dummy; + ResolveSymlink(dummy); + } +} + +//---------------------------------------------------------------------------------------- +void nsFileSpec::operator = (const FSSpec& inSpec) +//---------------------------------------------------------------------------------------- +{ + mSpec = inSpec; + mError = NS_OK; +} + +//---------------------------------------------------------------------------------------- +nsFileSpec::nsFileSpec(const nsFileSpec& inSpec) +//---------------------------------------------------------------------------------------- +: mSpec(inSpec.mSpec) +, mError(inSpec.Error()) +{ +// NS_ASSERTION(0, "nsFileSpec is unsupported - use nsIFile!"); +} + +//---------------------------------------------------------------------------------------- +nsFileSpec::nsFileSpec(const char* inNativePathString, PRBool inCreateDirs) +//---------------------------------------------------------------------------------------- +{ +// NS_ASSERTION(0, "nsFileSpec is unsupported - use nsIFile!"); + Clear(); // this sets mError to NS_ERROR_NOT_INITIALIZED + + if (inNativePathString) + { + mError = NS_FILE_RESULT(MacFileHelpers::FSSpecFromPathname( + inNativePathString, mSpec, inCreateDirs)); + if (mError == NS_FILE_RESULT(fnfErr)) + mError = NS_OK; + } + +} // nsFileSpec::nsFileSpec + +//---------------------------------------------------------------------------------------- +nsFileSpec::nsFileSpec(const nsString& inNativePathString, PRBool inCreateDirs) +//---------------------------------------------------------------------------------------- +{ +// NS_ASSERTION(0, "nsFileSpec is unsupported - use nsIFile!"); + Clear(); // this sets mError to NS_ERROR_NOT_INITIALIZED + + mError = NS_FILE_RESULT( + MacFileHelpers::FSSpecFromPathname( + NS_LossyConvertUCS2toASCII(inNativePathString).get(), + mSpec, inCreateDirs)); + if (mError == NS_FILE_RESULT(fnfErr)) + mError = NS_OK; + +} // nsFileSpec::nsFileSpec + +//---------------------------------------------------------------------------------------- +nsFileSpec::nsFileSpec(short vRefNum, long parID, ConstStr255Param fileName, PRBool resolveAlias) +//---------------------------------------------------------------------------------------- +{ +// NS_ASSERTION(0, "nsFileSpec is unsupported - use nsIFile!"); + mError = NS_FILE_RESULT(::FSMakeFSSpec(vRefNum, parID, fileName, &mSpec)); + if (mError == NS_FILE_RESULT(fnfErr)) + mError = NS_OK; + + if (resolveAlias) + { + PRBool dummy; + ResolveSymlink(dummy); + } +} + +//---------------------------------------------------------------------------------------- +nsFileSpec::nsFileSpec(const nsFilePath& inPath) +//---------------------------------------------------------------------------------------- +{ +// NS_ASSERTION(0, "nsFileSpec is unsupported - use nsIFile!"); + *this = inPath.GetFileSpec(); +} + +//---------------------------------------------------------------------------------------- +void nsFileSpec::operator = (const char* inString) +//---------------------------------------------------------------------------------------- +{ + Clear(); // this sets mError to NS_ERROR_NOT_INITIALIZED + + if (inString) + { + mError = NS_FILE_RESULT(MacFileHelpers::FSSpecFromPathname(inString, mSpec, true)); + if (mError == NS_FILE_RESULT(fnfErr)) + mError = NS_OK; + } + +} // nsFileSpec::operator = + +//---------------------------------------------------------------------------------------- +void nsFileSpec::operator = (const nsFileSpec& inSpec) +//---------------------------------------------------------------------------------------- +{ + mPath.SetToEmpty(); + mSpec.vRefNum = inSpec.mSpec.vRefNum; + mSpec.parID = inSpec.mSpec.parID; + + PRInt32 copySize = inSpec.mSpec.name[0] + 1; + if (copySize > sizeof(inSpec.mSpec.name)) + copySize = sizeof(inSpec.mSpec.name); + memcpy(mSpec.name, inSpec.mSpec.name, copySize); + mError = inSpec.Error(); // note that the error is propagated +} // nsFileSpec::operator = + +//---------------------------------------------------------------------------------------- +void nsFileSpec::operator = (const nsFilePath& inPath) +//---------------------------------------------------------------------------------------- +{ + *this = inPath.GetFileSpec(); +} // nsFileSpec::operator = + +//---------------------------------------------------------------------------------------- +inline void nsFileSpec::Clear() +//---------------------------------------------------------------------------------------- +{ + mPath.SetToEmpty(); + mSpec.vRefNum = 0; + mSpec.parID = 0; + mSpec.name[0] = 0; + mError = NS_ERROR_NOT_INITIALIZED; +} + +//---------------------------------------------------------------------------------------- +PRBool nsFileSpec::Exists() const +//---------------------------------------------------------------------------------------- +{ + if (NS_FAILED(mError)) return PR_FALSE; + FSSpec temp; + return ::FSMakeFSSpec(mSpec.vRefNum, mSpec.parID, mSpec.name, &temp) == noErr; +} // nsFileSpec::Exists() + +//---------------------------------------------------------------------------------------- +void nsFileSpec::GetModDate(TimeStamp& outStamp) const +//---------------------------------------------------------------------------------------- +{ + CInfoPBRec pb; + if (GetCatInfo(pb) == noErr) + outStamp = ((DirInfo*)&pb)->ioDrMdDat; // The mod date is in the same spot for files and dirs. + else + outStamp = 0; +} // nsFileSpec::GetModDate + +//---------------------------------------------------------------------------------------- +PRUint32 nsFileSpec::GetFileSize() const +//---------------------------------------------------------------------------------------- +{ + CInfoPBRec pb; + if (noErr == GetCatInfo(pb)) + return (PRUint32)((HFileInfo*)&pb)->ioFlLgLen; + return 0; +} // nsFileSpec::GetFileSize + +//---------------------------------------------------------------------------------------- +void nsFileSpec::SetLeafName(const char* inLeafName) +// In leaf name can actually be a partial path... +//---------------------------------------------------------------------------------------- +{ + NS_ASSERTION(inLeafName, "Attempt to set leaf name with a null string"); + + mPath.SetToEmpty(); + + if (inLeafName) + { + // what about long relative paths? Hmm? We don't have a routine for this anywhere. + Str255 partialPath; + MacFileHelpers::PLstrcpy(partialPath, inLeafName); + mError = NS_FILE_RESULT( + ::FSMakeFSSpec(mSpec.vRefNum, mSpec.parID, partialPath, &mSpec)); + if (mError == NS_FILE_RESULT(fnfErr)) + mError = NS_OK; + } + +} // nsFileSpec::SetLeafName + +//---------------------------------------------------------------------------------------- +char* nsFileSpec::GetLeafName() const +// Result needs to be nsCRT::free()ed. +//---------------------------------------------------------------------------------------- +{ + char leaf[sizeof(mSpec.name)]; + memcpy(leaf, &mSpec.name[1], mSpec.name[0]); + leaf[mSpec.name[0]] = '\0'; + return nsCRT::strdup(leaf); +} // nsFileSpec::GetLeafName + +//---------------------------------------------------------------------------------------- +void nsFileSpec::MakeAliasSafe() +//---------------------------------------------------------------------------------------- +{ + mPath.SetToEmpty(); + mError = NS_FILE_RESULT(MacFileHelpers::MakeAliasSafe(mSpec)); +} // nsFileSpec::MakeAliasSafe + +//---------------------------------------------------------------------------------------- +void nsFileSpec::MakeUnique(ConstStr255Param inSuggestedLeafName) +//---------------------------------------------------------------------------------------- +{ + mPath.SetToEmpty(); + if (inSuggestedLeafName[0] > 0) + MacFileHelpers::PLstrcpy(mSpec.name, inSuggestedLeafName); + + MakeUnique(); +} // nsFileSpec::MakeUnique + +//---------------------------------------------------------------------------------------- +PRBool nsFileSpec::IsFile() const +//---------------------------------------------------------------------------------------- +{ + long dirID; + Boolean isDirectory; + return (noErr == ::FSpGetDirectoryID(&mSpec, &dirID, &isDirectory) && !isDirectory); +} // nsFileSpec::IsFile + +//---------------------------------------------------------------------------------------- +PRBool nsFileSpec::IsDirectory() const +//---------------------------------------------------------------------------------------- +{ + long dirID; + Boolean isDirectory; + return (noErr == ::FSpGetDirectoryID(&mSpec, &dirID, &isDirectory) && isDirectory); +} // nsFileSpec::IsDirectory + +//---------------------------------------------------------------------------------------- +PRBool nsFileSpec::IsHidden() const +//---------------------------------------------------------------------------------------- +{ + CInfoPBRec cInfo; + PRBool hidden = PR_FALSE; + + if (noErr == GetCatInfo(cInfo)) + if (cInfo.hFileInfo.ioFlFndrInfo.fdFlags & kIsInvisible) + hidden = PR_TRUE; + + return hidden; +} // nsFileSpec::IsHidden + +//---------------------------------------------------------------------------------------- +PRBool nsFileSpec::IsSymlink() const +//---------------------------------------------------------------------------------------- +{ + CInfoPBRec cInfo; + PRBool hidden = PR_FALSE; + + if (noErr == GetCatInfo(cInfo)) + if (cInfo.hFileInfo.ioFlFndrInfo.fdFlags & kIsAlias) + hidden = PR_TRUE; + + return hidden; +} // nsFileSpec::IsSymlink + +//---------------------------------------------------------------------------------------- +nsresult nsFileSpec::ResolveSymlink(PRBool& wasAliased) +//---------------------------------------------------------------------------------------- +{ + Boolean wasAliased2; // Type conversion Boolean <--> PRBool + OSErr err = MacFileHelpers::ResolveAliasFile(mSpec, wasAliased2); + if (wasAliased2) + { + mError = NS_FILE_RESULT(err); + wasAliased = PR_TRUE; + } + else + wasAliased = PR_FALSE; + + return mError; +} // nsFileSpec::ResolveSymlink + +//---------------------------------------------------------------------------------------- +void nsFileSpec::GetParent(nsFileSpec& outSpec) const +//---------------------------------------------------------------------------------------- +{ + if (NS_SUCCEEDED(mError)) + outSpec.mError = NS_FILE_RESULT(::FSMakeFSSpec(mSpec.vRefNum, mSpec.parID, nsnull, outSpec)); +} // nsFileSpec::GetParent + +//---------------------------------------------------------------------------------------- +void nsFileSpec::operator += (const char* inRelativePath) +//---------------------------------------------------------------------------------------- +{ + NS_ASSERTION(inRelativePath, "Attempt to append relative path with null path"); + + // Invalidate the path cache string, since we're changing ourselves. + mPath.SetToEmpty(); + + // if we are already bad, don't allow appendage + if (NS_FAILED(Error())) + { + NS_WARNING("trying to append to a bad nsFileSpec"); + return; + } + + // Find the dirID of the directory described by this spec + long dirID; + Boolean isDirectory; + mError = NS_FILE_RESULT(::FSpGetDirectoryID(&mSpec, &dirID, &isDirectory)); + if (NS_FAILED(mError) || !isDirectory || !inRelativePath) + return; + // mSpec.vRefNum is already correct. + mSpec.parID = dirID; + + // Next, determine if it is a UNIX or Mac style path. Now, Macintosh relative paths + // are either leaf names (in which the distinction between unix and macintosh + // relative paths disappears) or they start with a colon. If we find an initial colon, + // then assume it's a macintosh path. + // If it is a UNIX path (including just a leaf name), we will also look for ':' and + // assert if we find one. + if (*inRelativePath != ':') + { + // Looks like a UNIX path (including possibly just a leaf name) + NS_ASSERTION(strchr(inRelativePath, ':') == nsnull, "Can not determine path type"); + // Convert unix path (which is unencoded) to a spec + mError = NS_FILE_RESULT( + MacFileHelpers::FSSpecFromUnixPath(inRelativePath, mSpec, false, false, true, true)); + } + else + { + // We must be a mac path! + mError = NS_FILE_RESULT(MacFileHelpers::FSSpecFromPathname(inRelativePath, mSpec, true)); + } + if (mError == NS_FILE_RESULT(fnfErr)) + mError = NS_OK; + +} // nsFileSpec::operator += + +//---------------------------------------------------------------------------------------- +void nsFileSpec::CreateDirectory(int /* unix mode */) +//---------------------------------------------------------------------------------------- +{ + long ignoredDirID; + OSErr err = ::FSpDirCreate(&mSpec, smCurrentScript, &ignoredDirID); + // it's OK if the dir already exists + if (err != noErr && IsDirectory()) + err = noErr; + + mError = NS_FILE_RESULT(err); + +} // nsFileSpec::CreateDirectory + +//---------------------------------------------------------------------------------------- +void nsFileSpec::Delete(PRBool inRecursive) const +//---------------------------------------------------------------------------------------- +{ + OSErr anErr; + + nsresult& mutableError = const_cast(this)->mError; + if (inRecursive) + { + // MoreFilesExtras + anErr = ::DeleteDirectory( + mSpec.vRefNum, + mSpec.parID, + const_cast(mSpec.name)); + } + else + anErr = ::FSpDelete(&mSpec); + + if (anErr == fnfErr) // deleting a file that doesn't exist isn't an error! + anErr = noErr; + + mutableError = NS_FILE_RESULT(anErr); + +} // nsFileSpec::Delete + +//---------------------------------------------------------------------------------------- +void nsFileSpec::RecursiveCopy(nsFileSpec newDir) const +//---------------------------------------------------------------------------------------- +{ + if (IsDirectory()) + { + if (!(newDir.Exists())) + { + newDir.CreateDirectory(); + } + + for (nsDirectoryIterator i(*this, PR_FALSE); i.Exists(); i++) + { + nsFileSpec& child = (nsFileSpec&)i; + + if (child.IsDirectory()) + { + nsFileSpec tmpDirSpec(newDir); + + char *leafname = child.GetLeafName(); + tmpDirSpec += leafname; + nsCRT::free(leafname); + + child.RecursiveCopy(tmpDirSpec); + } + else + { + child.RecursiveCopy(newDir); + } + } + } + else + { + nsFileSpec& filePath = (nsFileSpec&) *this; + + if (!(newDir.Exists())) + { + newDir.CreateDirectory(); + } + + filePath.CopyToDir(newDir); + } +} // nsFileSpec::RecursiveCopy + +//---------------------------------------------------------------------------------------- +nsresult nsFileSpec::Truncate(PRInt32 aNewLength) const +//---------------------------------------------------------------------------------------- +{ + short refNum; + OSErr err; + + // First see if we have an internal error set + if (NS_FAILED(mError)) + return mError; + + // Need to open the file to trunc + if (::FSpOpenDF(&mSpec, fsWrPerm, &refNum) != noErr) + return NS_FILE_FAILURE; + + err = ::SetEOF(refNum, aNewLength); + + // Close the file unless we got an error that it was already closed + if (err != fnOpnErr) + (void)::FSClose(refNum); + + if (err != noErr) + return NS_FILE_FAILURE; + + return NS_OK; +} // nsFileSpec::Truncate + +//---------------------------------------------------------------------------------------- +nsresult nsFileSpec::Rename(const char* inNewName) +//---------------------------------------------------------------------------------------- +{ + NS_ASSERTION(inNewName, "Attempt to rename with null new name"); + + if (strchr(inNewName, '/')) + return NS_FILE_FAILURE; // no relative paths here! + + Str255 pName; + MacFileHelpers::PLstrcpy(pName, inNewName); + if (::FSpRename(&mSpec, pName) != noErr) + return NS_FILE_FAILURE; + SetLeafName(inNewName); + return NS_OK; +} // nsFileSpec::Rename + +//---------------------------------------------------------------------------------------- +nsresult nsFileSpec::CopyToDir(const nsFileSpec& newParentDir) const +//---------------------------------------------------------------------------------------- +{ + // We can only copy into a directory, and (for now) can not copy entire directories + + if (!newParentDir.IsDirectory() || (IsDirectory() ) ) + return NS_FILE_FAILURE; + + nsresult rv = NS_FILE_RESULT(::FSpFileCopy(&mSpec, + &newParentDir.mSpec, + const_cast(GetLeafPName()), + nsnull, + 0, + true)); + + return rv; + +} // nsFileSpec::CopyToDir + +//---------------------------------------------------------------------------------------- +nsresult nsFileSpec::MoveToDir(const nsFileSpec& newParentDir) +//---------------------------------------------------------------------------------------- +{ + // We can only move into a directory + + if (!newParentDir.IsDirectory()) + return NS_FILE_FAILURE; + + nsresult result = NS_FILE_RESULT(::FSpMoveRenameCompat(&mSpec, + &newParentDir.mSpec, + const_cast(GetLeafPName()))); + + if ( NS_SUCCEEDED(result) ) + { + char* leafName = GetLeafName(); + *this = newParentDir + leafName; + nsCRT::free(leafName); + } + return result; +} // nsFileSpec::MoveToDir + +//---------------------------------------------------------------------------------------- +nsresult nsFileSpec::Execute(const char* /*args - how can this be cross-platform? problem! */ ) const +//---------------------------------------------------------------------------------------- +{ + if (IsDirectory()) + return NS_FILE_FAILURE; + + LaunchParamBlockRec launchThis; + launchThis.launchAppSpec = const_cast(&mSpec); + launchThis.launchAppParameters = nsnull; // args; + /* launch the thing */ + launchThis.launchBlockID = extendedBlock; + launchThis.launchEPBLength = extendedBlockLen; + launchThis.launchFileFlags = nsnull; + launchThis.launchControlFlags = launchContinue + launchNoFileFlags + launchUseMinimum; + launchThis.launchControlFlags += launchDontSwitch; + + nsresult result = NS_FILE_RESULT(::LaunchApplication(&launchThis)); + return result; + +} // nsFileSpec::Execute + +//---------------------------------------------------------------------------------------- +OSErr nsFileSpec::GetCatInfo(CInfoPBRec& outInfo) const +//---------------------------------------------------------------------------------------- +{ + DirInfo *dipb=(DirInfo *)&outInfo; + dipb->ioCompletion = nsnull; + dipb->ioFDirIndex = 0; // use dirID and name + dipb->ioVRefNum = mSpec.vRefNum; + dipb->ioDrDirID = mSpec.parID; + dipb->ioNamePtr = const_cast(this)->mSpec.name; + return PBGetCatInfoSync(&outInfo); +} // nsFileSpec::GetCatInfo() + +//---------------------------------------------------------------------------------------- +OSErr nsFileSpec::SetFileTypeAndCreator(OSType type, OSType creator) +//---------------------------------------------------------------------------------------- +{ + FInfo info; + OSErr err = ::FSpGetFInfo(&mSpec, &info); + if (err != noErr) + return err; + info.fdType = type; + info.fdCreator = creator; + err = ::FSpSetFInfo(&mSpec, &info); + return err; +} + +//---------------------------------------------------------------------------------------- +OSErr nsFileSpec::GetFileTypeAndCreator(OSType* type, OSType* creator) +//---------------------------------------------------------------------------------------- +{ + FInfo info; + OSErr err = ::FSpGetFInfo(&mSpec, &info); + if (err != noErr) + return err; + *type = info.fdType; + *creator = info.fdCreator; + return noErr; +} + +//---------------------------------------------------------------------------------------- +PRInt64 nsFileSpec::GetDiskSpaceAvailable() const +//---------------------------------------------------------------------------------------- +{ + PRInt64 space64Bits; + + LL_I2L(space64Bits , LONG_MAX); + + XVolumeParam pb; + pb.ioCompletion = nsnull; + pb.ioVolIndex = 0; + pb.ioNamePtr = nsnull; + pb.ioVRefNum = mSpec.vRefNum; + + // PBXGetVolInfoSync works on HFS+ volumes too! + OSErr err = ::PBXGetVolInfoSync(&pb); + + if (err == noErr) + { +#ifdef HAVE_LONG_LONG + space64Bits = pb.ioVFreeBytes; +#else + const UnsignedWide& freeBytes = UInt64ToUnsignedWide(pb.ioVFreeBytes); + space64Bits.lo = freeBytes.lo; + space64Bits.hi = freeBytes.hi; +#endif + } + + return space64Bits; +} // nsFileSpec::GetDiskSpace() + +//---------------------------------------------------------------------------------------- +const char* nsFileSpec::GetCString() const +// This is the only conversion to const char* that is provided, and it allows the +// path to be "passed" to NSPR file routines. This practice is VERY EVIL and should only +// be used to support legacy code. Using it guarantees bugs on Macintosh. The string is +// cached and freed by the nsFileSpec destructor, so do not delete (or free) it. +//---------------------------------------------------------------------------------------- +{ + if (mPath.IsEmpty()) + { + char* path = MacFileHelpers::PathNameFromFSSpec(mSpec); + if (path != NULL) { + const_cast(this)->mPath = path; // operator =() copies the string!!! + delete[] path; + } else { + const_cast(this)->mError = NS_ERROR_OUT_OF_MEMORY; + } + } + return mPath; +} + +#pragma mark - + +//======================================================================================== +// Macintosh nsFilePath implementation +//======================================================================================== + +//---------------------------------------------------------------------------------------- +static void AssignFromPath(nsFilePath& ioPath, const char* inString, PRBool inCreateDirs) +//---------------------------------------------------------------------------------------- +{ + NS_ASSERTION(inString, "AssignFromPath called with null inString"); + NS_ASSERTION(strstr(inString, kFileURLPrefix) != inString, "URL passed as path"); + + FSSpec spec; + spec.vRefNum = 0; + spec.parID = 0; + spec.name[0] = 0; + MacFileHelpers::FSSpecFromUnixPath( + inString, + spec, + false, + true, // resolve alias + true, + inCreateDirs); + // Now we have a spec, + // Invoke operator = (const nsFileSpec&) to do the rest. + // Why didn't we just say mPath = inString to get the path? Well, we want it to be + // canonical and absolute. + ioPath = spec; +} + +//---------------------------------------------------------------------------------------- +nsFilePath::nsFilePath(const char* inString, PRBool inCreateDirs) +//---------------------------------------------------------------------------------------- +{ + AssignFromPath(*this, inString, inCreateDirs); +} //nsFilePath::nsFilePath + +//---------------------------------------------------------------------------------------- +nsFilePath::nsFilePath(const nsString& inString, PRBool inCreateDirs) +//---------------------------------------------------------------------------------------- +{ + AssignFromPath(*this, NS_LossyConvertUCS2toASCII(inString).get(), + inCreateDirs); +} + +//---------------------------------------------------------------------------------------- +void nsFilePath::operator = (const char* inString) +//---------------------------------------------------------------------------------------- +{ + AssignFromPath(*this, inString, PR_FALSE); +} + +//---------------------------------------------------------------------------------------- +nsFilePath::nsFilePath(const nsFileSpec& inSpec) +//---------------------------------------------------------------------------------------- +{ + *this = inSpec; +} + +//---------------------------------------------------------------------------------------- +nsFilePath::nsFilePath(const nsFileURL& inOther) +//---------------------------------------------------------------------------------------- +{ + *this = inOther; +} + +//---------------------------------------------------------------------------------------- +void nsFilePath::operator = (const nsFileSpec& inSpec) +//---------------------------------------------------------------------------------------- +{ + char * path = MacFileHelpers::PathNameFromFSSpec(inSpec); + path = MacFileHelpers::EncodeMacPath(path, true, false); + mPath = path; + nsCRT::free(path); + mFileSpec = inSpec; +} // nsFilePath::operator = + +//---------------------------------------------------------------------------------------- +void nsFilePath::operator = (const nsFileURL& inOther) +//---------------------------------------------------------------------------------------- +{ + char * path = MacFileHelpers::PathNameFromFSSpec(inOther.mFileSpec); + path = MacFileHelpers::EncodeMacPath(path, true, false); + mPath = path; + nsCRT::free(path); + mFileSpec = inOther.GetFileSpec(); +} + +#pragma mark - + +//======================================================================================== +// nsFileURL implementation +//======================================================================================== + +//---------------------------------------------------------------------------------------- +nsFileURL::nsFileURL(const char* inString, PRBool inCreateDirs) +//---------------------------------------------------------------------------------------- +: mURL(inString) +{ + NS_ASSERTION(inString, "nsFileURL constructed with null inString"); + NS_ASSERTION(strstr(inString, kFileURLPrefix) == inString, "Not a URL!"); + mFileSpec.mError = NS_FILE_RESULT(MacFileHelpers::FSSpecFromUnixPath( + inString + kFileURLPrefixLength, + mFileSpec.mSpec, + true, // need to decode + false, // resolve alias + false, // must be a full path + inCreateDirs)); + if (mFileSpec.mError == NS_FILE_RESULT(fnfErr)) + mFileSpec.mError = NS_OK; +} // nsFileURL::nsFileURL + +//---------------------------------------------------------------------------------------- +nsFileURL::nsFileURL(const nsString& inString, PRBool inCreateDirs) +//---------------------------------------------------------------------------------------- +: mURL(nsnull) +{ + NS_LossyConvertUCS2toASCII cstring(inString); + mURL = cstring.get(); + NS_ASSERTION(strstr(cstring.get(), kFileURLPrefix) == cstring.get(), + "Not a URL!"); + mFileSpec.mError = NS_FILE_RESULT(MacFileHelpers::FSSpecFromUnixPath( + cstring.get() + kFileURLPrefixLength, + mFileSpec.mSpec, + true, // need to decode + false, // resolve alias + false, // must be a full path + inCreateDirs)); + if (mFileSpec.mError == NS_FILE_RESULT(fnfErr)) + mFileSpec.mError = NS_OK; +} // nsFileURL::nsFileURL + +//---------------------------------------------------------------------------------------- +nsFileURL::nsFileURL(const nsFilePath& inOther) +//---------------------------------------------------------------------------------------- +{ + *this = inOther.GetFileSpec(); +} // nsFileURL::nsFileURL + +//---------------------------------------------------------------------------------------- +nsFileURL::nsFileURL(const nsFileSpec& inOther) +//---------------------------------------------------------------------------------------- +{ + *this = inOther; +} // nsFileURL::nsFileURL + +//---------------------------------------------------------------------------------------- +void nsFileURL::operator = (const nsFilePath& inOther) +//---------------------------------------------------------------------------------------- +{ + *this = inOther.GetFileSpec(); +} // nsFileURL::operator = + +//---------------------------------------------------------------------------------------- +void nsFileURL::operator = (const nsFileSpec& inOther) +//---------------------------------------------------------------------------------------- +{ + mFileSpec = inOther; + char* path = MacFileHelpers::PathNameFromFSSpec( mFileSpec ); + char* encodedPath = MacFileHelpers::EncodeMacPath(path, true, true); + nsSimpleCharString encodedURL(kFileURLPrefix); + encodedURL += encodedPath; + nsCRT::free(encodedPath); + mURL = encodedURL; + if (encodedURL[encodedURL.Length() - 1] != '/' && inOther.IsDirectory()) + mURL += "/"; +} // nsFileURL::operator = + +//---------------------------------------------------------------------------------------- +void nsFileURL::operator = (const char* inString) +//---------------------------------------------------------------------------------------- +{ + NS_ASSERTION(inString, "nsFileURL operator= constructed with null inString"); + + mURL = inString; + NS_ASSERTION(strstr(inString, kFileURLPrefix) == inString, "Not a URL!"); + mFileSpec.mError = NS_FILE_RESULT(MacFileHelpers::FSSpecFromUnixPath( + inString + kFileURLPrefixLength, + mFileSpec.mSpec, + true, // need to decode + true, // resolve alias + false, // must be a full path + false)); // don't create dirs. + if (mFileSpec.mError == NS_FILE_RESULT(fnfErr)) + mFileSpec.mError = NS_OK; +} // nsFileURL::operator = + +#pragma mark - + +//======================================================================================== +// nsDirectoryIterator +//======================================================================================== + +//---------------------------------------------------------------------------------------- +nsDirectoryIterator::nsDirectoryIterator( + const nsFileSpec& inDirectory +, PRBool resolveSymLinks) +//---------------------------------------------------------------------------------------- + : mCurrent(inDirectory) + , mExists(false) + , mResoveSymLinks(resolveSymLinks) + , mIndex(-1) +{ + CInfoPBRec pb; + OSErr err = inDirectory.GetCatInfo(pb); + + // test that we have got a directory back, not a file + DirInfo* dipb = (DirInfo*)&pb; + if (err != noErr || !( dipb->ioFlAttrib & 0x0010)) + return; + // Sorry about this, there seems to be a bug in CWPro 4: + FSSpec& currentSpec = mCurrent.nsFileSpec::operator FSSpec&(); + mVRefNum = currentSpec.vRefNum; + mParID = dipb->ioDrDirID; + mMaxIndex = pb.dirInfo.ioDrNmFls; + mIndex = 0; // ready to increment + ++(*this); // the pre-increment operator + +} // nsDirectoryIterator::nsDirectoryIterator + +//---------------------------------------------------------------------------------------- +OSErr nsDirectoryIterator::SetToIndex() +//---------------------------------------------------------------------------------------- +{ + CInfoPBRec cipb; + DirInfo *dipb=(DirInfo *)&cipb; + Str255 objectName; + dipb->ioCompletion = nsnull; + dipb->ioFDirIndex = mIndex; + // Sorry about this, there seems to be a bug in CWPro 4: + FSSpec& currentSpec = mCurrent.nsFileSpec::operator FSSpec&(); + dipb->ioVRefNum = mVRefNum; /* Might need to use vRefNum, not sure*/ + dipb->ioDrDirID = mParID; + dipb->ioNamePtr = objectName; + OSErr err = PBGetCatInfoSync(&cipb); + FSSpec temp; + if (err == noErr) + err = FSMakeFSSpec(mVRefNum, mParID, objectName, &temp); + mCurrent = temp; // use the operator: it clears the string cache. + mExists = err == noErr; + + if (mExists && mResoveSymLinks) + { + PRBool ignore; + mCurrent.ResolveSymlink(ignore); + } + return err; +} // nsDirectoryIterator::SetToIndex() + +//---------------------------------------------------------------------------------------- +nsDirectoryIterator& nsDirectoryIterator::operator -- () +//---------------------------------------------------------------------------------------- +{ + mExists = false; + while (--mIndex > 0) + { + OSErr err = SetToIndex(); + if (err == noErr) + break; + } + return *this; +} // nsDirectoryIterator::operator -- + +//---------------------------------------------------------------------------------------- +nsDirectoryIterator& nsDirectoryIterator::operator ++ () +//---------------------------------------------------------------------------------------- +{ + mExists = false; + if (mIndex >= 0) // probably trying to use a file as a directory! + while (++mIndex <= mMaxIndex) + { + OSErr err = SetToIndex(); + if (err == noErr) + break; + } + return *this; +} // nsDirectoryIterator::operator ++ + diff --git a/src/libs/xpcom18a4/xpcom/obsolete/nsFileSpecOS2.cpp b/src/libs/xpcom18a4/xpcom/obsolete/nsFileSpecOS2.cpp new file mode 100644 index 00000000..4621d8b8 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/obsolete/nsFileSpecOS2.cpp @@ -0,0 +1,840 @@ +/* ***** 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 the Mozilla OS/2 libraries. + * + * The Initial Developer of the Original Code is + * John Fairhurst, . + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Henry Sobotka + * 00/01/06: general review and update against Win/Unix versions; + * replaced nsFileSpec::Execute implementation with system() call + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** + * + * This Original Code has been modified by IBM Corporation. + * Modifications made by IBM described herein are + * Copyright (c) International Business Machines + * Corporation, 2000 + * + * Modifications to Mozilla code or documentation + * identified per MPL Section 3.3 + * + * Date Modified by Description of modification + * 03/23/2000 IBM Corp. Fixed bug where 2 char or less profile names treated as drive letters. + * 06/20/2000 IBM Corp. Make it more like Windows version. + */ + +#define INCL_DOSERRORS +#define INCL_DOS +#define INCL_WINWORKPLACE +#include + +#ifdef XP_OS2_VACPP +#include +#endif + +#include +#include +#include +#include +#include + +//---------------------------------------------------------------------------------------- +void nsFileSpecHelpers::Canonify(nsSimpleCharString& ioPath, PRBool inMakeDirs) +// Canonify, make absolute, and check whether directories exist. This +// takes a (possibly relative) native path and converts it into a +// fully qualified native path. +//---------------------------------------------------------------------------------------- +{ + if (ioPath.IsEmpty()) + return; + + NS_ASSERTION(strchr((const char*)ioPath, '/') == 0, + "This smells like a Unix path. Native path expected! " + "Please fix."); + if (inMakeDirs) + { + const int mode = 0700; + nsSimpleCharString unixStylePath = ioPath; + nsFileSpecHelpers::NativeToUnix(unixStylePath); + nsFileSpecHelpers::MakeAllDirectories((const char*)unixStylePath, mode); + } + char buffer[_MAX_PATH]; + errno = 0; + *buffer = '\0'; +#ifdef XP_OS2 + PRBool removedBackslash = PR_FALSE; + PRUint32 lenstr = ioPath.Length(); + char &lastchar = ioPath[lenstr -1]; + + // Strip off any trailing backslash UNLESS it's the backslash that + // comes after "X:". Note also that "\" is valid. Sheesh. + // + if( lastchar == '\\' && (lenstr != 3 || ioPath[1] != ':') && lenstr != 1) + { + lastchar = '\0'; + removedBackslash = PR_TRUE; + } + + char canonicalPath[CCHMAXPATH] = ""; + + DosQueryPathInfo( (char*) ioPath, + FIL_QUERYFULLNAME, + canonicalPath, + CCHMAXPATH); +#else + char* canonicalPath = _fullpath(buffer, ioPath, _MAX_PATH); +#endif + + if (canonicalPath) + { + NS_ASSERTION( canonicalPath[0] != '\0', "Uh oh...couldn't convert" ); + if (canonicalPath[0] == '\0') + return; +#ifdef XP_OS2 + // If we removed that backslash, add it back onto the fullpath + if (removedBackslash) + strcat( canonicalPath, "\\"); +#endif + } + ioPath = canonicalPath; +} // nsFileSpecHelpers::Canonify + +//---------------------------------------------------------------------------------------- +void nsFileSpecHelpers::UnixToNative(nsSimpleCharString& ioPath) +// This just does string manipulation. It doesn't check reality, or canonify, or +// anything +//---------------------------------------------------------------------------------------- +{ + // Allow for relative or absolute. We can do this in place, because the + // native path is never longer. + + if (ioPath.IsEmpty()) + return; + + // Strip initial slash for an absolute path + char* src = (char*)ioPath; + if (*src == '/') { + if (!src[1]) { + // allocate new string by copying from ioPath[1] + nsSimpleCharString temp = src + 1; + ioPath = temp; + return; + } + // Since it was an absolute path, check for the drive letter + char* colonPointer = src + 2; + if (strstr(src, "|/") == colonPointer) + *colonPointer = ':'; + // allocate new string by copying from ioPath[1] + nsSimpleCharString temp = src + 1; + ioPath = temp; + } + + src = (char*)ioPath; + + if (*src) { + // Convert '/' to '\'. + while (*++src) + { + if (*src == '/') + *src = '\\'; + } + } +} // nsFileSpecHelpers::UnixToNative + +//---------------------------------------------------------------------------------------- +void nsFileSpecHelpers::NativeToUnix(nsSimpleCharString& ioPath) +// This just does string manipulation. It doesn't check reality, or canonify, or +// anything. The unix path is longer, so we can't do it in place. +//---------------------------------------------------------------------------------------- +{ + if (ioPath.IsEmpty()) + return; + + // Convert the drive-letter separator, if present + nsSimpleCharString temp("/"); + + char* cp = (char*)ioPath + 1; + if (strstr(cp, ":\\") == cp) + *cp = '|'; // absolute path + else + temp[0] = '\0'; // relative path + + // Convert '\' to '/' + for (; *cp; cp++) + { +#ifdef XP_OS2 + // OS2TODO - implement equivalent of IsDBCSLeadByte +#else + if(IsDBCSLeadByte(*cp) && *(cp+1) != nsnull) + { + cp++; + continue; + } +#endif + if (*cp == '\\') + *cp = '/'; + } + // Add the slash in front. + temp += ioPath; + ioPath = temp; +} + +//---------------------------------------------------------------------------------------- +nsFileSpec::nsFileSpec(const nsFilePath& inPath) +//---------------------------------------------------------------------------------------- +{ +// NS_ASSERTION(0, "nsFileSpec is unsupported - use nsIFile!"); + *this = inPath; +} + +//---------------------------------------------------------------------------------------- +void nsFileSpec::operator = (const nsFilePath& inPath) +//---------------------------------------------------------------------------------------- +{ + mPath = (const char*)inPath; + nsFileSpecHelpers::UnixToNative(mPath); + mError = NS_OK; +} // nsFileSpec::operator = + +//---------------------------------------------------------------------------------------- +nsFilePath::nsFilePath(const nsFileSpec& inSpec) +//---------------------------------------------------------------------------------------- +{ + *this = inSpec; +} // nsFilePath::nsFilePath + +//---------------------------------------------------------------------------------------- +void nsFilePath::operator = (const nsFileSpec& inSpec) +//---------------------------------------------------------------------------------------- +{ + mPath = inSpec.mPath; + nsFileSpecHelpers::NativeToUnix(mPath); +} // nsFilePath::operator = + +//---------------------------------------------------------------------------------------- +void nsFileSpec::SetLeafName(const char* inLeafName) +//---------------------------------------------------------------------------------------- +{ + NS_ASSERTION(inLeafName, "Attempt to SetLeafName with a null string"); + mPath.LeafReplace('\\', inLeafName); +} // nsFileSpec::SetLeafName + +//---------------------------------------------------------------------------------------- +char* nsFileSpec::GetLeafName() const +//---------------------------------------------------------------------------------------- +{ + return mPath.GetLeaf('\\'); +} // nsFileSpec::GetLeafName + +//---------------------------------------------------------------------------------------- +PRBool nsFileSpec::Exists() const +//---------------------------------------------------------------------------------------- +{ + struct stat st; + return !mPath.IsEmpty() && 0 == stat(nsNSPRPath(*this), &st); +} // nsFileSpec::Exists + +//---------------------------------------------------------------------------------------- +void nsFileSpec::GetModDate(TimeStamp& outStamp) const +//---------------------------------------------------------------------------------------- +{ + struct stat st; + if (!mPath.IsEmpty() && stat(nsNSPRPath(*this), &st) == 0) + outStamp = st.st_mtime; + else + outStamp = 0; +} // nsFileSpec::GetModDate + +//---------------------------------------------------------------------------------------- +PRUint32 nsFileSpec::GetFileSize() const +//---------------------------------------------------------------------------------------- +{ + struct stat st; + if (!mPath.IsEmpty() && stat(nsNSPRPath(*this), &st) == 0) + return (PRUint32)st.st_size; + return 0; +} // nsFileSpec::GetFileSize + +//---------------------------------------------------------------------------------------- +PRBool nsFileSpec::IsFile() const +//---------------------------------------------------------------------------------------- +{ + struct stat st; +#ifdef XP_OS2 + return !mPath.IsEmpty() && 0 == stat(nsNSPRPath(*this), &st) && ( S_IFREG & st.st_mode); +#else + return !mPath.IsEmpty() && 0 == stat(nsNSPRPath(*this), &st) && (_S_IFREG & st.st_mode); +#endif +} // nsFileSpec::IsFile + +//---------------------------------------------------------------------------------------- +PRBool nsFileSpec::IsDirectory() const +//---------------------------------------------------------------------------------------- +{ + struct stat st; +#ifdef XP_OS2 + return !mPath.IsEmpty() && 0 == stat(nsNSPRPath(*this), &st) && ( S_IFDIR & st.st_mode); +#else + return !mPath.IsEmpty() && 0 == stat(nsNSPRPath(*this), &st) && (_S_IFDIR & st.st_mode); +#endif +} // nsFileSpec::IsDirectory + +//---------------------------------------------------------------------------------------- +PRBool nsFileSpec::IsHidden() const +//---------------------------------------------------------------------------------------- +{ + PRBool hidden = PR_FALSE; + if (!mPath.IsEmpty()) + { +#ifdef XP_OS2 + FILESTATUS3 fs3; + APIRET rc; + + rc = DosQueryPathInfo( mPath, + FIL_STANDARD, + &fs3, + sizeof fs3); + if(!rc) + hidden = fs3.attrFile & FILE_HIDDEN ? PR_TRUE : PR_FALSE; +#else + DWORD attr = GetFileAttributes(mPath); + if (FILE_ATTRIBUTE_HIDDEN & attr) + hidden = PR_TRUE; +#endif + } + return hidden; +} +// nsFileSpec::IsHidden + +//---------------------------------------------------------------------------------------- +PRBool nsFileSpec::IsSymlink() const +//---------------------------------------------------------------------------------------- +{ +#ifdef XP_OS2 + return PR_FALSE; // No symlinks on OS/2 +#else + HRESULT hres; + IShellLink* psl; + + PRBool isSymlink = PR_FALSE; + + CoInitialize(NULL); + // Get a pointer to the IShellLink interface. + hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (void**)&psl); + if (SUCCEEDED(hres)) + { + IPersistFile* ppf; + + // Get a pointer to the IPersistFile interface. + hres = psl->QueryInterface(IID_IPersistFile, (void**)&ppf); + + if (SUCCEEDED(hres)) + { + WORD wsz[MAX_PATH]; + // Ensure that the string is Unicode. + MultiByteToWideChar(CP_ACP, 0, mPath, -1, wsz, MAX_PATH); + + // Load the shortcut. + hres = ppf->Load(wsz, STGM_READ); + if (SUCCEEDED(hres)) + { + isSymlink = PR_TRUE; + } + + // Release the pointer to the IPersistFile interface. + ppf->Release(); + } + + // Release the pointer to the IShellLink interface. + psl->Release(); + } + + CoUninitialize(); + + return isSymlink; +#endif +} + + +//---------------------------------------------------------------------------------------- +nsresult nsFileSpec::ResolveSymlink(PRBool& wasSymlink) +//---------------------------------------------------------------------------------------- +{ +#ifdef XP_OS2 + return NS_OK; // no symlinks on OS/2 +#else + wasSymlink = PR_FALSE; // assume failure + + if (Exists()) + return NS_OK; + + + HRESULT hres; + IShellLink* psl; + + CoInitialize(NULL); + + // Get a pointer to the IShellLink interface. + hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (void**)&psl); + if (SUCCEEDED(hres)) + { + IPersistFile* ppf; + + // Get a pointer to the IPersistFile interface. + hres = psl->QueryInterface(IID_IPersistFile, (void**)&ppf); + + if (SUCCEEDED(hres)) + { + WORD wsz[MAX_PATH]; + // Ensure that the string is Unicode. + MultiByteToWideChar(CP_ACP, 0, mPath, -1, wsz, MAX_PATH); + + // Load the shortcut. + hres = ppf->Load(wsz, STGM_READ); + if (SUCCEEDED(hres)) + { + wasSymlink = PR_TRUE; + + // Resolve the link. + hres = psl->Resolve(nsnull, SLR_NO_UI ); + if (SUCCEEDED(hres)) + { + char szGotPath[MAX_PATH]; + WIN32_FIND_DATA wfd; + + // Get the path to the link target. + hres = psl->GetPath( szGotPath, MAX_PATH, &wfd, SLGP_UNCPRIORITY ); + + if (SUCCEEDED(hres)) + { + // Here we modify the nsFileSpec; + mPath = szGotPath; + mError = NS_OK; + } + } + } + else { + // It wasn't a shortcut. Oh well. Leave it like it was. + hres = 0; + } + + // Release the pointer to the IPersistFile interface. + ppf->Release(); + } + // Release the pointer to the IShellLink interface. + psl->Release(); + } + + CoUninitialize(); + + if (SUCCEEDED(hres)) + return NS_OK; + + return NS_FILE_FAILURE; +#endif +} + + + +//---------------------------------------------------------------------------------------- +void nsFileSpec::GetParent(nsFileSpec& outSpec) const +//---------------------------------------------------------------------------------------- +{ + outSpec.mPath = mPath; + char* chars = (char*)outSpec.mPath; + chars[outSpec.mPath.Length() - 1] = '\0'; // avoid trailing separator, if any + char* cp = strrchr(chars, '\\'); + if (cp++) + outSpec.mPath.SetLength(cp - chars); // truncate. +} // nsFileSpec::GetParent + +//---------------------------------------------------------------------------------------- +void nsFileSpec::operator += (const char* inRelativePath) +//---------------------------------------------------------------------------------------- +{ + NS_ASSERTION(inRelativePath, "Attempt to do += with a null string"); + + if (!inRelativePath || mPath.IsEmpty()) + return; + + if (mPath[mPath.Length() - 1] == '\\') + mPath += "x"; + else + mPath += "\\x"; + + // If it's a (unix) relative path, make it native + nsSimpleCharString dosPath = inRelativePath; + nsFileSpecHelpers::UnixToNative(dosPath); + SetLeafName(dosPath); +} // nsFileSpec::operator += + +//---------------------------------------------------------------------------------------- +void nsFileSpec::CreateDirectory(int /*mode*/) +//---------------------------------------------------------------------------------------- +{ + // Note that mPath is canonical! + if (!mPath.IsEmpty()) +#ifdef XP_OS2 + // OS2TODO - vacpp complains about mkdir but PR_MkDir should be ok? + PR_MkDir(nsNSPRPath(*this), PR_CREATE_FILE); +#else + mkdir(nsNSPRPath(*this)); +#endif +} // nsFileSpec::CreateDirectory + +//---------------------------------------------------------------------------------------- +void nsFileSpec::Delete(PRBool inRecursive) const +//---------------------------------------------------------------------------------------- +{ + if (IsDirectory()) + { + if (inRecursive) + { + for (nsDirectoryIterator i(*this, PR_FALSE); i.Exists(); i++) + { + nsFileSpec& child = i.Spec(); + child.Delete(inRecursive); + } + } +#ifdef XP_OS2 + // OS2TODO - vacpp complains if use rmdir but PR_RmDir should be ok? + PR_RmDir(nsNSPRPath(*this)); +#else + rmdir(nsNSPRPath(*this)); +#endif + } + else if (!mPath.IsEmpty()) + { + remove(nsNSPRPath(*this)); + } +} // nsFileSpec::Delete + + +//---------------------------------------------------------------------------------------- +void nsFileSpec::RecursiveCopy(nsFileSpec newDir) const +//---------------------------------------------------------------------------------------- +{ + if (IsDirectory()) + { + if (!(newDir.Exists())) + { + newDir.CreateDirectory(); + } + + for (nsDirectoryIterator i(*this, PR_FALSE); i.Exists(); i++) + { + nsFileSpec& child = i.Spec(); + + if (child.IsDirectory()) + { + nsFileSpec tmpDirSpec(newDir); + + char *leafname = child.GetLeafName(); + tmpDirSpec += leafname; + nsCRT::free(leafname); + + child.RecursiveCopy(tmpDirSpec); + } + else + { + child.RecursiveCopy(newDir); + } + } + } + else if (!mPath.IsEmpty()) + { + nsFileSpec& filePath = (nsFileSpec&) *this; + + if (!(newDir.Exists())) + { + newDir.CreateDirectory(); + } + + filePath.CopyToDir(newDir); + } +} // nsFileSpec::RecursiveCopy + +//---------------------------------------------------------------------------------------- +nsresult +nsFileSpec::Truncate(PRInt32 aNewFileLength) const +//---------------------------------------------------------------------------------------- +{ +#ifdef XP_OS2 + APIRET rc; + HFILE hFile; + ULONG actionTaken; + + rc = DosOpen(mPath, + &hFile, + &actionTaken, + 0, + FILE_NORMAL, + OPEN_ACTION_FAIL_IF_NEW | OPEN_ACTION_OPEN_IF_EXISTS, + OPEN_SHARE_DENYREADWRITE | OPEN_ACCESS_READWRITE, + NULL); + + if (rc != NO_ERROR) + return NS_FILE_FAILURE; + + rc = DosSetFileSize(hFile, aNewFileLength); + + if (rc == NO_ERROR) + DosClose(hFile); + else + goto error; +#else + DWORD status; + HANDLE hFile; + + // Leave it to Microsoft to open an existing file with a function + // named "CreateFile". + hFile = CreateFile(mPath, + GENERIC_WRITE, + FILE_SHARE_READ, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL); + if (hFile == INVALID_HANDLE_VALUE) + return NS_FILE_FAILURE; + + // Seek to new, desired end of file + status = SetFilePointer(hFile, aNewFileLength, NULL, FILE_BEGIN); + if (status == 0xffffffff) + goto error; + + // Truncate file at current cursor position + if (!SetEndOfFile(hFile)) + goto error; + + if (!CloseHandle(hFile)) + return NS_FILE_FAILURE; +#endif + + return NS_OK; + + error: +#ifdef XP_OS2 + DosClose(hFile); +#else + CloseHandle(hFile); +#endif + return NS_FILE_FAILURE; + +} // nsFileSpec::Truncate + +//---------------------------------------------------------------------------------------- +nsresult nsFileSpec::Rename(const char* inNewName) +//---------------------------------------------------------------------------------------- +{ + NS_ASSERTION(inNewName, "Attempt to Rename with a null string"); + + // This function should not be used to move a file on disk. + if (strchr(inNewName, '/')) + return NS_FILE_FAILURE; + + char* oldPath = nsCRT::strdup(mPath); + + SetLeafName(inNewName); + + if (PR_Rename(oldPath, mPath) != NS_OK) + { + // Could not rename, set back to the original. + mPath = oldPath; + return NS_FILE_FAILURE; + } + + nsCRT::free(oldPath); + + return NS_OK; +} // nsFileSpec::Rename + +//---------------------------------------------------------------------------------------- +nsresult nsFileSpec::CopyToDir(const nsFileSpec& inParentDirectory) const +//---------------------------------------------------------------------------------------- +{ + // We can only copy into a directory, and (for now) can not copy entire directories + if (inParentDirectory.IsDirectory() && (! IsDirectory() ) ) + { + char *leafname = GetLeafName(); + nsSimpleCharString destPath(inParentDirectory.GetCString()); + destPath += "\\"; + destPath += leafname; + nsCRT::free(leafname); + + // CopyFile returns non-zero if succeeds +#ifdef XP_OS2 + APIRET rc; + PRBool copyOK; + + rc = DosCopy(GetCString(), (PSZ)destPath, DCPY_EXISTING); + + if (rc == NO_ERROR) + copyOK = PR_TRUE; + else + copyOK = PR_FALSE; +#else + int copyOK = CopyFile(GetCString(), destPath, PR_TRUE); +#endif + if (copyOK) + return NS_OK; + } + return NS_FILE_FAILURE; +} // nsFileSpec::CopyToDir + +//---------------------------------------------------------------------------------------- +nsresult nsFileSpec::MoveToDir(const nsFileSpec& inNewParentDirectory) +//---------------------------------------------------------------------------------------- +{ + // We can only copy into a directory, and (for now) can not copy entire directories + if (inNewParentDirectory.IsDirectory() && (! IsDirectory() ) ) + { + char *leafname = GetLeafName(); + nsSimpleCharString destPath(inNewParentDirectory.GetCString()); + destPath += "\\"; + destPath += leafname; + nsCRT::free(leafname); + + if (DosMove(GetCString(), destPath) == NO_ERROR) + { + *this = inNewParentDirectory + GetLeafName(); + return NS_OK; + } + + } + return NS_FILE_FAILURE; +} // nsFileSpec::MoveToDir + +//---------------------------------------------------------------------------------------- +nsresult nsFileSpec::Execute(const char* inArgs ) const +//---------------------------------------------------------------------------------------- +{ + if (!IsDirectory()) + { +#ifdef XP_OS2 + nsresult result = NS_FILE_FAILURE; + + if (!mPath.IsEmpty()) + { + nsSimpleCharString fileNameWithArgs = mPath + " " + inArgs; + result = NS_FILE_RESULT(system(fileNameWithArgs)); + } + return result; +#else + nsSimpleCharString fileNameWithArgs = "\""; + fileNameWithArgs += mPath + "\" " + inArgs; + int execResult = WinExec( fileNameWithArgs, SW_NORMAL ); + if (execResult > 31) + return NS_OK; +#endif + } + return NS_FILE_FAILURE; +} // nsFileSpec::Execute + + +//---------------------------------------------------------------------------------------- +PRInt64 nsFileSpec::GetDiskSpaceAvailable() const +//---------------------------------------------------------------------------------------- +{ + PRInt64 nBytes = 0; + ULONG ulDriveNo = toupper(mPath[0]) + 1 - 'A'; + FSALLOCATE fsAllocate; + APIRET rc = DosQueryFSInfo(ulDriveNo, + FSIL_ALLOC, + &fsAllocate, + sizeof(fsAllocate)); + + if (rc == NO_ERROR) { + nBytes = fsAllocate.cUnitAvail; + nBytes *= fsAllocate.cSectorUnit; + nBytes *= fsAllocate.cbSector; + } + + return nBytes; +} + + + +//======================================================================================== +// nsDirectoryIterator +//======================================================================================== + +//---------------------------------------------------------------------------------------- +nsDirectoryIterator::nsDirectoryIterator(const nsFileSpec& inDirectory, PRBool resolveSymlink) +//---------------------------------------------------------------------------------------- + : mCurrent(inDirectory) + , mDir(nsnull) + , mStarting(inDirectory) + , mExists(PR_FALSE) + , mResoveSymLinks(resolveSymlink) +{ + mDir = PR_OpenDir(inDirectory); + mCurrent += "dummy"; + mStarting += "dummy"; + ++(*this); +} // nsDirectoryIterator::nsDirectoryIterator + +//---------------------------------------------------------------------------------------- +nsDirectoryIterator::~nsDirectoryIterator() +//---------------------------------------------------------------------------------------- +{ + if (mDir) + PR_CloseDir(mDir); +} // nsDirectoryIterator::nsDirectoryIterator + +//---------------------------------------------------------------------------------------- +nsDirectoryIterator& nsDirectoryIterator::operator ++ () +//---------------------------------------------------------------------------------------- +{ + mExists = PR_FALSE; + if (!mDir) + return *this; + PRDirEntry* entry = PR_ReadDir(mDir, PR_SKIP_BOTH); // Ignore '.' && '..' + if (entry) + { + mExists = PR_TRUE; + mCurrent = mStarting; + mCurrent.SetLeafName(entry->name); + if (mResoveSymLinks) + { + PRBool ignore; + mCurrent.ResolveSymlink(ignore); + } + } + return *this; +} // nsDirectoryIterator::operator ++ + +//---------------------------------------------------------------------------------------- +nsDirectoryIterator& nsDirectoryIterator::operator -- () +//---------------------------------------------------------------------------------------- +{ + return ++(*this); // can't do it backwards. +} // nsDirectoryIterator::operator -- + diff --git a/src/libs/xpcom18a4/xpcom/obsolete/nsFileSpecUnix.cpp b/src/libs/xpcom18a4/xpcom/obsolete/nsFileSpecUnix.cpp new file mode 100644 index 00000000..8acb6330 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/obsolete/nsFileSpecUnix.cpp @@ -0,0 +1,703 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Henry Sobotka + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +// This file is included by nsFileSpec.cpp, and includes the Unix-specific +// implementations. + +#include +#include +#include +#include +#include +#include +#include +#include "xpcom-private.h" +#include "nsError.h" +#include "prio.h" /* for PR_Rename */ +#include "nsAutoBuffer.h" + +#if defined(_SCO_DS) +#define _SVID3 /* for statvfs.h */ +#endif + +#ifdef HAVE_SYS_STATVFS_H +#include +#endif + +#ifdef HAVE_SYS_VFS_H +#include +#endif + +#ifdef HAVE_SYS_STATFS_H +#include +#endif + +#ifdef HAVE_SYS_MOUNT_H +#include +#undef Free +#endif + +#ifdef HAVE_STATVFS +#define STATFS statvfs +#else +#define STATFS statfs +#endif + +#ifndef MAXPATHLEN +#define MAXPATHLEN 1024 /* Guessing this is okay. Works for SCO. */ +#endif + +#if defined(__QNX__) +#include /* for realpath */ +#define f_bavail f_bfree +extern "C" int truncate(const char *, off_t); +#endif + +#if defined(SUNOS4) +extern "C" int statfs(char *, struct statfs *); +#endif + +#if defined(OSF1) +extern "C" int statvfs(const char *, struct statvfs *); +#endif + +#ifdef XP_MACOSX +static void CopyUTF8toUTF16NFC(const nsACString& aSrc, nsAString& aResult); +#endif + +//---------------------------------------------------------------------------------------- +void nsFileSpecHelpers::Canonify(nsSimpleCharString& ioPath, PRBool inMakeDirs) +// Canonify, make absolute, and check whether directories exist +//---------------------------------------------------------------------------------------- +{ + if (ioPath.IsEmpty()) + return; + if (inMakeDirs) + { + const mode_t mode = 0700; + nsFileSpecHelpers::MakeAllDirectories((const char*)ioPath, mode); + } + + errno = 0; // needed? + + if (ioPath[0] != '/') + { + // the ioPath that was passed in is relative. We must cat it to the cwd. + char buffer[MAXPATHLEN]; + + (void) getcwd(buffer, MAXPATHLEN); + + strcat(buffer, "/"); + strcat(buffer, ioPath); + + ioPath = buffer; + } +} // nsFileSpecHelpers::Canonify + +//---------------------------------------------------------------------------------------- +void nsFileSpec::SetLeafName(const char* inLeafName) +//---------------------------------------------------------------------------------------- +{ + mPath.LeafReplace('/', inLeafName); +} // nsFileSpec::SetLeafName + +//---------------------------------------------------------------------------------------- +char* nsFileSpec::GetLeafName() const +//---------------------------------------------------------------------------------------- +{ +#ifndef XP_MACOSX + return mPath.GetLeaf('/'); +#else + char *name = mPath.GetLeaf('/'); + if (!name || !*name) + return name; + nsAutoString nameInNFC; + CopyUTF8toUTF16NFC(nsDependentCString(name), nameInNFC); + nsCRT::free(name); + return nsCRT::strdup(NS_ConvertUTF16toUTF8(nameInNFC).get()); +#endif +} // nsFileSpec::GetLeafName + +//---------------------------------------------------------------------------------------- +PRBool nsFileSpec::Exists() const +//---------------------------------------------------------------------------------------- +{ + struct stat st; + return !mPath.IsEmpty() && 0 == stat(mPath, &st); +} // nsFileSpec::Exists + +//---------------------------------------------------------------------------------------- +void nsFileSpec::GetModDate(TimeStamp& outStamp) const +//---------------------------------------------------------------------------------------- +{ + struct stat st; + if (!mPath.IsEmpty() && stat(mPath, &st) == 0) + outStamp = st.st_mtime; + else + outStamp = 0; +} // nsFileSpec::GetModDate + +//---------------------------------------------------------------------------------------- +PRUint32 nsFileSpec::GetFileSize() const +//---------------------------------------------------------------------------------------- +{ + struct stat st; + if (!mPath.IsEmpty() && stat(mPath, &st) == 0) + return (PRUint32)st.st_size; + return 0; +} // nsFileSpec::GetFileSize + +//---------------------------------------------------------------------------------------- +PRBool nsFileSpec::IsFile() const +//---------------------------------------------------------------------------------------- +{ + struct stat st; + return !mPath.IsEmpty() && stat(mPath, &st) == 0 && S_ISREG(st.st_mode); +} // nsFileSpec::IsFile + +//---------------------------------------------------------------------------------------- +PRBool nsFileSpec::IsDirectory() const +//---------------------------------------------------------------------------------------- +{ + struct stat st; + return !mPath.IsEmpty() && 0 == stat(mPath, &st) && S_ISDIR(st.st_mode); +} // nsFileSpec::IsDirectory + +//---------------------------------------------------------------------------------------- +PRBool nsFileSpec::IsHidden() const +//---------------------------------------------------------------------------------------- +{ + PRBool hidden = PR_FALSE; + char *leafname = GetLeafName(); + if (nsnull != leafname) + { + // rjc: don't return ".", "..", or any file/directory that begins with a "." + + /* if ((!strcmp(leafname, ".")) || (!strcmp(leafname, ".."))) */ + if (leafname[0] == '.') + { + hidden = PR_TRUE; + } + nsCRT::free(leafname); + } + return hidden; +} // nsFileSpec::IsHidden + +//---------------------------------------------------------------------------------------- +PRBool nsFileSpec::IsSymlink() const +//---------------------------------------------------------------------------------------- +{ + struct stat st; + if (!mPath.IsEmpty() && stat(mPath, &st) == 0 && S_ISLNK(st.st_mode)) + return PR_TRUE; + + return PR_FALSE; +} // nsFileSpec::IsSymlink + +//---------------------------------------------------------------------------------------- +nsresult nsFileSpec::ResolveSymlink(PRBool& wasAliased) +//---------------------------------------------------------------------------------------- +{ + wasAliased = PR_FALSE; + + char resolvedPath[MAXPATHLEN]; + int charCount = readlink(mPath, (char*)&resolvedPath, MAXPATHLEN); + if (0 < charCount) + { + if (MAXPATHLEN > charCount) + resolvedPath[charCount] = '\0'; + + wasAliased = PR_TRUE; + + /* if it's not an absolute path, + replace the leaf with what got resolved */ + if (resolvedPath[0] != '/') { + SetLeafName(resolvedPath); + } + else { + mPath = (char*)&resolvedPath; + } + + char* canonicalPath = realpath((const char *)mPath, resolvedPath); + NS_ASSERTION(canonicalPath, "realpath failed"); + if (canonicalPath) { + mPath = (char*)&resolvedPath; + } + else { + return NS_ERROR_FAILURE; + } + } + + return NS_OK; +} // nsFileSpec::ResolveSymlink + + +//---------------------------------------------------------------------------------------- +void nsFileSpec::GetParent(nsFileSpec& outSpec) const +//---------------------------------------------------------------------------------------- +{ + outSpec.mPath = mPath; + char* chars = (char*)outSpec.mPath; + chars[outSpec.mPath.Length() - 1] = '\0'; // avoid trailing separator, if any + char* cp = strrchr(chars, '/'); + if (cp++) + outSpec.mPath.SetLength(cp - chars); // truncate. +} // nsFileSpec::GetParent + +//---------------------------------------------------------------------------------------- +void nsFileSpec::operator += (const char* inRelativePath) +//---------------------------------------------------------------------------------------- +{ + NS_ASSERTION(inRelativePath, "Attempt to do += with a null string"); + + if (!inRelativePath || mPath.IsEmpty()) + return; + + char endChar = mPath[(int)(strlen(mPath) - 1)]; + if (endChar == '/') + mPath += "x"; + else + mPath += "/x"; + SetLeafName(inRelativePath); +} // nsFileSpec::operator += + +//---------------------------------------------------------------------------------------- +void nsFileSpec::CreateDirectory(int mode) +//---------------------------------------------------------------------------------------- +{ + // Note that mPath is canonical! + if (mPath.IsEmpty()) + return; + mkdir(mPath, mode); +} // nsFileSpec::CreateDirectory + +//---------------------------------------------------------------------------------------- +void nsFileSpec::Delete(PRBool inRecursive) const +// To check if this worked, call Exists() afterwards, see? +//---------------------------------------------------------------------------------------- +{ + if (IsDirectory()) + { + if (inRecursive) + { + for (nsDirectoryIterator i(*this, PR_FALSE); i.Exists(); i++) + { + nsFileSpec& child = (nsFileSpec&)i; + child.Delete(inRecursive); + } + } + rmdir(mPath); + } + else if (!mPath.IsEmpty()) + remove(mPath); +} // nsFileSpec::Delete + +//---------------------------------------------------------------------------------------- +void nsFileSpec::RecursiveCopy(nsFileSpec newDir) const +//---------------------------------------------------------------------------------------- +{ + if (IsDirectory()) + { + if (!(newDir.Exists())) + { + newDir.CreateDirectory(); + } + + for (nsDirectoryIterator i(*this, PR_FALSE); i.Exists(); i++) + { + nsFileSpec& child = (nsFileSpec&)i; + + if (child.IsDirectory()) + { + nsFileSpec tmpDirSpec(newDir); + + char *leafname = child.GetLeafName(); + tmpDirSpec += leafname; + nsCRT::free(leafname); + + child.RecursiveCopy(tmpDirSpec); + } + else + { + child.RecursiveCopy(newDir); + } + } + } + else if (!mPath.IsEmpty()) + { + nsFileSpec& filePath = (nsFileSpec&) *this; + + if (!(newDir.Exists())) + { + newDir.CreateDirectory(); + } + + filePath.CopyToDir(newDir); + } +} // nsFileSpec::RecursiveCopy + + +//---------------------------------------------------------------------------------------- +nsresult nsFileSpec::Truncate(PRInt32 offset) const +//---------------------------------------------------------------------------------------- +{ + char* Path = nsCRT::strdup(mPath); + + int rv = truncate(Path, offset) ; + + nsCRT::free(Path) ; + + if(!rv) + return NS_OK ; + else + return NS_ERROR_FAILURE ; +} // nsFileSpec::Truncate + +//---------------------------------------------------------------------------------------- +nsresult nsFileSpec::Rename(const char* inNewName) +//---------------------------------------------------------------------------------------- +{ + NS_ASSERTION(inNewName, "Attempt to Rename with a null string"); + + // This function should not be used to move a file on disk. + if (mPath.IsEmpty() || strchr(inNewName, '/')) + return NS_FILE_FAILURE; + + char* oldPath = nsCRT::strdup(mPath); + + SetLeafName(inNewName); + + if (PR_Rename(oldPath, mPath) != NS_OK) + { + // Could not rename, set back to the original. + mPath = oldPath; + return NS_FILE_FAILURE; + } + + nsCRT::free(oldPath); + + return NS_OK; +} // nsFileSpec::Rename + +//---------------------------------------------------------------------------------------- +static int CrudeFileCopy(const char* in, const char* out) +//---------------------------------------------------------------------------------------- +{ + struct stat in_stat; + int stat_result = -1; + + char buf [1024]; + FILE *ifp, *ofp; + int rbytes, wbytes; + + if (!in || !out) + return -1; + + stat_result = stat (in, &in_stat); + + ifp = fopen (in, "r"); + if (!ifp) + { + return -1; + } + + ofp = fopen (out, "w"); + if (!ofp) + { + fclose (ifp); + return -1; + } + + while ((rbytes = fread (buf, 1, sizeof(buf), ifp)) > 0) + { + while (rbytes > 0) + { + if ( (wbytes = fwrite (buf, 1, rbytes, ofp)) < 0 ) + { + fclose (ofp); + fclose (ifp); + unlink(out); + return -1; + } + rbytes -= wbytes; + } + } + fclose (ofp); + fclose (ifp); + + if (stat_result == 0) + chmod (out, in_stat.st_mode & 0777); + + return 0; +} // nsFileSpec::Rename + +//---------------------------------------------------------------------------------------- +nsresult nsFileSpec::CopyToDir(const nsFileSpec& inParentDirectory) const +//---------------------------------------------------------------------------------------- +{ + // We can only copy into a directory, and (for now) can not copy entire directories + nsresult result = NS_FILE_FAILURE; + + if (inParentDirectory.IsDirectory() && (! IsDirectory() ) ) + { + char *leafname = GetLeafName(); + nsSimpleCharString destPath(inParentDirectory.GetCString()); + destPath += "/"; + destPath += leafname; + nsCRT::free(leafname); + result = NS_FILE_RESULT(CrudeFileCopy(GetCString(), destPath)); + } + return result; +} // nsFileSpec::CopyToDir + +//---------------------------------------------------------------------------------------- +nsresult nsFileSpec::MoveToDir(const nsFileSpec& inNewParentDirectory) +//---------------------------------------------------------------------------------------- +{ + // We can only copy into a directory, and (for now) can not copy entire directories + nsresult result = NS_FILE_FAILURE; + + if (inNewParentDirectory.IsDirectory() && !IsDirectory()) + { + char *leafname = GetLeafName(); + nsSimpleCharString destPath(inNewParentDirectory.GetCString()); + destPath += "/"; + destPath += leafname; + nsCRT::free(leafname); + + result = NS_FILE_RESULT(CrudeFileCopy(GetCString(), (const char*)destPath)); + if (result == NS_OK) + { + // cast to fix const-ness + ((nsFileSpec*)this)->Delete(PR_FALSE); + + *this = inNewParentDirectory + GetLeafName(); + } + } + return result; +} + +//---------------------------------------------------------------------------------------- +nsresult nsFileSpec::Execute(const char* inArgs ) const +//---------------------------------------------------------------------------------------- +{ + nsresult result = NS_FILE_FAILURE; + + if (!mPath.IsEmpty() && !IsDirectory()) + { + nsSimpleCharString fileNameWithArgs = mPath + " " + inArgs; + result = NS_FILE_RESULT(system(fileNameWithArgs)); + } + + return result; + +} // nsFileSpec::Execute + +//---------------------------------------------------------------------------------------- +PRInt64 nsFileSpec::GetDiskSpaceAvailable() const +//---------------------------------------------------------------------------------------- +{ + PRInt64 bytes; /* XXX dougt needs to fix this */ + LL_I2L(bytes , LONG_MAX); // initialize to all the space in the world? + + +#if defined(HAVE_SYS_STATFS_H) || defined(HAVE_SYS_STATVFS_H) + + char curdir [MAXPATHLEN]; + if (mPath.IsEmpty()) + { + (void) getcwd(curdir, MAXPATHLEN); + if (!curdir) + return bytes; /* hope for the best as we did in cheddar */ + } + else + sprintf(curdir, "%.200s", (const char*)mPath); + + struct STATFS fs_buf; +#if defined(__QNX__) && !defined(HAVE_STATVFS) /* Maybe this should be handled differently? */ + if (STATFS(curdir, &fs_buf, 0, 0) < 0) +#else + if (STATFS(curdir, &fs_buf) < 0) +#endif + return bytes; /* hope for the best as we did in cheddar */ + +#ifdef DEBUG_DISK_SPACE + printf("DiskSpaceAvailable: %d bytes\n", + fs_buf.f_bsize * (fs_buf.f_bavail - 1)); +#endif + + PRInt64 bsize,bavail; + LL_I2L( bsize, fs_buf.f_bsize ); + LL_I2L( bavail, fs_buf.f_bavail - 1 ); + LL_MUL( bytes, bsize, bavail ); + return bytes; + +#else + /* + ** This platform doesn't have statfs or statvfs, so we don't have much + ** choice but to "hope for the best as we did in cheddar". + */ + return bytes; +#endif /* HAVE_SYS_STATFS_H or HAVE_SYS_STATVFS_H */ + +} // nsFileSpec::GetDiskSpace() + +//======================================================================================== +// nsDirectoryIterator +//======================================================================================== + +//---------------------------------------------------------------------------------------- +nsDirectoryIterator::nsDirectoryIterator(const nsFileSpec& inDirectory, PRBool resolveSymLinks) +//---------------------------------------------------------------------------------------- + : mCurrent(inDirectory) + , mExists(PR_FALSE) + , mResoveSymLinks(resolveSymLinks) + , mStarting(inDirectory) + , mDir(nsnull) + +{ + mStarting += "sysygy"; // save off the starting directory + mCurrent += "sysygy"; // prepare the path for SetLeafName + mDir = opendir((const char*)nsFilePath(inDirectory)); + ++(*this); +} // nsDirectoryIterator::nsDirectoryIterator + +//---------------------------------------------------------------------------------------- +nsDirectoryIterator::~nsDirectoryIterator() +//---------------------------------------------------------------------------------------- +{ + if (mDir) + closedir(mDir); +} // nsDirectoryIterator::nsDirectoryIterator + +//---------------------------------------------------------------------------------------- +nsDirectoryIterator& nsDirectoryIterator::operator ++ () +//---------------------------------------------------------------------------------------- +{ + mExists = PR_FALSE; + if (!mDir) + return *this; + const char dot[] = "."; + const char dotdot[] = ".."; + struct dirent* entry = readdir(mDir); + if (entry && strcmp(entry->d_name, dot) == 0) + entry = readdir(mDir); + if (entry && strcmp(entry->d_name, dotdot) == 0) + entry = readdir(mDir); + if (entry) + { + mExists = PR_TRUE; + mCurrent = mStarting; // restore mCurrent to be the starting directory. ResolveSymlink() may have taken us to another directory + mCurrent.SetLeafName(entry->d_name); + if (mResoveSymLinks) + { + PRBool ignore; + mCurrent.ResolveSymlink(ignore); + } + } + return *this; +} // nsDirectoryIterator::operator ++ + +//---------------------------------------------------------------------------------------- +nsDirectoryIterator& nsDirectoryIterator::operator -- () +//---------------------------------------------------------------------------------------- +{ + return ++(*this); // can't do it backwards. +} // nsDirectoryIterator::operator -- + +// Convert a UTF-8 string to a UTF-16 string while normalizing to +// Normalization Form C (composed Unicode). We need this because +// Mac OS X file system uses NFD (Normalization Form D : decomposed Unicode) +// while most other OS', server-side programs usually expect NFC. + +#ifdef XP_MACOSX +typedef void (*UnicodeNormalizer) (CFMutableStringRef, CFStringNormalizationForm); +static void CopyUTF8toUTF16NFC(const nsACString& aSrc, nsAString& aResult) +{ + static PRBool sChecked = PR_FALSE; + static UnicodeNormalizer sUnicodeNormalizer = NULL; + + // CFStringNormalize was not introduced until Mac OS 10.2 + if (!sChecked) { + CFBundleRef carbonBundle = + CFBundleGetBundleWithIdentifier(CFSTR("com.apple.Carbon")); + if (carbonBundle) + sUnicodeNormalizer = (UnicodeNormalizer) + ::CFBundleGetFunctionPointerForName(carbonBundle, + CFSTR("CFStringNormalize")); + sChecked = PR_TRUE; + } + + if (!sUnicodeNormalizer) { // OS X 10.1 or earlier + CopyUTF8toUTF16(aSrc, aResult); + return; + } + + const nsAFlatCString &inFlatSrc = PromiseFlatCString(aSrc); + + // The number of 16bit code units in a UTF-16 string will never be + // larger than the number of bytes in the corresponding UTF-8 string. + CFMutableStringRef inStr = + ::CFStringCreateMutable(NULL, inFlatSrc.Length()); + + if (!inStr) { + CopyUTF8toUTF16(aSrc, aResult); + return; + } + + ::CFStringAppendCString(inStr, inFlatSrc.get(), kCFStringEncodingUTF8); + + sUnicodeNormalizer(inStr, kCFStringNormalizationFormC); + + CFIndex length = CFStringGetLength(inStr); + const UniChar* chars = CFStringGetCharactersPtr(inStr); + + if (chars) + aResult.Assign(chars, length); + else { + nsAutoBuffer buffer; + if (buffer.EnsureElemCapacity(length)) { + CFStringGetCharacters(inStr, CFRangeMake(0, length), buffer.get()); + aResult.Assign(buffer.get(), length); + } + else + CopyUTF8toUTF16(aSrc, aResult); + } + CFRelease(inStr); +} +#endif diff --git a/src/libs/xpcom18a4/xpcom/obsolete/nsFileSpecWin.cpp b/src/libs/xpcom18a4/xpcom/obsolete/nsFileSpecWin.cpp new file mode 100644 index 00000000..7d7e863d --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/obsolete/nsFileSpecWin.cpp @@ -0,0 +1,766 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +// This file is included by nsFileSpec.cp, and includes the Windows-specific +// implementations. + +#include +#include +#include +#include +#include "prio.h" +#include "nsError.h" + +#include + +#if (_MSC_VER == 1100) || defined(__GNUC__) +#define INITGUID +#include +DEFINE_OLEGUID(IID_IPersistFile, 0x0000010BL, 0, 0); +#endif + +#include +#include +#include + +#ifdef UNICODE +#define CreateDirectoryW CreateDirectory +#else +#define CreateDirectoryA CreateDirectory +#endif + +//---------------------------------------------------------------------------------------- +void nsFileSpecHelpers::Canonify(nsSimpleCharString& ioPath, PRBool inMakeDirs) +// Canonify, make absolute, and check whether directories exist. This +// takes a (possibly relative) native path and converts it into a +// fully qualified native path. +//---------------------------------------------------------------------------------------- +{ + if (ioPath.IsEmpty()) + return; + + NS_ASSERTION(strchr((const char*)ioPath, '/') == 0, + "This smells like a Unix path. Native path expected! " + "Please fix."); + if (inMakeDirs) + { + const int mode = 0755; + nsSimpleCharString unixStylePath = ioPath; + nsFileSpecHelpers::NativeToUnix(unixStylePath); + nsFileSpecHelpers::MakeAllDirectories((const char*)unixStylePath, mode); + } + char buffer[_MAX_PATH]; + errno = 0; + *buffer = '\0'; + char* canonicalPath = _fullpath(buffer, ioPath, _MAX_PATH); + + if (canonicalPath) + { + NS_ASSERTION( canonicalPath[0] != '\0', "Uh oh...couldn't convert" ); + if (canonicalPath[0] == '\0') + return; + } + ioPath = canonicalPath; +} // nsFileSpecHelpers::Canonify + +//---------------------------------------------------------------------------------------- +void nsFileSpecHelpers::UnixToNative(nsSimpleCharString& ioPath) +// This just does string manipulation. It doesn't check reality, or canonify, or +// anything +//---------------------------------------------------------------------------------------- +{ + // Allow for relative or absolute. We can do this in place, because the + // native path is never longer. + + if (ioPath.IsEmpty()) + return; + + // Strip initial slash for an absolute path + char* src = (char*)ioPath; + if (*src == '/') { + if (!src[1]) { + // allocate new string by copying from ioPath[1] + nsSimpleCharString temp = src + 1; + ioPath = temp; + return; + } + // Since it was an absolute path, check for the drive letter + char* colonPointer = src + 2; + if (strstr(src, "|/") == colonPointer) + *colonPointer = ':'; + // allocate new string by copying from ioPath[1] + nsSimpleCharString temp = src + 1; + ioPath = temp; + } + + // Convert '/' to '\'. (Must check EVERY character: consider UNC path + // case.) + for (src = (char*)ioPath; *src; ++src) + { + if (*src == '/') + *src = '\\'; + } + +} // nsFileSpecHelpers::UnixToNative + +//---------------------------------------------------------------------------------------- +void nsFileSpecHelpers::NativeToUnix(nsSimpleCharString& ioPath) +// This just does string manipulation. It doesn't check reality, or canonify, or +// anything. The unix path is longer, so we can't do it in place. +//---------------------------------------------------------------------------------------- +{ + if (ioPath.IsEmpty()) + return; + + // Convert the drive-letter separator, if present + nsSimpleCharString temp("/"); + + char* cp = (char*)ioPath + 1; + if (strstr(cp, ":\\") == cp) + *cp = '|'; // absolute path + else + if (cp[0] == '\\') // unc path + cp--; + else + temp[0] = '\0'; // relative path + + // Convert '\' to '/' + for (; *cp; cp++) + { + if(IsDBCSLeadByte(*cp) && *(cp+1) != nsnull) + { + cp++; + continue; + } + if (*cp == '\\') + *cp = '/'; + } + // Add the slash in front. + temp += ioPath; + ioPath = temp; +} + +//---------------------------------------------------------------------------------------- +nsFileSpec::nsFileSpec(const nsFilePath& inPath) +//---------------------------------------------------------------------------------------- +{ +// NS_ASSERTION(0, "nsFileSpec is unsupported - use nsIFile!"); + *this = inPath; +} + +//---------------------------------------------------------------------------------------- +void nsFileSpec::operator = (const nsFilePath& inPath) +//---------------------------------------------------------------------------------------- +{ + mPath = (const char*)inPath; + nsFileSpecHelpers::UnixToNative(mPath); + mError = NS_OK; +} // nsFileSpec::operator = + +//---------------------------------------------------------------------------------------- +nsFilePath::nsFilePath(const nsFileSpec& inSpec) +//---------------------------------------------------------------------------------------- +{ + *this = inSpec; +} // nsFilePath::nsFilePath + +//---------------------------------------------------------------------------------------- +void nsFilePath::operator = (const nsFileSpec& inSpec) +//---------------------------------------------------------------------------------------- +{ + mPath = inSpec.mPath; + nsFileSpecHelpers::NativeToUnix(mPath); +} // nsFilePath::operator = + +//---------------------------------------------------------------------------------------- +void nsFileSpec::SetLeafName(const char* inLeafName) +//---------------------------------------------------------------------------------------- +{ + NS_ASSERTION(inLeafName, "Attempt to SetLeafName with a null string"); + mPath.LeafReplace('\\', inLeafName); +} // nsFileSpec::SetLeafName + +//---------------------------------------------------------------------------------------- +char* nsFileSpec::GetLeafName() const +//---------------------------------------------------------------------------------------- +{ + return mPath.GetLeaf('\\'); +} // nsFileSpec::GetLeafName + +//---------------------------------------------------------------------------------------- +PRBool nsFileSpec::Exists() const +//---------------------------------------------------------------------------------------- +{ + struct stat st; + return !mPath.IsEmpty() && 0 == stat(nsNSPRPath(*this), &st); +} // nsFileSpec::Exists + +//---------------------------------------------------------------------------------------- +void nsFileSpec::GetModDate(TimeStamp& outStamp) const +//---------------------------------------------------------------------------------------- +{ + struct stat st; + if (!mPath.IsEmpty() && stat(nsNSPRPath(*this), &st) == 0) + outStamp = st.st_mtime; + else + outStamp = 0; +} // nsFileSpec::GetModDate + +//---------------------------------------------------------------------------------------- +PRUint32 nsFileSpec::GetFileSize() const +//---------------------------------------------------------------------------------------- +{ + struct stat st; + if (!mPath.IsEmpty() && stat(nsNSPRPath(*this), &st) == 0) + return (PRUint32)st.st_size; + return 0; +} // nsFileSpec::GetFileSize + +//---------------------------------------------------------------------------------------- +PRBool nsFileSpec::IsFile() const +//---------------------------------------------------------------------------------------- +{ + struct stat st; + return !mPath.IsEmpty() && 0 == stat(nsNSPRPath(*this), &st) && (_S_IFREG & st.st_mode); +} // nsFileSpec::IsFile + +//---------------------------------------------------------------------------------------- +PRBool nsFileSpec::IsDirectory() const +//---------------------------------------------------------------------------------------- +{ + struct stat st; + return !mPath.IsEmpty() && 0 == stat(nsNSPRPath(*this), &st) && (_S_IFDIR & st.st_mode); +} // nsFileSpec::IsDirectory + +//---------------------------------------------------------------------------------------- +PRBool nsFileSpec::IsHidden() const +//---------------------------------------------------------------------------------------- +{ + PRBool hidden = PR_FALSE; + if (!mPath.IsEmpty()) + { + DWORD attr = GetFileAttributes(mPath); + if (FILE_ATTRIBUTE_HIDDEN & attr) + hidden = PR_TRUE; + } + return hidden; +} +// nsFileSpec::IsHidden + +//---------------------------------------------------------------------------------------- +PRBool nsFileSpec::IsSymlink() const +//---------------------------------------------------------------------------------------- +{ + HRESULT hres; + IShellLink* psl; + + PRBool isSymlink = PR_FALSE; + + CoInitialize(NULL); + // Get a pointer to the IShellLink interface. + hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (void**)&psl); + if (SUCCEEDED(hres)) + { + IPersistFile* ppf; + + // Get a pointer to the IPersistFile interface. + hres = psl->QueryInterface(IID_IPersistFile, (void**)&ppf); + + if (SUCCEEDED(hres)) + { + WCHAR wsz[MAX_PATH]; + // Ensure that the string is Unicode. + MultiByteToWideChar(CP_ACP, 0, mPath, -1, wsz, MAX_PATH); + + // Load the shortcut. + hres = ppf->Load(wsz, STGM_READ); + if (SUCCEEDED(hres)) + { + isSymlink = PR_TRUE; + } + + // Release the pointer to the IPersistFile interface. + ppf->Release(); + } + + // Release the pointer to the IShellLink interface. + psl->Release(); + } + + CoUninitialize(); + + return isSymlink; +} + + +//---------------------------------------------------------------------------------------- +nsresult nsFileSpec::ResolveSymlink(PRBool& wasSymlink) +//---------------------------------------------------------------------------------------- +{ + wasSymlink = PR_FALSE; // assume failure + + if (Exists()) + return NS_OK; + + + HRESULT hres; + IShellLink* psl; + + CoInitialize(NULL); + + // Get a pointer to the IShellLink interface. + hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (void**)&psl); + if (SUCCEEDED(hres)) + { + IPersistFile* ppf; + + // Get a pointer to the IPersistFile interface. + hres = psl->QueryInterface(IID_IPersistFile, (void**)&ppf); + + if (SUCCEEDED(hres)) + { + WCHAR wsz[MAX_PATH]; + // Ensure that the string is Unicode. + MultiByteToWideChar(CP_ACP, 0, mPath, -1, wsz, MAX_PATH); + + // Load the shortcut. + hres = ppf->Load(wsz, STGM_READ); + if (SUCCEEDED(hres)) + { + wasSymlink = PR_TRUE; + + // Resolve the link. + hres = psl->Resolve(nsnull, SLR_NO_UI ); + if (SUCCEEDED(hres)) + { + char szGotPath[MAX_PATH]; + WIN32_FIND_DATA wfd; + + // Get the path to the link target. + hres = psl->GetPath( szGotPath, MAX_PATH, &wfd, SLGP_UNCPRIORITY ); + + if (SUCCEEDED(hres)) + { + // Here we modify the nsFileSpec; + mPath = szGotPath; + mError = NS_OK; + } + } + } + else { + // It wasn't a shortcut. Oh well. Leave it like it was. + hres = 0; + } + + // Release the pointer to the IPersistFile interface. + ppf->Release(); + } + // Release the pointer to the IShellLink interface. + psl->Release(); + } + + CoUninitialize(); + + if (SUCCEEDED(hres)) + return NS_OK; + + return NS_FILE_FAILURE; +} + + + +//---------------------------------------------------------------------------------------- +void nsFileSpec::GetParent(nsFileSpec& outSpec) const +//---------------------------------------------------------------------------------------- +{ + outSpec.mPath = mPath; + char* chars = (char*)outSpec.mPath; + chars[outSpec.mPath.Length() - 1] = '\0'; // avoid trailing separator, if any + char* cp = strrchr(chars, '\\'); + if (cp++) + outSpec.mPath.SetLength(cp - chars); // truncate. +} // nsFileSpec::GetParent + +//---------------------------------------------------------------------------------------- +void nsFileSpec::operator += (const char* inRelativePath) +//---------------------------------------------------------------------------------------- +{ + NS_ASSERTION(inRelativePath, "Attempt to do += with a null string"); + + if (!inRelativePath || mPath.IsEmpty()) + return; + + if (mPath[mPath.Length() - 1] == '\\') + mPath += "x"; + else + mPath += "\\x"; + + // If it's a (unix) relative path, make it native + nsSimpleCharString dosPath = inRelativePath; + nsFileSpecHelpers::UnixToNative(dosPath); + SetLeafName(dosPath); +} // nsFileSpec::operator += + +//---------------------------------------------------------------------------------------- +void nsFileSpec::CreateDirectory(int /*mode*/) +//---------------------------------------------------------------------------------------- +{ + // Note that mPath is canonical! + if (!mPath.IsEmpty()) + mkdir(nsNSPRPath(*this)); +} // nsFileSpec::CreateDirectory + +//---------------------------------------------------------------------------------------- +void nsFileSpec::Delete(PRBool inRecursive) const +//---------------------------------------------------------------------------------------- +{ + if (IsDirectory()) + { + if (inRecursive) + { + for (nsDirectoryIterator i(*this, PR_FALSE); i.Exists(); i++) + { + nsFileSpec& child = (nsFileSpec&)i; + child.Delete(inRecursive); + } + } + rmdir(nsNSPRPath(*this)); + } + else if (!mPath.IsEmpty()) + { + remove(nsNSPRPath(*this)); + } +} // nsFileSpec::Delete + + +//---------------------------------------------------------------------------------------- +void nsFileSpec::RecursiveCopy(nsFileSpec newDir) const +//---------------------------------------------------------------------------------------- +{ + if (IsDirectory()) + { + if (!(newDir.Exists())) + { + newDir.CreateDirectory(); + } + + for (nsDirectoryIterator i(*this, PR_FALSE); i.Exists(); i++) + { + nsFileSpec& child = (nsFileSpec&)i; + + if (child.IsDirectory()) + { + nsFileSpec tmpDirSpec(newDir); + + char *leafname = child.GetLeafName(); + tmpDirSpec += leafname; + nsCRT::free(leafname); + + child.RecursiveCopy(tmpDirSpec); + } + else + { + child.RecursiveCopy(newDir); + } + } + } + else if (!mPath.IsEmpty()) + { + nsFileSpec& filePath = (nsFileSpec&) *this; + + if (!(newDir.Exists())) + { + newDir.CreateDirectory(); + } + + filePath.CopyToDir(newDir); + } +} // nsFileSpec::RecursiveCopy + +//---------------------------------------------------------------------------------------- +nsresult +nsFileSpec::Truncate(PRInt32 aNewFileLength) const +//---------------------------------------------------------------------------------------- +{ + DWORD status; + HANDLE hFile; + + // Leave it to Microsoft to open an existing file with a function + // named "CreateFile". + hFile = CreateFile(mPath, + GENERIC_WRITE, + FILE_SHARE_READ, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL); + if (hFile == INVALID_HANDLE_VALUE) + return NS_FILE_FAILURE; + + // Seek to new, desired end of file + status = SetFilePointer(hFile, aNewFileLength, NULL, FILE_BEGIN); + if (status == 0xffffffff) + goto error; + + // Truncate file at current cursor position + if (!SetEndOfFile(hFile)) + goto error; + + if (!CloseHandle(hFile)) + return NS_FILE_FAILURE; + + return NS_OK; + + error: + CloseHandle(hFile); + return NS_FILE_FAILURE; + +} // nsFileSpec::Truncate + +//---------------------------------------------------------------------------------------- +nsresult nsFileSpec::Rename(const char* inNewName) +//---------------------------------------------------------------------------------------- +{ + NS_ASSERTION(inNewName, "Attempt to Rename with a null string"); + + // This function should not be used to move a file on disk. + if (strchr(inNewName, '/')) + return NS_FILE_FAILURE; + + char* oldPath = nsCRT::strdup(mPath); + + SetLeafName(inNewName); + + if (PR_Rename(oldPath, mPath) != NS_OK) + { + // Could not rename, set back to the original. + mPath = oldPath; + return NS_FILE_FAILURE; + } + + nsCRT::free(oldPath); + + return NS_OK; +} // nsFileSpec::Rename + +//---------------------------------------------------------------------------------------- +nsresult nsFileSpec::CopyToDir(const nsFileSpec& inParentDirectory) const +//---------------------------------------------------------------------------------------- +{ + // We can only copy into a directory, and (for now) can not copy entire directories + if (inParentDirectory.IsDirectory() && (! IsDirectory() ) ) + { + char *leafname = GetLeafName(); + nsSimpleCharString destPath(inParentDirectory.GetCString()); + destPath += "\\"; + destPath += leafname; + nsCRT::free(leafname); + + // CopyFile returns non-zero if succeeds + int copyOK = CopyFile(GetCString(), destPath, PR_TRUE); + if (copyOK) + return NS_OK; + } + return NS_FILE_FAILURE; +} // nsFileSpec::CopyToDir + +//---------------------------------------------------------------------------------------- +nsresult nsFileSpec::MoveToDir(const nsFileSpec& inNewParentDirectory) +//---------------------------------------------------------------------------------------- +{ + // We can only copy into a directory, and (for now) can not copy entire directories + if (inNewParentDirectory.IsDirectory() && (! IsDirectory() ) ) + { + char *leafname = GetLeafName(); + nsSimpleCharString destPath(inNewParentDirectory.GetCString()); + destPath += "\\"; + destPath += leafname; + nsCRT::free(leafname); + + // MoveFile returns non-zero if succeeds + int copyOK = MoveFile(GetCString(), destPath); + + if (copyOK) + { + *this = inNewParentDirectory + GetLeafName(); + return NS_OK; + } + + } + return NS_FILE_FAILURE; +} // nsFileSpec::MoveToDir + +//---------------------------------------------------------------------------------------- +nsresult nsFileSpec::Execute(const char* inArgs ) const +//---------------------------------------------------------------------------------------- +{ + if (!IsDirectory()) + { + nsSimpleCharString fileNameWithArgs = "\""; + fileNameWithArgs += mPath + "\" " + inArgs; + int execResult = WinExec( fileNameWithArgs, SW_NORMAL ); + if (execResult > 31) + return NS_OK; + } + return NS_FILE_FAILURE; +} // nsFileSpec::Execute + + +//---------------------------------------------------------------------------------------- +PRInt64 nsFileSpec::GetDiskSpaceAvailable() const +//---------------------------------------------------------------------------------------- +{ + PRInt64 int64; + + LL_I2L(int64 , LONG_MAX); + + char aDrive[_MAX_DRIVE + 2]; + _splitpath( (const char*)mPath, aDrive, NULL, NULL, NULL); + + if (aDrive[0] == '\0') + { + // The back end is always trying to pass us paths that look + // like /c|/netscape/mail. See if we've got one of them + if (mPath.Length() > 2 && mPath[0] == '/' && mPath[2] == '|') + { + aDrive[0] = mPath[1]; + aDrive[1] = ':'; + aDrive[2] = '\0'; + } + else + { + // Return bogus large number and hope for the best + return int64; + } + } + + strcat(aDrive, "\\"); + + // Check disk space + DWORD dwSecPerClus, dwBytesPerSec, dwFreeClus, dwTotalClus; + ULARGE_INTEGER liFreeBytesAvailableToCaller, liTotalNumberOfBytes, liTotalNumberOfFreeBytes; + double nBytes = 0; + + BOOL (WINAPI* getDiskFreeSpaceExA)(LPCTSTR lpDirectoryName, + PULARGE_INTEGER lpFreeBytesAvailableToCaller, + PULARGE_INTEGER lpTotalNumberOfBytes, + PULARGE_INTEGER lpTotalNumberOfFreeBytes) = NULL; + + HINSTANCE hInst = LoadLibrary("KERNEL32.DLL"); + NS_ASSERTION(hInst != NULL, "COULD NOT LOAD KERNEL32.DLL"); + if (hInst != NULL) + { + getDiskFreeSpaceExA = (BOOL (WINAPI*)(LPCTSTR lpDirectoryName, + PULARGE_INTEGER lpFreeBytesAvailableToCaller, + PULARGE_INTEGER lpTotalNumberOfBytes, + PULARGE_INTEGER lpTotalNumberOfFreeBytes)) + GetProcAddress(hInst, "GetDiskFreeSpaceExA"); + FreeLibrary(hInst); + } + + if (getDiskFreeSpaceExA && (*getDiskFreeSpaceExA)(aDrive, + &liFreeBytesAvailableToCaller, + &liTotalNumberOfBytes, + &liTotalNumberOfFreeBytes)) + { + nBytes = (double)(signed __int64)liFreeBytesAvailableToCaller.QuadPart; + } + else if ( GetDiskFreeSpace(aDrive, &dwSecPerClus, &dwBytesPerSec, &dwFreeClus, &dwTotalClus)) + { + nBytes = (double)dwFreeClus*(double)dwSecPerClus*(double) dwBytesPerSec; + } + return (PRInt64)nBytes; +} + + + +//======================================================================================== +// nsDirectoryIterator +//======================================================================================== + +//---------------------------------------------------------------------------------------- +nsDirectoryIterator::nsDirectoryIterator(const nsFileSpec& inDirectory, PRBool resolveSymlink) +//---------------------------------------------------------------------------------------- + : mCurrent(inDirectory) + , mDir(nsnull) + , mStarting(inDirectory) + , mExists(PR_FALSE) + , mResoveSymLinks(resolveSymlink) +{ + mDir = PR_OpenDir(inDirectory); + mCurrent += "dummy"; + mStarting += "dummy"; + ++(*this); +} // nsDirectoryIterator::nsDirectoryIterator + +//---------------------------------------------------------------------------------------- +nsDirectoryIterator::~nsDirectoryIterator() +//---------------------------------------------------------------------------------------- +{ + if (mDir) + PR_CloseDir(mDir); +} // nsDirectoryIterator::nsDirectoryIterator + +//---------------------------------------------------------------------------------------- +nsDirectoryIterator& nsDirectoryIterator::operator ++ () +//---------------------------------------------------------------------------------------- +{ + mExists = PR_FALSE; + if (!mDir) + return *this; + PRDirEntry* entry = PR_ReadDir(mDir, PR_SKIP_BOTH); // Ignore '.' && '..' + if (entry) + { + mExists = PR_TRUE; + mCurrent = mStarting; + mCurrent.SetLeafName(entry->name); + if (mResoveSymLinks) + { + PRBool ignore; + mCurrent.ResolveSymlink(ignore); + } + } + return *this; +} // nsDirectoryIterator::operator ++ + +//---------------------------------------------------------------------------------------- +nsDirectoryIterator& nsDirectoryIterator::operator -- () +//---------------------------------------------------------------------------------------- +{ + return ++(*this); // can't do it backwards. +} // nsDirectoryIterator::operator -- + diff --git a/src/libs/xpcom18a4/xpcom/obsolete/nsFileStream.cpp b/src/libs/xpcom18a4/xpcom/obsolete/nsFileStream.cpp new file mode 100644 index 00000000..f20c60e3 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/obsolete/nsFileStream.cpp @@ -0,0 +1,392 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +// First checked in on 98/12/08 by John R. McMullen. +// Since nsFileStream.h is entirely templates, common code (such as open()) +// which does not actually depend on the charT, can be placed here. + +#include "nsFileStream.h" +#include "nsFileSpec.h" +#include "nsIFileSpec.h" +#include "nsIStringStream.h" +#include "nsInt64.h" +#include +#include + + +//======================================================================================== +// nsInputStream +//======================================================================================== + +//---------------------------------------------------------------------------------------- +nsInputStream::~nsInputStream() +//---------------------------------------------------------------------------------------- +{ +} + +//---------------------------------------------------------------------------------------- +char nsInputStream::get() +//---------------------------------------------------------------------------------------- +{ + char c; + if (read(&c, sizeof(c)) == sizeof(c)) + return c; + return 0; +} + +//---------------------------------------------------------------------------------------- +PRInt32 nsInputStream::read(void* s, PRInt32 n) +//---------------------------------------------------------------------------------------- +{ + if (!mInputStream) + return 0; + PRInt32 result = 0; + mInputStream->Read((char*)s, n, (PRUint32*)&result); + if (result == 0) + set_at_eof(PR_TRUE); + return result; +} // nsInputStream::read + +//---------------------------------------------------------------------------------------- +static void TidyEndOfLine(char*& cp) +// Assumes that cp is pointing at \n or \r. Nulls out the character, checks for +// a second terminator (of the opposite persuasion), and returns cp pointing past the +// entire eol construct (one or two characters). +//---------------------------------------------------------------------------------------- +{ + char ch = *cp; + *cp++ = '\0'; // terminate at the newline, then skip past it + if ((ch == '\n' && *cp == '\r') || (ch == '\r' && *cp == '\n')) + cp++; // possibly a pair. +} + +//---------------------------------------------------------------------------------------- +nsInputStream& nsInputStream::operator >> (char& c) +//---------------------------------------------------------------------------------------- +{ + c = get(); + return *this; +} + +//======================================================================================== +// nsOutputStream +//======================================================================================== + +//---------------------------------------------------------------------------------------- +nsOutputStream::~nsOutputStream() +//---------------------------------------------------------------------------------------- +{ +} + +//---------------------------------------------------------------------------------------- +void nsOutputStream::put(char c) +//---------------------------------------------------------------------------------------- +{ + write(&c, sizeof(c)); +} + +//---------------------------------------------------------------------------------------- +PRInt32 nsOutputStream::write(const void* s, PRInt32 n) +//---------------------------------------------------------------------------------------- +{ + if (!mOutputStream) + return 0; + PRInt32 result = 0; + mWriteStatus = mOutputStream->Write((char*)s, n, (PRUint32*)&result); + return result; +} // nsOutputStream::write + +//---------------------------------------------------------------------------------------- +nsresult nsOutputStream::flush() +//---------------------------------------------------------------------------------------- +{ + return NS_OK; +} + +//---------------------------------------------------------------------------------------- +nsresult nsOutputStream::lastWriteStatus() +//---------------------------------------------------------------------------------------- +{ + return mWriteStatus; +} + +//---------------------------------------------------------------------------------------- +nsOutputStream& nsOutputStream::operator << (char c) +//---------------------------------------------------------------------------------------- +{ + put(c); + return *this; +} + +//---------------------------------------------------------------------------------------- +nsOutputStream& nsOutputStream::operator << (const char* s) +//---------------------------------------------------------------------------------------- +{ + if (s) + write(s, strlen(s)); + return *this; +} + +//---------------------------------------------------------------------------------------- +nsOutputStream& nsOutputStream::operator << (short val) +//---------------------------------------------------------------------------------------- +{ + char buf[30]; + sprintf(buf, "%hd", val); + return (*this << buf); +} + +//---------------------------------------------------------------------------------------- +nsOutputStream& nsOutputStream::operator << (unsigned short val) +//---------------------------------------------------------------------------------------- +{ + char buf[30]; + sprintf(buf, "%hu", val); + return (*this << buf); +} + +//---------------------------------------------------------------------------------------- +nsOutputStream& nsOutputStream::operator << (long val) +//---------------------------------------------------------------------------------------- +{ + char buf[30]; + sprintf(buf, "%ld", val); + return (*this << buf); +} + +//---------------------------------------------------------------------------------------- +nsOutputStream& nsOutputStream::operator << (unsigned long val) +//---------------------------------------------------------------------------------------- +{ + char buf[30]; + sprintf(buf, "%lu", val); + return (*this << buf); +} + +//---------------------------------------------------------------------------------------- +nsOutputStream& nsOutputStream::operator << (int val) +//---------------------------------------------------------------------------------------- +{ + char buf[30]; + sprintf(buf, "%d", val); + return (*this << buf); +} + +//---------------------------------------------------------------------------------------- +nsOutputStream& nsOutputStream::operator << (unsigned int val) +//---------------------------------------------------------------------------------------- +{ + char buf[30]; + sprintf(buf, "%u", val); + return (*this << buf); +} + +//======================================================================================== +// nsRandomAccessInputStream +//======================================================================================== + +//---------------------------------------------------------------------------------------- +PRBool nsRandomAccessInputStream::readline(char* s, PRInt32 n) +// This will truncate if the buffer is too small. Result will always be null-terminated. +//---------------------------------------------------------------------------------------- +{ + PRBool bufferLargeEnough = PR_TRUE; // result + if (!s || !n) + return PR_TRUE; + + nsInt64 position = tell(); + const nsInt64 zero(0); + if (position < zero) + return PR_FALSE; + PRInt32 bytesRead = read(s, n - 1); + if (failed()) + return PR_FALSE; + s[bytesRead] = '\0'; // always terminate at the end of the buffer + char* tp = strpbrk(s, "\n\r"); + if (tp) + { + TidyEndOfLine(tp); + bytesRead = (tp - s); + } + else if (!eof() && n-1 == bytesRead) + bufferLargeEnough = PR_FALSE; + position += bytesRead; + seek(position); + return bufferLargeEnough; +} // nsRandomAccessInputStream::readline + +//======================================================================================== +// nsInputStringStream +//======================================================================================== + +//---------------------------------------------------------------------------------------- +nsInputStringStream::nsInputStringStream(const char* stringToRead) +//---------------------------------------------------------------------------------------- +{ + nsCOMPtr stream; + if (NS_FAILED(NS_NewCharInputStream(getter_AddRefs(stream), stringToRead))) + return; + mInputStream = stream; + mStore = do_QueryInterface(stream); +} + +//---------------------------------------------------------------------------------------- +nsInputStringStream::nsInputStringStream(const nsString& stringToRead) +//---------------------------------------------------------------------------------------- +{ + if (NS_FAILED(NS_NewStringInputStream(getter_AddRefs(mInputStream), stringToRead))) + return; + mStore = do_QueryInterface(mInputStream); +} + + +//======================================================================================== +// nsInputFileStream +//======================================================================================== + +//---------------------------------------------------------------------------------------- +nsInputFileStream::nsInputFileStream( + const nsFileSpec& inFile, + int nsprMode, + PRIntn accessMode) +//---------------------------------------------------------------------------------------- +{ + nsISupports* stream; + if (NS_FAILED(NS_NewIOFileStream(&stream, inFile, nsprMode, accessMode))) + return; + AssignFrom(stream); + NS_RELEASE(stream); +} // nsInputFileStream::nsInputFileStream + +//---------------------------------------------------------------------------------------- +nsInputFileStream::nsInputFileStream(nsIFileSpec* inSpec) +//---------------------------------------------------------------------------------------- +{ + nsIInputStream* stream; + if (NS_FAILED(inSpec->GetInputStream(&stream))) + return; + AssignFrom(stream); + NS_RELEASE(stream); +} // nsInputFileStream::nsInputFileStream + +//---------------------------------------------------------------------------------------- +nsInputFileStream::~nsInputFileStream() +//---------------------------------------------------------------------------------------- +{ +// if (is_open()) +// close(); +} + +//---------------------------------------------------------------------------------------- +void nsInputFileStream::AssignFrom(nsISupports* stream) +//---------------------------------------------------------------------------------------- +{ + mFile = do_QueryInterface(stream); + mInputStream = do_QueryInterface(stream); + mStore = do_QueryInterface(stream); + mFileInputStream = do_QueryInterface(stream); +} + +//======================================================================================== +// nsOutputFileStream +//======================================================================================== + +//---------------------------------------------------------------------------------------- +nsOutputFileStream::nsOutputFileStream(nsIFileSpec* inSpec) +//---------------------------------------------------------------------------------------- +{ + if (!inSpec) + return; + nsIOutputStream* stream; + if (NS_FAILED(inSpec->GetOutputStream(&stream))) + return; + AssignFrom(stream); + NS_RELEASE(stream); +} + +//---------------------------------------------------------------------------------------- +nsOutputFileStream::~nsOutputFileStream() +//---------------------------------------------------------------------------------------- +{ +// if (is_open()) +// close(); +} +//---------------------------------------------------------------------------------------- +void nsOutputFileStream::AssignFrom(nsISupports* stream) +//---------------------------------------------------------------------------------------- +{ + mFile = do_QueryInterface(stream); + mOutputStream = do_QueryInterface(stream); + mStore = do_QueryInterface(stream); + mFileOutputStream = do_QueryInterface(stream); +} + +//---------------------------------------------------------------------------------------- +nsresult nsOutputFileStream::flush() +//---------------------------------------------------------------------------------------- +{ + if (mFileOutputStream) + mFileOutputStream->Flush(); + return error(); +} + +//---------------------------------------------------------------------------------------- +void nsOutputFileStream::abort() +//---------------------------------------------------------------------------------------- +{ + mResult = NS_FILE_FAILURE; + close(); +} + +//======================================================================================== +// Manipulators +//======================================================================================== + +//---------------------------------------------------------------------------------------- +nsOutputStream& nsEndl(nsOutputStream& os) +//---------------------------------------------------------------------------------------- +{ +#if defined(XP_WIN) || defined(XP_OS2) + os.write("\r\n", 2); +#elif defined (XP_MAC) + os.put('\r'); +#else + os.put('\n'); +#endif + //os.flush(); + return os; +} // nsEndl diff --git a/src/libs/xpcom18a4/xpcom/obsolete/nsFileStream.h b/src/libs/xpcom18a4/xpcom/obsolete/nsFileStream.h new file mode 100644 index 00000000..b0cd5e8a --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/obsolete/nsFileStream.h @@ -0,0 +1,772 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +// First checked in on 98/11/20 by John R. McMullen in the wrong directory. +// Checked in again 98/12/04. +// Polished version 98/12/08. +// Completely rewritten to integrate with nsIInputStream and nsIOutputStream (the +// xpcom stream objects. + +//======================================================================================== +// +// Classes defined: +// +// nsInputStream, nsOutputStream +// These are the lightweight STATICALLY LINKED wrappers for +// the xpcom objects nsIInputStream and nsIOutputstream. +// Possible uses: +// If you are implementing a function that accepts one of these xpcom +// streams, just make one of these little jobbies on the stack, and +// the handy << or >> notation can be yours. +// +// nsInputFileStream, nsOutputFileStream +// These are the STATICALLY LINKED wrappers for the file-related +// versions of the above. +// nsIOFileStream +// An input and output file stream attached to the same file. +// +// This suite provide the following services: +// +// 1. Encapsulates all platform-specific file details, so that file i/o +// can be done correctly without any platform #ifdefs +// +// 2. Uses NSPR file services (NOT ansi file I/O), in order to get best +// native performance. This performance difference is especially large on +// macintosh. +// +// 3. Allows all the power of the ansi stream syntax. +// +// Basic example: +// +// nsFileSpec myPath("/Development/iotest.txt"); +// +// nsOutputFileStream testStream(myPath); +// testStream << "Hello World" << nsEndl; +// +// 4. Requires streams to be constructed using typesafe nsFileSpec specifier +// (not the notorious and bug prone const char*), namely nsFileSpec. See +// nsFileSpec.h for more details. +// +// 5. Fixes a bug that have been there for a long time, and +// is inevitable if you use NSPR alone: +// +// The problem on platforms (Macintosh) in which a path does not fully +// specify a file, because two volumes can have the same name. +// +// Not yet provided: +// +// Endian-awareness for reading and writing crossplatform binary files. At this +// time there seems to be no demand for this. +// +//======================================================================================== + +#ifndef _FILESTREAM_H_ +#define _FILESTREAM_H_ + +#include "xpcomobsolete.h" +#include "nsStringFwd.h" + +#ifdef XP_MAC +#include "pprio.h" // To get PR_ImportFile +#else +#include "prio.h" +#endif + +#include "nsCOMPtr.h" +#include "nsIFileStream.h" + +// Defined elsewhere +class nsFileSpec; +class nsIInputStream; +class nsIOutputStream; +class nsIFileSpec; + +//======================================================================================== +// Compiler-specific macros, as needed +//======================================================================================== +#if !defined(NS_USING_NAMESPACE) && (defined(__MWERKS__) || defined(_MSC_VER)) +#define NS_USING_NAMESPACE +#endif + +#ifdef NS_USING_NAMESPACE + +#define NS_NAMESPACE_PROTOTYPE +#define NS_NAMESPACE namespace +#define NS_NAMESPACE_END + +#else + +#define NS_NAMESPACE_PROTOTYPE static +#define NS_NAMESPACE struct +#define NS_NAMESPACE_END ; + +#endif // NS_USING_NAMESPACE + +#if !defined(XP_MAC) && !defined(__KCC) +// PR_STDOUT and PR_STDIN are fatal on Macintosh. So for console i/o, we must use the std +// stream stuff instead. However, we have to require that cout and cin are passed in +// to the constructor because in the current build, there is a copy in the base.shlb, +// and another in the caller's file. Passing it in as a parameter ensures that the +// caller and this library are using the same global object. Groan. +// +// Unix currently does not support iostreams at all. Their compilers do not support +// ANSI C++, or even ARM C++. +// +// Windows supports them, but only if you turn on the -GX compile flag, to support +// exceptions. + +// Catch 22. +#define NS_USE_PR_STDIO +#endif + +#ifdef NS_USE_PR_STDIO +class istream; +class ostream; +#define CONSOLE_IN 0 +#define CONSOLE_OUT 0 +#else +#include +using std::istream; +using std::ostream; +#define CONSOLE_IN &std::cin +#define CONSOLE_OUT &std::cout +#endif + +//=========================== End Compiler-specific macros =============================== + +//======================================================================================== +class NS_COM_OBSOLETE nsInputStream +// This is a convenience class, for use on the STACK ("new" junkies: get detoxed first). +// Given a COM-style stream, this allows you to use the >> operators. It also acquires and +// reference counts its stream. +// Please read the comments at the top of this file +//======================================================================================== +{ +public: + nsInputStream(nsIInputStream* inStream) + : mInputStream(do_QueryInterface(inStream)) + , mEOF(PR_FALSE) + {} + virtual ~nsInputStream(); + + nsCOMPtr GetIStream() const + { + return mInputStream; + } + PRBool eof() const { return get_at_eof(); } + char get(); + nsresult close() + { + NS_ASSERTION(mInputStream, "mInputStream is null!"); + if (mInputStream) { + return mInputStream->Close(); + } + return NS_OK; + } + PRInt32 read(void* s, PRInt32 n); + + // Input streamers. Add more as needed (int&, unsigned int& etc). (but you have to + // add delegators to the derived classes, too, because these operators don't inherit). + nsInputStream& operator >> (char& ch); + + // Support manipulators + nsInputStream& operator >> (nsInputStream& (*pf)(nsInputStream&)) + { + return pf(*this); + } + +protected: + + // These certainly need to be overridden, they give the best shot we can at detecting + // eof in a simple nsIInputStream. + virtual void set_at_eof(PRBool atEnd) + { + mEOF = atEnd; + } + virtual PRBool get_at_eof() const + { + return mEOF; + } +private: + + nsInputStream& operator >> (char* buf); // TOO DANGEROUS. DON'T DEFINE. + + // private and unimplemented to disallow copies and assigns + nsInputStream(const nsInputStream& rhs); + nsInputStream& operator=(const nsInputStream& rhs); + +// DATA +protected: + nsCOMPtr mInputStream; + PRBool mEOF; +}; // class nsInputStream + +typedef nsInputStream nsBasicInStream; // historic support for this name + +//======================================================================================== +class NS_COM_OBSOLETE nsOutputStream +// This is a convenience class, for use on the STACK ("new" junkies, get detoxed first). +// Given a COM-style stream, this allows you to use the << operators. It also acquires and +// reference counts its stream. +// Please read the comments at the top of this file +//======================================================================================== +{ +public: + nsOutputStream() {} + nsOutputStream(nsIOutputStream* inStream) + : mOutputStream(do_QueryInterface(inStream)) + {} + + virtual ~nsOutputStream(); + + nsCOMPtr GetIStream() const + { + return mOutputStream; + } + nsresult close() + { + if (mOutputStream) + return mOutputStream->Close(); + return NS_OK; + } + void put(char c); + PRInt32 write(const void* s, PRInt32 n); + virtual nsresult flush(); + nsresult lastWriteStatus(); + + // Output streamers. Add more as needed (but you have to add delegators to the derived + // classes, too, because these operators don't inherit). + nsOutputStream& operator << (const char* buf); + nsOutputStream& operator << (char ch); + nsOutputStream& operator << (short val); + nsOutputStream& operator << (unsigned short val); + nsOutputStream& operator << (long val); + nsOutputStream& operator << (unsigned long val); + nsOutputStream& operator << (int val); + nsOutputStream& operator << (unsigned int val); + + // Support manipulators + nsOutputStream& operator << (nsOutputStream& (*pf)(nsOutputStream&)) + { + return pf(*this); + } + +private: + + // private and unimplemented to disallow copies and assigns + nsOutputStream(const nsOutputStream& rhs); + nsOutputStream& operator=(const nsOutputStream& rhs); + + nsresult mWriteStatus; + +// DATA +protected: + nsCOMPtr mOutputStream; +}; // class nsOutputStream + +typedef nsOutputStream nsBasicOutStream; // Historic support for this name + +//======================================================================================== +class NS_COM_OBSOLETE nsErrorProne +// Common (virtual) base class for remembering errors on demand +//======================================================================================== +{ +public: + nsErrorProne() // for delayed opening + : mResult(NS_OK) + { + } + PRBool failed() const + { + return NS_FAILED(mResult); + } + nsresult error() const + { + return mResult; + } + +// DATA +protected: + nsresult mResult; +}; // class nsErrorProne + +//======================================================================================== +class NS_COM_OBSOLETE nsFileClient +// Because COM does not allow us to write functions which return a boolean value etc, +// this class is here to take care of the tedious "declare variable then call with +// the address of the variable" chores. +//======================================================================================== +: public virtual nsErrorProne +{ +public: + nsFileClient(const nsCOMPtr& inFile) + : mFile(do_QueryInterface(inFile)) + { + } + virtual ~nsFileClient() {} + + void open( + const nsFileSpec& inFile, + int nsprMode, + PRIntn accessMode) + { + if (mFile) + mResult = mFile->Open(inFile, nsprMode, accessMode); + } + PRBool is_open() const + { + PRBool result = PR_FALSE; + if (mFile) + mFile->GetIsOpen(&result); + return result; + } + PRBool is_file() const + { + return mFile ? PR_TRUE : PR_FALSE; + } + +protected: + + nsFileClient() // for delayed opening + { + } +// DATA +protected: + nsCOMPtr mFile; +}; // class nsFileClient + +//======================================================================================== +class NS_COM_OBSOLETE nsRandomAccessStoreClient +// Because COM does not allow us to write functions which return a boolean value etc, +// this class is here to take care of the tedious "declare variable then call with +// the address of the variable" chores. +//======================================================================================== +: public virtual nsErrorProne +{ +public: + nsRandomAccessStoreClient() // for delayed opening + { + } + nsRandomAccessStoreClient(const nsCOMPtr& inStore) + : mStore(do_QueryInterface(inStore)) + { + } + virtual ~nsRandomAccessStoreClient() {} + + void seek(PRInt64 offset) + { + seek(PR_SEEK_SET, offset); + } + + void seek(PRSeekWhence whence, PRInt64 offset) + { + set_at_eof(PR_FALSE); + if (mStore) + mResult = mStore->Seek(whence, offset); + } + PRInt64 tell() + { + PRInt64 result; + LL_I2L(result, -1); + if (mStore) + mResult = mStore->Tell(&result); + return result; + } + +protected: + + virtual PRBool get_at_eof() const + { + PRBool result = PR_TRUE; + if (mStore) + mStore->GetAtEOF(&result); + return result; + } + + virtual void set_at_eof(PRBool atEnd) + { + if (mStore) + mStore->SetAtEOF(atEnd); + } + +private: + + // private and unimplemented to disallow copies and assigns + nsRandomAccessStoreClient(const nsRandomAccessStoreClient& rhs); + nsRandomAccessStoreClient& operator=(const nsRandomAccessStoreClient& rhs); + +// DATA +protected: + nsCOMPtr mStore; +}; // class nsRandomAccessStoreClient + +//======================================================================================== +class NS_COM_OBSOLETE nsRandomAccessInputStream +// Please read the comments at the top of this file +//======================================================================================== +: public nsRandomAccessStoreClient +, public nsInputStream +{ +public: + nsRandomAccessInputStream(nsIInputStream* inStream) + : nsRandomAccessStoreClient(do_QueryInterface(inStream)) + , nsInputStream(inStream) + { + } + PRBool readline(char* s, PRInt32 n); + // Result always null-terminated. + // Check eof() before each call. + // CAUTION: false result only indicates line was truncated + // to fit buffer, or an error occurred (OTHER THAN eof). + + // Input streamers. Unfortunately, they don't inherit! + nsInputStream& operator >> (char& ch) + { return nsInputStream::operator >>(ch); } + nsInputStream& operator >> (nsInputStream& (*pf)(nsInputStream&)) + { return nsInputStream::operator >>(pf); } + +protected: + nsRandomAccessInputStream() + : nsInputStream(nsnull) + { + } + + virtual PRBool get_at_eof() const + { + return nsRandomAccessStoreClient::get_at_eof(); + } + + virtual void set_at_eof(PRBool atEnd) + { + nsRandomAccessStoreClient::set_at_eof(atEnd); + } + +private: + + // private and unimplemented to disallow copies and assigns + nsRandomAccessInputStream(const nsRandomAccessInputStream& rhs); + nsRandomAccessInputStream& operator=(const nsRandomAccessInputStream& rhs); + +}; // class nsRandomAccessInputStream + +//======================================================================================== +class NS_COM_OBSOLETE nsInputStringStream +//======================================================================================== +: public nsRandomAccessInputStream +{ +public: + nsInputStringStream(const char* stringToRead); + nsInputStringStream(const nsString& stringToRead); + + // Input streamers. Unfortunately, they don't inherit! + nsInputStream& operator >> (char& ch) + { return nsInputStream::operator >>(ch); } + nsInputStream& operator >> (nsInputStream& (*pf)(nsInputStream&)) + { return nsInputStream::operator >>(pf); } + + +private: + + // private and unimplemented to disallow copies and assigns + nsInputStringStream(const nsInputStringStream& rhs); + nsInputStringStream& operator=(const nsInputStringStream& rhs); + + +}; // class nsInputStringStream + +//======================================================================================== +class NS_COM_OBSOLETE nsInputFileStream +// Please read the comments at the top of this file +//======================================================================================== +: public nsRandomAccessInputStream +, public nsFileClient +{ +public: + enum { kDefaultMode = PR_RDONLY }; + nsInputFileStream(nsIInputStream* inStream) + : nsRandomAccessInputStream(inStream) + , nsFileClient(do_QueryInterface(inStream)) + , mFileInputStream(do_QueryInterface(inStream)) + { + } + nsInputFileStream( + const nsFileSpec& inFile, + int nsprMode = kDefaultMode, + PRIntn accessMode = 00666); + nsInputFileStream(nsIFileSpec* inFile); + virtual ~nsInputFileStream(); + + void Open( + const nsFileSpec& inFile, + int nsprMode = kDefaultMode, + PRIntn accessMode = 00666) + { + if (mFile) + mFile->Open(inFile, nsprMode, accessMode); + } + + // Input streamers. Unfortunately, they don't inherit! + nsInputStream& operator >> (char& ch) + { return nsInputStream::operator >>(ch); } + nsInputStream& operator >> (nsInputStream& (*pf)(nsInputStream&)) + { return nsInputStream::operator >>(pf); } + +protected: + void AssignFrom(nsISupports* stream); + +private: + + // private and unimplemented to disallow copies and assigns + nsInputFileStream(const nsInputFileStream& rhs); + nsInputFileStream& operator=(const nsInputFileStream& rhs); + +// DATA +protected: + nsCOMPtr mFileInputStream; +}; // class nsInputFileStream + +//======================================================================================== +class NS_COM_OBSOLETE nsRandomAccessOutputStream +// Please read the comments at the top of this file +//======================================================================================== +: public nsRandomAccessStoreClient +, public nsOutputStream +{ +public: + nsRandomAccessOutputStream(nsIOutputStream* inStream) + : nsRandomAccessStoreClient(do_QueryInterface(inStream)) + , nsOutputStream(inStream) + { + } + + // Output streamers. Unfortunately, they don't inherit! + nsOutputStream& operator << (const char* buf) + { return nsOutputStream::operator << (buf); } + nsOutputStream& operator << (char ch) + { return nsOutputStream::operator << (ch); } + nsOutputStream& operator << (short val) + { return nsOutputStream::operator << (val); } + nsOutputStream& operator << (unsigned short val) + { return nsOutputStream::operator << (val); } + nsOutputStream& operator << (long val) + { return nsOutputStream::operator << (val); } + nsOutputStream& operator << (unsigned long val) + { return nsOutputStream::operator << (val); } + nsOutputStream& operator << (int val) + { return nsOutputStream::operator << (val); } + nsOutputStream& operator << (unsigned int val) + { return nsOutputStream::operator << (val); } + nsOutputStream& operator << (nsOutputStream& (*pf)(nsOutputStream&)) + { return nsOutputStream::operator << (pf); } + +protected: + nsRandomAccessOutputStream() + : nsOutputStream(nsnull) + { + } + +private: + + // private and unimplemented to disallow copies and assigns + nsRandomAccessOutputStream(const nsRandomAccessOutputStream& rhs); + nsRandomAccessOutputStream& operator=(const nsRandomAccessOutputStream& rhs); + +}; // class nsRandomAccessOutputStream + +//======================================================================================== +class NS_COM_OBSOLETE nsOutputFileStream +// Please read the comments at the top of this file +//======================================================================================== +: public nsRandomAccessOutputStream +, public nsFileClient +{ +public: + enum { kDefaultMode = (PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE) }; + + nsOutputFileStream() {} + nsOutputFileStream(nsIOutputStream* inStream) + { + AssignFrom(inStream); + } + nsOutputFileStream( + const nsFileSpec& inFile, + int nsprMode = kDefaultMode, + PRIntn accessMode = 00666) + { + nsISupports* stream; + if (NS_FAILED(NS_NewIOFileStream( + &stream, + inFile, nsprMode, accessMode))) + return; + AssignFrom(stream); + NS_RELEASE(stream); + } + nsOutputFileStream(nsIFileSpec* inFile); + virtual ~nsOutputFileStream(); + + virtual nsresult flush(); + virtual void abort(); + + // Output streamers. Unfortunately, they don't inherit! + nsOutputStream& operator << (const char* buf) + { return nsOutputStream::operator << (buf); } + nsOutputStream& operator << (char ch) + { return nsOutputStream::operator << (ch); } + nsOutputStream& operator << (short val) + { return nsOutputStream::operator << (val); } + nsOutputStream& operator << (unsigned short val) + { return nsOutputStream::operator << (val); } + nsOutputStream& operator << (long val) + { return nsOutputStream::operator << (val); } + nsOutputStream& operator << (unsigned long val) + { return nsOutputStream::operator << (val); } + nsOutputStream& operator << (int val) + { return nsOutputStream::operator << (val); } + nsOutputStream& operator << (unsigned int val) + { return nsOutputStream::operator << (val); } + nsOutputStream& operator << (nsOutputStream& (*pf)(nsOutputStream&)) + { return nsOutputStream::operator << (pf); } + +protected: + void AssignFrom(nsISupports* stream); + +private: + + // private and unimplemented to disallow copies and assigns + nsOutputFileStream(const nsOutputFileStream& rhs); + nsOutputFileStream& operator=(const nsOutputFileStream& rhs); + +// DATA +protected: + nsCOMPtr mFileOutputStream; +}; // class nsOutputFileStream + + +//======================================================================================== +class nsIOFileStream +// Please read the comments at the top of this file +//======================================================================================== +: public nsInputFileStream +, public nsOutputStream +{ +public: + enum { kDefaultMode = (PR_RDWR | PR_CREATE_FILE) }; + + nsIOFileStream( + nsIInputStream* inInputStream + , nsIOutputStream* inOutputStream) + : nsInputFileStream(inInputStream) + , nsOutputStream(inOutputStream) + , mFileOutputStream(do_QueryInterface(inOutputStream)) + { + } + nsIOFileStream( + const nsFileSpec& inFile, + int nsprMode = kDefaultMode, + PRIntn accessMode = 00666) + : nsInputFileStream((nsIInputStream*)nsnull) + , nsOutputStream(nsnull) + { + nsISupports* stream; + if (NS_FAILED(NS_NewIOFileStream( + &stream, + inFile, nsprMode, accessMode))) + return; + mFile = do_QueryInterface(stream); + mStore = do_QueryInterface(stream); + mInputStream = do_QueryInterface(stream); + mOutputStream = do_QueryInterface(stream); + mFileInputStream = do_QueryInterface(stream); + mFileOutputStream = do_QueryInterface(stream); + NS_RELEASE(stream); + } + + virtual nsresult close() + { + // Doesn't matter which of the two we close: + // they're hooked up to the same file. + return nsInputFileStream::close(); + } + + // Output streamers. Unfortunately, they don't inherit! + nsOutputStream& operator << (const char* buf) + { return nsOutputStream::operator << (buf); } + nsOutputStream& operator << (char ch) + { return nsOutputStream::operator << (ch); } + nsOutputStream& operator << (short val) + { return nsOutputStream::operator << (val); } + nsOutputStream& operator << (unsigned short val) + { return nsOutputStream::operator << (val); } + nsOutputStream& operator << (long val) + { return nsOutputStream::operator << (val); } + nsOutputStream& operator << (unsigned long val) + { return nsOutputStream::operator << (val); } + nsOutputStream& operator << (int val) + { return nsOutputStream::operator << (val); } + nsOutputStream& operator << (unsigned int val) + { return nsOutputStream::operator << (val); } + nsOutputStream& operator << (nsOutputStream& (*pf)(nsOutputStream&)) + { return nsOutputStream::operator << (pf); } + + // Input streamers. Unfortunately, they don't inherit! + nsInputStream& operator >> (char& ch) + { return nsInputStream::operator >>(ch); } + nsInputStream& operator >> (nsInputStream& (*pf)(nsInputStream&)) + { return nsInputStream::operator >>(pf); } + + virtual nsresult flush() {if (mFileOutputStream) mFileOutputStream->Flush(); return error(); } + + +private: + + // private and unimplemented to disallow copies and assigns + nsIOFileStream(const nsIOFileStream& rhs); + nsIOFileStream& operator=(const nsIOFileStream& rhs); + + // DATA +protected: + nsCOMPtr mFileOutputStream; +}; // class nsIOFileStream + +//======================================================================================== +// Manipulators +//======================================================================================== + +NS_COM_OBSOLETE nsOutputStream& nsEndl(nsOutputStream& os); // outputs and FLUSHES. + +//======================================================================================== +#endif /* _FILESTREAM_H_ */ diff --git a/src/libs/xpcom18a4/xpcom/obsolete/nsIFileSpec.idl b/src/libs/xpcom18a4/xpcom/obsolete/nsIFileSpec.idl new file mode 100644 index 00000000..78abd9e7 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/obsolete/nsIFileSpec.idl @@ -0,0 +1,204 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + THIS INTERFACE IS DEPRECATED AND UNSUPPORTED! USE |nsIFile| and |nsILocalFile|. + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + + +// This is the only correct cross-platform way to specify a file. +// Strings are not such a way. If you grew up on windows or unix, you +// may think they are. Welcome to reality. + +#include "nsISupports.idl" + +%{C++ +#include "nsFileSpec.h" // for factory method +%} + +interface nsIFileURL; +interface nsIFilePath; +interface nsIOutputStream; +interface nsIInputStream; + +// Define Contractid and CID +%{C++ + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + THIS INTERFACE IS DEPRECATED AND UNSUPPORTED! USE |nsIFile| and |nsILocalFile|. + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +// {A5740FA2-146E-11d3-B00D-00C04FC2E79B} +#define NS_FILESPEC_CID \ +{ 0xa5740fa2, 0x146e, 0x11d3, { 0xb0, 0xd, 0x0, 0xc0, 0x4f, 0xc2, 0xe7, 0x9b } } + +#define NS_FILESPEC_CONTRACTID "@mozilla.org/filespec;1" +#define NS_FILESPEC_CLASSNAME "File Spec" + +%} + + native nsFileSpec(nsFileSpec); +[ref] native nsFileSpecRef(nsFileSpec); +[ptr] native nsFileSpecPtr(nsFileSpec); + +[scriptable, uuid(d8c0a080-0868-11d3-915f-d9d889d48e3c)] +interface nsIFileSpec : nsISupports +{ + void fromFileSpec([const] in nsIFileSpec original); + + attribute string URLString; + attribute string unixStyleFilePath; + attribute string persistentDescriptorString; + attribute string nativePath; + + readonly attribute string NSPRPath; + + void error(); + + boolean isValid(); + boolean failed(); + + attribute string leafName; + + readonly attribute nsIFileSpec parent; + readonly attribute nsIInputStream inputStream; + readonly attribute nsIOutputStream outputStream; + boolean isChildOf(in nsIFileSpec possibleParent); + [noscript] readonly attribute nsFileSpec fileSpec; + [noscript] void setFromFileSpec([const] in nsFileSpecRef spec); + + attribute string fileContents; + + void makeUnique(); + void makeUniqueWithSuggestedName(in string suggestedName); + + readonly attribute unsigned long modDate; + boolean modDateChanged(in unsigned long oldStamp); + + boolean isDirectory(); + boolean isFile(); + boolean exists(); + boolean isHidden(); + + boolean equals(in nsIFileSpec spec); + + readonly attribute unsigned long fileSize; + readonly attribute long long diskSpaceAvailable; + + void appendRelativeUnixPath(in string relativePath); + + void createDir(); + void touch(); + + boolean isSymlink(); + void resolveSymlink(); + + void delete(in boolean recursive); + void truncate(in long aNewLength); + void rename([const] in string newLeafName); + void copyToDir([const] in nsIFileSpec newParentDir); + void moveToDir([const] in nsIFileSpec newParentDir); + void execute([const] in string args); + + void openStreamForReading(); + void openStreamForWriting(); + void openStreamForReadingAndWriting(); + void closeStream(); + boolean isStreamOpen(); + + boolean eof(); + long read(inout string buffer, in long requestedCount); + void readLine(inout string line, in long bufferSize, out boolean wasTruncated); + + /** Check eof() before each call. + * CAUTION: false result only indicates line was truncated + * to fit buffer, or an error occurred (OTHER THAN eof). + */ + long write(in string data, in long requestedCount); + void flush(); + + void seek(in long offset); + long tell(); + void endLine(); + attribute AString unicodePath; + +}; + +// Define Contractid and CID +%{C++ +// {a3020981-2018-11d3-915f-a957795b7ebc} +#define NS_DIRECTORYITERATOR_CID \ +{ 0xa3020981, 0x2018, 0x11d3, { 0x91, 0x5f, 0xa9, 0x57, 0x79, 0x5b, 0x7e, 0xbc } } + +#define NS_DIRECTORYITERATOR_CONTRACTID "@mozilla.org/directoryiterator;1" +#define NS_DIRECTORYITERATOR_CLASSNAME "nsIDirectoryIterator" +%} + +[scriptable, uuid(d8c0a083-0868-11d3-915f-d9d889d48e3c)] +interface nsIDirectoryIterator : nsISupports +{ + void init(in nsIFileSpec parent, in boolean resolveSymlink); + boolean exists(); + void next(); + readonly attribute nsIFileSpec currentSpec; +}; + +%{C++ +// Factory methods if you link with xpcom +NS_COM_OBSOLETE nsresult NS_NewFileSpecWithSpec(const nsFileSpec& aSrcFileSpec, nsIFileSpec **result); +NS_COM_OBSOLETE nsresult NS_NewFileSpec(nsIFileSpec** result); +NS_COM_OBSOLETE nsresult NS_NewDirectoryIterator(nsIDirectoryIterator** result); + +// Convert from nsIFile to nsIFileSpec +// +// XXX This function is here only to assist with the migration from nsIFileSpec +// to nsIFile. This function will dissappear in future mozilla releases. +// +// ...ripped from nsPrefService.cpp: +// +// "So discouraged is the use of nsIFileSpec, nobody wanted to have this routine be +// public - It might lead to continued use of nsIFileSpec. Right now, [mozilla] has +// such a need for it, here it is. Let's stop having to use it though." +// +NS_COM_OBSOLETE nsresult NS_NewFileSpecFromIFile(nsIFile *aFile, nsIFileSpec **result); + +#define NS_BOOL_ACCESSOR(_method) { PRBool yes; return NS_SUCCEEDED(f->_method(&yes)) && yes; } +inline PRBool Exists(nsIFileSpec* f) NS_BOOL_ACCESSOR(Exists) +inline PRBool Exists(nsIDirectoryIterator* f) NS_BOOL_ACCESSOR(Exists) +inline PRBool IsDirectory(nsIFileSpec* f) NS_BOOL_ACCESSOR(IsDirectory) + +%} diff --git a/src/libs/xpcom18a4/xpcom/obsolete/nsIFileStream.cpp b/src/libs/xpcom18a4/xpcom/obsolete/nsIFileStream.cpp new file mode 100644 index 00000000..011bcdaa --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/obsolete/nsIFileStream.cpp @@ -0,0 +1,727 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Pierre Phaneuf + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsIFileStream.h" +#include "nsFileSpec.h" +#include "nsCOMPtr.h" + +#include "prerror.h" + +#include "nsSegmentedBuffer.h" +#include "nsInt64.h" + +#ifdef XP_MAC +#include "pprio.h" // To get PR_ImportFile +#else +#include "prio.h" +#endif + +#ifdef XP_MAC +#include +#include +#endif + +//======================================================================================== +class FileImpl + : public nsIRandomAccessStore + , public nsIFileSpecOutputStream + , public nsIFileSpecInputStream + , public nsIOpenFile +//======================================================================================== +{ + public: + FileImpl(PRFileDesc* inDesc); + FileImpl(const nsFileSpec& inFile, int nsprMode, PRIntn accessMode); + + // nsISupports interface + NS_DECL_ISUPPORTS + + // nsIOpenFile interface + NS_IMETHOD Open(const nsFileSpec& inFile, int nsprMode, PRIntn accessMode); + NS_IMETHOD Close(); + NS_IMETHOD GetIsOpen(PRBool* outOpen); + + // nsIInputStream interface + NS_IMETHOD Available(PRUint32 *aLength); + NS_IMETHOD Read(char* aBuf, PRUint32 aCount, PRUint32 *aReadCount); + NS_IMETHOD ReadSegments(nsWriteSegmentFun writer, void * closure, PRUint32 count, PRUint32 *_retval); + NS_IMETHOD IsNonBlocking(PRBool *aNonBlocking); + + // nsIOutputStream interface + NS_IMETHOD Write(const char* aBuf, PRUint32 aCount, PRUint32 *aWriteCount); + NS_IMETHOD Flush(); + NS_IMETHOD WriteFrom(nsIInputStream *inStr, PRUint32 count, PRUint32 *_retval); + NS_IMETHOD WriteSegments(nsReadSegmentFun reader, void * closure, PRUint32 count, PRUint32 *_retval); + + // nsIRandomAccessStore interface + NS_DECL_NSISEEKABLESTREAM + NS_IMETHOD GetAtEOF(PRBool* outAtEOF); + NS_IMETHOD SetAtEOF(PRBool inAtEOF); + + private: + + ~FileImpl(); + + protected: + + enum { + kOuputBufferSegmentSize = 4096, + kOuputBufferMaxSize = 4096 + }; + + nsresult InternalFlush(PRBool syncFile); + nsresult AllocateBuffers(PRUint32 segmentSize, PRUint32 maxSize); + + PRFileDesc* mFileDesc; + int mNSPRMode; + PRBool mFailed; + PRBool mEOF; + PRInt32 mLength; + + PRBool mGotBuffers; + nsSegmentedBuffer mOutBuffer; + char* mWriteCursor; + char* mWriteLimit; + +}; // class FileImpl + +NS_IMPL_RELEASE(FileImpl) +NS_IMPL_ADDREF(FileImpl) + +NS_IMPL_QUERY_HEAD(FileImpl) + NS_IMPL_QUERY_BODY(nsIOpenFile) + NS_IMPL_QUERY_BODY(nsISeekableStream) + NS_IMPL_QUERY_BODY(nsIRandomAccessStore) + NS_IMPL_QUERY_BODY(nsIOutputStream) + NS_IMPL_QUERY_BODY(nsIInputStream) + NS_IMPL_QUERY_BODY(nsIFileSpecInputStream) + NS_IMPL_QUERY_BODY(nsIFileSpecOutputStream) +NS_IMPL_QUERY_TAIL(nsIOutputStream) + + +//---------------------------------------------------------------------------------------- +FileImpl::FileImpl(PRFileDesc* inDesc) +//---------------------------------------------------------------------------------------- +: mFileDesc(inDesc) +, mNSPRMode(0) +, mFailed(PR_FALSE) +, mEOF(PR_FALSE) +, mLength(-1) +, mGotBuffers(PR_FALSE) +{ + mWriteCursor = nsnull; + mWriteLimit = nsnull; +} + + +//---------------------------------------------------------------------------------------- +FileImpl::FileImpl(const nsFileSpec& inFile, int nsprMode, PRIntn accessMode) +//---------------------------------------------------------------------------------------- +: mFileDesc(nsnull) +, mNSPRMode(-1) +, mEOF(PR_FALSE) +, mLength(-1) +, mGotBuffers(PR_FALSE) +{ + mWriteCursor = nsnull; + mWriteLimit = nsnull; + + nsresult rv = Open(inFile, nsprMode, accessMode); // this sets nsprMode + + if (NS_FAILED(rv)) + { + mFailed = PR_TRUE; +#if DEBUG + char *fileName = inFile.GetLeafName(); + printf("Opening file %s failed\n", fileName); + nsCRT::free(fileName); +#endif + } + else + { + mFailed = PR_FALSE; + } +} + +//---------------------------------------------------------------------------------------- +FileImpl::~FileImpl() +//---------------------------------------------------------------------------------------- +{ + nsresult rv = Close(); + NS_ASSERTION(NS_SUCCEEDED(rv), "Close failed"); +} + + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP FileImpl::Open( + const nsFileSpec& inFile, + int nsprMode, + PRIntn accessMode) +//---------------------------------------------------------------------------------------- +{ + if (mFileDesc) + if ((nsprMode & mNSPRMode) == nsprMode) + return NS_OK; + else + return NS_FILE_RESULT(PR_ILLEGAL_ACCESS_ERROR); + + const int nspr_modes[]={ + PR_WRONLY | PR_CREATE_FILE, + PR_WRONLY | PR_CREATE_FILE | PR_APPEND, + PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE, + PR_RDONLY, + PR_RDONLY | PR_APPEND, + PR_RDWR | PR_CREATE_FILE, + PR_RDWR | PR_CREATE_FILE | PR_TRUNCATE, +// "wb", +// "ab", +// "wb", +// "rb", +// "r+b", +// "w+b", + 0 }; + const int* currentLegalMode = nspr_modes; + while (*currentLegalMode && nsprMode != *currentLegalMode) + ++currentLegalMode; + if (!*currentLegalMode) + return NS_FILE_RESULT(PR_ILLEGAL_ACCESS_ERROR); + +#ifdef XP_MAC + // Use the file spec to open the file, because one path can be common to + // several files on the Macintosh (you can have several volumes with the + // same name, see). + mFileDesc = 0; + OSErr err = inFile.Error(); + if (err != noErr) + if (err != fnfErr || !(nsprMode & PR_CREATE_FILE)) + return NS_FILE_RESULT(inFile.Error()); + err = noErr; +#if DEBUG + const OSType kCreator = 'CWIE'; +#else + const OSType kCreator = 'MOSS'; +#endif + // Resolve the alias to the original file. + nsFileSpec original = inFile; + PRBool ignoredResult; + original.ResolveSymlink(ignoredResult); + const FSSpec& spec = original.operator const FSSpec&(); + if (nsprMode & PR_CREATE_FILE) { + // In order to get the right file type/creator, do it with an nsILocalFileMac + // Don't propagate any errors in doing this. If any error, just use FSpCreate. + FSSpec nonConstSpec = spec; + nsCOMPtr macFile; + nsresult res = NS_NewLocalFileWithFSSpec(&nonConstSpec, PR_FALSE, getter_AddRefs(macFile)); + if (NS_SUCCEEDED(res)) { + nsCOMPtr asFile(do_QueryInterface(macFile, &res)); + if (NS_SUCCEEDED(res)) { + res = asFile->Create(nsIFile::NORMAL_FILE_TYPE, 0); + if (res == NS_ERROR_FILE_ALREADY_EXISTS) + res = NS_OK; + } + } + if (NS_FAILED(res)) + err = FSpCreate(&spec, kCreator, 'TEXT', 0); + } + + if (err == dupFNErr) + err = noErr; + if (err != noErr) + return NS_FILE_RESULT(err); + + SInt8 perm; + if (nsprMode & PR_RDWR) + perm = fsRdWrPerm; + else if (nsprMode & PR_WRONLY) + perm = fsWrPerm; + else + perm = fsRdPerm; + + short refnum; + err = FSpOpenDF(&spec, perm, &refnum); + + if (err == noErr && (nsprMode & PR_TRUNCATE)) + err = ::SetEOF(refnum, 0); + if (err == noErr && (nsprMode & PR_APPEND)) + err = SetFPos(refnum, fsFromLEOF, 0); + if (err != noErr) + return NS_FILE_RESULT(err); + + if ((mFileDesc = PR_ImportFile(refnum)) == 0) + return NS_FILE_RESULT(PR_GetError()); +#else + // Platforms other than Macintosh... + // Another bug in NSPR: Mac PR_Open assumes a unix style path, but Win PR_Open assumes + // a windows path. + if ((mFileDesc = PR_Open((const char*)nsFileSpec(inFile), nsprMode, accessMode)) == 0) + return NS_FILE_RESULT(PR_GetError()); +#endif + mNSPRMode = nsprMode; + mLength = PR_Available(mFileDesc); + return NS_OK; +} // FileImpl::Open + + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP FileImpl::Available(PRUint32 *aLength) +//---------------------------------------------------------------------------------------- +{ + NS_PRECONDITION(aLength != nsnull, "null ptr"); + if (!aLength) + return NS_ERROR_NULL_POINTER; + if (mLength < 0) + return NS_ERROR_UNEXPECTED; + *aLength = mLength; + return NS_OK; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP FileImpl::GetIsOpen(PRBool* outOpen) +//---------------------------------------------------------------------------------------- +{ + *outOpen = (mFileDesc != nsnull && !mFailed); + return NS_OK; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP FileImpl::Seek(PRInt32 whence, PRInt64 offset) +//---------------------------------------------------------------------------------------- +{ + if (mFileDesc==PR_STDIN || mFileDesc==PR_STDOUT || mFileDesc==PR_STDERR || !mFileDesc) + return NS_FILE_RESULT(PR_BAD_DESCRIPTOR_ERROR); + mFailed = PR_FALSE; // reset on a seek. + mEOF = PR_FALSE; // reset on a seek. + + // To avoid corruption, we flush during a seek. see bug number 18949 + InternalFlush(PR_FALSE); + + nsInt64 position = PR_Seek64(mFileDesc, 0, PR_SEEK_CUR); + nsInt64 available = PR_Available64(mFileDesc); + nsInt64 fileSize = position + available; + nsInt64 newPosition = offset; + switch (whence) + { + case NS_SEEK_CUR: newPosition += position; break; + case NS_SEEK_SET: ; break; + case NS_SEEK_END: newPosition += fileSize; break; + } + const nsInt64 zero = 0; + if (newPosition < zero) + { + newPosition = 0; + mFailed = PR_TRUE; + } + if (newPosition >= fileSize) // nb: not "else if". + { + newPosition = fileSize; + mEOF = PR_TRUE; + } + if (PR_Seek64(mFileDesc, newPosition, PR_SEEK_SET) < 0) + mFailed = PR_TRUE; + return NS_OK; +} // FileImpl::Seek + + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP FileImpl::Read(char* aBuf, PRUint32 aCount, PRUint32 *aReadCount) +//---------------------------------------------------------------------------------------- +{ + NS_PRECONDITION(aBuf != nsnull, "null ptr"); + if (!aBuf) + return NS_ERROR_NULL_POINTER; + NS_PRECONDITION(aReadCount != nsnull, "null ptr"); + if (!aReadCount) + return NS_ERROR_NULL_POINTER; + if (!mFileDesc) + return NS_FILE_RESULT(PR_BAD_DESCRIPTOR_ERROR); + if (mFailed) + return NS_ERROR_FAILURE; + PRInt32 bytesRead = PR_Read(mFileDesc, aBuf, aCount); + if (bytesRead < 0) + { + *aReadCount = 0; + mFailed = PR_TRUE; + return NS_FILE_RESULT(PR_GetError()); + } + else if (bytesRead == 0) + { + mEOF = PR_TRUE; + } + *aReadCount = bytesRead; + return NS_OK; +} + +NS_IMETHODIMP +FileImpl::ReadSegments(nsWriteSegmentFun writer, void * closure, PRUint32 count, PRUint32 *_retval) +{ + NS_NOTREACHED("ReadSegments"); + return NS_ERROR_NOT_IMPLEMENTED; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP FileImpl::Write(const char* aBuf, PRUint32 aCount, PRUint32 *aWriteCount) +//---------------------------------------------------------------------------------------- +{ + NS_PRECONDITION(aBuf != nsnull, "null ptr"); + NS_PRECONDITION(aWriteCount != nsnull, "null ptr"); + + *aWriteCount = 0; + +#ifdef XP_MAC + // Calling PR_Write on stdout is sure suicide. + if (mFileDesc == PR_STDOUT || mFileDesc == PR_STDERR) + { + std::cout.write(aBuf, aCount); + *aWriteCount = aCount; + return NS_OK; + } +#endif + if (!mFileDesc) + return NS_FILE_RESULT(PR_BAD_DESCRIPTOR_ERROR); + if (mFailed) + return NS_ERROR_FAILURE; + + if (!mGotBuffers) + { + nsresult rv = AllocateBuffers(kOuputBufferSegmentSize, kOuputBufferMaxSize); + if (NS_FAILED(rv)) + return rv; // try to write non-buffered? + } + + PRUint32 bufOffset = 0; + PRUint32 currentWrite = 0; + while (aCount > 0) + { + if (mWriteCursor == nsnull || mWriteCursor == mWriteLimit) + { + char* seg = mOutBuffer.AppendNewSegment(); + if (seg == nsnull) + { + // buffer is full, try again + InternalFlush(PR_FALSE); + seg = mOutBuffer.AppendNewSegment(); + if (seg == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + } + mWriteCursor = seg; + mWriteLimit = seg + mOutBuffer.GetSegmentSize(); + } + + // move + currentWrite = mWriteLimit - mWriteCursor; + + if (aCount < currentWrite) + currentWrite = aCount; + + memcpy(mWriteCursor, (aBuf + bufOffset), currentWrite); + + mWriteCursor += currentWrite; + + aCount -= currentWrite; + bufOffset += currentWrite; + *aWriteCount += currentWrite; + } + + return NS_OK; +} + +static NS_METHOD +nsWriteSegmentToFile(nsIInputStream* in, + void* closure, + const char* fromRawSegment, + PRUint32 toOffset, + PRUint32 count, + PRUint32 *writeCount) +{ + NS_NOTREACHED("nsWriteSegmentToFile"); + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +FileImpl::WriteFrom(nsIInputStream *inStr, PRUint32 count, PRUint32 *result) +{ + return inStr->ReadSegments(nsWriteSegmentToFile, nsnull, count, result); +} + +NS_IMETHODIMP +FileImpl::WriteSegments(nsReadSegmentFun reader, void * closure, + PRUint32 count, PRUint32 *result) +{ + NS_NOTREACHED("WriteSegments"); + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +FileImpl::IsNonBlocking(PRBool *aNonBlocking) +{ + *aNonBlocking = PR_FALSE; + return NS_OK; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP FileImpl::Tell(PRInt64* outWhere) +//---------------------------------------------------------------------------------------- +{ + if (mFileDesc==PR_STDIN || mFileDesc==PR_STDOUT || mFileDesc==PR_STDERR || !mFileDesc) + return NS_FILE_RESULT(PR_BAD_DESCRIPTOR_ERROR); + *outWhere = PR_Seek64(mFileDesc, 0, PR_SEEK_CUR); + return NS_OK; +} // FileImpl::Tell + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP FileImpl::Close() +//---------------------------------------------------------------------------------------- +{ + if ((mNSPRMode & PR_RDONLY) == 0) + InternalFlush(PR_FALSE); + + if (mFileDesc==PR_STDIN || mFileDesc==PR_STDOUT || mFileDesc==PR_STDERR || !mFileDesc) + return NS_OK; + if (PR_Close(mFileDesc) == PR_SUCCESS) + mFileDesc = 0; + else + return NS_FILE_RESULT(PR_GetError()); + return NS_OK; +} // FileImpl::close + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP FileImpl::Flush() +//---------------------------------------------------------------------------------------- +{ + // for external callers, this will do a Sync as well as flush buffers. + return InternalFlush(PR_TRUE); +} // FileImpl::flush + + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP FileImpl::GetAtEOF(PRBool* outAtEOF) +//---------------------------------------------------------------------------------------- +{ + *outAtEOF = mEOF; + return NS_OK; +} + + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP FileImpl::SetAtEOF(PRBool inAtEOF) +//---------------------------------------------------------------------------------------- +{ + mEOF = inAtEOF; + return NS_OK; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP FileImpl::SetEOF() +//---------------------------------------------------------------------------------------- +{ + NS_NOTYETIMPLEMENTED("FileImpl::SetEOF"); + return NS_ERROR_NOT_IMPLEMENTED; +} + +//---------------------------------------------------------------------------------------- +nsresult FileImpl::AllocateBuffers(PRUint32 segmentSize, PRUint32 maxBufSize) +//---------------------------------------------------------------------------------------- +{ + nsresult rv = mOutBuffer.Init(segmentSize, maxBufSize); + if (NS_SUCCEEDED(rv)) + mGotBuffers = PR_TRUE; + + return rv; +} + +// external callers of Flush will have sync get called, +// but internal callers just want to flush the buffers to disk. +nsresult FileImpl::InternalFlush(PRBool syncFile) +{ +#ifdef XP_MAC + if (mFileDesc == PR_STDOUT || mFileDesc == PR_STDERR) + { + std::cout.flush(); + return NS_OK; + } +#endif + if (!mFileDesc) + return NS_FILE_RESULT(PR_BAD_DESCRIPTOR_ERROR); + + PRInt32 segCount = mOutBuffer.GetSegmentCount(); + PRUint32 segSize = mOutBuffer.GetSegmentSize(); + + for (PRInt32 i = 0; i < segCount; i++) + { + char* seg = mOutBuffer.GetSegment(i); + + // if it is the last buffer, it may not be completely full. + if(i == (segCount-1)) + segSize = (mWriteCursor - seg); + + PRInt32 bytesWrit = PR_Write(mFileDesc, seg, segSize); + if (bytesWrit != (PRInt32)segSize) + { + mFailed = PR_TRUE; + return NS_FILE_RESULT(PR_GetError()); + } + } + + if (mGotBuffers) + mOutBuffer.Empty(); + mWriteCursor = nsnull; + mWriteLimit = nsnull; + + // On unix, it seems to fail always. + if (syncFile && PR_Sync(mFileDesc) != PR_SUCCESS) + mFailed = PR_TRUE; + + return NS_OK; +} +//---------------------------------------------------------------------------------------- +nsresult NS_NewTypicalInputFileStream( + nsISupports** aResult, + const nsFileSpec& inFile + /*Default nsprMode == PR_RDONLY*/ + /*Default accessmode = 0666 (octal)*/) +// Factory method to get an nsInputStream from a file, using most common options +//---------------------------------------------------------------------------------------- +{ + // This QueryInterface was needed because NS_NewIOFileStream + // does a cast from (void *) to (nsISupports *) thus causing a + // vtable problem on Windows, where we really didn't have the proper pointer + // to an nsIInputStream, this ensures that we do + nsISupports * supports; + nsIInputStream * inStr; + + nsresult rv = NS_NewIOFileStream(&supports, inFile, PR_RDONLY, 0666); + + *aResult = nsnull; + if (NS_SUCCEEDED(rv)) { + if (NS_SUCCEEDED(supports->QueryInterface(NS_GET_IID(nsIInputStream), (void**)&inStr))) { + *aResult = inStr; + } + NS_RELEASE(supports); + } + return rv; +} + +//---------------------------------------------------------------------------------------- +nsresult NS_NewTypicalOutputFileStream( + nsISupports** aResult, + const nsFileSpec& inFile + /*default nsprMode= (PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE)*/ + /*Default accessMode= 0666 (octal)*/) +// Factory method to get an nsOutputStream to a file - most common case. +//---------------------------------------------------------------------------------------- +{ + // This QueryInterface was needed because NS_NewIOFileStream + // does a cast from (void *) to (nsISupports *) thus causing a + // vtable problem on Windows, where we really didn't have the proper pointer + // to an nsIOutputStream, this ensures that we do +#if 1 +/* nsISupports * supports; + nsIOutputStream * outStr; + + nsresult rv = NS_NewIOFileStream( + &supports, + inFile, + (PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE), + 0666); + + *aResult = nsnull; + if (NS_SUCCEEDED(rv)) { + if (NS_SUCCEEDED(supports->QueryInterface(NS_GET_IID(nsIOutputStream), (void**)&outStr))) { + *aResult = outStr; + } + NS_RELEASE(supports); + } + return rv; + */ + + nsCOMPtr supports; + nsIOutputStream * outStr; + + nsresult rv = NS_NewIOFileStream( + getter_AddRefs(supports), + inFile, + (PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE), + 0666); + + *aResult = nsnull; + if (NS_SUCCEEDED(rv)) { + if (NS_SUCCEEDED(supports->QueryInterface(NS_GET_IID(nsIOutputStream), (void**)&outStr))) { + *aResult = outStr; + } + } + return rv; +#else + return NS_NewIOFileStream( + aResult, + inFile, + (PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE), + 0666); +#endif +} + +//---------------------------------------------------------------------------------------- +NS_COM_OBSOLETE nsresult NS_NewIOFileStream( + nsISupports** aResult, + const nsFileSpec& inFile, + PRInt32 nsprMode /*default = (PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE)*/, + PRInt32 accessMode /*Default = 0666 (octal)*/) + // Factory method to get an object that implements both nsIInputStream + // and nsIOutputStream, associated with a file. +//---------------------------------------------------------------------------------------- +{ + NS_PRECONDITION(aResult != nsnull, "null ptr"); + if (!aResult) + return NS_ERROR_NULL_POINTER; + + FileImpl* stream = new FileImpl(inFile, nsprMode, accessMode); + if (! stream) + return NS_ERROR_OUT_OF_MEMORY; + + NS_ADDREF(stream); + PRBool isOpened = PR_FALSE; + stream->GetIsOpen(&isOpened); + if (!isOpened) + { + NS_RELEASE(stream); + return NS_ERROR_FAILURE; + } + + *aResult = (nsISupports*)(void*)stream; + return NS_OK; +} + diff --git a/src/libs/xpcom18a4/xpcom/obsolete/nsIFileStream.h b/src/libs/xpcom18a4/xpcom/obsolete/nsIFileStream.h new file mode 100644 index 00000000..251b3ffc --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/obsolete/nsIFileStream.h @@ -0,0 +1,157 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ +#ifndef nsIFileStream_h___ +#define nsIFileStream_h___ + +#include "xpcomobsolete.h" +#include "nsIInputStream.h" +#include "nsIOutputStream.h" +#include "nsISeekableStream.h" +#include "prio.h" + +class nsFileSpec; + +/* a6cf90e8-15b3-11d2-932e-00805f8add32 */ +#define NS_IOPENFILE_IID \ +{ 0xa6cf90e8, 0x15b3, 0x11d2, \ + {0x93, 0x2e, 0x00, 0x80, 0x5f, 0x8a, 0xdd, 0x32} } + +//======================================================================================== +class nsIOpenFile +// Represents a file, and supports Open. +//======================================================================================== +: public nsISupports +{ +public: + NS_DEFINE_STATIC_IID_ACCESSOR(NS_IOPENFILE_IID) + + NS_IMETHOD Open( + const nsFileSpec& inFile, + int nsprMode, + PRIntn accessMode) = 0; + // Note: Open() is only needed after + // an explicit Close(). All file streams + // are automatically opened on construction. + NS_IMETHOD GetIsOpen(PRBool* outOpen) = 0; + +}; // class nsIOpenFile + +/* a6cf90e8-15b3-11d2-932e-00805f8add32 */ +#define NS_IRANDOMACCESS_IID \ +{ 0xa6cf90eb, 0x15b3, 0x11d2, \ + {0x93, 0x2e, 0x00, 0x80, 0x5f, 0x8a, 0xdd, 0x32} } + +//======================================================================================== +class nsIRandomAccessStore +// Supports Seek, Tell etc. +//======================================================================================== +: public nsISeekableStream +{ +public: + NS_DEFINE_STATIC_IID_ACCESSOR(NS_IRANDOMACCESS_IID) + +/* "PROTECTED" */ + NS_IMETHOD GetAtEOF(PRBool* outAtEOF) = 0; + NS_IMETHOD SetAtEOF(PRBool inAtEOF) = 0; +}; // class nsIRandomAccessStore + + +#ifndef NO_XPCOM_FILE_STREAMS // hack to work around duplicate class definitions in here + // and mozilla/netwerks/base/nsIFileStreams.idl + +/* a6cf90e6-15b3-11d2-932e-00805f8add32 */ +#define NS_IFILESPECINPUTSTREAM_IID \ +{ 0xa6cf90e6, 0x15b3, 0x11d2, \ + {0x93, 0x2e, 0x00, 0x80, 0x5f, 0x8a, 0xdd, 0x32} } + +//======================================================================================== +class nsIFileSpecInputStream +// These are additional file-specific methods that files have, above what +// nsIInputStream supports. The current implementation supports both +// interfaces. +//======================================================================================== +: public nsIInputStream +{ +public: + NS_DEFINE_STATIC_IID_ACCESSOR(NS_IFILESPECINPUTSTREAM_IID) +}; // class nsIFileSpecInputStream + +/* a6cf90e7-15b3-11d2-932e-00805f8add32 */ +#define NS_IFILESPECOUTPUTSTREAM_IID \ +{ 0xa6cf90e7, 0x15b3, 0x11d2, \ + {0x93, 0x2e, 0x00, 0x80, 0x5f, 0x8a, 0xdd, 0x32} } + +//======================================================================================== +class nsIFileSpecOutputStream +// These are additional file-specific methods that files have, above what +// nsIOutputStream supports. The current implementation supports both +// interfaces. +//======================================================================================== +: public nsIOutputStream +{ +public: + NS_DEFINE_STATIC_IID_ACCESSOR(NS_IFILESPECOUTPUTSTREAM_IID) +}; // class nsIFileSpecOutputStream + +#endif // NO_XPCOM_FILE_STREAMS + +//---------------------------------------------------------------------------------------- +nsresult NS_NewTypicalInputFileStream( + nsISupports** aStreamResult, + const nsFileSpec& inFile + /*Default nsprMode == PR_RDONLY*/ + /*Default accessmode = 0700 (octal)*/); +// Factory method to get an nsInputStream from a file, using most common options + +//---------------------------------------------------------------------------------------- +nsresult NS_NewTypicalOutputFileStream( + nsISupports** aStreamResult, // will implement all the above interfaces + const nsFileSpec& inFile + /*default nsprMode= (PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE)*/ + /*Default accessMode= 0700 (octal)*/); + // Factory method to get an nsOutputStream to a file - most common case. + +//---------------------------------------------------------------------------------------- +extern "C" NS_COM_OBSOLETE nsresult NS_NewIOFileStream( + nsISupports** aStreamResult, // will implement all the above interfaces + const nsFileSpec& inFile, + PRInt32 nsprMode, + PRInt32 accessMode); + // Factory method to get an object that implements both nsIInputStream + // and nsIOutputStream, associated with a single file. + +#endif /* nsIFileSpecStream_h___ */ diff --git a/src/libs/xpcom18a4/xpcom/obsolete/nsIRegistry.idl b/src/libs/xpcom18a4/xpcom/obsolete/nsIRegistry.idl new file mode 100644 index 00000000..bc9990e2 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/obsolete/nsIRegistry.idl @@ -0,0 +1,186 @@ +/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org Code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsISupports.idl" +#include "nsIEnumerator.idl" + +interface nsIFile; + +typedef PRUint32 nsRegistryKey; +typedef long nsWellKnownRegistry; + +[scriptable,uuid(5D41A440-8E37-11d2-8059-00600811A9C3)] +interface nsIRegistry : nsISupports +{ + const long None = 0; + const long Users = 1; + const long Common = 2; + const long CurrentUser = 3; + + const long ApplicationComponentRegistry = 1; + const long ApplicationRegistry = 2; + + // Dont use this one. This for internal use only. + const long ApplicationCustomRegistry = -1; + + void open(in nsIFile regFile); + void openWellKnownRegistry(in nsWellKnownRegistry regid); + + void flush(); + boolean isOpen(); + + nsRegistryKey addKey(in nsRegistryKey baseKey, in wstring keyname); + nsRegistryKey getKey(in nsRegistryKey baseKey, in wstring keyname); + void removeKey(in nsRegistryKey baseKey, in wstring keyname); + + wstring getString(in nsRegistryKey baseKey, in wstring valname); + void setString(in nsRegistryKey baseKey, in wstring valname, in wstring value); + + string getStringUTF8(in nsRegistryKey baseKey, in string path); + void setStringUTF8(in nsRegistryKey baseKey, in string path, in string value); + + void getBytesUTF8(in nsRegistryKey baseKey, in string path, out PRUint32 length, [retval, array, size_is(length)] out PRUint8 valueArray); + void setBytesUTF8(in nsRegistryKey baseKey, in string path, in PRUint32 length, [array, size_is(length)] in PRUint8 valueArray); + PRInt32 getInt(in nsRegistryKey baseKey, in string path); + void setInt(in nsRegistryKey baseKey, in string path, in PRInt32 value); + PRInt64 getLongLong(in nsRegistryKey baseKey, in string path); + void setLongLong(in nsRegistryKey baseKey, in string path, inout PRInt64 value); + + /** + * addSubtree() and friends need to be renamed to addKeyUTF8(). + * If you are using these forms make sure you pass UTF8 data + */ + nsRegistryKey addSubtree(in nsRegistryKey baseKey, in string path); + void removeSubtree(in nsRegistryKey baseKey, in string path); + nsRegistryKey getSubtree(in nsRegistryKey baseKey, in string path); + + nsRegistryKey addSubtreeRaw(in nsRegistryKey baseKey, in string path); + void removeSubtreeRaw(in nsRegistryKey baseKey, in string path); + nsRegistryKey getSubtreeRaw(in nsRegistryKey baseKey, in string path); + + nsIEnumerator enumerateSubtrees(in nsRegistryKey baseKey); + nsIEnumerator enumerateAllSubtrees(in nsRegistryKey baseKey); + nsIEnumerator enumerateValues(in nsRegistryKey baseKey); + + const unsigned long String = 1; + const unsigned long Int32 = 2; + const unsigned long Bytes = 3; + const unsigned long File = 4; + + unsigned long getValueType(in nsRegistryKey baseKey, in string path); + PRUint32 getValueLength(in nsRegistryKey baseKey, in string path); + void deleteValue(in nsRegistryKey baseKey, in string path); + + /** + * escapeKey() takes arbitrary binary data and converts it into + * valid ASCII which can be used as registry key or value names + */ + void escapeKey([array, size_is(length)] in PRUint8 key, in PRUint32 terminator, inout PRUint32 length, [retval, array, size_is(length)] out PRUint8 escaped); + void unescapeKey([array, size_is(length)] in PRUint8 escaped, in PRUint32 terminator, inout PRUint32 length, [retval, array, size_is(length)] out PRUint8 key); + + attribute string currentUserName; + + void pack(); +}; + +[scriptable, uuid(8cecf236-1dd2-11b2-893c-f9848956eaec)] +interface nsIRegistryEnumerator : nsIEnumerator +{ + void currentItemInPlaceUTF8(out nsRegistryKey key, + [shared, retval] out string item); +}; + +[scriptable, uuid(D1B54831-AC07-11d2-805E-00600811A9C3)] +interface nsIRegistryNode : nsISupports +{ + readonly attribute string nameUTF8; + readonly attribute wstring name; + readonly attribute nsRegistryKey key; +}; + +[scriptable,uuid(5316C380-B2F8-11d2-A374-0080C6F80E4B)] +interface nsIRegistryValue : nsISupports +{ + readonly attribute wstring name; + readonly attribute string nameUTF8; + readonly attribute unsigned long type; + readonly attribute PRUint32 length; +}; + +[uuid(3A15FC88-7A61-4Ab4-8E58-31E95fAB3DA8)] +/** + * It sucks that nsIRegistry has to always allocate and return + * strings. nsIRegistryGetter adds in interfaces for non allocating getters + * to registry values. + */ +interface nsIRegistryGetter : nsISupports +{ + /** + * Get a string value of attribute valname in widestring or utf8 format + * + * @return + * NS_OK on success. + * buf has the string value copied into it. length is NOT changed. + * NS_ERROR_REG_BUFFER_TOO_SMALL if not enough buffer space. + * length is updated to actual length in chars including + * terminating NULL and buf will be unchanged. + * NS_ERROR_FAILURE if an unknown error happened. state of buf and + * length undefined. + * various failure codes otherwise. buf and length wont be updated. + */ + void getStringUTF8IntoBuffer(in nsRegistryKey baseKey, in string path, + inout char buf, inout PRUint32 length); + + /** + * Get a a byte array value of attribute valname + * + * @return + * NS_OK on success. buf has the string value copied into it. + * length is updated to actual number of bytes copied into buf. + * NS_ERROR_REG_BUFFER_TOO_SMALL if not enough buffer space. + * length is updated to actual length in PRUint8s including + * terminating NULL and buf will be unchanged. + * NS_ERROR_FAILURE if an unknown error happened. state of buf and + * length undefined. + * various other failure codes otherwise. buf and length wont be updated. + */ + void getBytesUTF8IntoBuffer(in nsRegistryKey baseKey, in string path, + inout PRUint8 buf, inout PRUint32 length); +}; + +%{ C++ +#include "nsIRegistryUtils.h" +%} diff --git a/src/libs/xpcom18a4/xpcom/obsolete/nsIRegistryUtils.h b/src/libs/xpcom18a4/xpcom/obsolete/nsIRegistryUtils.h new file mode 100644 index 00000000..a3d74d7a --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/obsolete/nsIRegistryUtils.h @@ -0,0 +1,63 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ +#ifndef __nsIRegistryUtils_h +#define __nsIRegistryUtils_h + +#define NS_REGISTRY_CONTRACTID "@mozilla.org/registry;1" +#define NS_REGISTRY_CLASSNAME "Mozilla Registry" +/* be761f00-a3b0-11d2-996c-0080c7cb1081 */ +#define NS_REGISTRY_CID \ +{ \ + 0xbe761f00, \ + 0xa3b0, \ + 0x11d2, \ + {0x99, 0x6c, 0x00, 0x80, 0xc7, 0xcb, 0x10, 0x81} \ +} + +/*------------------------------- Error Codes ---------------------------------- +------------------------------------------------------------------------------*/ +#define NS_ERROR_REG_BADTYPE NS_ERROR_GENERATE_FAILURE( NS_ERROR_MODULE_REG, 1 ) +#define NS_ERROR_REG_NO_MORE NS_ERROR_GENERATE_SUCCESS( NS_ERROR_MODULE_REG, 2 ) +#define NS_ERROR_REG_NOT_FOUND NS_ERROR_GENERATE_FAILURE( NS_ERROR_MODULE_REG, 3 ) +#define NS_ERROR_REG_NOFILE NS_ERROR_GENERATE_FAILURE( NS_ERROR_MODULE_REG, 4 ) +#define NS_ERROR_REG_BUFFER_TOO_SMALL NS_ERROR_GENERATE_FAILURE( NS_ERROR_MODULE_REG, 5 ) +#define NS_ERROR_REG_NAME_TOO_LONG NS_ERROR_GENERATE_FAILURE( NS_ERROR_MODULE_REG, 6 ) +#define NS_ERROR_REG_NO_PATH NS_ERROR_GENERATE_FAILURE( NS_ERROR_MODULE_REG, 7 ) +#define NS_ERROR_REG_READ_ONLY NS_ERROR_GENERATE_FAILURE( NS_ERROR_MODULE_REG, 8 ) +#define NS_ERROR_REG_BAD_UTF8 NS_ERROR_GENERATE_FAILURE( NS_ERROR_MODULE_REG, 9 ) + +#endif diff --git a/src/libs/xpcom18a4/xpcom/obsolete/nsSpecialSystemDirectory.cpp b/src/libs/xpcom18a4/xpcom/obsolete/nsSpecialSystemDirectory.cpp new file mode 100644 index 00000000..f120cd43 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/obsolete/nsSpecialSystemDirectory.cpp @@ -0,0 +1,1189 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Doug Turner + * IBM Corp. + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsSpecialSystemDirectory.h" +#include "nsDebug.h" + +#ifdef XP_MAC +#include +#include +#include +#include +#include +#include "nsIInternetConfigService.h" +#ifdef DEBUG +#include "prenv.h" // For PR_Getenv +#endif +#elif defined(XP_WIN) +#include +#include +#include +#include +#elif defined(XP_OS2) +#define MAX_PATH _MAX_PATH +#define INCL_WINWORKPLACE +#include +#include +#include +#include "prenv.h" +#elif defined(XP_UNIX) +#include +#include +#include +#include "prenv.h" +#elif defined(XP_BEOS) +#include +#include +#include +#include +#include +#include +#include +#include "prenv.h" +#endif + +#if defined(VMS) +#include +#endif + +#include "plstr.h" + +#include "nsHashtable.h" +#include "prlog.h" + +#if defined (XP_MAC) && UNIVERSAL_INTERFACES_VERSION < 0x0340 + enum { + kSystemDomain = -32766, /* Read-only system hierarchy.*/ + kLocalDomain = -32765, /* All users of a single machine have access to these resources.*/ + kNetworkDomain = -32764, /* All users configured to use a common network server has access to these resources.*/ + kUserDomain = -32763, /* Read/write. Resources that are private to the user.*/ + kClassicDomain = -32762, /* Domain referring to the currently configured Classic System Folder*/ + + kDomainLibraryFolderType = FOUR_CHAR_CODE('dlib') + }; +#endif + + +class SystemDirectoriesKey : public nsHashKey { +public: + + SystemDirectoriesKey(nsSpecialSystemDirectory::SystemDirectories newKey) : sdKey(newKey) {} + + virtual PRUint32 HashCode(void) const + { + return PRUint32(sdKey); + } + + virtual PRBool Equals(const nsHashKey *aKey) const + { + nsSpecialSystemDirectory::SystemDirectories other = + ((SystemDirectoriesKey*)aKey)->sdKey; + return other == sdKey; + } + + virtual nsHashKey *Clone(void) const + { + return new SystemDirectoriesKey(sdKey); + } + +private: + nsSpecialSystemDirectory::SystemDirectories sdKey; // sd for SystemDirectories +}; + +PR_STATIC_CALLBACK(PRBool) DeleteSystemDirKeys(nsHashKey *aKey, void *aData, void* closure) +{ + delete ((nsFileSpec *)aData); + return PR_TRUE; +} + +#define NS_SYSTEMDIR_HASH_NUM (10) +static nsHashtable *systemDirectoriesLocations = NULL; +#if defined (XP_WIN) +typedef BOOL (WINAPI * GetSpecialPathProc) (HWND hwndOwner, LPSTR lpszPath, int nFolder, BOOL fCreate); +GetSpecialPathProc gGetSpecialPathProc = NULL; +static HINSTANCE gShell32DLLInst = NULL; +#endif +NS_COM_OBSOLETE void StartupSpecialSystemDirectory() +{ +#if defined (XP_WIN) + /* On windows, the old method to get file locations is incredibly slow. + As of this writing, 3 calls to GetWindowsFolder accounts for 3% of mozilla + startup. Replacing these older calls with a single call to SHGetSpecialFolderPath + effectively removes these calls from the performace radar. We need to + support the older way of file location lookup on systems that do not have + IE4. (Note: gets the ansi version: SHGetSpecialFolderPathA). + */ + gShell32DLLInst = LoadLibrary("Shell32.dll"); + if(gShell32DLLInst) + { + gGetSpecialPathProc = (GetSpecialPathProc) GetProcAddress(gShell32DLLInst, + "SHGetSpecialFolderPathA"); + } +#endif +} + +NS_COM_OBSOLETE void ShutdownSpecialSystemDirectory() +{ + if (systemDirectoriesLocations) + { + systemDirectoriesLocations->Reset(DeleteSystemDirKeys); + delete systemDirectoriesLocations; + } +#if defined (XP_WIN) + if (gShell32DLLInst) + { + FreeLibrary(gShell32DLLInst); + gShell32DLLInst = NULL; + gGetSpecialPathProc = NULL; + } +#endif +} + +#if defined (XP_WIN) + +static PRBool gGlobalOSInitialized = PR_FALSE; +static PRBool gGlobalDBCSEnabledOS = PR_FALSE; + +//---------------------------------------------------------------------------------------- +static char* MakeUpperCase(char* aPath) +//---------------------------------------------------------------------------------------- +{ + // check if the Windows is DBCSEnabled once. + if (PR_FALSE == gGlobalOSInitialized) { + if (GetSystemMetrics(SM_DBCSENABLED)) + gGlobalDBCSEnabledOS = PR_TRUE; + gGlobalOSInitialized = PR_TRUE; + } + + // windows does not care about case. pu sh to uppercase: + int length = strlen(aPath); + int i = 0; /* C++ portability guide #20 */ + if (!gGlobalDBCSEnabledOS) { + // for non-DBCS windows + for (i = 0; i < length; i++) + if (islower(aPath[i])) + aPath[i] = _toupper(aPath[i]); + } + else { + // for DBCS windows + for (i = 0; i < length; i++) { + if (IsDBCSLeadByte(aPath[i])) { + // begining of the double bye char + i++; + } + else { + if ( islower(aPath[i])) + aPath[i] = _toupper(aPath[i]); + } + } //end of for loop + } + return aPath; +} + +//---------------------------------------------------------------------------------------- +static void GetWindowsFolder(int folder, nsFileSpec& outDirectory) +//---------------------------------------------------------------------------------------- +{ + + if (gGetSpecialPathProc) { + TCHAR path[MAX_PATH]; + HRESULT result = gGetSpecialPathProc(NULL, path, folder, true); + + if (!SUCCEEDED(result)) + return; + + // Append the trailing slash + int len = PL_strlen(path); + if (len>1 && path[len-1] != '\\') + { + path[len] = '\\'; + path[len + 1] = '\0'; + } + outDirectory = path; + return; + } + + LPMALLOC pMalloc = NULL; + LPSTR pBuffer = NULL; + LPITEMIDLIST pItemIDList = NULL; + int len; + + // Get the shell's allocator. + if (!SUCCEEDED(SHGetMalloc(&pMalloc))) + return; + + // Allocate a buffer + if ((pBuffer = (LPSTR) pMalloc->Alloc(MAX_PATH + 2)) == NULL) + return; + + // Get the PIDL for the folder. + if (!SUCCEEDED(SHGetSpecialFolderLocation( + NULL, folder, &pItemIDList))) + goto Clean; + + if (!SUCCEEDED(SHGetPathFromIDList(pItemIDList, pBuffer))) + goto Clean; + + // Append the trailing slash + len = PL_strlen(pBuffer); + pBuffer[len] = '\\'; + pBuffer[len + 1] = '\0'; + + // Assign the directory + outDirectory = pBuffer; + +Clean: + // Clean up. + if (pItemIDList) + pMalloc->Free(pItemIDList); + if (pBuffer) + pMalloc->Free(pBuffer); + + pMalloc->Release(); +} // GetWindowsFolder +#endif // XP_WIN + +//---------------------------------------------------------------------------------------- +static void GetCurrentWorkingDirectory(nsFileSpec& aFileSpec) +//---------------------------------------------------------------------------------------- +{ + aFileSpec = "."; + return; +} // GetCurrentWorkingDirectory + +//---------------------------------------------------------------------------------------- +static void GetCurrentProcessDirectory(nsFileSpec& aFileSpec) +//---------------------------------------------------------------------------------------- +{ +#if defined (XP_WIN) + char buf[MAX_PATH]; + if ( ::GetModuleFileName(0, buf, sizeof(buf)) ) { + // chop of the executable name by finding the rightmost backslash + char* lastSlash = PL_strrchr(buf, '\\'); + if (lastSlash) + *(lastSlash + 1) = '\0'; + + aFileSpec = buf; + return; + } + +#elif defined(XP_OS2) + PPIB ppib; + PTIB ptib; + char buffer[CCHMAXPATH]; + DosGetInfoBlocks( &ptib, &ppib); + DosQueryModuleName( ppib->pib_hmte, CCHMAXPATH, buffer); + *strrchr( buffer, '\\') = '\0'; // XXX DBCS misery + aFileSpec = buffer; + return; + + +#elif defined(XP_MAC) + // get info for the the current process to determine the directory + // its located in + OSErr err; + ProcessSerialNumber psn = {kNoProcess, kCurrentProcess}; + ProcessInfoRec pInfo; + FSSpec tempSpec; + + // initialize ProcessInfoRec before calling + // GetProcessInformation() or die horribly. + pInfo.processName = nil; + pInfo.processAppSpec = &tempSpec; + pInfo.processInfoLength = sizeof(ProcessInfoRec); + + if (!(err = GetProcessInformation(&psn, &pInfo))) + { + FSSpec appFSSpec = *(pInfo.processAppSpec); + long theDirID = appFSSpec.parID; + + Str255 name; + CInfoPBRec catInfo; + catInfo.dirInfo.ioCompletion = NULL; + catInfo.dirInfo.ioNamePtr = (StringPtr)&name; + catInfo.dirInfo.ioVRefNum = appFSSpec.vRefNum; + catInfo.dirInfo.ioDrDirID = theDirID; + catInfo.dirInfo.ioFDirIndex = -1; // -1 = query dir in ioDrDirID + + if (!(err = PBGetCatInfoSync(&catInfo))) + { + aFileSpec = nsFileSpec(appFSSpec.vRefNum, + catInfo.dirInfo.ioDrParID, + name, + PR_TRUE); + return; + } + } +#if defined(DEBUG) + else + { + // In the absence of a good way to get the executable directory let + // us try this for unix: + // - if VBOX_XPCOM_HOME is defined, that is it + char *moz5 = PR_GetEnv("VBOX_XPCOM_HOME"); + if (moz5) + { + printf( "nsSpecialSystemDirectory::VBOX_XPCOM_HOME is set to %s\n", moz5 ); + aFileSpec = moz5; + return; + } + else + { + static PRBool firstWarning = PR_TRUE; + + if(firstWarning) { + // Warn that VBOX_XPCOM_HOME not set, once. + printf("***Warning: VBOX_XPCOM_HOME not set.\n"); + firstWarning = PR_FALSE; + } + } + } +#endif /* DEBUG */ + +#elif defined(XP_UNIX) + + // In the absence of a good way to get the executable directory let + // us try this for unix: + // - if VBOX_XPCOM_HOME is defined, that is it + // - else give the current directory + char buf[MAXPATHLEN]; + char *moz5 = PR_GetEnv("VBOX_XPCOM_HOME"); + if (moz5) + { + aFileSpec = moz5; + return; + } + else + { +#if defined(DEBUG) + static PRBool firstWarning = PR_TRUE; + + if(firstWarning) { + // Warn that VBOX_XPCOM_HOME not set, once. + printf("Warning: VBOX_XPCOM_HOME not set.\n"); + firstWarning = PR_FALSE; + } +#endif /* DEBUG */ + + // Fall back to current directory. + if (getcwd(buf, sizeof(buf))) + { + aFileSpec = buf; + return; + } + } + +#elif defined(XP_BEOS) + + char *moz5 = getenv("VBOX_XPCOM_HOME"); + if (moz5) + { + aFileSpec = moz5; + return; + } + else + { + static char buf[MAXPATHLEN]; + int32 cookie = 0; + image_info info; + char *p; + *buf = 0; + if(get_next_image_info(0, &cookie, &info) == B_OK) + { + strcpy(buf, info.name); + if((p = strrchr(buf, '/')) != 0) + { + *p = 0; + aFileSpec = buf; + return; + } + } + } + +#endif + + NS_ERROR("unable to get current process directory"); +} // GetCurrentProcessDirectory() + +//nsSpecialSystemDirectory::nsSpecialSystemDirectory() +//: nsFileSpec(nsnull) +//{ +//} + +//---------------------------------------------------------------------------------------- +nsSpecialSystemDirectory::nsSpecialSystemDirectory(SystemDirectories aSystemSystemDirectory) +//---------------------------------------------------------------------------------------- +: nsFileSpec(nsnull) +{ + *this = aSystemSystemDirectory; +} + +//---------------------------------------------------------------------------------------- +nsSpecialSystemDirectory::~nsSpecialSystemDirectory() +//---------------------------------------------------------------------------------------- +{ +} + +//---------------------------------------------------------------------------------------- +void nsSpecialSystemDirectory::operator = (SystemDirectories aSystemSystemDirectory) +//---------------------------------------------------------------------------------------- +{ + SystemDirectoriesKey dirKey(aSystemSystemDirectory); + SystemDirectoriesKey mozBinDirKey(Moz_BinDirectory); + + // This flag is used to tell whether or not we need to append something + // onto the *this. Search for needToAppend to how it's used. + // IT's VERY IMPORTANT that needToAppend is initialized to PR_TRUE. + PRBool needToAppend = PR_TRUE; + +#ifdef XP_MAC + OSErr err; + short vRefNum; + long dirID; +#endif + + *this = (const char*)nsnull; + switch (aSystemSystemDirectory) + { + + case OS_DriveDirectory: +#if defined (XP_WIN) + { + char path[_MAX_PATH]; + PRInt32 len = GetWindowsDirectory( path, _MAX_PATH ); + if (len) + { + if ( path[1] == ':' && path[2] == '\\' ) + path[3] = 0; + } + *this = MakeUpperCase(path); + } +#elif defined(XP_OS2) + { + // printf( "*** Warning warning OS_DriveDirectory called for"); + + ULONG ulBootDrive = 0; + char buffer[] = " :\\OS2\\"; + DosQuerySysInfo( QSV_BOOT_DRIVE, QSV_BOOT_DRIVE, + &ulBootDrive, sizeof ulBootDrive); + buffer[0] = 'A' - 1 + ulBootDrive; // duh, 1-based index... + *this = buffer; +#ifdef DEBUG + printf( "Got OS_DriveDirectory: %s\n", buffer); +#endif + } +#elif defined(XP_MAC) + { + *this = kVolumeRootFolderType; + } +#else + *this = "/"; +#endif + break; + + + case OS_TemporaryDirectory: +#if defined (XP_WIN) + { + char path[_MAX_PATH]; + DWORD len = GetTempPath(_MAX_PATH, path); + *this = MakeUpperCase(path); + } +#elif defined(XP_OS2) + { + char buffer[CCHMAXPATH] = ""; + char *c = getenv( "TMP"); + if( c) strcpy( buffer, c); + else + { + c = getenv( "TEMP"); + if( c) strcpy( buffer, c); + } + if( c) *this = buffer; + // use exe's directory if not set + else GetCurrentProcessDirectory(*this); + } +#elif defined(XP_MAC) + *this = kTemporaryFolderType; + +#elif defined(XP_UNIX) || defined(XP_BEOS) + { + static const char *tPath = nsnull; + if (!tPath) { + tPath = PR_GetEnv("TMPDIR"); + if (!tPath || !*tPath) { + tPath = PR_GetEnv("TMP"); + if (!tPath || !*tPath) { + tPath = PR_GetEnv("TEMP"); + if (!tPath || !*tPath) { + tPath = "/tmp/"; + } + } + } + } + + *this = tPath; + } +#endif + break; + + case OS_CurrentProcessDirectory: + GetCurrentProcessDirectory(*this); + break; + + case OS_CurrentWorkingDirectory: + GetCurrentWorkingDirectory(*this); + break; + + case XPCOM_CurrentProcessComponentRegistry: + { + nsFileSpec *dirSpec = NULL; + + // if someone has called nsSpecialSystemDirectory::Set() + if (systemDirectoriesLocations) { + // look for the value for the argument key + if (!(dirSpec = (nsFileSpec *)systemDirectoriesLocations->Get(&dirKey))) { + // if not found, try Moz_BinDirectory + dirSpec = (nsFileSpec *) + systemDirectoriesLocations->Get(&mozBinDirKey); + } + else { + // if the value is found for the argument key, + // we don't need to append. + needToAppend = PR_FALSE; + } + } + + if (dirSpec) + { + *this = *dirSpec; + } + else + { + GetCurrentProcessDirectory(*this); + } + + if (needToAppend) { + // XXX We need to unify these names across all platforms +#if defined(XP_MAC) + *this += "Component Registry"; +#else + *this += "component.reg"; +#endif /* XP_MAC */ + } + } + break; + + case XPCOM_CurrentProcessComponentDirectory: + { + nsFileSpec *dirSpec = NULL; + // if someone has called nsSpecialSystemDirectory::Set() + if (systemDirectoriesLocations) { + // look for the value for the argument key + if (!(dirSpec = (nsFileSpec *)systemDirectoriesLocations->Get(&dirKey))) { + // if not found, try Moz_BinDirectory + dirSpec = (nsFileSpec *) + systemDirectoriesLocations->Get(&mozBinDirKey); + } + else { + // if the value is found for the argument key, + // we don't need to append. + needToAppend = PR_FALSE; + } + } + if (dirSpec) + { + *this = *dirSpec; + } + else + { + // /Components + GetCurrentProcessDirectory(*this); + } + + if (needToAppend) { + // XXX We need to unify these names across all platforms +#if defined(XP_MAC) + *this += "Components"; +#else + *this += "components"; +#endif /* XP_MAC */ + } + } + break; + + case Moz_BinDirectory: + { + nsFileSpec *dirSpec = NULL; + // if someone has called nsSpecialSystemDirectory::Set() + if (systemDirectoriesLocations) { + // look for the value for the argument key + dirSpec = (nsFileSpec *) + systemDirectoriesLocations->Get(&dirKey); + } + if (dirSpec) { + *this = *dirSpec; + } + else { + GetCurrentProcessDirectory(*this); + } + } + break; + +#if defined(XP_MAC) + case Mac_SystemDirectory: + *this = kSystemFolderType; + break; + + case Mac_DesktopDirectory: + *this = kDesktopFolderType; + break; + + case Mac_TrashDirectory: + *this = kTrashFolderType; + break; + + case Mac_StartupDirectory: + *this = kStartupFolderType; + break; + + case Mac_ShutdownDirectory: + *this = kShutdownFolderType; + break; + + case Mac_AppleMenuDirectory: + *this = kAppleMenuFolderType; + break; + + case Mac_ControlPanelDirectory: + *this = kControlPanelFolderType; + break; + + case Mac_ExtensionDirectory: + *this = kExtensionFolderType; + break; + + case Mac_FontsDirectory: + *this = kFontsFolderType; + break; + + case Mac_ClassicPreferencesDirectory: + { + // whether Mac OS X or pre-Mac OS X, return Classic's Prefs folder + short domain; + long response; + err = ::Gestalt(gestaltSystemVersion, &response); + domain = (!err && response >= 0x00001000) ? kClassicDomain : kOnSystemDisk; + err = ::FindFolder(domain, kPreferencesFolderType, true, &vRefNum, &dirID); + if (!err) { + err = ::FSMakeFSSpec(vRefNum, dirID, "\p", &mSpec); + } + mError = NS_FILE_RESULT(err); + break; + } + + case Mac_PreferencesDirectory: + { + // if Mac OS X, return Mac OS X's Prefs folder + // if pre-Mac OS X, return Mac OS's Prefs folder + err = ::FindFolder(kOnSystemDisk, kPreferencesFolderType, true, &vRefNum, &dirID); + if (!err) { + err = ::FSMakeFSSpec(vRefNum, dirID, "\p", &mSpec); + } + mError = NS_FILE_RESULT(err); + break; + } + + case Mac_DocumentsDirectory: + *this = kDocumentsFolderType; + break; + + case Mac_InternetSearchDirectory: + *this = kInternetSearchSitesFolderType; + break; + + case Mac_DefaultDownloadDirectory: + *this = kDefaultDownloadFolderType; + break; + + case Mac_UserLibDirectory: + { + err = ::FindFolder(kUserDomain, kDomainLibraryFolderType, true, &vRefNum, &dirID); + if (!err) { + err = ::FSMakeFSSpec(vRefNum, dirID, "\p", &mSpec); + } + mError = NS_FILE_RESULT(err); + break; + } +#endif + +#if defined (XP_WIN) + case Win_SystemDirectory: + { + char path[_MAX_PATH]; + PRInt32 len = GetSystemDirectory( path, _MAX_PATH ); + + // Need enough space to add the trailing backslash + if (len > _MAX_PATH-2) + break; + path[len] = '\\'; + path[len+1] = '\0'; + + *this = MakeUpperCase(path); + + break; + } + + case Win_WindowsDirectory: + { + char path[_MAX_PATH]; + PRInt32 len = GetWindowsDirectory( path, _MAX_PATH ); + + // Need enough space to add the trailing backslash + if (len > _MAX_PATH-2) + break; + + path[len] = '\\'; + path[len+1] = '\0'; + + *this = MakeUpperCase(path); + break; + } + + case Win_HomeDirectory: + { + char path[_MAX_PATH]; + if (GetEnvironmentVariable(TEXT("HOME"), path, _MAX_PATH) > 0) + { + PRInt32 len = PL_strlen(path); + // Need enough space to add the trailing backslash + if (len > _MAX_PATH - 2) + break; + + path[len] = '\\'; + path[len+1] = '\0'; + + *this = MakeUpperCase(path); + break; + } + + if (GetEnvironmentVariable(TEXT("HOMEDRIVE"), path, _MAX_PATH) > 0) + { + char temp[_MAX_PATH]; + if (GetEnvironmentVariable(TEXT("HOMEPATH"), temp, _MAX_PATH) > 0) + PL_strcatn(path, _MAX_PATH, temp); + + PRInt32 len = PL_strlen(path); + + // Need enough space to add the trailing backslash + if (len > _MAX_PATH - 2) + break; + + path[len] = '\\'; + path[len+1] = '\0'; + + *this = MakeUpperCase(path); + break; + } + } + case Win_Desktop: + { + GetWindowsFolder(CSIDL_DESKTOP, *this); + break; + } + case Win_Programs: + { + GetWindowsFolder(CSIDL_PROGRAMS, *this); + break; + } + case Win_Controls: + { + GetWindowsFolder(CSIDL_CONTROLS, *this); + break; + } + case Win_Printers: + { + GetWindowsFolder(CSIDL_PRINTERS, *this); + break; + } + case Win_Personal: + { + GetWindowsFolder(CSIDL_PERSONAL, *this); + break; + } + case Win_Favorites: + { + GetWindowsFolder(CSIDL_FAVORITES, *this); + break; + } + case Win_Startup: + { + GetWindowsFolder(CSIDL_STARTUP, *this); + break; + } + case Win_Recent: + { + GetWindowsFolder(CSIDL_RECENT, *this); + break; + } + case Win_Sendto: + { + GetWindowsFolder(CSIDL_SENDTO, *this); + break; + } + case Win_Bitbucket: + { + GetWindowsFolder(CSIDL_BITBUCKET, *this); + break; + } + case Win_Startmenu: + { + GetWindowsFolder(CSIDL_STARTMENU, *this); + break; + } + case Win_Desktopdirectory: + { + GetWindowsFolder(CSIDL_DESKTOPDIRECTORY, *this); + break; + } + case Win_Drives: + { + GetWindowsFolder(CSIDL_DRIVES, *this); + break; + } + case Win_Network: + { + GetWindowsFolder(CSIDL_NETWORK, *this); + break; + } + case Win_Nethood: + { + GetWindowsFolder(CSIDL_NETHOOD, *this); + break; + } + case Win_Fonts: + { + GetWindowsFolder(CSIDL_FONTS, *this); + break; + } + case Win_Templates: + { + GetWindowsFolder(CSIDL_TEMPLATES, *this); + break; + } + case Win_Common_Startmenu: + { + GetWindowsFolder(CSIDL_COMMON_STARTMENU, *this); + break; + } + case Win_Common_Programs: + { + GetWindowsFolder(CSIDL_COMMON_PROGRAMS, *this); + break; + } + case Win_Common_Startup: + { + GetWindowsFolder(CSIDL_COMMON_STARTUP, *this); + break; + } + case Win_Common_Desktopdirectory: + { + GetWindowsFolder(CSIDL_COMMON_DESKTOPDIRECTORY, *this); + break; + } + case Win_Appdata: + { + GetWindowsFolder(CSIDL_APPDATA, *this); + break; + } + case Win_Printhood: + { + GetWindowsFolder(CSIDL_PRINTHOOD, *this); + break; + } + case Win_Cookies: + { + GetWindowsFolder(CSIDL_COOKIES, *this); + break; + } +#endif // XP_WIN + +#if defined(XP_UNIX) + case Unix_LocalDirectory: + *this = "/usr/local/netscape/"; + break; + + case Unix_LibDirectory: + *this = "/usr/local/lib/netscape/"; + break; + + case Unix_HomeDirectory: +#ifdef VMS + { + char *pHome; + pHome = getenv("HOME"); + if (*pHome == '/') + *this = pHome; + else + *this = decc$translate_vms(pHome); + } +#else + *this = PR_GetEnv("HOME"); +#endif + break; + +#endif + +#ifdef XP_BEOS + case BeOS_SettingsDirectory: + { + char path[MAXPATHLEN]; + find_directory(B_USER_SETTINGS_DIRECTORY, 0, 0, path, MAXPATHLEN); + // Need enough space to add the trailing backslash + int len = strlen(path); + if (len > MAXPATHLEN-2) + break; + path[len] = '/'; + path[len+1] = '\0'; + *this = path; + break; + } + + case BeOS_HomeDirectory: + { + char path[MAXPATHLEN]; + find_directory(B_USER_DIRECTORY, 0, 0, path, MAXPATHLEN); + // Need enough space to add the trailing backslash + int len = strlen(path); + if (len > MAXPATHLEN-2) + break; + path[len] = '/'; + path[len+1] = '\0'; + *this = path; + break; + } + + case BeOS_DesktopDirectory: + { + char path[MAXPATHLEN]; + find_directory(B_DESKTOP_DIRECTORY, 0, 0, path, MAXPATHLEN); + // Need enough space to add the trailing backslash + int len = strlen(path); + if (len > MAXPATHLEN-2) + break; + path[len] = '/'; + path[len+1] = '\0'; + *this = path; + break; + } + + case BeOS_SystemDirectory: + { + char path[MAXPATHLEN]; + find_directory(B_BEOS_DIRECTORY, 0, 0, path, MAXPATHLEN); + // Need enough space to add the trailing backslash + int len = strlen(path); + if (len > MAXPATHLEN-2) + break; + path[len] = '/'; + path[len+1] = '\0'; + *this = path; + break; + } +#endif +#ifdef XP_OS2 + case OS2_SystemDirectory: + { + ULONG ulBootDrive = 0; + char buffer[] = " :\\OS2\\System\\"; + DosQuerySysInfo( QSV_BOOT_DRIVE, QSV_BOOT_DRIVE, + &ulBootDrive, sizeof ulBootDrive); + buffer[0] = 'A' - 1 + ulBootDrive; // duh, 1-based index... + *this = buffer; +#ifdef DEBUG + printf( "Got OS2_SystemDirectory: %s\n", buffer); +#endif + break; + } + + case OS2_OS2Directory: + { + ULONG ulBootDrive = 0; + char buffer[] = " :\\OS2\\"; + DosQuerySysInfo( QSV_BOOT_DRIVE, QSV_BOOT_DRIVE, + &ulBootDrive, sizeof ulBootDrive); + buffer[0] = 'A' - 1 + ulBootDrive; // duh, 1-based index... + *this = buffer; +#ifdef DEBUG + printf( "Got OS2_OS2Directory: %s\n", buffer); +#endif + break; + } + + case OS2_HomeDirectory: + { + char *tPath = PR_GetEnv("MOZILLA_HOME"); + /* If MOZILLA_HOME is not set, use GetCurrentProcessDirectory */ + /* To ensure we get a long filename system */ + if (!tPath || !*tPath) + GetCurrentProcessDirectory(*this); + else + *this = tPath; + PrfWriteProfileString(HINI_USERPROFILE, "Mozilla", "Home", *this); + break; + } + + case OS2_DesktopDirectory: + { + char szPath[CCHMAXPATH + 1]; + BOOL fSuccess; + fSuccess = WinQueryActiveDesktopPathname (szPath, sizeof(szPath)); + int len = strlen (szPath); + if (len > CCHMAXPATH -1) + break; + szPath[len] = '\\'; + szPath[len + 1] = '\0'; +#ifdef DEBUG + if (fSuccess) { + printf ("Got OS2_DesktopDirectory: %s\n", szPath); + } else { + printf ("Failed getting OS2_DesktopDirectory: %s\n", szPath); + } +#endif + break; + } + +#endif + default: + break; + } +} + +void +nsSpecialSystemDirectory::Set(SystemDirectories dirToSet, nsFileSpec *dirSpec) +{ + SystemDirectoriesKey dirKey(dirToSet); + + PR_ASSERT(NULL != dirSpec); + + if (NULL == systemDirectoriesLocations) { + systemDirectoriesLocations = new nsHashtable(NS_SYSTEMDIR_HASH_NUM); + } + PR_ASSERT(NULL != systemDirectoriesLocations); + + nsFileSpec *newSpec = new nsFileSpec(*dirSpec); + if (NULL != newSpec) { + systemDirectoriesLocations->Put(&dirKey, newSpec); + } + + return; +} + +#if defined(XP_MAC) +//---------------------------------------------------------------------------------------- +nsSpecialSystemDirectory::nsSpecialSystemDirectory(OSType folderType) +//---------------------------------------------------------------------------------------- +{ + *this = folderType; +} + +//---------------------------------------------------------------------------------------- +void nsSpecialSystemDirectory::operator = (OSType folderType) +//---------------------------------------------------------------------------------------- +{ + CInfoPBRec cinfo; + DirInfo *dipb=(DirInfo *)&cinfo; + + // hack: first check for kDefaultDownloadFolderType + // if it is, get Internet Config Download folder, if that's + // not availble use desktop folder + if (folderType == kDefaultDownloadFolderType) + { + nsCOMPtr icService (do_GetService(NS_INTERNETCONFIGSERVICE_CONTRACTID)); + if (icService) + { + if (NS_SUCCEEDED(icService->GetDownloadFolder(&mSpec))) + return; + else + folderType = kDesktopFolderType; + } + else + { + folderType = kDesktopFolderType; + } + } + // Call FindFolder to fill in the vrefnum and dirid + for (int attempts = 0; attempts < 2; attempts++) + { + mError = NS_FILE_RESULT( + FindFolder( + kOnSystemDisk, + folderType, + true, + &dipb->ioVRefNum, + &dipb->ioDrDirID)); + if (NS_SUCCEEDED(mError)) + break; + if (attempts > 0) + return; + switch (folderType) + { + case kDocumentsFolderType: + // Find folder will find this, as long as it exists. + // The "create" parameter, however, is sadly ignored. + // How do we internationalize this? + *this = kVolumeRootFolderType; + *this += "Documents"; + CreateDirectory(); + break; + } // switch + } // for + StrFileName filename; + filename[0] = '\0'; + dipb->ioNamePtr = (StringPtr)&filename; + dipb->ioFDirIndex = -1; + + mError = NS_FILE_RESULT(PBGetCatInfoSync(&cinfo)); + if (NS_SUCCEEDED(mError)) + { + mError = NS_FILE_RESULT(FSMakeFSSpec(dipb->ioVRefNum, dipb->ioDrParID, filename, &mSpec)); + } +} +#endif // XP_MAC diff --git a/src/libs/xpcom18a4/xpcom/obsolete/nsSpecialSystemDirectory.h b/src/libs/xpcom18a4/xpcom/obsolete/nsSpecialSystemDirectory.h new file mode 100644 index 00000000..577cd0c0 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/obsolete/nsSpecialSystemDirectory.h @@ -0,0 +1,167 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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 Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Doug Turner + * IBM Corp. + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +#ifndef _NSSPECIALSYSTEMDIRECTORY_H_ +#define _NSSPECIALSYSTEMDIRECTORY_H_ + +#include "xpcomobsolete.h" +#include "nsFileSpec.h" + +#if defined(XP_MAC) || defined(XP_MACOSX) +#include +#endif + + +extern NS_COM_OBSOLETE void StartupSpecialSystemDirectory(); +extern NS_COM_OBSOLETE void ShutdownSpecialSystemDirectory(); + + +// SEE ALSO: +// mozilla/xpfe/appshell/public/nsFileLocations.h + +class NS_COM_OBSOLETE nsSpecialSystemDirectory : public nsFileSpec +{ + + public: + enum SystemDirectories + { + OS_DriveDirectory = 1 + , OS_TemporaryDirectory = 2 + , OS_CurrentProcessDirectory= 3 + , OS_CurrentWorkingDirectory= 4 + + , XPCOM_CurrentProcessComponentDirectory= 5 + , XPCOM_CurrentProcessComponentRegistry= 6 + + , Moz_BinDirectory = 10 + + , Mac_SystemDirectory = 101 + , Mac_DesktopDirectory = 102 + , Mac_TrashDirectory = 103 + , Mac_StartupDirectory = 104 + , Mac_ShutdownDirectory = 105 + , Mac_AppleMenuDirectory = 106 + , Mac_ControlPanelDirectory = 107 + , Mac_ExtensionDirectory = 108 + , Mac_FontsDirectory = 109 + , Mac_ClassicPreferencesDirectory = 110 + , Mac_DocumentsDirectory = 111 + , Mac_InternetSearchDirectory = 112 + , Mac_DefaultDownloadDirectory = 113 + , Mac_UserLibDirectory = 114 + , Mac_PreferencesDirectory = 115 + + , Win_SystemDirectory = 201 + , Win_WindowsDirectory = 202 + + , Win_HomeDirectory = 203 + , Win_Desktop = 204 + , Win_Programs = 205 + , Win_Controls = 206 + , Win_Printers = 207 + , Win_Personal = 208 + , Win_Favorites = 209 + , Win_Startup = 210 + , Win_Recent = 211 + , Win_Sendto = 212 + , Win_Bitbucket = 213 + , Win_Startmenu = 214 + , Win_Desktopdirectory = 215 + , Win_Drives = 216 + , Win_Network = 217 + , Win_Nethood = 218 + , Win_Fonts = 219 + , Win_Templates = 220 + , Win_Common_Startmenu = 221 + , Win_Common_Programs = 222 + , Win_Common_Startup = 223 + , Win_Common_Desktopdirectory = 224 + , Win_Appdata = 225 + , Win_Printhood = 226 + , Win_Cookies = 227 + + , Unix_LocalDirectory = 301 + , Unix_LibDirectory = 302 + , Unix_HomeDirectory = 303 + + , BeOS_SettingsDirectory = 401 + , BeOS_HomeDirectory = 402 + , BeOS_DesktopDirectory = 403 + , BeOS_SystemDirectory = 404 + + , OS2_SystemDirectory = 501 + , OS2_OS2Directory = 502 + , OS2_DesktopDirectory = 503 + , OS2_HomeDirectory = 504 + }; + + //nsSpecialSystemDirectory(); + nsSpecialSystemDirectory(SystemDirectories aSystemSystemDirectory); + + virtual ~nsSpecialSystemDirectory(); + + void operator = (SystemDirectories aSystemSystemDirectory); + +#if defined(XP_MAC) || defined(XP_MACOSX) + void operator = (OSType folderType); + nsSpecialSystemDirectory(OSType folderType); + enum { + kDefaultDownloadFolderType = FOUR_CHAR_CODE('DfDÄ') /* Default Download Folder */ + }; +#endif + + /** + + * @param: dirToSet, the value to set for this safeLocation + + * @param: dirSpec, the directory specified as a filespec + + */ + + static void Set(SystemDirectories dirToSet, nsFileSpec *dirSpec); + + +private: + void operator = (const char* inPath) { *(nsFileSpec*)this = inPath; } + +}; // class NS_COM_OBSOLETE nsSpecialSystemDirectory + + +#endif diff --git a/src/libs/xpcom18a4/xpcom/obsolete/nsXPCOMObsolete.cpp b/src/libs/xpcom18a4/xpcom/obsolete/nsXPCOMObsolete.cpp new file mode 100644 index 00000000..45391c0f --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/obsolete/nsXPCOMObsolete.cpp @@ -0,0 +1,54 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsXPCOM.h" +#include "nsIGenericFactory.h" + +#include "nsFileSpecImpl.h" + +#define COMPONENT(NAME, Ctor) \ + { NS_##NAME##_CLASSNAME, NS_##NAME##_CID, NS_##NAME##_CONTRACTID, Ctor } + + +static const nsModuleComponentInfo components[] = +{ + COMPONENT(FILESPEC, nsFileSpecImpl::Create), + COMPONENT(DIRECTORYITERATOR, nsDirectoryIteratorImpl::Create), +}; + +NS_IMPL_NSGETMODULE(xpcomObsoleteModule, components) + diff --git a/src/libs/xpcom18a4/xpcom/obsolete/xpcomobsolete.h b/src/libs/xpcom18a4/xpcom/obsolete/xpcomobsolete.h new file mode 100644 index 00000000..13914115 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/obsolete/xpcomobsolete.h @@ -0,0 +1,50 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* ***** 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 IBM Corporation. + * Portions created by IBM Corporation are Copyright (C) 2003 + * IBM Corporation. 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 ***** */ + +#ifndef xpcomobsolete_h___ +#define xpcomobsolete_h___ + +#include "nscore.h" + +#ifdef _IMPL_NS_COM_OBSOLETE +#define NS_COM_OBSOLETE NS_EXPORT +#else +#define NS_COM_OBSOLETE NS_IMPORT +#endif + +#endif /* !defined(xpcomobsolete_h___) */ diff --git a/src/libs/xpcom18a4/xpcom/obsolete/xpcomobsolete.pkg b/src/libs/xpcom18a4/xpcom/obsolete/xpcomobsolete.pkg new file mode 100644 index 00000000..d44a8939 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/obsolete/xpcomobsolete.pkg @@ -0,0 +1,7 @@ +[gecko xpi-bootstrap] +#if SHARED_LIBRARY +dist/bin/@SHARED_LIBRARY@ +#endif + +[gecko] +!xpt dist/bin/components/xpcom_obsolete.xpt diff --git a/src/libs/xpcom18a4/xpcom/proxy/.cvsignore b/src/libs/xpcom18a4/xpcom/proxy/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/proxy/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/xpcom/proxy/Makefile.in b/src/libs/xpcom18a4/xpcom/proxy/Makefile.in new file mode 100644 index 00000000..c30f214f --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/proxy/Makefile.in @@ -0,0 +1,49 @@ +# +# ***** 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.org Code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of 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 ***** + +DEPTH = ../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = xpcom +DIRS = public src + +include $(topsrcdir)/config/rules.mk + diff --git a/src/libs/xpcom18a4/xpcom/proxy/public/.cvsignore b/src/libs/xpcom18a4/xpcom/proxy/public/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/proxy/public/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/xpcom/proxy/public/Makefile.in b/src/libs/xpcom18a4/xpcom/proxy/public/Makefile.in new file mode 100644 index 00000000..d6950b9a --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/proxy/public/Makefile.in @@ -0,0 +1,63 @@ +# +# ***** 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.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of 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 ***** + +DEPTH = ../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = xpcom +ifeq ($(OS_ARCH),WINNT) +XPIDL_MODULE = proxyObject +else +XPIDL_MODULE = proxyObjInst +endif + +EXPORTS = \ + nsProxyEvent.h \ + nsProxyRelease.h \ + nsProxiedService.h \ + $(NULL) + +XPIDLSRCS = nsIProxyCreateInstance.idl \ + nsIProxyObjectManager.idl \ + $(NULL) + +include $(topsrcdir)/config/rules.mk + diff --git a/src/libs/xpcom18a4/xpcom/proxy/public/nsIProxyCreateInstance.idl b/src/libs/xpcom18a4/xpcom/proxy/public/nsIProxyCreateInstance.idl new file mode 100644 index 00000000..cd576f7b --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/proxy/public/nsIProxyCreateInstance.idl @@ -0,0 +1,53 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsISupports.idl" + +[scriptable, uuid(948c2080-0398-11d3-915e-0000863011c4)] +interface nsIProxyCreateInstance : nsISupports +{ + [noscript] void CreateInstanceByIID(in nsIIDRef cid, + in nsISupports aOuter, + in nsIIDRef iid, + out voidPtr result); + + [noscript] void CreateInstanceByContractID(in string aContractID, + in nsISupports aOuter, + in nsIIDRef iid, + out voidPtr result); +}; + diff --git a/src/libs/xpcom18a4/xpcom/proxy/public/nsIProxyObjectManager.idl b/src/libs/xpcom18a4/xpcom/proxy/public/nsIProxyObjectManager.idl new file mode 100644 index 00000000..5b2cfd4d --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/proxy/public/nsIProxyObjectManager.idl @@ -0,0 +1,87 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Doug Turner (Original Author) + * Dan Mosedale + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsISupports.idl" +interface nsIEventQueue; + +[scriptable, uuid(eea90d43-b059-11d2-915e-c12b696c9333)] +interface nsIProxyObjectManager : nsISupports +{ + void getProxyForObject(in nsIEventQueue destQueue, + in nsIIDRef iid, + in nsISupports object, + in PRInt32 proxyType, + [iid_is(iid),retval] out nsQIResult result); + + void getProxy(in nsIEventQueue destQueue, + in nsIIDRef cid, + in nsISupports aOuter, + in nsIIDRef iid, + in PRInt32 proxyType, + [iid_is(iid),retval] out nsQIResult result); + +}; + + +%{C++ +#include "nsProxyEvent.h" + +#define NS_XPCOMPROXY_CONTRACTID "@mozilla.org/xpcomproxy;1" +#define NS_XPCOMPROXY_CLASSNAME "XPCom Proxy" + +#define NS_PROXYEVENT_MANAGER_CID \ +{ 0xeea90d41, \ + 0xb059, \ + 0x11d2, \ + {0x91, 0x5e, 0xc1, 0x2b, 0x69, 0x6c, 0x93, 0x33}\ +} + +/** + * Helper function for code that already has a link-time dependency on + * libxpcom and needs to get proxies in a bunch of different places. + * This way, the caller isn't forced to get the proxy object manager + * themselves every single time, thus making the calling code more + * readable. + */ +extern NS_COM nsresult +NS_GetProxyForObject(nsIEventQueue *destQueue, + REFNSIID aIID, + nsISupports* aObj, + PRInt32 proxyType, + void** aProxyObject); +%} diff --git a/src/libs/xpcom18a4/xpcom/proxy/public/nsProxiedService.h b/src/libs/xpcom18a4/xpcom/proxy/public/nsProxiedService.h new file mode 100644 index 00000000..3a39ade1 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/proxy/public/nsProxiedService.h @@ -0,0 +1,164 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Pierre Phaneuf + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +#ifndef __nsProxiedServiceManager_h_ +#define __nsProxiedServiceManager_h_ + +#include "nsIServiceManager.h" +#include "nsIProxyObjectManager.h" + +//////////////////////////////////////////////////////////////////////////////// +// NS_WITH_PROXIED_SERVICE: macro to make using services that need to be proxied +// before using them easier. +// Now you can replace this: +// { +// nsresult rv; +// nsCOMPtr pIMyService = +// do_GetService(kMyServiceCID, &rv); +// if(NS_FAILED(rv)) +// return; +// nsCOMPtr pIProxyObjectManager = +// do_GetService(kProxyObjectManagerCID, &rv); +// if(NS_FAILED(rv)) +// return; +// nsIMyService pIProxiedObject = NULL; +// rv = pIProxyObjectManager->GetProxyForObject(pIProxyQueue, +// NS_GET_IID(nsIMyService), +// pIMyService, PROXY_SYNC, +// (void**)&pIProxiedObject); +// pIProxiedObject->DoIt(...); // Executed on same thread as pIProxyQueue +// ... +// pIProxiedObject->Release(); // Must be done as not managed for you. +// } +// with this: +// { +// nsresult rv; +// NS_WITH_PROXIED_SERVICE(nsIMyService, pIMyService, kMyServiceCID, +// pIProxyQueue, &rv); +// if(NS_FAILED(rv)) +// return; +// pIMyService->DoIt(...); // Executed on the same thread as pIProxyQueue +// } +// and the automatic destructor will take care of releasing the service and +// the proxied object for you. +// +// Note that this macro requires you to link with the xpcom DLL to pick up the +// static member functions from nsServiceManager. + +#define NS_WITH_PROXIED_SERVICE(T, var, cid, Q, rvAddr) \ + nsProxiedService _serv##var(cid, NS_GET_IID(T), Q, PR_FALSE, rvAddr); \ + T* var = (T*)(nsISupports*)_serv##var; + +#define NS_WITH_ALWAYS_PROXIED_SERVICE(T, var, cid, Q, rvAddr) \ + nsProxiedService _serv##var(cid, NS_GET_IID(T), Q, PR_TRUE, rvAddr); \ + T* var = (T*)(nsISupports*)_serv##var; + +//////////////////////////////////////////////////////////////////////////////// +// nsProxiedService +//////////////////////////////////////////////////////////////////////////////// + +class nsProxiedService +{ + public: + + nsProxiedService(const nsCID &aClass, const nsIID &aIID, + nsIEventQueue* pIProxyQueue, PRBool always, nsresult*rv) + { + *rv = nsServiceManager::GetService(aClass, + aIID, + getter_AddRefs(mService)); + if (NS_FAILED(*rv)) return; + InitProxy(aIID, pIProxyQueue, always, rv); + } + + nsProxiedService(const char* aContractID, const nsIID &aIID, + nsIEventQueue* pIProxyQueue, PRBool always, nsresult*rv) + { + *rv = nsServiceManager::GetService(aContractID, + aIID, + getter_AddRefs(mService)); + if (NS_FAILED(*rv)) return; + InitProxy(aIID, pIProxyQueue, always, rv); + } + + void InitProxy(const nsIID &aIID, nsIEventQueue* pIProxyQueue, + PRBool always, nsresult*rv) + { + static NS_DEFINE_CID(kProxyObjectManagerCID, NS_PROXYEVENT_MANAGER_CID); + + nsCOMPtr pIProxyObjectManager = + do_GetService(kProxyObjectManagerCID, rv); + if (NS_FAILED(*rv)) return; + + PRInt32 proxyType = PROXY_SYNC; + if (always) proxyType |= PROXY_ALWAYS; + *rv = pIProxyObjectManager->GetProxyForObject(pIProxyQueue, + aIID, + mService, + proxyType, + getter_AddRefs(mProxiedService)); + } + + ~nsProxiedService() + { + } + + nsISupports* operator->() const + { + NS_PRECONDITION(mProxiedService != 0, "Your code should test the error result from the constructor."); + return mProxiedService; + } + + PRBool operator==(const nsISupports* other) + { + return ((mProxiedService == other) || (mService == other)); + } + + operator nsISupports*() const + { + return mProxiedService; + } + + protected: + nsCOMPtr mProxiedService; + nsCOMPtr mService; + + }; + + +#endif //__nsProxiedServiceManager_h_ diff --git a/src/libs/xpcom18a4/xpcom/proxy/public/nsProxyEvent.h b/src/libs/xpcom18a4/xpcom/proxy/public/nsProxyEvent.h new file mode 100644 index 00000000..c718bbdb --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/proxy/public/nsProxyEvent.h @@ -0,0 +1,183 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +#ifndef __nsProxyEvent_h_ +#define __nsProxyEvent_h_ + +#include "nsCOMPtr.h" +#include "nsAutoPtr.h" +#include "nscore.h" +#include "nsISupports.h" +#include "nsIFactory.h" + +#include "nsIEventQueueService.h" +#include "nsIEventQueue.h" +#include "plevent.h" +#include "prtypes.h" +#include "xptcall.h" +#include "xptinfo.h" + +class nsProxyObjectCallInfo; + +#define PROXY_SYNC 0x0001 // acts just like a function call. +#define PROXY_ASYNC 0x0002 // fire and forget. This will return immediately and you will lose all return information. +#define PROXY_ALWAYS 0x0004 // ignore check to see if the eventQ is on the same thread as the caller, and alway return a proxied object. + +//#define AUTOPROXIFICATION + +// WARNING about PROXY_ASYNC: +// +// If the calling thread goes away, any function which accesses the calling stack +// will blow up. +// +// example: +// +// myFoo->bar(&x) +// +// ... thread goes away ... +// +// bar(PRInt32 *x) +// { +// *x = 0; <----- You will blow up here. +// +// +// So what gets saved? +// +// You can safely pass base types by value. You can also pass interface pointers. +// I will make sure that the interface pointers are addrefed while they are being +// proxied. You can also pass string and wstring. These I will copy and free. +// +// I do **NOT** copy arrays or strings with size. If you are using these either +// change your interface, or contact me about this feature request. + + + + +class nsProxyObject +{ +public: + nsProxyObject(nsIEventQueue *destQueue, PRInt32 proxyType, nsISupports *realObject); + nsProxyObject(nsIEventQueue *destQueue, PRInt32 proxyType, const nsCID &aClass, nsISupports *aDelegate, const nsIID &aIID); + + void AddRef(); + void Release(); + + ~nsProxyObject(); + + nsresult Post( PRUint32 methodIndex, + nsXPTMethodInfo * info, + nsXPTCMiniVariant * params, + nsIInterfaceInfo * interfaceInfo); + + nsresult PostAndWait(nsProxyObjectCallInfo *proxyInfo); + nsISupports* GetRealObject() const { return mRealObject; } + nsIEventQueue* GetQueue() const { return mDestQueue; } + PRInt32 GetProxyType() const { return mProxyType; } + + friend class nsProxyEventObject; +private: + + nsAutoRefCnt mRefCnt; + + PRInt32 mProxyType; + + nsCOMPtr mDestQueue; /* destination queue */ + + nsCOMPtr mRealObject; /* the non-proxy object that this event is referring to. + This is a strong ref. */ + nsCOMPtr mEventQService; + + nsresult convertMiniVariantToVariant(nsXPTMethodInfo * methodInfo, + nsXPTCMiniVariant * params, + nsXPTCVariant **fullParam, + uint8 *paramCount); + +}; + + +class nsProxyObjectCallInfo +{ +public: + + nsProxyObjectCallInfo(nsProxyObject* owner, + nsXPTMethodInfo *methodInfo, + PRUint32 methodIndex, + nsXPTCVariant* parameterList, + PRUint32 parameterCount, + PLEvent *event); + + ~nsProxyObjectCallInfo(); + + PRUint32 GetMethodIndex() const { return mMethodIndex; } + nsXPTCVariant* GetParameterList() const { return mParameterList; } + PRUint32 GetParameterCount() const { return mParameterCount; } + PLEvent* GetPLEvent() const { return mEvent; } + nsresult GetResult() const { return mResult; } + nsProxyObject* GetProxyObject() const { return mOwner; } + + PRBool GetCompleted(); + void SetCompleted(); + void PostCompleted(); + + void SetResult(nsresult rv) {mResult = rv; } + + nsIEventQueue* GetCallersQueue(); + void SetCallersQueue(nsIEventQueue* queue); + +private: + + nsresult mResult; /* this is the return result of the called function */ + nsXPTMethodInfo *mMethodInfo; + PRUint32 mMethodIndex; /* which method to be called? */ + nsXPTCVariant *mParameterList; /* marshalled in parameter buffer */ + PRUint32 mParameterCount; /* number of params */ + PLEvent *mEvent; /* the current plevent */ + PRInt32 mCompleted; /* is true when the method has been called. */ + + nsCOMPtr mCallersEventQ; /* this is the eventQ that we must post a message back to + when we are done invoking the method (only PROXY_SYNC). + */ + + nsRefPtr mOwner; /* this is the strong referenced nsProxyObject */ + + void RefCountInInterfacePointers(PRBool addRef); + void CopyStrings(PRBool copy); + +}; + + +#endif diff --git a/src/libs/xpcom18a4/xpcom/proxy/public/nsProxyRelease.h b/src/libs/xpcom18a4/xpcom/proxy/public/nsProxyRelease.h new file mode 100644 index 00000000..413a3d0e --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/proxy/public/nsProxyRelease.h @@ -0,0 +1,112 @@ +/* -*- Mode: C++; tab-width: 3; indent-tabs-mode: nil; c-basic-offset: 3 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +#ifndef nsProxyRelease_h__ +#define nsProxyRelease_h__ + +#include "nsIEventQueueService.h" +#include "pratom.h" +#include "prmem.h" + +/** + * Ensures that the delete of a nsISupports object occurs on the target thread. + * + * @param target + * the target thread where the doomed object should be released. + * @param doomed + * the doomed object; the object to be released on the target thread. + * @param alwaysProxy + * normally, if NS_ProxyRelease is called on the target thread, then the + * doomed object will released directly. however, if this parameter is + * true, then a PLEvent will always be posted to the target thread and + * the release will happen when that PLEvent is handled. + */ +NS_COM nsresult NS_ProxyRelease + (nsIEventTarget *target, nsISupports *doomed, PRBool alwaysProxy=PR_FALSE); + + +#define NS_IMPL_PROXY_RELEASE(_class) \ +NS_IMETHODIMP_(nsrefcnt) _class::Release(void) \ +{ \ + NS_PRECONDITION(0 != mRefCnt, "dup release"); \ + nsrefcnt count = PR_AtomicDecrement((PRInt32 *)&mRefCnt); \ + NS_LOG_RELEASE(this, count, #_class); \ + \ + if (count == 0) \ + { \ + mRefCnt = 1; /* stabilize */ \ + PRBool callDirectly = PR_TRUE; \ + static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID); \ + nsCOMPtr eventQService \ + = do_GetService(kEventQueueServiceCID); \ + NS_ASSERTION(eventQService, "event queue service is unavailable"); \ + \ + nsCOMPtr eventQ; \ + if (eventQService) { \ + eventQService->GetThreadEventQueue(NS_UI_THREAD, getter_AddRefs(eventQ)); \ + if (eventQ) \ + eventQ->IsOnCurrentThread(&callDirectly); \ + } \ + \ + if (callDirectly) \ + { \ + NS_RELEASE(this); \ + return 0; \ + } \ + PLEvent *event = new PLEvent; \ + if (event == nsnull) \ + { \ + NS_ASSERTION(0, "Could not create a plevent. Deleting on wrong thread!"); \ + NS_DELETEXPCOM(this); \ + return 0; \ + } \ + \ + PL_InitEvent(event, \ + NS_STATIC_CAST(nsISupports*, this), \ + ReleaseDestructorEventHandler, \ + ReleaseDestructorDestroyHandler); \ + \ + eventQ->PostEvent(event); \ + return 0; \ + } \ + return count; \ +} \ + + + + +#endif diff --git a/src/libs/xpcom18a4/xpcom/proxy/src/.cvsignore b/src/libs/xpcom18a4/xpcom/proxy/src/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/proxy/src/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/xpcom/proxy/src/Makefile.in b/src/libs/xpcom18a4/xpcom/proxy/src/Makefile.in new file mode 100644 index 00000000..3d46f60b --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/proxy/src/Makefile.in @@ -0,0 +1,67 @@ +# +# ***** 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.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of 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 ***** + +DEPTH = ../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = xpcom +LIBRARY_NAME = xpcomproxy_s +REQUIRES = string \ + $(NULL) + + +CPPSRCS = \ + nsProxyEvent.cpp \ + nsProxyEventClass.cpp \ + nsProxyEventObject.cpp \ + nsProxyObjectManager.cpp \ + nsProxyRelease.cpp \ + $(NULL) + +DEFINES += -D_IMPL_NS_COM -DEXPORT_XPTC_API -DEXPORT_XPTI_API + +# No shared lib; Force creation of static lib +FORCE_STATIC_LIB = 1 + +# Force use of PIC +FORCE_USE_PIC = 1 + +include $(topsrcdir)/config/rules.mk diff --git a/src/libs/xpcom18a4/xpcom/proxy/src/nsIProxyCreateInstance.h b/src/libs/xpcom18a4/xpcom/proxy/src/nsIProxyCreateInstance.h new file mode 100644 index 00000000..13755d74 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/proxy/src/nsIProxyCreateInstance.h @@ -0,0 +1,39 @@ +/* + * DO NOT EDIT. THIS FILE IS GENERATED FROM nsIProxyCreateInstance.idl + */ + +#ifndef __gen_nsIProxyCreateInstance_h__ +#define __gen_nsIProxyCreateInstance_h__ + +#include "nsISupports.h" /* interface nsISupports */ +#include "nsrootidl.h" /* interface nsrootidl */ + +#ifdef XPIDL_JS_STUBS +#include "jsapi.h" +#endif + +/* starting interface: nsIProxyCreateInstance */ + +/* {948c2080-0398-11d3-915e-0000863011c4} */ +#define NS_IPROXYCREATEINSTANCE_IID_STR "948c2080-0398-11d3-915e-0000863011c4" +#define NS_IPROXYCREATEINSTANCE_IID \ + {0x948c2080, 0x0398, 0x11d3, \ + { 0x91, 0x5e, 0x00, 0x00, 0x86, 0x30, 0x11, 0xc4 }} + +class nsIProxyCreateInstance : public nsISupports { + public: + NS_DEFINE_STATIC_IID_ACCESSOR(NS_IPROXYCREATEINSTANCE_IID) + + /* void CreateInstanceByIID (in nsIIDRef cid, in nsISupports aOuter, in nsIIDRef iid, out voidStar result); */ + NS_IMETHOD CreateInstanceByIID(const nsIID & cid, nsISupports *aOuter, const nsIID & iid, void * *result) = 0; + + /* void CreateInstanceByContractID (in string aContractID, in nsISupports aOuter, in nsIIDRef iid, out voidStar result); */ + NS_IMETHOD CreateInstanceByContractID(const char *aContractID, nsISupports *aOuter, const nsIID & iid, void * *result) = 0; + +#ifdef XPIDL_JS_STUBS + static NS_EXPORT_(JSObject *) InitJSClass(JSContext *cx); + static NS_EXPORT_(JSObject *) GetJSObject(JSContext *cx, nsIProxyCreateInstance *priv); +#endif +}; + +#endif /* __gen_nsIProxyCreateInstance_h__ */ diff --git a/src/libs/xpcom18a4/xpcom/proxy/src/nsProxyEvent.cpp b/src/libs/xpcom18a4/xpcom/proxy/src/nsProxyEvent.cpp new file mode 100644 index 00000000..561c2fdb --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/proxy/src/nsProxyEvent.cpp @@ -0,0 +1,613 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** + * + * This Original Code has been modified by IBM Corporation. + * Modifications made by IBM described herein are + * Copyright (c) International Business Machines + * Corporation, 2000 + * + * Modifications to Mozilla code or documentation + * identified per MPL Section 3.3 + * + * Date Modified by Description of modification + * 04/20/2000 IBM Corp. Added PR_CALLBACK for Optlink use in OS2 + */ + +#include "nsProxyEvent.h" +#include "nsProxyEventPrivate.h" +#include "nsIProxyObjectManager.h" +#include "nsCRT.h" + +#include "pratom.h" +#include "prmem.h" +#include "xptcall.h" + +#include "nsIComponentManager.h" +#include "nsComponentManagerObsolete.h" +#include "nsIServiceManager.h" +#include "nsMemory.h" +#include "nsIEventQueueService.h" +#include "nsIThread.h" + +#include "nsIAtom.h" //hack! Need a way to define a component as threadsafe (ie. sta). + +/** + * Map the nsAUTF8String, nsUTF8String classes to the nsACString and + * nsCString classes respectively for now. These defines need to be removed + * once Jag lands his nsUTF8String implementation. + */ +#define nsAUTF8String nsACString +#define nsUTF8String nsCString + +static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID); + +static void* PR_CALLBACK EventHandler(PLEvent *self); +static void PR_CALLBACK DestroyHandler(PLEvent *self); +static void* PR_CALLBACK CompletedEventHandler(PLEvent *self); +static void PR_CALLBACK CompletedDestroyHandler(PLEvent *self) ; +static void* PR_CALLBACK ProxyDestructorEventHandler(PLEvent *self); +static void PR_CALLBACK ProxyDestructorDestroyHandler(PLEvent *self) ; + +nsProxyObjectCallInfo::nsProxyObjectCallInfo( nsProxyObject* owner, + nsXPTMethodInfo *methodInfo, + PRUint32 methodIndex, + nsXPTCVariant* parameterList, + PRUint32 parameterCount, + PLEvent *event) +{ + NS_ASSERTION(owner, "No nsProxyObject!"); + NS_ASSERTION(methodInfo, "No nsXPTMethodInfo!"); + NS_ASSERTION(event, "No PLEvent!"); + + mCompleted = 0; + mMethodIndex = methodIndex; + mParameterList = parameterList; + mParameterCount = parameterCount; + mEvent = event; + mMethodInfo = methodInfo; + mCallersEventQ = nsnull; + + mOwner = owner; + + RefCountInInterfacePointers(PR_TRUE); + if (mOwner->GetProxyType() & PROXY_ASYNC) + CopyStrings(PR_TRUE); +} + + +nsProxyObjectCallInfo::~nsProxyObjectCallInfo() +{ + RefCountInInterfacePointers(PR_FALSE); + if (mOwner->GetProxyType() & PROXY_ASYNC) + CopyStrings(PR_FALSE); + + mOwner = nsnull; + + PR_FREEIF(mEvent); + + if (mParameterList) +#ifdef VBOX_USE_IPRT_IN_XPCOM + nsMemory::Free((void*) mParameterList); +#else + free( (void*) mParameterList); +#endif +} + +void +nsProxyObjectCallInfo::RefCountInInterfacePointers(PRBool addRef) +{ + for (PRUint32 i = 0; i < mParameterCount; i++) + { + nsXPTParamInfo paramInfo = mMethodInfo->GetParam(i); + + if (paramInfo.GetType().IsInterfacePointer() ) + { + nsISupports* anInterface = nsnull; + + if (paramInfo.IsIn()) + { + anInterface = ((nsISupports*)mParameterList[i].val.p); + + if (anInterface) + { + if(addRef) + anInterface->AddRef(); + else + anInterface->Release(); + + } + } + } + } +} + +void +nsProxyObjectCallInfo::CopyStrings(PRBool copy) +{ + for (PRUint32 i = 0; i < mParameterCount; i++) + { + const nsXPTParamInfo paramInfo = mMethodInfo->GetParam(i); + + if(paramInfo.IsIn()) + { + const nsXPTType& type = paramInfo.GetType(); + uint8 type_tag = type.TagPart(); + void *ptr = mParameterList[i].val.p; + + if (!ptr) + continue; + + if (copy) + { + switch (type_tag) + { + case nsXPTType::T_CHAR_STR: + mParameterList[i].val.p = + PL_strdup((const char *)ptr); + break; + case nsXPTType::T_WCHAR_STR: + mParameterList[i].val.p = + nsCRT::strdup((const PRUnichar *)ptr); + break; + case nsXPTType::T_DOMSTRING: + case nsXPTType::T_ASTRING: + mParameterList[i].val.p = + new nsString(*((nsAString*) ptr)); + break; + case nsXPTType::T_CSTRING: + mParameterList[i].val.p = + new nsCString(*((nsACString*) ptr)); + break; + case nsXPTType::T_UTF8STRING: + mParameterList[i].val.p = + new nsUTF8String(*((nsAUTF8String*) ptr)); + break; + default: + // Other types are ignored + break; + } + } + else + { + switch (type_tag) + { + case nsXPTType::T_CHAR_STR: + case nsXPTType::T_WCHAR_STR: + PL_strfree((char*) ptr); + break; + case nsXPTType::T_DOMSTRING: + case nsXPTType::T_ASTRING: + delete (nsString*) ptr; + break; + case nsXPTType::T_CSTRING: + delete (nsCString*) ptr; + break; + case nsXPTType::T_UTF8STRING: + delete (nsUTF8String*) ptr; + break; + default: + // Other types are ignored + break; + } + } + } + } +} + +PRBool +nsProxyObjectCallInfo::GetCompleted() +{ + return (PRBool)mCompleted; +} + +void +nsProxyObjectCallInfo::SetCompleted() +{ + PR_AtomicSet(&mCompleted, 1); +} + +void +nsProxyObjectCallInfo::PostCompleted() +{ + if (mCallersEventQ) + { + PLEvent *event = PR_NEW(PLEvent); + + PL_InitEvent(event, + this, + CompletedEventHandler, + CompletedDestroyHandler); + + mCallersEventQ->PostSynchronousEvent(event, nsnull); + PR_FREEIF(event); + } + else + { + // caller does not have an eventQ? This is an error! + SetCompleted(); + } +} + +nsIEventQueue* +nsProxyObjectCallInfo::GetCallersQueue() +{ + return mCallersEventQ; +} +void +nsProxyObjectCallInfo::SetCallersQueue(nsIEventQueue* queue) +{ + mCallersEventQ = queue; +} + + +nsProxyObject::nsProxyObject(nsIEventQueue *destQueue, PRInt32 proxyType, nsISupports *realObject) +{ + mEventQService = do_GetService(kEventQueueServiceCID); + + mRealObject = realObject; + mDestQueue = do_QueryInterface(destQueue); + mProxyType = proxyType; +} + + +nsProxyObject::nsProxyObject(nsIEventQueue *destQueue, PRInt32 proxyType, const nsCID &aClass, nsISupports *aDelegate, const nsIID &aIID) +{ + mEventQService = do_GetService(kEventQueueServiceCID); + + nsComponentManager::CreateInstance(aClass, + aDelegate, + aIID, + getter_AddRefs(mRealObject)); + + mDestQueue = do_QueryInterface(destQueue); + mProxyType = proxyType; +} + +nsProxyObject::~nsProxyObject() +{ + // I am worried about order of destruction here. + // do not remove assignments. + + mRealObject = 0; + mDestQueue = 0; +} + + +void +nsProxyObject::AddRef() +{ + PR_AtomicIncrement((PRInt32 *)&mRefCnt); + NS_LOG_ADDREF(this, mRefCnt, "nsProxyObject", sizeof(*this)); +} + +void +nsProxyObject::Release(void) +{ + NS_PRECONDITION(0 != mRefCnt, "dup release"); + + nsrefcnt count = PR_AtomicDecrement((PRInt32 *)&mRefCnt); + NS_LOG_RELEASE(this, count, "nsProxyObject"); + + if (count == 0) + { + mRefCnt = 1; /* stabilize */ + + PRBool callDirectly; + mDestQueue->IsOnCurrentThread(&callDirectly); + + if (callDirectly) + { + delete this; + return; + } + + // need to do something special here so that + // the real object will always be deleted on + // the correct thread.. + + PLEvent *event = PR_NEW(PLEvent); + if (event == nsnull) + { + NS_ASSERTION(0, "Could not create a plevent. Leaking nsProxyObject!"); + return; // if this happens we are going to leak. + } + + PL_InitEvent(event, + this, + ProxyDestructorEventHandler, + ProxyDestructorDestroyHandler); + + mDestQueue->PostEvent(event); + } +} + + +nsresult +nsProxyObject::PostAndWait(nsProxyObjectCallInfo *proxyInfo) +{ + if (proxyInfo == nsnull || mEventQService == nsnull) + return NS_ERROR_NULL_POINTER; + + PRBool eventLoopCreated = PR_FALSE; + nsresult rv; + + nsCOMPtr eventQ; + rv = mEventQService->GetThreadEventQueue(NS_CURRENT_THREAD, getter_AddRefs(eventQ)); + if (NS_FAILED(rv)) + { + rv = mEventQService->CreateMonitoredThreadEventQueue(); + eventLoopCreated = PR_TRUE; + if (NS_FAILED(rv)) + return rv; + + rv = mEventQService->GetThreadEventQueue(NS_CURRENT_THREAD, getter_AddRefs(eventQ)); + } + + if (NS_FAILED(rv)) + return rv; + + proxyInfo->SetCallersQueue(eventQ); + + PLEvent* event = proxyInfo->GetPLEvent(); + if (!event) + return NS_ERROR_NULL_POINTER; + + mDestQueue->PostEvent(event); + + while (! proxyInfo->GetCompleted()) + { + PLEvent *nextEvent; + rv = eventQ->WaitForEvent(&nextEvent); + if (NS_FAILED(rv)) break; + + eventQ->HandleEvent(nextEvent); + } + + if (eventLoopCreated) + { + mEventQService->DestroyThreadEventQueue(); + eventQ = 0; + } + + return rv; +} + + +nsresult +nsProxyObject::convertMiniVariantToVariant(nsXPTMethodInfo *methodInfo, + nsXPTCMiniVariant * params, + nsXPTCVariant **fullParam, + uint8 *outParamCount) +{ + uint8 paramCount = methodInfo->GetParamCount(); + *outParamCount = paramCount; + *fullParam = nsnull; + + if (!paramCount) return NS_OK; + +#ifdef VBOX_USE_IPRT_IN_XPCOM + *fullParam = (nsXPTCVariant*)nsMemory::Alloc(sizeof(nsXPTCVariant) * paramCount); +#else + *fullParam = (nsXPTCVariant*)malloc(sizeof(nsXPTCVariant) * paramCount); +#endif + + if (*fullParam == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + + for (int i = 0; i < paramCount; i++) + { + const nsXPTParamInfo& paramInfo = methodInfo->GetParam(i); + if ((mProxyType & PROXY_ASYNC) && paramInfo.IsDipper()) + { + NS_WARNING("Async proxying of out parameters is not supported"); + return NS_ERROR_PROXY_INVALID_OUT_PARAMETER; + } + uint8 flags = paramInfo.IsOut() ? nsXPTCVariant::PTR_IS_DATA : 0; + (*fullParam)[i].Init(params[i], paramInfo.GetType(), flags); + } + + return NS_OK; +} + +nsresult +nsProxyObject::Post( PRUint32 methodIndex, + nsXPTMethodInfo *methodInfo, + nsXPTCMiniVariant * params, + nsIInterfaceInfo *interfaceInfo) +{ + nsresult rv = NS_OK; + + if (! mDestQueue || ! mRealObject) + return NS_ERROR_OUT_OF_MEMORY; + + if (methodInfo->IsNotXPCOM()) + return NS_ERROR_PROXY_INVALID_IN_PARAMETER; + + nsXPTCVariant *fullParam; + uint8 paramCount; + rv = convertMiniVariantToVariant(methodInfo, params, &fullParam, ¶mCount); + + if (NS_FAILED(rv)) + return rv; + + PRBool callDirectly; + + // see if we should call into the method directly. Either it is a QI function call + // (methodIndex == 0), or it is a sync proxy and this code is running on the same thread + // as the destination event queue. + if ( (methodIndex == 0) || + (mProxyType & PROXY_SYNC && + NS_SUCCEEDED(mDestQueue->IsOnCurrentThread(&callDirectly)) && + callDirectly)) + { + + // invoke the magic of xptc... + nsresult rv = XPTC_InvokeByIndex( mRealObject, + methodIndex, + paramCount, + fullParam); + + if (fullParam) +#ifdef VBOX_USE_IPRT_IN_XPCOM + nsMemory::Free(fullParam); +#else + free(fullParam); +#endif + return rv; + } + + PLEvent *event = PR_NEW(PLEvent); + + if (event == nsnull) { + if (fullParam) +#ifdef VBOX_USE_IPRT_IN_XPCOM + nsMemory::Free(fullParam); +#else + free(fullParam); +#endif + return NS_ERROR_OUT_OF_MEMORY; + } + + nsProxyObjectCallInfo *proxyInfo = new nsProxyObjectCallInfo(this, + methodInfo, + methodIndex, + fullParam, // will be deleted by ~() + paramCount, + event); // will be deleted by ~() + + if (proxyInfo == nsnull) { + PR_DELETE(event); + if (fullParam) +#ifdef VBOX_USE_IPRT_IN_XPCOM + nsMemory::Free(fullParam); +#else + free(fullParam); +#endif + return NS_ERROR_OUT_OF_MEMORY; + } + + PL_InitEvent(event, + proxyInfo, + EventHandler, + DestroyHandler); + + if (mProxyType & PROXY_SYNC) + { + rv = PostAndWait(proxyInfo); + + if (NS_SUCCEEDED(rv)) + rv = proxyInfo->GetResult(); + delete proxyInfo; + return rv; + } + + if (mProxyType & PROXY_ASYNC) + { + mDestQueue->PostEvent(event); + return NS_OK; + } + return NS_ERROR_UNEXPECTED; +} + + + +static void DestroyHandler(PLEvent *self) +{ + nsProxyObjectCallInfo* owner = (nsProxyObjectCallInfo*)PL_GetEventOwner(self); + nsProxyObject* proxyObject = owner->GetProxyObject(); + + if (proxyObject == nsnull) + return; + + if (proxyObject->GetProxyType() & PROXY_ASYNC) + { + delete owner; + } + else + { + owner->PostCompleted(); + } + +} + +static void* EventHandler(PLEvent *self) +{ + nsProxyObjectCallInfo *info = (nsProxyObjectCallInfo*)PL_GetEventOwner(self); + NS_ASSERTION(info, "No nsProxyObjectCallInfo!"); + + nsProxyObject *proxyObject = info->GetProxyObject(); + + if (proxyObject) + { + // invoke the magic of xptc... + nsresult rv = XPTC_InvokeByIndex( proxyObject->GetRealObject(), + info->GetMethodIndex(), + info->GetParameterCount(), + info->GetParameterList()); + info->SetResult(rv); + } + else + { + info->SetResult(NS_ERROR_OUT_OF_MEMORY); + } + return NULL; +} + +static void CompletedDestroyHandler(PLEvent *self) +{ +} + +static void* CompletedEventHandler(PLEvent *self) +{ + nsProxyObjectCallInfo* owner = (nsProxyObjectCallInfo*)PL_GetEventOwner(self); + owner->SetCompleted(); + return nsnull; +} + +static void* ProxyDestructorEventHandler(PLEvent *self) +{ + nsProxyObject* owner = (nsProxyObject*) PL_GetEventOwner(self); + NS_DELETEXPCOM(owner); + return nsnull; +} + +static void ProxyDestructorDestroyHandler(PLEvent *self) +{ + PR_DELETE(self); +} + diff --git a/src/libs/xpcom18a4/xpcom/proxy/src/nsProxyEventClass.cpp b/src/libs/xpcom18a4/xpcom/proxy/src/nsProxyEventClass.cpp new file mode 100644 index 00000000..8e221afa --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/proxy/src/nsProxyEventClass.cpp @@ -0,0 +1,367 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Pierre Phaneuf + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsProxyEvent.h" +#include "nsIProxyObjectManager.h" +#include "nsProxyEventPrivate.h" + +#include "nsIComponentManager.h" +#include "nsIServiceManager.h" +#include "nsCOMPtr.h" + +#include "nsMemory.h" +#include "nsHashtable.h" + +#include "nsAutoLock.h" +#include "nsIInterfaceInfoManager.h" +#include "xptcall.h" + +// LIFETIME_CACHE will cache class for the entire cyle of the application. +#define LIFETIME_CACHE + +static uint32 zero_methods_descriptor; + + +/* ssc@netscape.com wishes he could get rid of this instance of + * |NS_DEFINE_IID|, but |ProxyEventClassIdentity| is not visible from + * here. + */ +static NS_DEFINE_IID(kProxyObject_Identity_Class_IID, NS_PROXYEVENT_IDENTITY_CLASS_IID); + +////////////////////////////////////////////////////////////////////////////////////////////////// +// nsProxyEventClass +////////////////////////////////////////////////////////////////////////////////////////////////// +NS_IMPL_THREADSAFE_ISUPPORTS1(nsProxyEventClass, nsProxyEventClass) + +// static +nsProxyEventClass* +nsProxyEventClass::GetNewOrUsedClass(REFNSIID aIID) +{ + /* find in our hash table */ + + nsProxyObjectManager *manager = nsProxyObjectManager::GetInstance(); + if (manager == nsnull) return nsnull; + + // dont need to lock the map, because this is only called + // by nsProxyEventClass::GetNewOrUsed which locks it for us. + + nsHashtable *iidToClassMap = manager->GetIIDToProxyClassMap(); + + if (iidToClassMap == nsnull) + { + return nsnull; + } + + nsProxyEventClass* clazz = nsnull; + nsIDKey key(aIID); + +#ifdef PROXYEVENTCLASS_DEBUG + char* iidStr = aIID.ToString(); + printf("GetNewOrUsedClass %s\n", iidStr); + nsCRT::free(iidStr); +#endif + + clazz = (nsProxyEventClass*) iidToClassMap->Get(&key); + if(clazz) + { + NS_ADDREF(clazz); +#ifdef PROXYEVENTCLASS_DEBUG + char* iidStr = aIID.ToString(); + printf("GetNewOrUsedClass %s hit\n", iidStr); + nsCRT::free(iidStr); +#endif + } + else + { + nsCOMPtr iimgr = getter_AddRefs(XPTI_GetInterfaceInfoManager()); + if(iimgr) + { + nsCOMPtr info; + if(NS_SUCCEEDED(iimgr->GetInfoForIID(&aIID, getter_AddRefs(info)))) + { + /* + Check to see if isISupportsDescendent + */ + nsCOMPtr oldest = info; + nsCOMPtr parent; + + while(NS_SUCCEEDED(oldest->GetParent(getter_AddRefs(parent)))&& + parent) + { + oldest = parent; + } + + PRBool isISupportsDescendent = PR_FALSE; + nsID* iid; + if(NS_SUCCEEDED(oldest->GetInterfaceIID(&iid))) + { + isISupportsDescendent = iid->Equals(NS_GET_IID(nsISupports)); + nsMemory::Free(iid); + } + + NS_ASSERTION(isISupportsDescendent, "!isISupportsDescendent"); + + if (isISupportsDescendent) + { + clazz = new nsProxyEventClass(aIID, info); + if(!clazz->mDescriptors) + NS_RELEASE(clazz); // sets clazz to NULL + } + } + } + } + return clazz; +} + +nsProxyEventClass::nsProxyEventClass() +{ + NS_WARNING("This constructor should never be called"); +} + +nsProxyEventClass::nsProxyEventClass(REFNSIID aIID, nsIInterfaceInfo* aInfo) +: mIID(aIID), + mDescriptors(NULL) +{ + NS_ADDREF_THIS(); + + mInfo = aInfo; + + /* add use to the used classes */ + nsIDKey key(aIID); + + nsProxyObjectManager *manager = nsProxyObjectManager::GetInstance(); + if (manager == nsnull) return; + // dont need to lock the map, because this is only called + // by GetNewOrUsed which locks it for us. + + nsHashtable *iidToClassMap = manager->GetIIDToProxyClassMap(); + + if (iidToClassMap != nsnull) + { + iidToClassMap->Put(&key, this); +#ifdef LIFETIME_CACHE + // extra addref to hold it in the cache + NS_ADDREF_THIS(); +#endif +#ifdef PROXYEVENTCLASS_DEBUG + char* iidStr = aIID.ToString(); + printf("GetNewOrUsedClass %s put\n", iidStr); + nsCRT::free(iidStr); +#endif + } + + uint16 methodCount; + if(NS_SUCCEEDED(mInfo->GetMethodCount(&methodCount))) + { + if(methodCount) + { + int wordCount = (methodCount/32)+1; + if(NULL != (mDescriptors = new uint32[wordCount])) + { + memset(mDescriptors, 0, wordCount * sizeof(uint32)); + } + } + else + { + mDescriptors = &zero_methods_descriptor; + } + } +} + +nsProxyEventClass::~nsProxyEventClass() +{ + if(mDescriptors && mDescriptors != &zero_methods_descriptor) + delete [] mDescriptors; + + if (nsProxyObjectManager::IsManagerShutdown()) + return; + +#ifndef LIFETIME_CACHE + nsIDKey key(mIID); + + nsCOMPtr manager = getter_AddRefs(nsProxyObjectManager::GetInstance()); + if (manager == nsnull) return; + nsHashtable *iidToClassMap = manager->GetIIDToProxyClassMap(); + + if (iidToClassMap != nsnull) + { + iidToClassMap->Remove(&key); +#ifdef PROXYEVENTCLASS_DEBUG + char* iidStr = mIID.ToString(); + printf("GetNewOrUsedClass %s remove\n", iidStr); + nsCRT::free(iidStr); +#endif + } +#endif +} + +nsresult +nsProxyEventClass::CallQueryInterfaceOnProxy(nsProxyEventObject* self, REFNSIID aIID, nsProxyEventObject** aInstancePtr) +{ + NS_PRECONDITION(aInstancePtr, "Requires non-null result"); + + nsresult rv; + + *aInstancePtr = nsnull; // in case of error. + + + // The functions we will call: QueryInterface(REFNSIID aIID, void** aInstancePtr) + + nsXPTCMiniVariant var[2]; + + var[0].val.p = (void*)&aIID; + var[1].val.p = (void*)aInstancePtr; + + nsCOMPtr interfaceInfo; + const nsXPTMethodInfo *mi; + + nsCOMPtr iim = getter_AddRefs(XPTI_GetInterfaceInfoManager()); + + if (!iim) return NS_NOINTERFACE; + iim->GetInfoForName("nsISupports", getter_AddRefs(interfaceInfo)); + interfaceInfo->GetMethodInfo(0, &mi); // 0 is QueryInterface + + rv = self->CallMethod(0, mi, var); + + if (NS_SUCCEEDED(rv)) + { + nsISupports *aIdentificationObject; + + rv = (*aInstancePtr)->QueryInterface(kProxyObject_Identity_Class_IID, (void**)&aIdentificationObject); + + if (NS_FAILED(rv)) + { + // okay, aInstancePtr was not a proxy. Lets create one. + nsProxyObjectManager *manager = nsProxyObjectManager::GetInstance(); + if (manager == nsnull) + { + NS_IF_RELEASE((*aInstancePtr)); + return NS_ERROR_FAILURE; + } + + rv = manager->GetProxyForObject(self->GetQueue(), + aIID, + self->GetRealObject(), + self->GetProxyType(), + (void**) &aIdentificationObject); + } + + NS_IF_RELEASE((*aInstancePtr)); + (*aInstancePtr) = NS_STATIC_CAST(nsProxyEventObject*, aIdentificationObject); + } + return rv; +} + + +/***************************************************************************/ +// This 'ProxyEventClassIdentity' class and singleton allow us to figure out if +// any given nsISupports* is implemented by a nsProxy object. This is done +// using a QueryInterface call on the interface pointer with our ID. If +// that call returns NS_OK and the pointer is to a nsProxyEventObject. It must +// be released when done. + +// NS_PROXYEVENT_IDENTITY_CLASS_IID defined in nsProxyEventPrivate.h +class ProxyEventClassIdentity +{ + // no instance methods... +public: + NS_DEFINE_STATIC_IID_ACCESSOR(NS_PROXYEVENT_IDENTITY_CLASS_IID) + + static void* GetSingleton() + { + static ProxyEventClassIdentity* singleton = NULL; + if(!singleton) + singleton = new ProxyEventClassIdentity(); + return (void*) singleton; + } +}; + +NS_IMETHODIMP +nsProxyEventClass::DelegatedQueryInterface(nsProxyEventObject* self, + REFNSIID aIID, + void** aInstancePtr) +{ + + if(aIID.Equals(NS_GET_IID(ProxyEventClassIdentity))) + { + *aInstancePtr = NS_STATIC_CAST(void*, self); + NS_ADDREF(self); + return NS_OK; + } + + nsProxyEventObject* sibling; + { + nsProxyObjectManager* manager = nsProxyObjectManager::GetInstance(); + nsAutoMonitor mon(manager->GetMonitor()); + + // This includes checking for nsISupports and the iid of self. + // And it also checks for other wrappers that have been constructed + // for this object. + if(nsnull != (sibling = self->LockedFind(aIID))) + { + NS_ADDREF(sibling); + *aInstancePtr = (void*) sibling; + return NS_OK; + } + + // check if asking for an interface that we inherit from + nsCOMPtr current = GetInterfaceInfo(); + nsCOMPtr parent; + + while(NS_SUCCEEDED(current->GetParent(getter_AddRefs(parent))) && parent) + { + current = parent; + + nsIID* iid; + if(NS_SUCCEEDED(current->GetInterfaceIID(&iid)) && iid) + { + PRBool found = aIID.Equals(*iid); + nsMemory::Free(iid); + if(found) + { + *aInstancePtr = (void*) self; + NS_ADDREF(self); + return NS_OK; + } + } + } + } + + return CallQueryInterfaceOnProxy(self, aIID, (nsProxyEventObject**)aInstancePtr); +} diff --git a/src/libs/xpcom18a4/xpcom/proxy/src/nsProxyEventObject.cpp b/src/libs/xpcom18a4/xpcom/proxy/src/nsProxyEventObject.cpp new file mode 100644 index 00000000..d529fc05 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/proxy/src/nsProxyEventObject.cpp @@ -0,0 +1,555 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Pierre Phaneuf + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "prprf.h" +#include "prmem.h" + +#include "nscore.h" +#include "nsProxyEvent.h" +#include "nsIProxyObjectManager.h" +#include "nsProxyEventPrivate.h" + +#include "nsHashtable.h" + +#include "nsIInterfaceInfoManager.h" +#include "xptcall.h" + +#include "nsAutoLock.h" + +static NS_DEFINE_IID(kProxyObject_Identity_Class_IID, NS_PROXYEVENT_IDENTITY_CLASS_IID); + + +//////////////////////////////////////////////////////////////////////////////// + +class nsProxyEventKey : public nsHashKey +{ +public: + nsProxyEventKey(void* rootObjectKey, void* destQueueKey, PRInt32 proxyType) + : mRootObjectKey(rootObjectKey), mDestQueueKey(destQueueKey), mProxyType(proxyType) { + } + + PRUint32 HashCode(void) const { + return NS_PTR_TO_INT32(mRootObjectKey) ^ + NS_PTR_TO_INT32(mDestQueueKey) ^ mProxyType; + } + + PRBool Equals(const nsHashKey *aKey) const { + const nsProxyEventKey* other = (const nsProxyEventKey*)aKey; + return mRootObjectKey == other->mRootObjectKey + && mDestQueueKey == other->mDestQueueKey + && mProxyType == other->mProxyType; + } + + nsHashKey *Clone() const { + return new nsProxyEventKey(mRootObjectKey, mDestQueueKey, mProxyType); + } + +protected: + void* mRootObjectKey; + void* mDestQueueKey; + PRInt32 mProxyType; +}; + +//////////////////////////////////////////////////////////////////////////////// + +#ifdef DEBUG_xpcom_proxy +static PRMonitor* mon = nsnull; +static PRUint32 totalProxyObjects = 0; +static PRUint32 outstandingProxyObjects = 0; + +void +nsProxyEventObject::DebugDump(const char * message, PRUint32 hashKey) +{ + + if (mon == nsnull) + { + mon = PR_NewMonitor(); + } + + PR_EnterMonitor(mon); + + if (message) + { + printf("\n-=-=-=-=-=-=-=-=-=-=-=-=-\n"); + printf("%s\n", message); + + if(strcmp(message, "Create") == 0) + { + totalProxyObjects++; + outstandingProxyObjects++; + } + else if(strcmp(message, "Delete") == 0) + { + outstandingProxyObjects--; + } + } + printf("nsProxyEventObject @ %x with mRefCnt = %d\n", this, mRefCnt); + + PRBool isRoot = mRoot == nsnull; + printf("%s wrapper around @ %x\n", isRoot ? "ROOT":"non-root\n", GetRealObject()); + + nsCOMPtr rootObject = do_QueryInterface(mProxyObject->mRealObject); + nsCOMPtr rootQueue = do_QueryInterface(mProxyObject->mDestQueue); + nsProxyEventKey key(rootObject, rootQueue, mProxyObject->mProxyType); + printf("Hashkey: %d\n", key.HashCode()); + + char* name; + GetClass()->GetInterfaceInfo()->GetName(&name); + printf("interface name is %s\n", name); + if(name) + nsMemory::Free(name); + char * iid = GetClass()->GetProxiedIID().ToString(); + printf("IID number is %s\n", iid); + delete iid; + printf("nsProxyEventClass @ %x\n", mClass); + + if(mNext) + { + if(isRoot) + { + printf("Additional wrappers for this object...\n"); + } + mNext->DebugDump(nsnull, 0); + } + + printf("[proxyobjects] %d total used in system, %d outstading\n", totalProxyObjects, outstandingProxyObjects); + + if (message) + printf("-=-=-=-=-=-=-=-=-=-=-=-=-\n"); + + PR_ExitMonitor(mon); +} +#endif + + + +////////////////////////////////////////////////////////////////////////////////////////////////// +// +// nsProxyEventObject +// +////////////////////////////////////////////////////////////////////////////////////////////////// +nsProxyEventObject* +nsProxyEventObject::GetNewOrUsedProxy(nsIEventQueue *destQueue, + PRInt32 proxyType, + nsISupports *aObj, + REFNSIID aIID) +{ + nsresult rv; + + if (!aObj) + return nsnull; + + nsISupports* rawObject = aObj; + + // + // make sure that the object pass in is not a proxy... + // if the object *is* a proxy, then be nice and build the proxy + // for the real object... + // + nsCOMPtr identificationObject; + + rv = rawObject->QueryInterface(kProxyObject_Identity_Class_IID, + getter_AddRefs(identificationObject)); + if (NS_SUCCEEDED(rv)) { + // + // ATTENTION!!!! + // + // If you are hitting any of the assertions in this block of code, + // please contact dougt@netscape.com. + // + + // if you hit this assertion, you might want to check out how + // you are using proxies. You shouldn't need to be creating + // a proxy from a proxy. -- dougt@netscape.com + NS_ASSERTION(0, "Someone is building a proxy from a proxy"); + + NS_ASSERTION(identificationObject, "where did my identification object go!"); + if (!identificationObject) { + return nsnull; + } + + // someone is asking us to create a proxy for a proxy. Lets get + // the real object and build aproxy for that! + rawObject = identificationObject->GetRealObject(); + + NS_ASSERTION(rawObject, "where did my real object go!"); + if (!rawObject) { + return nsnull; + } + } + + // + // Get the root nsISupports of the |real| object. + // + nsCOMPtr rootObject; + + rootObject = do_QueryInterface(rawObject, &rv); + if (NS_FAILED(rv) || !rootObject) { + NS_ASSERTION(NS_FAILED(rv), "where did my root object go!"); + return nsnull; + } + + // Get the root nsISupports of the event queue... This is used later, + // as part of the hashtable key... + nsCOMPtr destQRoot = do_QueryInterface(destQueue, &rv); + if (NS_FAILED(rv) || !destQRoot) { + return nsnull; + } + + // + // Enter the proxy object creation lock. + // + // This lock protects thev linked list which chains proxies together + // (ie. mRoot and mNext) and ensures that there is no hashtable contention + // between the time that a proxy is looked up (and not found) in the + // hashtable and then added... + // + nsProxyObjectManager *manager = nsProxyObjectManager::GetInstance(); + if (!manager) { + return nsnull; + } + + nsAutoMonitor mon(manager->GetMonitor()); + + // Get the hash table containing root proxy objects... + nsHashtable *realToProxyMap = manager->GetRealObjectToProxyObjectMap(); + if (!realToProxyMap) { + return nsnull; + } + + // Now, lookup the root nsISupports of the raw object in the hashtable + // The key consists of 3 pieces of information: + // - root nsISupports of the raw object + // - event queue of the current thread + // - type of proxy being constructed... + // + nsProxyEventKey rootkey(rootObject.get(), destQRoot.get(), proxyType); + + nsCOMPtr rootProxy; + nsCOMPtr proxy; + nsProxyEventObject* peo; + + // find in our hash table + rootProxy = (nsProxyEventObject*) realToProxyMap->Get(&rootkey); + + if(rootProxy) { + // + // At least one proxy has already been created for this raw object... + // + // Look for the specific interface proxy in the list off of + // the root proxy... + // + peo = rootProxy->LockedFind(aIID); + + if(peo) { + // An existing proxy is available... So use it. + NS_ADDREF(peo); + return peo; + } + } + else { + // build the root proxy + nsCOMPtr rootClazz; + + rootClazz = dont_AddRef(nsProxyEventClass::GetNewOrUsedClass( + NS_GET_IID(nsISupports))); + if (!rootClazz) { + return nsnull; + } + + peo = new nsProxyEventObject(destQueue, + proxyType, + rootObject, + rootClazz, + nsnull); + if(!peo) { + // Ouch... Out of memory! + return nsnull; + } + + // Add this root proxy into the hash table... + realToProxyMap->Put(&rootkey, peo); + + if(aIID.Equals(NS_GET_IID(nsISupports))) { + // + // Since the requested proxy is for the nsISupports interface of + // the raw object, use the new root proxy as the specific proxy + // too... + // + NS_ADDREF(peo); + return peo; + } + + // This assignment is an owning reference to the new ProxyEventObject. + // So, it will automatically get deleted if any subsequent early + // returns are taken... + rootProxy = do_QueryInterface(peo); + } + + // + // at this point we have a proxy for the root nsISupports (ie. rootProxy) + // but we need to build the specific proxy for this interface... + // + NS_ASSERTION(rootProxy, "What happened to the root proxy!"); + + // Get a class for this IID. + nsCOMPtr proxyClazz; + + proxyClazz = dont_AddRef(nsProxyEventClass::GetNewOrUsedClass(aIID)); + if(!proxyClazz) { + return nsnull; + } + + // Get the raw interface for this IID + nsCOMPtr rawInterface; + + rv = rawObject->QueryInterface(aIID, getter_AddRefs(rawInterface)); + if (NS_FAILED(rv) || !rawInterface) { + NS_ASSERTION(NS_FAILED(rv), "where did my rawInterface object go!"); + return nsnull; + } + + peo = new nsProxyEventObject(destQueue, + proxyType, + rawInterface, + proxyClazz, + rootProxy); + if (!peo) { + // Ouch... Out of memory! + return nsnull; + } + + // + // Add the new specific proxy to the head of the list of proxies hanging + // off of the rootProxy... + // + peo->mNext = rootProxy->mNext; + rootProxy->mNext = peo; + + NS_ADDREF(peo); + return peo; + +} + +nsProxyEventObject* nsProxyEventObject::LockedFind(REFNSIID aIID) +{ + if(aIID.Equals(mClass->GetProxiedIID())) { + return this; + } + + if(aIID.Equals(NS_GET_IID(nsISupports))) { + return this; + } + + nsProxyEventObject* cur = (mRoot ? mRoot : mNext); + while(cur) { + if(aIID.Equals(cur->GetClass()->GetProxiedIID())) { + return cur; + } + cur = cur->mNext; + } + + return nsnull; +} + +nsProxyEventObject::nsProxyEventObject() +: mNext(nsnull) +{ + NS_WARNING("This constructor should never be called"); +} + +nsProxyEventObject::nsProxyEventObject(nsIEventQueue *destQueue, + PRInt32 proxyType, + nsISupports* aObj, + nsProxyEventClass* aClass, + nsProxyEventObject* root) + : mClass(aClass), + mRoot(root), + mNext(nsnull) +{ + NS_IF_ADDREF(mRoot); + + mProxyObject = new nsProxyObject(destQueue, proxyType, aObj); + +#ifdef DEBUG_xpcom_proxy + DebugDump("Create", 0); +#endif +} + +nsProxyEventObject::~nsProxyEventObject() +{ +#ifdef DEBUG_xpcom_proxy + DebugDump("Delete", 0); +#endif + if (mRoot) { + // + // This proxy is not the root interface so it must be removed + // from the chain of proxies... + // + nsProxyEventObject* cur = mRoot; + while(cur) { + if(cur->mNext == this) { + cur->mNext = mNext; + mNext = nsnull; + break; + } + cur = cur->mNext; + } + NS_ASSERTION(cur, "failed to find wrapper in its own chain"); + } + else { + // + // This proxy is for the root interface. Each proxy in the chain + // has a strong reference to the root... So, when its refcount goes + // to zero, it safe to remove it because no proxies are in its chain. + // + if (! nsProxyObjectManager::IsManagerShutdown()) { + nsProxyObjectManager* manager = nsProxyObjectManager::GetInstance(); + nsHashtable *realToProxyMap = manager->GetRealObjectToProxyObjectMap(); + + NS_ASSERTION(!mNext, "There are still proxies in the chain!"); + + if (realToProxyMap != nsnull) { + nsCOMPtr rootObject = do_QueryInterface(mProxyObject->mRealObject); + nsCOMPtr rootQueue = do_QueryInterface(mProxyObject->mDestQueue); + nsProxyEventKey key(rootObject, rootQueue, mProxyObject->mProxyType); +#ifdef DEBUG_dougt + void* value = +#endif + realToProxyMap->Remove(&key); +#ifdef DEBUG_dougt + NS_ASSERTION(value, "failed to remove from realToProxyMap"); +#endif + } + } + } + + // I am worried about ordering. + // do not remove assignments. + mProxyObject = nsnull; + mClass = nsnull; + NS_IF_RELEASE(mRoot); +} + +// +// nsISupports implementation... +// + +NS_IMPL_THREADSAFE_ADDREF(nsProxyEventObject) + +NS_IMETHODIMP_(nsrefcnt) +nsProxyEventObject::Release(void) +{ + // + // Be pessimistic about whether the manager or even the monitor exist... + // This is to protect against shutdown issues where a proxy object could + // be destroyed after (or while) the Proxy Manager is being destroyed... + // + nsProxyObjectManager* manager = nsProxyObjectManager::GetInstance(); + nsAutoMonitor mon(manager ? manager->GetMonitor() : nsnull); + + nsrefcnt count; + NS_PRECONDITION(0 != mRefCnt, "dup release"); + // Decrement atomically - in case the Proxy Object Manager has already + // been deleted and the monitor is unavailable... + count = PR_AtomicDecrement((PRInt32 *)&mRefCnt); + NS_LOG_RELEASE(this, count, "nsProxyEventObject"); + if (0 == count) { + mRefCnt = 1; /* stabilize */ + // + // Remove the proxy from the hashtable (if necessary) or its + // proxy chain. This must be done inside of the proxy lock to + // prevent GetNewOrUsedProxy(...) from ressurecting it... + // + NS_DELETEXPCOM(this); + return 0; + } + return count; +} + +NS_IMETHODIMP +nsProxyEventObject::QueryInterface(REFNSIID aIID, void** aInstancePtr) +{ + if( aIID.Equals(GetIID()) ) + { + *aInstancePtr = NS_STATIC_CAST(nsISupports*, this); + NS_ADDREF_THIS(); + return NS_OK; + } + + return mClass->DelegatedQueryInterface(this, aIID, aInstancePtr); +} + +// +// nsXPTCStubBase implementation... +// + +NS_IMETHODIMP +nsProxyEventObject::GetInterfaceInfo(nsIInterfaceInfo** info) +{ + NS_ENSURE_ARG_POINTER(info); + + *info = mClass->GetInterfaceInfo(); + + NS_ASSERTION(*info, "proxy class without interface"); + if (!*info) { + return NS_ERROR_UNEXPECTED; + } + + NS_ADDREF(*info); + return NS_OK; +} + +NS_IMETHODIMP +nsProxyEventObject::CallMethod(PRUint16 methodIndex, + const nsXPTMethodInfo* info, + nsXPTCMiniVariant * params) +{ + nsresult rv; + + if (mProxyObject) { + rv = mProxyObject->Post(methodIndex, + (nsXPTMethodInfo*)info, + params, + mClass->GetInterfaceInfo()); + } else { + rv = NS_ERROR_NULL_POINTER; + } + + return rv; +} diff --git a/src/libs/xpcom18a4/xpcom/proxy/src/nsProxyEventPrivate.h b/src/libs/xpcom18a4/xpcom/proxy/src/nsProxyEventPrivate.h new file mode 100644 index 00000000..ee34927e --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/proxy/src/nsProxyEventPrivate.h @@ -0,0 +1,201 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Pierre Phaneuf + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +#ifndef __nsProxyEventPrivate_h_ +#define __nsProxyEventPrivate_h_ + +#include "nscore.h" +#include "nsISupports.h" +#include "nsIFactory.h" +#include "nsHashtable.h" + +#include "plevent.h" +#include "xptcall.h" // defines nsXPTCVariant +#include "nsIEventQueue.h" + +#include "nsProxyEvent.h" +#include "nsIProxyObjectManager.h" + +class nsProxyEventObject; +class nsProxyEventClass; + +#define NS_PROXYEVENT_CLASS_IID \ +{ 0xeea90d42, \ + 0xb059, \ + 0x11d2, \ + {0x91, 0x5e, 0xc1, 0x2b, 0x69, 0x6c, 0x93, 0x33}\ +} + +#define NS_PROXYEVENT_IDENTITY_CLASS_IID \ +{ 0xeea90d45, 0xb059, 0x11d2, \ + { 0x91, 0x5e, 0xc1, 0x2b, 0x69, 0x6c, 0x93, 0x33 } } + + +#define NS_PROXYEVENT_OBJECT_IID \ +{ 0xec373590, 0x9164, 0x11d3, \ +{0x8c, 0x73, 0x00, 0x00, 0x64, 0x65, 0x73, 0x74} } + + +class nsProxyEventClass : public nsISupports +{ +public: + NS_DECL_ISUPPORTS + + NS_DEFINE_STATIC_IID_ACCESSOR(NS_PROXYEVENT_CLASS_IID) + static nsProxyEventClass* GetNewOrUsedClass(REFNSIID aIID); + + NS_IMETHOD DelegatedQueryInterface( nsProxyEventObject* self, + REFNSIID aIID, + void** aInstancePtr); + + + nsIInterfaceInfo* GetInterfaceInfo() const {return mInfo;} + const nsIID& GetProxiedIID() const {return mIID; } +protected: + nsProxyEventClass(); + nsProxyEventClass(REFNSIID aIID, nsIInterfaceInfo* aInfo); + +private: + ~nsProxyEventClass(); + + nsIID mIID; + nsCOMPtr mInfo; + uint32* mDescriptors; + + nsresult CallQueryInterfaceOnProxy(nsProxyEventObject* self, + REFNSIID aIID, + nsProxyEventObject** aInstancePtr); +}; + + + +class nsProxyEventObject : public nsXPTCStubBase +{ +public: + + NS_DECL_ISUPPORTS + + NS_DEFINE_STATIC_IID_ACCESSOR(NS_PROXYEVENT_OBJECT_IID) + + static nsProxyEventObject* GetNewOrUsedProxy(nsIEventQueue *destQueue, + PRInt32 proxyType, + nsISupports *aObj, + REFNSIID aIID); + + + NS_IMETHOD GetInterfaceInfo(nsIInterfaceInfo** info); + + // call this method and return result + NS_IMETHOD CallMethod(PRUint16 methodIndex, const nsXPTMethodInfo* info, nsXPTCMiniVariant* params); + + + nsProxyEventClass* GetClass() const { return mClass; } + nsIEventQueue* GetQueue() const { return (mProxyObject ? mProxyObject->GetQueue() : nsnull);} + nsISupports* GetRealObject() const { return (mProxyObject ? mProxyObject->GetRealObject(): nsnull);} + PRInt32 GetProxyType() const { return (mProxyObject ? mProxyObject->GetProxyType() : nsnull);} + + nsProxyEventObject(); + nsProxyEventObject(nsIEventQueue *destQueue, + PRInt32 proxyType, + nsISupports* aObj, + nsProxyEventClass* aClass, + nsProxyEventObject* root); + + nsProxyEventObject* LockedFind(REFNSIID aIID); + +#ifdef DEBUG_xpcom_proxy + void DebugDump(const char * message, PRUint32 hashKey); +#endif + +private: + ~nsProxyEventObject(); + +protected: + void LockedRemoveProxy(); + +protected: + nsCOMPtr mClass; + nsRefPtr mProxyObject; + + // Owning reference... + nsProxyEventObject *mRoot; + + // Weak reference... + nsProxyEventObject *mNext; +}; + + + + +//////////////////////////////////////////////////////////////////////////////// +// nsProxyObjectManager +//////////////////////////////////////////////////////////////////////////////// + +class nsProxyObjectManager: public nsIProxyObjectManager +{ +public: + + NS_DECL_ISUPPORTS + NS_DECL_NSIPROXYOBJECTMANAGER + + + static NS_METHOD Create(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr); + + nsProxyObjectManager(); + + static nsProxyObjectManager *GetInstance(); + static PRBool IsManagerShutdown(); + + static void Shutdown(); + + nsHashtable* GetRealObjectToProxyObjectMap() { return &mProxyObjectMap;} + nsHashtable* GetIIDToProxyClassMap() { return &mProxyClassMap; } + + PRMonitor* GetMonitor() const { return mProxyCreationMonitor; } + +private: + ~nsProxyObjectManager(); + + static nsProxyObjectManager* mInstance; + nsHashtable mProxyObjectMap; + nsHashtable mProxyClassMap; + PRMonitor *mProxyCreationMonitor; +}; + + +#endif diff --git a/src/libs/xpcom18a4/xpcom/proxy/src/nsProxyObjectManager.cpp b/src/libs/xpcom18a4/xpcom/proxy/src/nsProxyObjectManager.cpp new file mode 100644 index 00000000..0602bcd7 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/proxy/src/nsProxyObjectManager.cpp @@ -0,0 +1,322 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Doug Turner (Original Author) + * Judson Valeski + * Dan Matejka + * Scott Collins + * Heikki Toivonen + * Patrick Beard + * Pierre Phaneuf + * Warren Harris + * Chris Seawood + * Chris Waterson + * Dan Mosedale + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsProxyEvent.h" +#include "nsIProxyObjectManager.h" +#include "nsProxyEventPrivate.h" + +#include "nsIProxyCreateInstance.h" + +#include "nsIComponentManager.h" +#include "nsIServiceManager.h" +#include "nsComponentManagerObsolete.h" +#include "nsCOMPtr.h" + +#include "nsIEventQueueService.h" +#include "nsIThread.h" + + +static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID); + +/***************************************************************************/ +/* nsProxyCreateInstance */ +/* This private class will allow us to create Instances on another thread */ +/***************************************************************************/ +class nsProxyCreateInstance : public nsIProxyCreateInstance +{ + NS_DECL_ISUPPORTS + NS_IMETHOD CreateInstanceByIID(const nsIID & cid, nsISupports *aOuter, const nsIID & iid, void * *result); + NS_IMETHOD CreateInstanceByContractID(const char *aContractID, nsISupports *aOuter, const nsIID & iid, void * *result); + + nsProxyCreateInstance() {} + +private: + ~nsProxyCreateInstance() {} +}; + +NS_IMPL_ISUPPORTS1(nsProxyCreateInstance, nsIProxyCreateInstance) + +NS_IMETHODIMP nsProxyCreateInstance::CreateInstanceByIID(const nsIID & cid, nsISupports *aOuter, const nsIID & iid, void * *result) +{ + return nsComponentManager::CreateInstance( cid, + aOuter, + iid, + result); +} + + +NS_IMETHODIMP nsProxyCreateInstance::CreateInstanceByContractID(const char *aContractID, nsISupports *aOuter, const nsIID & iid, void * *result) +{ + return nsComponentManager::CreateInstance( aContractID, + aOuter, + iid, + result); +} + +///////////////////////////////////////////////////////////////////////// +// nsProxyObjectManager +///////////////////////////////////////////////////////////////////////// + +nsProxyObjectManager* nsProxyObjectManager::mInstance = nsnull; + +NS_IMPL_THREADSAFE_ISUPPORTS1(nsProxyObjectManager, nsIProxyObjectManager) + +nsProxyObjectManager::nsProxyObjectManager() + : mProxyObjectMap(256, PR_TRUE), + mProxyClassMap(256, PR_TRUE) +{ + mProxyCreationMonitor = PR_NewMonitor(); +} + +static PRBool PurgeProxyClasses(nsHashKey *aKey, void *aData, void* closure) +{ + nsProxyEventClass* ptr = NS_REINTERPRET_CAST(nsProxyEventClass*, aData); + NS_RELEASE(ptr); + return PR_TRUE; +} + +nsProxyObjectManager::~nsProxyObjectManager() +{ + mProxyClassMap.Reset((nsHashtableEnumFunc)PurgeProxyClasses, nsnull); + + if (mProxyCreationMonitor) { + PR_DestroyMonitor(mProxyCreationMonitor); + } + + nsProxyObjectManager::mInstance = nsnull; +} + +PRBool +nsProxyObjectManager::IsManagerShutdown() +{ + if (mInstance) + return PR_FALSE; + return PR_TRUE; +} + +nsProxyObjectManager * +nsProxyObjectManager::GetInstance() +{ + if (! mInstance) + { + mInstance = new nsProxyObjectManager(); + } + return mInstance; +} + + +void +nsProxyObjectManager::Shutdown() +{ + mInstance = nsnull; +} + + +// Helpers +NS_IMETHODIMP +nsProxyObjectManager::Create(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr) +{ + nsProxyObjectManager *proxyObjectManager = GetInstance(); + + if (proxyObjectManager == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + + return proxyObjectManager->QueryInterface(aIID, aInstancePtr); +} + + +NS_IMETHODIMP +nsProxyObjectManager::GetProxyForObject(nsIEventQueue *destQueue, + REFNSIID aIID, + nsISupports* aObj, + PRInt32 proxyType, + void** aProxyObject) +{ + if (!aObj) return NS_ERROR_NULL_POINTER; + if (!aProxyObject) return NS_ERROR_NULL_POINTER; + + nsresult rv; + nsCOMPtr postQ; + + + *aProxyObject = nsnull; + + // check to see if the destination Q is a special case. + + nsCOMPtr eventQService = + do_GetService(kEventQueueServiceCID, &rv); + if (NS_FAILED(rv)) + return rv; + + rv = eventQService->ResolveEventQueue(destQueue, getter_AddRefs(postQ)); + if (NS_FAILED(rv)) + return rv; + + // check to see if the eventQ is on our thread. If so, just return the real object. + + if (postQ && !(proxyType & PROXY_ASYNC) && !(proxyType & PROXY_ALWAYS)) + { + PRBool aResult; + postQ->IsOnCurrentThread(&aResult); + + if (aResult) + { + return aObj->QueryInterface(aIID, aProxyObject); + } + } + + // check to see if proxy is there or not. + *aProxyObject = nsProxyEventObject::GetNewOrUsedProxy(postQ, proxyType, aObj, aIID); + + if (*aProxyObject == nsnull) + return NS_ERROR_NO_INTERFACE; //fix error code? + + return NS_OK; +} + + +NS_IMETHODIMP +nsProxyObjectManager::GetProxy( nsIEventQueue *destQueue, + const nsCID &aClass, + nsISupports *aDelegate, + const nsIID &aIID, + PRInt32 proxyType, + void** aProxyObject) +{ + if (!aProxyObject) return NS_ERROR_NULL_POINTER; + *aProxyObject = nsnull; + + // 1. Create a proxy for creating an instance on another thread. + + nsIProxyCreateInstance* ciProxy = nsnull; + + nsProxyCreateInstance* ciObject = new nsProxyCreateInstance(); + + if (ciObject == nsnull) + return NS_ERROR_NULL_POINTER; + + NS_ADDREF(ciObject); + + nsresult rv = GetProxyForObject(destQueue, + NS_GET_IID(nsIProxyCreateInstance), + ciObject, + PROXY_SYNC, + (void**)&ciProxy); + + if (NS_FAILED(rv)) + { + NS_RELEASE(ciObject); + return rv; + } + + // 2. now create a new instance of the request object via our proxy. + + nsISupports* aObj; + + rv = ciProxy->CreateInstanceByIID(aClass, + aDelegate, + aIID, + (void**)&aObj); + + + // 3. Delete the create instance proxy and its real object. + + NS_RELEASE(ciProxy); + NS_RELEASE(ciObject); + + // 4. Check to see if creating the requested instance failed. + if ( NS_FAILED(rv)) + { + return rv; + } + + // 5. Now create a proxy object for the requested object. + + rv = GetProxyForObject(destQueue, aIID, aObj, proxyType, aProxyObject); + + // 6. release ownership of aObj so that aProxyObject owns it. + + NS_RELEASE(aObj); + + // 7. return the error returned from GetProxyForObject. Either way, we our out of here. + + return rv; +} + +/** + * Helper function for code that already has a link-time dependency on + * libxpcom and needs to get proxies in a bunch of different places. + * This way, the caller isn't forced to get the proxy object manager + * themselves every single time, thus making the calling code more + * readable. + */ +NS_COM nsresult +NS_GetProxyForObject(nsIEventQueue *destQueue, + REFNSIID aIID, + nsISupports* aObj, + PRInt32 proxyType, + void** aProxyObject) +{ + static NS_DEFINE_CID(proxyObjMgrCID, NS_PROXYEVENT_MANAGER_CID); + + nsresult rv; // temp for return value + + // get the proxy object manager + // + nsCOMPtr proxyObjMgr = + do_GetService(proxyObjMgrCID, &rv); + + if (NS_FAILED(rv)) + return NS_ERROR_FAILURE; + + // and try to get the proxy object + // + return proxyObjMgr->GetProxyForObject(destQueue, aIID, aObj, + proxyType, aProxyObject); +} diff --git a/src/libs/xpcom18a4/xpcom/proxy/src/nsProxyRelease.cpp b/src/libs/xpcom18a4/xpcom/proxy/src/nsProxyRelease.cpp new file mode 100644 index 00000000..3ceeb667 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/proxy/src/nsProxyRelease.cpp @@ -0,0 +1,55 @@ +#include "nsProxyRelease.h" + +PR_STATIC_CALLBACK(void*) +HandleProxyReleaseEvent(PLEvent *self) +{ + nsISupports* owner = (nsISupports*) self->owner; + NS_RELEASE(owner); + return nsnull; +} + +PR_STATIC_CALLBACK(void) +DestroyProxyReleaseEvent(PLEvent *self) +{ + delete self; +} + +NS_COM nsresult +NS_ProxyRelease(nsIEventTarget *target, nsISupports *doomed, PRBool alwaysProxy) +{ + nsresult rv; + + if (!target) { + NS_RELEASE(doomed); + return NS_OK; + } + + if (!alwaysProxy) { + PRBool onCurrentThread = PR_FALSE; + rv = target->IsOnCurrentThread(&onCurrentThread); + if (NS_SUCCEEDED(rv) && onCurrentThread) { + NS_RELEASE(doomed); + return NS_OK; + } + } + + PLEvent *ev = new PLEvent; + if (!ev) { + // we do not release doomed here since it may cause a delete on the + // wrong thread. better to leak than crash. + return NS_ERROR_OUT_OF_MEMORY; + } + + PL_InitEvent(ev, doomed, + HandleProxyReleaseEvent, + DestroyProxyReleaseEvent); + + rv = target->PostEvent(ev); + if (NS_FAILED(rv)) { + NS_WARNING("failed to post proxy release event"); + PL_DestroyEvent(ev); + // again, it is better to leak the doomed object than risk crashing as + // a result of deleting it on the wrong thread. + } + return rv; +} diff --git a/src/libs/xpcom18a4/xpcom/proxy/tests/.cvsignore b/src/libs/xpcom18a4/xpcom/proxy/tests/.cvsignore new file mode 100644 index 00000000..b7457ff6 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/proxy/tests/.cvsignore @@ -0,0 +1,2 @@ +Makefile +proxytests diff --git a/src/libs/xpcom18a4/xpcom/proxy/tests/Makefile.in b/src/libs/xpcom18a4/xpcom/proxy/tests/Makefile.in new file mode 100644 index 00000000..e5e908f1 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/proxy/tests/Makefile.in @@ -0,0 +1,60 @@ +# +# ***** 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.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of 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 ***** + +DEPTH = ../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = xpcom +XPIDL_MODULE = proxytest +REQUIRES = $(NULL) + +CPPSRCS = proxytests.cpp +XPIDLSRCS = nsITestProxy.idl + +SIMPLE_PROGRAMS = $(CPPSRCS:.cpp=$(BIN_SUFFIX)) + +LIBS = \ + $(XPCOM_LIBS) \ + $(NSPR_LIBS) \ + $(NULL) + +include $(topsrcdir)/config/rules.mk + diff --git a/src/libs/xpcom18a4/xpcom/proxy/tests/nsITestProxy.idl b/src/libs/xpcom18a4/xpcom/proxy/tests/nsITestProxy.idl new file mode 100644 index 00000000..98cb3f94 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/proxy/tests/nsITestProxy.idl @@ -0,0 +1,9 @@ +#include "nsISupports.idl" + +[uuid(1979e980-1cfd-11d3-915e-0000863011c4)] +interface nsITestProxy : nsISupports +{ + long Test(in long p1, in long p2); + void Test2(); + void Test3(in nsISupports p1, out nsISupports p2); +}; diff --git a/src/libs/xpcom18a4/xpcom/proxy/tests/proxytests.cpp b/src/libs/xpcom18a4/xpcom/proxy/tests/proxytests.cpp new file mode 100644 index 00000000..20693463 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/proxy/tests/proxytests.cpp @@ -0,0 +1,553 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Pierre Phaneuf + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 + +#include "nsXPCOM.h" +#include "nsIComponentManager.h" +#include "nsIComponentRegistrar.h" +#include "nsIServiceManager.h" +#include "nsCOMPtr.h" + +#include "nscore.h" +#include "nspr.h" +#include "prmon.h" + +#include "nsITestProxy.h" + +#include "nsIProxyObjectManager.h" +#include "nsIEventQueueService.h" + +static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID); + +/***************************************************************************/ +/* nsTestXPCFoo */ +/***************************************************************************/ +class nsTestXPCFoo : public nsITestProxy +{ + NS_DECL_ISUPPORTS + NS_IMETHOD Test(PRInt32 p1, PRInt32 p2, PRInt32* retval); + NS_IMETHOD Test2(); + NS_IMETHOD Test3(nsISupports *p1, nsISupports **p2); + + nsTestXPCFoo(); +}; + +nsTestXPCFoo::nsTestXPCFoo() +{ + NS_ADDREF_THIS(); +} + +NS_IMPL_ISUPPORTS1(nsTestXPCFoo, nsITestProxy) + +NS_IMETHODIMP nsTestXPCFoo::Test(PRInt32 p1, PRInt32 p2, PRInt32* retval) +{ + printf("Thread (%d) Test Called successfully! Party on...\n", p1); + *retval = p1+p2; + return NS_OK; +} + + +NS_IMETHODIMP nsTestXPCFoo::Test2() +{ + printf("The quick brown netscape jumped over the old lazy ie..\n"); + + return NS_OK; +} + +NS_IMETHODIMP nsTestXPCFoo::Test3(nsISupports *p1, nsISupports **p2) +{ + if (p1 != nsnull) + { + nsITestProxy *test; + + p1->QueryInterface(NS_GET_IID(nsITestProxy), (void**)&test); + + test->Test2(); + PRInt32 a; + test->Test( 1, 2, &a); + printf("\n1+2=%d\n",a); + } + + + *p2 = new nsTestXPCFoo(); + return NS_OK; +} + +/***************************************************************************/ +/* nsTestXPCFoo2 */ +/***************************************************************************/ +class nsTestXPCFoo2 : public nsITestProxy +{ + NS_DECL_ISUPPORTS + NS_IMETHOD Test(PRInt32 p1, PRInt32 p2, PRInt32* retval); + NS_IMETHOD Test2(); + NS_IMETHOD Test3(nsISupports *p1, nsISupports **p2); + + nsTestXPCFoo2(); +}; + +nsTestXPCFoo2::nsTestXPCFoo2() +{ + NS_ADDREF_THIS(); +} + +NS_IMPL_THREADSAFE_ISUPPORTS1(nsTestXPCFoo2, nsITestProxy) + +NS_IMETHODIMP nsTestXPCFoo2::Test(PRInt32 p1, PRInt32 p2, PRInt32* retval) +{ +printf("calling back to caller!\n\n"); + + nsIProxyObjectManager* manager; + nsITestProxy * proxyObject; + + nsServiceManager::GetService( NS_XPCOMPROXY_CONTRACTID, + NS_GET_IID(nsIProxyObjectManager), + (nsISupports **)&manager); + + printf("ProxyObjectManager: %p \n", manager); + + PR_ASSERT(manager); + + manager->GetProxyForObject((nsIEventQueue*)p1, NS_GET_IID(nsITestProxy), this, PROXY_SYNC, (void**)&proxyObject); + proxyObject->Test3(nsnull, nsnull); + + printf("Deleting Proxy Object\n"); + NS_RELEASE(proxyObject); + + return NS_OK; +} + + +NS_IMETHODIMP nsTestXPCFoo2::Test2() +{ + printf("nsTestXPCFoo2::Test2() called\n"); + + return NS_OK; +} + + +NS_IMETHODIMP nsTestXPCFoo2::Test3(nsISupports *p1, nsISupports **p2) +{ + printf("Got called"); + return NS_OK; +} + + + +typedef struct _ArgsStruct +{ + nsIEventQueue* queue; + PRInt32 threadNumber; +}ArgsStruct; + + + +// This will create two objects both descendants of a single IID. +void TestCase_TwoClassesOneInterface(void *arg) +{ + ArgsStruct *argsStruct = (ArgsStruct*) arg; + + + nsIProxyObjectManager* manager; + + nsServiceManager::GetService( NS_XPCOMPROXY_CONTRACTID, + NS_GET_IID(nsIProxyObjectManager), + (nsISupports **)&manager); + + printf("ProxyObjectManager: %p \n", manager); + + PR_ASSERT(manager); + + nsITestProxy *proxyObject; + nsITestProxy *proxyObject2; + + nsTestXPCFoo* foo = new nsTestXPCFoo(); + nsTestXPCFoo2* foo2 = new nsTestXPCFoo2(); + + PR_ASSERT(foo); + PR_ASSERT(foo2); + + + manager->GetProxyForObject(argsStruct->queue, NS_GET_IID(nsITestProxy), foo, PROXY_SYNC, (void**)&proxyObject); + + manager->GetProxyForObject(argsStruct->queue, NS_GET_IID(nsITestProxy), foo2, PROXY_SYNC, (void**)&proxyObject2); + + + + if (proxyObject && proxyObject2) + { + // release ownership of the real object. + + PRInt32 a; + nsresult rv; + PRInt32 threadNumber = argsStruct->threadNumber; + + printf("Deleting real Object (%d)\n", threadNumber); + NS_RELEASE(foo); + + printf("Deleting real Object 2 (%d)\n", threadNumber); + NS_RELEASE(foo2); + + + printf("Thread (%d) Prior to calling proxyObject->Test.\n", threadNumber); + rv = proxyObject->Test(threadNumber, 0, &a); + printf("Thread (%d) error: %d.\n", threadNumber, rv); + + + printf("Thread (%d) Prior to calling proxyObject->Test2.\n", threadNumber); + rv = proxyObject->Test2(); + printf("Thread (%d) error: %d.\n", threadNumber, rv); + + printf("Thread (%d) Prior to calling proxyObject2->Test2.\n", threadNumber); + rv = proxyObject2->Test2(); + printf("Thread (%d) proxyObject2 error: %d.\n", threadNumber, rv); + + printf("Deleting Proxy Object (%d)\n", threadNumber ); + NS_RELEASE(proxyObject); + + printf("Deleting Proxy Object 2 (%d)\n", threadNumber ); + NS_RELEASE(proxyObject2); + } + + PR_Sleep( PR_MillisecondsToInterval(1000) ); // If your thread goes away, your stack goes away. Only use ASYNC on calls that do not have out parameters +} + + + +void TestCase_NestedLoop(void *arg) +{ + ArgsStruct *argsStruct = (ArgsStruct*) arg; + + + nsIProxyObjectManager* manager; + + nsServiceManager::GetService( NS_XPCOMPROXY_CONTRACTID, + NS_GET_IID(nsIProxyObjectManager), + (nsISupports **)&manager); + + printf("ProxyObjectManager: %p \n", manager); + + PR_ASSERT(manager); + + nsITestProxy *proxyObject; + nsTestXPCFoo2* foo = new nsTestXPCFoo2(); + + PR_ASSERT(foo); + + + manager->GetProxyForObject(argsStruct->queue, NS_GET_IID(nsITestProxy), foo, PROXY_SYNC, (void**)&proxyObject); + + if (proxyObject) + { + // release ownership of the real object. + + nsresult rv; + PRInt32 threadNumber = argsStruct->threadNumber; + + printf("Deleting real Object (%d)\n", threadNumber); + NS_RELEASE(foo); + + PRInt32 retval; + + printf("Getting EventQueue...\n"); + + nsIEventQueue* eventQ; + nsCOMPtr eventQService = + do_GetService(kEventQueueServiceCID, &rv); + if (NS_SUCCEEDED(rv)) + { + rv = eventQService->GetThreadEventQueue(NS_CURRENT_THREAD, &eventQ); + if (NS_FAILED(rv)) + rv = eventQService->CreateThreadEventQueue(); + if (NS_FAILED(rv)) + return; + else + rv = eventQService->GetThreadEventQueue(NS_CURRENT_THREAD, &eventQ); + + printf("Thread (%d) Prior to calling proxyObject->Test.\n", threadNumber); + rv = proxyObject->Test(NS_PTR_TO_INT32(eventQ), 0, &retval); + printf("Thread (%d) proxyObject error: %d.\n", threadNumber, rv); + + printf("Deleting Proxy Object (%d)\n", threadNumber ); + NS_RELEASE(proxyObject); + } + + PR_Sleep( PR_MillisecondsToInterval(1000) ); // If your thread goes away, your stack goes away. Only use ASYNC on calls that do not have out parameters + } +} + + + +void TestCase_2(void *arg) +{ + + ArgsStruct *argsStruct = (ArgsStruct*) arg; + + nsIProxyObjectManager* manager; + + nsServiceManager::GetService( NS_XPCOMPROXY_CONTRACTID, + NS_GET_IID(nsIProxyObjectManager), + (nsISupports **)&manager); + + PR_ASSERT(manager); + + nsITestProxy *proxyObject; + + manager->GetProxy(argsStruct->queue, + NS_GET_IID(nsITestProxy), // should be CID! + nsnull, + NS_GET_IID(nsITestProxy), + PROXY_SYNC, + (void**)&proxyObject); + + if (proxyObject != nsnull) + { + NS_RELEASE(proxyObject); + } +} + + + +void TestCase_nsISupports(void *arg) +{ + + ArgsStruct *argsStruct = (ArgsStruct*) arg; + + nsIProxyObjectManager* manager; + + nsServiceManager::GetService( NS_XPCOMPROXY_CONTRACTID, + NS_GET_IID(nsIProxyObjectManager), + (nsISupports **)&manager); + + PR_ASSERT(manager); + + nsITestProxy *proxyObject; + nsTestXPCFoo* foo = new nsTestXPCFoo(); + + PR_ASSERT(foo); + + manager->GetProxyForObject(argsStruct->queue, NS_GET_IID(nsITestProxy), foo, PROXY_SYNC, (void**)&proxyObject); + + if (proxyObject != nsnull) + { + nsISupports *bISupports = nsnull, *cISupports = nsnull; + + proxyObject->Test3(foo, &bISupports); + proxyObject->Test3(bISupports, &cISupports); + + nsITestProxy *test; + bISupports->QueryInterface(NS_GET_IID(nsITestProxy), (void**)&test); + + test->Test2(); + + NS_RELEASE(foo); + NS_RELEASE(proxyObject); + } +} + + + + + +/***************************************************************************/ +/* ProxyTest */ +/***************************************************************************/ + +static void PR_CALLBACK ProxyTest( void *arg ) +{ + //TestCase_TwoClassesOneInterface(arg); + // TestCase_2(arg); + //TestCase_nsISupports(arg); + TestCase_NestedLoop(arg); + + NS_RELEASE( ((ArgsStruct*) arg)->queue); + free((void*) arg); +} + +nsIEventQueue *gEventQueue = nsnull; + +static void PR_CALLBACK EventLoop( void *arg ) +{ + nsresult rv; + printf("Creating EventQueue...\n"); + + nsIEventQueue* eventQ; + nsCOMPtr eventQService = + do_GetService(kEventQueueServiceCID, &rv); + if (NS_SUCCEEDED(rv)) { + rv = eventQService->GetThreadEventQueue(NS_CURRENT_THREAD, &eventQ); + if (NS_FAILED(rv)) + rv = eventQService->CreateThreadEventQueue(); + if (NS_FAILED(rv)) + return; + else + rv = eventQService->GetThreadEventQueue(NS_CURRENT_THREAD, &eventQ); + } + if (NS_FAILED(rv)) return; + + rv = eventQ->QueryInterface(NS_GET_IID(nsIEventQueue), (void**)&gEventQueue); + if (NS_FAILED(rv)) return; + + + printf("Verifing calling Proxy on eventQ thread.\n"); + + nsIProxyObjectManager* manager; + + nsServiceManager::GetService( NS_XPCOMPROXY_CONTRACTID, + NS_GET_IID(nsIProxyObjectManager), + (nsISupports **)&manager); + + PR_ASSERT(manager); + + nsITestProxy *proxyObject; + nsTestXPCFoo* foo = new nsTestXPCFoo(); + + PR_ASSERT(foo); + + manager->GetProxyForObject(gEventQueue, NS_GET_IID(nsITestProxy), foo, PROXY_SYNC, (void**)&proxyObject); + + PRInt32 a; + proxyObject->Test(1, 2, &a); + proxyObject->Test2(); + + + NS_RELEASE(proxyObject); + delete foo; + + printf("End of Verification calling Proxy on eventQ thread.\n"); + + + printf("Looping for events.\n"); + + PLEvent* event = nsnull; + + while ( PR_SUCCESS == PR_Sleep( PR_MillisecondsToInterval(1)) ) + { + rv = gEventQueue->GetEvent(&event); + if (NS_FAILED(rv)) + return; + gEventQueue->HandleEvent(event); + } + + gEventQueue->ProcessPendingEvents(); + + printf("Closing down Event Queue.\n"); + delete gEventQueue; + gEventQueue = nsnull; + + printf("End looping for events.\n\n"); +} + +int +main(int argc, char **argv) +{ + int numberOfThreads = 1; + + if (argc > 1) + numberOfThreads = atoi(argv[1]); + + nsCOMPtr servMan; + NS_InitXPCOM2(getter_AddRefs(servMan), nsnull, nsnull); + nsCOMPtr registrar = do_QueryInterface(servMan); + NS_ASSERTION(registrar, "Null nsIComponentRegistrar"); + registrar->AutoRegister(nsnull); + + static PRThread** threads = (PRThread**) calloc(sizeof(PRThread*), numberOfThreads); + static PRThread* aEventThread; + + aEventThread = PR_CreateThread(PR_USER_THREAD, + EventLoop, + NULL, + PR_PRIORITY_NORMAL, + PR_GLOBAL_THREAD, + PR_JOINABLE_THREAD, + 0 ); + + + PR_Sleep(PR_MillisecondsToInterval(1000)); + + NS_ASSERTION(gEventQueue, "no main event queue"); // BAD BAD BAD. EVENT THREAD DID NOT CREATE QUEUE. This may be a timing issue, set the + // sleep about longer, and try again. + + printf("Spawn Threads:\n"); + for (PRInt32 spawn = 0; spawn < numberOfThreads; spawn++) + { + + ArgsStruct *args = (ArgsStruct *) malloc (sizeof(ArgsStruct)); + + args->queue = gEventQueue; + NS_ADDREF(args->queue); + args->threadNumber = spawn; + + threads[spawn] = PR_CreateThread(PR_USER_THREAD, + ProxyTest, + args, + PR_PRIORITY_NORMAL, + PR_GLOBAL_THREAD, + PR_JOINABLE_THREAD, + 0 ); + + printf("\tThread (%d) spawned\n", spawn); + + PR_Sleep( PR_MillisecondsToInterval(250) ); + } + + printf("All Threads Spawned.\n\n"); + + + + printf("Wait for threads.\n"); + for (PRInt32 i = 0; i < numberOfThreads; i++) + { + PRStatus rv; + printf("Thread (%d) Join...\n", i); + rv = PR_JoinThread(threads[i]); + printf("Thread (%d) Joined. (error: %d).\n", i, rv); + } + + PR_Interrupt(aEventThread); + PR_JoinThread(aEventThread); + + + printf("Calling Cleanup.\n"); + PR_Cleanup(); + + printf("Return zero.\n"); + return 0; +} diff --git a/src/libs/xpcom18a4/xpcom/reflect/.cvsignore b/src/libs/xpcom18a4/xpcom/reflect/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/xpcom/reflect/Makefile.in b/src/libs/xpcom18a4/xpcom/reflect/Makefile.in new file mode 100644 index 00000000..171900b1 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/Makefile.in @@ -0,0 +1,49 @@ +# +# ***** 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.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of 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 ***** + +DEPTH = ../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = xpcom +DIRS = xptinfo xptcall + +include $(topsrcdir)/config/rules.mk + diff --git a/src/libs/xpcom18a4/xpcom/reflect/Makefile.kup b/src/libs/xpcom18a4/xpcom/reflect/Makefile.kup new file mode 100644 index 00000000..e69de29b diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/.cvsignore b/src/libs/xpcom18a4/xpcom/reflect/xptcall/.cvsignore new file mode 100644 index 00000000..a1af50c2 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/.cvsignore @@ -0,0 +1,4 @@ +Makefile +mk.bat +set_env.bat +none.pdb diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/Makefile.in b/src/libs/xpcom18a4/xpcom/reflect/xptcall/Makefile.in new file mode 100644 index 00000000..e3173730 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/Makefile.in @@ -0,0 +1,49 @@ +# +# ***** 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.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of 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 ***** + +DEPTH = ../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = xpcom +DIRS = public src + +include $(topsrcdir)/config/rules.mk + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/Makefile.kup b/src/libs/xpcom18a4/xpcom/reflect/xptcall/Makefile.kup new file mode 100644 index 00000000..e69de29b diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/README b/src/libs/xpcom18a4/xpcom/reflect/xptcall/README new file mode 100644 index 00000000..0c401fe8 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/README @@ -0,0 +1,6 @@ +see: + +http://www.mozilla.org/scriptable/xptcall-faq.html +and +http://lxr.mozilla.org/mozilla/source/xpcom/reflect/xptcall/porting.html + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/porting.html b/src/libs/xpcom18a4/xpcom/reflect/xptcall/porting.html new file mode 100644 index 00000000..b8b204a1 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/porting.html @@ -0,0 +1,212 @@ + + +xptcall Porting Guide + + +

xptcall Porting Guide

+ +

Overview

+ +
+ + xptcall is a +library that supports both invoking methods on arbitrary xpcom objects and +implementing classes whose objects can impersonate any xpcom interface. It does +this using platform specific assembly language code. This code needs to be +ported to all platforms that want to support xptcall (and thus mozilla). + +
+ +

The tree

+ +
+
+mozilla/xpcom/reflect/xptcall
+  +--public  // exported headers
+  +--src  // core source
+  |  \--md  // platform specific parts
+  |     +--mac  // mac ppc
+  |     +--unix  // all unix
+  |     \--win32  // win32
+  |     +--test  // simple tests to get started
+  \--tests  // full tests via api
+
+ +Porters are free to create subdirectories under the base md +directory for their given platforms and to integrate into the build system as +appropriate for their platform. + +
+ +

Theory of operation

+ +
+ +There are really two pieces of functionality: invoke and stubs... + +

+ +The invoke functionality requires the implementation of the +following on each platform (from xptcall/public/xptcall.h): + +

+XPTC_PUBLIC_API(nsresult)
+XPTC_InvokeByIndex(nsISupports* that, PRUint32 methodIndex,
+                   PRUint32 paramCount, nsXPTCVariant* params);
+
+ +Calling code is expected to supply an array of nsXPTCVariant +structs. These are discriminated unions describing the type and value of each +parameter of the target function. The platform specific code then builds a call +frame and invokes the method indicated by the index methodIndex on +the xpcom interface that. + +

+ +Here are examples of this implementation for +Win32 +and +Linux x86, NetBSD x86, and FreeBSD. + +Both of these implementations use the basic strategy of: figure out how much +stack space is needed for the params, make the space in a new frame, copy the +params to that space, invoke the method, cleanup and return. C++ is used where +appropriate, Assembly language is used where necessary. Inline assembly language is used here, +but it is equally valid to use separate assembly language source files. Porters +can decide how best to do this for their platforms. + +

+ +The stubs functionality is more complex. The goal here is a class +whose vtbl can look like the vtbl of any arbitrary xpcom interface. Objects of +this class can then be built to impersonate any xpcom object. The base interface +for this is (from xptcall/public/xptcall.h): + +

+class nsXPTCStubBase : public nsISupports
+{
+public:
+    // Include generated vtbl stub declarations.
+    // These are virtual and *also* implemented by this class..
+#include "xptcstubsdecl.inc"
+
+    // The following methods must be provided by inheritor of this class.
+
+    // return a refcounted pointer to the InterfaceInfo for this object
+    // NOTE: on some platforms this MUST not fail or we crash!
+    NS_IMETHOD GetInterfaceInfo(nsIInterfaceInfo** info) = 0;
+
+    // call this method and return result
+    NS_IMETHOD CallMethod(PRUint16 methodIndex,
+                          const nsXPTMethodInfo* info,
+                          nsXPTCMiniVariant* params) = 0;
+};
+
+ +Code that wishes to make use of this stubs functionality (such as +XPConnect) implement a class +which inherits from nsXPTCStubBase and implements the +GetInterfaceInfo and CallMethod to let the +platform specific code know how to get interface information and how to dispatch methods +once their parameters have been pulled out of the platform specific calling +frame. + +

+ +Porters of this functionality implement the platform specific code for the +stub methods that fill the vtbl for this class. The idea here is that the +class has a vtbl full of a large number of generic stubs. All instances of this +class share that vtbl and the same stubs. The stubs forward calls to a platform +specific method that uses the interface information supplied by +the overridden GetInterfaceInfo to extract the parameters and build +an array of platform independent nsXPTCMiniVariant structs which +are in turn passed on to the overridden CallMethod. The +platform dependent code is responsible for doing any cleanup and returning. + +

+ +The stub methods are declared in xptcall/public/xptcstubsdecl.inc. +These are '#included' into the declaration of nsXPTCStubBase. A +similar include file (xptcall/public/xptcstubsdef.inc) +is expanded using platform specific macros to define the stub functions. These +'.inc' files are checked into cvs. However, they can be regenerated as necessary +(i.e. to change the number of stubs or to change their specific declaration) +using the Perl script xptcall/public/genstubs.pl. + +

+ +Here are examples of this implementation for Win32 +and Linux x86, NetBSD x86, and FreeBSD. +Both of these examples use inline assembly language. That is just how I +decided to do it. You can do it as you choose. + +

+ +The Win32 version is somewhat tighter because the __declspec(naked) feature +allows for very small stubs. However, the __stdcall requires the callee to clean +up the stack, so it is imperative that the interface information scheme allow +the code to determine the correct stack pointer fixup for return without fail, +else the process will crash. + +

+ +I opted to use inline assembler for the gcc Linux x86 port. I ended up with +larger stubs than I would have preferred rather than battle the compiler over +what would happen to the stack before my asm code began running. + +

+ +I believe that the non-assembly parts of these files can be copied and reused +with minimal (but not zero) platform specific tweaks. Feel free to copy and +paste as necessary. Please remember that safety and reliability are more +important than speed optimizations. This code is primarily used to connect XPCOM +components with JavaScript; function call overhead is a tiny part of the +time involved. + +

+ +I put together +xptcall/src/md/test + as a place to evolve the basic functionality as a port is coming together. +Not all of the functionality is exercised, but it is a place to get started. +xptcall/tests + has an api level test for XPTC_InvokeByIndex, but no tests for +the stubs functionality. Such a test ought to be written, but this has not +yet been done. + +

+ +A full 'test' at this point requires building the client and running the +XPConnect test called TestXPC in +mozilla/js/src/xpconnect/tests +. + +

+ +Getting these ports done is very important. Please let me know if you are interested in doing one. +I'll answer any questions as I get them. + +

+ + +Porting Status + + +

+ +
+Author: John Bandhauer <jband@netscape.com>
+Last modified: 31 May 1999 + + + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/public/.cvsignore b/src/libs/xpcom18a4/xpcom/reflect/xptcall/public/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/public/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/public/Makefile.in b/src/libs/xpcom18a4/xpcom/reflect/xptcall/public/Makefile.in new file mode 100644 index 00000000..ac8432af --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/public/Makefile.in @@ -0,0 +1,54 @@ +# +# ***** 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.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of 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 ***** + +DEPTH = ../../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = xpcom + +EXPORTS = \ + xptcall.h \ + xptcstubsdecl.inc \ + xptcstubsdef.inc \ + $(NULL) + +include $(topsrcdir)/config/rules.mk + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/public/genstubs.pl b/src/libs/xpcom18a4/xpcom/reflect/xptcall/public/genstubs.pl new file mode 100755 index 00000000..b8962930 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/public/genstubs.pl @@ -0,0 +1,78 @@ +#!/usr/local/bin/perl + +# This is used to generate stub entry points. We generate a file to +# be included in the declaraion and a file to be used for expanding macros +# to represent the implementation of the stubs. + +# +# if "$entry_count" is ever changed and the .inc files regenerated then +# the following issues need to be addressed: +# +# 1) Alpha NT has a .def file that lists exports by symbol. It will need +# updating. +# 2) The current Linux ARM code has a limitation of only having 256-3 stubs +# +# more dependencies??? +# + +# 3 entries are already 'used' by the 3 methods of nsISupports. +# 3+247+5=255 This should get us in under the Linux ARM limitation +$entry_count = 247; +$sentinel_count = 5; + +$decl_name = "xptcstubsdecl.inc"; +$def_name = "xptcstubsdef.inc"; + +## +## Write the declarations include file +## + +die "Can't open $decl_name" if !open(OUTFILE, ">$decl_name"); + +print OUTFILE "/* generated file - DO NOT EDIT */\n\n"; +print OUTFILE "/* includes ",$entry_count," stub entries, and ", + $sentinel_count," sentinel entries */\n\n"; +print OUTFILE "/*\n"; +print OUTFILE "* declarations of normal stubs...\n"; +print OUTFILE "* 0 is QueryInterface\n"; +print OUTFILE "* 1 is AddRef\n"; +print OUTFILE "* 2 is Release\n"; +print OUTFILE "*/\n"; +print OUTFILE "#if !defined(__ia64) || (!defined(__hpux) && !defined(__linux__))\n"; +for($i = 0; $i < $entry_count; $i++) { + print OUTFILE "NS_IMETHOD Stub",$i+3,"();\n"; +} +print OUTFILE "#else\n"; +for($i = 0; $i < $entry_count; $i++) { + print OUTFILE "NS_IMETHOD Stub",$i+3,"(PRUint64,\n"; + print OUTFILE " PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64);\n"; + +} +print OUTFILE "#endif\n"; + +print OUTFILE "\n/* declarations of sentinel stubs */\n"; + +for($i = 0; $i < $sentinel_count; $i++) { + print OUTFILE "NS_IMETHOD Sentinel",$i,"();\n"; +} +close(OUTFILE); + + +## +## Write the definitions include file. This assumes a macro will be used to +## expand the entries written... +## + +die "Can't open $def_name" if !open(OUTFILE, ">$def_name"); + +print OUTFILE "/* generated file - DO NOT EDIT */\n\n"; +print OUTFILE "/* includes ",$entry_count," stub entries, and ", + $sentinel_count," sentinel entries */\n\n"; + +for($i = 0; $i < $entry_count; $i++) { + print OUTFILE "STUB_ENTRY(",$i+3,")\n"; +} + +for($i = 0; $i < $sentinel_count; $i++) { + print OUTFILE "SENTINEL_ENTRY(",$i,")\n"; +} diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/public/xptcall.h b/src/libs/xpcom18a4/xpcom/reflect/xptcall/public/xptcall.h new file mode 100644 index 00000000..153a047e --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/public/xptcall.h @@ -0,0 +1,271 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Public declarations for xptcall. */ + +#ifndef xptcall_h___ +#define xptcall_h___ + +#include "prtypes.h" +#include "nscore.h" +#include "nsISupports.h" +#include "xpt_struct.h" +#include "xptinfo.h" +#include "nsIInterfaceInfo.h" + +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +#define XPTC_InvokeByIndex VBoxNsxpXPTC_InvokeByIndex +#endif /* VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + +/***************************************************************************/ +/* + * The linkage of XPTC API functions differs depending on whether the file is + * used within the XPTC library or not. Any source file within the XPTC + * library should define EXPORT_XPTC_API whereas any client of the library + * should not. + */ +#ifdef EXPORT_XPTC_API +#define XPTC_PUBLIC_API(t) PR_IMPLEMENT(t) +#define XPTC_PUBLIC_DATA(t) PR_IMPLEMENT_DATA(t) +#if defined(_WIN32) +# define XPTC_EXPORT __declspec(dllexport) +#elif defined(XP_OS2) && defined(__declspec) +# define XPTC_EXPORT __declspec(dllexport) +#elif defined(XP_OS2_VACPP) +# define XPTC_EXPORT extern +#else +# ifdef VBOX_HAVE_VISIBILITY_HIDDEN +# define XPTC_EXPORT __attribute__((visibility("default"))) +# else +# define XPTC_EXPORT +# endif +#endif +#else +#if defined(_WIN32) +# define XPTC_PUBLIC_API(t) __declspec(dllimport) t +# define XPTC_PUBLIC_DATA(t) __declspec(dllimport) t +# define XPTC_EXPORT __declspec(dllimport) +#elif defined(XP_OS2) && defined(__declspec) +# define XPTC_PUBLIC_API(t) __declspec(dllimport) t +# define XPTC_PUBLIC_DATA(t) __declspec(dllimport) t +# define XPTC_EXPORT __declspec(dllimport) +#elif defined(XP_OS2_VACPP) +# define XPTC_PUBLIC_API(t) extern t +# define XPTC_PUBLIC_DATA(t) extern t +# define XPTC_EXPORT extern +#else +# define XPTC_PUBLIC_API(t) PR_IMPLEMENT(t) +# define XPTC_PUBLIC_DATA(t) t +# define XPTC_EXPORT +#endif +#endif +#define XPTC_FRIEND_API(t) XPTC_PUBLIC_API(t) +#define XPTC_FRIEND_DATA(t) XPTC_PUBLIC_DATA(t) +/***************************************************************************/ + +struct nsXPTCMiniVariant +{ +// No ctors or dtors so that we can use arrays of these on the stack +// with no penalty. + union + { + PRInt8 i8; + PRInt16 i16; + PRInt32 i32; + PRInt64 i64; + PRUint8 u8; + PRUint16 u16; + PRUint32 u32; + PRUint64 u64; + float f; + double d; + PRBool b; + char c; + PRUnichar wc; + void* p; + } val; +}; + +struct nsXPTCVariant : public nsXPTCMiniVariant +{ +// No ctors or dtors so that we can use arrays of these on the stack +// with no penalty. + + // inherits 'val' here + void* ptr; + nsXPTType type; + PRUint8 flags; + + enum + { + // these are bitflags! + PTR_IS_DATA = 0x1, // ptr points to 'real' data in val + VAL_IS_ALLOCD = 0x2, // val.p holds alloc'd ptr that must be freed + VAL_IS_IFACE = 0x4, // val.p holds interface ptr that must be released + VAL_IS_ARRAY = 0x8, // val.p holds a pointer to an array needing cleanup + VAL_IS_DOMSTR = 0x10, // val.p holds a pointer to domstring needing cleanup + VAL_IS_UTF8STR = 0x20, // val.p holds a pointer to utf8string needing cleanup + VAL_IS_CSTR = 0x40 // val.p holds a pointer to cstring needing cleanup + }; + + /* VBox: Added to prevent -Wclass-memaccess warnings (nsXPTType has a constructor) in python/src/VariantUtils.cpp */ + nsXPTCVariant() : ptr(NULL), flags(0) + { + val.p = NULL; + type.flags = 0; /* stupid nsXPTType constructor only do random bytes (documented) */ + } + + void ClearFlags() {flags = 0;} + void SetPtrIsData() {flags |= PTR_IS_DATA;} + void SetValIsAllocated() {flags |= VAL_IS_ALLOCD;} + void SetValIsInterface() {flags |= VAL_IS_IFACE;} + void SetValIsArray() {flags |= VAL_IS_ARRAY;} + void SetValIsDOMString() {flags |= VAL_IS_DOMSTR;} + void SetValIsUTF8String() {flags |= VAL_IS_UTF8STR;} + void SetValIsCString() {flags |= VAL_IS_CSTR;} + + PRBool IsPtrData() const {return 0 != (flags & PTR_IS_DATA);} + PRBool IsValAllocated() const {return 0 != (flags & VAL_IS_ALLOCD);} + PRBool IsValInterface() const {return 0 != (flags & VAL_IS_IFACE);} + PRBool IsValArray() const {return 0 != (flags & VAL_IS_ARRAY);} + PRBool IsValDOMString() const {return 0 != (flags & VAL_IS_DOMSTR);} + PRBool IsValUTF8String() const {return 0 != (flags & VAL_IS_UTF8STR);} + PRBool IsValCString() const {return 0 != (flags & VAL_IS_CSTR);} +#ifdef VBOX + PRBool MustFreeVal() const {return 0 != (flags & ( VAL_IS_ALLOCD + | VAL_IS_IFACE + | VAL_IS_DOMSTR + | VAL_IS_UTF8STR + | VAL_IS_CSTR)); } +#endif + + void Init(const nsXPTCMiniVariant& mv, const nsXPTType& t, PRUint8 f) + { + type = t; + flags = f; + + if(f & PTR_IS_DATA) + { + ptr = mv.val.p; + val.p = nsnull; + } + else + { + ptr = nsnull; + switch(t.TagPart()) { + case nsXPTType::T_I8: val.i8 = mv.val.i8; break; + case nsXPTType::T_I16: val.i16 = mv.val.i16; break; + case nsXPTType::T_I32: val.i32 = mv.val.i32; break; + case nsXPTType::T_I64: val.i64 = mv.val.i64; break; + case nsXPTType::T_U8: val.u8 = mv.val.u8; break; + case nsXPTType::T_U16: val.u16 = mv.val.u16; break; + case nsXPTType::T_U32: val.u32 = mv.val.u32; break; + case nsXPTType::T_U64: val.u64 = mv.val.u64; break; + case nsXPTType::T_FLOAT: val.f = mv.val.f; break; + case nsXPTType::T_DOUBLE: val.d = mv.val.d; break; + case nsXPTType::T_BOOL: val.b = mv.val.b; break; + case nsXPTType::T_CHAR: val.c = mv.val.c; break; + case nsXPTType::T_WCHAR: val.wc = mv.val.wc; break; + case nsXPTType::T_VOID: /* fall through */ + case nsXPTType::T_IID: /* fall through */ + case nsXPTType::T_DOMSTRING: /* fall through */ + case nsXPTType::T_CHAR_STR: /* fall through */ + case nsXPTType::T_WCHAR_STR: /* fall through */ + case nsXPTType::T_INTERFACE: /* fall through */ + case nsXPTType::T_INTERFACE_IS: /* fall through */ + case nsXPTType::T_ARRAY: /* fall through */ + case nsXPTType::T_PSTRING_SIZE_IS: /* fall through */ + case nsXPTType::T_PWSTRING_SIZE_IS: /* fall through */ + case nsXPTType::T_UTF8STRING: /* fall through */ + case nsXPTType::T_CSTRING: /* fall through */ + default: val.p = mv.val.p; break; + } + } + } +}; + +/***************************************************************************/ + +#undef IMETHOD_VISIBILITY +#define IMETHOD_VISIBILITY NS_VISIBILITY_DEFAULT + +class XPTC_EXPORT nsXPTCStubBase : public nsISupports +{ +public: + // We are going to implement this to force the compiler to generate a + // vtbl for this class. Since this is overridden in the inheriting class + // we expect it to never be called. + // *This is needed by the Irix implementation.* + NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr); + + // Implement dummy constructor, destructor to workaround Solaris gcc 4.8.2 + // linking issue (see @bugref{5838}). + nsXPTCStubBase() {} + ~nsXPTCStubBase() {} + + // Include generated vtbl stub declarations. + // These are virtual and *also* implemented by this class.. +#include "xptcstubsdecl.inc" + + // The following methods must be provided by inheritor of this class. + + // return a refcounted pointer to the InterfaceInfo for this object + // NOTE: on some platforms this MUST not fail or we crash! + NS_IMETHOD GetInterfaceInfo(nsIInterfaceInfo** info) = 0; + + // call this method and return result + NS_IMETHOD CallMethod(PRUint16 methodIndex, + const nsXPTMethodInfo* info, + nsXPTCMiniVariant* params) = 0; +}; + +#undef IMETHOD_VISIBILITY +#define IMETHOD_VISIBILITY NS_VISIBILITY_HIDDEN + +PR_BEGIN_EXTERN_C + +XPTC_PUBLIC_API(nsresult) +XPTC_InvokeByIndex(nsISupports* that, PRUint32 methodIndex, + PRUint32 paramCount, nsXPTCVariant* params); + +// Used to force linking of these obj for the static library into the dll +extern void xptc_dummy(); +extern void xptc_dummy2(); + +PR_END_EXTERN_C + +#endif /* xptcall_h___ */ diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/public/xptcstubsdecl.inc b/src/libs/xpcom18a4/xpcom/reflect/xptcall/public/xptcstubsdecl.inc new file mode 100644 index 00000000..99116d68 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/public/xptcstubsdecl.inc @@ -0,0 +1,761 @@ +/* generated file - DO NOT EDIT */ + +/* includes 247 stub entries, and 5 sentinel entries */ + +/* +* declarations of normal stubs... +* 0 is QueryInterface +* 1 is AddRef +* 2 is Release +*/ +#if !defined(__ia64) || (!defined(__hpux) && !defined(__linux__)) +NS_IMETHOD Stub3(); +NS_IMETHOD Stub4(); +NS_IMETHOD Stub5(); +NS_IMETHOD Stub6(); +NS_IMETHOD Stub7(); +NS_IMETHOD Stub8(); +NS_IMETHOD Stub9(); +NS_IMETHOD Stub10(); +NS_IMETHOD Stub11(); +NS_IMETHOD Stub12(); +NS_IMETHOD Stub13(); +NS_IMETHOD Stub14(); +NS_IMETHOD Stub15(); +NS_IMETHOD Stub16(); +NS_IMETHOD Stub17(); +NS_IMETHOD Stub18(); +NS_IMETHOD Stub19(); +NS_IMETHOD Stub20(); +NS_IMETHOD Stub21(); +NS_IMETHOD Stub22(); +NS_IMETHOD Stub23(); +NS_IMETHOD Stub24(); +NS_IMETHOD Stub25(); +NS_IMETHOD Stub26(); +NS_IMETHOD Stub27(); +NS_IMETHOD Stub28(); +NS_IMETHOD Stub29(); +NS_IMETHOD Stub30(); +NS_IMETHOD Stub31(); +NS_IMETHOD Stub32(); +NS_IMETHOD Stub33(); +NS_IMETHOD Stub34(); +NS_IMETHOD Stub35(); +NS_IMETHOD Stub36(); +NS_IMETHOD Stub37(); +NS_IMETHOD Stub38(); +NS_IMETHOD Stub39(); +NS_IMETHOD Stub40(); +NS_IMETHOD Stub41(); +NS_IMETHOD Stub42(); +NS_IMETHOD Stub43(); +NS_IMETHOD Stub44(); +NS_IMETHOD Stub45(); +NS_IMETHOD Stub46(); +NS_IMETHOD Stub47(); +NS_IMETHOD Stub48(); +NS_IMETHOD Stub49(); +NS_IMETHOD Stub50(); +NS_IMETHOD Stub51(); +NS_IMETHOD Stub52(); +NS_IMETHOD Stub53(); +NS_IMETHOD Stub54(); +NS_IMETHOD Stub55(); +NS_IMETHOD Stub56(); +NS_IMETHOD Stub57(); +NS_IMETHOD Stub58(); +NS_IMETHOD Stub59(); +NS_IMETHOD Stub60(); +NS_IMETHOD Stub61(); +NS_IMETHOD Stub62(); +NS_IMETHOD Stub63(); +NS_IMETHOD Stub64(); +NS_IMETHOD Stub65(); +NS_IMETHOD Stub66(); +NS_IMETHOD Stub67(); +NS_IMETHOD Stub68(); +NS_IMETHOD Stub69(); +NS_IMETHOD Stub70(); +NS_IMETHOD Stub71(); +NS_IMETHOD Stub72(); +NS_IMETHOD Stub73(); +NS_IMETHOD Stub74(); +NS_IMETHOD Stub75(); +NS_IMETHOD Stub76(); +NS_IMETHOD Stub77(); +NS_IMETHOD Stub78(); +NS_IMETHOD Stub79(); +NS_IMETHOD Stub80(); +NS_IMETHOD Stub81(); +NS_IMETHOD Stub82(); +NS_IMETHOD Stub83(); +NS_IMETHOD Stub84(); +NS_IMETHOD Stub85(); +NS_IMETHOD Stub86(); +NS_IMETHOD Stub87(); +NS_IMETHOD Stub88(); +NS_IMETHOD Stub89(); +NS_IMETHOD Stub90(); +NS_IMETHOD Stub91(); +NS_IMETHOD Stub92(); +NS_IMETHOD Stub93(); +NS_IMETHOD Stub94(); +NS_IMETHOD Stub95(); +NS_IMETHOD Stub96(); +NS_IMETHOD Stub97(); +NS_IMETHOD Stub98(); +NS_IMETHOD Stub99(); +NS_IMETHOD Stub100(); +NS_IMETHOD Stub101(); +NS_IMETHOD Stub102(); +NS_IMETHOD Stub103(); +NS_IMETHOD Stub104(); +NS_IMETHOD Stub105(); +NS_IMETHOD Stub106(); +NS_IMETHOD Stub107(); +NS_IMETHOD Stub108(); +NS_IMETHOD Stub109(); +NS_IMETHOD Stub110(); +NS_IMETHOD Stub111(); +NS_IMETHOD Stub112(); +NS_IMETHOD Stub113(); +NS_IMETHOD Stub114(); +NS_IMETHOD Stub115(); +NS_IMETHOD Stub116(); +NS_IMETHOD Stub117(); +NS_IMETHOD Stub118(); +NS_IMETHOD Stub119(); +NS_IMETHOD Stub120(); +NS_IMETHOD Stub121(); +NS_IMETHOD Stub122(); +NS_IMETHOD Stub123(); +NS_IMETHOD Stub124(); +NS_IMETHOD Stub125(); +NS_IMETHOD Stub126(); +NS_IMETHOD Stub127(); +NS_IMETHOD Stub128(); +NS_IMETHOD Stub129(); +NS_IMETHOD Stub130(); +NS_IMETHOD Stub131(); +NS_IMETHOD Stub132(); +NS_IMETHOD Stub133(); +NS_IMETHOD Stub134(); +NS_IMETHOD Stub135(); +NS_IMETHOD Stub136(); +NS_IMETHOD Stub137(); +NS_IMETHOD Stub138(); +NS_IMETHOD Stub139(); +NS_IMETHOD Stub140(); +NS_IMETHOD Stub141(); +NS_IMETHOD Stub142(); +NS_IMETHOD Stub143(); +NS_IMETHOD Stub144(); +NS_IMETHOD Stub145(); +NS_IMETHOD Stub146(); +NS_IMETHOD Stub147(); +NS_IMETHOD Stub148(); +NS_IMETHOD Stub149(); +NS_IMETHOD Stub150(); +NS_IMETHOD Stub151(); +NS_IMETHOD Stub152(); +NS_IMETHOD Stub153(); +NS_IMETHOD Stub154(); +NS_IMETHOD Stub155(); +NS_IMETHOD Stub156(); +NS_IMETHOD Stub157(); +NS_IMETHOD Stub158(); +NS_IMETHOD Stub159(); +NS_IMETHOD Stub160(); +NS_IMETHOD Stub161(); +NS_IMETHOD Stub162(); +NS_IMETHOD Stub163(); +NS_IMETHOD Stub164(); +NS_IMETHOD Stub165(); +NS_IMETHOD Stub166(); +NS_IMETHOD Stub167(); +NS_IMETHOD Stub168(); +NS_IMETHOD Stub169(); +NS_IMETHOD Stub170(); +NS_IMETHOD Stub171(); +NS_IMETHOD Stub172(); +NS_IMETHOD Stub173(); +NS_IMETHOD Stub174(); +NS_IMETHOD Stub175(); +NS_IMETHOD Stub176(); +NS_IMETHOD Stub177(); +NS_IMETHOD Stub178(); +NS_IMETHOD Stub179(); +NS_IMETHOD Stub180(); +NS_IMETHOD Stub181(); +NS_IMETHOD Stub182(); +NS_IMETHOD Stub183(); +NS_IMETHOD Stub184(); +NS_IMETHOD Stub185(); +NS_IMETHOD Stub186(); +NS_IMETHOD Stub187(); +NS_IMETHOD Stub188(); +NS_IMETHOD Stub189(); +NS_IMETHOD Stub190(); +NS_IMETHOD Stub191(); +NS_IMETHOD Stub192(); +NS_IMETHOD Stub193(); +NS_IMETHOD Stub194(); +NS_IMETHOD Stub195(); +NS_IMETHOD Stub196(); +NS_IMETHOD Stub197(); +NS_IMETHOD Stub198(); +NS_IMETHOD Stub199(); +NS_IMETHOD Stub200(); +NS_IMETHOD Stub201(); +NS_IMETHOD Stub202(); +NS_IMETHOD Stub203(); +NS_IMETHOD Stub204(); +NS_IMETHOD Stub205(); +NS_IMETHOD Stub206(); +NS_IMETHOD Stub207(); +NS_IMETHOD Stub208(); +NS_IMETHOD Stub209(); +NS_IMETHOD Stub210(); +NS_IMETHOD Stub211(); +NS_IMETHOD Stub212(); +NS_IMETHOD Stub213(); +NS_IMETHOD Stub214(); +NS_IMETHOD Stub215(); +NS_IMETHOD Stub216(); +NS_IMETHOD Stub217(); +NS_IMETHOD Stub218(); +NS_IMETHOD Stub219(); +NS_IMETHOD Stub220(); +NS_IMETHOD Stub221(); +NS_IMETHOD Stub222(); +NS_IMETHOD Stub223(); +NS_IMETHOD Stub224(); +NS_IMETHOD Stub225(); +NS_IMETHOD Stub226(); +NS_IMETHOD Stub227(); +NS_IMETHOD Stub228(); +NS_IMETHOD Stub229(); +NS_IMETHOD Stub230(); +NS_IMETHOD Stub231(); +NS_IMETHOD Stub232(); +NS_IMETHOD Stub233(); +NS_IMETHOD Stub234(); +NS_IMETHOD Stub235(); +NS_IMETHOD Stub236(); +NS_IMETHOD Stub237(); +NS_IMETHOD Stub238(); +NS_IMETHOD Stub239(); +NS_IMETHOD Stub240(); +NS_IMETHOD Stub241(); +NS_IMETHOD Stub242(); +NS_IMETHOD Stub243(); +NS_IMETHOD Stub244(); +NS_IMETHOD Stub245(); +NS_IMETHOD Stub246(); +NS_IMETHOD Stub247(); +NS_IMETHOD Stub248(); +NS_IMETHOD Stub249(); +#else +NS_IMETHOD Stub3(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub4(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub5(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub6(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub7(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub8(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub9(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub10(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub11(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub12(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub13(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub14(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub15(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub16(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub17(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub18(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub19(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub20(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub21(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub22(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub23(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub24(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub25(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub26(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub27(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub28(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub29(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub30(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub31(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub32(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub33(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub34(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub35(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub36(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub37(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub38(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub39(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub40(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub41(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub42(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub43(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub44(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub45(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub46(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub47(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub48(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub49(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub50(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub51(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub52(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub53(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub54(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub55(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub56(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub57(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub58(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub59(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub60(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub61(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub62(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub63(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub64(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub65(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub66(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub67(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub68(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub69(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub70(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub71(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub72(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub73(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub74(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub75(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub76(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub77(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub78(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub79(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub80(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub81(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub82(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub83(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub84(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub85(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub86(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub87(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub88(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub89(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub90(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub91(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub92(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub93(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub94(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub95(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub96(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub97(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub98(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub99(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub100(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub101(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub102(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub103(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub104(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub105(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub106(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub107(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub108(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub109(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub110(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub111(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub112(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub113(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub114(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub115(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub116(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub117(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub118(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub119(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub120(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub121(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub122(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub123(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub124(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub125(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub126(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub127(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub128(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub129(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub130(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub131(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub132(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub133(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub134(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub135(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub136(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub137(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub138(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub139(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub140(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub141(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub142(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub143(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub144(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub145(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub146(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub147(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub148(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub149(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub150(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub151(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub152(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub153(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub154(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub155(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub156(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub157(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub158(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub159(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub160(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub161(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub162(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub163(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub164(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub165(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub166(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub167(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub168(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub169(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub170(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub171(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub172(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub173(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub174(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub175(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub176(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub177(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub178(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub179(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub180(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub181(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub182(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub183(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub184(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub185(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub186(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub187(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub188(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub189(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub190(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub191(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub192(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub193(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub194(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub195(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub196(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub197(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub198(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub199(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub200(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub201(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub202(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub203(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub204(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub205(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub206(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub207(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub208(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub209(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub210(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub211(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub212(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub213(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub214(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub215(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub216(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub217(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub218(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub219(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub220(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub221(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub222(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub223(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub224(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub225(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub226(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub227(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub228(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub229(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub230(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub231(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub232(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub233(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub234(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub235(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub236(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub237(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub238(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub239(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub240(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub241(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub242(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub243(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub244(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub245(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub246(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub247(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub248(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub249(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +#endif + +/* declarations of sentinel stubs */ +NS_IMETHOD Sentinel0(); +NS_IMETHOD Sentinel1(); +NS_IMETHOD Sentinel2(); +NS_IMETHOD Sentinel3(); +NS_IMETHOD Sentinel4(); diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/public/xptcstubsdef.inc b/src/libs/xpcom18a4/xpcom/reflect/xptcall/public/xptcstubsdef.inc new file mode 100644 index 00000000..780e2f52 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/public/xptcstubsdef.inc @@ -0,0 +1,256 @@ +/* generated file - DO NOT EDIT */ + +/* includes 247 stub entries, and 5 sentinel entries */ + +STUB_ENTRY(3) +STUB_ENTRY(4) +STUB_ENTRY(5) +STUB_ENTRY(6) +STUB_ENTRY(7) +STUB_ENTRY(8) +STUB_ENTRY(9) +STUB_ENTRY(10) +STUB_ENTRY(11) +STUB_ENTRY(12) +STUB_ENTRY(13) +STUB_ENTRY(14) +STUB_ENTRY(15) +STUB_ENTRY(16) +STUB_ENTRY(17) +STUB_ENTRY(18) +STUB_ENTRY(19) +STUB_ENTRY(20) +STUB_ENTRY(21) +STUB_ENTRY(22) +STUB_ENTRY(23) +STUB_ENTRY(24) +STUB_ENTRY(25) +STUB_ENTRY(26) +STUB_ENTRY(27) +STUB_ENTRY(28) +STUB_ENTRY(29) +STUB_ENTRY(30) +STUB_ENTRY(31) +STUB_ENTRY(32) +STUB_ENTRY(33) +STUB_ENTRY(34) +STUB_ENTRY(35) +STUB_ENTRY(36) +STUB_ENTRY(37) +STUB_ENTRY(38) +STUB_ENTRY(39) +STUB_ENTRY(40) +STUB_ENTRY(41) +STUB_ENTRY(42) +STUB_ENTRY(43) +STUB_ENTRY(44) +STUB_ENTRY(45) +STUB_ENTRY(46) +STUB_ENTRY(47) +STUB_ENTRY(48) +STUB_ENTRY(49) +STUB_ENTRY(50) +STUB_ENTRY(51) +STUB_ENTRY(52) +STUB_ENTRY(53) +STUB_ENTRY(54) +STUB_ENTRY(55) +STUB_ENTRY(56) +STUB_ENTRY(57) +STUB_ENTRY(58) +STUB_ENTRY(59) +STUB_ENTRY(60) +STUB_ENTRY(61) +STUB_ENTRY(62) +STUB_ENTRY(63) +STUB_ENTRY(64) +STUB_ENTRY(65) +STUB_ENTRY(66) +STUB_ENTRY(67) +STUB_ENTRY(68) +STUB_ENTRY(69) +STUB_ENTRY(70) +STUB_ENTRY(71) +STUB_ENTRY(72) +STUB_ENTRY(73) +STUB_ENTRY(74) +STUB_ENTRY(75) +STUB_ENTRY(76) +STUB_ENTRY(77) +STUB_ENTRY(78) +STUB_ENTRY(79) +STUB_ENTRY(80) +STUB_ENTRY(81) +STUB_ENTRY(82) +STUB_ENTRY(83) +STUB_ENTRY(84) +STUB_ENTRY(85) +STUB_ENTRY(86) +STUB_ENTRY(87) +STUB_ENTRY(88) +STUB_ENTRY(89) +STUB_ENTRY(90) +STUB_ENTRY(91) +STUB_ENTRY(92) +STUB_ENTRY(93) +STUB_ENTRY(94) +STUB_ENTRY(95) +STUB_ENTRY(96) +STUB_ENTRY(97) +STUB_ENTRY(98) +STUB_ENTRY(99) +STUB_ENTRY(100) +STUB_ENTRY(101) +STUB_ENTRY(102) +STUB_ENTRY(103) +STUB_ENTRY(104) +STUB_ENTRY(105) +STUB_ENTRY(106) +STUB_ENTRY(107) +STUB_ENTRY(108) +STUB_ENTRY(109) +STUB_ENTRY(110) +STUB_ENTRY(111) +STUB_ENTRY(112) +STUB_ENTRY(113) +STUB_ENTRY(114) +STUB_ENTRY(115) +STUB_ENTRY(116) +STUB_ENTRY(117) +STUB_ENTRY(118) +STUB_ENTRY(119) +STUB_ENTRY(120) +STUB_ENTRY(121) +STUB_ENTRY(122) +STUB_ENTRY(123) +STUB_ENTRY(124) +STUB_ENTRY(125) +STUB_ENTRY(126) +STUB_ENTRY(127) +STUB_ENTRY(128) +STUB_ENTRY(129) +STUB_ENTRY(130) +STUB_ENTRY(131) +STUB_ENTRY(132) +STUB_ENTRY(133) +STUB_ENTRY(134) +STUB_ENTRY(135) +STUB_ENTRY(136) +STUB_ENTRY(137) +STUB_ENTRY(138) +STUB_ENTRY(139) +STUB_ENTRY(140) +STUB_ENTRY(141) +STUB_ENTRY(142) +STUB_ENTRY(143) +STUB_ENTRY(144) +STUB_ENTRY(145) +STUB_ENTRY(146) +STUB_ENTRY(147) +STUB_ENTRY(148) +STUB_ENTRY(149) +STUB_ENTRY(150) +STUB_ENTRY(151) +STUB_ENTRY(152) +STUB_ENTRY(153) +STUB_ENTRY(154) +STUB_ENTRY(155) +STUB_ENTRY(156) +STUB_ENTRY(157) +STUB_ENTRY(158) +STUB_ENTRY(159) +STUB_ENTRY(160) +STUB_ENTRY(161) +STUB_ENTRY(162) +STUB_ENTRY(163) +STUB_ENTRY(164) +STUB_ENTRY(165) +STUB_ENTRY(166) +STUB_ENTRY(167) +STUB_ENTRY(168) +STUB_ENTRY(169) +STUB_ENTRY(170) +STUB_ENTRY(171) +STUB_ENTRY(172) +STUB_ENTRY(173) +STUB_ENTRY(174) +STUB_ENTRY(175) +STUB_ENTRY(176) +STUB_ENTRY(177) +STUB_ENTRY(178) +STUB_ENTRY(179) +STUB_ENTRY(180) +STUB_ENTRY(181) +STUB_ENTRY(182) +STUB_ENTRY(183) +STUB_ENTRY(184) +STUB_ENTRY(185) +STUB_ENTRY(186) +STUB_ENTRY(187) +STUB_ENTRY(188) +STUB_ENTRY(189) +STUB_ENTRY(190) +STUB_ENTRY(191) +STUB_ENTRY(192) +STUB_ENTRY(193) +STUB_ENTRY(194) +STUB_ENTRY(195) +STUB_ENTRY(196) +STUB_ENTRY(197) +STUB_ENTRY(198) +STUB_ENTRY(199) +STUB_ENTRY(200) +STUB_ENTRY(201) +STUB_ENTRY(202) +STUB_ENTRY(203) +STUB_ENTRY(204) +STUB_ENTRY(205) +STUB_ENTRY(206) +STUB_ENTRY(207) +STUB_ENTRY(208) +STUB_ENTRY(209) +STUB_ENTRY(210) +STUB_ENTRY(211) +STUB_ENTRY(212) +STUB_ENTRY(213) +STUB_ENTRY(214) +STUB_ENTRY(215) +STUB_ENTRY(216) +STUB_ENTRY(217) +STUB_ENTRY(218) +STUB_ENTRY(219) +STUB_ENTRY(220) +STUB_ENTRY(221) +STUB_ENTRY(222) +STUB_ENTRY(223) +STUB_ENTRY(224) +STUB_ENTRY(225) +STUB_ENTRY(226) +STUB_ENTRY(227) +STUB_ENTRY(228) +STUB_ENTRY(229) +STUB_ENTRY(230) +STUB_ENTRY(231) +STUB_ENTRY(232) +STUB_ENTRY(233) +STUB_ENTRY(234) +STUB_ENTRY(235) +STUB_ENTRY(236) +STUB_ENTRY(237) +STUB_ENTRY(238) +STUB_ENTRY(239) +STUB_ENTRY(240) +STUB_ENTRY(241) +STUB_ENTRY(242) +STUB_ENTRY(243) +STUB_ENTRY(244) +STUB_ENTRY(245) +STUB_ENTRY(246) +STUB_ENTRY(247) +STUB_ENTRY(248) +STUB_ENTRY(249) +SENTINEL_ENTRY(0) +SENTINEL_ENTRY(1) +SENTINEL_ENTRY(2) +SENTINEL_ENTRY(3) +SENTINEL_ENTRY(4) diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/.cvsignore b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/Makefile.in b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/Makefile.in new file mode 100644 index 00000000..987fc505 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/Makefile.in @@ -0,0 +1,62 @@ +# +# ***** 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.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of 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 ***** + +DEPTH = ../../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = xpcom +LIBRARY_NAME = xptcall + + +DIRS = md + +CPPSRCS = xptcall.cpp + +# we don't want the shared lib, but we want to force the creation of a static lib. +FORCE_STATIC_LIB = 1 + +# Force use of PIC +FORCE_USE_PIC = 1 + +include $(topsrcdir)/config/rules.mk + +DEFINES += -DEXPORT_XPTC_API -D_IMPL_NS_COM -D_IMPL_NS_BASE + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/Makefile.kup b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/Makefile.kup new file mode 100644 index 00000000..e69de29b diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/.cvsignore b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/Makefile.in b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/Makefile.in new file mode 100644 index 00000000..dd70cabf --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/Makefile.in @@ -0,0 +1,56 @@ +# +# ***** 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.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of 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 ***** + +DEPTH = ../../../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +ifeq ($(MOZ_WIDGET_TOOLKIT),os2) +DIRS = os2 +else +ifeq ($(MOZ_WIDGET_TOOLKIT),windows) +DIRS = win32 +else +DIRS = unix +endif +endif + +include $(topsrcdir)/config/rules.mk + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/Makefile.kup b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/Makefile.kup new file mode 100644 index 00000000..e69de29b diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/mac/xptcinvoke_mac.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/mac/xptcinvoke_mac.cpp new file mode 100644 index 00000000..29343c08 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/mac/xptcinvoke_mac.cpp @@ -0,0 +1,148 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Platform specific code to invoke XPCOM methods on native objects */ + +#include "xptcprivate.h" + +#ifndef XP_MAC +#error "This code is for Macintosh only" +#endif + +extern "C" uint32 +invoke_count_words(PRUint32 paramCount, nsXPTCVariant* s) +{ + PRUint32 result = 0; + for(PRUint32 i = 0; i < paramCount; i++, s++) + { + if(s->IsPtrData()) + { + result++; + continue; + } + switch(s->type) + { + case nsXPTType::T_I8 : + case nsXPTType::T_I16 : + case nsXPTType::T_I32 : + result++; + break; + case nsXPTType::T_I64 : + result+=2; + break; + case nsXPTType::T_U8 : + case nsXPTType::T_U16 : + case nsXPTType::T_U32 : + result++; + break; + case nsXPTType::T_U64 : + result+=2; + break; + case nsXPTType::T_FLOAT : + result++; + break; + case nsXPTType::T_DOUBLE : + result+=2; + break; + case nsXPTType::T_BOOL : + case nsXPTType::T_CHAR : + case nsXPTType::T_WCHAR : + result++; + break; + default: + // all the others are plain pointer types + result++; + break; + } + } + return result; +} + +extern "C" void +invoke_copy_to_stack(PRUint32* d, PRUint32 paramCount, nsXPTCVariant* s, double *fprData) +{ + PRUint32 fpCount = 0; + for(PRUint32 i = 0; i < paramCount; i++, d++, s++) + { + if(s->IsPtrData()) + { + *((void**)d) = s->ptr; + continue; + } + switch(s->type) + { + case nsXPTType::T_I8 : *((PRInt32*) d) = s->val.i8; break; + case nsXPTType::T_I16 : *((PRInt32*) d) = s->val.i16; break; + case nsXPTType::T_I32 : *((PRInt32*) d) = s->val.i32; break; + case nsXPTType::T_I64 : *((PRInt64*) d) = s->val.i64; d++; break; + case nsXPTType::T_U8 : *((PRUint32*) d) = s->val.u8; break; + case nsXPTType::T_U16 : *((PRUint32*)d) = s->val.u16; break; + case nsXPTType::T_U32 : *((PRUint32*)d) = s->val.u32; break; + case nsXPTType::T_U64 : *((PRUint64*)d) = s->val.u64; d++; break; + case nsXPTType::T_FLOAT : *((float*) d) = s->val.f; + if (fpCount < 13) + fprData[fpCount++] = s->val.f; + break; + case nsXPTType::T_DOUBLE : *((double*) d) = s->val.d; d++; + if (fpCount < 13) + fprData[fpCount++] = s->val.d; + break; + case nsXPTType::T_BOOL : *((PRBool*) d) = s->val.b; break; + case nsXPTType::T_CHAR : *((PRInt32*) d) = s->val.c; break; + case nsXPTType::T_WCHAR : *((PRUint32*) d) = s->val.wc; break; + default: + // all the others are plain pointer types + *((void**)d) = s->val.p; + break; + } + } +} + +#pragma export on + +extern "C" nsresult _XPTC_InvokeByIndex(nsISupports* that, PRUint32 methodIndex, + PRUint32 paramCount, nsXPTCVariant* params); + +extern "C" +XPTC_PUBLIC_API(nsresult) +XPTC_InvokeByIndex(nsISupports* that, PRUint32 methodIndex, + PRUint32 paramCount, nsXPTCVariant* params) +{ + return _XPTC_InvokeByIndex(that, methodIndex, paramCount, params); +} + +#pragma export off diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/mac/xptcinvoke_mac.s b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/mac/xptcinvoke_mac.s new file mode 100644 index 00000000..47544dd3 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/mac/xptcinvoke_mac.s @@ -0,0 +1,128 @@ + # + # -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + # + # The contents of this file are subject to the Netscape 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/NPL/ + # + # 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.org code. + # + # The Initial Developer of the Original Code is Netscape + # Communications Corporation. Portions created by Netscape are + # Copyright (C) 1999 Netscape Communications Corporation. All + # Rights Reserved. + # + # Contributor(s): + # + + csect CODE{PR} +# +# XPTC_InvokeByIndex(nsISupports* that, PRUint32 methodIndex, +# PRUint32 paramCount, nsXPTCVariant* params) +# + + import .invoke_count_words + import .invoke_copy_to_stack + import .__ptr_glue + +._XPTC_InvokeByIndex: + mflr r0 + stw r31,-4(sp) +# +# save off the incoming values in the caller's parameter area +# + stw r3,24(sp) # that + stw r4,28(sp) # methodIndex + stw r5,32(sp) # paramCount + stw r6,36(sp) # params + stw r0,8(sp) + stwu sp,-144(sp) # = 24 for linkage area, 8 * 13 for fprData area, 8 for saved registers, + # 8 to keep stack 16-byte aligned. + +# set up for and call 'invoke_count_words' to get new stack size +# + mr r3,r5 + mr r4,r6 + bl .invoke_count_words + nop + +# prepare args for 'invoke_copy_to_stack' call +# + lwz r4,176(sp) # paramCount + lwz r5,180(sp) # params +# addi r6,sp,128 # fprData + mr r6,sp # fprData + slwi r3,r3,2 # number of bytes of stack required + addi r3,r3,28 # linkage area + mr r31,sp # save original stack top + sub sp,sp,r3 # bump the stack + clrrwi sp,sp,4 # keep the stack 16-byte aligned. + lwz r3,0(r31) # act like real alloca, so 0(sp) always points back to + stw r3,0(sp) # previous stack frame. + addi r3,sp,28 # parameter pointer excludes linkage area size + 'this' + + bl .invoke_copy_to_stack + nop + + lfd f1,0(r31) + lfd f2,8(r31) + lfd f3,16(r31) + lfd f4,24(r31) + lfd f5,32(r31) + lfd f6,40(r31) + lfd f7,48(r31) + lfd f8,56(r31) + lfd f9,64(r31) + lfd f10,72(r31) + lfd f11,80(r31) + lfd f12,88(r31) + lfd f13,96(r31) + + lwz r3,168(r31) # that + lwz r4,0(r3) # get vTable from 'that' + lwz r5,172(r31) # methodIndex + slwi r5,r5,2 # methodIndex * 4 + addi r5,r5,8 # step over junk at start of vTable ! + lwzx r12,r5,r4 # get function pointer + + lwz r4,28(sp) + lwz r5,32(sp) + lwz r6,36(sp) + lwz r7,40(sp) + lwz r8,44(sp) + lwz r9,48(sp) + lwz r10,52(sp) + + bl .__ptr_glue + nop + + + mr sp,r31 + lwz r0,152(sp) + addi sp,sp,144 + mtlr r0 + lwz r31,-4(sp) + blr + +# traceback table. + traceback: + dc.l 0 + dc.l 0x00002040 + dc.l 0 + dc.l (traceback - ._XPTC_InvokeByIndex) # size of the code. + dc.w 20 # short length of identifier. + dc.b '._XPTC_InvokeByIndex' + + csect DATA + import TOC + export ._XPTC_InvokeByIndex + + dc.l ._XPTC_InvokeByIndex + dc.l TOC + \ No newline at end of file diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/mac/xptcstubs_mac.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/mac/xptcstubs_mac.cpp new file mode 100644 index 00000000..3fea7d51 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/mac/xptcstubs_mac.cpp @@ -0,0 +1,265 @@ +/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Implement shared vtbl methods. */ + +#pragma export on + +#include "xptcprivate.h" + +#if defined(XP_MAC) + +/* + For mac, the first 8 integral and the first 13 f.p. parameters arrive + in a separate chunk of data that has been loaded from the registers. The + args pointer has been set to the start of the parameters BEYOND the ones + arriving in registers +*/ +extern "C" nsresult +PrepareAndDispatch(nsXPTCStubBase* self, PRUint32 methodIndex, PRUint32* args, PRUint32 *gprData, double *fprData) +{ +#define PARAM_BUFFER_COUNT 16 +#define PARAM_GPR_COUNT 7 + + nsXPTCMiniVariant paramBuffer[PARAM_BUFFER_COUNT]; + nsXPTCMiniVariant* dispatchParams = NULL; + nsIInterfaceInfo* iface_info = NULL; + const nsXPTMethodInfo* info; + PRUint8 paramCount; + PRUint8 i; + nsresult result = NS_ERROR_FAILURE; + + NS_ASSERTION(self,"no self"); + + self->GetInterfaceInfo(&iface_info); + NS_ASSERTION(iface_info,"no interface info"); + + iface_info->GetMethodInfo(PRUint16(methodIndex), &info); + NS_ASSERTION(info,"no interface info"); + + paramCount = info->GetParamCount(); + + // setup variant array pointer + if(paramCount > PARAM_BUFFER_COUNT) + dispatchParams = new nsXPTCMiniVariant[paramCount]; + else + dispatchParams = paramBuffer; + NS_ASSERTION(dispatchParams,"no place for params"); + + PRUint32* ap = args; + PRUint32 iCount = 0; + PRUint32 fpCount = 0; + for(i = 0; i < paramCount; i++) + { + const nsXPTParamInfo& param = info->GetParam(i); + const nsXPTType& type = param.GetType(); + nsXPTCMiniVariant* dp = &dispatchParams[i]; + + if(param.IsOut() || !type.IsArithmetic()) + { + if (iCount < PARAM_GPR_COUNT) + dp->val.p = (void*) gprData[iCount++]; + else + dp->val.p = (void*) *ap++; + continue; + } + // else + switch(type) + { + case nsXPTType::T_I8 : if (iCount < PARAM_GPR_COUNT) + dp->val.i8 = (PRInt8) gprData[iCount++]; + else + dp->val.i8 = (PRInt8) *ap++; + break; + case nsXPTType::T_I16 : if (iCount < PARAM_GPR_COUNT) + dp->val.i16 = (PRInt16) gprData[iCount++]; + else + dp->val.i16 = (PRInt16) *ap++; + break; + case nsXPTType::T_I32 : if (iCount < PARAM_GPR_COUNT) + dp->val.i32 = (PRInt32) gprData[iCount++]; + else + dp->val.i32 = (PRInt32) *ap++; + break; + case nsXPTType::T_I64 : +#ifdef HAVE_LONG_LONG + PRUint64 tempu64; + if (iCount & 1) iCount++; // longlongs are aligned in odd/even register pairs, eg. r5/r6 + if ((iCount + 1) < PARAM_GPR_COUNT) + { + tempu64 = *(PRUint64*) &gprData[iCount]; + iCount += 2; + } + else + { + if ((PRUint32) ap & 4) ap++; // longlongs are 8-byte aligned on stack + tempu64 = *(PRUint64*) ap; + ap += 2; + } + dp->val.i64 = (PRUint64)tempu64; +#else + if (iCount < PARAM_GPR_COUNT) + dp->val.i64.hi = (PRInt32) gprData[iCount++]; + else + dp->val.i64.hi = (PRInt32) *ap++; + if (iCount < PARAM_GPR_COUNT) + dp->val.i64.lo = (PRUint32) gprData[iCount++]; + else + dp->val.i64.lo = (PRUint32) *ap++; +#endif + break; + case nsXPTType::T_U8 : if (iCount < PARAM_GPR_COUNT) + dp->val.i8 = (PRUint8) gprData[iCount++]; + else + dp->val.i8 = (PRUint8) *ap++; + break; + case nsXPTType::T_U16 : if (iCount < PARAM_GPR_COUNT) + dp->val.i16 = (PRUint16) gprData[iCount++]; + else + dp->val.i16 = (PRUint16) *ap++; + break; + case nsXPTType::T_U32 : if (iCount < PARAM_GPR_COUNT) + dp->val.i32 = (PRUint32) gprData[iCount++]; + else + dp->val.i32 = (PRUint32) *ap++; + break; + case nsXPTType::T_U64 : +#ifdef HAVE_LONG_LONG + // PRUint64 tempu64; // declared above and still in scope + if (iCount & 1) iCount++; // longlongs are aligned in odd/even register pairs, eg. r5/r6 + if ((iCount + 1) < PARAM_GPR_COUNT) + { + tempu64 = *(PRUint64*) &gprData[iCount]; + iCount += 2; + } + else + { + if ((PRUint32) ap & 4) ap++; // longlongs are 8-byte aligned on stack + tempu64 = *(PRUint64*) ap; + ap += 2; + } + dp->val.i64 = (PRUint64)tempu64; +#else + if (iCount < PARAM_GPR_COUNT) + dp->val.i64.hi = (PRUint32) gprData[iCount++]; + else + dp->val.i64.hi = (PRUint32) *ap++; + if (iCount < PARAM_GPR_COUNT) + dp->val.i64.lo = (PRUint32) gprData[iCount++]; + else + dp->val.i64.lo = (PRUint32) *ap++; +#endif + break; + case nsXPTType::T_FLOAT : if (fpCount < 13) { + dp->val.f = (float) fprData[fpCount++]; + if (iCount < PARAM_GPR_COUNT) + ++iCount; + else + ++ap; + } + else + dp->val.f = *((float*) ap++); + break; + case nsXPTType::T_DOUBLE : if (fpCount < 13) { + dp->val.d = (double) fprData[fpCount++]; + if (iCount < PARAM_GPR_COUNT) + ++iCount; + else + ++ap; + if (iCount < PARAM_GPR_COUNT) + ++iCount; + else + ++ap; + } + else { + dp->val.f = *((double*) ap); + ap += 2; + } + break; + case nsXPTType::T_BOOL : if (iCount < PARAM_GPR_COUNT) + dp->val.b = (PRBool) gprData[iCount++]; + else + dp->val.b = (PRBool) *ap++; + break; + case nsXPTType::T_CHAR : if (iCount < PARAM_GPR_COUNT) + dp->val.c = (char) gprData[iCount++]; + else + dp->val.c = (char) *ap++; + break; + case nsXPTType::T_WCHAR : if (iCount < PARAM_GPR_COUNT) + dp->val.wc = (wchar_t) gprData[iCount++]; + else + dp->val.wc = (wchar_t) *ap++; + break; + default: + NS_ASSERTION(0, "bad type"); + break; + } + } + + result = self->CallMethod((PRUint16)methodIndex, info, dispatchParams); + + NS_RELEASE(iface_info); + + if(dispatchParams != paramBuffer) + delete [] dispatchParams; + + return result; +} + +extern "C" void SharedStub(); + +#define STUB_ENTRY(n) \ +asm nsresult nsXPTCStubBase::Stub##n() \ +{ \ + addi r12,r0,n; \ + b SharedStub \ +} + +#define SENTINEL_ENTRY(n) \ +nsresult nsXPTCStubBase::Sentinel##n() \ +{ \ + NS_ASSERTION(0,"nsXPTCStubBase::Sentinel called"); \ + return NS_ERROR_NOT_IMPLEMENTED; \ +} + + +#include "xptcstubsdef.inc" + +#pragma export off + +#endif diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/mac/xptcstubs_mac.s b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/mac/xptcstubs_mac.s new file mode 100644 index 00000000..d2f7185b --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/mac/xptcstubs_mac.s @@ -0,0 +1,78 @@ + # + # -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + # + # The contents of this file are subject to the Netscape 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/NPL/ + # + # 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.org code. + # + # The Initial Developer of the Original Code is Netscape + # Communications Corporation. Portions created by Netscape are + # Copyright (C) 1999 Netscape Communications Corporation. All + # Rights Reserved. + # + # Contributor(s): + # + + csect CODE{PR} +# +# on entry SharedStub has the method selector in r12, the rest of the original +# parameters are in r3 thru r10 and f1 thru f13 +# + import .PrepareAndDispatch + +.SharedStub: + mflr r0 + stw r0,8(sp) + + stwu sp,-176(sp) # room for linkage (24), fprData (104), gprData(28) + # outgoing params to PrepareAndDispatch (20) + + stw r4,44(sp) + stw r5,48(sp) + stw r6,52(sp) + stw r7,56(sp) + stw r8,60(sp) + stw r9,64(sp) + stw r10,68(sp) + stfd f1,72(sp) + stfd f2,80(sp) + stfd f3,88(sp) + stfd f4,96(sp) + stfd f5,104(sp) + stfd f6,112(sp) + stfd f7,120(sp) + stfd f8,128(sp) + stfd f9,136(sp) + stfd f10,144(sp) + stfd f11,152(sp) + stfd f12,156(sp) + stfd f13,164(sp) + + addi r6,sp,44 # gprData + addi r7,sp,72 # fprData + # r3 has the 'self' pointer already + mr r4,r12 # methodIndex selector + addi r5,sp,232 # pointer to callers args area, beyond r3-r10 mapped range + + bl .PrepareAndDispatch + nop + + lwz r0,184(sp) + addi sp,sp,176 + mtlr r0 + blr + + csect DATA + import TOC + export .SharedStub + + dc.l .SharedStub + dc.l TOC diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/os2/.cvsignore b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/os2/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/os2/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/os2/Makefile.in b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/os2/Makefile.in new file mode 100644 index 00000000..cfd57c83 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/os2/Makefile.in @@ -0,0 +1,72 @@ +# +# ***** 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.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of 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 ***** + +DEPTH = ../../../../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = xpcom +LIBRARY_NAME = xptcmd + +ifdef GNU_CXX +CPPSRCS = \ + ../unix/xptcinvoke_gcc_x86_unix.cpp \ + ../unix/xptcstubs_gcc_x86_unix.cpp \ + $(NULL) +LOCAL_INCLUDES = -I$(srcdir)/../unix +DEFINES += -DMOZ_NEED_LEADING_UNDERSCORE +else +CPPSRCS = xptcstubs_os2.cpp +ASFILES = xptcinvoke_vacpp.asm xptcstubs_vacpp.asm +endif + +# Force use of PIC +FORCE_USE_PIC = 1 + +include $(topsrcdir)/config/config.mk + +# we don't want the shared lib, but we want to force the creation of a static lib. +FORCE_STATIC_LIB = 1 + +include $(topsrcdir)/config/rules.mk + +DEFINES += -DEXPORT_XPTC_API + +INCLUDES += -I$(srcdir)/../.. diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/os2/xptcinvoke_emx.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/os2/xptcinvoke_emx.cpp new file mode 100644 index 00000000..17fcadfe --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/os2/xptcinvoke_emx.cpp @@ -0,0 +1,185 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * John Fairhurst + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** + * + * This Original Code has been modified by IBM Corporation. + * Modifications made by IBM described herein are + * Copyright (c) International Business Machines + * Corporation, 2000 + * + * Modifications to Mozilla code or documentation + * identified per MPL Section 3.3 + * + * Date Modified by Description of modification + * 03/22/2000 IBM Corp. Fixed multiple inheritance bug in XPTC_InvokeByIndex to adjust the + * "that" (this) pointer appropriately. + */ + +/* Platform specific code to invoke XPCOM methods on native objects */ + +// This is 80% copied directly from other platforms; the assembler +// stuff is all my fault, though. (jmf) + +#if !defined(__EMX__) +#error "This code is for OS/2 EMX only" +#endif + +#include "xptcprivate.h" + +// Remember that these 'words' are 32-bit DWORDs +static PRUint32 +invoke_count_words( PRUint32 paramCount, nsXPTCVariant* s) +{ + PRUint32 result = 0; + + for(PRUint32 i = 0; i < paramCount; i++, s++) + { + if(s->IsPtrData()) + result++; + + else { + + switch(s->type) + { + // 64-bit types + case nsXPTType::T_I64 : + case nsXPTType::T_U64 : + case nsXPTType::T_DOUBLE : + result+=2; + break; + + // all others are dwords + default: + result++; + break; + } + } + } + return result; +} + + +static void +invoke_copy_to_stack( PRUint32* d, uint32 paramCount, nsXPTCVariant* s) +{ + for( PRUint32 i = 0; i < paramCount; i++, d++, s++) + { + if(s->IsPtrData()) + *((void**)d) = s->ptr; + + else { + + switch(s->type) + { + case nsXPTType::T_I8 : *((int8*) d) = s->val.i8; break; + case nsXPTType::T_I16 : *((int16*) d) = s->val.i16; break; + case nsXPTType::T_I32 : *((int32*) d) = s->val.i32; break; + case nsXPTType::T_I64 : *((int64*) d) = s->val.i64; d++; break; + case nsXPTType::T_U8 : *((uint8*) d) = s->val.u8; break; + case nsXPTType::T_U16 : *((uint16*) d) = s->val.u16; break; + case nsXPTType::T_U32 : *((uint32*) d) = s->val.u32; break; + case nsXPTType::T_U64 : *((uint64*) d) = s->val.u64; d++; break; + case nsXPTType::T_FLOAT : *((float*) d) = s->val.f; break; + case nsXPTType::T_DOUBLE : *((double*) d) = s->val.d; d++; break; + case nsXPTType::T_BOOL : *((PRBool*) d) = s->val.b; break; + case nsXPTType::T_CHAR : *((char*) d) = s->val.c; break; + case nsXPTType::T_WCHAR : *((wchar_t*)d) = s->val.wc; break; + default: + // all the others are plain pointer types + *((void**)d) = s->val.p; + break; + } + } + } +} + + +XPTC_PUBLIC_API(nsresult) +XPTC_InvokeByIndex( nsISupports *that, PRUint32 index, + PRUint32 paramcount, nsXPTCVariant* params) +{ + int ibytes; + void *pStack; + int result = NS_OK; + + // Find size in bytes necessary for call + ibytes = 4 * invoke_count_words( paramcount, params); + + __asm__ __volatile__( + "movl %1, %%eax\n" /* load |ibytes| into eax */ + "subl %%eax, %%esp\n" /* make room on stack */ + "movl %%esp, %0" /* store base in |pStack| */ + : "=g" (pStack) /* %0 */ + : "g" (ibytes) /* %1 */ + : "ax", "memory", "sp" + ); + + // Fill in that gap in the stack with the params to the method + invoke_copy_to_stack( (PRUint32*) pStack, paramcount, params); + + // push the hidden 'this' parameter, traverse the vtable, + // and then call the method. + + __asm__ __volatile__( + "movl %2, %%eax\n" /* |that| ptr -> eax */ + "movl (%%eax), %%edx\n" /* vptr -> edx */ + "movl %3, %%ebx\n" + "shl $3, %%ebx\n" /* 8 bytes per method.. */ + "addl $8, %%ebx\n" /* ..plus 8 to skip over 1st 8 bytes of vtbl */ + + "addl %%ebx, %%edx\n" /* find appropriate vtbl entry */ + "movswl (%%edx),%%ecx\n" /* get possible |that| ptr adjustment value */ + "addl %%ecx, %%eax\n" /* adjust the |that| ptr (needed for multiple inheritance) */ + "pushl %%eax\n" /* enstack the possibly-adjusted |that| */ + + "addl $4, %%edx\n" /* ..add 4 more to get to the method's entry point */ + + "call (%%edx)\n" /* call method */ + "movl %%eax, %0\n" /* save rc in |result| */ + "movl %1, %%ebx\n" /* clear up stack */ + "addl $4, %%ebx\n" + "addl %%ebx, %%esp" + : "=g" (result) /* %0 */ + : "g" (ibytes), /* %1 */ + "g" (that), /* %2 */ + "g" (index) /* %3 */ + : "ax", "bx", "dx", "memory", "sp" + ); + + return result; +} diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/os2/xptcinvoke_gcc_x86_os2.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/os2/xptcinvoke_gcc_x86_os2.cpp new file mode 100644 index 00000000..6bbb93b0 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/os2/xptcinvoke_gcc_x86_os2.cpp @@ -0,0 +1,159 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Platform specific code to invoke XPCOM methods on native objects */ + +/* This file is basically a copy of xptcinvoke_gcc_x86_unix.cpp with some + * irrelevant parts stipped off and some OS/2 specific modifications added, + * so it needs to be kept in sync with the original. */ + +#include "xptcprivate.h" +#include "xptc_platforms_unixish_x86.h" +#include "xptc_gcc_x86_unix.h" + +extern "C" { +static +void ATTRIBUTE_USED __attribute__ ((regparm(3))) +invoke_copy_to_stack(PRUint32 paramCount, nsXPTCVariant* s, PRUint32* d) +{ + for(PRUint32 i = paramCount; i >0; i--, d++, s++) + { + if(s->IsPtrData()) + { + *((void**)d) = s->ptr; + continue; + } + + switch(s->type) + { + case nsXPTType::T_I64 : *((PRInt64*) d) = s->val.i64; d++; break; + case nsXPTType::T_U64 : *((PRUint64*)d) = s->val.u64; d++; break; + case nsXPTType::T_DOUBLE : *((double*) d) = s->val.d; d++; break; + default : *((void**)d) = s->val.p; break; + } + } +} +} // extern "C" + +/* + XPTC_PUBLIC_API(nsresult) + XPTC_InvokeByIndex(nsISupports* that, PRUint32 methodIndex, + PRUint32 paramCount, nsXPTCVariant* params); + + Each param takes at most two 4-byte words. + It doesn't matter if we push too many words, and calculating the exact + amount takes time. + + that = ebp + 0x08 + methodIndex = ebp + 0x0c + paramCount = ebp + 0x10 + params = ebp + 0x14 + + NOTE NOTE NOTE: + As of 2002-04-29 this function references no global variables nor does + it call non-static functions so preserving and loading the PIC register + is unnecessary. Define MOZ_PRESERVE_PIC if this changes. See mozilla + bug 140412 for details. However, avoid this if you can. It's slower. +*/ + +#if defined(__declspec) +#define SYMBOL_EXPORT(sym) \ + ".stabs \"" sym ",0=" sym ",code\", 0x6c,0,0,-42\n\t" +#else +#define SYMBOL_EXPORT(sym) +#endif + +__asm__ ( + ".text\n\t" +/* alignment here seems unimportant here; this was 16, now it's 2 which + is what xptcstubs uses. */ + ".align 2\n\t" + ".globl " SYMBOL_UNDERSCORE "XPTC_InvokeByIndex\n\t" + ".type " SYMBOL_UNDERSCORE "XPTC_InvokeByIndex,@function\n" + SYMBOL_EXPORT(SYMBOL_UNDERSCORE "XPTC_InvokeByIndex") + SYMBOL_UNDERSCORE "XPTC_InvokeByIndex:\n\t" + "pushl %ebp\n\t" + "movl %esp, %ebp\n\t" +#ifdef MOZ_PRESERVE_PIC + "pushl %ebx\n\t" + "call 0f\n\t" + ".subsection 1\n" + "0:\n\t" + "movl (%esp), %ebx\n\t" + "ret\n\t" + ".previous\n\t" + "addl $_GLOBAL_OFFSET_TABLE_, %ebx\n\t" +#endif + "movl 0x10(%ebp), %eax\n\t" + "leal 0(,%eax,8),%edx\n\t" + "movl %esp, %ecx\n\t" + "subl %edx, %ecx\n\t" +/* Since there may be 64-bit data, it occurs to me that aligning this + space might be a performance gain. However, I don't think the rest + of mozilla worries about such things. In any event, do it here. + "andl $0xfffffff8, %ecx\n\t" + */ + "movl %ecx, %esp\n\t" /* make stack space */ + "movl 0x14(%ebp), %edx\n\t" + "call " SYMBOL_UNDERSCORE "invoke_copy_to_stack\n\t" + "movl 0x08(%ebp), %ecx\n\t" /* 'that' */ +#ifdef CFRONT_STYLE_THIS_ADJUST + "movl (%ecx), %edx\n\t" + "movl 0x0c(%ebp), %eax\n\t" /* function index */ + "shll $3, %eax\n\t" /* *= 8 */ + "addl $8, %eax\n\t" /* += 8 skip first entry */ + "addl %eax, %edx\n\t" + "movswl (%edx), %eax\n\t" /* 'this' offset */ + "addl %eax, %ecx\n\t" + "pushl %ecx\n\t" + "addl $4, %edx\n\t" /* += 4, method pointer */ +#else /* THUNK_BASED_THIS_ADJUST */ + "pushl %ecx\n\t" + "movl (%ecx), %edx\n\t" + "movl 0x0c(%ebp), %eax\n\t" /* function index */ + "leal (%edx,%eax,4), %edx\n\t" +#endif + "call *(%edx)\n\t" +#ifdef MOZ_PRESERVE_PIC + "movl -4(%ebp), %ebx\n\t" +#endif + "movl %ebp, %esp\n\t" + "popl %ebp\n\t" + "ret\n" + ".size " SYMBOL_UNDERSCORE "XPTC_InvokeByIndex, . -" SYMBOL_UNDERSCORE "XPTC_InvokeByIndex\n\t" +); + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/os2/xptcinvoke_vacpp.asm b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/os2/xptcinvoke_vacpp.asm new file mode 100644 index 00000000..4d013fdb --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/os2/xptcinvoke_vacpp.asm @@ -0,0 +1,268 @@ +COMMENT | -*- Mode: asm; tab-width: 8; c-basic-offset: 4 -*- + + ***** 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.org Code. + + The Initial Developer of the Original Code is + Netscape Communications Corporation. + Portions created by the Initial Developer are Copyright (C) 2001 + the Initial Developer. All Rights Reserved. + + Contributor(s): + Henry Sobotka + + Alternatively, the contents of this file may be used under the terms of + either of 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 ***** + Version 1.0 (the "NPL"); you may not use this file except in + compliance with the NPL. You may obtain a copy of the NPL at + http://www.mozilla.org/NPL/ + + Software distributed under the NPL is distributed on an "AS IS" basis, + WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + for the specific language governing rights and limitations under the + NPL. + + The Initial Developer of this code under the NPL is Netscape + Communications Corporation. Portions created by Netscape are + Copyright (C) 1999 Netscape Communications Corporation. All Rights + Reserved. + + Contributor: Henry Sobotka + + This Original Code has been modified by IBM Corporation. + Modifications made by IBM described herein are + Copyright (c) International Business Machines + Corporation, 2000 + + Modifications to Mozilla code or documentation + identified per MPL Section 3.3 + + Date Modified by Description of modification + 03/23/2000 IBM Corp. Various fixes for parameter passing and adjusting the 'this' + pointer for multiply inherited objects. + + xptcall_vacpp.asm: ALP assembler procedures for VAC++ build of xptcall + + We use essentially the same algorithm as the other platforms, except + Optlink as calling convention. This means loading the three leftmost + conforming (<= 4 bytes, enum or pointer) parameters into eax, edx and ecx, + and the four leftmost float types atop the FP stack. As "this" goes into + eax, we only have to load edx and ecx (if there are two parameters). + Nonconforming parameters go on the stack. As the right-size space has + to be allocated at the proper place (order of parameters) in the stack + for each conforming parameter, we simply copy them all. | + + + .486P + .MODEL FLAT, OPTLINK + .STACK + + .CODE + +t_Int4Bytes equ 001004h +t_Int8Bytes equ 001008h +t_Float4Bytes equ 000104h +t_Float8Bytes equ 000108h + +TypesArray dd t_Int4Bytes ; nsXPTType::T_I8 + dd t_Int4Bytes ; nsXPTType::T_I16 + dd t_Int4Bytes ; nsXPTType::T_I32 + dd t_Int8Bytes ; nsXPTType::T_I64 (***) + dd t_Int4Bytes ; nsXPTType::T_U8 + dd t_Int4Bytes ; nsXPTType::T_U16 + dd t_Int4Bytes ; nsXPTType::T_U32 + dd t_Int8Bytes ; nsXPTType::T_U64 (***) + dd t_Float4Bytes ; nsXPTType::T_FLOAT (***) + dd t_Float8Bytes ; nsXPTType::T_DOUBLE (***) + dd t_Int4Bytes ; nsXPTType::T_BOOL + dd t_Int4Bytes ; nsXPTType::T_CHAR + dd t_Int4Bytes ; nsXPTType::T_WCHAR + dd t_Int4Bytes ; TD_VOID + dd t_Int4Bytes ; TD_PNSIID + dd t_Int4Bytes ; TD_DOMSTRING + dd t_Int4Bytes ; TD_PSTRING + dd t_Int4Bytes ; TD_PWSTRING + dd t_Int4Bytes ; TD_INTERFACE_TYPE + dd t_Int4Bytes ; TD_INTERFACE_IS_TYPE + dd t_Int4Bytes ; TD_ARRAY + dd t_Int4Bytes ; TD_PSTRING_SIZE_IS + dd t_Int4Bytes ; TD_PWSTRING_SIZE_IS + dd t_Int4Bytes ; TD_UTF8STRING + dd t_Int4Bytes ; TD_CSTRING + dd t_Int4Bytes ; TD_ASTRING + ; All other values default to 4 byte int/ptr + + + + ; Optlink puts 'that' in eax, 'index' in edx, 'paramcount' in ecx + ; 'params' is on the stack... +XPTC_InvokeByIndex PROC OPTLINK EXPORT USES ebx edi esi, that, index, paramcount, params + + LOCAL cparams:dword, fparams:dword, reg_edx:dword, reg_ecx:dword, count:dword + + mov dword ptr [that], eax ; that + mov dword ptr [index], edx ; index + mov dword ptr [paramcount], ecx ; paramcount + mov dword ptr [count], ecx ; save a copy of count + +; #define FOURBYTES 4 +; #define EIGHTBYTES 8 +; #define FLOAT 0x00000100 +; #define INT 0x00001000 +; #define LENGTH 0x000000ff +; +;types[ ] = { +; FOURBYES | INT, // int/uint/ptr/etc +; EIGHTBYTES | INT, // long long +; FOURBYES | FLOAT, // float +; EIGHTBYTES | FLOAT // double +;}; +; params+00h = val // double +; params+08h = ptr +; params+0ch = type +; params+0dh = flags +; PTR_IS_DATA = 0x01 +; ecx = params +; edx = src +; edi = dst +; ebx = type (bh = int/float, bl = byte count) + + xor eax, eax + mov dword ptr [cparams],eax ; cparams = 0; + mov dword ptr [fparams],eax ; fparams = 0; + + shl ecx, 03h + sub esp, ecx ; dst/esp = add esp, paramCount * 8 + mov edi, esp + + push eax ; push 0 // "end" of floating point register stack... + + mov ecx, dword ptr [params] ; // params is a "register" variable +@While1: + mov eax, dword ptr [count] ; while( count-- ) + or eax, eax ; // (test for zero) + je @EndWhile1 + dec eax + mov dword ptr [count], eax + ; { + + test byte ptr [ecx+0dh],01h ; if ( params->flags & PTR_IS_DATA ) { + je @IfElse1 + lea edx, dword ptr [ecx+08h] ; src = ¶ms->ptr; + mov ebx, 01004h ; type = INT | FOURBYTES; + jmp @EndIf1 +@IfElse1: ; } else { + mov edx, ecx ; src = ¶ms->val + movzx eax, byte ptr [ecx+0ch] ; type = types[params->type]; + cmp eax, 22 ; // range check params->type... (0 to 22) + jle @TypeOK + mov eax,2 ; // all others default to 4 byte int +@TypeOK: + mov ebx, dword ptr [TypesArray+eax*4] +@EndIf1: ; } + + test bh, 001h ; if ( type & FLOAT ) { + je @EndIf2 + cmp dword ptr [fparams], 4 ; if ( fparams < 4 ) { + jge @EndIf3 + push edx ; push src; + push ebx ; push type + inc dword ptr [fparams] ; fparams++; +;;; movzx eax, bl ; // dst += (type & LENGTH); +;;; add edi, eax ; +;;; xor ebx, ebx ; // type = 0; // "handled" +@EndIf3: ; } +@EndIf2: ; } + + ; // copy bytes... +@While2: or bl, bl ; while( type & LENGTH ) { + je @EndWhile2 + test bh, 010h ; if( type & INT ) { + je @EndIf4 + cmp dword ptr [cparams], 8 ; if( cparams < 8 ) { + jge @EndIf5 + lea eax, dword ptr [reg_edx] ; (®_edx)[cparams] = *src; + sub eax, dword ptr [cparams] + mov esi, dword ptr [edx] + mov dword ptr [eax], esi + add dword ptr [cparams], 4 ; cparams += 4; +;;; jmp @NoCopy ; // goto nocopy; +@EndIf5: ; } +@EndIf4: ; } + mov eax, dword ptr [edx] ; *dst = *src; + mov dword ptr [edi], eax +@NoCopy: ;nocopy: + add edi, 4 ; dst++; + add edx, 4 ; src++; + sub bl, 4 ; type -= 4; + jmp @While2 +@EndWhile2: ; } + add ecx, 010h ; params++; + jmp @While1 +@EndWhile1: ; } + + ; // Set up fpu and regs can make the call... +@While3: pop ebx ; while ( pop type ) { + or ebx, ebx + je @EndWhile3 + pop edx ; pop src + cmp bl, 08h ; if( type & EIGHTBYTES ) { + jne @IfElse6 + fld qword ptr [edx] ; fld qword ptr [src] + jmp @EndIf6 +@IfElse6: ; } else { + fld dword ptr [edx] ; fld dword ptr [src] +@EndIf6: ; } + jmp @While3 +@EndWhile3: ; } + + ; make the call + mov eax, dword ptr [that] ; get 'that' ("this" ptr) + mov ebx, dword ptr [index] ; get index + shl ebx, 03h ; index *= 8 bytes per method + add ebx, 08h ; += 8 at head of vtable + add ebx, [eax] ; calculate address + + mov ecx, dword ptr [ebx+04h] + add eax, ecx + sub esp, 04h ; make room for 'this' ptr on stack + + mov edx, dword ptr [reg_edx] + mov ecx, dword ptr [reg_ecx] + + call dword ptr [ebx] ; call method + + mov ecx, dword ptr [paramcount] + shl ecx, 03h + add esp, ecx ; remove space on stack for params + add esp, 04h ; remove space on stack for 'this' ptr + ret + + ENDP + + END + + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/os2/xptcstubs_emx.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/os2/xptcstubs_emx.cpp new file mode 100644 index 00000000..6cde9231 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/os2/xptcstubs_emx.cpp @@ -0,0 +1,153 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Implement shared vtbl methods */ + +// This is a 98% copy of other implementations; see comment at top of +// xptcinvoke_emx.cpp for why this file exists. +// + +#include "xptcprivate.h" + +#if !defined(__EMX__) +#error "This code is for OS/2 EMX only" +#endif + +static nsresult +PrepareAndDispatch( nsXPTCStubBase *self, PRUint32 methodIndex, + PRUint32 *args) +{ +#define PARAM_BUFFER_COUNT 16 + + nsXPTCMiniVariant paramBuffer[PARAM_BUFFER_COUNT]; + nsXPTCMiniVariant* dispatchParams = NULL; + nsIInterfaceInfo* iface_info = NULL; + const nsXPTMethodInfo* info; + PRUint8 paramCount; + PRUint8 i; + nsresult result = NS_ERROR_FAILURE; + + // If anything fails before stackBytesToPop can be set then + // the failure is completely catastrophic! + + NS_ASSERTION(self,"no self"); + + self->GetInterfaceInfo(&iface_info); + NS_ASSERTION(iface_info,"no interface info"); + + iface_info->GetMethodInfo(PRUint16(methodIndex), &info); + NS_ASSERTION(info,"no interface info"); + + paramCount = info->GetParamCount(); + + // setup variant array pointer + if(paramCount > PARAM_BUFFER_COUNT) + dispatchParams = new nsXPTCMiniVariant[paramCount]; + else + dispatchParams = paramBuffer; + NS_ASSERTION(dispatchParams,"no place for params"); + + PRUint32* ap = args; + for(i = 0; i < paramCount; i++, ap++) + { + const nsXPTParamInfo& param = info->GetParam(i); + const nsXPTType& type = param.GetType(); + nsXPTCMiniVariant* dp = &dispatchParams[i]; + + if(param.IsOut() || !type.IsArithmetic()) + { + dp->val.p = (void*) *ap; + continue; + } + // else + switch(type) + { + case nsXPTType::T_I8 : dp->val.i8 = *((PRInt8*) ap); break; + case nsXPTType::T_I16 : dp->val.i16 = *((PRInt16*) ap); break; + case nsXPTType::T_I32 : dp->val.i32 = *((PRInt32*) ap); break; + case nsXPTType::T_I64 : dp->val.i64 = *((PRInt64*) ap); ap++; break; + case nsXPTType::T_U8 : dp->val.u8 = *((PRUint8*) ap); break; + case nsXPTType::T_U16 : dp->val.u16 = *((PRUint16*)ap); break; + case nsXPTType::T_U32 : dp->val.u32 = *((PRUint32*)ap); break; + case nsXPTType::T_U64 : dp->val.u64 = *((PRUint64*)ap); ap++; break; + case nsXPTType::T_FLOAT : dp->val.f = *((float*) ap); break; + case nsXPTType::T_DOUBLE : dp->val.d = *((double*) ap); ap++; break; + case nsXPTType::T_BOOL : dp->val.b = *((PRBool*) ap); break; + case nsXPTType::T_CHAR : dp->val.c = *((char*) ap); break; + case nsXPTType::T_WCHAR : dp->val.wc = *((wchar_t*) ap); break; + default: + NS_ASSERTION(0, "bad type"); + break; + } + } + + result = self->CallMethod((PRUint16)methodIndex, info, dispatchParams); + + NS_RELEASE(iface_info); + + if(dispatchParams != paramBuffer) + delete [] dispatchParams; + + return result; +} + +#define STUB_ENTRY(n) \ +nsresult nsXPTCStubBase::Stub##n() \ +{ \ + register void* method = PrepareAndDispatch; \ + register nsresult result; \ + __asm__ __volatile__( \ + "leal 0x0c(%%ebp), %%ecx\n\t" /* args */ \ + "pushl %%ecx\n\t" \ + "pushl $"#n"\n\t" /* method index */ \ + "movl 0x08(%%ebp), %%ecx\n\t" /* this */ \ + "pushl %%ecx\n\t" \ + "call *%%edx" /* PrepareAndDispatch */ \ + : "=a" (result) /* %0 */ \ + : "d" (method) /* %1 */ \ + : "ax", "dx", "cx", "memory" ); \ + return result; \ +} + +#define SENTINEL_ENTRY(n) \ +nsresult nsXPTCStubBase::Sentinel##n() \ +{ \ + NS_ASSERTION(0,"nsXPCWrappedJS::Sentinel called"); \ + return NS_ERROR_NOT_IMPLEMENTED; \ +} + +#include "xptcstubsdef.inc" diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/os2/xptcstubs_gcc_x86_os2.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/os2/xptcstubs_gcc_x86_os2.cpp new file mode 100644 index 00000000..6304b67a --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/os2/xptcstubs_gcc_x86_os2.cpp @@ -0,0 +1,180 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Implement shared vtbl methods. */ + +/* This file is basically a copy of xptcinvoke_gcc_x86_unix.cpp with some + * irrelevant parts stipped off and some OS/2 specific modifications added, + * so it needs to be kept in sync with the original. */ + +#include "xptcprivate.h" +#include "xptc_platforms_unixish_x86.h" +#include "xptc_gcc_x86_unix.h" + +extern "C" { +static nsresult ATTRIBUTE_USED +__attribute__ ((regparm (3))) +PrepareAndDispatch(uint32 methodIndex, nsXPTCStubBase* self, PRUint32* args) +{ +#define PARAM_BUFFER_COUNT 16 + + nsXPTCMiniVariant paramBuffer[PARAM_BUFFER_COUNT]; + nsXPTCMiniVariant* dispatchParams = NULL; + nsIInterfaceInfo* iface_info = NULL; + const nsXPTMethodInfo* info = NULL; + PRUint8 paramCount; + PRUint8 i; + nsresult result = NS_ERROR_FAILURE; + + NS_ASSERTION(self,"no self"); + + self->GetInterfaceInfo(&iface_info); + NS_ASSERTION(iface_info,"no interface info"); + if (!iface_info) + return NS_ERROR_UNEXPECTED; + + iface_info->GetMethodInfo(PRUint16(methodIndex), &info); + NS_ASSERTION(info,"no method info"); + if (!info) + return NS_ERROR_UNEXPECTED; + + paramCount = info->GetParamCount(); + + // setup variant array pointer + if(paramCount > PARAM_BUFFER_COUNT) + dispatchParams = new nsXPTCMiniVariant[paramCount]; + else + dispatchParams = paramBuffer; + NS_ASSERTION(dispatchParams,"no place for params"); + if (!dispatchParams) + return NS_ERROR_OUT_OF_MEMORY; + + PRUint32* ap = args; + for(i = 0; i < paramCount; i++, ap++) + { + const nsXPTParamInfo& param = info->GetParam(i); + const nsXPTType& type = param.GetType(); + nsXPTCMiniVariant* dp = &dispatchParams[i]; + + if(param.IsOut() || !type.IsArithmetic()) + { + dp->val.p = (void*) *ap; + continue; + } + // else + dp->val.p = (void*) *ap; + switch(type) + { + case nsXPTType::T_I64 : dp->val.i64 = *((PRInt64*) ap); ap++; break; + case nsXPTType::T_U64 : dp->val.u64 = *((PRUint64*)ap); ap++; break; + case nsXPTType::T_DOUBLE : dp->val.d = *((double*) ap); ap++; break; + } + } + + result = self->CallMethod((PRUint16)methodIndex, info, dispatchParams); + + NS_RELEASE(iface_info); + + if(dispatchParams != paramBuffer) + delete [] dispatchParams; + + return result; +} +} // extern "C" + +#if defined(__declspec) +#define SYMBOL_EXPORT(sym) \ + ".stabs \"" sym ",0=" sym ",code\", 0x6c,0,0,-42\n\t" +#else +#define SYMBOL_EXPORT(sym) +#endif + +#define STUB_ENTRY(n) \ +asm(".text\n\t" \ + ".align 2\n\t" \ + ".if " #n " < 10\n\t" \ + ".globl " SYMBOL_UNDERSCORE "_ZN14nsXPTCStubBase5Stub" #n "Ev\n\t" \ + ".type " SYMBOL_UNDERSCORE "_ZN14nsXPTCStubBase5Stub" #n "Ev,@function\n" \ + SYMBOL_EXPORT(SYMBOL_UNDERSCORE "_ZN14nsXPTCStubBase5Stub" #n "Ev") \ + SYMBOL_UNDERSCORE "_ZN14nsXPTCStubBase5Stub" #n "Ev:\n\t" \ + ".elseif " #n " < 100\n\t" \ + ".globl " SYMBOL_UNDERSCORE "_ZN14nsXPTCStubBase6Stub" #n "Ev\n\t" \ + ".type " SYMBOL_UNDERSCORE "_ZN14nsXPTCStubBase6Stub" #n "Ev,@function\n" \ + SYMBOL_EXPORT(SYMBOL_UNDERSCORE "_ZN14nsXPTCStubBase6Stub" #n "Ev") \ + SYMBOL_UNDERSCORE "_ZN14nsXPTCStubBase6Stub" #n "Ev:\n\t" \ + ".elseif " #n " < 1000\n\t" \ + ".globl " SYMBOL_UNDERSCORE "_ZN14nsXPTCStubBase7Stub" #n "Ev\n\t" \ + ".type " SYMBOL_UNDERSCORE "_ZN14nsXPTCStubBase7Stub" #n "Ev,@function\n" \ + SYMBOL_EXPORT(SYMBOL_UNDERSCORE "_ZN14nsXPTCStubBase7Stub" #n "Ev") \ + SYMBOL_UNDERSCORE "_ZN14nsXPTCStubBase7Stub" #n "Ev:\n\t" \ + ".else\n\t" \ + ".err \"stub number " #n " >= 1000 not yet supported\"\n\t" \ + ".endif\n\t" \ + "movl $" #n ", %eax\n\t" \ + "jmp " SYMBOL_UNDERSCORE "SharedStub\n\t" \ + ".if " #n " < 10\n\t" \ + ".size " SYMBOL_UNDERSCORE "_ZN14nsXPTCStubBase5Stub" #n "Ev,.-" SYMBOL_UNDERSCORE "_ZN14nsXPTCStubBase5Stub" #n "Ev\n\t" \ + ".elseif " #n " < 100\n\t" \ + ".size " SYMBOL_UNDERSCORE "_ZN14nsXPTCStubBase6Stub" #n "Ev,.-" SYMBOL_UNDERSCORE "_ZN14nsXPTCStubBase6Stub" #n "Ev\n\t" \ + ".else\n\t" \ + ".size " SYMBOL_UNDERSCORE "_ZN14nsXPTCStubBase7Stub" #n "Ev,.-" SYMBOL_UNDERSCORE "_ZN14nsXPTCStubBase7Stub" #n "Ev\n\t" \ + ".endif"); + +// static nsresult SharedStub(PRUint32 methodIndex) __attribute__((regparm(1))) +asm(".text\n\t" + ".align 2\n\t" + ".type " SYMBOL_UNDERSCORE "SharedStub,@function\n\t" + SYMBOL_UNDERSCORE "SharedStub:\n\t" + "leal 0x08(%esp), %ecx\n\t" + "movl 0x04(%esp), %edx\n\t" + "jmp " SYMBOL_UNDERSCORE "PrepareAndDispatch\n\t" + ".size " SYMBOL_UNDERSCORE "SharedStub,.-" SYMBOL_UNDERSCORE "SharedStub"); + +#define SENTINEL_ENTRY(n) \ +nsresult nsXPTCStubBase::Sentinel##n() \ +{ \ + NS_ASSERTION(0,"nsXPTCStubBase::Sentinel called"); \ + return NS_ERROR_NOT_IMPLEMENTED; \ +} + +#include "xptcstubsdef.inc" + +void +xptc_dummy() +{ +} + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/os2/xptcstubs_os2.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/os2/xptcstubs_os2.cpp new file mode 100644 index 00000000..33e8574a --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/os2/xptcstubs_os2.cpp @@ -0,0 +1,195 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** 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.org Code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * John Fairhurst + * Henry Sobotka added VAC++ support + * and fixed emx asm to work with gcc 2.95.2 (Jan. 2000) + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Implement shared vtbl methods */ + +#include "xptcprivate.h" + +#if !defined (__EMX__) && !defined(__IBMCPP__) +#error "This code is only for OS/2" +#endif + +// Procedure in xptcall_vacpp.asm +#ifdef XP_OS2_VACPP +extern nsresult SetEntryFromIndex(int stubidx); +#endif + +#ifdef XP_OS2_VACPP +nsresult +PrepareAndDispatch( nsXPTCStubBase *self, PRUint32 methodIndex, + PRUint32 *args) +#else +static nsresult +PrepareAndDispatch( nsXPTCStubBase *self, PRUint32 methodIndex, + PRUint32 *args) +#endif +{ +#define PARAM_BUFFER_COUNT 16 + + nsXPTCMiniVariant paramBuffer[PARAM_BUFFER_COUNT]; + nsXPTCMiniVariant* dispatchParams = NULL; + nsIInterfaceInfo* iface_info = NULL; + const nsXPTMethodInfo* info; + PRUint8 paramCount; + PRUint8 i; + nsresult result = NS_ERROR_FAILURE; + + // If anything fails before stackBytesToPop can be set then + // the failure is completely catastrophic! + + NS_ASSERTION(self,"no self"); + + self->GetInterfaceInfo(&iface_info); + NS_ASSERTION(iface_info,"no interface info"); + + iface_info->GetMethodInfo(PRUint16(methodIndex), &info); + NS_ASSERTION(info,"no interface info"); + + paramCount = info->GetParamCount(); + +#ifdef XP_OS2_VACPP + /* If paramCount is > 0, write out the EDX pointer to the + space on the stack args[0]. args[-4] is the space on + the stack where it was pushed */ + if (paramCount) { + args[0] = args[-4]; + + /* If this is the second parameter, or if the first parameter is an + 8 byte long long, write out the ECX pointer to the space on the + stack args[1]. args[-3] is the space on the stack where it was + pushed */ + nsXPTType type = info->GetParam(0).GetType(); + if( paramCount > 1 || + type == nsXPTType::T_I64 || type == nsXPTType::T_U64 ) + { + args[1] = args[-3]; + } + } +#endif + + // setup variant array pointer + if(paramCount > PARAM_BUFFER_COUNT) + dispatchParams = new nsXPTCMiniVariant[paramCount]; + else + dispatchParams = paramBuffer; + NS_ASSERTION(dispatchParams,"no place for params"); + + PRUint32* ap = args; + for(i = 0; i < paramCount; i++, ap++) + { + const nsXPTParamInfo& param = info->GetParam(i); + const nsXPTType& type = param.GetType(); + nsXPTCMiniVariant* dp = &dispatchParams[i]; + + if(param.IsOut() || !type.IsArithmetic()) + { + dp->val.p = (void*) *ap; + continue; + } + // else + switch(type) + { + case nsXPTType::T_I8 : dp->val.i8 = *((PRInt8*) ap); break; + case nsXPTType::T_I16 : dp->val.i16 = *((PRInt16*) ap); break; + case nsXPTType::T_I32 : dp->val.i32 = *((PRInt32*) ap); break; + case nsXPTType::T_I64 : dp->val.i64 = *((PRInt64*) ap); ap++; break; + case nsXPTType::T_U8 : dp->val.u8 = *((PRUint8*) ap); break; + case nsXPTType::T_U16 : dp->val.u16 = *((PRUint16*)ap); break; + case nsXPTType::T_U32 : dp->val.u32 = *((PRUint32*)ap); break; + case nsXPTType::T_U64 : dp->val.u64 = *((PRUint64*)ap); ap++; break; + case nsXPTType::T_FLOAT : dp->val.f = *((float*) ap); break; + case nsXPTType::T_DOUBLE : dp->val.d = *((double*) ap); ap++; break; + case nsXPTType::T_BOOL : dp->val.b = *((PRBool*) ap); break; + case nsXPTType::T_CHAR : dp->val.c = *((char*) ap); break; + case nsXPTType::T_WCHAR : dp->val.wc = *((wchar_t*) ap); break; + default: + NS_ASSERTION(0, "bad type"); + break; + } + } + + result = self->CallMethod((PRUint16)methodIndex, info, dispatchParams); + + NS_RELEASE(iface_info); + + if(dispatchParams != paramBuffer) + delete [] dispatchParams; + + return result; +} + +#ifdef XP_OS2_VACPP + +#define STUB_ENTRY(n) + +#else + +#define STUB_ENTRY(n) \ +nsresult nsXPTCStubBase::Stub##n() \ +{ \ + register nsresult (*method) (nsXPTCStubBase *, PRUint32, PRUint32 *) = PrepareAndDispatch; \ + int temp0, temp1; \ + register nsresult result; \ + __asm__ __volatile__( \ + "leal 0x0c(%%ebp), %%ecx\n\t" /* args */ \ + "pushl %%ecx\n\t" \ + "pushl $"#n"\n\t" /* method index */ \ + "movl 0x08(%%ebp), %%ecx\n\t" /* this */ \ + "pushl %%ecx\n\t" \ + "call *%%edx\n\t" /* PrepareAndDispatch */ \ + "addl $12, %%esp" \ + : "=a" (result), /* %0 */ \ + "=&c" (temp0), /* %1 */ \ + "=d" (temp1) /* %2 */ \ + : "2" (method) /* %2 */ \ + : "memory" ); \ + return result; \ +} +#endif + +#define SENTINEL_ENTRY(n) \ +nsresult nsXPTCStubBase::Sentinel##n() \ +{ \ + NS_ASSERTION(0,"nsXPCWrappedJS::Sentinel called"); \ + return NS_ERROR_NOT_IMPLEMENTED; \ +} + +#include "xptcstubsdef.inc" diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/os2/xptcstubs_vacpp.asm b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/os2/xptcstubs_vacpp.asm new file mode 100644 index 00000000..3464a1f9 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/os2/xptcstubs_vacpp.asm @@ -0,0 +1,1563 @@ +COMMENT | -*- Mode: asm; tab-width: 8; c-basic-offset: 4 -*- + + ***** 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.org Code. + + The Initial Developer of the Original Code is + Netscape Communications Corporation. + Portions created by the Initial Developer are Copyright (C) 2001 + the Initial Developer. All Rights Reserved. + + Contributor(s): + John Fairhurst + Henry Sobotka + + Alternatively, the contents of this file may be used under the terms of + either of 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 ***** + Version 1.0 (the "NPL"); you may not use this file except in + compliance with the NPL. You may obtain a copy of the NPL at + http://www.mozilla.org/NPL/ + + Software distributed under the NPL is distributed on an "AS IS" basis, + WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + for the specific language governing rights and limitations under the + NPL. + + The Initial Developer of this code under the NPL is Netscape + Communications Corporation. Portions created by Netscape are + Copyright (C) 1999 Netscape Communications Corporation. All Rights + Reserved. + + Contributor: Henry Sobotka + + xptcallstub_vacpp.asm: ALP assembler procedure for VAC++ build of xptcall + | + + .486P + .MODEL FLAT, OPTLINK + .STACK + + .CODE + + EXTERN OPTLINK PrepareAndDispatch__FP14nsXPTCStubBaseUiPUi:PROC + +setentidx MACRO index + + push ecx ; Save parameters + push edx ; Save parameters - don't need to save eax - it is the "this" ptr + lea ecx, dword ptr [esp+10h] ; Load pointer to "args" into ecx + mov edx, index ; Move vtable index into edx + sub esp, 0ch ; Make room for three parameters on the stack + call PrepareAndDispatch__FP14nsXPTCStubBaseUiPUi + add esp, 14h ; Reset stack pointer + ret + ENDM + +; 251 STUB_ENTRY(249) + +Stub249__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0f9h +Stub249__14nsXPTCStubBaseFv endp + +; 250 STUB_ENTRY(248) + +Stub248__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0f8h +Stub248__14nsXPTCStubBaseFv endp + +; 249 STUB_ENTRY(247) + +Stub247__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0f7h +Stub247__14nsXPTCStubBaseFv endp + +; 248 STUB_ENTRY(246) + +Stub246__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0f6h +Stub246__14nsXPTCStubBaseFv endp + +; 247 STUB_ENTRY(245) + +Stub245__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0f5h +Stub245__14nsXPTCStubBaseFv endp + +; 246 STUB_ENTRY(244) + +Stub244__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0f4h +Stub244__14nsXPTCStubBaseFv endp + +; 245 STUB_ENTRY(243) + +Stub243__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0f3h +Stub243__14nsXPTCStubBaseFv endp + +; 244 STUB_ENTRY(242) + +Stub242__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0f2h +Stub242__14nsXPTCStubBaseFv endp + +; 243 STUB_ENTRY(241) + +Stub241__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0f1h +Stub241__14nsXPTCStubBaseFv endp + +; 242 STUB_ENTRY(240) + +Stub240__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0f0h +Stub240__14nsXPTCStubBaseFv endp + +; 241 STUB_ENTRY(239) + +Stub239__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0efh +Stub239__14nsXPTCStubBaseFv endp + +; 240 STUB_ENTRY(238) + +Stub238__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0eeh +Stub238__14nsXPTCStubBaseFv endp + +; 239 STUB_ENTRY(237) + +Stub237__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0edh +Stub237__14nsXPTCStubBaseFv endp + +; 238 STUB_ENTRY(236) + +Stub236__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0ech +Stub236__14nsXPTCStubBaseFv endp + +; 237 STUB_ENTRY(235) + +Stub235__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0ebh +Stub235__14nsXPTCStubBaseFv endp + +; 236 STUB_ENTRY(234) + +Stub234__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0eah +Stub234__14nsXPTCStubBaseFv endp + +; 235 STUB_ENTRY(233) + +Stub233__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0e9h +Stub233__14nsXPTCStubBaseFv endp + +; 234 STUB_ENTRY(232) + +Stub232__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0e8h +Stub232__14nsXPTCStubBaseFv endp + +; 233 STUB_ENTRY(231) + +Stub231__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0e7h +Stub231__14nsXPTCStubBaseFv endp + +; 232 STUB_ENTRY(230) + +Stub230__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0e6h +Stub230__14nsXPTCStubBaseFv endp + +; 231 STUB_ENTRY(229) + +Stub229__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0e5h +Stub229__14nsXPTCStubBaseFv endp + +; 230 STUB_ENTRY(228) + +Stub228__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0e4h +Stub228__14nsXPTCStubBaseFv endp + +; 229 STUB_ENTRY(227) + +Stub227__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0e3h +Stub227__14nsXPTCStubBaseFv endp + +; 228 STUB_ENTRY(226) + +Stub226__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0e2h +Stub226__14nsXPTCStubBaseFv endp + +; 227 STUB_ENTRY(225) + +Stub225__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0e1h +Stub225__14nsXPTCStubBaseFv endp + +; 226 STUB_ENTRY(224) + +Stub224__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0e0h +Stub224__14nsXPTCStubBaseFv endp + +; 225 STUB_ENTRY(223) + +Stub223__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0dfh +Stub223__14nsXPTCStubBaseFv endp + +; 224 STUB_ENTRY(222) + +Stub222__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0deh +Stub222__14nsXPTCStubBaseFv endp + +; 223 STUB_ENTRY(221) + +Stub221__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0ddh +Stub221__14nsXPTCStubBaseFv endp + +; 222 STUB_ENTRY(220) + +Stub220__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0dch +Stub220__14nsXPTCStubBaseFv endp + +; 221 STUB_ENTRY(219) + +Stub219__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0dbh +Stub219__14nsXPTCStubBaseFv endp + +; 220 STUB_ENTRY(218) + +Stub218__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0dah +Stub218__14nsXPTCStubBaseFv endp + +; 219 STUB_ENTRY(217) + +Stub217__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0d9h +Stub217__14nsXPTCStubBaseFv endp + +; 218 STUB_ENTRY(216) + +Stub216__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0d8h +Stub216__14nsXPTCStubBaseFv endp + +; 217 STUB_ENTRY(215) + +Stub215__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0d7h +Stub215__14nsXPTCStubBaseFv endp + +; 216 STUB_ENTRY(214) + +Stub214__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0d6h +Stub214__14nsXPTCStubBaseFv endp + +; 215 STUB_ENTRY(213) + +Stub213__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0d5h +Stub213__14nsXPTCStubBaseFv endp + +; 214 STUB_ENTRY(212) + +Stub212__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0d4h +Stub212__14nsXPTCStubBaseFv endp + +; 213 STUB_ENTRY(211) + +Stub211__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0d3h +Stub211__14nsXPTCStubBaseFv endp + +; 212 STUB_ENTRY(210) + +Stub210__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0d2h +Stub210__14nsXPTCStubBaseFv endp + +; 211 STUB_ENTRY(209) + +Stub209__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0d1h +Stub209__14nsXPTCStubBaseFv endp + +; 210 STUB_ENTRY(208) + +Stub208__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0d0h +Stub208__14nsXPTCStubBaseFv endp + +; 209 STUB_ENTRY(207) + +Stub207__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0cfh +Stub207__14nsXPTCStubBaseFv endp + +; 208 STUB_ENTRY(206) + +Stub206__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0ceh +Stub206__14nsXPTCStubBaseFv endp + +; 207 STUB_ENTRY(205) + +Stub205__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0cdh +Stub205__14nsXPTCStubBaseFv endp + +; 206 STUB_ENTRY(204) + +Stub204__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0cch +Stub204__14nsXPTCStubBaseFv endp + +; 205 STUB_ENTRY(203) + +Stub203__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0cbh +Stub203__14nsXPTCStubBaseFv endp + +; 204 STUB_ENTRY(202) + +Stub202__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0cah +Stub202__14nsXPTCStubBaseFv endp + +; 203 STUB_ENTRY(201) + +Stub201__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0c9h +Stub201__14nsXPTCStubBaseFv endp + +; 202 STUB_ENTRY(200) + +Stub200__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0c8h +Stub200__14nsXPTCStubBaseFv endp + +; 201 STUB_ENTRY(199) + +Stub199__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0c7h +Stub199__14nsXPTCStubBaseFv endp + +; 200 STUB_ENTRY(198) + +Stub198__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0c6h +Stub198__14nsXPTCStubBaseFv endp + +; 199 STUB_ENTRY(197) + +Stub197__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0c5h +Stub197__14nsXPTCStubBaseFv endp + +; 198 STUB_ENTRY(196) + +Stub196__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0c4h +Stub196__14nsXPTCStubBaseFv endp + +; 197 STUB_ENTRY(195) + +Stub195__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0c3h +Stub195__14nsXPTCStubBaseFv endp + +; 196 STUB_ENTRY(194) + +Stub194__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0c2h +Stub194__14nsXPTCStubBaseFv endp + +; 195 STUB_ENTRY(193) + +Stub193__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0c1h +Stub193__14nsXPTCStubBaseFv endp + +; 194 STUB_ENTRY(192) + +Stub192__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0c0h +Stub192__14nsXPTCStubBaseFv endp + +; 193 STUB_ENTRY(191) + +Stub191__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0bfh +Stub191__14nsXPTCStubBaseFv endp + +; 192 STUB_ENTRY(190) + +Stub190__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0beh +Stub190__14nsXPTCStubBaseFv endp + +; 191 STUB_ENTRY(189) + +Stub189__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0bdh +Stub189__14nsXPTCStubBaseFv endp + +; 190 STUB_ENTRY(188) + +Stub188__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0bch +Stub188__14nsXPTCStubBaseFv endp + +; 189 STUB_ENTRY(187) + +Stub187__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0bbh +Stub187__14nsXPTCStubBaseFv endp + +; 188 STUB_ENTRY(186) + +Stub186__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0bah +Stub186__14nsXPTCStubBaseFv endp + +; 187 STUB_ENTRY(185) + +Stub185__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0b9h +Stub185__14nsXPTCStubBaseFv endp + +; 186 STUB_ENTRY(184) + +Stub184__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0b8h +Stub184__14nsXPTCStubBaseFv endp + +; 185 STUB_ENTRY(183) + +Stub183__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0b7h +Stub183__14nsXPTCStubBaseFv endp + +; 184 STUB_ENTRY(182) + +Stub182__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0b6h +Stub182__14nsXPTCStubBaseFv endp + +; 183 STUB_ENTRY(181) + +Stub181__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0b5h +Stub181__14nsXPTCStubBaseFv endp + +; 182 STUB_ENTRY(180) + +Stub180__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0b4h +Stub180__14nsXPTCStubBaseFv endp + +; 181 STUB_ENTRY(179) + +Stub179__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0b3h +Stub179__14nsXPTCStubBaseFv endp + +; 180 STUB_ENTRY(178) + +Stub178__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0b2h +Stub178__14nsXPTCStubBaseFv endp + +; 179 STUB_ENTRY(177) + +Stub177__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0b1h +Stub177__14nsXPTCStubBaseFv endp + +; 178 STUB_ENTRY(176) + +Stub176__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0b0h +Stub176__14nsXPTCStubBaseFv endp + +; 177 STUB_ENTRY(175) + +Stub175__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0afh +Stub175__14nsXPTCStubBaseFv endp + +; 176 STUB_ENTRY(174) + +Stub174__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0aeh +Stub174__14nsXPTCStubBaseFv endp + +; 175 STUB_ENTRY(173) + +Stub173__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0adh +Stub173__14nsXPTCStubBaseFv endp + +; 174 STUB_ENTRY(172) + +Stub172__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0ach +Stub172__14nsXPTCStubBaseFv endp + +; 173 STUB_ENTRY(171) + +Stub171__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0abh +Stub171__14nsXPTCStubBaseFv endp + +; 172 STUB_ENTRY(170) + +Stub170__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0aah +Stub170__14nsXPTCStubBaseFv endp + +; 171 STUB_ENTRY(169) + +Stub169__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0a9h +Stub169__14nsXPTCStubBaseFv endp + +; 170 STUB_ENTRY(168) + +Stub168__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0a8h +Stub168__14nsXPTCStubBaseFv endp + +; 169 STUB_ENTRY(167) + +Stub167__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0a7h +Stub167__14nsXPTCStubBaseFv endp + +; 168 STUB_ENTRY(166) + +Stub166__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0a6h +Stub166__14nsXPTCStubBaseFv endp + +; 167 STUB_ENTRY(165) + +Stub165__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0a5h +Stub165__14nsXPTCStubBaseFv endp + +; 166 STUB_ENTRY(164) + +Stub164__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0a4h +Stub164__14nsXPTCStubBaseFv endp + +; 165 STUB_ENTRY(163) + +Stub163__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0a3h +Stub163__14nsXPTCStubBaseFv endp + +; 164 STUB_ENTRY(162) + +Stub162__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0a2h +Stub162__14nsXPTCStubBaseFv endp + +; 163 STUB_ENTRY(161) + +Stub161__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0a1h +Stub161__14nsXPTCStubBaseFv endp + +; 162 STUB_ENTRY(160) + +Stub160__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0a0h +Stub160__14nsXPTCStubBaseFv endp + +; 161 STUB_ENTRY(159) + +Stub159__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 09fh +Stub159__14nsXPTCStubBaseFv endp + +; 160 STUB_ENTRY(158) + +Stub158__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 09eh +Stub158__14nsXPTCStubBaseFv endp + +; 159 STUB_ENTRY(157) + +Stub157__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 09dh +Stub157__14nsXPTCStubBaseFv endp + +; 158 STUB_ENTRY(156) + +Stub156__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 09ch +Stub156__14nsXPTCStubBaseFv endp + +; 157 STUB_ENTRY(155) + +Stub155__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 09bh +Stub155__14nsXPTCStubBaseFv endp + +; 156 STUB_ENTRY(154) + +Stub154__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 09ah +Stub154__14nsXPTCStubBaseFv endp + +; 155 STUB_ENTRY(153) + +Stub153__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 099h +Stub153__14nsXPTCStubBaseFv endp + +; 154 STUB_ENTRY(152) + +Stub152__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 098h +Stub152__14nsXPTCStubBaseFv endp + +; 153 STUB_ENTRY(151) + +Stub151__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 097h +Stub151__14nsXPTCStubBaseFv endp + +; 152 STUB_ENTRY(150) + +Stub150__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 096h +Stub150__14nsXPTCStubBaseFv endp + +; 151 STUB_ENTRY(149) + +Stub149__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 095h +Stub149__14nsXPTCStubBaseFv endp + +; 150 STUB_ENTRY(148) + +Stub148__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 094h +Stub148__14nsXPTCStubBaseFv endp + +; 149 STUB_ENTRY(147) + +Stub147__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 093h +Stub147__14nsXPTCStubBaseFv endp + +; 148 STUB_ENTRY(146) + +Stub146__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 092h +Stub146__14nsXPTCStubBaseFv endp + +; 147 STUB_ENTRY(145) + +Stub145__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 091h +Stub145__14nsXPTCStubBaseFv endp + +; 146 STUB_ENTRY(144) + +Stub144__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 090h +Stub144__14nsXPTCStubBaseFv endp + +; 145 STUB_ENTRY(143) + +Stub143__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 08fh +Stub143__14nsXPTCStubBaseFv endp + +; 144 STUB_ENTRY(142) + +Stub142__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 08eh +Stub142__14nsXPTCStubBaseFv endp + +; 143 STUB_ENTRY(141) + +Stub141__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 08dh +Stub141__14nsXPTCStubBaseFv endp + +; 142 STUB_ENTRY(140) + +Stub140__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 08ch +Stub140__14nsXPTCStubBaseFv endp + +; 141 STUB_ENTRY(139) + +Stub139__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 08bh +Stub139__14nsXPTCStubBaseFv endp + +; 140 STUB_ENTRY(138) + +Stub138__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 08ah +Stub138__14nsXPTCStubBaseFv endp + +; 139 STUB_ENTRY(137) + +Stub137__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 089h +Stub137__14nsXPTCStubBaseFv endp + +; 138 STUB_ENTRY(136) + +Stub136__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 088h +Stub136__14nsXPTCStubBaseFv endp + +; 137 STUB_ENTRY(135) + +Stub135__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 087h +Stub135__14nsXPTCStubBaseFv endp + +; 136 STUB_ENTRY(134) + +Stub134__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 086h +Stub134__14nsXPTCStubBaseFv endp + +; 135 STUB_ENTRY(133) + +Stub133__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 085h +Stub133__14nsXPTCStubBaseFv endp + +; 134 STUB_ENTRY(132) + +Stub132__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 084h +Stub132__14nsXPTCStubBaseFv endp + +; 133 STUB_ENTRY(131) + +Stub131__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 083h +Stub131__14nsXPTCStubBaseFv endp + +; 132 STUB_ENTRY(130) + +Stub130__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 082h +Stub130__14nsXPTCStubBaseFv endp + +; 131 STUB_ENTRY(129) + +Stub129__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 081h +Stub129__14nsXPTCStubBaseFv endp + +; 130 STUB_ENTRY(128) + +Stub128__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 080h +Stub128__14nsXPTCStubBaseFv endp + +; 129 STUB_ENTRY(127) + +Stub127__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 07fh +Stub127__14nsXPTCStubBaseFv endp + +; 128 STUB_ENTRY(126) + +Stub126__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 07eh +Stub126__14nsXPTCStubBaseFv endp + +; 127 STUB_ENTRY(125) + +Stub125__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 07dh +Stub125__14nsXPTCStubBaseFv endp + +; 126 STUB_ENTRY(124) + +Stub124__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 07ch +Stub124__14nsXPTCStubBaseFv endp + +; 125 STUB_ENTRY(123) + +Stub123__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 07bh +Stub123__14nsXPTCStubBaseFv endp + +; 124 STUB_ENTRY(122) + +Stub122__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 07ah +Stub122__14nsXPTCStubBaseFv endp + +; 123 STUB_ENTRY(121) + +Stub121__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 079h +Stub121__14nsXPTCStubBaseFv endp + +; 122 STUB_ENTRY(120) + +Stub120__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 078h +Stub120__14nsXPTCStubBaseFv endp + +; 121 STUB_ENTRY(119) + +Stub119__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 077h +Stub119__14nsXPTCStubBaseFv endp + +; 120 STUB_ENTRY(118) + +Stub118__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 076h +Stub118__14nsXPTCStubBaseFv endp + +; 119 STUB_ENTRY(117) + +Stub117__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 075h +Stub117__14nsXPTCStubBaseFv endp + +; 118 STUB_ENTRY(116) + +Stub116__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 074h +Stub116__14nsXPTCStubBaseFv endp + +; 117 STUB_ENTRY(115) + +Stub115__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 073h +Stub115__14nsXPTCStubBaseFv endp + +; 116 STUB_ENTRY(114) + +Stub114__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 072h +Stub114__14nsXPTCStubBaseFv endp + +; 115 STUB_ENTRY(113) + +Stub113__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 071h +Stub113__14nsXPTCStubBaseFv endp + +; 114 STUB_ENTRY(112) + +Stub112__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 070h +Stub112__14nsXPTCStubBaseFv endp + +; 113 STUB_ENTRY(111) + +Stub111__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 06fh +Stub111__14nsXPTCStubBaseFv endp + +; 112 STUB_ENTRY(110) + +Stub110__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 06eh +Stub110__14nsXPTCStubBaseFv endp + +; 111 STUB_ENTRY(109) + +Stub109__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 06dh +Stub109__14nsXPTCStubBaseFv endp + +; 110 STUB_ENTRY(108) + +Stub108__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 06ch +Stub108__14nsXPTCStubBaseFv endp + +; 109 STUB_ENTRY(107) + +Stub107__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 06bh +Stub107__14nsXPTCStubBaseFv endp + +; 108 STUB_ENTRY(106) + +Stub106__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 06ah +Stub106__14nsXPTCStubBaseFv endp + +; 107 STUB_ENTRY(105) + +Stub105__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 069h +Stub105__14nsXPTCStubBaseFv endp + +; 106 STUB_ENTRY(104) + +Stub104__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 068h +Stub104__14nsXPTCStubBaseFv endp + +; 105 STUB_ENTRY(103) + +Stub103__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 067h +Stub103__14nsXPTCStubBaseFv endp + +; 104 STUB_ENTRY(102) + +Stub102__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 066h +Stub102__14nsXPTCStubBaseFv endp + +; 103 STUB_ENTRY(101) + +Stub101__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 065h +Stub101__14nsXPTCStubBaseFv endp + +; 102 STUB_ENTRY(100) + +Stub100__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 064h +Stub100__14nsXPTCStubBaseFv endp + +; 101 STUB_ENTRY(99) + +Stub99__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 063h +Stub99__14nsXPTCStubBaseFv endp + +; 100 STUB_ENTRY(98) + +Stub98__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 062h +Stub98__14nsXPTCStubBaseFv endp + +; 99 STUB_ENTRY(97) + +Stub97__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 061h +Stub97__14nsXPTCStubBaseFv endp + +; 98 STUB_ENTRY(96) + +Stub96__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 060h +Stub96__14nsXPTCStubBaseFv endp + +; 97 STUB_ENTRY(95) + +Stub95__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 05fh +Stub95__14nsXPTCStubBaseFv endp + +; 96 STUB_ENTRY(94) + +Stub94__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 05eh +Stub94__14nsXPTCStubBaseFv endp + +; 95 STUB_ENTRY(93) + +Stub93__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 05dh +Stub93__14nsXPTCStubBaseFv endp + +; 94 STUB_ENTRY(92) + +Stub92__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 05ch +Stub92__14nsXPTCStubBaseFv endp + +; 93 STUB_ENTRY(91) + +Stub91__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 05bh +Stub91__14nsXPTCStubBaseFv endp + +; 92 STUB_ENTRY(90) + +Stub90__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 05ah +Stub90__14nsXPTCStubBaseFv endp + +; 91 STUB_ENTRY(89) + +Stub89__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 059h +Stub89__14nsXPTCStubBaseFv endp + +; 90 STUB_ENTRY(88) + +Stub88__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 058h +Stub88__14nsXPTCStubBaseFv endp + +; 89 STUB_ENTRY(87) + +Stub87__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 057h +Stub87__14nsXPTCStubBaseFv endp + +; 88 STUB_ENTRY(86) + +Stub86__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 056h +Stub86__14nsXPTCStubBaseFv endp + +; 87 STUB_ENTRY(85) + +Stub85__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 055h +Stub85__14nsXPTCStubBaseFv endp + +; 86 STUB_ENTRY(84) + +Stub84__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 054h +Stub84__14nsXPTCStubBaseFv endp + +; 85 STUB_ENTRY(83) + +Stub83__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 053h +Stub83__14nsXPTCStubBaseFv endp + +; 84 STUB_ENTRY(82) + +Stub82__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 052h +Stub82__14nsXPTCStubBaseFv endp + +; 83 STUB_ENTRY(81) + +Stub81__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 051h +Stub81__14nsXPTCStubBaseFv endp + +; 82 STUB_ENTRY(80) + +Stub80__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 050h +Stub80__14nsXPTCStubBaseFv endp + +; 81 STUB_ENTRY(79) + +Stub79__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 04fh +Stub79__14nsXPTCStubBaseFv endp + +; 80 STUB_ENTRY(78) + +Stub78__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 04eh +Stub78__14nsXPTCStubBaseFv endp + +; 79 STUB_ENTRY(77) + +Stub77__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 04dh +Stub77__14nsXPTCStubBaseFv endp + +; 78 STUB_ENTRY(76) + +Stub76__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 04ch +Stub76__14nsXPTCStubBaseFv endp + +; 77 STUB_ENTRY(75) + +Stub75__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 04bh +Stub75__14nsXPTCStubBaseFv endp + +; 76 STUB_ENTRY(74) + +Stub74__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 04ah +Stub74__14nsXPTCStubBaseFv endp + +; 75 STUB_ENTRY(73) + +Stub73__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 049h +Stub73__14nsXPTCStubBaseFv endp + +; 74 STUB_ENTRY(72) + +Stub72__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 048h +Stub72__14nsXPTCStubBaseFv endp + +; 73 STUB_ENTRY(71) + +Stub71__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 047h +Stub71__14nsXPTCStubBaseFv endp + +; 72 STUB_ENTRY(70) + +Stub70__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 046h +Stub70__14nsXPTCStubBaseFv endp + +; 71 STUB_ENTRY(69) + +Stub69__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 045h +Stub69__14nsXPTCStubBaseFv endp + +; 70 STUB_ENTRY(68) + +Stub68__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 044h +Stub68__14nsXPTCStubBaseFv endp + +; 69 STUB_ENTRY(67) + +Stub67__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 043h +Stub67__14nsXPTCStubBaseFv endp + +; 68 STUB_ENTRY(66) + +Stub66__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 042h +Stub66__14nsXPTCStubBaseFv endp + +; 67 STUB_ENTRY(65) + +Stub65__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 041h +Stub65__14nsXPTCStubBaseFv endp + +; 66 STUB_ENTRY(64) + +Stub64__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 040h +Stub64__14nsXPTCStubBaseFv endp + +; 65 STUB_ENTRY(63) + +Stub63__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 03fh +Stub63__14nsXPTCStubBaseFv endp + +; 64 STUB_ENTRY(62) + +Stub62__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 03eh +Stub62__14nsXPTCStubBaseFv endp + +; 63 STUB_ENTRY(61) + +Stub61__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 03dh +Stub61__14nsXPTCStubBaseFv endp + +; 62 STUB_ENTRY(60) + +Stub60__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 03ch +Stub60__14nsXPTCStubBaseFv endp + +; 61 STUB_ENTRY(59) + +Stub59__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 03bh +Stub59__14nsXPTCStubBaseFv endp + +; 60 STUB_ENTRY(58) + +Stub58__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 03ah +Stub58__14nsXPTCStubBaseFv endp + +; 59 STUB_ENTRY(57) + +Stub57__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 039h +Stub57__14nsXPTCStubBaseFv endp + +; 58 STUB_ENTRY(56) + +Stub56__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 038h +Stub56__14nsXPTCStubBaseFv endp + +; 57 STUB_ENTRY(55) + +Stub55__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 037h +Stub55__14nsXPTCStubBaseFv endp + +; 56 STUB_ENTRY(54) + +Stub54__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 036h +Stub54__14nsXPTCStubBaseFv endp + +; 55 STUB_ENTRY(53) + +Stub53__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 035h +Stub53__14nsXPTCStubBaseFv endp + +; 54 STUB_ENTRY(52) + +Stub52__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 034h +Stub52__14nsXPTCStubBaseFv endp + +; 53 STUB_ENTRY(51) + +Stub51__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 033h +Stub51__14nsXPTCStubBaseFv endp + +; 52 STUB_ENTRY(50) + +Stub50__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 032h +Stub50__14nsXPTCStubBaseFv endp + +; 51 STUB_ENTRY(49) + +Stub49__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 031h +Stub49__14nsXPTCStubBaseFv endp + +; 50 STUB_ENTRY(48) + +Stub48__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 030h +Stub48__14nsXPTCStubBaseFv endp + +; 49 STUB_ENTRY(47) + +Stub47__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 02fh +Stub47__14nsXPTCStubBaseFv endp + +; 48 STUB_ENTRY(46) + +Stub46__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 02eh +Stub46__14nsXPTCStubBaseFv endp + +; 47 STUB_ENTRY(45) + +Stub45__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 02dh +Stub45__14nsXPTCStubBaseFv endp + +; 46 STUB_ENTRY(44) + +Stub44__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 02ch +Stub44__14nsXPTCStubBaseFv endp + +; 45 STUB_ENTRY(43) + +Stub43__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 02bh +Stub43__14nsXPTCStubBaseFv endp + +; 44 STUB_ENTRY(42) + +Stub42__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 02ah +Stub42__14nsXPTCStubBaseFv endp + +; 43 STUB_ENTRY(41) + +Stub41__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 029h +Stub41__14nsXPTCStubBaseFv endp + +; 42 STUB_ENTRY(40) + +Stub40__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 028h +Stub40__14nsXPTCStubBaseFv endp + +; 41 STUB_ENTRY(39) + +Stub39__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 027h +Stub39__14nsXPTCStubBaseFv endp + +; 40 STUB_ENTRY(38) + +Stub38__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 026h +Stub38__14nsXPTCStubBaseFv endp + +; 39 STUB_ENTRY(37) + +Stub37__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 025h +Stub37__14nsXPTCStubBaseFv endp + +; 38 STUB_ENTRY(36) + +Stub36__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 024h +Stub36__14nsXPTCStubBaseFv endp + +; 37 STUB_ENTRY(35) + +Stub35__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 023h +Stub35__14nsXPTCStubBaseFv endp + +; 36 STUB_ENTRY(34) + +Stub34__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 022h +Stub34__14nsXPTCStubBaseFv endp + +; 35 STUB_ENTRY(33) + +Stub33__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 021h +Stub33__14nsXPTCStubBaseFv endp + +; 34 STUB_ENTRY(32) + +Stub32__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 020h +Stub32__14nsXPTCStubBaseFv endp + +; 33 STUB_ENTRY(31) + +Stub31__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 01fh +Stub31__14nsXPTCStubBaseFv endp + +; 32 STUB_ENTRY(30) + +Stub30__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 01eh +Stub30__14nsXPTCStubBaseFv endp + +; 31 STUB_ENTRY(29) + +Stub29__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 01dh +Stub29__14nsXPTCStubBaseFv endp + +; 30 STUB_ENTRY(28) + +Stub28__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 01ch +Stub28__14nsXPTCStubBaseFv endp + +; 29 STUB_ENTRY(27) + +Stub27__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 01bh +Stub27__14nsXPTCStubBaseFv endp + +; 28 STUB_ENTRY(26) + +Stub26__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 01ah +Stub26__14nsXPTCStubBaseFv endp + +; 27 STUB_ENTRY(25) + +Stub25__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 019h +Stub25__14nsXPTCStubBaseFv endp + +; 26 STUB_ENTRY(24) + +Stub24__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 018h +Stub24__14nsXPTCStubBaseFv endp + +; 25 STUB_ENTRY(23) + +Stub23__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 017h +Stub23__14nsXPTCStubBaseFv endp + +; 24 STUB_ENTRY(22) + +Stub22__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 016h +Stub22__14nsXPTCStubBaseFv endp + +; 23 STUB_ENTRY(21) + +Stub21__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 015h +Stub21__14nsXPTCStubBaseFv endp + +; 22 STUB_ENTRY(20) + +Stub20__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 014h +Stub20__14nsXPTCStubBaseFv endp + +; 21 STUB_ENTRY(19) + +Stub19__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 013h +Stub19__14nsXPTCStubBaseFv endp + +; 20 STUB_ENTRY(18) + +Stub18__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 012h +Stub18__14nsXPTCStubBaseFv endp + +; 19 STUB_ENTRY(17) + +Stub17__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 011h +Stub17__14nsXPTCStubBaseFv endp + +; 18 STUB_ENTRY(16) + +Stub16__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 010h +Stub16__14nsXPTCStubBaseFv endp + +; 17 STUB_ENTRY(15) + +Stub15__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0fh +Stub15__14nsXPTCStubBaseFv endp + +; 16 STUB_ENTRY(14) + +Stub14__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0eh +Stub14__14nsXPTCStubBaseFv endp + +; 15 STUB_ENTRY(13) + +Stub13__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0dh +Stub13__14nsXPTCStubBaseFv endp + +; 14 STUB_ENTRY(12) + +Stub12__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0ch +Stub12__14nsXPTCStubBaseFv endp + +; 13 STUB_ENTRY(11) + +Stub11__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0bh +Stub11__14nsXPTCStubBaseFv endp + +; 12 STUB_ENTRY(10) + +Stub10__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0ah +Stub10__14nsXPTCStubBaseFv endp + +; 11 STUB_ENTRY(9) + +Stub9__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 09h +Stub9__14nsXPTCStubBaseFv endp + +; 10 STUB_ENTRY(8) + +Stub8__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 08h +Stub8__14nsXPTCStubBaseFv endp + +; 9 STUB_ENTRY(7) + +Stub7__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 07h +Stub7__14nsXPTCStubBaseFv endp + +; 8 STUB_ENTRY(6) + +Stub6__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 06h +Stub6__14nsXPTCStubBaseFv endp + +; 7 STUB_ENTRY(5) + +Stub5__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 05h +Stub5__14nsXPTCStubBaseFv endp + +; 6 STUB_ENTRY(4) + +Stub4__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 04h +Stub4__14nsXPTCStubBaseFv endp + +; 5 STUB_ENTRY(3) + +Stub3__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 03h +Stub3__14nsXPTCStubBaseFv endp + + + END + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/test/.cvsignore b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/test/.cvsignore new file mode 100644 index 00000000..055e647f --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/test/.cvsignore @@ -0,0 +1,2 @@ +Makefile +invoke_test diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/test/Makefile.in b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/test/Makefile.in new file mode 100644 index 00000000..dbf0f64d --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/test/Makefile.in @@ -0,0 +1,50 @@ +# +# ***** 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.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of 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 ***** + +DEPTH = ../../../../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = xpcom +CPPSRCS = stub_test.cpp #invoke_test.cpp +SIMPLE_PROGRAMS = $(CPPSRCS:.cpp=$(BIN_SUFFIX)) + +include $(topsrcdir)/config/rules.mk + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/test/README b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/test/README new file mode 100644 index 00000000..04850b2e --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/test/README @@ -0,0 +1,6 @@ +These are just simple test programs in which stripped down versions of the +XPConnect invoke and stubs code can be built and tested as the code is brought +up on various platforms. These probrams do not test the param sizing and copying +functionality of the routines. However, they do supply a place where the lowest +level assembly language code can be developed and debugged in the simplest of +contexts before it is moved into the real routines. \ No newline at end of file diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/test/clean.bat b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/test/clean.bat new file mode 100644 index 00000000..f320e222 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/test/clean.bat @@ -0,0 +1,5 @@ +@echo off +echo deleting intermediate files +if exist *.obj del *.obj > NUL +if exist *.ilk del *.ilk > NUL +if exist *.pdb del *.pdb > NUL \ No newline at end of file diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/test/invoke_test.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/test/invoke_test.cpp new file mode 100644 index 00000000..376ba58f --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/test/invoke_test.cpp @@ -0,0 +1,239 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 + +typedef unsigned nsresult; +typedef unsigned PRUint32; +typedef unsigned nsXPCVariant; + + +#if defined(WIN32) +#define NS_IMETHOD virtual nsresult __stdcall +#define NS_IMETHODIMP nsresult __stdcall +#else +#define NS_IMETHOD virtual nsresult +#define NS_IMETHODIMP nsresult +#endif + + +class base{ +public: + NS_IMETHOD ignored() = 0; +}; + +class foo : public base { +public: + NS_IMETHOD callme1(int i, int j) = 0; + NS_IMETHOD callme2(int i, int j) = 0; + NS_IMETHOD callme3(int i, int j) = 0; +}; + +class bar : public foo{ +public: + NS_IMETHOD ignored(); + NS_IMETHOD callme1(int i, int j); + NS_IMETHOD callme2(int i, int j); + NS_IMETHOD callme3(int i, int j); +}; + +/* +class baz : public base { +public: + NS_IMETHOD ignored(); + NS_IMETHOD callme1(); + NS_IMETHOD callme2(); + NS_IMETHOD callme3(); + void setfoo(foo* f) {other = f;} + + foo* other; +}; +NS_IMETHODIMP baz::ignored(){return 0;} +*/ + +NS_IMETHODIMP bar::ignored(){return 0;} + +NS_IMETHODIMP bar::callme1(int i, int j) +{ + printf("called bar::callme1 with: %d %d\n", i, j); + return 5; +} + +NS_IMETHODIMP bar::callme2(int i, int j) +{ + printf("called bar::callme2 with: %d %d\n", i, j); + return 5; +} + +NS_IMETHODIMP bar::callme3(int i, int j) +{ + printf("called bar::callme3 with: %d %d\n", i, j); + return 5; +} + +void docall(foo* f, int i, int j){ + f->callme1(i, j); +} + +/***************************************************************************/ +#if defined(WIN32) + +static PRUint32 __stdcall +invoke_count_words(PRUint32 paramCount, nsXPCVariant* s) +{ + return paramCount; +} + +static void __stdcall +invoke_copy_to_stack(PRUint32* d, PRUint32 paramCount, nsXPCVariant* s) +{ + for(PRUint32 i = 0; i < paramCount; i++, d++, s++) + { + *((PRUint32*)d) = *((PRUint32*)s); + } +} + +static nsresult __stdcall +DoInvoke(void* that, PRUint32 index, + PRUint32 paramCount, nsXPCVariant* params) +{ + __asm { + push params + push paramCount + call invoke_count_words // stdcall, result in eax + shl eax,2 // *= 4 + sub esp,eax // make space for params + mov edx,esp + push params + push paramCount + push edx + call invoke_copy_to_stack // stdcall + mov ecx,that // instance in ecx + push ecx // push this + mov edx,[ecx] // vtable in edx + mov eax,index + shl eax,2 // *= 4 + add edx,eax + call [edx] // stdcall, i.e. callee cleans up stack. + } +} + +#else +/***************************************************************************/ +// just Linux_x86 now. Add other later... + +static PRUint32 +invoke_count_words(PRUint32 paramCount, nsXPCVariant* s) +{ + return paramCount; +} + +static void +invoke_copy_to_stack(PRUint32* d, PRUint32 paramCount, nsXPCVariant* s) +{ + for(PRUint32 i = 0; i < paramCount; i++, d++, s++) + { + *((PRUint32*)d) = *((PRUint32*)s); + } +} + +static nsresult +DoInvoke(void* that, PRUint32 index, + PRUint32 paramCount, nsXPCVariant* params) +{ + PRUint32 result; + void* fn_count = invoke_count_words; + void* fn_copy = invoke_copy_to_stack; + + __asm__ __volatile__( + "pushl %4\n\t" + "pushl %3\n\t" + "movl %5, %%eax\n\t" + "call *%%eax\n\t" /* count words */ + "addl $0x8, %%esp\n\t" + "shl $2, %%eax\n\t" /* *= 4 */ + "subl %%eax, %%esp\n\t" /* make room for params */ + "movl %%esp, %%edx\n\t" + "pushl %4\n\t" + "pushl %3\n\t" + "pushl %%edx\n\t" + "movl %6, %%eax\n\t" + "call *%%eax\n\t" /* copy params */ + "addl $0xc, %%esp\n\t" + "movl %1, %%ecx\n\t" + "pushl %%ecx\n\t" + "movl (%%ecx), %%edx\n\t" + "movl %2, %%eax\n\t" /* function index */ + "shl $2, %%eax\n\t" /* *= 4 */ + "addl $8, %%eax\n\t" /* += 8 */ + "addl %%eax, %%edx\n\t" + "call *(%%edx)\n\t" /* safe to not cleanup esp */ + "movl %%eax, %0" + : "=g" (result) /* %0 */ + : "g" (that), /* %1 */ + "g" (index), /* %2 */ + "g" (paramCount), /* %3 */ + "g" (params), /* %4 */ + "g" (fn_count), /* %5 */ + "g" (fn_copy) /* %6 */ + : "ax", "cx", "dx", "memory" + ); + + return result; +} + +#endif +/***************************************************************************/ + +int main() +{ + nsXPCVariant params1[2] = {1,2}; + nsXPCVariant params2[2] = {2,4}; + nsXPCVariant params3[2] = {3,6}; + + foo* a = new bar(); + +// printf("calling via C++...\n"); +// docall(a, 12, 24); + + printf("calling via ASM...\n"); + DoInvoke(a, 1, 2, params1); + DoInvoke(a, 2, 2, params2); + DoInvoke(a, 3, 2, params3); + + return 0; +} diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/test/mk_invoke.bat b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/test/mk_invoke.bat new file mode 100644 index 00000000..10a9be51 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/test/mk_invoke.bat @@ -0,0 +1,9 @@ +@echo off +@echo deleing old output +if exist invoke_test.obj del invoke_test.obj > NUL +if exist invoke_test.ilk del invoke_test.ilk > NUL +if exist *.pdb del *.pdb > NUL +if exist invoke_test.exe del invoke_test.exe > NUL + +@echo building... +cl /nologo -Zi -DWIN32 invoke_test.cpp \ No newline at end of file diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/test/mk_stub.bat b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/test/mk_stub.bat new file mode 100644 index 00000000..f9af17af --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/test/mk_stub.bat @@ -0,0 +1,9 @@ +@echo off +@echo deleing old output +if exist stub_test.obj del stub_test.obj > NUL +if exist stub_test.ilk del stub_test.ilk > NUL +if exist *.pdb del *.pdb > NUL +if exist stub_test.exe del stub_test.exe > NUL + +@echo building... +cl /nologo -Zi -DWIN32 stub_test.cpp \ No newline at end of file diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/test/stub_test.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/test/stub_test.cpp new file mode 100644 index 00000000..10935299 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/test/stub_test.cpp @@ -0,0 +1,210 @@ + +#include + +typedef unsigned nsresult; +typedef unsigned PRUint32; +typedef unsigned nsXPCVariant; + + +#if defined(WIN32) +#define NS_IMETHOD virtual nsresult __stdcall +#define NS_IMETHODIMP nsresult __stdcall +#else +#define NS_IMETHOD virtual nsresult +#define NS_IMETHODIMP nsresult +#endif + + +class base{ +public: + NS_IMETHOD ignored() = 0; +}; + +class foo : public base { +public: + NS_IMETHOD callme1(int i, int j) = 0; + NS_IMETHOD callme2(int i, int j) = 0; + NS_IMETHOD callme3(int i, int j) = 0; +}; + +class bar : public foo{ +public: + NS_IMETHOD ignored(); + NS_IMETHOD callme1(int i, int j); + NS_IMETHOD callme2(int i, int j); + NS_IMETHOD callme3(int i, int j); +}; + +class baz : public base { +public: + NS_IMETHOD ignored(); + NS_IMETHOD callme1(); + NS_IMETHOD callme2(); + NS_IMETHOD callme3(); + void setfoo(foo* f) {other = f;} + + foo* other; +}; +NS_IMETHODIMP baz::ignored(){return 0;} + +NS_IMETHODIMP bar::ignored(){return 0;} + +NS_IMETHODIMP bar::callme1(int i, int j) +{ + printf("called bar::callme1 with: %d %d\n", i, j); + return 15; +} + +NS_IMETHODIMP bar::callme2(int i, int j) +{ + printf("called bar::callme2 with: %d %d\n", i, j); + return 25; +} + +NS_IMETHODIMP bar::callme3(int i, int j) +{ + printf("called bar::callme3 with: %d %d\n", i, j); + return 35; +} + +void docall(foo* f, int i, int j){ + f->callme1(i, j); +} + +/***************************************************************************/ +#if defined(WIN32) + +static int __stdcall +PrepareAndDispatch(baz* self, PRUint32 methodIndex, + PRUint32* args, PRUint32* stackBytesToPop) +{ + fprintf(stdout, "PrepareAndDispatch (%p, %d, %p)\n", + (void*)self, methodIndex, (void*)args); + foo* a = self->other; + int p1 = (int) *args; + int p2 = (int) *(args+1); + int out = 0; + switch(methodIndex) + { + case 1: out = a->callme1(p1, p2); break; + case 2: out = a->callme2(p1, p2); break; + case 3: out = a->callme3(p1, p2); break; + } + *stackBytesToPop = 2*4; + return out; +} + +#ifndef __GNUC__ +static __declspec(naked) void SharedStub(void) +{ + __asm { + push ebp // set up simple stack frame + mov ebp, esp // stack has: ebp/vtbl_index/retaddr/this/args + push ecx // make room for a ptr + lea eax, [ebp-4] // pointer to stackBytesToPop + push eax + lea ecx, [ebp+16] // pointer to args + push ecx + mov edx, [ebp+4] // vtbl_index + push edx + mov eax, [ebp+12] // this + push eax + call PrepareAndDispatch + mov edx, [ebp+8] // return address + mov ecx, [ebp-4] // stackBytesToPop + add ecx, 12 // for this, the index, and ret address + mov esp, ebp + pop ebp + add esp, ecx // fix up stack pointer + jmp edx // simulate __stdcall return + } +} + +// these macros get expanded (many times) in the file #included below +#define STUB_ENTRY(n) \ +__declspec(naked) nsresult __stdcall baz::callme##n() \ +{ __asm push n __asm jmp SharedStub } + +#else /* __GNUC__ */ + +#define STUB_ENTRY(n) \ +nsresult __stdcall baz::callme##n() \ +{ \ + PRUint32 *args, stackBytesToPop; \ + int result = 0; \ + baz *obj; \ + __asm__ __volatile__ ( \ + "leal 0x0c(%%ebp), %0\n\t" /* args */ \ + "movl 0x08(%%ebp), %1\n\t" /* this */ \ + : "=r" (args), \ + "=r" (obj)); \ + result = PrepareAndDispatch(obj, n, args,&stackBytesToPop); \ + fprintf(stdout, "stub returning: %d\n", result); \ + fprintf(stdout, "bytes to pop: %d\n", stackBytesToPop); \ + return result; \ +} + +#endif /* ! __GNUC__ */ + +#else +/***************************************************************************/ +// just Linux_x86 now. Add other later... + +static int +PrepareAndDispatch(baz* self, PRUint32 methodIndex, PRUint32* args) +{ + foo* a = self->other; + int p1 = (int) *args; + int p2 = (int) *(args+1); + switch(methodIndex) + { + case 1: a->callme1(p1, p2); break; + case 2: a->callme2(p1, p2); break; + case 3: a->callme3(p1, p2); break; + } + return 1; +} + +#define STUB_ENTRY(n) \ +nsresult baz::callme##n() \ +{ \ + register void* method = PrepareAndDispatch; \ + register nsresult result; \ + __asm__ __volatile__( \ + "leal 0x0c(%%ebp), %%ecx\n\t" /* args */ \ + "pushl %%ecx\n\t" \ + "pushl $"#n"\n\t" /* method index */ \ + "movl 0x08(%%ebp), %%ecx\n\t" /* this */ \ + "pushl %%ecx\n\t" \ + "call *%%edx" /* PrepareAndDispatch */ \ + : "=a" (result) /* %0 */ \ + : "d" (method) /* %1 */ \ + : "memory" ); \ + return result; \ +} + +#endif +/***************************************************************************/ + +STUB_ENTRY(1) +STUB_ENTRY(2) +STUB_ENTRY(3) + +int main() +{ + foo* a = new bar(); + baz* b = new baz(); + + /* here we make the global 'check for alloc failure' checker happy */ + if(!a || !b) + return 1; + + foo* c = (foo*)b; + + b->setfoo(a); + c->callme1(1,2); + c->callme2(2,4); + c->callme3(3,6); + + return 0; +} diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/.cvsignore b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/.cvsignore new file mode 100644 index 00000000..ff6fd9bc --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/.cvsignore @@ -0,0 +1,2 @@ +Makefile +xptcstubs_asm_mips.s diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/Makefile.in b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/Makefile.in new file mode 100644 index 00000000..78bf1f92 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/Makefile.in @@ -0,0 +1,416 @@ +# +# ***** 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.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of 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 ***** + +DEPTH = ../../../../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = xpcom +LIBRARY_NAME = xptcmd + +# +# The default is this buildable, but non-functioning code. +# +CPPSRCS := xptcinvoke_unsupported.cpp xptcstubs_unsupported.cpp + +# Force use of PIC +FORCE_USE_PIC = 1 + +include $(topsrcdir)/config/config.mk + +###################################################################### +# i386 and beyond +###################################################################### +# +# Lots of Unixish x86 flavors +# +ifneq (,$(filter FreeBSD NetBSD OpenBSD BSD_OS Darwin,$(OS_ARCH))) +ifeq (86,$(findstring 86,$(OS_TEST))) +CPPSRCS := xptcinvoke_unixish_x86.cpp xptcstubs_unixish_x86.cpp +endif +endif +# +# New code for Linux, et. al., with gcc +# Migrate other platforms here after testing +# +ifneq (,$(filter Linux,$(OS_ARCH))) +# Linux/x86-64 +ifeq (x86_64,$(OS_TEST)) +CPPSRCS := xptcinvoke_x86_64_linux.cpp xptcstubs_x86_64_linux.cpp +else +ifeq (86,$(findstring 86,$(OS_TEST))) +CPPSRCS := xptcinvoke_gcc_x86_unix.cpp xptcstubs_gcc_x86_unix.cpp +endif +endif +endif +# IA64 Linux +ifneq (,$(filter Linux,$(OS_ARCH))) +ifneq (,$(findstring ia64,$(OS_TEST))) +CPPSRCS := xptcinvoke_ipf64.cpp xptcstubs_ipf64.cpp +ASFILES := xptcstubs_asm_ipf64.s xptcinvoke_asm_ipf64.s +endif +endif +# +# BeOS/Intel (uses the same unixish_x86 code) +# +ifeq ($(OS_ARCH)$(OS_TEST),BeOSBePC) +CPPSRCS := xptcinvoke_unixish_x86.cpp xptcstubs_unixish_x86.cpp +endif +# +# Neutrino/Intel (uses the same unixish_x86 code) +# +ifeq ($(OS_TARGET)$(OS_TEST),NTOx86) +CPPSRCS := xptcinvoke_unixish_x86.cpp xptcstubs_unixish_x86.cpp +endif + +###################################################################### +# Solaris/Intel +###################################################################### +# +# Solaris/Intel +# +ifeq ($(OS_ARCH),SunOS) +ifeq ($(OS_TEST),i86pc) +CPPSRCS := xptcinvoke_x86_solaris.cpp xptcstubs_x86_solaris.cpp +# 28817: if Solaris Intel OS, and native compiler, always build optimised. +ifndef GNU_CC +CXXFLAGS += -O +endif +endif +endif + +###################################################################### +# Alpha +###################################################################### +# +# Tru64/Alpha +# +ifeq ($(OS_ARCH)$(OS_TEST),OSF1alpha) +CPPSRCS := xptcinvoke_osf1_alpha.cpp xptcstubs_osf1_alpha.cpp +ASFILES := xptcinvoke_asm_osf1_alpha.s xptcstubs_asm_osf1_alpha.s +endif +# +# Linux/Alpha +# +ifneq (,$(filter Linuxalpha FreeBSDalpha NetBSDalpha,$(OS_ARCH)$(OS_TEST))) +CPPSRCS := xptcinvoke_linux_alpha.cpp xptcstubs_linux_alpha.cpp +endif +# +# OpenVMS/Alpha +# +ifeq ($(OS_ARCH)$(CPU_ARCH),OpenVMSAlpha) +CPPSRCS := xptcinvoke_openvms_alpha.cpp xptcstubs_openvms_alpha.cpp +ASFILES := xptcinvoke_asm_openvms_alpha.s xptcstubs_asm_openvms_alpha.s +endif + +###################################################################### +# ARM +###################################################################### +# +# Linux/ARM +# +ifeq ($(OS_ARCH),Linux) +ifneq (,$(filter arm% sa110,$(OS_TEST))) +CPPSRCS := xptcinvoke_arm.cpp xptcstubs_arm.cpp +CXXFLAGS += -O2 +endif +endif +# +# NetBSD/ARM +# +ifeq ($(OS_ARCH),NetBSD) +ifneq (,$(filter arm% sa110,$(OS_TEST))) +CPPSRCS := xptcinvoke_arm_netbsd.cpp xptcstubs_arm_netbsd.cpp +endif +endif + +###################################################################### +# HPPA +###################################################################### +# +# HP-UX/PA32 +# +# for gas and gcc, check comment in xptcinvoke_asm_pa32.s +ifeq ($(OS_ARCH),HP-UX) +ifneq ($(CC),gcc) +ifneq ($(OS_TEST),ia64) +CPPSRCS := xptcinvoke_pa32.cpp xptcstubs_pa32.cpp +ASFILES := xptcstubs_asm_pa32.s xptcinvoke_asm_pa32.s +else +CPPSRCS := xptcinvoke_ipf32.cpp xptcstubs_ipf32.cpp +ASFILES := xptcstubs_asm_ipf32.s xptcinvoke_asm_ipf32.s +endif + +# #18875 Building the CPP's (CXX) optimized causes a crash +CXXFLAGS := $(filter-out $(MOZ_OPTIMIZE_FLAGS), $(CXXFLAGS)) +endif +endif + +###################################################################### +# M68k +###################################################################### +# +# NetBSD/m68k +# +ifeq ($(OS_ARCH),NetBSD) +ifneq (,$(filter amiga atari hp300 mac68k mvme68k next68k sun3 sun3x x68k,$(OS_TEST))) +CPPSRCS := xptcinvoke_netbsd_m68k.cpp xptcstubs_netbsd_m68k.cpp +endif +endif + +# +# Linux/m68k +# +ifeq ($(OS_ARCH),Linux) +ifeq ($(OS_TEST),m68k) +CPPSRCS := xptcinvoke_linux_m68k.cpp xptcstubs_linux_m68k.cpp +endif +endif + +###################################################################### +# MIPS +###################################################################### +# +# IRIX/MIPS +# +ifeq ($(OS_ARCH),IRIX) +ifneq ($(basename $(OS_RELEASE)),5) +CPPSRCS := xptcinvoke_irix.cpp xptcstubs_irix.cpp +ASFILES := xptcinvoke_asm_irix.s xptcstubs_asm_irix.s +ifdef GNU_CC +ASFLAGS += -Wa,-D__GNUC__ +else +CXXFLAGS := $(shell echo $(CXXFLAGS) | sed 's/-O\(3\|fast\)/-O2/g') +endif +endif +endif + +ifeq ($(OS_ARCH),Linux) +ifneq (,$(findstring mips, $(OS_TEST))) +CPPSRCS := xptcinvoke_mips.cpp xptcstubs_mips.cpp +ASFILES := xptcinvoke_asm_mips.s xptcstubs_asm_mips.s +#xptcstubs_mips.cpp +# xptcstubs_asm_mips.s +ifdef GNU_CC +ASFLAGS += $(INCLUDES) -x assembler-with-cpp -D__GNUC__ +endif +endif +endif + +###################################################################### +# PowerPC +###################################################################### +# +# AIX/PPC +# +ifeq ($(OS_ARCH),AIX) +ifdef HAVE_64BIT_OS +CPPSRCS := xptcinvoke_ppc_aix64.cpp xptcstubs_ppc_aix64.cpp +ASFILES := xptcinvoke_asm_ppc_aix64.s xptcstubs_asm_ppc_aix64.s +else +ifeq ($(AIX_OBJMODEL),ibm) +CPPSRCS := xptcinvoke_ppc_aix.cpp xptcstubs_ppc_aix.cpp +ASFILES := xptcinvoke_asm_ppc_ibmobj_aix.s xptcstubs_asm_ppc_aix.s +else +CPPSRCS := xptcinvoke_ppc_aix.cpp xptcstubs_ppc_aix.cpp +ASFILES := xptcinvoke_asm_ppc_aix.s xptcstubs_asm_ppc_aix.s +endif +endif + +# #24617 Building the CPP's (CXX) optimized causes a crash +CXXFLAGS := $(filter-out $(MOZ_OPTIMIZE_FLAGS), $(CXXFLAGS)) +endif + +# +# Linux/PPC +# +ifeq ($(OS_ARCH)$(OS_TEST),Linuxppc) +CPPSRCS := xptcinvoke_ppc_linux.cpp xptcstubs_ppc_linux.cpp +ASFILES := xptcinvoke_asm_ppc_linux.s xptcstubs_asm_ppc_linux.s +AS := $(CC) -c -x assembler-with-cpp +endif + +# +# NetBSD/PPC +# +ifneq (,$(filter NetBSDmacppc NetBSDbebox NetBSDofppc NetBSDprep NetBSDamigappc,$(OS_ARCH)$(OS_TEST))) +CPPSRCS := xptcinvoke_ppc_netbsd.cpp xptcstubs_ppc_netbsd.cpp +ASFILES := xptcinvoke_asm_ppc_netbsd.s xptcstubs_asm_ppc_netbsd.s +endif + +# +# Darwin/PPC +# +ifeq ($(OS_ARCH),Darwin) +ifeq ($(TARGET_CPU), powerpc) +ASFLAGS += -x assembler-with-cpp # assumes $(AS) == $(CC) +ifdef HAVE_GCC3_ABI +ASFLAGS += -DHAVE_GCC3_ABI +endif +CPPSRCS := xptcinvoke_ppc_rhapsody.cpp xptcstubs_ppc_rhapsody.cpp +ASFILES := xptcinvoke_asm_ppc_rhapsody.s xptcstubs_asm_ppc_darwin.s +endif +endif + +###################################################################### +# SPARC +###################################################################### +# +# BSD_OS/SPARC +# +ifeq ($(OS_ARCH),BSD_OS) +ifneq (,$(findstring sparc,$(OS_TEST))) +CPPSRCS := xptcinvoke_sparc_solaris.cpp xptcstubs_sparc_solaris.cpp +ASFILES := xptcinvoke_asm_sparc_bsdos.s xptcstubs_asm_sparc_solaris.s +endif +endif +# +# Linux/SPARC +# +ifeq ($(OS_ARCH),Linux) +ifneq (,$(findstring sparc,$(OS_TEST))) +CPPSRCS := xptcinvoke_sparc_solaris.cpp xptcstubs_sparc_solaris.cpp +ifdef HAVE_GCC3_ABI +ASFILES := xptcinvoke_asm_sparc_linux_GCC3.s xptcstubs_asm_sparc_solaris.s +else +ASFILES := xptcinvoke_asm_sparc_linux.s xptcstubs_asm_sparc_solaris.s +endif +endif +endif +# +# NetBSD/SPARC +# +ifeq ($(OS_ARCH)$(OS_TEST),NetBSDsparc) +CPPSRCS := xptcinvoke_sparc_netbsd.cpp xptcstubs_sparc_netbsd.cpp +ASFILES := xptcinvoke_asm_sparc_netbsd.s xptcstubs_asm_sparc_netbsd.s +endif +# +# Solaris/SPARC +# +ifeq ($(OS_ARCH),SunOS) +ifneq (86,$(findstring 86,$(OS_TEST))) +ifdef HAVE_64BIT_OS +CPPSRCS := xptcinvoke_sparcv9_solaris.cpp xptcstubs_sparcv9_solaris.cpp +else +CPPSRCS := xptcinvoke_sparc_solaris.cpp xptcstubs_sparc_solaris.cpp +endif + +ifeq ($(GNU_CC),1) +ifdef HAVE_GCC3_ABI +ASFILES := xptcinvoke_asm_sparc_solaris_GCC3.s xptcstubs_asm_sparc_solaris.s +else +ASFILES := xptcinvoke_asm_sparc_solaris_GCC.s xptcstubs_asm_sparc_solaris.s +endif +else +ifdef HAVE_64BIT_OS +ASFILES := xptcinvoke_asm_sparcv9_solaris_SUNW.s xptcstubs_asm_sparcv9_solaris.s +else +ASFILES := xptcinvoke_asm_sparc_solaris_SUNW.s xptcstubs_asm_sparc_solaris.s +endif +endif + +endif +endif + +###################################################################### +# S/390 +###################################################################### +# +# Linux for S/390 +# +ifeq ($(OS_ARCH)$(OS_TEST),Linuxs390) +CPPSRCS := xptcinvoke_linux_s390.cpp xptcstubs_linux_s390.cpp +endif + +ifeq ($(OS_ARCH)$(OS_TEST),Linuxs390x) +CPPSRCS := xptcinvoke_linux_s390x.cpp xptcstubs_linux_s390x.cpp +endif + + +# we don't want the shared lib, but we want to force the creation of a static lib. +FORCE_STATIC_LIB = 1 + +include $(topsrcdir)/config/rules.mk + +DEFINES += -DEXPORT_XPTC_API + +INCLUDES += -I$(srcdir)/../.. + +ifeq ($(OS_ARCH),Linux) +ifneq (,$(findstring mips, $(OS_TEST))) +xptcstubs_asm_mips.o: xptcstubs_asm_mips.s.m4 $(PUBLIC)/xptcstubsdef.inc + m4 $(INCLUDES) $< > ./xptcstubs_asm_mips.s && \ + $(AS) -o $@ $(ASFLAGS) $(AS_DASH_C_FLAG) ./xptcstubs_asm_mips.s + $(RM) -f ./xptcstubs_asm_mips.s +endif +endif + +ifeq ($(OS_ARCH),Darwin) +xptcstubs_asm_ppc_darwin.o: xptcstubs_asm_ppc_darwin.s.m4 $(PUBLIC)/xptcstubsdef.inc Makefile + gm4 $(INCLUDES) $< > ./xptcstubs_asm_ppc_darwin.s && \ + $(AS) -o $@ $(ASFLAGS) $(AS_DASH_C_FLAG) ./xptcstubs_asm_ppc_darwin.s + $(RM) -f ./xptcstubs_asm_ppc_darwin.s +endif + +ifeq ($(OS_ARCH),IRIX) +# The assembler on IRIX (6.3 only?) seems to have trouble with the default command, +# but works fine if we first copy the header and source file into the current dir. +xptcstubs_asm_irix.o: $(PUBLIC)/xptcstubsdef.inc $(srcdir)/xptcstubs_asm_irix.s + @rm -f ./xptcstubsdef.inc + @cp $(PUBLIC)/xptcstubsdef.inc . + @if test ! -f ./Makefile.in; then rm -f ./xptcstubs_asm_irix.s; cp $(srcdir)/xptcstubs_asm_irix.s .; else true; fi + $(AS) -o $@ $(ASFLAGS) $(AS_DASH_C_FLAG) ./xptcstubs_asm_irix.s + @rm -f ./xptcstubsdef.inc + @if test ! -f ./Makefile.in; then rm -f ./xptcstubs_asm_irix.s; else true; fi +endif + +ifeq ($(OS_ARCH),OpenVMS) +# Our assembler wants the include file to be of assembler syntax, not C/C++ +# syntax, so we have to massage it slightly. + +xptcstubs_asm_openvms_alpha.o: $(PUBLIC)/xptcstubsdef.inc $(srcdir)/xptcstubs_asm_openvms_alpha.s + sed \ + -e 's/^\(.*_ENTRY\)(\([0-9]*\))/ \1 \2/' \ + -e 's/\/\*\(.*\)\*\//; \1/' \ + $(PUBLIC)/xptcstubsdef.inc > ./xptcstubsdef_asm.vms + $(AS) -o $@ $(ASFLAGS) $(AS_DASH_C_FLAG) $(srcdir)/xptcstubs_asm_openvms_alpha.s + @rm -f ./xptcstubsdef_asm.vms +endif + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/Makefile.kup b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/Makefile.kup new file mode 100644 index 00000000..e69de29b diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/vtable_layout_x86.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/vtable_layout_x86.cpp new file mode 100644 index 00000000..912f50e4 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/vtable_layout_x86.cpp @@ -0,0 +1,62 @@ +/* this code contributed by Bert Driehuis */ + +#include + +// Try to determine the vtable layout generated by G++ +// Produces the offset at which the first vtable entry can be +// found, and the factor to apply for subsequent entries on stdout. +// Example output: +// #define GCC_VTABLE_START 0xc +// #define GCC_VTABLE_FACTOR 0x8 + +class test { +public: + virtual int t1(void); + virtual int t2(void); + int x; +}; + +test::test() { this->x = 0x12121212; }; + +int test::t1(void) { return 1; } +int test::t2(void) { return 2; } + +void die(char *x) { + fprintf(stderr, "%s\n", x); + exit(1); +} + +int +main() +{ + int i; + test *t = new test(); + int *tp = (int *) t; + int off1 = -1; + int off2 = -1; + int factor; + int factorshift; + + if (*tp++ != 0x12121212) + die("Integer element test::x not found!"); + tp = (int *) *tp; + for (i = 0; i < 10; i++) { + if (tp[i] == (int) t->t1) + off1 = i; + if (tp[i] == (int) t->t2) + off2 = i; + } + if (off1 == -1 || off2 == -1) + die("Could not determine offset into vtable!"); + factor = (off2 - off1) * 4; + factorshift = -1; + while (factor) { + factorshift++; + factor >>= 1; + } + printf("/* Automatically generated by vtable_layout_x86.cpp */\n"); + printf("#define GCC_VTABLE_START\t0x%x\n", off1 * 4); + printf("#define GCC_VTABLE_FACTOR\t0x%x\n", (off2 - off1) * 4); + printf("#define GCC_VTABLE_SHIFT\t0x%x\n", factorshift); + exit(0); +} diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptc_gcc_x86_unix.h b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptc_gcc_x86_unix.h new file mode 100644 index 00000000..707352aa --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptc_gcc_x86_unix.h @@ -0,0 +1,92 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Special include file for xptc*_gcc_x86_unix.cpp */ + +// +// this may improve the static function calls, but may not. +// + +// #define MOZ_USE_STDCALL + +#ifdef MOZ_USE_STDCALL +#define ATTRIBUTE_STDCALL __attribute__ ((__stdcall__)) +#else +#define ATTRIBUTE_STDCALL +#endif + +#ifdef MOZ_NEED_LEADING_UNDERSCORE +#define SYMBOL_UNDERSCORE "_" +#else +#define SYMBOL_UNDERSCORE +#endif + +/* + What are those keeper functions? + + The problem: gcc doesn't know that the assembler routines call + static functions so gcc may not emit the definition (i.e., the + code) for these functions. In gcc 3.1 and up + "__attribute__ ((used))" exists and solves the problem. + For older gcc versions it's not so easy. One could use the + -fkeep-inline-functions but that keeps a surprising number of + functions which bloats the compiled library. It seems otherwise + harmless, though. Alternatively, one could use + -fno-inline-functions which works right now but might cause a + slowdown under some circumstances. The problem with these methods + is that they do not automatically adapt to the compiler used. + + The best solution seems to be to create dummy functions that + reference the appropriate static functions. It's then necessary + to "use" these functions in a way that gcc will not optimize + away. The keeper functions use assembly code to confuse gcc. + + One drawback is that the keeper functions are externally visible + so they shouldn't do anything harmful. + + With the right linker, one could make the keeper functions local + so they wouldn't be visible. + */ + + +// gcc 3.1 and up +#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1) +#define ATTRIBUTE_USED __attribute__ ((__used__)) +#else +#define ATTRIBUTE_USED +#endif + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptc_platforms_unixish_x86.h b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptc_platforms_unixish_x86.h new file mode 100644 index 00000000..23eb23ee --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptc_platforms_unixish_x86.h @@ -0,0 +1,161 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Platform specific #defines to be shared by the various platforms sharing +* the unixish_86 code +*/ + +/* +* The goal here is to clearly define the binary compatibility parameters for +* the platforms that will use this code. Rather than switch at compile time +* based on the compiler that happens to be in use we are forcing implementors +* to make a conscious decision. +* +* For some of these platforms the community may choose to have more than one +* binary model in effect. In that case I suggest that there be explicit sub +* defines for that platform specifying 'TYPE1', 'TYPE2', etc. The decision on +* which 'TYPE' to use would be triggered by a setting passed through from the +* config system. +* +* For example we might end up with something like: +* +* #elif defined(NTO) +* # if defined(TYPE1) +* # define CFRONT_STYLE_THIS_ADJUST +* # elif defined(TYPE1) +* # define THUNK_BASED_THIS_ADJUST +* # else +* # error "need TYPE1 or TYPE2 for NTO" +* # endif +* #elif defined(__BEOS__) +* +* and so on.... +* +*/ + +#if defined(LINUX) + +#if (__GNUC__ == 2) && (__GNUC_MINOR__ <= 7) +/* Old gcc 2.7.x.x. What does gcc 2.8.x do?? */ +#define CFRONT_STYLE_THIS_ADJUST +#else +/* egcs and later */ +#define THUNK_BASED_THIS_ADJUST +#endif + +#elif defined(__FreeBSD__) +/* System versions of gcc on FreeBSD don't use thunks. On 3.x, the system + * compiler is gcc 2.7.2.3, which doesn't use thunks by default. On 4.x and + * 5.x, /usr/src/contrib/gcc/config/freebsd.h explicitly undef's + * DEFAULT_VTABLE_THUNKS. (The one exception is a brief period (September + * 1999 - Jan 2000) during 4.0-CURRENT, after egcs was merged -- + * this was changed before 4.0-RELEASE, but we can handle it anyway.) + * + * Versions of gcc from the ports collection (/usr/ports/lang/egcs), + * however, have DEFAULT_VTABLE_THUNKS #defined to 1, at least + * in all ports collections since the 2.95 merge. (Supporting optional + * compilers from FreeBSD 3.2 or earlier seems unnecessary). + * + * The easiest way to distinguish the ports collection gcc from the system + * gcc is that the system gcc defines __FreeBSD_cc_version. This variable + * can also identify versions that use thunks. This includes some 4.x versions + * and now newer 5.x versions. + */ +#if defined(__FreeBSD_cc_version) && \ + (__FreeBSD_cc_version < 500003) && \ + (__FreeBSD_cc_version < 400002 || __FreeBSD_cc_version > 400003) +#define CFRONT_STYLE_THIS_ADJUST +#else +#define THUNK_BASED_THIS_ADJUST +#endif + +#elif defined(__NetBSD__) +#define THUNK_BASED_THIS_ADJUST + +#elif defined(__OpenBSD__) +/* OpenBSD instroduces GCC 2.95.x in late May 1999 */ +#include +#if OpenBSD <= 199905 +#define THUNK_BASED_THIS_ADJUST +#else +#define CFRONT_STYLE_THIS_ADJUST +#endif + +#elif defined(__bsdi__) +#include +#if _BSDI_VERSION >= 199910 +/* BSDI/4.1 ships with egcs, ergo thunk-based */ +#define THUNK_BASED_THIS_ADJUST +#else +#define CFRONT_STYLE_THIS_ADJUST +#endif + +#elif defined(NTO) +#define CFRONT_STYLE_THIS_ADJUST + +#elif defined(__BEOS__) +#define CFRONT_STYLE_THIS_ADJUST + +#elif defined(__sun__) || defined(__sun) +#if defined(__GXX_ABI_VERSION) && __GXX_ABI_VERSION >= 100 /* G++ V3 ABI */ +#define THUNK_BASED_THIS_ADJUST +#else +#define CFRONT_STYLE_THIS_ADJUST +#endif + +#elif defined(_WIN32) +#define THUNK_BASED_THIS_ADJUST + +#elif defined(__EMX__) +#define THUNK_BASED_THIS_ADJUST + +#elif defined (__APPLE__) && (__MACH__) +#define THUNK_BASED_THIS_ADJUST + +#else +#error "need a platform define if using unixish x86 code" +#endif + +/***************************************************************************/ + +#if !defined(THUNK_BASED_THIS_ADJUST) && !defined(CFRONT_STYLE_THIS_ADJUST) +#error "need to define 'this' adjust scheme" +#endif + +#if defined(THUNK_BASED_THIS_ADJUST) && defined(CFRONT_STYLE_THIS_ADJUST) +#error "need to define only ONE 'this' adjust scheme" +#endif diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_amd64_darwin.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_amd64_darwin.cpp new file mode 100644 index 00000000..af2919d8 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_amd64_darwin.cpp @@ -0,0 +1,218 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** 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.org Code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +// Platform specific code to invoke XPCOM methods on native objects + +#include "xptcprivate.h" + +// 6 integral parameters are passed in registers +const PRUint32 GPR_COUNT = 6; + +// 8 floating point parameters are passed in SSE registers +const PRUint32 FPR_COUNT = 8; + +// Remember that these 'words' are 64-bit long +static inline void +invoke_count_words(PRUint32 paramCount, nsXPTCVariant * s, + PRUint32 & nr_gpr, PRUint32 & nr_fpr, PRUint32 & nr_stack) +{ + nr_gpr = 1; // skip one GP register for 'that' + nr_fpr = 0; + nr_stack = 0; + + /* Compute number of eightbytes of class MEMORY. */ + for (uint32 i = 0; i < paramCount; i++, s++) { + if (!s->IsPtrData() + && (s->type == nsXPTType::T_FLOAT || s->type == nsXPTType::T_DOUBLE)) { + if (nr_fpr < FPR_COUNT) + nr_fpr++; + else + nr_stack++; + } + else { + if (nr_gpr < GPR_COUNT) + nr_gpr++; + else + nr_stack++; + } + } +} + +static void +invoke_copy_to_stack(PRUint64 * d, PRUint32 paramCount, nsXPTCVariant * s, + PRUint64 * gpregs, double * fpregs) +{ + PRUint32 nr_gpr = 1; // skip one GP register for 'that' + PRUint32 nr_fpr = 0; + PRUint64 value; + + for (uint32 i = 0; i < paramCount; i++, s++) { + if (s->IsPtrData()) + value = (PRUint64) s->ptr; + else { + switch (s->type) { + case nsXPTType::T_FLOAT: break; + case nsXPTType::T_DOUBLE: break; + case nsXPTType::T_I8: value = s->val.i8; break; + case nsXPTType::T_I16: value = s->val.i16; break; + case nsXPTType::T_I32: value = s->val.i32; break; + case nsXPTType::T_I64: value = s->val.i64; break; + case nsXPTType::T_U8: value = s->val.u8; break; + case nsXPTType::T_U16: value = s->val.u16; break; + case nsXPTType::T_U32: value = s->val.u32; break; + case nsXPTType::T_U64: value = s->val.u64; break; + case nsXPTType::T_BOOL: value = s->val.b; break; + case nsXPTType::T_CHAR: value = s->val.c; break; + case nsXPTType::T_WCHAR: value = s->val.wc; break; + default: value = (PRUint64) s->val.p; break; + } + } + + if (!s->IsPtrData() && s->type == nsXPTType::T_DOUBLE) { + if (nr_fpr < FPR_COUNT) + fpregs[nr_fpr++] = s->val.d; + else { + *((double *)d) = s->val.d; + d++; + } + } + else if (!s->IsPtrData() && s->type == nsXPTType::T_FLOAT) { + if (nr_fpr < FPR_COUNT) + // The value in %xmm register is already prepared to + // be retrieved as a float. Therefore, we pass the + // value verbatim, as a double without conversion. + fpregs[nr_fpr++] = s->val.d; + else { + *((float *)d) = s->val.f; + d++; + } + } + else { + if (nr_gpr < GPR_COUNT) + gpregs[nr_gpr++] = value; + else + *d++ = value; + } + } +} + +extern "C" +XPTC_PUBLIC_API(nsresult) +XPTC_InvokeByIndex(nsISupports * that, PRUint32 methodIndex, + PRUint32 paramCount, nsXPTCVariant * params) +{ + PRUint32 nr_gpr, nr_fpr, nr_stack; + invoke_count_words(paramCount, params, nr_gpr, nr_fpr, nr_stack); + + // Stack, if used, must be 16-bytes aligned + if (nr_stack) + nr_stack = (nr_stack + 1) & ~1; + + // Load parameters to stack, if necessary + PRUint64 *stack = (PRUint64 *) __builtin_alloca(nr_stack * 8); + PRUint64 gpregs[GPR_COUNT]; + double fpregs[FPR_COUNT]; + invoke_copy_to_stack(stack, paramCount, params, gpregs, fpregs); + + // disable the warning about sometimes not initialized variables which is hit + // when we pass less than 8 XMM or less than 6 GPR registers. +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wsometimes-uninitialized" + + // Load FPR registers from fpregs[] + register double d0 asm("xmm0"); + register double d1 asm("xmm1"); + register double d2 asm("xmm2"); + register double d3 asm("xmm3"); + register double d4 asm("xmm4"); + register double d5 asm("xmm5"); + register double d6 asm("xmm6"); + register double d7 asm("xmm7"); + + switch (nr_fpr) { +#define ARG_FPR(N) \ + case N+1: d##N = fpregs[N]; + ARG_FPR(7); + ARG_FPR(6); + ARG_FPR(5); + ARG_FPR(4); + ARG_FPR(3); + ARG_FPR(2); + ARG_FPR(1); + ARG_FPR(0); + case 0:; +#undef ARG_FPR + } + + // Load GPR registers from gpregs[] + register PRUint64 a0 asm("rdi"); + register PRUint64 a1 asm("rsi"); + register PRUint64 a2 asm("rdx"); + register PRUint64 a3 asm("rcx"); + register PRUint64 a4 asm("r8"); + register PRUint64 a5 asm("r9"); + + switch (nr_gpr) { +#define ARG_GPR(N) \ + case N+1: a##N = gpregs[N]; + ARG_GPR(5); + ARG_GPR(4); + ARG_GPR(3); + ARG_GPR(2); + ARG_GPR(1); + case 1: a0 = (PRUint64) that; + case 0:; +#undef ARG_GPR + } + + // Ensure that assignments to SSE registers won't be optimized away + asm("" :: + "x" (d0), "x" (d1), "x" (d2), "x" (d3), + "x" (d4), "x" (d5), "x" (d6), "x" (d7)); + + // Get pointer to method + PRUint64 methodAddress = *((PRUint64 *)that); + methodAddress += 8 * methodIndex; + methodAddress = *((PRUint64 *)methodAddress); + + typedef PRUint32 (*Method)(PRUint64, PRUint64, PRUint64, PRUint64, PRUint64, PRUint64); + PRUint32 result = ((Method)methodAddress)(a0, a1, a2, a3, a4, a5); + return result; + +#pragma clang diagnostic pop +} diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_amd64_vbox.asm b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_amd64_vbox.asm new file mode 100644 index 00000000..c0746855 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_amd64_vbox.asm @@ -0,0 +1,403 @@ +; $Id: xptcinvoke_amd64_vbox.asm $ +;; @file +; XPCOM - Implementation XPTC_InvokeByIndex in assembly. +; +; This solves the problem of Clang and gcc (sometimes) not playing along with +; the alloca() based trick to pass stack parameters. We first had trouble +; when enabling asan with gcc 8.2, then Clang 11 on mac had similar issues +; (at least for profile builds). +; + +; +; Copyright (C) 2020-2022 Oracle and/or its affiliates. +; +; This file is part of VirtualBox base platform packages, as +; available from https://www.virtualbox.org. +; +; 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, in version 3 of the +; License. +; +; This program is distributed in the hope that it will be useful, but +; WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +; General Public License for more details. +; +; You should have received a copy of the GNU General Public License +; along with this program; if not, see . +; +; SPDX-License-Identifier: GPL-3.0-only +; + + +;********************************************************************************************************************************* +;* Internal Functions * +;********************************************************************************************************************************* +%include "iprt/asmdefs.mac" + + +;********************************************************************************************************************************* +;* Structures and Typedefs * +;********************************************************************************************************************************* +struc nsXPTCVariant + .val resq 1 + .ptr resq 1 + .type resb 1 + .flags resb 1 + alignb 8 +endstruc + + +;********************************************************************************************************************************* +;* Defined Constants And Macros * +;********************************************************************************************************************************* +;; @name Selected nsXPTCVariant::flags values. +;; @{ +%define PTR_IS_DATA 1 +;; @} + +;; @name Selected nsXPTType (nsXPTCVariant::type) values. +;; @{ +%define T_FLOAT 8 +%define T_DOUBLE 9 +;; @} + +;; Error code we use if there are too many parameters. +%define DISP_E_BADPARAMCOUNT 0x8002000e + +;; Effect name mangling. +%ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP + %define XPTC_InvokeByIndex VBoxNsxpXPTC_InvokeByIndex +%endif + + +BEGINCODE + +;; +; +; @cproto nsresult XPTC_InvokeByIndex(nsISupports *pThat, PRUint32 idxMethod, PRUint32 cParams, nsXPTCVariant *paParams) +; +; @param pThat Pointer to the object we're invoking a method on. register:rdi +; @param idxMethod The VTable method index. register:esi +; @param cParams Number of parameters in addition to pThat. register:edx +; @param paParams Array of parameter values and info. register:rcx +; +BEGINPROC_EXPORTED XPTC_InvokeByIndex + push rbp + mov rbp, rsp + push rbx + push r12 + + ; + ; Move essential input parameters into non-parameter registers. + ; + mov rbx, rcx ; rbx = first / current parameter + mov r12d, edx ; r12 = parameter count / left + + ; Look up the method address in the vtable and store it in r11 (freeing up rsi). + mov r11, [rdi] ; r11 = vtable + mov esi, esi ; zero extend vtable index. + mov r11, [r11 + rsi * 8] ; r11 = method to call. + +%define WITH_OPTIMIZATION +%ifdef WITH_OPTIMIZATION + ; + ; If there are 5 or fewer parameters and they are all suitable for GREGs, + ; we can try optimize the processing here. + ; + ; Switch on count, using fall-thought-to-smaller-value logic, default + ; case goes to generic (slow) code path. + ; + dec edx ; we can still use edx for the parameter count here as a throwaway. + jz .fast_1 + dec edx + jz .fast_2 + dec edx + jz .fast_3 + dec edx + jz .fast_4 + dec edx + jnz .slow_or_zero +%macro fast_case 4 +%1: + mov eax, [rbx + nsXPTCVariant_size * %3 + nsXPTCVariant.type] ; ASSUMES 'type' and 'flags' are adjacent byte fields. + test ah, PTR_IS_DATA + mov %4, [rbx + nsXPTCVariant_size * %3 + nsXPTCVariant.ptr] + jnz %2 + sub al, T_FLOAT + sub al, 2 + jl .fast_bailout + mov %4, [rbx + nsXPTCVariant_size * %3 + nsXPTCVariant.val] +%endmacro + fast_case .fast_5, .fast_4, 4, r9 + fast_case .fast_4, .fast_3, 3, r8 + fast_case .fast_3, .fast_2, 2, rcx + fast_case .fast_2, .fast_1, 1, rdx + fast_case .fast_1, .fast_0, 0, rsi +.fast_0: + xor eax, eax + call r11 ; note! stack is aligned here. + +.fast_return: + lea rsp, [rbp - 8*2] + pop r12 + pop rbx + leave + ret + +.slow_or_zero: + cmp r12d, 0 + je .fast_0 + %if 0 + jmp .slow +.fast_bailout: + int3 + %else +.fast_bailout: + %endif +.slow: +%endif + ; One more push. + push r13 + + ; + ; Check that there aren't unreasonably many parameters + ; (we could do ~255, but 64 is more reasonable number). + ; + cmp r12d, 64 + je .too_many_parameters + + ; + ; For simplicity reserve stack space for all parameters and point r10 at it. + ; + lea edx, [r12d * 8] + sub rsp, rdx + and rsp, byte 0ffffffffffffffe0h ; 32 byte aligned stack. + mov r10, rsp ; r10 = next stack parameter. + + ; + ; Set up parameter pointer and register distribution counts. + ; + mov eax, 1 ; al = greg count, ah = fpreg count. + + ; + ; Anything to do here? + ; +%ifndef WITH_OPTIMIZATION + test r12d,r12d + jz .make_call +%endif + jmp .param_loop + + ; + ; The loop. + ; + ALIGNCODE(64) +.param_loop_advance: + add rbx, nsXPTCVariant_size +.param_loop: + ; First test for pointers using 'flags' then work 'type' for the rest. + test byte [rbx + nsXPTCVariant.flags], PTR_IS_DATA + jnz .is_ptr + cmp byte [rbx + nsXPTCVariant.type], T_FLOAT + jge .maybe_in_fpreg + + ; + ; nsXPTCVariant.val belongs in a GREG or on the stack. + ; Note! Hope we can get away with not zero extending the value here. + ; +.in_greg: + inc al + cmp al, 1+1 + je .in_greg_rsi + cmp al, 2+1 + je .in_greg_rdx + cmp al, 3+1 + je .in_greg_rcx + cmp al, 4+1 + je .in_greg_r8 + cmp al, 5+1 + ja .on_stack +.in_greg_r9: + mov r9, [rbx + nsXPTCVariant.val] + jmp .next +.in_greg_r8: + mov r8, [rbx + nsXPTCVariant.val] + jmp .next +.in_greg_rcx: + mov rcx, [rbx + nsXPTCVariant.val] + jmp .next +.in_greg_rdx: + mov rdx, [rbx + nsXPTCVariant.val] + jmp .next +.in_greg_rsi: + mov rsi, [rbx + nsXPTCVariant.val] + jmp .next + + ; + ; Pointers are loaded from the 'ptr' rather than the 'val' member. + ; + ALIGNCODE(64) +.is_ptr: + inc al + cmp al, 1+1 + je .ptr_in_greg_rsi + cmp al, 2+1 + je .ptr_in_greg_rdx + cmp al, 3+1 + je .ptr_in_greg_rcx + cmp al, 4+1 + je .ptr_in_greg_r8 + cmp al, 5+1 + je .ptr_in_greg_r9 + mov r13, [rbx + nsXPTCVariant.ptr] + jmp .r13_on_stack + +.ptr_in_greg_r9: + mov r9, [rbx + nsXPTCVariant.ptr] + jmp .next +.ptr_in_greg_r8: + mov r8, [rbx + nsXPTCVariant.ptr] + jmp .next +.ptr_in_greg_rcx: + mov rcx, [rbx + nsXPTCVariant.ptr] + jmp .next +.ptr_in_greg_rdx: + mov rdx, [rbx + nsXPTCVariant.ptr] + jmp .next +.ptr_in_greg_rsi: + mov rsi, [rbx + nsXPTCVariant.ptr] + jmp .next + + ; + ; Maybe we've got a float or double type here... + ; +.maybe_in_fpreg: + je .float_in_fpreg + cmp byte [rbx + nsXPTCVariant.type], T_DOUBLE + jne .in_greg + +.double_in_fpreg: + cmp ah, 8 ; Ensure max AL value of 8 when making call. + jge .on_stack + inc ah + cmp ah, 0+1 + je .double_in_xmm0 + cmp ah, 1+1 + je .double_in_xmm1 + cmp ah, 2+1 + je .double_in_xmm2 + cmp ah, 3+1 + je .double_in_xmm3 + cmp ah, 4+1 + je .double_in_xmm4 + cmp ah, 5+1 + je .double_in_xmm5 + cmp ah, 6+1 + je .double_in_xmm6 +.double_in_xmm7: + movsd xmm7, [rbx + nsXPTCVariant.val] + jmp .next +.double_in_xmm6: + movsd xmm6, [rbx + nsXPTCVariant.val] + jmp .next +.double_in_xmm5: + movsd xmm5, [rbx + nsXPTCVariant.val] + jmp .next +.double_in_xmm4: + movsd xmm4, [rbx + nsXPTCVariant.val] + jmp .next +.double_in_xmm3: + movsd xmm3, [rbx + nsXPTCVariant.val] + jmp .next +.double_in_xmm2: + movsd xmm2, [rbx + nsXPTCVariant.val] + jmp .next +.double_in_xmm1: + movsd xmm1, [rbx + nsXPTCVariant.val] + jmp .next +.double_in_xmm0: + movsd xmm0, [rbx + nsXPTCVariant.val] + jmp .next + +.float_in_fpreg: + cmp ah, 8 ; Ensure max AL value of 8 when making call. + jge .on_stack + inc ah + cmp ah, 0+1 + je .float_in_xmm0 + cmp ah, 1+1 + je .float_in_xmm1 + cmp ah, 2+1 + je .float_in_xmm2 + cmp ah, 3+1 + je .float_in_xmm3 + cmp ah, 4+1 + je .float_in_xmm4 + cmp ah, 5+1 + je .float_in_xmm5 + cmp ah, 6+1 + je .float_in_xmm6 +.float_in_xmm7: + movss xmm7, [rbx + nsXPTCVariant.val] + jmp .next +.float_in_xmm6: + movss xmm6, [rbx + nsXPTCVariant.val] + jmp .next +.float_in_xmm5: + movss xmm5, [rbx + nsXPTCVariant.val] + jmp .next +.float_in_xmm4: + movss xmm4, [rbx + nsXPTCVariant.val] + jmp .next +.float_in_xmm3: + movss xmm3, [rbx + nsXPTCVariant.val] + jmp .next +.float_in_xmm2: + movss xmm2, [rbx + nsXPTCVariant.val] + jmp .next +.float_in_xmm1: + movss xmm1, [rbx + nsXPTCVariant.val] + jmp .next +.float_in_xmm0: + movss xmm0, [rbx + nsXPTCVariant.val] + jmp .next + + ; + ; Put the value onto the stack via r13. + ; + ALIGNCODE(64) +.on_stack: + mov r13, [rbx + nsXPTCVariant.val] +.r13_on_stack: + mov [r10], r13 + lea r10, [r10 + 8] + + ; + ; Update parameter pointer and count and maybe loop again. + ; +.next: + dec r12d + jnz .param_loop_advance + + ; + ; Call the method and return. + ; +.make_call: + movzx eax, ah ; AL = number of parameters in XMM registers (variadict only, but easy to do). +.make_just_call: + call r11 + +.return: + lea rsp, [rbp - 8*3] + pop r13 + pop r12 + pop rbx + leave + ret + +.too_many_parameters: + mov eax, DISP_E_BADPARAMCOUNT + jmp .return +ENDPROC XPTC_InvokeByIndex diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_arm.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_arm.cpp new file mode 100644 index 00000000..1b2c5c67 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_arm.cpp @@ -0,0 +1,220 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Platform specific code to invoke XPCOM methods on native objects */ + +#include "xptcprivate.h" + +#if !defined(LINUX) || !defined(__arm__) +#error "This code is for Linux ARM only. Check that it works on your system, too.\nBeware that this code is highly compiler dependent." +#endif + +// Remember that these 'words' are 32bit DWORDS + +static PRUint32 +invoke_count_words(PRUint32 paramCount, nsXPTCVariant* s) +{ + PRUint32 result = 0; + for(PRUint32 i = 0; i < paramCount; i++, s++) + { + if(s->IsPtrData()) + { + result++; + continue; + } + switch(s->type) + { + case nsXPTType::T_I8 : + case nsXPTType::T_I16 : + case nsXPTType::T_I32 : + result++; + break; + case nsXPTType::T_I64 : + result+=2; + break; + case nsXPTType::T_U8 : + case nsXPTType::T_U16 : + case nsXPTType::T_U32 : + result++; + break; + case nsXPTType::T_U64 : + result+=2; + break; + case nsXPTType::T_FLOAT : + result++; + break; + case nsXPTType::T_DOUBLE : + result+=2; + break; + case nsXPTType::T_BOOL : + case nsXPTType::T_CHAR : + case nsXPTType::T_WCHAR : + result++; + break; + default: + // all the others are plain pointer types + result++; + break; + } + } + return result; +} + +static void +invoke_copy_to_stack(PRUint32* d, PRUint32 paramCount, nsXPTCVariant* s) +{ + for(PRUint32 i = 0; i < paramCount; i++, d++, s++) + { + if(s->IsPtrData()) + { + *((void**)d) = s->ptr; + continue; + } + switch(s->type) + { + case nsXPTType::T_I8 : *((PRInt8*) d) = s->val.i8; break; + case nsXPTType::T_I16 : *((PRInt16*) d) = s->val.i16; break; + case nsXPTType::T_I32 : *((PRInt32*) d) = s->val.i32; break; + case nsXPTType::T_I64 : *((PRInt64*) d) = s->val.i64; d++; break; + case nsXPTType::T_U8 : *((PRUint8*) d) = s->val.u8; break; + case nsXPTType::T_U16 : *((PRUint16*)d) = s->val.u16; break; + case nsXPTType::T_U32 : *((PRUint32*)d) = s->val.u32; break; + case nsXPTType::T_U64 : *((PRUint64*)d) = s->val.u64; d++; break; + case nsXPTType::T_FLOAT : *((float*) d) = s->val.f; break; + case nsXPTType::T_DOUBLE : *((double*) d) = s->val.d; d++; break; + case nsXPTType::T_BOOL : *((PRBool*) d) = s->val.b; break; + case nsXPTType::T_CHAR : *((char*) d) = s->val.c; break; + case nsXPTType::T_WCHAR : *((wchar_t*) d) = s->val.wc; break; + default: + // all the others are plain pointer types + *((void**)d) = s->val.p; + break; + } + } +} + +extern "C" { + struct my_params_struct { + nsISupports* that; + PRUint32 Index; + PRUint32 Count; + nsXPTCVariant* params; + PRUint32 fn_count; + PRUint32 fn_copy; + }; +}; + +XPTC_PUBLIC_API(nsresult) +XPTC_InvokeByIndex(nsISupports* that, PRUint32 methodIndex, + PRUint32 paramCount, nsXPTCVariant* params) +{ + PRUint32 result; + struct my_params_struct my_params; + my_params.that = that; + my_params.Index = methodIndex; + my_params.Count = paramCount; + my_params.params = params; + my_params.fn_copy = (PRUint32) &invoke_copy_to_stack; + my_params.fn_count = (PRUint32) &invoke_count_words; + +/* This is to call a given method of class that. + * The parameters are in params, the number is in paramCount. + * The routine will issue calls to count the number of words + * required for argument passing and to copy the arguments to + * the stack. + * Since APCS passes the first 3 params in r1-r3, we need to + * load the first three words from the stack and correct the stack + * pointer (sp) in the appropriate way. This means: + * + * 1.) more than 3 arguments: load r1-r3, correct sp and remember No. + * of bytes left on the stack in r4 + * + * 2.) <= 2 args: load r1-r3 (we won't be causing a stack overflow I hope), + * restore sp as if nothing had happened and set the marker r4 to zero. + * + * Afterwards sp will be restored using the value in r4 (which is not a temporary register + * and will be preserved by the function/method called according to APCS [ARM Procedure + * Calling Standard]). + * + * !!! IMPORTANT !!! + * This routine makes assumptions about the vtable layout of the c++ compiler. It's implemented + * for arm-linux GNU g++ >= 2.8.1 (including egcs and gcc-2.95.[1-3])! + * + */ + + __asm__ __volatile__( + "ldr r1, [%1, #12] \n\t" /* prepare to call invoke_count_words */ + "ldr ip, [%1, #16] \n\t" /* r0=paramCount, r1=params */ + "ldr r0, [%1, #8] \n\t" + "mov lr, pc \n\t" /* call it... */ + "mov pc, ip \n\t" + "mov r4, r0, lsl #2 \n\t" /* This is the amount of bytes needed. */ + "sub sp, sp, r4 \n\t" /* use stack space for the args... */ + "mov r0, sp \n\t" /* prepare a pointer an the stack */ + "ldr r1, [%1, #8] \n\t" /* =paramCount */ + "ldr r2, [%1, #12] \n\t" /* =params */ + "ldr ip, [%1, #20] \n\t" /* =invoke_copy_to_stack */ + "mov lr, pc \n\t" /* copy args to the stack like the */ + "mov pc, ip \n\t" /* compiler would. */ + "ldr r0, [%1] \n\t" /* =that */ + "ldr r1, [r0, #0] \n\t" /* get that->vtable offset */ + "ldr r2, [%1, #4] \n\t" + "mov r2, r2, lsl #2 \n\t" /* a vtable_entry(x)=8 + (4 bytes * x) */ +#if defined(__GXX_ABI_VERSION) && __GXX_ABI_VERSION >= 100 /* G++ V3 ABI */ + "ldr ip, [r1, r2] \n\t" /* get method adress from vtable */ +#else /* non G++ V3 ABI */ + "add r2, r2, #8 \n\t" /* with this compilers */ + "ldr ip, [r1, r2] \n\t" /* get method adress from vtable */ +#endif + "cmp r4, #12 \n\t" /* more than 3 arguments??? */ + "ldmgtia sp!, {r1, r2, r3}\n\t" /* yes: load arguments for r1-r3 */ + "subgt r4, r4, #12 \n\t" /* and correct the stack pointer */ + "ldmleia sp, {r1, r2, r3}\n\t" /* no: load r1-r3 from stack */ + "addle sp, sp, r4 \n\t" /* and restore stack pointer */ + "movle r4, #0 \n\t" /* a mark for restoring sp */ + "ldr r0, [%1, #0] \n\t" /* get (self) */ + "mov lr, pc \n\t" /* call mathod */ + "mov pc, ip \n\t" + "add sp, sp, r4 \n\t" /* restore stack pointer */ + "mov %0, r0 \n\t" /* the result... */ + : "=r" (result) + : "r" (&my_params) + : "r0", "r1", "r2", "r3", "r4", "ip", "lr", "sp" + ); + + return result; +} diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_arm64_vbox.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_arm64_vbox.cpp new file mode 100644 index 00000000..6611f667 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_arm64_vbox.cpp @@ -0,0 +1,296 @@ +/* $Id: xptcinvoke_arm64_vbox.cpp $ */ +/** @file + * XPCOM - Implementation XPTC_InvokeByIndex for arm64. + */ + +/* + * Copyright (C) 2021-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * SPDX-License-Identifier: GPL-3.0-only + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include "xptcprivate.h" +#include +#include +#include + + +/********************************************************************************************************************************* +* Defined Constants And Macros * +*********************************************************************************************************************************/ +#define NUM_ARGS_IN_GPRS 8 /**< Number of arguments passed in general purpose registers (starting with x0). */ +#define NUM_ARGS_IN_FPRS 8 /**< Number of arguments passed in floating point registers (starting with d0). */ + +#define MY_MAX_ARGS 64 /**< Limit ourselves to 64 arguments. */ + + + +AssertCompileMemberOffset(nsXPTCVariant, val, 0); + +extern "C" __attribute__((naked)) nsresult +arm64AsmInvoker(uintptr_t pfnMethod /*x0*/, uint32_t cParams /*w1*/, nsXPTCVariant *paParams /*x2*/, uint64_t cbStack /*x3*/, + uint8_t *acbStackArgs /*x4*/, uint64_t *pauGprArgs /*x5*/, uint64_t *pauFprArgs /*x6*/, uint32_t cFprArgs /*x7*/) +{ + __asm__ __volatile__( + /* Prologue - create the frame. */ "\ + sub sp, sp, 16 \n\ + stp x29, x30, [sp] \n\ + mov x29, sp \n\ + .cfi_def_cfa x29, 16 \n\ + .cfi_rel_offset x30, -8 \n\ + .cfi_rel_offset x29, -16 \n\ +\n\ +" /* Move pfnMethod to x16 and pauGprArgs to x7 free up x0 and x5: */ "\ + mov x16, x0 \n\ + mov x17, x5 \n\ +\n\ +" /* Load FPU registers first so we free up x6 & x7 early: */ "\ + cmp w7, #0 \n\ + b.eq Lno_fprs\n\ + ldp d0, d1, [x6] \n\ + ldp d2, d3, [x6, #16] \n\ + ldp d4, d5, [x6, #32] \n\ + ldp d6, d7, [x6, #48] \n\ +Lno_fprs:\n\ +\n\ +" /* Do argument passing by stack (if any). We align the stack to 16 bytes. */ "\ + cmp x3, #0 \n\ + beq Lno_stack_args \n\ + sub x3, sp, x3 \n\ + bic x3, x3, #15 \n\ + mov sp, x3 \n\ +Lnext_parameter: \n\ + ldrb w7, [x4] \n\ + cmp w7, #0 \n\ + beq Ladvance\n\ +\n\ + cmp w7, #4 \n\ + bgt Lstore_64bits\n\ + cmp w7, #1 \n\ + beq Lstore_8bits\n\ + cmp w7, #2 \n\ + beq Lstore_16bits\n\ +\n\ +Lstore_32bits:\n\ + ldr w0, [x2] \n\ + add x3, x3, #3 \n\ + bic x3, x3, #3 \n\ + str w0, [x3] \n" +#ifdef RT_OS_DARWIN /* macOS compacts stack usage. */ +" add x3, x3, #4 \n" +#endif +" b Ladvance \n\ +\n\ +Lstore_8bits:\n\ + ldrb w0, [x2] \n\ + strb w0, [x3] \n" +#ifdef RT_OS_DARWIN /* macOS compacts stack usage. */ +" add x3, x3, #1 \n" +#endif +" b Ladvance \n\ +\n\ +Lstore_16bits:\n\ + ldrh w0, [x2] \n\ + add x3, x3, #1 \n\ + bic x3, x3, #1 \n\ + strh w0, [x3] \n" +#ifdef RT_OS_DARWIN /* macOS compacts stack usage. */ +" add x3, x3, #2 \n" +#endif +" b Ladvance \n\ +\n\ +Lstore_64bits_ptr:\n\ + ldr x0, [x2, %[offPtrInXPTCVariant]] \n\ + b Lstore_64bits_common \n\ +Lstore_64bits:\n\ + tst w7, #0x80 \n\ + bne Lstore_64bits_ptr \n\ + ldr x0, [x2] \n\ +Lstore_64bits_common:\n\ + add x3, x3, #7 \n\ + bic x3, x3, #7 \n\ + str x0, [x3] \n" +#ifdef RT_OS_DARWIN /* macOS compacts stack usage. */ +" add x3, x3, #8 \n" +#endif +"\n\ +Ladvance:\n" +#ifndef RT_OS_DARWIN /* macOS compacts stack usage. */ +" add x3, x3, #8 \n" +#endif +" add x4, x4, #1 \n\ + add x2, x2, %[cbXPTCVariant] \n\ + sub w1, w1, #1 \n\ + cmp w1, #0 \n\ + bne Lnext_parameter \n\ +\n\ +" /* reserve stack space for the integer and floating point registers and save them: */ "\ +Lno_stack_args: \n\ +\n\ +" /* Load general purpose argument registers: */ "\ + ldp x0, x1, [x17] \n\ + ldp x2, x3, [x17, #16] \n\ + ldp x4, x5, [x17, #32] \n\ + ldp x6, x7, [x17, #48] \n\ +\n\ +" /* Make the call: */ "\ + blr x16 \n\ +\n\ +" /* Epilogue (clang does not emit the .cfi's here, so drop them too?): */ "\ + mov sp, x29 \n\ + ldp x29, x30, [sp] \n\ + add sp, sp, #16 \n\ + .cfi_def_cfa sp, 0 \n\ + .cfi_restore x29 \n\ + .cfi_restore x30 \n\ + ret \n\ +" : + : [cbXPTCVariant] "i" (sizeof(nsXPTCVariant)) + , [offPtrInXPTCVariant] "i" (offsetof(nsXPTCVariant, ptr)) + :); +} + + +XPTC_PUBLIC_API(nsresult) +XPTC_InvokeByIndex(nsISupports *pThis, PRUint32 idxMethod, PRUint32 cParams, nsXPTCVariant *paParams) +{ + AssertMsgReturn(cParams <= MY_MAX_ARGS, ("cParams=%#x idxMethod=%#x\n", cParams, idxMethod), NS_ERROR_UNEXPECTED); + + /* + * Prepare + */ + uint64_t auGprArgs[NUM_ARGS_IN_GPRS] = {0}; + uint64_t auFprArgs[NUM_ARGS_IN_GPRS] = {0}; + uint8_t acbStackArgs[MY_MAX_ARGS]; /* The number of value bytes to copy onto the stack. Zero if in register. */ + uint32_t cbStackArgs = 0; + uint32_t cFprArgs = 0; + uint32_t cGprArgs = 0; + + /* First argument is always 'pThis'. The 'pThis' argument is not accounted + for in cParams or acbStackArgs. */ + auGprArgs[cGprArgs++] = (uintptr_t)pThis; + + /* Do the other arguments. */ + for (PRUint32 i = 0; i < cParams; i++) + { + if (paParams[i].IsPtrData()) + { + if (cGprArgs < NUM_ARGS_IN_GPRS) + { + auGprArgs[cGprArgs++] = (uintptr_t)paParams[i].ptr; + acbStackArgs[i] = 0; + } + else + { + acbStackArgs[i] = sizeof(paParams[i].ptr) | UINT8_C(0x80); +#ifdef RT_OS_DARWIN /* macOS compacts stack usage. */ + cbStackArgs = RT_ALIGN_32(cbStackArgs, sizeof(paParams[i].ptr)) + sizeof(paParams[i].ptr); +#else + cbStackArgs += sizeof(uint64_t); +#endif + } + } + else + { + if ( paParams[i].type != nsXPTType::T_FLOAT + && paParams[i].type != nsXPTType::T_DOUBLE) + { + if (cGprArgs < NUM_ARGS_IN_GPRS) + { + switch (paParams[i].type) + { + case nsXPTType::T_I8: auGprArgs[cGprArgs++] = paParams[i].val.i8; break; + case nsXPTType::T_I16: auGprArgs[cGprArgs++] = paParams[i].val.i16; break; + case nsXPTType::T_I32: auGprArgs[cGprArgs++] = paParams[i].val.i32; break; + case nsXPTType::T_I64: auGprArgs[cGprArgs++] = paParams[i].val.i64; break; + case nsXPTType::T_U8: auGprArgs[cGprArgs++] = paParams[i].val.u8; break; + case nsXPTType::T_U16: auGprArgs[cGprArgs++] = paParams[i].val.u16; break; + case nsXPTType::T_U32: auGprArgs[cGprArgs++] = paParams[i].val.u32; break; + default: + case nsXPTType::T_U64: auGprArgs[cGprArgs++] = paParams[i].val.u64; break; + case nsXPTType::T_BOOL: auGprArgs[cGprArgs++] = paParams[i].val.b; break; + case nsXPTType::T_CHAR: auGprArgs[cGprArgs++] = paParams[i].val.c; break; + case nsXPTType::T_WCHAR: auGprArgs[cGprArgs++] = paParams[i].val.wc; break; + } + acbStackArgs[i] = 0; + } + else + { + uint8_t cbStack; + switch (paParams[i].type) + { + case nsXPTType::T_I8: cbStack = sizeof(paParams[i].val.i8); break; + case nsXPTType::T_I16: cbStack = sizeof(paParams[i].val.i16); break; + case nsXPTType::T_I32: cbStack = sizeof(paParams[i].val.i32); break; + case nsXPTType::T_I64: cbStack = sizeof(paParams[i].val.i64); break; + case nsXPTType::T_U8: cbStack = sizeof(paParams[i].val.u8); break; + case nsXPTType::T_U16: cbStack = sizeof(paParams[i].val.u16); break; + case nsXPTType::T_U32: cbStack = sizeof(paParams[i].val.u32); break; + default: + case nsXPTType::T_U64: cbStack = sizeof(paParams[i].val.u64); break; + case nsXPTType::T_BOOL: cbStack = sizeof(paParams[i].val.b); break; + case nsXPTType::T_CHAR: cbStack = sizeof(paParams[i].val.c); break; + case nsXPTType::T_WCHAR: cbStack = sizeof(paParams[i].val.wc); break; + } + acbStackArgs[i] = cbStack; +#ifdef RT_OS_DARWIN /* macOS compacts stack usage. */ + cbStackArgs = RT_ALIGN_32(cbStackArgs, cbStack) + cbStack; +#else + cbStackArgs += sizeof(uint64_t); +#endif + } + } + else if (cFprArgs < NUM_ARGS_IN_FPRS) + { + AssertCompile(sizeof(paParams[i].val.f) == 4); + AssertCompile(sizeof(paParams[i].val.d) == 8); + if (paParams[i].type == nsXPTType::T_FLOAT) + auFprArgs[cFprArgs++] = paParams[i].val.u32; + else + auFprArgs[cFprArgs++] = paParams[i].val.u64; + acbStackArgs[i] = 0; + } + else + { + uint8_t cbStack; + if (paParams[i].type == nsXPTType::T_FLOAT) + cbStack = sizeof(paParams[i].val.f); + else + cbStack = sizeof(paParams[i].val.d); + acbStackArgs[i] = cbStack; +#ifdef RT_OS_DARWIN /* macOS compacts stack usage. */ + cbStackArgs = RT_ALIGN_32(cbStackArgs, cbStack) + cbStack; +#else + cbStackArgs += sizeof(uint64_t); +#endif + } + } + } + + /* + * Pass it on to a naked wrapper function that does the nitty gritty work. + */ + uintptr_t *pauVtable = *(uintptr_t **)pThis; + return arm64AsmInvoker(pauVtable[idxMethod], cParams, paParams, cbStackArgs, acbStackArgs, auGprArgs, auFprArgs, cFprArgs); +} + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_arm_netbsd.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_arm_netbsd.cpp new file mode 100644 index 00000000..0213bd76 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_arm_netbsd.cpp @@ -0,0 +1,213 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Platform specific code to invoke XPCOM methods on native objects */ + +#include "xptcprivate.h" + +// Remember that these 'words' are 32bit DWORDS + +static PRUint32 +invoke_count_words(PRUint32 paramCount, nsXPTCVariant* s) +{ + PRUint32 result = 0; + for(PRUint32 i = 0; i < paramCount; i++, s++) + { + if(s->IsPtrData()) + { + result++; + continue; + } + switch(s->type) + { + case nsXPTType::T_I8 : + case nsXPTType::T_I16 : + case nsXPTType::T_I32 : + result++; + break; + case nsXPTType::T_I64 : + result+=2; + break; + case nsXPTType::T_U8 : + case nsXPTType::T_U16 : + case nsXPTType::T_U32 : + result++; + break; + case nsXPTType::T_U64 : + result+=2; + break; + case nsXPTType::T_FLOAT : + result++; + break; + case nsXPTType::T_DOUBLE : + result+=2; + break; + case nsXPTType::T_BOOL : + case nsXPTType::T_CHAR : + case nsXPTType::T_WCHAR : + result++; + break; + default: + // all the others are plain pointer types + result++; + break; + } + } + return result; +} + +static void +invoke_copy_to_stack(PRUint32* d, PRUint32 paramCount, nsXPTCVariant* s) +{ + for(PRUint32 i = 0; i < paramCount; i++, d++, s++) + { + if(s->IsPtrData()) + { + *((void**)d) = s->ptr; + continue; + } + switch(s->type) + { + case nsXPTType::T_I8 : *((PRInt8*) d) = s->val.i8; break; + case nsXPTType::T_I16 : *((PRInt16*) d) = s->val.i16; break; + case nsXPTType::T_I32 : *((PRInt32*) d) = s->val.i32; break; + case nsXPTType::T_I64 : *((PRInt64*) d) = s->val.i64; d++; break; + case nsXPTType::T_U8 : *((PRUint8*) d) = s->val.u8; break; + case nsXPTType::T_U16 : *((PRUint16*)d) = s->val.u16; break; + case nsXPTType::T_U32 : *((PRUint32*)d) = s->val.u32; break; + case nsXPTType::T_U64 : *((PRUint64*)d) = s->val.u64; d++; break; + case nsXPTType::T_FLOAT : *((float*) d) = s->val.f; break; + case nsXPTType::T_DOUBLE : *((double*) d) = s->val.d; d++; break; + case nsXPTType::T_BOOL : *((PRBool*) d) = s->val.b; break; + case nsXPTType::T_CHAR : *((char*) d) = s->val.c; break; + case nsXPTType::T_WCHAR : *((wchar_t*) d) = s->val.wc; break; + default: + // all the others are plain pointer types + *((void**)d) = s->val.p; + break; + } + } +} + +extern "C" +struct my_params_struct { + nsISupports* that; + PRUint32 Index; + PRUint32 Count; + nsXPTCVariant* params; + PRUint32 fn_count; + PRUint32 fn_copy; +}; + +XPTC_PUBLIC_API(nsresult) +XPTC_InvokeByIndex(nsISupports* that, PRUint32 methodIndex, + PRUint32 paramCount, nsXPTCVariant* params) +{ + PRUint32 result; + struct my_params_struct my_params; + my_params.that = that; + my_params.Index = methodIndex; + my_params.Count = paramCount; + my_params.params = params; + my_params.fn_copy = (PRUint32) &invoke_copy_to_stack; + my_params.fn_count = (PRUint32) &invoke_count_words; + +/* This is to call a given method of class that. + * The parameters are in params, the number is in paramCount. + * The routine will issue calls to count the number of words + * required for argument passing and to copy the arguments to + * the stack. + * Since APCS passes the first 3 params in r1-r3, we need to + * load the first three words from the stack and correct the stack + * pointer (sp) in the appropriate way. This means: + * + * 1.) more than 3 arguments: load r1-r3, correct sp and remember No. + * of bytes left on the stack in r4 + * + * 2.) <= 2 args: load r1-r3 (we won't be causing a stack overflow I hope), + * restore sp as if nothing had happened and set the marker r4 to zero. + * + * Afterwards sp will be restored using the value in r4 (which is not a temporary register + * and will be preserved by the function/method called according to APCS [ARM Procedure + * Calling Standard]). + * + * !!! IMPORTANT !!! + * This routine makes assumptions about the vtable layout of the c++ compiler. It's implemented + * for arm-linux GNU g++ >= 2.8.1 (including egcs and gcc-2.95.[1-3])! + * + */ + + __asm__ __volatile__( + "ldr r1, [%1, #12] \n\t" /* prepare to call invoke_count_words */ + "ldr ip, [%1, #16] \n\t" /* r0=paramCount, r1=params */ + "ldr r0, [%1, #8] \n\t" + "mov lr, pc \n\t" /* call it... */ + "mov pc, ip \n\t" + "mov r4, r0, lsl #2 \n\t" /* This is the amount of bytes needed. */ + "sub sp, sp, r4 \n\t" /* use stack space for the args... */ + "mov r0, sp \n\t" /* prepare a pointer an the stack */ + "ldr r1, [%1, #8] \n\t" /* =paramCount */ + "ldr r2, [%1, #12] \n\t" /* =params */ + "ldr ip, [%1, #20] \n\t" /* =invoke_copy_to_stack */ + "mov lr, pc \n\t" /* copy args to the stack like the */ + "mov pc, ip \n\t" /* compiler would. */ + "ldr r0, [%1] \n\t" /* =that */ + "ldr r1, [r0, #0] \n\t" /* get that->vtable offset */ + "ldr r2, [%1, #4] \n\t" + "add r2, r1, r2, lsl #3\n\t" /* a vtable_entry(x)=8 + (8 bytes * x) */ + "add r2, r2, #8 \n\t" /* with this compilers */ + "ldr r3, [r2] \n\t" /* get virtual offset from vtable */ + "mov r3, r3, lsl #16 \n\t" + "add r0, r0, r3, asr #16\n\t" + "ldr ip, [r2, #4] \n\t" /* get method address from vtable */ + "cmp r4, #12 \n\t" /* more than 3 arguments??? */ + "ldmgtia sp!, {r1, r2, r3}\n\t" /* yes: load arguments for r1-r3 */ + "subgt r4, r4, #12 \n\t" /* and correct the stack pointer */ + "ldmleia sp, {r1, r2, r3}\n\t" /* no: load r1-r3 from stack */ + "addle sp, sp, r4 \n\t" /* and restore stack pointer */ + "movle r4, #0 \n\t" /* a mark for restoring sp */ + "mov lr, pc \n\t" /* call mathod */ + "mov pc, ip \n\t" + "add sp, sp, r4 \n\t" /* restore stack pointer */ + "mov %0, r0 \n\t" /* the result... */ + : "=r" (result) + : "r" (&my_params) + : "r0", "r1", "r2", "r3", "r4", "ip", "lr" + ); + + return result; +} diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_ipf32.s b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_ipf32.s new file mode 100644 index 00000000..c846b1f4 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_ipf32.s @@ -0,0 +1,145 @@ + +// Select C numeric constant + .radix C +// for 64 bit mode, use .psr abi64 + .psr abi32 +// big endian + .psr msb +// Section has executable code + .section .text, "ax","progbits" +// procedure named 'XPTC_InvokeByIndex' + .proc XPTC_InvokeByIndex +// manual bundling + .explicit + +// extern "C" PRUint32 +// invoke_copy_to_stack(uint64_t* d, +// const PRUint32 paramCount, nsXPTCVariant* s) + .global invoke_copy_to_stack +// .exclass invoke_copy_to_stack, @fullyvisible + .type invoke_copy_to_stack,@function + +// .exclass XPTC_InvokeByIndex, @fullyvisible + .type XPTC_InvokeByIndex,@function + +// XPTC_InvokeByIndex(nsISupports* that, PRUint32 methodIndex, +// PRUint32 paramCount, nsXPTCVariant* params); +XPTC_InvokeByIndex:: + .prologue + .save ar.pfs, r37 +// allocate 4 input args, 6 local args, and 8 output args + alloc r37 = ar.pfs, 4, 6, 8, 0 // M + nop.i 0 ;; // I + +// unwind table already knows gp, no need to specify anything + add r39 = 0, gp // A + .save rp, r36 + mov r36 = rp // I + .vframe r38 + add r38 = 0, sp ;; // A + +// We first calculate the amount of extra memory stack space required +// for the arguments, and register storage. +// We then call invoke_copy_to_stack() to write the argument contents +// to the specified memory regions. +// We then copy the integer arguments to integer registers, and floating +// arguments to float registers. +// Lastly we load the virtual table jump pointer, and call the target +// subroutine. + +// in0 : that +// in1 : methodIndex +// in2 : paramCount +// in3 : params + +// stack frame size is 16 + (8 * even(paramCount)) + 64 + 64 +// 16 byte frame header +// 8 * even(paramCount) memory argument area +// 64 bytes integer register area +// 64 bytes float register area +// This scheme makes sure stack fram size is a multiple of 16 + + .body + add r10 = 8, r0 // A +// r41 points to float register area + add r41 = -64, sp // A +// r40 points to int register area + add r40 = -128, sp ;; // A + + add out1 = 0, r40 // A + add out2 = 0, r41 // A + tbit.z p14,p15 = in2,0 ;; // I + +// compute 8 * even(paramCount) +(p14) shladd r11 = in2, 3, r0 ;; // A +(p15) shladd r11 = in2, 3, r10 ;; // A + sub out0 = r40, r11 ;; // A + +// advance the stack frame + add sp = -16, out0 // A + add out3 = 0, in2 // A + add out4 = 0, in3 // A + +// branch to invoke_copy_to_stack + br.call.sptk.few rp = invoke_copy_to_stack ;; // B + +// restore gp + add gp = 0, r39 // A + add out0 = 0, in0 // A + +// load the integer and float registers + ld8 out1 = [r40], 8 // M + ldfd f8 = [r41], 8 ;; // M + + ld8 out2 = [r40], 8 // M + ldfd f9 = [r41], 8 ;; // M + + ld8 out3 = [r40], 8 // M + ldfd f10 = [r41], 8 ;; // M + + ld8 out4 = [r40], 8 // M + ldfd f11 = [r41], 8 ;; // M + + ld8 out5 = [r40], 8 // M + ldfd f12 = [r41], 8 ;; // M +// 16 * methodIndex + shladd r11 = in1, 4, r0 // A + + ld8 out6 = [r40], 8 // M + ldfd f13 = [r41], 8 ;; // M + + ld8 out7 = [r40], 8 // M + ldfd f14 = [r41], 8 // M + addp4 r8 = 0, in0 ;; // A + +// look up virtual base table and dispatch to target subroutine +// This section assumes 32 bit pointer mode, and virtual base table +// layout from the ABI http://www.codesourcery.com/cxx-abi/abi.html + +// load base table + ld4 r8 = [r8] ;; // M + addp4 r8 = r11, r8 ;; // A + + // first entry is jump pointer, second entry is gp + addp4 r9 = 8, r8 ;; // A +// load jump pointer + ld8 r8 = [r8] + +// load gp + ld8 gp = [r9] ;; // M + mov b6 = r8 ;; // I + +// branch to target virtual function + br.call.sptk.few rp = b6 ;; // B + +// epilog + mov ar.pfs = r37 // I + mov rp = r36 ;; // I + + add sp = 0, r38 // A + add gp = 0, r39 // A + br.ret.sptk.few rp ;; // B + + .endp + + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_ipf64.s b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_ipf64.s new file mode 100644 index 00000000..5e1b1a23 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_ipf64.s @@ -0,0 +1,145 @@ + +// Select C numeric constant + .radix C +// for 64 bit mode, use .psr abi64 + .psr abi64 +// little endian + .psr lsb +// Section has executable code + .section .text, "ax","progbits" +// procedure named 'XPTC_InvokeByIndex' + .proc XPTC_InvokeByIndex +// manual bundling + .explicit + +// extern "C" PRUint32 +// invoke_copy_to_stack(uint64_t* d, +// const PRUint32 paramCount, nsXPTCVariant* s) + .global invoke_copy_to_stack +// .exclass invoke_copy_to_stack, @fullyvisible + .type invoke_copy_to_stack,@function + +// .exclass XPTC_InvokeByIndex, @fullyvisible + .type XPTC_InvokeByIndex,@function + +// XPTC_InvokeByIndex(nsISupports* that, PRUint32 methodIndex, +// PRUint32 paramCount, nsXPTCVariant* params); +XPTC_InvokeByIndex:: + .prologue + .save ar.pfs, r37 +// allocate 4 input args, 6 local args, and 8 output args + alloc r37 = ar.pfs, 4, 6, 8, 0 // M + nop.i 0 ;; // I + +// unwind table already knows gp, no need to specify anything + add r39 = 0, gp // A + .save rp, r36 + mov r36 = rp // I + .vframe r38 + add r38 = 0, sp ;; // A + +// We first calculate the amount of extra memory stack space required +// for the arguments, and register storage. +// We then call invoke_copy_to_stack() to write the argument contents +// to the specified memory regions. +// We then copy the integer arguments to integer registers, and floating +// arguments to float registers. +// Lastly we load the virtual table jump pointer, and call the target +// subroutine. + +// in0 : that +// in1 : methodIndex +// in2 : paramCount +// in3 : params + +// stack frame size is 16 + (8 * even(paramCount)) + 64 + 64 +// 16 byte frame header +// 8 * even(paramCount) memory argument area +// 64 bytes integer register area +// 64 bytes float register area +// This scheme makes sure stack fram size is a multiple of 16 + + .body + add r10 = 8, r0 // A +// r41 points to float register area + add r41 = -64, sp // A +// r40 points to int register area + add r40 = -128, sp ;; // A + + add out1 = 0, r40 // A + add out2 = 0, r41 // A + tbit.z p14,p15 = in2,0 ;; // I + +// compute 8 * even(paramCount) +(p14) shladd r11 = in2, 3, r0 ;; // A +(p15) shladd r11 = in2, 3, r10 ;; // A + sub out0 = r40, r11 ;; // A + +// advance the stack frame + add sp = -16, out0 // A + add out3 = 0, in2 // A + add out4 = 0, in3 // A + +// branch to invoke_copy_to_stack + br.call.sptk.few rp = invoke_copy_to_stack ;; // B + +// restore gp + add gp = 0, r39 // A + add out0 = 0, in0 // A + +// load the integer and float registers + ld8 out1 = [r40], 8 // M + ldfd f8 = [r41], 8 ;; // M + + ld8 out2 = [r40], 8 // M + ldfd f9 = [r41], 8 ;; // M + + ld8 out3 = [r40], 8 // M + ldfd f10 = [r41], 8 ;; // M + + ld8 out4 = [r40], 8 // M + ldfd f11 = [r41], 8 ;; // M + + ld8 out5 = [r40], 8 // M + ldfd f12 = [r41], 8 ;; // M +// 16 * methodIndex + shladd r11 = in1, 4, r0 // A + + ld8 out6 = [r40], 8 // M + ldfd f13 = [r41], 8 ;; // M + + ld8 out7 = [r40], 8 // M + ldfd f14 = [r41], 8 // M + add r8 = 0, in0 ;; // A + +// look up virtual base table and dispatch to target subroutine +// This section assumes 64 bit pointer mode, and virtual base table +// layout from the ABI http://www.codesourcery.com/cxx-abi/abi.html + +// load base table + ld8 r8 = [r8] ;; // M + add r8 = r11, r8 ;; // A + + // first entry is jump pointer, second entry is gp + add r9 = 8, r8 ;; // A +// load jump pointer + ld8 r8 = [r8] + +// load gp + ld8 gp = [r9] ;; // M + mov b6 = r8 ;; // I + +// branch to target virtual function + br.call.sptk.few rp = b6 ;; // B + +// epilog + mov ar.pfs = r37 // I + mov rp = r36 ;; // I + + add sp = 0, r38 // A + add gp = 0, r39 // A + br.ret.sptk.few rp ;; // B + + .endp + + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_irix.s b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_irix.s new file mode 100644 index 00000000..4e8e0895 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_irix.s @@ -0,0 +1,149 @@ + +#include +#include + +.text +.globl invoke_count_words +.globl invoke_copy_to_stack + +LOCALSZ=7 # a0, a1, a2, a3, s0, ra, gp +FRAMESZ=(((NARGSAVE+LOCALSZ)*SZREG)+ALSZ)&ALMASK + +RAOFF=FRAMESZ-(1*SZREG) +A0OFF=FRAMESZ-(2*SZREG) +A1OFF=FRAMESZ-(3*SZREG) +A2OFF=FRAMESZ-(4*SZREG) +A3OFF=FRAMESZ-(5*SZREG) +S0OFF=FRAMESZ-(6*SZREG) +GPOFF=FRAMESZ-(7*SZREG) + + # + # _XPTC_InvokeByIndex(that, methodIndex, paramCount, params) + # a0 a1 a2 a3 + +NESTED(_XPTC_InvokeByIndex, FRAMESZ, ra) + SETUP_GP + PTR_SUBU sp, FRAMESZ + SETUP_GP64(GPOFF, _XPTC_InvokeByIndex) + SAVE_GP(GPOFF) + + REG_S ra, RAOFF(sp) + REG_S a0, A0OFF(sp) + REG_S a1, A1OFF(sp) + REG_S a2, A2OFF(sp) + REG_S a3, A3OFF(sp) + REG_S s0, S0OFF(sp) + REG_S gp, GPOFF(sp) + + # invoke_count_words(paramCount, params) + move a0, a2 + move a1, a3 + jal invoke_count_words + + # invoke_copy_to_stack(PRUint32* d, PRUint32 paramCount, + # nsXPTCVariant* s, PRUint32 *reg) + + REG_L a1, A2OFF(sp) # a1 - paramCount + REG_L a2, A3OFF(sp) # a2 - params + + # save sp before we copy the params to the stack + move t0, sp + + # assume full size of 8 bytes per param to be safe + sll v0, 4 # 8 bytes * num params + subu sp, sp, v0 # make room + move a0, sp # a0 - param stack address + + # create temporary stack space to write int and fp regs + subu sp, 64 # 64 = 8 regs of 8 bytes + + move a3, sp + + # save the old sp and save the arg stack + subu sp, sp, 16 + REG_S t0, 0(sp) + REG_S a0, 8(sp) + + # copy the param into the stack areas + jal invoke_copy_to_stack + + REG_L t3, 8(sp) # get previous a0 + REG_L sp, 0(sp) # get orig sp back + + REG_L a0, A0OFF(sp) # a0 - that + REG_L a1, A1OFF(sp) # a1 - methodIndex + +#ifdef __GNUC__ + # t1 = methodIndex * 8 + # (use shift instead of mult) + sll t1, a1, 3 +#else + # t1 = methodIndex * 12 + # (use shift and subtract trick instead of mult) + sll t1, a1, 2 + subu t1, t1, a1 + sll t1, t1, 2 +#endif + + # calculate the function we need to jump to, + # which must then be saved in t9 + lw t9, 0(a0) + addu t9, t9, t1 +#ifdef __GNUC__ + lw t9, 12(t9) # t9 = *(that+t1+12) +#else + li t2, 20 + addu t9, t9, t2 + lw t9, 0(t9) # t9 = *(that+t1+20) +#endif + + # calculate the proper "this" pointer for the + # function that they asked for + lw t0, 0(a0) + addu t0, t1 +#ifdef __GNUC__ + lh t0, 8(t0) +#else + lw t0, 12(t0) +#endif + + addu a0, a0, t0 + + # get register save area from invoke_copy_to_stack + subu t1, t3, 64 + + # a1..a7 and f13..f19 should now be set to what + # invoke_copy_to_stack told us. skip a0 and f12 + # because that's the "this" pointer + + REG_L a1, 0(t1) + REG_L a2, 8(t1) + REG_L a3, 16(t1) + REG_L a4, 24(t1) + REG_L a5, 32(t1) + REG_L a6, 40(t1) + REG_L a7, 48(t1) + + l.d $f13, 0(t1) + l.d $f14, 8(t1) + l.d $f15, 16(t1) + l.d $f16, 24(t1) + l.d $f17, 32(t1) + l.d $f18, 40(t1) + l.d $f19, 48(t1) + + # save away our stack pointer and create + # the stack pointer for the function + move s0, sp + move sp, t3 + + jalr ra, t9 + + move sp, s0 + + RESTORE_GP64 + REG_L ra, RAOFF(sp) + REG_L s0, S0OFF(sp) + PTR_ADDU sp, FRAMESZ + j ra +.end _XPTC_InvokeByIndex diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_mips.s b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_mips.s new file mode 100644 index 00000000..f011aaf5 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_mips.s @@ -0,0 +1,166 @@ +/* -*- Mode: asm; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * Version: MPL 1.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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corp, Inc. + * Portions created by the Initial Developer are Copyright (C) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Brendan Eich + * Stuart Parmenter + */ + +/* This code is for MIPS using the O32 ABI. */ + +#include +#include + +.text +.globl invoke_count_words +.globl invoke_copy_to_stack + +# We need a variable number of words allocated from the stack for copies of +# the params, and this space must come between the high frame (where ra, gp, +# and s0 are saved) and the low frame (where a0-a3 are saved by the callee +# functions we invoke). + +LOCALSZ=4 # s0, s1, ra, gp +NARGSAVE=4 # a0, a1, a2, a3 +HIFRAMESZ=(LOCALSZ*SZREG) +LOFRAMESZ=(NARGSAVE*SZREG) +FRAMESZ=(HIFRAMESZ+LOFRAMESZ+ALSZ)&ALMASK + +# XXX these 2*SZREG, etc. are very magic -- we *know* that ALSZ&ALMASK cause +# FRAMESZ to be 0 mod 8, in this case to be 16 and not 12. +RAOFF=FRAMESZ - (2*SZREG) +GPOFF=FRAMESZ - (3*SZREG) +S0OFF=FRAMESZ - (4*SZREG) +S1OFF=FRAMESZ - (5*SZREG) + +# These are not magic -- they are just our argsave slots in the caller frame. +A0OFF=FRAMESZ +A1OFF=FRAMESZ + (1*SZREG) +A2OFF=FRAMESZ + (2*SZREG) +A3OFF=FRAMESZ + (3*SZREG) + + # + # _XPTC_InvokeByIndex(that, methodIndex, paramCount, params) + # a0 a1 a2 a3 + +NESTED(_XPTC_InvokeByIndex, FRAMESZ, ra) + + .set noreorder + .cpload t9 + .set reorder + + subu sp, FRAMESZ + + # specify the save register mask -- XXX do we want the a0-a3 here, given + # our "split" frame where the args are saved below a dynamicly allocated + # region under the high frame? + # + # 10010000000000010000000011110000 + .mask 0x900100F0, -((NARGSAVE+LOCALSZ)*SZREG) + + # thou shalt not use .cprestore if yer frame has variable size... + # .cprestore GPOFF + + REG_S ra, RAOFF(sp) + + # this happens automatically with .cprestore, but we cannot use that op... + REG_S gp, GPOFF(sp) + REG_S s0, S0OFF(sp) + REG_S s1, S1OFF(sp) + + REG_S a0, A0OFF(sp) + REG_S a1, A1OFF(sp) + REG_S a2, A2OFF(sp) + REG_S a3, A3OFF(sp) + + # invoke_count_words(paramCount, params) + move a0, a2 + move a1, a3 + + jal invoke_count_words + lw gp, GPOFF(sp) + + # save the old sp so we can pop the param area and any "low frame" + # needed as an argsave area below the param block for callees that + # we invoke. + move s0, sp + + REG_L a1, A2OFF(sp) # a1 = paramCount + REG_L a2, A3OFF(sp) # a2 = params + + # we define a word as 4 bytes, period end of story! + sll v0, 2 # 4 bytes * result of invoke_copy_words + subu v0, LOFRAMESZ # but we take back the argsave area built into + # our stack frame -- SWEET! + subu sp, sp, v0 # make room + move a0, sp # a0 = param stack address + move s1, a0 # save it for later -- it should be safe here + + # the old sp is still saved in s0, but we now need another argsave + # area ("low frame") for the invoke_copy_to_stack call. + subu sp, sp, LOFRAMESZ + + # copy the param into the stack areas + # invoke_copy_to_stack(PRUint32* d, PRUint32 paramCount, + # nsXPTCVariant* s) + jal invoke_copy_to_stack + lw gp, GPOFF(s0) + + move sp, s0 # get orig sp back, popping params and argsave + + REG_L a0, A0OFF(sp) # a0 = set "that" to be "this" + REG_L a1, A1OFF(sp) # a1 = methodIndex + + # t1 = methodIndex * 4 + # (use shift instead of mult) + sll t1, a1, 2 + + # calculate the function we need to jump to, + # which must then be saved in t9 + lw t9, 0(a0) + addu t9, t9, t1 + lw t9, 8(t9) + + # a1..a3 and f13..f14 should now be set to what + # invoke_copy_to_stack told us. skip a0 and f12 + # because that is the "this" pointer + + REG_L a1, 1*SZREG(s1) + REG_L a2, 2*SZREG(s1) + REG_L a3, 3*SZREG(s1) + + l.d $f13, 8(s1) + l.d $f14, 16(s1) + + # Create the stack pointer for the function, which must have 4 words + # of space for callee-saved args. invoke_count_words allocated space + # for a0 starting at s1, so we just move s1 into sp. + move sp, s1 + + jalr ra, t9 + lw gp, GPOFF(s0) + + move sp, s0 + + REG_L ra, RAOFF(sp) + REG_L s0, S0OFF(sp) + addu sp, FRAMESZ + j ra +.end _XPTC_InvokeByIndex diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_openvms_alpha.s b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_openvms_alpha.s new file mode 100644 index 00000000..d37a91d2 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_openvms_alpha.s @@ -0,0 +1,99 @@ +;* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- +;* +;* The contents of this file are subject to the Netscape 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/NPL/ +;* +;* 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.org code. +;* +;* The Initial Developer of the Original Code is Netscape +;* Communications Corporation. Portions created by Netscape are +;* Copyright (C) 1998 Netscape Communications Corporation. All +;* Rights Reserved. +;* +;* Contributor(s): +;*/ + +; +; XPTC_PUBLIC_API(nsresult) +; XPTC_InvokeByIndex(nsISupports* that, PRUint32 methodIndex, +; PRUint32 paramCount, nsXPTCVariant* params) +; + + .title "INVOKE" "Invoke By Index" + + $routine XPTC_InvokeByIndex, kind=stack, saved_regs= + + mov r27,r2 ; Need to set up a base register... + .base r2,$LS ; ...for the LINKAGE_PAIR call + + mov r17,r3 ; save methodIndex in r3 + mov r18,r4 ; save paramCount in r4 + +; +; Allocate enough stack space to hold the greater of 6 or "paramCount"+1 +; parameters. (+1 for "this" pointer) Room for at least 6 parameters +; is required for storage of those passed via registers. +; + + cmplt R18,5,R1 ; paramCount = MAX(5, "paramCount") + cmovne R1,5,R18 + s8addq R18,16,R1 ; room for "paramCount"+1 params (8 bytes each) + bic R1,15,R1 ; stack space is rounded up to 0 % 16 + subq SP,R1,SP + + stq R16,0(SP) ; save "that" (as "this" pointer) + addq SP,8,R16 ; pass stack pointer + mov R4,R17 ; pass original "paramCount + mov R19,R18 ; pass "params" + mov 4,r25 ; argument count + + $LINKAGE_PAIR invoke_copy_to_stack + ldq r26,$LP ; get entry point address from linkage pair + ldq r27,$LP+8 ; get procedure descriptor address from lp + jsr r26,r26 ; and call the routine + +; +; Copy the first 6 parameters to registers and remove from stack frame. +; Both the integer and floating point registers are set for each parameter +; except the first which is the "this" pointer. (integer only) +; The floating point registers are all set as doubles since the +; invoke_copy_to_stack function should have converted the floats. +; + ldq R16,0(SP) ; integer registers + ldq R17,8(SP) + ldq R18,16(SP) + ldq R19,24(SP) + ldq R20,32(SP) + ldq R21,40(SP) + ldt F17,8(SP) ; floating point registers + ldt F18,16(SP) + ldt F19,24(SP) + ldt F20,32(SP) + ldt F21,40(SP) + + addq SP,48,SP ; remove params from stack + +; +; Call the virtual function with the constructed stack frame. +; First three methods are always QueryInterface, AddRef and Release. +; + addq r4,1,r25 ; argument count now includes "this" + mov R16,R1 ; load "this" + ldl R1,0(R1) ; load vtable + s4addq r3,0,r28 ; vtable index = "methodIndex" * 4 + addq r1,r28,r1 + ldl r27,0(r1) ; load procedure value + ldq r26,8(r27) ; load entry point address + jsr r26,r26 ; call virtual function + + $return + + $end_routine XPTC_InvokeByIndex + .end diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_osf1_alpha.s b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_osf1_alpha.s new file mode 100644 index 00000000..ad7b2f82 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_osf1_alpha.s @@ -0,0 +1,83 @@ +/* + * XPTC_PUBLIC_API(nsresult) + * XPTC_InvokeByIndex(nsISupports* that, PRUint32 methodIndex, + * PRUint32 paramCount, nsXPTCVariant* params) + */ +.text +.align 4 +.globl XPTC_InvokeByIndex +.ent XPTC_InvokeByIndex +XPTC_InvokeByIndex: +.frame $15,32,$26,0 +.mask 0x4008000,-32 +ldgp $29,0($27) +XPTC_InvokeByIndexXv: +subq $30,32,$30 +stq $26,0($30) +stq $15,8($30) +bis $30,$30,$15 +.prologue 1 + +/* + * Allocate enough stack space to hold the greater of 6 or "paramCount"+1 + * parameters. (+1 for "this" pointer) Room for at least 6 parameters + * is required for storage of those passed via registers. + */ + +bis $31,5,$2 /* count = MAX(5, "paramCount") */ +cmplt $2,$18,$1 +cmovne $1,$18,$2 +s8addq $2,16,$1 /* room for count+1 params (8 bytes each) */ +bic $1,15,$1 /* stack space is rounded up to 0 % 16 */ +subq $30,$1,$30 + +stq $16,0($30) /* save "that" (as "this" pointer) */ +stq $17,16($15) /* save "methodIndex" */ + +addq $30,8,$16 /* pass stack pointer */ +bis $18,$18,$17 /* pass "paramCount" */ +bis $19,$19,$18 /* pass "params" */ +jsr $26,invoke_copy_to_stack /* call invoke_copy_to_stack */ +ldgp $29,0($26) + +/* + * Copy the first 6 parameters to registers and remove from stack frame. + * Both the integer and floating point registers are set for each parameter + * except the first which is the "this" pointer. (integer only) + * The floating point registers are all set as doubles since the + * invoke_copy_to_stack function should have converted the floats. + */ +ldq $16,0($30) /* integer registers */ +ldq $17,8($30) +ldq $18,16($30) +ldq $19,24($30) +ldq $20,32($30) +ldq $21,40($30) +ldt $f17,8($30) /* floating point registers */ +ldt $f18,16($30) +ldt $f19,24($30) +ldt $f20,32($30) +ldt $f21,40($30) + +addq $30,48,$30 /* remove params from stack */ + +/* + * Call the virtual function with the constructed stack frame. + */ +bis $16,$16,$1 /* load "this" */ +ldq $2,16($15) /* load "methodIndex" */ +ldq $1,0($1) /* load vtable */ +s8addq $2,0,$2 /* vtable index = "methodIndex" * 8 + 16 */ +addq $1,$2,$1 +ldq $27,0($1) /* load address of function */ +jsr $26,($27),0 /* call virtual function */ +ldgp $29,0($26) + +bis $15,$15,$30 +ldq $26,0($30) +ldq $15,8($30) +addq $30,32,$30 +ret $31,($26),1 +.end XPTC_InvokeByIndex + + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_pa32.s b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_pa32.s new file mode 100644 index 00000000..8ce8f17f --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_pa32.s @@ -0,0 +1,131 @@ + .LEVEL 1.1 +framesz .EQU 128 + +; XPTC_InvokeByIndex(nsISuppots* that, PRUint32 methodIndex, +; PRUint32 paramCount, nsXPTCVariant* params); + +; g++ need to compile everything with -fvtable-thunks ! + + .SPACE $TEXT$,SORT=8 + .SUBSPA $CODE$,QUAD=0,ALIGN=4,ACCESS=0x2c,CODE_ONLY,SORT=24 +XPTC_InvokeByIndex + .PROC + .CALLINFO CALLER,FRAME=72,ENTRY_GR=%r3,SAVE_RP,SAVE_SP,ARGS_SAVED,ALLOCA_FRAME + + ; frame marker takes 48 bytes, + ; register spill area takes 8 bytes, + ; local stack area takes 72 bytes result in 128 bytes total + + .ENTRY + STW %rp,-20(%sp) + STW,MA %r3,128(%sp) + + LDO -framesz(%r30),%r28 + STW %r28,-4(%r30) ; save previous sp + STW %r19,-32(%r30) + + STW %r26,-36-framesz(%r30) ; save argument registers in + STW %r25,-40-framesz(%r30) ; in PREVIOUS frame + STW %r24,-44-framesz(%r30) ; + STW %r23,-48-framesz(%r30) ; + + B,L .+8,%r2 + ADDIL L'invoke_count_bytes-$PIC_pcrel$1+4,%r2,%r1 + LDO R'invoke_count_bytes-$PIC_pcrel$2+8(%r1),%r1 +$PIC_pcrel$1 + LDSID (%r1),%r31 +$PIC_pcrel$2 + MTSP %r31,%sr0 + .CALL ARGW0=GR,ARGW1=GR,ARGW2=GR ;in=24,25,26;out=28 + BE,L 0(%sr0,%r1),%r31 + COPY %r31,%r2 + + CMPIB,>= 0,%r28, .+76 + COPY %r30,%r3 ; copy stack ptr to saved stack ptr + ADD %r30,%r28,%r30 ; extend stack frame + LDW -4(%r3),%r28 ; move frame + STW %r28,-4(%r30) + LDW -8(%r3),%r28 + STW %r28,-8(%r30) + LDW -12(%r3),%r28 + STW %r28,-12(%r30) + LDW -16(%r3),%r28 + STW %r28,-16(%r30) + LDW -20(%r3),%r28 + STW %r28,-20(%r30) + LDW -24(%r3),%r28 + STW %r28,-24(%r30) + LDW -28(%r3),%r28 + STW %r28,-28(%r30) + LDW -32(%r3),%r28 + STW %r28,-32(%r30) + + LDO -40(%r30),%r26 ; load copy address + LDW -44-framesz(%r3),%r25 ; load rest of 2 arguments + LDW -48-framesz(%r3),%r24 ; + + LDW -32(%r30),%r19 ; shared lib call destroys r19; reload + B,L .+8,%r2 + ADDIL L'invoke_copy_to_stack-$PIC_pcrel$3+4,%r2,%r1 + LDO R'invoke_copy_to_stack-$PIC_pcrel$4+8(%r1),%r1 +$PIC_pcrel$3 + LDSID (%r1),%r31 +$PIC_pcrel$4 + MTSP %r31,%sr0 + .CALL ARGW0=GR,ARGW1=GR,ARGW2=GR ;in=24,25,26 + BE,L 0(%sr0,%r1),%r31 + COPY %r31,%r2 + + LDO -48(%r30),%r20 + EXTRW,U,= %r28,31,1,%r22 + FLDD 0(%r20),%fr7 ; load double arg 1 + EXTRW,U,= %r28,30,1,%r22 + FLDW 8(%r20),%fr5L ; load float arg 1 + EXTRW,U,= %r28,29,1,%r22 + FLDW 4(%r20),%fr6L ; load float arg 2 + EXTRW,U,= %r28,28,1,%r22 + FLDW 0(%r20),%fr7L ; load float arg 3 + + LDW -36-framesz(%r3),%r26 ; load ptr to 'that' + LDW -40(%r30),%r25 ; load the rest of dispatch argument registers + LDW -44(%r30),%r24 + LDW -48(%r30),%r23 + + LDW -36-framesz(%r3),%r20 ; load vtable addr + LDW -40-framesz(%r3),%r28 ; load index + LDW 0(%r20),%r20 ; follow vtable + LDO 16(%r20),%r20 ; offset vtable by 16 bytes (g++: 8, aCC: 16) + SH2ADDL %r28,%r20,%r28 ; add 4*index to vtable entry + LDW 0(%r28),%r22 ; load vtable entry + + B,L .+8,%r2 + ADDIL L'$$dyncall_external-$PIC_pcrel$5+4,%r2,%r1 + LDO R'$$dyncall_external-$PIC_pcrel$6+8(%r1),%r1 +$PIC_pcrel$5 + LDSID (%r1),%r31 +$PIC_pcrel$6 + MTSP %r31,%sr0 + .CALL ARGW0=GR,ARGW1=GR,ARGW2=GR,ARGW3=GR,RTNVAL=GR +;in=22-26;out=28; + BE,L 0(%sr0,%r1),%r31 + COPY %r31,%r2 + + LDW -32(%r30),%r19 + COPY %r3,%r30 ; restore saved stack ptr + + LDW -148(%sp),%rp + BVE (%rp) + .EXIT + LDW,MB -128(%sp),%r3 + + .PROCEND ;in=23,24,25,26; + + .ALIGN 8 + .SPACE $TEXT$ + .SUBSPA $CODE$ + .IMPORT $$dyncall_external,MILLICODE + .IMPORT invoke_count_bytes,CODE + .IMPORT invoke_copy_to_stack,CODE + .EXPORT XPTC_InvokeByIndex,ENTRY,PRIV_LEV=3,ARGW0=GR,ARGW1=GR,ARGW2=GR,ARGW3=GR,RTNVAL=GR,LONG_RETURN + .END + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_ppc_aix.s b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_ppc_aix.s new file mode 100644 index 00000000..3684d154 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_ppc_aix.s @@ -0,0 +1,146 @@ + # + # -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + # + # The contents of this file are subject to the Netscape 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/NPL/ + # + # 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.org code. + # + # The Initial Developer of the Original Code is Netscape + # Communications Corporation. Portions created by Netscape are + # Copyright (C) 1999 Netscape Communications Corporation. All + # Rights Reserved. + # + # Contributor(s): + # IBM Corporation + # + +.set r0,0; .set sp,1; .set RTOC,2; .set r3,3; .set r4,4 +.set r5,5; .set r6,6; .set r7,7; .set r8,8; .set r9,9 +.set r10,10; .set r11,11; .set r12,12; .set r13,13; .set r14,14 +.set r15,15; .set r16,16; .set r17,17; .set r18,18; .set r19,19 +.set r20,20; .set r21,21; .set r22,22; .set r23,23; .set r24,24 +.set r25,25; .set r26,26; .set r27,27; .set r28,28; .set r29,29 +.set r30,30; .set r31,31 +.set f0,0; .set f1,1; .set f2,2; .set f3,3; .set f4,4 +.set f5,5; .set f6,6; .set f7,7; .set f8,8; .set f9,9 +.set f10,10; .set f11,11; .set f12,12; .set f13,13; .set f14,14 +.set f15,15; .set f16,16; .set f17,17; .set f18,18; .set f19,19 +.set f20,20; .set f21,21; .set f22,22; .set f23,23; .set f24,24 +.set f25,25; .set f26,26; .set f27,27; .set f28,28; .set f29,29 +.set f30,30; .set f31,31 +.set BO_IF,12 +.set CR0_EQ,2 + + + + .rename H.10.NO_SYMBOL{PR},"" + .rename H.18.XPTC_InvokeByIndex{TC},"XPTC_InvokeByIndex" + + +# .text section + + .csect H.10.NO_SYMBOL{PR} + .globl .XPTC_InvokeByIndex + .globl XPTC_InvokeByIndex{DS} + .extern .invoke_copy_to_stack + .extern ._ptrgl{PR} + + +# +# XPTC_InvokeByIndex(nsISupports* that, PRUint32 methodIndex, +# PRUint32 paramCount, nsXPTCVariant* params) +# + +.XPTC_InvokeByIndex: + mflr r0 + stw r31,-4(sp) +# +# save off the incoming values in the caller's parameter area +# + stw r3,24(sp) # that + stw r4,28(sp) # methodIndex + stw r5,32(sp) # paramCount + stw r6,36(sp) # params + stw r0,8(sp) + stwu sp,-136(sp) # = 24 for linkage area, 8 * 13 for fprData area, 8 for saved registers + +# prepare args for 'invoke_copy_to_stack' call +# + lwz r4,168(sp) # paramCount + lwz r5,172(sp) # params + mr r6,sp # fprData + slwi r3,r4,3 # number of bytes of stack required + # at most 8*paramCount + addi r3,r3,28 # linkage area + mr r31,sp # save original stack top + subfc sp,r3,sp # bump the stack + addi r3,sp,28 # parameter pointer excludes linkage area size + 'this' + + bl .invoke_copy_to_stack + nop + + lfd f1,0(r31) # Restore floating point registers + lfd f2,8(r31) + lfd f3,16(r31) + lfd f4,24(r31) + lfd f5,32(r31) + lfd f6,40(r31) + lfd f7,48(r31) + lfd f8,56(r31) + lfd f9,64(r31) + lfd f10,72(r31) + lfd f11,80(r31) + lfd f12,88(r31) + lfd f13,96(r31) + + lwz r3,160(r31) # that + lwz r4,0(r3) # get vTable from 'that' + lwz r5,164(r31) # methodIndex + slwi r5,r5,3 # methodIndex * 8 + addi r5,r5,8 # step over junk at start of vTable ! + lwzx r11,r5,r4 # get function pointer + + addi r5,r5,4 # We need to manually adjust the 'that' pointer, this is CFRONT based + lwzx r5,r4,r5 # offset = r4(vtable) + r5(methodIndex offset) - 4 + add r3,r5,r3 # adjust 'that' r3 = r3 + r5 + + lwz r4,28(sp) + lwz r5,32(sp) + lwz r6,36(sp) + lwz r7,40(sp) + lwz r8,44(sp) + lwz r9,48(sp) + lwz r10,52(sp) + + bl ._ptrgl{PR} + nop + + mr sp,r31 + lwz r0,144(sp) + addi sp,sp,136 + mtlr r0 + lwz r31,-4(sp) + blr + + +# .data section + + .toc # 0x00000038 +T.18.XPTC_InvokeByIndex: + .tc H.18.XPTC_InvokeByIndex{TC},XPTC_InvokeByIndex{DS} + + .csect XPTC_InvokeByIndex{DS} + .long .XPTC_InvokeByIndex # "\0\0\0\0" + .long TOC{TC0} # "\0\0\0008" + .long 0x00000000 # "\0\0\0\0" +# End csect XPTC_InvokeByIndex{DS} + +# .bss section diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_ppc_aix64.s b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_ppc_aix64.s new file mode 100644 index 00000000..a174e424 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_ppc_aix64.s @@ -0,0 +1,161 @@ +# ***** BEGIN LICENSE BLOCK ***** +# +# Version: MPL 1.1/LGPL 2.1/GPL 2.0 +# +# 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.org code. +# +# The Initial Developer of the Original Code is IBM Corporation. +# Portions created by IBM are +# Copyright (C) 2002, International Business Machines Corporation. +# All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of 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 LGPL or the GPL. 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 ***** + +.set r0,0; .set sp,1; .set RTOC,2; .set r3,3; .set r4,4 +.set r5,5; .set r6,6; .set r7,7; .set r8,8; .set r9,9 +.set r10,10; .set r11,11; .set r12,12; .set r13,13; .set r14,14 +.set r15,15; .set r16,16; .set r17,17; .set r18,18; .set r19,19 +.set r20,20; .set r21,21; .set r22,22; .set r23,23; .set r24,24 +.set r25,25; .set r26,26; .set r27,27; .set r28,28; .set r29,29 +.set r30,30; .set r31,31 +.set f0,0; .set f1,1; .set f2,2; .set f3,3; .set f4,4 +.set f5,5; .set f6,6; .set f7,7; .set f8,8; .set f9,9 +.set f10,10; .set f11,11; .set f12,12; .set f13,13; .set f14,14 +.set f15,15; .set f16,16; .set f17,17; .set f18,18; .set f19,19 +.set f20,20; .set f21,21; .set f22,22; .set f23,23; .set f24,24 +.set f25,25; .set f26,26; .set f27,27; .set f28,28; .set f29,29 +.set f30,30; .set f31,31 +.set BO_IF,12 +.set CR0_EQ,2 + + .rename H.10.NO_SYMBOL{PR},"" + .rename H.18.XPTC_InvokeByIndex{TC},"XPTC_InvokeByIndex" + + +# .text section + + .csect H.10.NO_SYMBOL{PR} + .globl .XPTC_InvokeByIndex + .globl XPTC_InvokeByIndex{DS} + .extern .invoke_copy_to_stack + .extern ._ptrgl{PR} + +# +# XPTC_InvokeByIndex(nsISupports* that, PRUint32 methodIndex, +# PRUint32 paramCount, nsXPTCVariant* params) +# + +.XPTC_InvokeByIndex: + mflr r0 + std r31,-8(sp) +# +# save off the incoming values in the caller's parameter area +# + std r3,48(sp) # that + std r4,56(sp) # methodIndex + std r5,64(sp) # paramCount + std r6,72(sp) # params + std r0,16(sp) + stdu sp,-168(sp) # 2*24=48 for linkage area, + # 8*13=104 for fprData area + # 16 for saved registers + +# prepare args for 'invoke_copy_to_stack' call +# + ld r4,232(sp) # paramCount (168+8+56) + ld r5,240(sp) # params + mr r6,sp # fprData + sldi r3,r4,3 # number of bytes of stack required + # is at most numParams*8 + addi r3,r3,56 # linkage area (48) + this (8) + mr r31,sp # save original stack top + subfc sp,r3,sp # bump the stack + addi r3,sp,56 # parameter pointer excludes linkage area + # size + 'this' + + bl .invoke_copy_to_stack + nop + + lfd f1,0(r31) # Restore floating point registers + lfd f2,8(r31) + lfd f3,16(r31) + lfd f4,24(r31) + lfd f5,32(r31) + lfd f6,40(r31) + lfd f7,48(r31) + lfd f8,56(r31) + lfd f9,64(r31) + lfd f10,72(r31) + lfd f11,80(r31) + lfd f12,88(r31) + lfd f13,96(r31) + + ld r3,216(r31) # that (168+48) + ld r4,0(r3) # get vTable from 'that' + ld r5,224(r31) # methodIndex (168+56) + sldi r5,r5,3 # methodIndex * 8 + # No junk at the start of 64bit vtable !!! + ldx r11,r5,r4 # get function pointer (this jumps + # either to the function if no adjustment + # is needed (displacement = 0), or it + # jumps to the thunk code, which will jump + # to the function at the end) + + # No adjustment of the that pointer in 64bit mode, this is done + # by the thunk code + + ld r4,56(sp) + ld r5,64(sp) + ld r6,72(sp) + ld r7,80(sp) + ld r8,88(sp) + ld r9,96(sp) + ld r10,104(sp) + + bl ._ptrgl{PR} + nop + + mr sp,r31 + ld r0,184(sp) # 168+16 + addi sp,sp,168 + mtlr r0 + ld r31,-8(sp) + blr + +# .data section + + .toc # 0x00000038 +T.18.XPTC_InvokeByIndex: + .tc H.18.XPTC_InvokeByIndex{TC},XPTC_InvokeByIndex{DS} + + .csect XPTC_InvokeByIndex{DS} + .llong .XPTC_InvokeByIndex # "\0\0\0\0" + .llong TOC{TC0} # "\0\0\0008" + .llong 0x00000000 # "\0\0\0\0" +# End csect XPTC_InvokeByIndex{DS} + +# .bss section diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_ppc_ibmobj_aix.s b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_ppc_ibmobj_aix.s new file mode 100644 index 00000000..064a73ab --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_ppc_ibmobj_aix.s @@ -0,0 +1,140 @@ + # + # -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + # + # The contents of this file are subject to the Netscape 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/NPL/ + # + # 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.org code. + # + # The Initial Developer of the Original Code is IBM Corporation. + # Portions created by IBM are + # Copyright (C) 2004, International Business Machines Corporation. + # All Rights Reserved. + # + # Contributor(s): + # + +.set r0,0; .set sp,1; .set RTOC,2; .set r3,3; .set r4,4 +.set r5,5; .set r6,6; .set r7,7; .set r8,8; .set r9,9 +.set r10,10; .set r11,11; .set r12,12; .set r13,13; .set r14,14 +.set r15,15; .set r16,16; .set r17,17; .set r18,18; .set r19,19 +.set r20,20; .set r21,21; .set r22,22; .set r23,23; .set r24,24 +.set r25,25; .set r26,26; .set r27,27; .set r28,28; .set r29,29 +.set r30,30; .set r31,31 +.set f0,0; .set f1,1; .set f2,2; .set f3,3; .set f4,4 +.set f5,5; .set f6,6; .set f7,7; .set f8,8; .set f9,9 +.set f10,10; .set f11,11; .set f12,12; .set f13,13; .set f14,14 +.set f15,15; .set f16,16; .set f17,17; .set f18,18; .set f19,19 +.set f20,20; .set f21,21; .set f22,22; .set f23,23; .set f24,24 +.set f25,25; .set f26,26; .set f27,27; .set f28,28; .set f29,29 +.set f30,30; .set f31,31 +.set BO_IF,12 +.set CR0_EQ,2 + + + + .rename H.10.NO_SYMBOL{PR},"" + .rename H.18.XPTC_InvokeByIndex{TC},"XPTC_InvokeByIndex" + + +# .text section + + .csect H.10.NO_SYMBOL{PR} + .globl .XPTC_InvokeByIndex + .globl XPTC_InvokeByIndex{DS} + .extern .invoke_copy_to_stack + .extern ._ptrgl{PR} + + +# +# XPTC_InvokeByIndex(nsISupports* that, PRUint32 methodIndex, +# PRUint32 paramCount, nsXPTCVariant* params) +# + +.XPTC_InvokeByIndex: + mflr r0 + stw r31,-4(sp) +# +# save off the incoming values in the caller's parameter area +# + stw r3,24(sp) # that + stw r4,28(sp) # methodIndex + stw r5,32(sp) # paramCount + stw r6,36(sp) # params + stw r0,8(sp) + stwu sp,-136(sp) # = 24 for linkage area, 8 * 13 for fprData area, 8 for saved registers + +# prepare args for 'invoke_copy_to_stack' call +# + lwz r4,168(sp) # paramCount + lwz r5,172(sp) # params + mr r6,sp # fprData + slwi r3,r4,3 # number of bytes of stack required + # at most 8*paramCount + addi r3,r3,28 # linkage area + mr r31,sp # save original stack top + subfc sp,r3,sp # bump the stack + addi r3,sp,28 # parameter pointer excludes linkage area size + 'this' + + bl .invoke_copy_to_stack + nop + + lfd f1,0(r31) # Restore floating point registers + lfd f2,8(r31) + lfd f3,16(r31) + lfd f4,24(r31) + lfd f5,32(r31) + lfd f6,40(r31) + lfd f7,48(r31) + lfd f8,56(r31) + lfd f9,64(r31) + lfd f10,72(r31) + lfd f11,80(r31) + lfd f12,88(r31) + lfd f13,96(r31) + + lwz r3,160(r31) # that + lwz r4,0(r3) # get vTable from 'that' + lwz r5,164(r31) # methodIndex + slwi r5,r5,2 # methodIndex * 4 + lwzx r11,r5,r4 # get function pointer + + lwz r4,28(sp) + lwz r5,32(sp) + lwz r6,36(sp) + lwz r7,40(sp) + lwz r8,44(sp) + lwz r9,48(sp) + lwz r10,52(sp) + + bl ._ptrgl{PR} + nop + + mr sp,r31 + lwz r0,144(sp) + addi sp,sp,136 + mtlr r0 + lwz r31,-4(sp) + blr + + +# .data section + + .toc # 0x00000038 +T.18.XPTC_InvokeByIndex: + .tc H.18.XPTC_InvokeByIndex{TC},XPTC_InvokeByIndex{DS} + + .csect XPTC_InvokeByIndex{DS} + .long .XPTC_InvokeByIndex # "\0\0\0\0" + .long TOC{TC0} # "\0\0\0008" + .long 0x00000000 # "\0\0\0\0" +# End csect XPTC_InvokeByIndex{DS} + +# .bss section diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_ppc_linux.s b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_ppc_linux.s new file mode 100644 index 00000000..b9aaa997 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_ppc_linux.s @@ -0,0 +1,113 @@ +// -*- Mode: Asm -*- +// +// The contents of this file are subject to the Netscape 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/NPL/ +// +// 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.org code. +// +// The Initial Developer of the Original Code is Netscape +// Communications Corporation. Portions created by Netscape are +// Copyright (C) 1999 Netscape Communications Corporation. All +// Rights Reserved. +// +// Contributor(s): +// Franz.Sirl-kernel@lauterbach.com (Franz Sirl) +// beard@netscape.com (Patrick Beard) +// waterson@netscape.com (Chris Waterson) +// + +.set r0,0; .set sp,1; .set RTOC,2; .set r3,3; .set r4,4 +.set r5,5; .set r6,6; .set r7,7; .set r8,8; .set r9,9 +.set r10,10; .set r11,11; .set r12,12; .set r13,13; .set r14,14 +.set r15,15; .set r16,16; .set r17,17; .set r18,18; .set r19,19 +.set r20,20; .set r21,21; .set r22,22; .set r23,23; .set r24,24 +.set r25,25; .set r26,26; .set r27,27; .set r28,28; .set r29,29 +.set r30,30; .set r31,31 +.set f0,0; .set f1,1; .set f2,2; .set f3,3; .set f4,4 +.set f5,5; .set f6,6; .set f7,7; .set f8,8; .set f9,9 +.set f10,10; .set f11,11; .set f12,12; .set f13,13; .set f14,14 +.set f15,15; .set f16,16; .set f17,17; .set f18,18; .set f19,19 +.set f20,20; .set f21,21; .set f22,22; .set f23,23; .set f24,24 +.set f25,25; .set f26,26; .set f27,27; .set f28,28; .set f29,29 +.set f30,30; .set f31,31 + + .section ".text" + .align 2 + .globl XPTC_InvokeByIndex + .type XPTC_InvokeByIndex,@function + +// +// XPTC_InvokeByIndex(nsISupports* that, PRUint32 methodIndex, +// PRUint32 paramCount, nsXPTCVariant* params) +// + +XPTC_InvokeByIndex: + stwu sp,-32(sp) // setup standard stack frame + mflr r0 // save LR + stw r3,8(sp) // r3 <= that + stw r4,12(sp) // r4 <= methodIndex + stw r30,16(sp) + stw r31,20(sp) + + stw r0,36(sp) // store LR backchain + mr r31,sp + + rlwinm r10,r5,3,0,27 // r10 = (ParamCount * 2 * 4) & ~0x0f + addi r0,r10,96 // reserve stack for GPR and FPR register save area r0 = r10 + 96 + lwz r9,0(sp) // r9 = backchain + neg r0,r0 + stwux r9,sp,r0 // reserve stack space and save SP backchain + + addi r3,sp,8 // r3 <= args + mr r4,r5 // r4 <= paramCount + mr r5,r6 // r5 <= params + add r6,r3,r10 // r6 <= gpregs ( == args + r10 ) + mr r30,r6 // store in r30 for use later... + addi r7,r6,32 // r7 <= fpregs ( == gpregs + 32 ) + + bl invoke_copy_to_stack@local // (args, paramCount, params, gpregs, fpregs) + + lfd f1,32(r30) // load FP registers with method parameters + lfd f2,40(r30) + lfd f3,48(r30) + lfd f4,56(r30) + lfd f5,64(r30) + lfd f6,72(r30) + lfd f7,80(r30) + lfd f8,88(r30) + + lwz r3,8(r31) // r3 <= that + lwz r4,12(r31) // r4 <= methodIndex + lwz r5,0(r3) // r5 <= vtable ( == *that ) +#if !((__GNUC__ == 3 && __GNUC_MINOR__ < 2) || __GXX_ABI_VERSION >= 100) // G++ pre-V3 ABI + addi r4,r4,2 // skip first two vtable entries +#endif + slwi r4,r4,2 // convert to offset ( *= 4 ) + lwzx r0,r5,r4 // r0 <= methodpointer ( == vtable + offset ) + + lwz r4,4(r30) // load GP regs with method parameters + lwz r5,8(r30) + lwz r6,12(r30) + lwz r7,16(r30) + lwz r8,20(r30) + lwz r9,24(r30) + lwz r10,28(r30) + + mtlr r0 // copy methodpointer to LR + blrl // call method + + lwz r30,16(r31) // restore r30 & r31 + lwz r31,20(r31) + + lwz r11,0(sp) // clean up the stack + lwz r0,4(r11) + mtlr r0 + mr sp,r11 + blr diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_ppc_netbsd.s b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_ppc_netbsd.s new file mode 100644 index 00000000..18c775a9 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_ppc_netbsd.s @@ -0,0 +1,114 @@ +# -*- Mode: Asm -*- +# +# The contents of this file are subject to the Netscape 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/NPL/ +# +# 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.org code. +# +# The Initial Developer of the Original Code is Netscape +# Communications Corporation. Portions created by Netscape are +# Copyright (C) 1999 Netscape Communications Corporation. All +# Rights Reserved. +# +# Contributor(s): +# Franz.Sirl-kernel@lauterbach.com (Franz Sirl) +# beard@netscape.com (Patrick Beard) +# waterson@netscape.com (Chris Waterson) +# +.set r0,0; .set sp,1; .set RTOC,2; .set r3,3; .set r4,4 +.set r5,5; .set r6,6; .set r7,7; .set r8,8; .set r9,9 +.set r10,10; .set r11,11; .set r12,12; .set r13,13; .set r14,14 +.set r15,15; .set r16,16; .set r17,17; .set r18,18; .set r19,19 +.set r20,20; .set r21,21; .set r22,22; .set r23,23; .set r24,24 +.set r25,25; .set r26,26; .set r27,27; .set r28,28; .set r29,29 +.set r30,30; .set r31,31 +.set f0,0; .set f1,1; .set f2,2; .set f3,3; .set f4,4 +.set f5,5; .set f6,6; .set f7,7; .set f8,8; .set f9,9 +.set f10,10; .set f11,11; .set f12,12; .set f13,13; .set f14,14 +.set f15,15; .set f16,16; .set f17,17; .set f18,18; .set f19,19 +.set f20,20; .set f21,21; .set f22,22; .set f23,23; .set f24,24 +.set f25,25; .set f26,26; .set f27,27; .set f28,28; .set f29,29 +.set f30,30; .set f31,31 + + .section ".text" + .align 2 + .globl XPTC_InvokeByIndex + .type XPTC_InvokeByIndex,@function + +# +# XPTC_InvokeByIndex(nsISupports* that, PRUint32 methodIndex, +# PRUint32 paramCount, nsXPTCVariant* params) +# + +XPTC_InvokeByIndex: + stwu sp,-32(sp) # setup standard stack frame + mflr r0 # save LR + stw r3,8(sp) # r3 <= that + stw r4,12(sp) # r4 <= methodIndex + stw r30,16(sp) + stw r31,20(sp) + + stw r0,36(sp) # store LR backchain + mr r31,sp + + rlwinm r10,r5,3,0,27 # r10 = (ParamCount * 2 * 4) & ~0x0f + addi r0,r10,96 # reserve stack for GPR and FPR register save area r0 = r10 + 96 + lwz r9,0(sp) # r9 = backchain + neg r0,r0 + stwux r9,sp,r0 # reserve stack sapce and save SP backchain + + addi r3,sp,8 # r3 <= args + mr r4,r5 # r4 <= paramCount + mr r5,r6 # r5 <= params + add r6,r3,r10 # r6 <= gpregs ( == args + r10 ) + mr r30,r6 # store in r30 for use later... + addi r7,r6,32 # r7 <= fpregs ( == gpregs + 32 ) + + bl invoke_copy_to_stack@local # (args, paramCount, params, gpregs, fpregs) + + lfd f1,32(r30) # load FP registers with method parameters + lfd f2,40(r30) + lfd f3,48(r30) + lfd f4,56(r30) + lfd f5,64(r30) + lfd f6,72(r30) + lfd f7,80(r30) + lfd f8,88(r30) + + lwz r3,8(r31) # r3 <= that + lwz r4,12(r31) # r4 <= methodIndex + lwz r5,0(r3) # r5 <= vtable ( == *that ) + slwi r4,r4,3 # convert to offset ( *= 8 ) + addi r4,r4,8 # skip first two vtable entries + add r4,r4,r5 + lhz r0,0(r4) # virtual base offset + extsh r0,r0 + add r3,r3,r0 + lwz r0,4(r4) # r0 <= methodpointer ( == vtable + offset ) + + lwz r4,4(r30) # load GP regs with method parameters + lwz r5,8(r30) + lwz r6,12(r30) + lwz r7,16(r30) + lwz r8,20(r30) + lwz r9,24(r30) + lwz r10,28(r30) + + mtlr r0 # copy methodpointer to LR + blrl # call method + + lwz r30,16(r31) # restore r30 & r31 + lwz r31,20(r31) + + lwz r11,0(sp) # clean up the stack + lwz r0,4(r11) + mtlr r0 + mr sp,r11 + blr diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_ppc_rhapsody.s b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_ppc_rhapsody.s new file mode 100644 index 00000000..8a5c9afb --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_ppc_rhapsody.s @@ -0,0 +1,162 @@ +# +# -*- Mode: Asm -*- +# +# The contents of this file are subject to the Netscape 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/NPL/ +# +# 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.org code. +# +# The Initial Developer of the Original Code is Netscape +# Communications Corporation. Portions created by Netscape are +# Copyright (C) 1999 Netscape Communications Corporation. All +# Rights Reserved. +# +# Contributor(s): +# Patrick C. Beard +# + +# +# ** Assumed vtable layout (obtained by disassembling with gdb): +# ** 4 bytes per vtable entry, skip 0th and 1st entries, so the mapping +# ** from index to entry is (4 * index) + 8. +# + +.text + .align 2 +# +# XPTC_InvokeByIndex(nsISupports* that, PRUint32 methodIndex, +# PRUint32 paramCount, nsXPTCVariant* params) +# + +.globl __XPTC_InvokeByIndex +__XPTC_InvokeByIndex: + mflr r0 + stw r31,-4(r1) +# +# save off the incoming values in the callers parameter area +# + stw r3,24(r1) ; that + stw r4,28(r1) ; methodIndex + stw r5,32(r1) ; paramCount + stw r6,36(r1) ; params + stw r0,8(r1) + stwu r1,-144(r1) ; 24 for linkage area, + ; 8*13 for fprData area, + ; 8 for saved registers, + ; 8 to keep stack 16-byte aligned + +# set up for and call 'invoke_count_words' to get new stack size +# + mr r3,r5 + mr r4,r6 + + stwu r1,-24(r1) + bl L_invoke_count_words$stub + lwz r1,0(r1) + +# prepare args for 'invoke_copy_to_stack' call +# + lwz r4,176(r1) ; paramCount + lwz r5,180(r1) ; params + mr r6,r1 ; fprData + slwi r3,r3,2 ; number of stack bytes required + addi r3,r3,28 ; linkage area + mr r31,r1 ; save original stack top + sub r1,r1,r3 ; bump the stack + clrrwi r1,r1,4 ; keep the stack 16-byte aligned + addi r3,r31,144 ; act like real alloca, so 0(sp) always + stw r3,0(r1) ; points back to previous stack frame + addi r3,r1,28 ; parameter pointer excludes linkage area size + 'this' + +# create "temporary" stack frame for _invoke_copy_to_stack to operate in. + stwu r1,-40(r1) + bl L_invoke_copy_to_stack$stub +# remove temporary stack frame. + lwz r1,0(r1) + + lfd f1,0(r31) + lfd f2,8(r31) + lfd f3,16(r31) + lfd f4,24(r31) + lfd f5,32(r31) + lfd f6,40(r31) + lfd f7,48(r31) + lfd f8,56(r31) + lfd f9,64(r31) + lfd f10,72(r31) + lfd f11,80(r31) + lfd f12,88(r31) + lfd f13,96(r31) + + lwz r3,168(r31) ; that + lwz r4,0(r3) ; get vTable from 'that' + lwz r5,172(r31) ; methodIndex + slwi r5,r5,2 ; methodIndex * 4 +#ifndef HAVE_GCC3_ABI + addi r5,r5,8 ; (methodIndex * 4) + 8 +#endif + lwzx r12,r5,r4 ; get function pointer + + lwz r4,28(r1) + lwz r5,32(r1) + lwz r6,36(r1) + lwz r7,40(r1) + lwz r8,44(r1) + lwz r9,48(r1) + lwz r10,52(r1) + + mtlr r12 + blrl + + mr r1,r31 + lwz r0,152(r1) + addi r1,r1,144 + mtlr r0 + lwz r31,-4(r1) + + blr + +.picsymbol_stub +L_invoke_count_words$stub: + .indirect_symbol _invoke_count_words + mflr r0 + bcl 20,31,L1$pb +L1$pb: + mflr r11 + addis r11,r11,ha16(L1$lz-L1$pb) + mtlr r0 + lwz r12,lo16(L1$lz-L1$pb)(r11) + mtctr r12 + addi r11,r11,lo16(L1$lz-L1$pb) + bctr +.lazy_symbol_pointer +L1$lz: + .indirect_symbol _invoke_count_words + .long dyld_stub_binding_helper + + +.picsymbol_stub +L_invoke_copy_to_stack$stub: + .indirect_symbol _invoke_copy_to_stack + mflr r0 + bcl 20,31,L2$pb +L2$pb: + mflr r11 + addis r11,r11,ha16(L2$lz-L2$pb) + mtlr r0 + lwz r12,lo16(L2$lz-L2$pb)(r11) + mtctr r12 + addi r11,r11,lo16(L2$lz-L2$pb) + bctr +.lazy_symbol_pointer +L2$lz: + .indirect_symbol _invoke_copy_to_stack + .long dyld_stub_binding_helper + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_sparc_bsdos.s b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_sparc_bsdos.s new file mode 100644 index 00000000..b744ee9b --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_sparc_bsdos.s @@ -0,0 +1,121 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * The contents of this file are subject to the Netscape 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/NPL/ + * + * 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.org code. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): Chris Torek (torek@bsdi.com), Kurt Lidl (lidl@pix.net) + */ + +/* Platform specific code to invoke XPCOM methods on native objects */ + .global XPTC_InvokeByIndex +/* + XPTC_InvokeByIndex(nsISupports* that, PRUint32 methodIndex, + PRUint32 paramCount, nsXPTCVariant* params); + +*/ +XPTC_InvokeByIndex: + /* regular C/C++ stack frame -- see */ + save %sp, -96, %sp + + /* + * invoke_count_words(paramCount, params) apparently tells us + * how many "32-bit words" are involved in passing the given + * parameters to the target function. + */ + mov %i2, %o0 + call invoke_count_words ! invoke_count_words(paramCount, params) + mov %i3, %o1 + + /* + * ??? Torek wonders: does invoke_count_words always force its + * return value to be even? If not, we would have to adjust + * the return value ... should make it a multiple of 8 anyway, + * for efficiency (32 byte cache lines); will do that here thus: + * + * We already have room (in our callee's "argument dump" area, + * sp->fr_argd) for six parameters, and we are going to use + * five of those (fr_argd[1] through fr_argd[5]) in a moment. + * This space is followed by fr_argx[1], room for a seventh. + * Thus, if invoke_count_words returns a value between 0 and 6 + * inclusive, we do not need any stack adjustment. For values + * from 7 through (7+8) we want to make room for another 8 + * parameters, and so on. Thus, we want to calculate: + * + * n_extra_words = (wordcount + 1) & ~7 + * + * and then make room for that many more 32-bit words. (Normally + * it would be ((w+7)&~7; we just subtract off the room-for-6 we + * already have.) + */ + inc %o0 + andn %o0, 7, %o0 + sll %o0, 2, %o0 ! convert to bytes + sub %sp, %o0, %sp ! and make room for arguments + + /* + * Copy all the arguments to the stack, starting at the argument + * dump area at [%sp + 68], even though the first six arguments + * go in the six %o registers. We will just load up those + * arguments after the copy is done. The first argument to + * any C++ member function is always the "this" parameter so + * we actually start with what will go in %o1, at [%sp + 72]. + */ + add %sp, 72, %o0 ! invoke_copy_to_stack(addr, + mov %i2, %o1 ! paramCount, + call invoke_copy_to_stack + mov %i3, %o2 ! params); + + /* + * This is the only really tricky (compiler-dependent) part + * (everything else here relies only on the V8 SPARC calling + * conventions). "methodIndex" (%i1) is an index into a C++ + * vtable. The word at "*that" points to the vtable, but for + * some reason, the first function (index=0) is at vtable[2*4], + * the second (index 1) at vtable[3*4], the third at vtable[4*4], + * and so on. Thus, we want, in effect: + * + * that->vTable[index + 2] + */ + ld [%i0], %l0 ! vTable = *that + add %i1, 2, %l1 + sll %l1, 2, %l1 + ld [%l0 + %l1], %l0 ! fn = vTable[index + 2] + + /* + * Now load up the various function parameters. We do not know, + * nor really care, how many there are -- we just load five words + * from the stack (there are always at least five such words to + * load, even if some of them are junk) into %o1 through %o5, + * and set %o0 = %i0, to pass "that" to the target member function + * as its C++ "this" parameter. + * + * If there are more than five parameters, any extras go on our + * stack starting at sp->fr_argx ([%sp + 92]), which is of course + * where we have just copied them. + */ + ld [%sp + 72], %o1 + ld [%sp + 76], %o2 + ld [%sp + 80], %o3 + ld [%sp + 84], %o4 + ld [%sp + 88], %o5 + call %l0 ! fn(that, %o1, %o2, %o3, %o4, %o5) + mov %i0, %o0 + + ! return whatever fn() returned + ret + restore %o0, 0, %o0 + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_sparc_linux.s b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_sparc_linux.s new file mode 100644 index 00000000..c23fd1e7 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_sparc_linux.s @@ -0,0 +1,67 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * The contents of this file are subject to the Netscape 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/NPL/ + * + * 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.org code. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + */ + +/* Platform specific code to invoke XPCOM methods on native objects */ + .global XPTC_InvokeByIndex +/* + XPTC_InvokeByIndex(nsISupports* that, PRUint32 methodIndex, + PRUint32 paramCount, nsXPTCVariant* params); + +*/ +XPTC_InvokeByIndex: + save %sp,-(64 + 16),%sp ! room for the register window and + ! struct pointer, rounded up to 0 % 16 + mov %i2,%o0 ! paramCount + call invoke_count_words ! returns the required stack size in %o0 + mov %i3,%o1 ! params + + sll %o0,2,%l0 ! number of bytes + sub %sp,%l0,%sp ! create the additional stack space + + mov %sp,%o0 ! pointer for copied args + add %o0,72,%o0 ! step past the register window, the + ! struct result pointer and the 'this' slot + mov %i2,%o1 ! paramCount + call invoke_copy_to_stack + mov %i3,%o2 ! params +! +! calculate the target address from the vtable +! + add %i1,1,%i1 ! vTable is zero-based, index is 1 based (?) + ld [%i0],%l1 ! *that --> vTable + sll %i1,2,%i1 ! 32 bit pointer + add %i1,%l1,%l1 ! vTable[index * 4], l1 now points to vTable entry + ld [%l1 + 4],%l0 ! target address + +.L5: ld [%sp + 88],%o5 +.L4: ld [%sp + 84],%o4 +.L3: ld [%sp + 80],%o3 +.L2: ld [%sp + 76],%o2 +.L1: ld [%sp + 72],%o1 +.L0: + jmpl %l0,%o7 ! call the routine +! always have a 'this', from the incoming 'that' + mov %i0,%o0 + + mov %o0,%i0 ! propagate return value + ret + restore diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_sparc_linux_GCC3.s b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_sparc_linux_GCC3.s new file mode 100644 index 00000000..9a6b02ae --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_sparc_linux_GCC3.s @@ -0,0 +1,84 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * 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.org code. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * David S. Miller (ported to gcc3) + * + * 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. + */ + +/* + * Platform specific code to invoke XPCOM methods on native objects for + * Linux/Sparc with gcc 3 ABI. + */ + .global XPTC_InvokeByIndex +/* + * XPTC_InvokeByIndex(nsISupports* that, PRUint32 methodIndex, + * PRUint32 paramCount, nsXPTCVariant* params); + * + */ +XPTC_InvokeByIndex: + save %sp,-(64 + 16),%sp ! room for the register window and + ! struct pointer, rounded up to 0 % 16 + mov %i2,%o0 ! paramCount + call invoke_count_words ! returns the required stack size in %o0 + mov %i3,%o1 ! params + + sll %o0,2,%l0 ! number of bytes + sub %sp,%l0,%sp ! create the additional stack space + + mov %sp,%o0 ! pointer for copied args + add %o0,72,%o0 ! step past the register window, the + ! struct result pointer and the 'this' slot + mov %i2,%o1 ! paramCount + call invoke_copy_to_stack + mov %i3,%o2 ! params +! +! calculate the target address from the vtable +! + ld [%i0],%l1 ! *that --> vTable + sll %i1,2,%i1 ! multiply index by 4 + add %i1,%l1,%l1 ! l1 now points to vTable entry + ld [%l1],%l0 ! target address + +.L5: ld [%sp + 88],%o5 +.L4: ld [%sp + 84],%o4 +.L3: ld [%sp + 80],%o3 +.L2: ld [%sp + 76],%o2 +.L1: ld [%sp + 72],%o1 +.L0: + jmpl %l0,%o7 ! call the routine +! always have a 'this', from the incoming 'that' + mov %i0,%o0 + + mov %o0,%i0 ! propagate return value + ret + restore diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_sparc_netbsd.s b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_sparc_netbsd.s new file mode 100644 index 00000000..be0e34a7 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_sparc_netbsd.s @@ -0,0 +1,71 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * The contents of this file are subject to the Netscape 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/NPL/ + * + * 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.org code. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + */ + +/* Platform specific code to invoke XPCOM methods on native objects */ + .global XPTC_InvokeByIndex +/* + XPTC_InvokeByIndex(nsISupports* that, PRUint32 methodIndex, + PRUint32 paramCount, nsXPTCVariant* params); + +*/ +XPTC_InvokeByIndex: + save %sp,-(64 + 16),%sp ! room for the register window and + ! struct pointer, rounded up to 0 % 16 + mov %i2,%o0 ! paramCount + call invoke_count_words ! returns the required stack size in %o0 + mov %i3,%o1 ! params + + sll %o0,2,%l0 ! number of bytes + sub %sp,%l0,%sp ! create the additional stack space + + mov %sp,%o0 ! pointer for copied args + add %o0,72,%o0 ! step past the register window, the + ! struct result pointer and the 'this' slot + mov %i2,%o1 ! paramCount + call invoke_copy_to_stack + mov %i3,%o2 ! params +! +! calculate the target address from the vtable +! + add %i1,1,%i1 ! vTable is zero-based, index is 1 based (?) + ld [%i0],%l1 ! *that --> vTable + sll %i1,3,%i1 + add %i1,%l1,%l1 ! vTable[index * 8], l1 now points to vTable entry + lduh [%l1],%l0 ! this adjustor + sll %l0,16,%l0 ! sign extend to 32 bits + sra %l0,16,%l0 + add %l0,%i0,%i0 ! adjust this + ld [%l1 + 4],%l0 ! target address + +.L5: ld [%sp + 88],%o5 +.L4: ld [%sp + 84],%o4 +.L3: ld [%sp + 80],%o3 +.L2: ld [%sp + 76],%o2 +.L1: ld [%sp + 72],%o1 +.L0: + jmpl %l0,%o7 ! call the routine +! always have a 'this', from the incoming 'that' + mov %i0,%o0 + + mov %o0,%i0 ! propagate return value + ret + restore diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_sparc_solaris.s b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_sparc_solaris.s new file mode 100644 index 00000000..be0e34a7 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_sparc_solaris.s @@ -0,0 +1,71 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * The contents of this file are subject to the Netscape 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/NPL/ + * + * 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.org code. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + */ + +/* Platform specific code to invoke XPCOM methods on native objects */ + .global XPTC_InvokeByIndex +/* + XPTC_InvokeByIndex(nsISupports* that, PRUint32 methodIndex, + PRUint32 paramCount, nsXPTCVariant* params); + +*/ +XPTC_InvokeByIndex: + save %sp,-(64 + 16),%sp ! room for the register window and + ! struct pointer, rounded up to 0 % 16 + mov %i2,%o0 ! paramCount + call invoke_count_words ! returns the required stack size in %o0 + mov %i3,%o1 ! params + + sll %o0,2,%l0 ! number of bytes + sub %sp,%l0,%sp ! create the additional stack space + + mov %sp,%o0 ! pointer for copied args + add %o0,72,%o0 ! step past the register window, the + ! struct result pointer and the 'this' slot + mov %i2,%o1 ! paramCount + call invoke_copy_to_stack + mov %i3,%o2 ! params +! +! calculate the target address from the vtable +! + add %i1,1,%i1 ! vTable is zero-based, index is 1 based (?) + ld [%i0],%l1 ! *that --> vTable + sll %i1,3,%i1 + add %i1,%l1,%l1 ! vTable[index * 8], l1 now points to vTable entry + lduh [%l1],%l0 ! this adjustor + sll %l0,16,%l0 ! sign extend to 32 bits + sra %l0,16,%l0 + add %l0,%i0,%i0 ! adjust this + ld [%l1 + 4],%l0 ! target address + +.L5: ld [%sp + 88],%o5 +.L4: ld [%sp + 84],%o4 +.L3: ld [%sp + 80],%o3 +.L2: ld [%sp + 76],%o2 +.L1: ld [%sp + 72],%o1 +.L0: + jmpl %l0,%o7 ! call the routine +! always have a 'this', from the incoming 'that' + mov %i0,%o0 + + mov %o0,%i0 ! propagate return value + ret + restore diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_sparc_solaris_GCC.s b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_sparc_solaris_GCC.s new file mode 100644 index 00000000..203e3f1c --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_sparc_solaris_GCC.s @@ -0,0 +1,71 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * The contents of this file are subject to the Netscape 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/NPL/ + * + * 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.org code. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + */ + +/* Platform specific code to invoke XPCOM methods on native objects */ + .global XPTC_InvokeByIndex +/* + XPTC_InvokeByIndex(nsISupports* that, PRUint32 methodIndex, + PRUint32 paramCount, nsXPTCVariant* params); + +*/ +XPTC_InvokeByIndex: + save %sp,-(64 + 32),%sp ! room for the register window and + ! struct pointer, rounded up to 0 % 32 + mov %i2,%o0 ! paramCount + call invoke_count_words ! returns the required stack size in %o0 + mov %i3,%o1 ! params + + sll %o0,2,%l0 ! number of bytes + sub %sp,%l0,%sp ! create the additional stack space + + mov %sp,%o0 ! pointer for copied args + add %o0,72,%o0 ! step past the register window, the + ! struct result pointer and the 'this' slot + mov %i2,%o1 ! paramCount + call invoke_copy_to_stack + mov %i3,%o2 ! params +! +! calculate the target address from the vtable +! + add %i1,1,%i1 ! vTable is zero-based, index is 1 based (?) + ld [%i0],%l1 ! *that --> vTable + sll %i1,3,%i1 + add %i1,%l1,%l1 ! vTable[index * 8], l1 now points to vTable entry + lduh [%l1],%l0 ! this adjustor + sll %l0,16,%l0 ! sign extend to 32 bits + sra %l0,16,%l0 + add %l0,%i0,%i0 ! adjust this + ld [%l1 + 4],%l0 ! target address + +.L5: ld [%sp + 88],%o5 +.L4: ld [%sp + 84],%o4 +.L3: ld [%sp + 80],%o3 +.L2: ld [%sp + 76],%o2 +.L1: ld [%sp + 72],%o1 +.L0: + jmpl %l0,%o7 ! call the routine +! always have a 'this', from the incoming 'that' + mov %i0,%o0 + + mov %o0,%i0 ! propagate return value + ret + restore diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_sparc_solaris_GCC3.s b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_sparc_solaris_GCC3.s new file mode 100644 index 00000000..6a2e9606 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_sparc_solaris_GCC3.s @@ -0,0 +1,70 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * The contents of this file are subject to the Netscape 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/NPL/ + * + * 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.org code. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * David Baron (ported to + * gcc 3/sparc-sun-solaris from gcc 2.x/sparc-sun-solaris) + */ + +/* + * Platform specific code to invoke XPCOM methods on native objects for + * solaris/sparc with gcc 3 ABI. + */ + .global XPTC_InvokeByIndex +/* + * XPTC_InvokeByIndex(nsISupports* that, PRUint32 methodIndex, + * PRUint32 paramCount, nsXPTCVariant* params); + */ +XPTC_InvokeByIndex: + save %sp,-(64 + 32),%sp ! room for the register window and + ! struct pointer, rounded up to 0 % 32 + mov %i2,%o0 ! paramCount + call invoke_count_words ! returns the required stack size in %o0 + mov %i3,%o1 ! params + + sll %o0,2,%l0 ! number of bytes + sub %sp,%l0,%sp ! create the additional stack space + + mov %sp,%o0 ! pointer for copied args + add %o0,72,%o0 ! step past the register window, the + ! struct result pointer and the 'this' slot + mov %i2,%o1 ! paramCount + call invoke_copy_to_stack + mov %i3,%o2 ! params +! +! calculate the target address from the vtable +! + ld [%i0],%l1 ! *that --> vTable + sll %i1,2,%i1 ! multiply index by 4 + add %i1,%l1,%l1 ! l1 now points to vTable entry + ld [%l1],%l0 ! target address + +.L5: ld [%sp + 88],%o5 +.L4: ld [%sp + 84],%o4 +.L3: ld [%sp + 80],%o3 +.L2: ld [%sp + 76],%o2 +.L1: ld [%sp + 72],%o1 +.L0: + jmpl %l0,%o7 ! call the routine +! always have a 'this', from the incoming 'that' + mov %i0,%o0 + + mov %o0,%i0 ! propagate return value + ret + restore diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_sparc_solaris_SUNW.s b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_sparc_solaris_SUNW.s new file mode 100644 index 00000000..b70f1b46 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_sparc_solaris_SUNW.s @@ -0,0 +1,72 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * The contents of this file are subject to the Netscape 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/NPL/ + * + * 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.org code. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + */ + +/* Platform specific code to invoke XPCOM methods on native objects */ + + .global XPTC_InvokeByIndex + .type XPTC_InvokeByIndex, #function +/* + XPTC_InvokeByIndex(nsISupports* that, PRUint32 methodIndex, + PRUint32 paramCount, nsXPTCVariant* params); + +*/ +XPTC_InvokeByIndex: + save %sp,-(64 + 32),%sp ! room for the register window and + ! struct pointer, rounded up to 0 % 32 + sll %i2,3,%l0 ! assume the worst case + ! paramCount * 2 * 4 bytes + cmp %l0, 0 ! are there any args? If not, + be .invoke ! no need to copy args to stack + + sub %sp,%l0,%sp ! create the additional stack space + add %sp,72,%o0 ! step past the register window, the + ! struct result pointer and the 'this' slot + mov %i2,%o1 ! paramCount + call invoke_copy_to_stack + mov %i3,%o2 ! params + +! +! load arguments from stack into the outgoing registers +! + ld [%sp + 72],%o1 + ld [%sp + 76],%o2 + ld [%sp + 80],%o3 + ld [%sp + 84],%o4 + ld [%sp + 88],%o5 + +! +! calculate the target address from the vtable +! +.invoke: + sll %i1,2,%l0 ! index *= 4 + add %l0,8,%l0 ! there are 2 extra entries in the vTable + ld [%i0],%l1 ! *that --> address of vtable + ld [%l0 + %l1],%l0 ! that->vtable[index * 4 + 8] --> address + + jmpl %l0,%o7 ! call the routine + mov %i0,%o0 ! move 'this' pointer to out register + + mov %o0,%i0 ! propagate return value + ret + restore + + .size XPTC_InvokeByIndex, .-XPTC_InvokeByIndex diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_sparcv9_solaris_SUNW.s b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_sparcv9_solaris_SUNW.s new file mode 100644 index 00000000..232ed6bd --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_sparcv9_solaris_SUNW.s @@ -0,0 +1,103 @@ +/* -*- Mode: asm; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * 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.org code. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 2001 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * Stuart Parmenter + * Chris Seawood + */ + +/* + Platform specific code to invoke XPCOM methods on native objects + for sparcv9 Solaris. + + See the SPARC Compliance Definition (SCD) Chapter 3 + for more information about what is going on here, including + the use of BIAS (0x7ff). + The SCD is available from http://www.sparc.com/. +*/ + + .global XPTC_InvokeByIndex + .type XPTC_InvokeByIndex, #function + +/* + XPTC_InvokeByIndex(nsISupports* that, PRUint32 methodIndex, + PRUint32 paramCount, nsXPTCVariant* params); + +*/ +XPTC_InvokeByIndex: + save %sp,-(128 + 64),%sp ! room for the register window and + ! struct pointer, rounded up to 0 % 64 + sll %i2,4,%l0 ! assume the worst case + ! paramCount * 2 * 8 bytes + cmp %l0, 0 ! are there any args? If not, + be .invoke ! no need to copy args to stack + + sub %sp,%l0,%sp ! create the additional stack space + add %sp,0x7ff+136,%o0 ! step past the register window, the + ! struct result pointer and the 'this' slot + mov %i2,%o1 ! paramCount + call invoke_copy_to_stack + mov %i3,%o2 ! params + +! +! load arguments from stack into the outgoing registers +! BIAS is 0x7ff (2047) +! + +! load the %o1..5 64bit (extended word) output registers registers + ldx [%sp + 0x7ff + 136],%o1 ! %i1 + ldx [%sp + 0x7ff + 144],%o2 ! %i2 + ldx [%sp + 0x7ff + 152],%o3 ! %i3 + ldx [%sp + 0x7ff + 160],%o4 ! %i4 + ldx [%sp + 0x7ff + 168],%o5 ! %i5 + +! load the even number double registers starting with %d2 + ldd [%sp + 0x7ff + 136],%d2 + ldd [%sp + 0x7ff + 144],%d4 + ldd [%sp + 0x7ff + 152],%d6 + ldd [%sp + 0x7ff + 160],%d8 + ldd [%sp + 0x7ff + 168],%d10 + ldd [%sp + 0x7ff + 176],%d12 + ldd [%sp + 0x7ff + 184],%d14 + ldd [%sp + 0x7ff + 192],%d16 + ldd [%sp + 0x7ff + 200],%d18 + ldd [%sp + 0x7ff + 208],%d20 + ldd [%sp + 0x7ff + 216],%d22 + ldd [%sp + 0x7ff + 224],%d24 + ldd [%sp + 0x7ff + 232],%d26 + ldd [%sp + 0x7ff + 240],%d28 + ldd [%sp + 0x7ff + 248],%d30 + +! +! calculate the target address from the vtable +! +.invoke: + sll %i1,3,%l0 ! index *= 8 + add %l0,16,%l0 ! there are 2 extra entries in the vTable (16bytes) + ldx [%i0],%l1 ! *that --> address of vtable + ldx [%l0 + %l1],%l0 ! that->vtable[index * 8 + 16] --> address + + jmpl %l0,%o7 ! call the routine + mov %i0,%o0 ! move 'this' pointer to out register + + mov %o0,%i0 ! propagate return value + ret + restore + + .size XPTC_InvokeByIndex, .-XPTC_InvokeByIndex diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_gcc_x86_unix.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_gcc_x86_unix.cpp new file mode 100644 index 00000000..79b17ae3 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_gcc_x86_unix.cpp @@ -0,0 +1,215 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Platform specific code to invoke XPCOM methods on native objects */ + +#ifdef __GNUC__ /* Gnu compiler. */ + +#include "xptcprivate.h" +#include "xptc_platforms_unixish_x86.h" +#include "xptc_gcc_x86_unix.h" + +extern "C" { +#ifndef XP_WIN32 +static +#endif +void ATTRIBUTE_USED __attribute__ ((regparm(3))) +invoke_copy_to_stack(PRUint32 paramCount, nsXPTCVariant* s, PRUint32* d) +{ + for(PRUint32 i = paramCount; i >0; i--, d++, s++) + { + if(s->IsPtrData()) + { + *((void**)d) = s->ptr; + continue; + } + + switch(s->type) + { + case nsXPTType::T_I64 : *((PRInt64*) d) = s->val.i64; d++; break; + case nsXPTType::T_U64 : *((PRUint64*)d) = s->val.u64; d++; break; + case nsXPTType::T_DOUBLE : *((double*) d) = s->val.d; d++; break; + default : *((void**)d) = s->val.p; break; + } + } +} +} // extern "C" + +// NOTE! See xptc_gcc_x86_unix.h for the reason why this function exists. +#if (__GNUC__ < 3 || (__GNUC__ == 3 && __GNUC_MINOR__ == 0)) +PRUint32 +xptc_invoke_copy_to_stack_keeper (void) +{ + PRUint32 dummy1; + void ATTRIBUTE_USED __attribute__ ((regparm(3))) (*dummy2) + (PRUint32, nsXPTCVariant*, PRUint32*) = invoke_copy_to_stack; + +// dummy2 references invoke_copy_to_stack, now we have to "use" it + __asm__ __volatile__ ( + "" + : "=&a" (dummy1) + : "g" (dummy2) + ); + + return dummy1 & 0xF0F00000; +} +#endif + + +/* + XPTC_PUBLIC_API(nsresult) + XPTC_InvokeByIndex(nsISupports* that, PRUint32 methodIndex, + PRUint32 paramCount, nsXPTCVariant* params); + + Each param takes at most two 4-byte words. + It doesn't matter if we push too many words, and calculating the exact + amount takes time. + + that = ebp + 0x08 + methodIndex = ebp + 0x0c + paramCount = ebp + 0x10 + params = ebp + 0x14 + + NOTE NOTE NOTE: + As of 2002-04-29 this function references no global variables nor does + it call non-static functions so preserving and loading the PIC register + is unnecessary. Define MOZ_PRESERVE_PIC if this changes. See mozilla + bug 140412 for details. However, avoid this if you can. It's slower. +*/ +/* + * Hack for gcc for win32. Functions used externally must be + * explicitly dllexported. + * Bug 226609 + */ +#ifdef XP_WIN32 +extern "C" { + nsresult _XPTC_InvokeByIndex(nsISupports* that, PRUint32 methodIndex, + PRUint32 paramCount, nsXPTCVariant* params); + XPTC_PUBLIC_API(nsresult) + XPTC_InvokeByIndex(nsISupports* that, PRUint32 methodIndex, + PRUint32 paramCount, nsXPTCVariant* params) { + return _XPTC_InvokeByIndex(that, methodIndex, paramCount, params); + } +} +#endif + +__asm__ ( + ".text\n\t" +/* alignment here seems unimportant here; this was 16, now it's 2 which + is what xptcstubs uses. */ + ".align 2\n\t" +#ifdef XP_WIN32 + ".globl " SYMBOL_UNDERSCORE "_XPTC_InvokeByIndex\n\t" + ".type " SYMBOL_UNDERSCORE "_XPTC_InvokeByIndex,@function\n" + SYMBOL_UNDERSCORE "_XPTC_InvokeByIndex:\n\t" +#else +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP + ".globl " SYMBOL_UNDERSCORE "VBoxNsxpXPTC_InvokeByIndex\n\t" + ".type " SYMBOL_UNDERSCORE "VBoxNsxpXPTC_InvokeByIndex,@function\n" + SYMBOL_UNDERSCORE "VBoxNsxpXPTC_InvokeByIndex:\n\t" +#else + ".globl " SYMBOL_UNDERSCORE "XPTC_InvokeByIndex\n\t" + ".type " SYMBOL_UNDERSCORE "XPTC_InvokeByIndex,@function\n" + SYMBOL_UNDERSCORE "XPTC_InvokeByIndex:\n\t" +#endif +#endif + "pushl %ebp\n\t" + "movl %esp, %ebp\n\t" +#ifdef MOZ_PRESERVE_PIC + "pushl %ebx\n\t" + "call 0f\n\t" + ".subsection 1\n" + "0:\n\t" + "movl (%esp), %ebx\n\t" + "ret\n\t" + ".previous\n\t" + "addl $_GLOBAL_OFFSET_TABLE_, %ebx\n\t" +#endif + "movl 0x10(%ebp), %eax\n\t" + "leal 0(,%eax,8),%edx\n\t" + "movl %esp, %ecx\n\t" + "subl %edx, %ecx\n\t" +/* Since there may be 64-bit data, it occurs to me that aligning this + space might be a performance gain. However, I don't think the rest + of mozilla worries about such things. In any event, do it here. + "andl $0xfffffff8, %ecx\n\t" + */ + "movl %ecx, %esp\n\t" /* make stack space */ + "movl 0x14(%ebp), %edx\n\t" + "call " SYMBOL_UNDERSCORE "invoke_copy_to_stack\n\t" + "movl 0x08(%ebp), %ecx\n\t" /* 'that' */ +#ifdef CFRONT_STYLE_THIS_ADJUST + "movl (%ecx), %edx\n\t" + "movl 0x0c(%ebp), %eax\n\t" /* function index */ + "shll $3, %eax\n\t" /* *= 8 */ + "addl $8, %eax\n\t" /* += 8 skip first entry */ + "addl %eax, %edx\n\t" + "movswl (%edx), %eax\n\t" /* 'this' offset */ + "addl %eax, %ecx\n\t" + "pushl %ecx\n\t" + "addl $4, %edx\n\t" /* += 4, method pointer */ +#else /* THUNK_BASED_THIS_ADJUST */ + "pushl %ecx\n\t" + "movl (%ecx), %edx\n\t" + "movl 0x0c(%ebp), %eax\n\t" /* function index */ +#if defined(__GXX_ABI_VERSION) && __GXX_ABI_VERSION >= 100 /* G++ V3 ABI */ + "leal (%edx,%eax,4), %edx\n\t" +#else /* not G++ V3 ABI */ + "leal 8(%edx,%eax,4), %edx\n\t" +#endif /* G++ V3 ABI */ +#endif + "call *(%edx)\n\t" +#ifdef MOZ_PRESERVE_PIC + "movl -4(%ebp), %ebx\n\t" +#endif + "movl %ebp, %esp\n\t" + "popl %ebp\n\t" + "ret\n" +#ifdef XP_WIN32 + ".size " SYMBOL_UNDERSCORE "_XPTC_InvokeByIndex, . -" SYMBOL_UNDERSCORE "_XPTC_InvokeByIndex\n\t" +#else +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP + ".size " SYMBOL_UNDERSCORE "VBoxNsxpXPTC_InvokeByIndex, . -" SYMBOL_UNDERSCORE "VBoxNsxpXPTC_InvokeByIndex\n\t" +#else + ".size " SYMBOL_UNDERSCORE "XPTC_InvokeByIndex, . -" SYMBOL_UNDERSCORE "XPTC_InvokeByIndex\n\t" +#endif +#endif +); + +#else +#error "can't find a compiler to use" +#endif /* __GNUC__ */ diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_ipf32.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_ipf32.cpp new file mode 100644 index 00000000..5a959317 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_ipf32.cpp @@ -0,0 +1,164 @@ + +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "xptcprivate.h" + +#include + +// "This code is for IA64 only" + + +/* invoke_copy_to_stack() will copy from variant array 's' to + * the stack argument area 'mloc', the integer register area 'iloc', and + * the float register area 'floc'. + * + */ +extern "C" void +invoke_copy_to_stack(uint64_t* mloc, uint64_t* iloc, uint64_t* floc, + const PRUint32 paramCount, nsXPTCVariant* s) +{ + uint64_t* dest = mloc; + PRUint32 len = paramCount; + nsXPTCVariant* source = s; + + PRUint32 indx; + PRUint32 endlen; + endlen = (len > 7) ? 7 : len; + /* handle the memory arguments */ + for (indx = 7; indx < len; ++indx) + { + if (source[indx].IsPtrData()) + { +#ifdef __LP64__ + /* 64 bit pointer mode */ + *((void**) dest) = source[indx].ptr; +#else + /* 32 bit pointer mode */ + uint32_t* adr = (uint32_t*) dest; + *(adr) = 0; + *(adr+1) = (uint32_t) source[indx].ptr; +#endif + } + else + switch (source[indx].type) + { + case nsXPTType::T_I8 : *(dest) = source[indx].val.i8; break; + case nsXPTType::T_I16 : *(dest) = source[indx].val.i16; break; + case nsXPTType::T_I32 : *(dest) = source[indx].val.i32; break; + case nsXPTType::T_I64 : *(dest) = source[indx].val.i64; break; + case nsXPTType::T_U8 : *(dest) = source[indx].val.u8; break; + case nsXPTType::T_U16 : *(dest) = source[indx].val.u16; break; + case nsXPTType::T_U32 : *(dest) = source[indx].val.u32; break; + case nsXPTType::T_U64 : *(dest) = source[indx].val.u64; break; + case nsXPTType::T_FLOAT : *(dest) = source[indx].val.u32; break; + case nsXPTType::T_DOUBLE: *(dest) = source[indx].val.u64; break; + case nsXPTType::T_BOOL : *(dest) = source[indx].val.b; break; + case nsXPTType::T_CHAR : *(dest) = source[indx].val.c; break; + case nsXPTType::T_WCHAR : *(dest) = source[indx].val.wc; break; + default: + // all the others are plain pointer types +#ifdef __LP64__ + /* 64 bit pointer mode */ + *((void**) dest) = source[indx].val.p; +#else + { + /* 32 bit pointer mode */ + uint32_t* adr = (uint32_t*) dest; + *(adr) = 0; + *(adr+1) = (uint32_t) source[indx].val.p; + } +#endif + } + ++dest; + } + /* process register arguments */ + dest = iloc; + for (indx = 0; indx < endlen; ++indx) + { + if (source[indx].IsPtrData()) + { +#ifdef __LP64__ + /* 64 bit pointer mode */ + *((void**) dest) = source[indx].ptr; +#else + /* 32 bit pointer mode */ + uint32_t* adr = (uint32_t*) dest; + *(adr) = 0; + *(adr+1) = (uint32_t) source[indx].ptr; +#endif + } + else + switch (source[indx].type) + { + case nsXPTType::T_I8 : *(dest) = source[indx].val.i8; break; + case nsXPTType::T_I16 : *(dest) = source[indx].val.i16; break; + case nsXPTType::T_I32 : *(dest) = source[indx].val.i32; break; + case nsXPTType::T_I64 : *(dest) = source[indx].val.i64; break; + case nsXPTType::T_U8 : *(dest) = source[indx].val.u8; break; + case nsXPTType::T_U16 : *(dest) = source[indx].val.u16; break; + case nsXPTType::T_U32 : *(dest) = source[indx].val.u32; break; + case nsXPTType::T_U64 : *(dest) = source[indx].val.u64; break; + case nsXPTType::T_FLOAT : + *((double*) (floc++)) = (double) source[indx].val.f; + break; + case nsXPTType::T_DOUBLE: + *((double*) (floc++)) = source[indx].val.d; + break; + case nsXPTType::T_BOOL : *(dest) = source[indx].val.b; break; + case nsXPTType::T_CHAR : *(dest) = source[indx].val.c; break; + case nsXPTType::T_WCHAR : *(dest) = source[indx].val.wc; break; + default: + // all the others are plain pointer types +#ifdef __LP64__ + /* 64 bit pointer mode */ + *((void**) dest) = source[indx].val.p; +#else + { + /* 32 bit pointer mode */ + uint32_t* adr = (uint32_t*) dest; + *(adr) = 0; + *(adr+1) = (uint32_t) source[indx].val.p; + } +#endif + } + ++dest; + } + +} + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_ipf64.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_ipf64.cpp new file mode 100644 index 00000000..356c2c7b --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_ipf64.cpp @@ -0,0 +1,133 @@ + +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "xptcprivate.h" + +#include +#include + +// "This code is for IA64 only" + + +/* invoke_copy_to_stack() will copy from variant array 's' to + * the stack argument area 'mloc', the integer register area 'iloc', and + * the float register area 'floc'. + * + */ +extern "C" void +invoke_copy_to_stack(uint64_t* mloc, uint64_t* iloc, uint64_t* floc, + const PRUint32 paramCount, nsXPTCVariant* s) +{ + uint64_t* dest = mloc; + PRUint32 len = paramCount; + nsXPTCVariant* source = s; + + PRUint32 indx; + PRUint32 endlen; + endlen = (len > 7) ? 7 : len; + /* handle the memory arguments */ + for (indx = 7; indx < len; ++indx) + { + if (source[indx].IsPtrData()) + { + /* 64 bit pointer mode */ + *((void**) dest) = source[indx].ptr; + } + else + switch (source[indx].type) + { + case nsXPTType::T_I8 : *(dest) = source[indx].val.i8; break; + case nsXPTType::T_I16 : *(dest) = source[indx].val.i16; break; + case nsXPTType::T_I32 : *(dest) = source[indx].val.i32; break; + case nsXPTType::T_I64 : *(dest) = source[indx].val.i64; break; + case nsXPTType::T_U8 : *(dest) = source[indx].val.u8; break; + case nsXPTType::T_U16 : *(dest) = source[indx].val.u16; break; + case nsXPTType::T_U32 : *(dest) = source[indx].val.u32; break; + case nsXPTType::T_U64 : *(dest) = source[indx].val.u64; break; + case nsXPTType::T_FLOAT : *(dest) = source[indx].val.u32; break; + case nsXPTType::T_DOUBLE: *(dest) = source[indx].val.u64; break; + case nsXPTType::T_BOOL : *(dest) = source[indx].val.b; break; + case nsXPTType::T_CHAR : *(dest) = source[indx].val.c; break; + case nsXPTType::T_WCHAR : *(dest) = source[indx].val.wc; break; + default: + // all the others are plain pointer types + /* 64 bit pointer mode */ + *((void**) dest) = source[indx].val.p; + } + ++dest; + } + /* process register arguments */ + dest = iloc; + for (indx = 0; indx < endlen; ++indx) + { + if (source[indx].IsPtrData()) + { + /* 64 bit pointer mode */ + *((void**) dest) = source[indx].ptr; + } + else + switch (source[indx].type) + { + case nsXPTType::T_I8 : *(dest) = source[indx].val.i8; break; + case nsXPTType::T_I16 : *(dest) = source[indx].val.i16; break; + case nsXPTType::T_I32 : *(dest) = source[indx].val.i32; break; + case nsXPTType::T_I64 : *(dest) = source[indx].val.i64; break; + case nsXPTType::T_U8 : *(dest) = source[indx].val.u8; break; + case nsXPTType::T_U16 : *(dest) = source[indx].val.u16; break; + case nsXPTType::T_U32 : *(dest) = source[indx].val.u32; break; + case nsXPTType::T_U64 : *(dest) = source[indx].val.u64; break; + case nsXPTType::T_FLOAT : + *((double*) (floc++)) = (double) source[indx].val.f; + break; + case nsXPTType::T_DOUBLE: + *((double*) (floc++)) = source[indx].val.d; + break; + case nsXPTType::T_BOOL : *(dest) = source[indx].val.b; break; + case nsXPTType::T_CHAR : *(dest) = source[indx].val.c; break; + case nsXPTType::T_WCHAR : *(dest) = source[indx].val.wc; break; + default: + // all the others are plain pointer types + /* 64 bit pointer mode */ + *((void**) dest) = source[indx].val.p; + } + ++dest; + } + +} + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_irix.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_irix.cpp new file mode 100644 index 00000000..67aa6144 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_irix.cpp @@ -0,0 +1,173 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Platform specific code to invoke XPCOM methods on native objects */ + +#include "xptcprivate.h" + +#if (_MIPS_SIM != _ABIN32) +#error "This code is for IRIX N32 only" +#endif + +extern "C" uint32 +invoke_count_words(PRUint32 paramCount, nsXPTCVariant* s) +{ + return(paramCount*2); +} + +extern "C" void +invoke_copy_to_stack(PRUint64* d, PRUint32 paramCount, + nsXPTCVariant* s, PRUint64 *regs) +{ +#define N_ARG_REGS 7 /* 8 regs minus 1 for "this" ptr */ + + for (PRUint32 i = 0; i < paramCount; i++, s++) + { + if (s->IsPtrData()) { + if (i < N_ARG_REGS) + regs[i] = (PRUint64)s->ptr; + else + *d++ = (PRUint64)s->ptr; + continue; + } + switch (s->type) { + // + // signed types first + // + case nsXPTType::T_I8: + if (i < N_ARG_REGS) + ((PRInt64*)regs)[i] = s->val.i8; + else + *d++ = s->val.i8; + break; + case nsXPTType::T_I16: + if (i < N_ARG_REGS) + ((PRInt64*)regs)[i] = s->val.i16; + else + *d++ = s->val.i16; + break; + case nsXPTType::T_I32: + if (i < N_ARG_REGS) + ((PRInt64*)regs)[i] = s->val.i32; + else + *d++ = s->val.i32; + break; + case nsXPTType::T_I64: + if (i < N_ARG_REGS) + ((PRInt64*)regs)[i] = s->val.i64; + else + *d++ = s->val.i64; + break; + // + // unsigned types next + // + case nsXPTType::T_U8: + if (i < N_ARG_REGS) + regs[i] = s->val.u8; + else + *d++ = s->val.u8; + break; + case nsXPTType::T_U16: + if (i < N_ARG_REGS) + regs[i] = s->val.u16; + else + *d++ = s->val.u16; + break; + case nsXPTType::T_U32: + if (i < N_ARG_REGS) + regs[i] = s->val.u32; + else + *d++ = s->val.u32; + break; + case nsXPTType::T_U64: + if (i < N_ARG_REGS) + regs[i] = s->val.u64; + else + *d++ = s->val.u64; + break; + case nsXPTType::T_FLOAT: + if (i < N_ARG_REGS) + // Place a float in least significant bytes. + *(float*)(((char*)®s[i+1]) - sizeof(float)) = s->val.f; + else + *(float*)d++ = s->val.f; + break; + case nsXPTType::T_DOUBLE: + if (i < N_ARG_REGS) + *(double*)®s[i] = s->val.d; + else + *(double*)d++ = s->val.d; + break; + case nsXPTType::T_BOOL: + if (i < N_ARG_REGS) + regs[i] = s->val.b; + else + *d++ = s->val.b; + break; + case nsXPTType::T_CHAR: + if (i < N_ARG_REGS) + regs[i] = s->val.c; + else + *d++ = s->val.c; + break; + case nsXPTType::T_WCHAR: + if (i < N_ARG_REGS) + regs[i] = s->val.wc; + else + *d++ = s->val.wc; + break; + default: + // all the others are plain pointer types + if (i < N_ARG_REGS) + regs[i] = (PRUint64)s->val.p; + else + *d++ = (PRUint64)s->val.p; + break; + } + } +} + +extern "C" nsresult _XPTC_InvokeByIndex(nsISupports* that, PRUint32 methodIndex, + PRUint32 paramCount, nsXPTCVariant* params); + +extern "C" +XPTC_PUBLIC_API(nsresult) +XPTC_InvokeByIndex(nsISupports* that, PRUint32 methodIndex, + PRUint32 paramCount, nsXPTCVariant* params) +{ + return _XPTC_InvokeByIndex(that, methodIndex, paramCount, params); +} diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_linux_alpha.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_linux_alpha.cpp new file mode 100644 index 00000000..7f7d84c3 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_linux_alpha.cpp @@ -0,0 +1,181 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Glen Nakamura + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Platform specific code to invoke XPCOM methods on native objects */ + +#include "xptcprivate.h" + +/* Prototype specifies unmangled function name and disables unused warning */ +static void +invoke_copy_to_stack(PRUint64* d, PRUint32 paramCount, nsXPTCVariant* s) +__asm__("invoke_copy_to_stack") __attribute__((unused)); + +static void +invoke_copy_to_stack(PRUint64* d, PRUint32 paramCount, nsXPTCVariant* s) +{ + const PRUint8 NUM_ARG_REGS = 6-1; // -1 for "this" pointer + + for(PRUint32 i = 0; i < paramCount; i++, d++, s++) + { + if(s->IsPtrData()) + { + *d = (PRUint64)s->ptr; + continue; + } + switch(s->type) + { + case nsXPTType::T_I8 : *d = (PRUint64)s->val.i8; break; + case nsXPTType::T_I16 : *d = (PRUint64)s->val.i16; break; + case nsXPTType::T_I32 : *d = (PRUint64)s->val.i32; break; + case nsXPTType::T_I64 : *d = (PRUint64)s->val.i64; break; + case nsXPTType::T_U8 : *d = (PRUint64)s->val.u8; break; + case nsXPTType::T_U16 : *d = (PRUint64)s->val.u16; break; + case nsXPTType::T_U32 : *d = (PRUint64)s->val.u32; break; + case nsXPTType::T_U64 : *d = (PRUint64)s->val.u64; break; + case nsXPTType::T_FLOAT : + if(i < NUM_ARG_REGS) + { + // convert floats to doubles if they are to be passed + // via registers so we can just deal with doubles later + union { PRUint64 u64; double d; } t; + t.d = (double)s->val.f; + *d = t.u64; + } + else + // otherwise copy to stack normally + *d = (PRUint64)s->val.u32; + break; + case nsXPTType::T_DOUBLE : *d = (PRUint64)s->val.u64; break; + case nsXPTType::T_BOOL : *d = (PRUint64)s->val.b; break; + case nsXPTType::T_CHAR : *d = (PRUint64)s->val.c; break; + case nsXPTType::T_WCHAR : *d = (PRUint64)s->val.wc; break; + default: + // all the others are plain pointer types + *d = (PRUint64)s->val.p; + break; + } + } +} + +/* + * XPTC_PUBLIC_API(nsresult) + * XPTC_InvokeByIndex(nsISupports* that, PRUint32 methodIndex, + * PRUint32 paramCount, nsXPTCVariant* params) + */ +__asm__( + "#### XPTC_InvokeByIndex ####\n" +".text\n\t" + ".align 5\n\t" + ".globl XPTC_InvokeByIndex\n\t" + ".ent XPTC_InvokeByIndex\n" +"XPTC_InvokeByIndex:\n\t" + ".frame $15,32,$26,0\n\t" + ".mask 0x4008000,-32\n\t" + "ldgp $29,0($27)\n" +"$XPTC_InvokeByIndex..ng:\n\t" + "subq $30,32,$30\n\t" + "stq $26,0($30)\n\t" + "stq $15,8($30)\n\t" + "bis $30,$30,$15\n\t" + ".prologue 1\n\t" + + /* + * Allocate enough stack space to hold the greater of 6 or "paramCount"+1 + * parameters. (+1 for "this" pointer) Room for at least 6 parameters + * is required for storage of those passed via registers. + */ + + "bis $31,5,$2\n\t" /* count = MAX(5, "paramCount") */ + "cmplt $2,$18,$1\n\t" + "cmovne $1,$18,$2\n\t" + "s8addq $2,16,$1\n\t" /* room for count+1 params (8 bytes each) */ + "bic $1,15,$1\n\t" /* stack space is rounded up to 0 % 16 */ + "subq $30,$1,$30\n\t" + + "stq $16,0($30)\n\t" /* save "that" (as "this" pointer) */ + "stq $17,16($15)\n\t" /* save "methodIndex" */ + + "addq $30,8,$16\n\t" /* pass stack pointer */ + "bis $18,$18,$17\n\t" /* pass "paramCount" */ + "bis $19,$19,$18\n\t" /* pass "params" */ + "bsr $26,$invoke_copy_to_stack..ng\n\t" /* call invoke_copy_to_stack */ + + /* + * Copy the first 6 parameters to registers and remove from stack frame. + * Both the integer and floating point registers are set for each parameter + * except the first which is the "this" pointer. (integer only) + * The floating point registers are all set as doubles since the + * invoke_copy_to_stack function should have converted the floats. + */ + "ldq $16,0($30)\n\t" /* integer registers */ + "ldq $17,8($30)\n\t" + "ldq $18,16($30)\n\t" + "ldq $19,24($30)\n\t" + "ldq $20,32($30)\n\t" + "ldq $21,40($30)\n\t" + "ldt $f17,8($30)\n\t" /* floating point registers */ + "ldt $f18,16($30)\n\t" + "ldt $f19,24($30)\n\t" + "ldt $f20,32($30)\n\t" + "ldt $f21,40($30)\n\t" + + "addq $30,48,$30\n\t" /* remove params from stack */ + + /* + * Call the virtual function with the constructed stack frame. + */ + "bis $16,$16,$1\n\t" /* load "this" */ + "ldq $2,16($15)\n\t" /* load "methodIndex" */ + "ldq $1,0($1)\n\t" /* load vtable */ +#if defined(__GXX_ABI_VERSION) && __GXX_ABI_VERSION >= 100 /* G++ V3 ABI */ + "s8addq $2,$31,$2\n\t" /* vtable index = "methodIndex" * 8 */ +#else /* not G++ V3 ABI */ + "s8addq $2,16,$2\n\t" /* vtable index = "methodIndex" * 8 + 16 */ +#endif /* G++ V3 ABI */ + "addq $1,$2,$1\n\t" + "ldq $27,0($1)\n\t" /* load address of function */ + "jsr $26,($27),0\n\t" /* call virtual function */ + "ldgp $29,0($26)\n\t" + + "bis $15,$15,$30\n\t" + "ldq $26,0($30)\n\t" + "ldq $15,8($30)\n\t" + "addq $30,32,$30\n\t" + "ret $31,($26),1\n\t" + ".end XPTC_InvokeByIndex" + ); diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_linux_m68k.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_linux_m68k.cpp new file mode 100644 index 00000000..363e45e0 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_linux_m68k.cpp @@ -0,0 +1,170 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Platform specific code to invoke XPCOM methods on native objects */ + +#include "xptcprivate.h" + +// Remember that these 'words' are 32bit DWORDS + +extern "C" { + static PRUint32 + invoke_count_words(PRUint32 paramCount, nsXPTCVariant* s) + { + PRUint32 result = 0; + for(PRUint32 i = 0; i < paramCount; i++, s++) + { + if(s->IsPtrData()) + { + result++; + continue; + } + switch(s->type) + { + case nsXPTType::T_I8 : + case nsXPTType::T_I16 : + case nsXPTType::T_I32 : + result++; + break; + case nsXPTType::T_I64 : + result+=2; + break; + case nsXPTType::T_U8 : + case nsXPTType::T_U16 : + case nsXPTType::T_U32 : + result++; + break; + case nsXPTType::T_U64 : + result+=2; + break; + case nsXPTType::T_FLOAT : + result++; + break; + case nsXPTType::T_DOUBLE : + result+=2; + break; + case nsXPTType::T_BOOL : + case nsXPTType::T_CHAR : + case nsXPTType::T_WCHAR : + result++; + break; + default: + // all the others are plain pointer types + result++; + break; + } + } + return result; + } + + void + invoke_copy_to_stack(PRUint32* d, PRUint32 paramCount, nsXPTCVariant* s) + { + for(PRUint32 i = 0; i < paramCount; i++, d++, s++) + { + if(s->IsPtrData()) + { + *((void**)d) = s->ptr; + continue; + } + switch(s->type) + { + // 8 and 16 bit types should be promoted to 32 bits when copying + // onto the stack. + case nsXPTType::T_I8 : *((PRUint32*)d) = s->val.i8; break; + case nsXPTType::T_I16 : *((PRUint32*)d) = s->val.i16; break; + case nsXPTType::T_I32 : *((PRInt32*) d) = s->val.i32; break; + case nsXPTType::T_I64 : *((PRInt64*) d) = s->val.i64; d++; break; + case nsXPTType::T_U8 : *((PRUint32*)d) = s->val.u8; break; + case nsXPTType::T_U16 : *((PRUint32*)d) = s->val.u16; break; + case nsXPTType::T_U32 : *((PRUint32*)d) = s->val.u32; break; + case nsXPTType::T_U64 : *((PRUint64*)d) = s->val.u64; d++; break; + case nsXPTType::T_FLOAT : *((float*) d) = s->val.f; break; + case nsXPTType::T_DOUBLE : *((double*) d) = s->val.d; d++; break; + case nsXPTType::T_BOOL : *((PRBool*) d) = s->val.b; break; + case nsXPTType::T_CHAR : *((PRUint32*)d) = s->val.c; break; + case nsXPTType::T_WCHAR : *((wchar_t*) d) = s->val.wc; break; + + default: + // all the others are plain pointer types + *((void**)d) = s->val.p; + break; + } + } + } +} + +XPTC_PUBLIC_API(nsresult) +XPTC_InvokeByIndex(nsISupports* that, PRUint32 methodIndex, + PRUint32 paramCount, nsXPTCVariant* params) +{ + PRUint32 result, n; + + n = invoke_count_words(paramCount, params) * 4; + + __asm__ __volatile__( + "subl %5, %/sp\n\t" /* make room for params */ + "movl %/sp, %/a0\n\t" + "movl %4, %/sp@-\n\t" + "movl %3, %/sp@-\n\t" + "movl %/a0, %/sp@-\n\t" + "jbsr invoke_copy_to_stack\n\t" /* copy params */ + "addl #12, %/sp\n\t" + "movl %1, %/a0\n\t" + "movl %/a0, %/sp@-\n\t" + "movl %/a0@, %/a0\n\t" + "movl %2, %/d0\n\t" /* function index */ +#if defined(__GXX_ABI_VERSION) && __GXX_ABI_VERSION >= 100 /* G++ V3 ABI */ + "movl %/a0@(%/d0:l:4), %/a0\n\t" +#else /* not V3 */ + "movl %/a0@(8,%/d0:l:4), %/a0\n\t" +#endif + "jbsr %/a0@\n\t" /* safe to not cleanup sp */ + "movl %/d0, %0\n\t" + "addql #4, %/sp\n\t" + "addl %5, %/sp" + : "=g" (result) /* %0 */ + : "g" (that), /* %1 */ + "g" (methodIndex), /* %2 */ + "g" (paramCount), /* %3 */ + "g" (params), /* %4 */ + "g" (n) /* %5 */ + : "a0", "a1", "d0", "d1", "memory" + ); + + return result; +} diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_linux_s390.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_linux_s390.cpp new file mode 100644 index 00000000..5da035ca --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_linux_s390.cpp @@ -0,0 +1,254 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Platform specific code to invoke XPCOM methods on native objects */ + +#include "xptcprivate.h" + + +static PRUint32 +invoke_count_words(PRUint32 paramCount, nsXPTCVariant* s) +{ + PRUint32 overflow = 0, gpr = 1 /*this*/, fpr = 0; + for(PRUint32 i = 0; i < paramCount; i++, s++) + { + if(s->IsPtrData()) + { + if (gpr < 5) gpr++; else overflow++; + continue; + } + switch(s->type) + { + case nsXPTType::T_I8 : + case nsXPTType::T_I16 : + case nsXPTType::T_I32 : + if (gpr < 5) gpr++; else overflow++; + break; + case nsXPTType::T_I64 : + if (gpr < 4) gpr+=2; else gpr=5, overflow+=2; + break; + case nsXPTType::T_U8 : + case nsXPTType::T_U16 : + case nsXPTType::T_U32 : + if (gpr < 5) gpr++; else overflow++; + break; + case nsXPTType::T_U64 : + if (gpr < 4) gpr+=2; else gpr=5, overflow+=2; + break; + case nsXPTType::T_FLOAT : + if (fpr < 2) fpr++; else overflow++; + break; + case nsXPTType::T_DOUBLE : + if (fpr < 2) fpr++; else overflow+=2; + break; + case nsXPTType::T_BOOL : + case nsXPTType::T_CHAR : + case nsXPTType::T_WCHAR : + if (gpr < 5) gpr++; else overflow++; + break; + default: + // all the others are plain pointer types + if (gpr < 5) gpr++; else overflow++; + break; + } + } + /* Round up number of overflow words to ensure stack + stays aligned to 8 bytes. */ + return (overflow + 1) & ~1; +} + +static void +invoke_copy_to_stack(PRUint32 paramCount, nsXPTCVariant* s, PRUint32* d_ov, PRUint32 overflow) +{ + PRUint32 *d_gpr = d_ov + overflow; + PRUint64 *d_fpr = (PRUint64 *)(d_gpr + 4); + PRUint32 gpr = 1 /*this*/, fpr = 0; + + for(PRUint32 i = 0; i < paramCount; i++, s++) + { + if(s->IsPtrData()) + { + if (gpr < 5) + *((void**)d_gpr) = s->ptr, d_gpr++, gpr++; + else + *((void**)d_ov ) = s->ptr, d_ov++; + continue; + } + switch(s->type) + { + case nsXPTType::T_I8 : + if (gpr < 5) + *((PRInt32*) d_gpr) = s->val.i8, d_gpr++, gpr++; + else + *((PRInt32*) d_ov ) = s->val.i8, d_ov++; + break; + case nsXPTType::T_I16 : + if (gpr < 5) + *((PRInt32*) d_gpr) = s->val.i16, d_gpr++, gpr++; + else + *((PRInt32*) d_ov ) = s->val.i16, d_ov++; + break; + case nsXPTType::T_I32 : + if (gpr < 5) + *((PRInt32*) d_gpr) = s->val.i32, d_gpr++, gpr++; + else + *((PRInt32*) d_ov ) = s->val.i32, d_ov++; + break; + case nsXPTType::T_I64 : + if (gpr < 4) + *((PRInt64*) d_gpr) = s->val.i64, d_gpr+=2, gpr+=2; + else + *((PRInt64*) d_ov ) = s->val.i64, d_ov+=2, gpr=5; + break; + case nsXPTType::T_U8 : + if (gpr < 5) + *((PRUint32*) d_gpr) = s->val.u8, d_gpr++, gpr++; + else + *((PRUint32*) d_ov ) = s->val.u8, d_ov++; + break; + case nsXPTType::T_U16 : + if (gpr < 5) + *((PRUint32*)d_gpr) = s->val.u16, d_gpr++, gpr++; + else + *((PRUint32*)d_ov ) = s->val.u16, d_ov++; + break; + case nsXPTType::T_U32 : + if (gpr < 5) + *((PRUint32*)d_gpr) = s->val.u32, d_gpr++, gpr++; + else + *((PRUint32*)d_ov ) = s->val.u32, d_ov++; + break; + case nsXPTType::T_U64 : + if (gpr < 4) + *((PRUint64*)d_gpr) = s->val.u64, d_gpr+=2, gpr+=2; + else + *((PRUint64*)d_ov ) = s->val.u64, d_ov+=2, gpr=5; + break; + case nsXPTType::T_FLOAT : + if (fpr < 2) + *((float*) d_fpr) = s->val.f, d_fpr++, fpr++; + else + *((float*) d_ov ) = s->val.f, d_ov++; + break; + case nsXPTType::T_DOUBLE : + if (fpr < 2) + *((double*) d_fpr) = s->val.d, d_fpr++, fpr++; + else + *((double*) d_ov ) = s->val.d, d_ov+=2; + break; + case nsXPTType::T_BOOL : + if (gpr < 5) + *((PRUint32*)d_gpr) = s->val.b, d_gpr++, gpr++; + else + *((PRUint32*)d_ov ) = s->val.b, d_ov++; + break; + case nsXPTType::T_CHAR : + if (gpr < 5) + *((PRUint32*)d_gpr) = s->val.c, d_gpr++, gpr++; + else + *((PRUint32*)d_ov ) = s->val.c, d_ov++; + break; + case nsXPTType::T_WCHAR : + if (gpr < 5) + *((PRUint32*)d_gpr) = s->val.wc, d_gpr++, gpr++; + else + *((PRUint32*)d_ov ) = s->val.wc, d_ov++; + break; + default: + // all the others are plain pointer types + if (gpr < 5) + *((void**) d_gpr) = s->val.p, d_gpr++, gpr++; + else + *((void**) d_ov ) = s->val.p, d_ov++; + break; + } + } +} + +XPTC_PUBLIC_API(nsresult) +XPTC_InvokeByIndex(nsISupports* that, PRUint32 methodIndex, + PRUint32 paramCount, nsXPTCVariant* params) +{ + PRUint32 *vtable = *(PRUint32 **)that; +#if defined(__GXX_ABI_VERSION) && __GXX_ABI_VERSION >= 100 /* G++ V3 ABI */ + PRUint32 method = vtable[methodIndex]; +#else /* not G++ V3 ABI */ + PRUint32 method = vtable[methodIndex + 2]; +#endif /* G++ V3 ABI */ + PRUint32 overflow = invoke_count_words (paramCount, params); + PRUint32 result; + + __asm__ __volatile__ + ( + "lr 7,15\n\t" + "ahi 7,-32\n\t" + + "lr 3,%3\n\t" + "sll 3,2\n\t" + "lcr 3,3\n\t" + "l 2,0(15)\n\t" + "la 15,0(3,7)\n\t" + "st 2,0(15)\n\t" + + "lr 2,%1\n\t" + "lr 3,%2\n\t" + "la 4,96(15)\n\t" + "lr 5,%3\n\t" + "basr 14,%4\n\t" + + "lr 2,%5\n\t" + "ld 0,112(7)\n\t" + "ld 2,120(7)\n\t" + "lm 3,6,96(7)\n\t" + "basr 14,%6\n\t" + + "la 15,32(7)\n\t" + + "lr %0,2\n\t" + : "=r" (result) + : "r" (paramCount), + "r" (params), + "r" (overflow), + "a" (invoke_copy_to_stack), + "a" (that), + "a" (method) + : "2", "3", "4", "5", "6", "7", "memory" + ); + + return result; +} diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_linux_s390x.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_linux_s390x.cpp new file mode 100644 index 00000000..5a4268b6 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_linux_s390x.cpp @@ -0,0 +1,250 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Platform specific code to invoke XPCOM methods on native objects */ + +#include "xptcprivate.h" + + +static PRUint32 +invoke_count_words(PRUint32 paramCount, nsXPTCVariant* s) +{ + PRUint32 overflow = 0, gpr = 1 /*this*/, fpr = 0; + for(PRUint32 i = 0; i < paramCount; i++, s++) + { + if(s->IsPtrData()) + { + if (gpr < 5) gpr++; else overflow++; + continue; + } + switch(s->type) + { + case nsXPTType::T_I8 : + case nsXPTType::T_I16 : + case nsXPTType::T_I32 : + case nsXPTType::T_I64 : + if (gpr < 5) gpr++; else overflow++; + break; + case nsXPTType::T_U8 : + case nsXPTType::T_U16 : + case nsXPTType::T_U32 : + case nsXPTType::T_U64 : + if (gpr < 5) gpr++; else overflow++; + break; + case nsXPTType::T_FLOAT : + case nsXPTType::T_DOUBLE : + if (fpr < 4) fpr++; else overflow++; + break; + case nsXPTType::T_BOOL : + case nsXPTType::T_CHAR : + case nsXPTType::T_WCHAR : + if (gpr < 5) gpr++; else overflow++; + break; + default: + // all the others are plain pointer types + if (gpr < 5) gpr++; else overflow++; + break; + } + } + /* Round up number of overflow words to ensure stack + stays aligned to 8 bytes. */ + return (overflow + 1) & ~1; +} + +static void +invoke_copy_to_stack(PRUint32 paramCount, nsXPTCVariant* s, PRUint64* d_ov, PRUint32 overflow) +{ + PRUint64 *d_gpr = d_ov + overflow; + PRUint64 *d_fpr = (PRUint64 *)(d_gpr + 4); + PRUint32 gpr = 1 /*this*/, fpr = 0; + + for(PRUint32 i = 0; i < paramCount; i++, s++) + { + if(s->IsPtrData()) + { + if (gpr < 5) + *((void**)d_gpr) = s->ptr, d_gpr++, gpr++; + else + *((void**)d_ov ) = s->ptr, d_ov++; + continue; + } + switch(s->type) + { + case nsXPTType::T_I8 : + if (gpr < 5) + *((PRInt64*) d_gpr) = s->val.i8, d_gpr++, gpr++; + else + *((PRInt64*) d_ov ) = s->val.i8, d_ov++; + break; + case nsXPTType::T_I16 : + if (gpr < 5) + *((PRInt64*) d_gpr) = s->val.i16, d_gpr++, gpr++; + else + *((PRInt64*) d_ov ) = s->val.i16, d_ov++; + break; + case nsXPTType::T_I32 : + if (gpr < 5) + *((PRInt64*) d_gpr) = s->val.i32, d_gpr++, gpr++; + else + *((PRInt64*) d_ov ) = s->val.i32, d_ov++; + break; + case nsXPTType::T_I64 : + if (gpr < 5) + *((PRInt64*) d_gpr) = s->val.i64, d_gpr++, gpr++; + else + *((PRInt64*) d_ov ) = s->val.i64, d_ov++; + break; + case nsXPTType::T_U8 : + if (gpr < 5) + *((PRUint64*) d_gpr) = s->val.u8, d_gpr++, gpr++; + else + *((PRUint64*) d_ov ) = s->val.u8, d_ov++; + break; + case nsXPTType::T_U16 : + if (gpr < 5) + *((PRUint64*)d_gpr) = s->val.u16, d_gpr++, gpr++; + else + *((PRUint64*)d_ov ) = s->val.u16, d_ov++; + break; + case nsXPTType::T_U32 : + if (gpr < 5) + *((PRUint64*)d_gpr) = s->val.u32, d_gpr++, gpr++; + else + *((PRUint64*)d_ov ) = s->val.u32, d_ov++; + break; + case nsXPTType::T_U64 : + if (gpr < 5) + *((PRUint64*)d_gpr) = s->val.u64, d_gpr++, gpr++; + else + *((PRUint64*)d_ov ) = s->val.u64, d_ov++; + break; + case nsXPTType::T_FLOAT : + if (fpr < 4) + *((float*) d_fpr) = s->val.f, d_fpr++, fpr++; + else + *(((float*) d_ov )+1) = s->val.f, d_ov++; + break; + case nsXPTType::T_DOUBLE : + if (fpr < 4) + *((double*) d_fpr) = s->val.d, d_fpr++, fpr++; + else + *((double*) d_ov ) = s->val.d, d_ov++; + break; + case nsXPTType::T_BOOL : + if (gpr < 5) + *((PRUint64*)d_gpr) = s->val.b, d_gpr++, gpr++; + else + *((PRUint64*)d_ov ) = s->val.b, d_ov++; + break; + case nsXPTType::T_CHAR : + if (gpr < 5) + *((PRUint64*)d_gpr) = s->val.c, d_gpr++, gpr++; + else + *((PRUint64*)d_ov ) = s->val.c, d_ov++; + break; + case nsXPTType::T_WCHAR : + if (gpr < 5) + *((PRUint64*)d_gpr) = s->val.wc, d_gpr++, gpr++; + else + *((PRUint64*)d_ov ) = s->val.wc, d_ov++; + break; + default: + // all the others are plain pointer types + if (gpr < 5) + *((void**) d_gpr) = s->val.p, d_gpr++, gpr++; + else + *((void**) d_ov ) = s->val.p, d_ov++; + break; + } + } +} + +XPTC_PUBLIC_API(nsresult) +XPTC_InvokeByIndex(nsISupports* that, PRUint32 methodIndex, + PRUint32 paramCount, nsXPTCVariant* params) +{ + PRUint64 *vtable = *(PRUint64 **)that; +#if defined(__GXX_ABI_VERSION) && __GXX_ABI_VERSION >= 100 /* G++ V3 ABI */ + PRUint64 method = vtable[methodIndex]; +#else /* not G++ V3 ABI */ + PRUint64 method = vtable[methodIndex + 2]; +#endif /* G++ V3 ABI */ + PRUint64 overflow = invoke_count_words (paramCount, params); + PRUint64 result; + + __asm__ __volatile__ + ( + "lgr 7,15\n\t" + "aghi 7,-64\n\t" + + "lgr 3,%3\n\t" + "sllg 3,3,3\n\t" + "lcgr 3,3\n\t" + "lg 2,0(15)\n\t" + "la 15,0(3,7)\n\t" + "stg 2,0(15)\n\t" + + "lgr 2,%1\n\t" + "lgr 3,%2\n\t" + "la 4,160(15)\n\t" + "lgr 5,%3\n\t" + "basr 14,%4\n\t" + + "lgr 2,%5\n\t" + "ld 0,192(7)\n\t" + "ld 2,200(7)\n\t" + "ld 4,208(7)\n\t" + "ld 6,216(7)\n\t" + "lmg 3,6,160(7)\n\t" + "basr 14,%6\n\t" + + "la 15,64(7)\n\t" + + "lgr %0,2\n\t" + : "=r" (result) + : "r" ((PRUint64)paramCount), + "r" (params), + "r" (overflow), + "a" (invoke_copy_to_stack), + "a" (that), + "a" (method) + : "2", "3", "4", "5", "6", "7", "memory" + ); + + return result; +} diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_mips.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_mips.cpp new file mode 100644 index 00000000..a73e4327 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_mips.cpp @@ -0,0 +1,122 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * Version: MPL 1.1 + * + * ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corp, Inc. + * Portions created by the Initial Developer are Copyright (C) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Stuart Parmenter + * Brendan Eich + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* This code is for MIPS using the O32 ABI. */ + +/* Platform specific code to invoke XPCOM methods on native objects */ + +#include "xptcprivate.h" + + +extern "C" uint32 +invoke_count_words(PRUint32 paramCount, nsXPTCVariant* s) +{ + // Count a word for a0 even though it's never stored or loaded + // We do this only for alignment of register pairs. + PRUint32 result = 1; + for (PRUint32 i = 0; i < paramCount; i++, s++) + { + result++; + + if (s->IsPtrData()) + continue; + + switch(s->type) + { + case nsXPTType::T_I64 : + case nsXPTType::T_U64 : + case nsXPTType::T_DOUBLE : + if (result & 1) + result++; + result++; + break; + } + } + return (result + 1) & ~(PRUint32)1; +} + +extern "C" void +invoke_copy_to_stack(PRUint32* d, PRUint32 paramCount, + nsXPTCVariant* s) +{ + // Skip the unused a0 slot, which we keep only for register pair alignment. + d++; + + for (PRUint32 i = 0; i < paramCount; i++, d++, s++) + { + if (s->IsPtrData()) + { + *((void**)d) = s->ptr; + continue; + } + + *((void**)d) = s->val.p; + + switch(s->type) + { + case nsXPTType::T_I64 : + if ((PRWord)d & 4) d++; + *((PRInt64*) d) = s->val.i64; d++; + break; + case nsXPTType::T_U64 : + if ((PRWord)d & 4) d++; + *((PRUint64*) d) = s->val.u64; d++; + break; + case nsXPTType::T_DOUBLE : + if ((PRWord)d & 4) d++; + *((double*) d) = s->val.d; d++; + break; + } + } +} + +extern "C" nsresult _XPTC_InvokeByIndex(nsISupports* that, PRUint32 methodIndex, + PRUint32 paramCount, + nsXPTCVariant* params); + +extern "C" +XPTC_PUBLIC_API(nsresult) +XPTC_InvokeByIndex(nsISupports* that, PRUint32 methodIndex, + PRUint32 paramCount, nsXPTCVariant* params) +{ + return _XPTC_InvokeByIndex(that, methodIndex, paramCount, params); +} + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_netbsd_m68k.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_netbsd_m68k.cpp new file mode 100644 index 00000000..65bf8f0c --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_netbsd_m68k.cpp @@ -0,0 +1,175 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Platform specific code to invoke XPCOM methods on native objects */ + +#include "xptcprivate.h" + +// Remember that these 'words' are 32bit DWORDS + +#if !defined(__NetBSD__) || !defined(__m68k__) +#error This code is for NetBSD/m68k only +#endif + +extern "C" { + static PRUint32 + invoke_count_words(PRUint32 paramCount, nsXPTCVariant* s) + { + PRUint32 result = 0; + for(PRUint32 i = 0; i < paramCount; i++, s++) + { + if(s->IsPtrData()) + { + result++; + continue; + } + switch(s->type) + { + case nsXPTType::T_I8 : + case nsXPTType::T_I16 : + case nsXPTType::T_I32 : + result++; + break; + case nsXPTType::T_I64 : + result+=2; + break; + case nsXPTType::T_U8 : + case nsXPTType::T_U16 : + case nsXPTType::T_U32 : + result++; + break; + case nsXPTType::T_U64 : + result+=2; + break; + case nsXPTType::T_FLOAT : + result++; + break; + case nsXPTType::T_DOUBLE : + result+=2; + break; + case nsXPTType::T_BOOL : + case nsXPTType::T_CHAR : + case nsXPTType::T_WCHAR : + result++; + break; + default: + // all the others are plain pointer types + result++; + break; + } + } + return result; + } + + static void + invoke_copy_to_stack(PRUint32* d, PRUint32 paramCount, nsXPTCVariant* s) + { + for(PRUint32 i = 0; i < paramCount; i++, d++, s++) + { + if(s->IsPtrData()) + { + *((void**)d) = s->ptr; + continue; + } + switch(s->type) + { + // 8 and 16 bit types should be promoted to 32 bits when copying + // onto the stack. + case nsXPTType::T_I8 : *((PRUint32*)d) = s->val.i8; break; + case nsXPTType::T_I16 : *((PRUint32*)d) = s->val.i16; break; + case nsXPTType::T_I32 : *((PRInt32*) d) = s->val.i32; break; + case nsXPTType::T_I64 : *((PRInt64*) d) = s->val.i64; d++; break; + case nsXPTType::T_U8 : *((PRUint32*)d) = s->val.u8; break; + case nsXPTType::T_U16 : *((PRUint32*)d) = s->val.u16; break; + case nsXPTType::T_U32 : *((PRUint32*)d) = s->val.u32; break; + case nsXPTType::T_U64 : *((PRUint64*)d) = s->val.u64; d++; break; + case nsXPTType::T_FLOAT : *((float*) d) = s->val.f; break; + case nsXPTType::T_DOUBLE : *((double*) d) = s->val.d; d++; break; + case nsXPTType::T_BOOL : *((PRBool*) d) = s->val.b; break; + case nsXPTType::T_CHAR : *((PRUint32*)d) = s->val.c; break; + // wchar_t is an int (32 bits) on NetBSD + case nsXPTType::T_WCHAR : *((wchar_t*) d) = s->val.wc; break; + default: + // all the others are plain pointer types + *((void**)d) = s->val.p; + break; + } + } + } +} + +XPTC_PUBLIC_API(nsresult) +XPTC_InvokeByIndex(nsISupports* that, PRUint32 methodIndex, + PRUint32 paramCount, nsXPTCVariant* params) +{ + PRUint32 result; + + __asm__ __volatile__( + "movl %4, sp@-\n\t" + "movl %3, sp@-\n\t" + "jbsr _invoke_count_words\n\t" /* count words */ + "addql #8, sp\n\t" + "lsll #2, d0\n\t" /* *= 4 */ + "movl sp, a2\n\t" /* save original sp */ + "subl d0, sp\n\t" /* make room for params */ + "movl sp, a0\n\t" + "movl %4, sp@-\n\t" + "movl %3, sp@-\n\t" + "movl a0, sp@-\n\t" + "jbsr _invoke_copy_to_stack\n\t" /* copy params */ + "addl #12, sp\n\t" + "movl %1, a0\n\t" + "movl a0@, a1\n\t" + "movl %2, d0\n\t" /* function index */ + "movl a0, d1\n\t" + "movw a1@(8,d0:l:8), a0\n\t" + "addl a0, d1\n\t" + "movl a1@(12,d0:l:8), a1\n\t" + "movl d1, sp@-\n\t" + "jbsr a1@\n\t" + "movl a2, sp\n\t" /* restore original sp */ + "movl d0, %0\n\t" + : "=g" (result) /* %0 */ + : "g" (that), /* %1 */ + "g" (methodIndex), /* %2 */ + "g" (paramCount), /* %3 */ + "g" (params) /* %4 */ + : "a0", "a1", "a2", "d0", "d1", "memory" + ); + + return result; +} diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_openvms_alpha.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_openvms_alpha.cpp new file mode 100644 index 00000000..ae22a48c --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_openvms_alpha.cpp @@ -0,0 +1,107 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Platform specific code to invoke XPCOM methods on native objects */ + +#include "xptcprivate.h" + +extern "C" { + +/* This is in the ASM file */ +XPTC_PUBLIC_API(nsresult) +XPTC_InvokeByIndex(nsISupports* that, PRUint32 methodIndex, + PRUint32 paramCount, nsXPTCVariant* params); + + +void +invoke_copy_to_stack(PRUint64* d, PRUint32 paramCount, nsXPTCVariant* s) +{ + const PRUint8 NUM_ARG_REGS = 6-1; // -1 for "this" pointer + + for(PRUint32 i = 0; i < paramCount; i++, d++, s++) + { + if(s->IsPtrData()) + { + *d = (PRUint64)s->ptr; + continue; + } + switch(s->type) + { + /* + ** The line for T_U32 may look wrong (we use signed value for an + ** unsigned data type), but it is right. Why? The Alpha calling + ** standard is defined to sign extend all 32-bit values, regardless + ** of whether they are int, unsigned int, or 32-bit pointer. The + ** caller must "sign-extend" it by replicating bit 31 in bits 32 + ** thru 63 (yes, even for unsigned). This is the format that results + ** naturally from the LDL instruction, the ADDL instruction, etc. + */ + case nsXPTType::T_I8 : *d = (PRUint64)s->val.i8; break; + case nsXPTType::T_I16 : *d = (PRUint64)s->val.i16; break; + case nsXPTType::T_I32 : *d = (PRUint64)s->val.i32; break; + case nsXPTType::T_I64 : *d = (PRUint64)s->val.i64; break; + case nsXPTType::T_U8 : *d = (PRUint64)s->val.u8; break; + case nsXPTType::T_U16 : *d = (PRUint64)s->val.u16; break; + case nsXPTType::T_U32 : *d = (PRUint64)s->val.i32; break; + case nsXPTType::T_U64 : *d = (PRUint64)s->val.u64; break; + case nsXPTType::T_FLOAT : + if(i < NUM_ARG_REGS) + { + // convert floats to doubles if they are to be passed + // via registers so we can just deal with doubles later + union { PRUint64 u64; double d; } t; + t.d = (double)s->val.f; + *d = t.u64; + } + else + // otherwise copy to stack normally + *d = (PRUint64)s->val.u32; + break; + case nsXPTType::T_DOUBLE : *d = (PRUint64)s->val.u64; break; + case nsXPTType::T_BOOL : *d = (PRUint64)s->val.b; break; + case nsXPTType::T_CHAR : *d = (PRUint64)s->val.c; break; + case nsXPTType::T_WCHAR : *d = (PRUint64)s->val.wc; break; + default: + // all the others are plain pointer types + *d = (PRUint64)s->val.p; + break; + } + } +} + +} + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_osf1_alpha.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_osf1_alpha.cpp new file mode 100644 index 00000000..13c3b23d --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_osf1_alpha.cpp @@ -0,0 +1,93 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Platform specific code to invoke XPCOM methods on native objects */ + +/* contributed by Steve Streeter */ + +#include "xptcprivate.h" + +/* Prototype specifies unmangled function name */ +extern "C" void +invoke_copy_to_stack(PRUint64* d, PRUint32 paramCount, nsXPTCVariant* s); + +extern "C" void +invoke_copy_to_stack(PRUint64* d, PRUint32 paramCount, nsXPTCVariant* s) +{ + const PRUint8 NUM_ARG_REGS = 6-1; // -1 for "this" pointer + + for(PRUint32 i = 0; i < paramCount; i++, d++, s++) + { + if(s->IsPtrData()) + { + *d = (PRUint64)s->ptr; + continue; + } + switch(s->type) + { + case nsXPTType::T_I8 : *d = (PRUint64)s->val.i8; break; + case nsXPTType::T_I16 : *d = (PRUint64)s->val.i16; break; + case nsXPTType::T_I32 : *d = (PRUint64)s->val.i32; break; + case nsXPTType::T_I64 : *d = (PRUint64)s->val.i64; break; + case nsXPTType::T_U8 : *d = (PRUint64)s->val.u8; break; + case nsXPTType::T_U16 : *d = (PRUint64)s->val.u16; break; + case nsXPTType::T_U32 : *d = (PRUint64)s->val.u32; break; + case nsXPTType::T_U64 : *d = (PRUint64)s->val.u64; break; + case nsXPTType::T_FLOAT : + if(i < NUM_ARG_REGS) + { + // convert floats to doubles if they are to be passed + // via registers so we can just deal with doubles later + union { PRUint64 u64; double d; } t; + t.d = (double)s->val.f; + *d = t.u64; + } + else + // otherwise copy to stack normally + *d = (PRUint64)s->val.u32; + break; + case nsXPTType::T_DOUBLE : *d = (PRUint64)s->val.u64; break; + case nsXPTType::T_BOOL : *d = (PRUint64)s->val.b; break; + case nsXPTType::T_CHAR : *d = (PRUint64)s->val.c; break; + case nsXPTType::T_WCHAR : *d = (PRUint64)s->val.wc; break; + default: + // all the others are plain pointer types + *d = (PRUint64)s->val.p; + break; + } + } +} diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_pa32.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_pa32.cpp new file mode 100644 index 00000000..c6208a50 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_pa32.cpp @@ -0,0 +1,181 @@ + +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "xptcprivate.h" + +#if _HPUX +#error "This code is for HP-PA RISC 32 bit mode only" +#endif + +#include + +typedef unsigned nsXPCVariant; + +extern "C" PRInt32 +invoke_count_bytes(nsISupports* that, const PRUint32 methodIndex, + const PRUint32 paramCount, const nsXPTCVariant* s) +{ + PRInt32 result = 4; /* variant records do not include self pointer */ + + /* counts the number of bytes required by the argument stack, + 64 bit integer, and double requires 8 bytes. All else requires + 4 bytes. + */ + + { + PRUint32 indx; + for (indx = paramCount; indx > 0; --indx, ++s) + { + if (! s->IsPtrData()) + { + if (s->type == nsXPTType::T_I64 || s->type == nsXPTType::T_U64 || + s->type == nsXPTType::T_DOUBLE) + { + /* 64 bit integer and double aligned on 8 byte boundaries */ + result += (result & 4) + 8; + continue; + } + } + result += 4; /* all other cases use 4 bytes */ + } + } + result -= 72; /* existing stack buffer is 72 bytes */ + if (result < 0) + return 0; + { + /* round up to 64 bytes boundary */ + PRInt32 remainder = result & 63; + return (remainder == 0) ? result : (result + 64 - remainder); + } +} + +extern "C" PRUint32 +invoke_copy_to_stack(PRUint32* d, + const PRUint32 paramCount, nsXPTCVariant* s) +{ + + typedef struct + { + PRUint32 hi; + PRUint32 lo; + } DU; + + PRUint32* dest = d; + nsXPTCVariant* source = s; + /* we clobber param vars by copying stuff on stack, have to use local var */ + + PRUint32 floatflags = 0; + /* flag indicating which floating point registers to load */ + + PRUint32 regwords = 1; /* register 26 is reserved for ptr to 'that' */ + PRUint32 indx; + + for (indx = paramCount; indx > 0; --indx, --dest, ++source) + { + if (source->IsPtrData()) + { + *((void**) dest) = source->ptr; + ++regwords; + continue; + } + switch (source->type) + { + case nsXPTType::T_I8 : *((PRInt32*) dest) = source->val.i8; break; + case nsXPTType::T_I16 : *((PRInt32*) dest) = source->val.i16; break; + case nsXPTType::T_I32 : *((PRInt32*) dest) = source->val.i32; break; + case nsXPTType::T_I64 : + case nsXPTType::T_U64 : + if (regwords & 1) + { + /* align on double word boundary */ + --dest; + ++regwords; + } + *((uint32*) dest) = ((DU *) source)->lo; + *((uint32*) --dest) = ((DU *) source)->hi; + /* big endian - hi word in low addr */ + regwords += 2; + continue; + case nsXPTType::T_DOUBLE : + if (regwords & 1) + { + /* align on double word boundary */ + --dest; + ++regwords; + } + switch (regwords) /* load double precision float register */ + { + case 2: + floatflags |= 1; + } + *((uint32*) dest) = ((DU *) source)->lo; + *((uint32*) --dest) = ((DU *) source)->hi; + /* big endian - hi word in low addr */ + regwords += 2; + continue; + case nsXPTType::T_FLOAT : + switch (regwords) /* load single precision float register */ + { + case 1: + floatflags |= 2; + break; + case 2: + floatflags |= 4; + break; + case 3: + floatflags |= 8; + } + *((float*) dest) = source->val.f; + break; + case nsXPTType::T_U8 : *((PRUint32*) (dest)) = source->val.u8; break; + case nsXPTType::T_U16 : *((PRUint32*) (dest)) = source->val.u16; break; + case nsXPTType::T_U32 : *((PRUint32*) (dest)) = source->val.u32; break; + case nsXPTType::T_BOOL : *((PRBool*) (dest)) = source->val.b; break; + case nsXPTType::T_CHAR : *((PRUint32*) (dest)) = source->val.c; break; + case nsXPTType::T_WCHAR : *((PRInt32*) (dest)) = source->val.wc; break; + + default: + // all the others are plain pointer types + *((void**) dest) = source->val.p; + } + ++regwords; + } + return floatflags; +} + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_ppc_aix.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_ppc_aix.cpp new file mode 100644 index 00000000..d353063c --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_ppc_aix.cpp @@ -0,0 +1,106 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Platform specific code to invoke XPCOM methods on native objects */ + +#include "xptcprivate.h" + +#ifndef AIX +#error "This code is for PowerPC only" +#endif + +extern "C" void +invoke_copy_to_stack(PRUint32* d, PRUint32 paramCount, nsXPTCVariant* s, double *fprData) +{ +/* + We need to copy the parameters for this function to locals and use them + from there since the parameters occupy the same stack space as the stack + we're trying to populate. +*/ + PRUint32 *l_d = d; + nsXPTCVariant *l_s = s; + PRUint32 l_paramCount = paramCount, fpCount = 0; + double *l_fprData = fprData; + + typedef struct { + uint32 hi; + uint32 lo; + } DU; // have to move 64 bit entities as 32 bit halves since + // stack slots are not guaranteed 16 byte aligned + + for(uint32 i = 0; i < l_paramCount; i++, l_d++, l_s++) + { + if(l_s->IsPtrData()) + { + *((void**)l_d) = l_s->ptr; + continue; + } + switch(l_s->type) + { + case nsXPTType::T_I8 : *((int32*) l_d) = l_s->val.i8; break; + case nsXPTType::T_I16 : *((int32*) l_d) = l_s->val.i16; break; + case nsXPTType::T_I32 : *((int32*) l_d) = l_s->val.i32; break; + case nsXPTType::T_I64 : + case nsXPTType::T_U64 : + *((uint32*) l_d++) = ((DU *)l_s)->hi; + *((uint32*) l_d) = ((DU *)l_s)->lo; + break; + case nsXPTType::T_DOUBLE : + *((uint32*) l_d++) = ((DU *)l_s)->hi; + *((uint32*) l_d) = ((DU *)l_s)->lo; + if(fpCount < 13) + l_fprData[fpCount++] = l_s->val.d; + break; + case nsXPTType::T_U8 : *((uint32*) l_d) = l_s->val.u8; break; + case nsXPTType::T_U16 : *((uint32*) l_d) = l_s->val.u16; break; + case nsXPTType::T_U32 : *((uint32*) l_d) = l_s->val.u32; break; + case nsXPTType::T_FLOAT : + *((float*) l_d) = l_s->val.f; + if(fpCount < 13) + l_fprData[fpCount++] = l_s->val.f; + break; + case nsXPTType::T_BOOL : *((PRBool*) l_d) = l_s->val.b; break; + case nsXPTType::T_CHAR : *((uint32*) l_d) = l_s->val.c; break; + case nsXPTType::T_WCHAR : *((int32*) l_d) = l_s->val.wc; break; + default: + // all the others are plain pointer types + *((void**)l_d) = l_s->val.p; + break; + } + } +} + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_ppc_aix64.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_ppc_aix64.cpp new file mode 100644 index 00000000..a42611b8 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_ppc_aix64.cpp @@ -0,0 +1,95 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/LGPL 2.1/GPL 2.0 + * + * 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.org code. + * + * The Initial Developer of the Original Code is IBM Corporation. + * Portions created by IBM are + * Copyright (C) 2002, International Business Machines Corporation. + * All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 LGPL or the GPL. 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 ***** */ + +/* Platform specific code to invoke XPCOM methods on native objects */ + +#include "xptcprivate.h" + +#ifdef _AIX + +extern "C" void +invoke_copy_to_stack(PRUint64* d, PRUint32 paramCount, nsXPTCVariant* s, double *fprData) +{ +/* + We need to copy the parameters for this function to locals and use them + from there since the parameters occupy the same stack space as the stack + we're trying to populate. +*/ + PRUint64 *l_d = d; + nsXPTCVariant *l_s = s; + PRUint32 l_paramCount = paramCount, fpCount = 0; + double *l_fprData = fprData; + + for(PRUint32 i = 0; i < l_paramCount; i++, l_d++, l_s++) + { + if(l_s->IsPtrData()) + { + *l_d = (PRUint64)l_s->ptr; + continue; + } + switch(l_s->type) + { + case nsXPTType::T_I8: *l_d = (PRUint64)l_s->val.i8; break; + case nsXPTType::T_I16: *l_d = (PRUint64)l_s->val.i16; break; + case nsXPTType::T_I32: *l_d = (PRUint64)l_s->val.i32; break; + case nsXPTType::T_I64: *l_d = (PRUint64)l_s->val.i64; break; + case nsXPTType::T_U8: *l_d = (PRUint64)l_s->val.u8; break; + case nsXPTType::T_U16: *l_d = (PRUint64)l_s->val.u16; break; + case nsXPTType::T_U32: *l_d = (PRUint64)l_s->val.u32; break; + case nsXPTType::T_U64: *l_d = (PRUint64)l_s->val.u64; break; + case nsXPTType::T_BOOL: *l_d = (PRUint64)l_s->val.b; break; + case nsXPTType::T_CHAR: *l_d = (PRUint64)l_s->val.c; break; + case nsXPTType::T_WCHAR: *l_d = (PRUint64)l_s->val.wc; break; + + case nsXPTType::T_DOUBLE: + *((double*)l_d) = l_s->val.d; + if(fpCount < 13) + l_fprData[fpCount++] = l_s->val.d; + break; + case nsXPTType::T_FLOAT: + *((float*)l_d) = l_s->val.f; + if(fpCount < 13) + l_fprData[fpCount++] = l_s->val.f; + break; + default: + // all the others are plain pointer types + *l_d = (PRUint64)l_s->val.p; + break; + } + } +} +#endif + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_ppc_linux.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_ppc_linux.cpp new file mode 100644 index 00000000..7303045a --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_ppc_linux.cpp @@ -0,0 +1,141 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Franz.Sirl-kernel@lauterbach.com (Franz Sirl) + * beard@netscape.com (Patrick Beard) + * waterson@netscape.com (Chris Waterson) + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +// Platform specific code to invoke XPCOM methods on native objects + +// The purpose of XPTC_InvokeByIndex() is to map a platform +// indepenpent call to the platform ABI. To do that, +// XPTC_InvokeByIndex() has to determine the method to call via vtable +// access. The parameters for the method are read from the +// nsXPTCVariant* and prepared for th native ABI. For the Linux/PPC +// ABI this means that the first 8 integral and floating point +// parameters are passed in registers. + +#include "xptcprivate.h" + +// 8 integral parameters are passed in registers +#define GPR_COUNT 8 + +// 8 floating point parameters are passed in registers, floats are +// promoted to doubles when passed in registers +#define FPR_COUNT 8 + +extern "C" PRUint32 +invoke_count_words(PRUint32 paramCount, nsXPTCVariant* s) +{ + return PRUint32(((paramCount * 2) + 3) & ~3); +} + +extern "C" void +invoke_copy_to_stack(PRUint32* d, + PRUint32 paramCount, + nsXPTCVariant* s, + PRUint32* gpregs, + double* fpregs) +{ + PRUint32 gpr = 1; // skip one GP reg for 'that' + PRUint32 fpr = 0; + PRUint32 tempu32; + PRUint64 tempu64; + + for(uint32 i = 0; i < paramCount; i++, s++) { + if(s->IsPtrData()) + tempu32 = (PRUint32) s->ptr; + else { + switch(s->type) { + case nsXPTType::T_FLOAT: break; + case nsXPTType::T_DOUBLE: break; + case nsXPTType::T_I8: tempu32 = s->val.i8; break; + case nsXPTType::T_I16: tempu32 = s->val.i16; break; + case nsXPTType::T_I32: tempu32 = s->val.i32; break; + case nsXPTType::T_I64: tempu64 = s->val.i64; break; + case nsXPTType::T_U8: tempu32 = s->val.u8; break; + case nsXPTType::T_U16: tempu32 = s->val.u16; break; + case nsXPTType::T_U32: tempu32 = s->val.u32; break; + case nsXPTType::T_U64: tempu64 = s->val.u64; break; + case nsXPTType::T_BOOL: tempu32 = s->val.b; break; + case nsXPTType::T_CHAR: tempu32 = s->val.c; break; + case nsXPTType::T_WCHAR: tempu32 = s->val.wc; break; + default: tempu32 = (PRUint32) s->val.p; break; + } + } + + if (!s->IsPtrData() && s->type == nsXPTType::T_DOUBLE) { + if (fpr < FPR_COUNT) + fpregs[fpr++] = s->val.d; + else { + if ((PRUint32) d & 4) d++; // doubles are 8-byte aligned on stack + *((double*) d) = s->val.d; + d += 2; + } + } + else if (!s->IsPtrData() && s->type == nsXPTType::T_FLOAT) { + if (fpr < FPR_COUNT) + fpregs[fpr++] = s->val.f; // if passed in registers, floats are promoted to doubles + else + *((float*) d++) = s->val.f; + } + else if (!s->IsPtrData() && (s->type == nsXPTType::T_I64 + || s->type == nsXPTType::T_U64)) { + if ((gpr + 1) < GPR_COUNT) { + if (gpr & 1) gpr++; // longlongs are aligned in odd/even register pairs, eg. r5/r6 + *((PRUint64*) &gpregs[gpr]) = tempu64; + gpr += 2; + } + else { + if ((PRUint32) d & 4) d++; // longlongs are 8-byte aligned on stack + *((PRUint64*) d) = tempu64; + d += 2; + } + } + else { + if (gpr < GPR_COUNT) + gpregs[gpr++] = tempu32; + else + *d++ = tempu32; + } + + } +} + +extern "C" +XPTC_PUBLIC_API(nsresult) +XPTC_InvokeByIndex(nsISupports* that, PRUint32 methodIndex, + PRUint32 paramCount, nsXPTCVariant* params); diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_ppc_netbsd.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_ppc_netbsd.cpp new file mode 100644 index 00000000..0de8ea62 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_ppc_netbsd.cpp @@ -0,0 +1,147 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Franz.Sirl-kernel@lauterbach.com (Franz Sirl) + * beard@netscape.com (Patrick Beard) + * waterson@netscape.com (Chris Waterson) + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +// Platform specific code to invoke XPCOM methods on native objects + +// The purpose of XPTC_InvokeByIndex() is to map a platform +// indepenpent call to the platform ABI. To do that, +// XPTC_InvokeByIndex() has to determine the method to call via vtable +// access. The parameters for the method are read from the +// nsXPTCVariant* and prepared for th native ABI. For the Linux/PPC +// ABI this means that the first 8 integral and floating point +// parameters are passed in registers. + +#include "xptcprivate.h" + +// 8 integral parameters are passed in registers +#define GPR_COUNT 8 + +// 8 floating point parameters are passed in registers, floats are +// promoted to doubles when passed in registers +#define FPR_COUNT 8 + +extern "C" PRUint32 +invoke_count_words(PRUint32 paramCount, nsXPTCVariant* s) +{ + return PRUint32(((paramCount * 2) + 3) & ~3); +} + +extern "C" void +invoke_copy_to_stack(PRUint32* d, + PRUint32 paramCount, + nsXPTCVariant* s, + PRUint32* gpregs, + double* fpregs) +{ + PRUint32 gpr = 1; // skip one GP reg for 'that' + PRUint32 fpr = 0; + PRUint32 tempu32; + PRUint64 tempu64; + + for(uint32 i = 0; i < paramCount; i++, s++) { + if(s->IsPtrData()) + tempu32 = (PRUint32) s->ptr; + else { + switch(s->type) { + case nsXPTType::T_FLOAT: break; + case nsXPTType::T_DOUBLE: break; + case nsXPTType::T_I8: tempu32 = s->val.i8; break; + case nsXPTType::T_I16: tempu32 = s->val.i16; break; + case nsXPTType::T_I32: tempu32 = s->val.i32; break; + case nsXPTType::T_I64: tempu64 = s->val.i64; break; + case nsXPTType::T_U8: tempu32 = s->val.u8; break; + case nsXPTType::T_U16: tempu32 = s->val.u16; break; + case nsXPTType::T_U32: tempu32 = s->val.u32; break; + case nsXPTType::T_U64: tempu64 = s->val.u64; break; + case nsXPTType::T_BOOL: tempu32 = s->val.b; break; + case nsXPTType::T_CHAR: tempu32 = s->val.c; break; + case nsXPTType::T_WCHAR: tempu32 = s->val.wc; break; + default: tempu32 = (PRUint32) s->val.p; break; + } + } + + if (!s->IsPtrData() && s->type == nsXPTType::T_DOUBLE) { + if (fpr < FPR_COUNT) + fpregs[fpr++] = s->val.d; + else { + if ((PRUint32) d & 4) d++; // doubles are 8-byte aligned on stack + *((double*) d) = s->val.d; + d += 2; + if (gpr < GPR_COUNT) + gpr += 2; + } + } + else if (!s->IsPtrData() && s->type == nsXPTType::T_FLOAT) { + if (fpr < FPR_COUNT) + fpregs[fpr++] = s->val.f; // if passed in registers, floats are promoted to doubles + else { + *((float*) d) = s->val.f; + d += 1; + if (gpr < GPR_COUNT) + gpr += 1; + } + } + else if (!s->IsPtrData() && (s->type == nsXPTType::T_I64 + || s->type == nsXPTType::T_U64)) { + if ((gpr + 1) < GPR_COUNT) { + if (gpr & 1) gpr++; // longlongs are aligned in odd/even register pairs, eg. r5/r6 + *((PRUint64*) &gpregs[gpr]) = tempu64; + gpr += 2; + } + else { + if ((PRUint32) d & 4) d++; // longlongs are 8-byte aligned on stack + *((PRUint64*) d) = tempu64; + d += 2; + } + } + else { + if (gpr < GPR_COUNT) + gpregs[gpr++] = tempu32; + else + *d++ = tempu32; + } + + } +} + +extern "C" +XPTC_PUBLIC_API(nsresult) +XPTC_InvokeByIndex(nsISupports* that, PRUint32 methodIndex, + PRUint32 paramCount, nsXPTCVariant* params); diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_ppc_rhapsody.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_ppc_rhapsody.cpp new file mode 100644 index 00000000..9a08acfd --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_ppc_rhapsody.cpp @@ -0,0 +1,145 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Platform specific code to invoke XPCOM methods on native objects */ + +#include "xptcprivate.h" + +extern "C" uint32 +invoke_count_words(PRUint32 paramCount, nsXPTCVariant* s) +{ + PRUint32 result = 0; + /* fprintf(stderr,"invoke_count_words(%d,%p)\n",paramCount, s);*/ + + for(PRUint32 i = 0; i < paramCount; i++, s++) + { + if(s->IsPtrData()) + { + result++; + continue; + } + switch(s->type) + { + case nsXPTType::T_I8 : + case nsXPTType::T_I16 : + case nsXPTType::T_I32 : + result++; + break; + case nsXPTType::T_I64 : + result+=2; + break; + case nsXPTType::T_U8 : + case nsXPTType::T_U16 : + case nsXPTType::T_U32 : + result++; + break; + case nsXPTType::T_U64 : + result+=2; + break; + case nsXPTType::T_FLOAT : + result++; + break; + case nsXPTType::T_DOUBLE : + result+=2; + break; + case nsXPTType::T_BOOL : + case nsXPTType::T_CHAR : + case nsXPTType::T_WCHAR : + result++; + break; + default: + // all the others are plain pointer types + result++; + break; + } + } + return result; +} + +extern "C" void +invoke_copy_to_stack(PRUint32* d, PRUint32 paramCount, nsXPTCVariant* s, double *fprData) +{ + PRUint32 fpCount = 0; + + /* fprintf(stderr,"invoke_copy_to_stack(%p, %d, %p, %p)\n", d, paramCount, s, fprData);*/ + + for(PRUint32 i = 0; i < paramCount; i++, d++, s++) + { + if(s->IsPtrData()) + { + *((void**)d) = s->ptr; + continue; + } + switch(s->type) + { + case nsXPTType::T_I8 : *((PRInt32*) d) = s->val.i8; break; + case nsXPTType::T_I16 : *((PRInt32*) d) = s->val.i16; break; + case nsXPTType::T_I32 : *((PRInt32*) d) = s->val.i32; break; + case nsXPTType::T_I64 : *((PRInt64*) d) = s->val.i64; d++; break; + case nsXPTType::T_U8 : *((PRUint32*) d) = s->val.u8; break; + case nsXPTType::T_U16 : *((PRUint32*)d) = s->val.u16; break; + case nsXPTType::T_U32 : *((PRUint32*)d) = s->val.u32; break; + case nsXPTType::T_U64 : *((PRUint64*)d) = s->val.u64; d++; break; + case nsXPTType::T_FLOAT : *((float*) d) = s->val.f; + if (fpCount < 13) + fprData[fpCount++] = s->val.f; + break; + case nsXPTType::T_DOUBLE : *((double*) d) = s->val.d; d++; + if (fpCount < 13) + fprData[fpCount++] = s->val.d; + break; + case nsXPTType::T_BOOL : *((PRBool*) d) = s->val.b; break; + case nsXPTType::T_CHAR : *((PRInt32*) d) = s->val.c; break; + case nsXPTType::T_WCHAR : *((PRUint32*) d) = s->val.wc; break; + default: + // all the others are plain pointer types + *((void**)d) = s->val.p; + break; + } + } +} + +extern "C" nsresult _XPTC_InvokeByIndex(nsISupports* that, PRUint32 methodIndex, + PRUint32 paramCount, nsXPTCVariant* params); + +extern "C" +XPTC_PUBLIC_API(nsresult) +XPTC_InvokeByIndex(nsISupports* that, PRUint32 methodIndex, + PRUint32 paramCount, nsXPTCVariant* params) +{ + return _XPTC_InvokeByIndex(that, methodIndex, paramCount, params); +} diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_sparc_netbsd.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_sparc_netbsd.cpp new file mode 100644 index 00000000..fb2af366 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_sparc_netbsd.cpp @@ -0,0 +1,156 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Platform specific code to invoke XPCOM methods on native objects */ + +#include "xptcprivate.h" + +/* solaris defines __sparc for workshop compilers and + linux defines __sparc__ */ + +#if !defined(__sparc) && !defined(__sparc__) +#error "This code is for Sparc only" +#endif + +typedef unsigned nsXPCVariant; + +extern "C" PRUint32 +invoke_count_words(PRUint32 paramCount, nsXPTCVariant* s) +{ + PRUint32 result = 0; + for(PRUint32 i = 0; i < paramCount; i++, s++) + { + if(s->IsPtrData()) + { + result++; + continue; + } + switch(s->type) + { + case nsXPTType::T_I8 : + case nsXPTType::T_I16 : + case nsXPTType::T_I32 : + result++; + break; + case nsXPTType::T_I64 : + result+=2; + break; + case nsXPTType::T_U8 : + case nsXPTType::T_U16 : + case nsXPTType::T_U32 : + result++; + break; + case nsXPTType::T_U64 : + result+=2; + break; + case nsXPTType::T_FLOAT : + result++; + break; + case nsXPTType::T_DOUBLE : + result+=2; + break; + case nsXPTType::T_BOOL : + case nsXPTType::T_CHAR : + case nsXPTType::T_WCHAR : + result++; + break; + default: + // all the others are plain pointer types + result++; + break; + } + } + // nuts, I know there's a cooler way of doing this, but it's late + // now and it'll probably come to me in the morning. + if (result & 0x3) result += 4 - (result & 0x3); // ensure q-word alignment + return result; +} + +extern "C" PRUint32 +invoke_copy_to_stack(PRUint32* d, PRUint32 paramCount, nsXPTCVariant* s) +{ +/* + We need to copy the parameters for this function to locals and use them + from there since the parameters occupy the same stack space as the stack + we're trying to populate. +*/ + uint32 *l_d = d; + nsXPTCVariant *l_s = s; + uint32 l_paramCount = paramCount; + uint32 regCount = 0; // return the number of registers to load from the stack + + typedef struct { + uint32 hi; + uint32 lo; + } DU; // have to move 64 bit entities as 32 bit halves since + // stack slots are not guaranteed 16 byte aligned + + for(uint32 i = 0; i < l_paramCount; i++, l_d++, l_s++) + { + if (regCount < 5) regCount++; + if(l_s->IsPtrData()) + { + *((void**)l_d) = l_s->ptr; + continue; + } + switch(l_s->type) + { + case nsXPTType::T_I8 : *((int32*) l_d) = l_s->val.i8; break; + case nsXPTType::T_I16 : *((int32*) l_d) = l_s->val.i16; break; + case nsXPTType::T_I32 : *((int32*) l_d) = l_s->val.i32; break; + case nsXPTType::T_I64 : + case nsXPTType::T_U64 : + case nsXPTType::T_DOUBLE : *((uint32*) l_d++) = ((DU *)l_s)->hi; + if (regCount < 5) regCount++; + *((uint32*) l_d) = ((DU *)l_s)->lo; + break; + case nsXPTType::T_U8 : *((uint32*) l_d) = l_s->val.u8; break; + case nsXPTType::T_U16 : *((uint32*) l_d) = l_s->val.u16; break; + case nsXPTType::T_U32 : *((uint32*) l_d) = l_s->val.u32; break; + case nsXPTType::T_FLOAT : *((float*) l_d) = l_s->val.f; break; + case nsXPTType::T_BOOL : *((PRBool*) l_d) = l_s->val.b; break; + case nsXPTType::T_CHAR : *((uint32*) l_d) = l_s->val.c; break; + case nsXPTType::T_WCHAR : *((int32*)l_d) = l_s->val.wc; break; + default: + // all the others are plain pointer types + *((void**)l_d) = l_s->val.p; + break; + } + } + return regCount; +} + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_sparc_solaris.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_sparc_solaris.cpp new file mode 100644 index 00000000..fb2af366 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_sparc_solaris.cpp @@ -0,0 +1,156 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Platform specific code to invoke XPCOM methods on native objects */ + +#include "xptcprivate.h" + +/* solaris defines __sparc for workshop compilers and + linux defines __sparc__ */ + +#if !defined(__sparc) && !defined(__sparc__) +#error "This code is for Sparc only" +#endif + +typedef unsigned nsXPCVariant; + +extern "C" PRUint32 +invoke_count_words(PRUint32 paramCount, nsXPTCVariant* s) +{ + PRUint32 result = 0; + for(PRUint32 i = 0; i < paramCount; i++, s++) + { + if(s->IsPtrData()) + { + result++; + continue; + } + switch(s->type) + { + case nsXPTType::T_I8 : + case nsXPTType::T_I16 : + case nsXPTType::T_I32 : + result++; + break; + case nsXPTType::T_I64 : + result+=2; + break; + case nsXPTType::T_U8 : + case nsXPTType::T_U16 : + case nsXPTType::T_U32 : + result++; + break; + case nsXPTType::T_U64 : + result+=2; + break; + case nsXPTType::T_FLOAT : + result++; + break; + case nsXPTType::T_DOUBLE : + result+=2; + break; + case nsXPTType::T_BOOL : + case nsXPTType::T_CHAR : + case nsXPTType::T_WCHAR : + result++; + break; + default: + // all the others are plain pointer types + result++; + break; + } + } + // nuts, I know there's a cooler way of doing this, but it's late + // now and it'll probably come to me in the morning. + if (result & 0x3) result += 4 - (result & 0x3); // ensure q-word alignment + return result; +} + +extern "C" PRUint32 +invoke_copy_to_stack(PRUint32* d, PRUint32 paramCount, nsXPTCVariant* s) +{ +/* + We need to copy the parameters for this function to locals and use them + from there since the parameters occupy the same stack space as the stack + we're trying to populate. +*/ + uint32 *l_d = d; + nsXPTCVariant *l_s = s; + uint32 l_paramCount = paramCount; + uint32 regCount = 0; // return the number of registers to load from the stack + + typedef struct { + uint32 hi; + uint32 lo; + } DU; // have to move 64 bit entities as 32 bit halves since + // stack slots are not guaranteed 16 byte aligned + + for(uint32 i = 0; i < l_paramCount; i++, l_d++, l_s++) + { + if (regCount < 5) regCount++; + if(l_s->IsPtrData()) + { + *((void**)l_d) = l_s->ptr; + continue; + } + switch(l_s->type) + { + case nsXPTType::T_I8 : *((int32*) l_d) = l_s->val.i8; break; + case nsXPTType::T_I16 : *((int32*) l_d) = l_s->val.i16; break; + case nsXPTType::T_I32 : *((int32*) l_d) = l_s->val.i32; break; + case nsXPTType::T_I64 : + case nsXPTType::T_U64 : + case nsXPTType::T_DOUBLE : *((uint32*) l_d++) = ((DU *)l_s)->hi; + if (regCount < 5) regCount++; + *((uint32*) l_d) = ((DU *)l_s)->lo; + break; + case nsXPTType::T_U8 : *((uint32*) l_d) = l_s->val.u8; break; + case nsXPTType::T_U16 : *((uint32*) l_d) = l_s->val.u16; break; + case nsXPTType::T_U32 : *((uint32*) l_d) = l_s->val.u32; break; + case nsXPTType::T_FLOAT : *((float*) l_d) = l_s->val.f; break; + case nsXPTType::T_BOOL : *((PRBool*) l_d) = l_s->val.b; break; + case nsXPTType::T_CHAR : *((uint32*) l_d) = l_s->val.c; break; + case nsXPTType::T_WCHAR : *((int32*)l_d) = l_s->val.wc; break; + default: + // all the others are plain pointer types + *((void**)l_d) = l_s->val.p; + break; + } + } + return regCount; +} + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_sparcv9_solaris.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_sparcv9_solaris.cpp new file mode 100644 index 00000000..83b28ebb --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_sparcv9_solaris.cpp @@ -0,0 +1,107 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Stuart Parmenter + * Chris Seawood + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + + +/* Platform specific code to invoke XPCOM methods on native objects */ + +#include "xptcprivate.h" + +#if !defined(__sparc) && !defined(__sparc__) +#error "This code is for Sparc only" +#endif + +/* Prototype specifies unmangled function name */ +extern "C" PRUint64 +invoke_copy_to_stack(PRUint64* d, PRUint32 paramCount, nsXPTCVariant* s); + +extern "C" PRUint64 +invoke_copy_to_stack(PRUint64* d, PRUint32 paramCount, nsXPTCVariant* s) +{ + /* + We need to copy the parameters for this function to locals and use them + from there since the parameters occupy the same stack space as the stack + we're trying to populate. + */ + PRUint64 *l_d = d; + nsXPTCVariant *l_s = s; + PRUint64 l_paramCount = paramCount; + PRUint64 regCount = 0; // return the number of registers to load from the stack + + for(PRUint64 i = 0; i < l_paramCount; i++, l_d++, l_s++) + { + if (regCount < 5) regCount++; + + if (l_s->IsPtrData()) + { + *l_d = (PRUint64)l_s->ptr; + continue; + } + switch (l_s->type) + { + case nsXPTType::T_I8 : *((PRInt64*)l_d) = l_s->val.i8; break; + case nsXPTType::T_I16 : *((PRInt64*)l_d) = l_s->val.i16; break; + case nsXPTType::T_I32 : *((PRInt64*)l_d) = l_s->val.i32; break; + case nsXPTType::T_I64 : *((PRInt64*)l_d) = l_s->val.i64; break; + + case nsXPTType::T_U8 : *((PRUint64*)l_d) = l_s->val.u8; break; + case nsXPTType::T_U16 : *((PRUint64*)l_d) = l_s->val.u16; break; + case nsXPTType::T_U32 : *((PRUint64*)l_d) = l_s->val.u32; break; + case nsXPTType::T_U64 : *((PRUint64*)l_d) = l_s->val.u64; break; + + /* in the case of floats, we want to put the bits in to the + 64bit space right justified... floats in the paramter array on + sparcv9 use odd numbered registers.. %f1, %f3, so we have to skip + the space that would be occupied by %f0, %f2, etc. + */ + case nsXPTType::T_FLOAT : *(((float*)l_d) + 1) = l_s->val.f; break; + case nsXPTType::T_DOUBLE: *((double*)l_d) = l_s->val.d; break; + case nsXPTType::T_BOOL : *((PRBool*)l_d) = l_s->val.b; break; + case nsXPTType::T_CHAR : *((PRUint64*)l_d) = l_s->val.c; break; + case nsXPTType::T_WCHAR : *((PRInt64*)l_d) = l_s->val.wc; break; + + default: + // all the others are plain pointer types + *((void**)l_d) = l_s->val.p; + break; + } + } + + return regCount; +} diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_unixish_x86.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_unixish_x86.cpp new file mode 100644 index 00000000..76445fa4 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_unixish_x86.cpp @@ -0,0 +1,187 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mark Mentovai + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Platform specific code to invoke XPCOM methods on native objects */ + +#include "xptcprivate.h" +#include "xptc_platforms_unixish_x86.h" + +extern "C" { + +static void +invoke_copy_to_stack(PRUint32 paramCount, nsXPTCVariant* s, PRUint32* d) +{ + for(PRUint32 i = paramCount; i >0; i--, d++, s++) + { + if(s->IsPtrData()) + { + *((void**)d) = s->ptr; + continue; + } + +/* XXX: the following line is here (rather than as the default clause in + * the following switch statement) so that the Sun native compiler + * will generate the correct assembly code on the Solaris Intel + * platform. See the comments in bug #28817 for more details. + */ + + *((void**)d) = s->val.p; + + switch(s->type) + { + case nsXPTType::T_I64 : *((PRInt64*) d) = s->val.i64; d++; break; + case nsXPTType::T_U64 : *((PRUint64*)d) = s->val.u64; d++; break; + case nsXPTType::T_DOUBLE : *((double*) d) = s->val.d; d++; break; + } + } +} + +} + +XPTC_PUBLIC_API(nsresult) +XPTC_InvokeByIndex(nsISupports* that, PRUint32 methodIndex, + PRUint32 paramCount, nsXPTCVariant* params) +{ +#ifdef __GNUC__ /* Gnu compiler. */ + PRUint32 result; + /* Each param takes at most 2, 4-byte words + It doesn't matter if we push too many words, and calculating the exact + amount takes time. */ + PRUint32 n = paramCount << 3; + void (*fn_copy) (unsigned int, nsXPTCVariant *, PRUint32 *) = invoke_copy_to_stack; + int temp1, temp2; + + /* These are only significant when KEEP_STACK_16_BYTE_ALIGNED is + defined. Otherwise, they're just placeholders to keep the parameter + indices the same for aligned and unaligned users in the inline asm + block. */ + unsigned int saved_esp; + + __asm__ __volatile__( +#ifdef KEEP_STACK_16_BYTE_ALIGNED + "movl %%esp, %3\n\t" +#endif + "subl %8, %%esp\n\t" /* make room for params */ +#ifdef KEEP_STACK_16_BYTE_ALIGNED + /* For the second CALL, there will be one parameter before the ones + copied by invoke_copy_to_stack. Make sure that the stack will be + aligned for that CALL. */ + "subl $4, %%esp\n\t" + "andl $0xfffffff0, %%esp\n\t" + /* For the first CALL, there are three parameters. Leave padding to + ensure alignment. */ + "subl $4, %%esp\n\t" + /* The third parameter to invoke_copy_to_stack is the destination pointer. + It needs to point into the parameter area prepared for the second CALL, + leaving room for the |that| parameter. This reuses |n|, which was + the stack space to reserve, but that's OK because it's no longer needed + if the stack is being kept aligned. */ + "leal 8(%%esp), %8\n\t" + "pushl %8\n\t" +#else + "pushl %%esp\n\t" +#endif + "pushl %7\n\t" + "pushl %6\n\t" + "call *%9\n\t" /* copy params */ +#ifdef KEEP_STACK_16_BYTE_ALIGNED + /* The stack is still aligned from the first CALL. Keep it aligned for + the next one by popping past the parameters from the first CALL and + leaving space for the first (|that|) parameter for the second CALL. */ + "addl $0x14, %%esp\n\t" +#else + "addl $0xc, %%esp\n\t" +#endif + "movl %4, %%ecx\n\t" +#ifdef CFRONT_STYLE_THIS_ADJUST + "movl (%%ecx), %%edx\n\t" + "movl %5, %%eax\n\t" /* function index */ + "shl $3, %%eax\n\t" /* *= 8 */ + "addl $8, %%eax\n\t" /* += 8 skip first entry */ + "addl %%eax, %%edx\n\t" + "movswl (%%edx), %%eax\n\t" /* 'this' offset */ + "addl %%eax, %%ecx\n\t" + "pushl %%ecx\n\t" + "addl $4, %%edx\n\t" /* += 4, method pointer */ +#else /* THUNK_BASED_THIS_ADJUST */ + "pushl %%ecx\n\t" + "movl (%%ecx), %%edx\n\t" + "movl %5, %%eax\n\t" /* function index */ +#if defined(__GXX_ABI_VERSION) && __GXX_ABI_VERSION >= 100 /* G++ V3 ABI */ + "leal (%%edx,%%eax,4), %%edx\n\t" +#else /* not G++ V3 ABI */ + "leal 8(%%edx,%%eax,4), %%edx\n\t" +#endif /* G++ V3 ABI */ +#endif + "call *(%%edx)\n\t" /* safe to not cleanup esp */ +#ifdef KEEP_STACK_16_BYTE_ALIGNED + "movl %3, %%esp\n\t" +#else + "addl $4, %%esp\n\t" + "addl %8, %%esp" +#endif + : "=a" (result), /* %0 */ + "=c" (temp1), /* %1 */ + "=d" (temp2), /* %2 */ +#ifdef KEEP_STACK_16_BYTE_ALIGNED + "=&g" (saved_esp) /* %3 */ +#else + /* Don't waste a register, this isn't used if alignment is unimportant */ + "=m" (saved_esp) /* %3 */ +#endif + : "g" (that), /* %4 */ + "g" (methodIndex), /* %5 */ + "1" (paramCount), /* %6 */ + "2" (params), /* %7 */ +#ifdef KEEP_STACK_16_BYTE_ALIGNED + /* Must be in a register, it's the target of an LEA instruction */ + "r" (n), /* %8 */ +#else + "g" (n), /* %8 */ +#endif + "0" (fn_copy) /* %9 */ + : "memory" + ); + + return result; + +#else +#error "can't find a compiler to use" +#endif /* __GNUC__ */ + +} diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_unsupported.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_unsupported.cpp new file mode 100644 index 00000000..88219d8d --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_unsupported.cpp @@ -0,0 +1,48 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Platform specific code to invoke XPCOM methods on native objects */ + +#include "xptcprivate.h" + +XPTC_PUBLIC_API(nsresult) +XPTC_InvokeByIndex(nsISupports* that, PRUint32 methodIndex, + PRUint32 paramCount, nsXPTCVariant* params) +{ + NS_ASSERTION(0,"XPTC_InvokeByIndex called on unsupported platform"); + return NS_ERROR_NOT_IMPLEMENTED; +} diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_x86_64_linux.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_x86_64_linux.cpp new file mode 100644 index 00000000..b017c741 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_x86_64_linux.cpp @@ -0,0 +1,227 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** 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.org Code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +// Platform specific code to invoke XPCOM methods on native objects + +#include "xptcprivate.h" + +// 6 integral parameters are passed in registers +const PRUint32 GPR_COUNT = 6; + +// 8 floating point parameters are passed in SSE registers +const PRUint32 FPR_COUNT = 8; + +// Remember that these 'words' are 64-bit long +static inline void +invoke_count_words(PRUint32 paramCount, nsXPTCVariant * s, + PRUint32 & nr_gpr, PRUint32 & nr_fpr, PRUint32 & nr_stack) +{ + nr_gpr = 1; // skip one GP register for 'that' + nr_fpr = 0; + nr_stack = 0; + + /* Compute number of eightbytes of class MEMORY. */ + for (uint32 i = 0; i < paramCount; i++, s++) { + if (!s->IsPtrData() + && (s->type == nsXPTType::T_FLOAT || s->type == nsXPTType::T_DOUBLE)) { + if (nr_fpr < FPR_COUNT) + nr_fpr++; + else + nr_stack++; + } + else { + if (nr_gpr < GPR_COUNT) + nr_gpr++; + else + nr_stack++; + } + } +} + +static void +invoke_copy_to_stack(PRUint64 * d, PRUint32 paramCount, nsXPTCVariant * s, + PRUint64 * gpregs, double * fpregs) +{ + PRUint32 nr_gpr = 1; // skip one GP register for 'that' + PRUint32 nr_fpr = 0; + PRUint64 value; + + for (uint32 i = 0; i < paramCount; i++, s++) { + if (s->IsPtrData()) + value = (PRUint64) s->ptr; + else { + switch (s->type) { + case nsXPTType::T_FLOAT: break; + case nsXPTType::T_DOUBLE: break; + case nsXPTType::T_I8: value = s->val.i8; break; + case nsXPTType::T_I16: value = s->val.i16; break; + case nsXPTType::T_I32: value = s->val.i32; break; + case nsXPTType::T_I64: value = s->val.i64; break; + case nsXPTType::T_U8: value = s->val.u8; break; + case nsXPTType::T_U16: value = s->val.u16; break; + case nsXPTType::T_U32: value = s->val.u32; break; + case nsXPTType::T_U64: value = s->val.u64; break; + case nsXPTType::T_BOOL: value = s->val.b; break; + case nsXPTType::T_CHAR: value = s->val.c; break; + case nsXPTType::T_WCHAR: value = s->val.wc; break; + default: value = (PRUint64) s->val.p; break; + } + } + + if (!s->IsPtrData() && s->type == nsXPTType::T_DOUBLE) { + if (nr_fpr < FPR_COUNT) + fpregs[nr_fpr++] = s->val.d; + else { + *((double *)d) = s->val.d; + d++; + } + } + else if (!s->IsPtrData() && s->type == nsXPTType::T_FLOAT) { + if (nr_fpr < FPR_COUNT) + // The value in %xmm register is already prepared to + // be retrieved as a float. Therefore, we pass the + // value verbatim, as a double without conversion. + fpregs[nr_fpr++] = s->val.d; + else { + *((float *)d) = s->val.f; + d++; + } + } + else { + if (nr_gpr < GPR_COUNT) + gpregs[nr_gpr++] = value; + else + *d++ = value; + } + } +} + +extern "C" +XPTC_PUBLIC_API(nsresult) +XPTC_InvokeByIndex(nsISupports * that, PRUint32 methodIndex, + PRUint32 paramCount, nsXPTCVariant * params) +{ + PRUint32 nr_gpr, nr_fpr, nr_stack; + invoke_count_words(paramCount, params, nr_gpr, nr_fpr, nr_stack); + + // Stack, if used, must be 16-bytes aligned + if (nr_stack) + nr_stack = (nr_stack + 1) & ~1; + +#ifndef VBOX_WITH_GCC_SANITIZER + // Load parameters to stack, if necessary + PRUint64 *stack = (PRUint64 *) __builtin_alloca(nr_stack * 8); +#else + typedef struct { PRUint64 stack[20]; } methodStack; + if (nr_stack > 20) + return NS_ERROR_CALL_FAILED; + methodStack stack; +#endif + PRUint64 gpregs[GPR_COUNT]; + double fpregs[FPR_COUNT]; +#ifndef VBOX_WITH_GCC_SANITIZER + invoke_copy_to_stack(stack, paramCount, params, gpregs, fpregs); +#else + invoke_copy_to_stack(stack.stack, paramCount, params, gpregs, fpregs); +#endif + + // Load FPR registers from fpregs[] + register double d0 asm("xmm0"); + register double d1 asm("xmm1"); + register double d2 asm("xmm2"); + register double d3 asm("xmm3"); + register double d4 asm("xmm4"); + register double d5 asm("xmm5"); + register double d6 asm("xmm6"); + register double d7 asm("xmm7"); + + switch (nr_fpr) { +#define ARG_FPR(N) \ + case N+1: d##N = fpregs[N]; + ARG_FPR(7); + ARG_FPR(6); + ARG_FPR(5); + ARG_FPR(4); + ARG_FPR(3); + ARG_FPR(2); + ARG_FPR(1); + ARG_FPR(0); + case 0:; +#undef ARG_FPR + } + + // Load GPR registers from gpregs[] + register PRUint64 a0 asm("rdi"); + register PRUint64 a1 asm("rsi"); + register PRUint64 a2 asm("rdx"); + register PRUint64 a3 asm("rcx"); + register PRUint64 a4 asm("r8"); + register PRUint64 a5 asm("r9"); + + switch (nr_gpr) { +#define ARG_GPR(N) \ + case N+1: a##N = gpregs[N]; + ARG_GPR(5); + ARG_GPR(4); + ARG_GPR(3); + ARG_GPR(2); + ARG_GPR(1); + case 1: a0 = (PRUint64) that; + case 0:; +#undef ARG_GPR + } + + // Ensure that assignments to SSE registers won't be optimized away + asm("" :: + "x" (d0), "x" (d1), "x" (d2), "x" (d3), + "x" (d4), "x" (d5), "x" (d6), "x" (d7)); + + // Get pointer to method + PRUint64 methodAddress = *((PRUint64 *)that); + methodAddress += 8 * methodIndex; + methodAddress = *((PRUint64 *)methodAddress); + +#ifndef VBOX_WITH_GCC_SANITIZER + typedef PRUint32 (*Method)(PRUint64, PRUint64, PRUint64, PRUint64, PRUint64, PRUint64); + PRUint32 result = ((Method)methodAddress)(a0, a1, a2, a3, a4, a5); +#else + typedef PRUint32 (*Method)(PRUint64, PRUint64, PRUint64, PRUint64, PRUint64, PRUint64, methodStack); + PRUint32 result = ((Method)methodAddress)(a0, a1, a2, a3, a4, a5, stack); +#endif + return result; +} diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_x86_solaris.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_x86_solaris.cpp new file mode 100644 index 00000000..14ecb2d8 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_x86_solaris.cpp @@ -0,0 +1,285 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** 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.org Code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Platform specific code to invoke XPCOM methods on native objects */ + +#include "xptcprivate.h" +#include "xptc_platforms_unixish_x86.h" +#ifdef VBOX +# include +#endif + +extern "C" { + +// Remember that these 'words' are 32bit DWORDS + +static PRUint32 +invoke_count_words(PRUint32 paramCount, nsXPTCVariant* s) +{ + PRUint32 result = 0; + for(PRUint32 i = 0; i < paramCount; i++, s++) + { + if(s->IsPtrData()) + { + result++; + continue; + } + result++; + switch(s->type) + { + case nsXPTType::T_I64 : + case nsXPTType::T_U64 : + case nsXPTType::T_DOUBLE : + result++; + break; + } + } + return result; +} + +static void +invoke_copy_to_stack(PRUint32 paramCount, nsXPTCVariant* s, PRUint32* d) +{ + for(PRUint32 i = 0; i < paramCount; i++, d++, s++) + { + if(s->IsPtrData()) + { + *((void**)d) = s->ptr; + continue; + } + +/* XXX: the following line is here (rather than as the default clause in + * the following switch statement) so that the Sun native compiler + * will generate the correct assembly code on the Solaris Intel + * platform. See the comments in bug #28817 for more details. + */ + + *((void**)d) = s->val.p; + + switch(s->type) + { + case nsXPTType::T_I64 : *((PRInt64*) d) = s->val.i64; d++; break; + case nsXPTType::T_U64 : *((PRUint64*)d) = s->val.u64; d++; break; + case nsXPTType::T_DOUBLE : *((double*) d) = s->val.d; d++; break; + } + } +} + +} + +XPTC_PUBLIC_API(nsresult) +XPTC_InvokeByIndex(nsISupports* that, PRUint32 methodIndex, + PRUint32 paramCount, nsXPTCVariant* params) +{ +#ifdef __GNUC__ /* Gnu compiler. */ + PRUint32 result; + PRUint32 n = invoke_count_words (paramCount, params) * 4; + int temp1, temp2, temp3; + +# ifdef VBOX + /* This is for dealing with gcc 4.5.2 not using registers for 'g' parameters + and instead trying to get things like 'that' via %esp after we've changed it. */ +# if 1 /* safe version. */ + void (*fn_copy) (unsigned int, nsXPTCVariant *, PRUint32 *) = invoke_copy_to_stack; + struct Combined + { + PRUint32 that; /* offset: 0 */ + PRUint32 pfn; /* offset: 4 */ + PRUint32 savedEsp; /* offset: 8 */ + PRUint32 paramCount; /* offset: 12 */ + PRUint32 params; /* offset: 16 */ + } Combined; +# ifdef CFRONT_STYLE_THIS_ADJUST + struct CFRONTVTE { uintptr_t off, pfn } *pVtab = *(struct CFRONTVTE **)that; + Combined.that = (uintptr_t)that + pVtab[methodIndex + 1].off; + Combined.pfn = pVtab[methodIndex + 1].pfn; +# elif defined(__GXX_ABI_VERSION) && __GXX_ABI_VERSION >= 100 /* G++ V3 ABI */ + Combined.that = (uintptr_t)that; + Combined.pfn = (*(uintptr_t **)that)[methodIndex]; +# else /* not G++ V3 ABI */ + Combined.that = (uintptr_t)that; + Combined.pfn = (*(uintptr_t **)that)[2 + methodIndex]; +# endif /* G++ V3 ABI */ + Combined.paramCount = paramCount; + Combined.params = (uintptr_t)params; + + __asm__ __volatile__( + "mov %%esp, 8(%%esi)\n\t" /* savedEsp = %esp */ + "subl %1, %%esp\n\t" /* make room for params */ + + /* Call invoke_count_words to copy the parameters. */ + "pushl %%esp\n\t" /* arg2: dest */ + "pushl 16(%%esi)\n\t" /* arg1: params */ + "pushl 12(%%esi)\n\t" /* arg0: paramCount */ + "call *%0\n\t" + "addl $0xc, %%esp\n\t" + + /* Push the this pointer. */ + "pushl (%%esi)\n\t" /* that */ + "call *4(%%esi)\n\t" + "mov 8(%%esi), %%esp\n\t" + : "=a" (result), /* %0 */ + "=c" (temp1), /* %1 */ + "=d" (temp2) /* %2 */ + : "S" (&Combined), /* %3 */ + "0" (fn_copy), + "1" (n) + : "memory" + ); + +# else /* Small version; ASSUMES nothing important gets put on the stack after the the alloca. */ + uintptr_t *pauStack = (uintptr_t *)alloca(n + sizeof(uintptr_t)); + invoke_copy_to_stack(paramCount, params, &pauStack[1]); +# ifdef CFRONT_STYLE_THIS_ADJUST + struct CFRONTVTE { uintptr_t off, pfn } *pVtab = *(struct CFRONTVTE **)that; + pauStack[0] = (uintptr_t)that + pVtab[methodIndex + 1].off; + uintptr_t pfn = pVtab[methodIndex + 1].pfn; +# elif defined(__GXX_ABI_VERSION) && __GXX_ABI_VERSION >= 100 /* G++ V3 ABI */ + pauStack[0] = (uintptr_t)that; + uintptr_t pfn = (*(uintptr_t **)that)[methodIndex]; +# else /* not G++ V3 ABI */ + pauStack[0] = (uintptr_t)that; + uintptr_t pfn = (*(uintptr_t **)that)[2 + methodIndex]; +# endif /* G++ V3 ABI */ + + __asm__ __volatile__( + "xchg %%esp, %3\n\t" /* save+load %esp */ + "call *%0\n\t" + "xchg %%esp, %3\n\t" /* restore %esp */ + : "=a" (result), /* %0 */ + "=c" (temp1), /* %1 */ + "=d" (temp2) /* %2 */ + : "S" (pauStack), /* %3 */ + "0" (pfn) + : "memory" + ); +# endif + +# else /* !VBOX */ + void (*fn_copy) (unsigned int, nsXPTCVariant *, PRUint32 *) = invoke_copy_to_stack; + __asm__ __volatile__( + "subl %8, %%esp\n\t" /* make room for params */ + "pushl %%esp\n\t" + "pushl %7\n\t" + "pushl %6\n\t" + "call *%0\n\t" /* copy params */ + "addl $0xc, %%esp\n\t" + "movl %4, %%ecx\n\t" +#ifdef CFRONT_STYLE_THIS_ADJUST + "movl (%%ecx), %%edx\n\t" + "movl %5, %%eax\n\t" /* function index */ + "shl $3, %%eax\n\t" /* *= 8 */ + "addl $8, %%eax\n\t" /* += 8 skip first entry */ + "addl %%eax, %%edx\n\t" + "movswl (%%edx), %%eax\n\t" /* 'this' offset */ + "addl %%eax, %%ecx\n\t" + "pushl %%ecx\n\t" + "addl $4, %%edx\n\t" /* += 4, method pointer */ +#else /* THUNK_BASED_THIS_ADJUST */ + "pushl %%ecx\n\t" + "movl (%%ecx), %%edx\n\t" + "movl %5, %%eax\n\t" /* function index */ +#if defined(__GXX_ABI_VERSION) && __GXX_ABI_VERSION >= 100 /* G++ V3 ABI */ + "leal (%%edx,%%eax,4), %%edx\n\t" +#else /* not G++ V3 ABI */ + "leal 8(%%edx,%%eax,4), %%edx\n\t" +#endif /* G++ V3 ABI */ +#endif + "call *(%%edx)\n\t" /* safe to not cleanup esp */ + "addl $4, %%esp\n\t" + "addl %8, %%esp" + : "=a" (result), /* %0 */ + "=c" (temp1), /* %1 */ + "=d" (temp2), /* %2 */ + "=g" (temp3) /* %3 */ + : "g" (that), /* %4 */ + "g" (methodIndex), /* %5 */ + "1" (paramCount), /* %6 */ + "2" (params), /* %7 */ + "g" (n), /* %8 */ + "0" (fn_copy) /* %3 */ + : "memory" + ); +# endif /* !VBOX */ + + return result; +#elif defined(__SUNPRO_CC) /* Sun Workshop Compiler. */ + +asm( + "\n\t /: PRUint32 n = invoke_count_words (paramCount, params) * 4;" + + "\n\t pushl %ebx / preserve ebx" + "\n\t pushl %esi / preserve esi" + "\n\t movl %esp, %ebx / save address of pushed esi and ebx" + + "\n\t pushl 20(%ebp) / \"params\"" + "\n\t pushl 16(%ebp) / \"paramCount\"" + "\n\t call invoke_count_words" + "\n\t mov %ebx, %esp / restore esp" + + "\n\t sall $2,%eax" + "\n\t subl %eax, %esp / make room for arguments" + "\n\t movl %esp, %esi / save new esp" + + "\n\t pushl %esp" + "\n\t pushl 20(%ebp) / \"params\"" + "\n\t pushl 16(%ebp) / \"paramCount\"" + "\n\t call invoke_copy_to_stack / copy params" + "\n\t movl %esi, %esp / restore new esp" + + "\n\t movl 8(%ebp),%ecx / \"that\"" + "\n\t pushl %ecx / \"that\"" + "\n\t movl (%ecx), %edx" + "\n\t movl 12(%ebp), %eax / function index: \"methodIndex\"" + "\n\t movl 8(%edx,%eax,4), %edx" + + "\n\t call *%edx" + "\n\t mov %ebx, %esp" + "\n\t popl %esi" + "\n\t popl %ebx" +); + +/* result == %eax */ + if(0) /* supress "*** is expected to return a value." error */ + return 0; + +#else +#error "can't find a compiler to use" +#endif /* __GNUC__ */ + +} diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_amd64_darwin.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_amd64_darwin.cpp new file mode 100644 index 00000000..5b55c930 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_amd64_darwin.cpp @@ -0,0 +1,243 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** 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.org Code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +// Implement shared vtbl methods. + +#include "xptcprivate.h" + +// The Linux/x86-64 ABI passes the first 6 integer parameters and the +// first 8 floating point parameters in registers (rdi, rsi, rdx, rcx, +// r8, r9 and xmm0-xmm7), no stack space is allocated for these by the +// caller. The rest of the parameters are passed in the callers stack +// area. + +const PRUint32 PARAM_BUFFER_COUNT = 16; +const PRUint32 GPR_COUNT = 6; +const PRUint32 FPR_COUNT = 8; + +// PrepareAndDispatch() is called by SharedStub() and calls the actual method. +// +// - 'args[]' contains the arguments passed on stack +// - 'gpregs[]' contains the arguments passed in integer registers +// - 'fpregs[]' contains the arguments passed in floating point registers +// +// The parameters are mapped into an array of type 'nsXPTCMiniVariant' +// and then the method gets called. + +extern "C" nsresult +PrepareAndDispatch(nsXPTCStubBase * self, PRUint32 methodIndex, + PRUint64 * args, PRUint64 * gpregs, double *fpregs) +{ + nsXPTCMiniVariant paramBuffer[PARAM_BUFFER_COUNT]; + nsXPTCMiniVariant* dispatchParams = NULL; + nsIInterfaceInfo* iface_info = NULL; + const nsXPTMethodInfo* info = NULL; + PRUint32 paramCount; + PRUint32 i; + nsresult result = NS_ERROR_FAILURE; + + NS_ASSERTION(self,"no self"); + + self->GetInterfaceInfo(&iface_info); + NS_ASSERTION(iface_info,"no interface info"); + if (!iface_info) + return NS_ERROR_UNEXPECTED; + + iface_info->GetMethodInfo(PRUint16(methodIndex), &info); + NS_ASSERTION(info,"no method info"); + if (!info) + return NS_ERROR_UNEXPECTED; + + paramCount = info->GetParamCount(); + + // setup variant array pointer + if (paramCount > PARAM_BUFFER_COUNT) + dispatchParams = new nsXPTCMiniVariant[paramCount]; + else + dispatchParams = paramBuffer; + + NS_ASSERTION(dispatchParams,"no place for params"); + if (!dispatchParams) + return NS_ERROR_OUT_OF_MEMORY; + + PRUint64* ap = args; + PRUint32 nr_gpr = 1; // skip one GPR register for 'that' + PRUint32 nr_fpr = 0; + PRUint64 value; + + for (i = 0; i < paramCount; i++) { + const nsXPTParamInfo& param = info->GetParam(i); + const nsXPTType& type = param.GetType(); + nsXPTCMiniVariant* dp = &dispatchParams[i]; + + if (!param.IsOut() && type == nsXPTType::T_DOUBLE) { + if (nr_fpr < FPR_COUNT) + dp->val.d = fpregs[nr_fpr++]; + else + dp->val.d = *(double*) ap++; + continue; + } + else if (!param.IsOut() && type == nsXPTType::T_FLOAT) { + if (nr_fpr < FPR_COUNT) + // The value in %xmm register is already prepared to + // be retrieved as a float. Therefore, we pass the + // value verbatim, as a double without conversion. + dp->val.d = *(double*) ap++; + else + dp->val.f = *(float*) ap++; + continue; + } + else { + if (nr_gpr < GPR_COUNT) + value = gpregs[nr_gpr++]; + else + value = *ap++; + } + + if (param.IsOut() || !type.IsArithmetic()) { + dp->val.p = (void*) value; + continue; + } + + switch (type) { + case nsXPTType::T_I8: dp->val.i8 = (PRInt8) value; break; + case nsXPTType::T_I16: dp->val.i16 = (PRInt16) value; break; + case nsXPTType::T_I32: dp->val.i32 = (PRInt32) value; break; + case nsXPTType::T_I64: dp->val.i64 = (PRInt64) value; break; + case nsXPTType::T_U8: dp->val.u8 = (PRUint8) value; break; + case nsXPTType::T_U16: dp->val.u16 = (PRUint16) value; break; + case nsXPTType::T_U32: dp->val.u32 = (PRUint32) value; break; + case nsXPTType::T_U64: dp->val.u64 = (PRUint64) value; break; + case nsXPTType::T_BOOL: dp->val.b = (PRBool) value; break; + case nsXPTType::T_CHAR: dp->val.c = (char) value; break; + case nsXPTType::T_WCHAR: dp->val.wc = (wchar_t) value; break; + + default: + NS_ASSERTION(0, "bad type"); + break; + } + } + + result = self->CallMethod((PRUint16) methodIndex, info, dispatchParams); + + NS_RELEASE(iface_info); + + if (dispatchParams != paramBuffer) + delete [] dispatchParams; + + return result; +} + +#if defined(__GXX_ABI_VERSION) && __GXX_ABI_VERSION >= 100 /* G++ V3 ABI */ +// Darwin/AMD64 uses gcc >= 3.1 +#define STUB_ENTRY(n) \ +asm(".text\n\t" \ + ".align 2\n\t" \ + ".if " #n " < 10\n\t" \ + ".globl __ZN14nsXPTCStubBase5Stub" #n "Ev\n\t" \ + /*".type __ZN14nsXPTCStubBase5Stub" #n "Ev,@function\n"*/ \ + "__ZN14nsXPTCStubBase5Stub" #n "Ev:\n\t" \ + ".elseif " #n " < 100\n\t" \ + ".globl __ZN14nsXPTCStubBase6Stub" #n "Ev\n\t" \ + /*".type __ZN14nsXPTCStubBase6Stub" #n "Ev,@function\n"*/ \ + "__ZN14nsXPTCStubBase6Stub" #n "Ev:\n\t" \ + ".elseif " #n " < 1000\n\t" \ + ".globl __ZN14nsXPTCStubBase7Stub" #n "Ev\n\t" \ + /*".type __ZN14nsXPTCStubBase7Stub" #n "Ev,@function\n"*/ \ + "__ZN14nsXPTCStubBase7Stub" #n "Ev:\n\t" \ + ".else\n\t" \ + ".err \"stub number " #n " >= 1000 not yet supported\"\n\t" \ + ".endif\n\t" \ + "movl $" #n ", %eax\n\t" \ + "jmp SharedStub\n\t" \ + ".if " #n " < 10\n\t" \ + /*".size __ZN14nsXPTCStubBase5Stub" #n "Ev,.-__ZN14nsXPTCStubBase5Stub" #n "Ev\n\t"*/ \ + ".elseif " #n " < 100\n\t" \ + /*".size __ZN14nsXPTCStubBase6Stub" #n "Ev,.-__ZN14nsXPTCStubBase6Stub" #n "Ev\n\t"*/ \ + ".else\n\t" \ + /*".size __ZN14nsXPTCStubBase7Stub" #n "Ev,.-__ZN14nsXPTCStubBase7Stub" #n "Ev\n\t"*/ \ + ".endif"); + +// static nsresult SharedStub(PRUint32 methodIndex) [methodIndex is in eax]. +asm(".text\n\t" + ".align 2\n\t" +/* ".type SharedStub,@function\n\t" */ + "SharedStub:\n\t" + // make room for gpregs (48), fpregs (64) + "pushq %rbp\n\t" + "movq %rsp,%rbp\n\t" + "subq $112,%rsp\n\t" + // save GP registers + "movq %rdi,-112(%rbp)\n\t" + "movq %rsi,-104(%rbp)\n\t" + "movq %rdx, -96(%rbp)\n\t" + "movq %rcx, -88(%rbp)\n\t" + "movq %r8 , -80(%rbp)\n\t" + "movq %r9 , -72(%rbp)\n\t" + "leaq -112(%rbp),%rcx\n\t" + // save FP registers + "movsd %xmm0,-64(%rbp)\n\t" + "movsd %xmm1,-56(%rbp)\n\t" + "movsd %xmm2,-48(%rbp)\n\t" + "movsd %xmm3,-40(%rbp)\n\t" + "movsd %xmm4,-32(%rbp)\n\t" + "movsd %xmm5,-24(%rbp)\n\t" + "movsd %xmm6,-16(%rbp)\n\t" + "movsd %xmm7, -8(%rbp)\n\t" + "leaq -64(%rbp),%r8\n\t" + // rdi has the 'self' pointer already + "movl %eax,%esi\n\t" + "leaq 16(%rbp),%rdx\n\t" + "call _PrepareAndDispatch\n\t" + "leave\n\t" + "ret\n\t" +/* ".size SharedStub,.-SharedStub" */ + ); + +#define SENTINEL_ENTRY(n) \ +nsresult nsXPTCStubBase::Sentinel##n() \ +{ \ + NS_ASSERTION(0,"nsXPTCStubBase::Sentinel called"); \ + return NS_ERROR_NOT_IMPLEMENTED; \ +} + +#include "xptcstubsdef.inc" + +#else +#error "Unsupported compiler. Use gcc >= 3.1 for Darwin/AMD64." +#endif /* __GNUC__ */ diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_arm.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_arm.cpp new file mode 100644 index 00000000..fc90ecea --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_arm.cpp @@ -0,0 +1,244 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Russell King + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Implement shared vtbl methods. */ + +#include "xptcprivate.h" + +#if !defined(LINUX) || !defined(__arm__) +#error "This code is for Linux ARM only. Please check if it works for you, too.\nDepends strongly on gcc behaviour." +#endif + +/* Specify explicitly a symbol for this function, don't try to guess the c++ mangled symbol. */ +static nsresult PrepareAndDispatch(nsXPTCStubBase* self, uint32 methodIndex, PRUint32* args) asm("_PrepareAndDispatch"); + +static nsresult +PrepareAndDispatch(nsXPTCStubBase* self, uint32 methodIndex, PRUint32* args) +{ +#define PARAM_BUFFER_COUNT 16 + + nsXPTCMiniVariant paramBuffer[PARAM_BUFFER_COUNT]; + nsXPTCMiniVariant* dispatchParams = NULL; + nsIInterfaceInfo* iface_info = NULL; + const nsXPTMethodInfo* info; + PRUint8 paramCount; + PRUint8 i; + nsresult result = NS_ERROR_FAILURE; + + NS_ASSERTION(self,"no self"); + + self->GetInterfaceInfo(&iface_info); + NS_ASSERTION(iface_info,"no interface info"); + + iface_info->GetMethodInfo(PRUint16(methodIndex), &info); + NS_ASSERTION(info,"no interface info"); + + paramCount = info->GetParamCount(); + + // setup variant array pointer + if(paramCount > PARAM_BUFFER_COUNT) + dispatchParams = new nsXPTCMiniVariant[paramCount]; + else + dispatchParams = paramBuffer; + NS_ASSERTION(dispatchParams,"no place for params"); + + PRUint32* ap = args; + for(i = 0; i < paramCount; i++, ap++) + { + const nsXPTParamInfo& param = info->GetParam(i); + const nsXPTType& type = param.GetType(); + nsXPTCMiniVariant* dp = &dispatchParams[i]; + + if(param.IsOut() || !type.IsArithmetic()) + { + dp->val.p = (void*) *ap; + continue; + } + // else + switch(type) + { + case nsXPTType::T_I8 : dp->val.i8 = *((PRInt8*) ap); break; + case nsXPTType::T_I16 : dp->val.i16 = *((PRInt16*) ap); break; + case nsXPTType::T_I32 : dp->val.i32 = *((PRInt32*) ap); break; + case nsXPTType::T_I64 : dp->val.i64 = *((PRInt64*) ap); ap++; break; + case nsXPTType::T_U8 : dp->val.u8 = *((PRUint8*) ap); break; + case nsXPTType::T_U16 : dp->val.u16 = *((PRUint16*)ap); break; + case nsXPTType::T_U32 : dp->val.u32 = *((PRUint32*)ap); break; + case nsXPTType::T_U64 : dp->val.u64 = *((PRUint64*)ap); ap++; break; + case nsXPTType::T_FLOAT : dp->val.f = *((float*) ap); break; + case nsXPTType::T_DOUBLE : dp->val.d = *((double*) ap); ap++; break; + case nsXPTType::T_BOOL : dp->val.b = *((PRBool*) ap); break; + case nsXPTType::T_CHAR : dp->val.c = *((char*) ap); break; + case nsXPTType::T_WCHAR : dp->val.wc = *((wchar_t*) ap); break; + default: + NS_ASSERTION(0, "bad type"); + break; + } + } + + result = self->CallMethod((PRUint16)methodIndex, info, dispatchParams); + + NS_RELEASE(iface_info); + + if(dispatchParams != paramBuffer) + delete [] dispatchParams; + + return result; +} + +/* + * This is our shared stub. + * + * r0 = Self. + * + * The Rules: + * We pass an (undefined) number of arguments into this function. + * The first 3 C++ arguments are in r1 - r3, the rest are built + * by the calling function on the stack. + * + * We are allowed to corrupt r0 - r3, ip, and lr. + * + * Other Info: + * We pass the stub number in using `ip'. + * + * Implementation: + * - We save r1 to r3 inclusive onto the stack, which will be + * immediately below the caller saved arguments. + * - setup r2 (PrepareAndDispatch's args pointer) to point at + * the base of all these arguments + * - Save LR (for the return address) + * - Set r1 (PrepareAndDispatch's methodindex argument) from ip + * - r0 is passed through (self) + * - Call PrepareAndDispatch + * - When the call returns, we return by loading the PC off the + * stack, and undoing the stack (one instruction)! + * + */ +__asm__ ("\n\ +SharedStub: \n\ + stmfd sp!, {r1, r2, r3} \n\ + mov r2, sp \n\ + str lr, [sp, #-4]! \n\ + mov r1, ip \n\ + bl _PrepareAndDispatch \n\ + ldr pc, [sp], #16"); + +/* + * Create sets of stubs to call the SharedStub. + * We don't touch the stack here, nor any registers, other than IP. + * IP is defined to be corruptable by a called function, so we are + * safe to use it. + * + * This will work with or without optimisation. + */ +#if defined(__GXX_ABI_VERSION) && __GXX_ABI_VERSION >= 100 /* G++ V3 ABI */ +/* + * Note : As G++3 ABI contains the length of the functionname in the + * mangled name, it is difficult to get a generic assembler mechanism like + * in the G++ 2.95 case. + * Create names would be like : + * _ZN14nsXPTCStubBase5Stub9Ev + * _ZN14nsXPTCStubBase6Stub13Ev + * _ZN14nsXPTCStubBase7Stub144Ev + * Use the assembler directives to get the names right... + */ + +#define STUB_ENTRY(n) \ + __asm__( \ + ".section \".text\"\n" \ +" .align 2\n" \ +" .iflt ("#n" - 10)\n" \ +" .globl _ZN14nsXPTCStubBase5Stub"#n"Ev\n" \ +" .type _ZN14nsXPTCStubBase5Stub"#n"Ev,#function\n" \ +"_ZN14nsXPTCStubBase5Stub"#n"Ev:\n" \ +" .else\n" \ +" .iflt ("#n" - 100)\n" \ +" .globl _ZN14nsXPTCStubBase6Stub"#n"Ev\n" \ +" .type _ZN14nsXPTCStubBase6Stub"#n"Ev,#function\n" \ +"_ZN14nsXPTCStubBase6Stub"#n"Ev:\n" \ +" .else\n" \ +" .iflt ("#n" - 1000)\n" \ +" .globl _ZN14nsXPTCStubBase7Stub"#n"Ev\n" \ +" .type _ZN14nsXPTCStubBase7Stub"#n"Ev,#function\n" \ +"_ZN14nsXPTCStubBase7Stub"#n"Ev:\n" \ +" .else\n" \ +" .err \"stub number "#n"> 1000 not yet supported\"\n" \ +" .endif\n" \ +" .endif\n" \ +" .endif\n" \ +" mov ip, #"#n"\n" \ +" b SharedStub\n\t"); + +#if 0 +/* + * This part is left in as comment : this is how the method definition + * should look like. + */ + +#define STUB_ENTRY(n) \ +nsresult nsXPTCStubBase::Stub##n () \ +{ \ + __asm__ ( \ +" mov ip, #"#n"\n" \ +" b SharedStub\n\t"); \ + return 0; /* avoid warnings */ \ +} +#endif + +#else /* G++2.95 ABI */ + +#define STUB_ENTRY(n) \ + __asm__( \ + ".section \".text\"\n" \ +" .align\n" \ +" .globl Stub"#n"__14nsXPTCStubBase\n" \ +" .type Stub"#n"__14nsXPTCStubBase,#function\n\n" \ +"Stub"#n"__14nsXPTCStubBase:\n" \ +" mov ip, #"#n"\n" \ +" b SharedStub\n\t"); + +#endif + +#define SENTINEL_ENTRY(n) \ +nsresult nsXPTCStubBase::Sentinel##n() \ +{ \ + NS_ASSERTION(0,"nsXPTCStubBase::Sentinel called"); \ + return NS_ERROR_NOT_IMPLEMENTED; \ +} + +#include "xptcstubsdef.inc" diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_arm64_vbox.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_arm64_vbox.cpp new file mode 100644 index 00000000..82856234 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_arm64_vbox.cpp @@ -0,0 +1,272 @@ +/* $Id: xptcstubs_arm64_vbox.cpp $ */ +/** @file + * XPCOM - XPTC stubs for arm64. + */ + +/* + * Copyright (C) 2021-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * SPDX-License-Identifier: GPL-3.0-only + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include "xptcprivate.h" +#include +#include +#include + + +/********************************************************************************************************************************* +* Defined Constants And Macros * +*********************************************************************************************************************************/ +#if defined(RT_OS_DARWIN) +# define NAME_PREFIX _ +# define NAME_PREFIX_STR "_" +#else +# define NAME_PREFIX +# define NAME_PREFIX_STR "" +#endif +#define ASMNAME(a_Name) NAME_PREFIX ## a_Name +#define NUM_ARGS_IN_GPRS 8 /**< Number of arguments passed in general purpose registers (starting with x0). */ +#define NUM_ARGS_IN_FPRS 8 /**< Number of arguments passed in floating point registers (starting with d0). */ + + +/********************************************************************************************************************************* +* Internal Functions * +*********************************************************************************************************************************/ +extern "C" __attribute__((naked)) nsresult CommonXPTCStub(void); +DECL_NO_INLINE(extern "C", nsresult) +CommonXPTCStubCWorker(nsXPTCStubBase *pThis, uint32_t idxMethod, uint64_t *pauGprArgs, uint64_t *pauFprArgs, uint64_t *puStackArgs); + + +/** + * All the stubs call this shared code w/ method index in w17. + * + * The naked attribute means pure inline assembly function. clang complains + * if we put C statements in it. So, this exacty what we need here and for the + * stubs. + * + * @note This could be static if we weren't afraid the compile would optimize it + * out. + */ +extern "C" __attribute__((naked)) nsresult CommonXPTCStub(void) +{ + __asm__ __volatile__( + /* Prologue - reserve space for frame+link reg spill and the GPR and FPR arrays. */ "\ + sub sp, sp, %[cbGPRandFPRs] + 16 \n\ + stp x29, x30, [sp, %[cbGPRandFPRs]] \n\ + add x29, sp, %[cbGPRandFPRs] \n\ + .cfi_def_cfa x29, 16 \n\ + .cfi_rel_offset x30, -8 \n\ + .cfi_rel_offset x29, -16 \n\ +" + /* reserve stack space for the integer and floating point registers and save them: */ "\ + \n\ + stp x0, x1, [sp, #0] \n\ + stp x2, x3, [sp, #16] \n\ + stp x4, x5, [sp, #32] \n\ + stp x6, x7, [sp, #48] \n\ + \n\ + stp d0, d1, [sp, %[cbGPRs]] \n\ + stp d2, d3, [sp, %[cbGPRs] + 16] \n\ + stp d4, d5, [sp, %[cbGPRs] + 32] \n\ + stp d6, d7, [sp, %[cbGPRs] + 48] \n\ +\n" + /* Call the C worker. We keep x0 as is. + Set w1 to the w17 method index from the stubs. */ "\ + mov w1, w17 \n\ + mov x2, sp \n\ + add x3, sp, %[cbGPRs] \n\ + add x4, sp, %[cbGPRandFPRs] + 16 \n\ + bl " NAME_PREFIX_STR "CommonXPTCStubCWorker \n\ +" + /* Epilogue (clang does not emit the .cfi's here, so drop them too?): */ "\ + ldp x29, x30, [sp, %[cbGPRandFPRs]] \n\ + add sp, sp, %[cbGPRandFPRs] + 16 \n\ + .cfi_def_cfa sp, 0 \n\ + .cfi_restore x29 \n\ + .cfi_restore x30 \n\ + ret \n\ +" : + : [cbGPRandFPRs] "i" (NUM_ARGS_IN_GPRS * 8 + NUM_ARGS_IN_FPRS * 8) + , [cbGPRs] "i" (NUM_ARGS_IN_GPRS * 8) + :); +} + +#define STUB_ENTRY(n) \ + __attribute__((naked)) nsresult nsXPTCStubBase::Stub##n() \ + { \ + __asm__ __volatile__ ("mov w17, #" #n "\n\t" \ + "b " NAME_PREFIX_STR "CommonXPTCStub\n\t"); \ + } + +#define SENTINEL_ENTRY(n) \ + nsresult nsXPTCStubBase::Sentinel##n() \ + { \ + AssertMsgFailed(("nsXPTCStubBase::Sentinel" #n " called!\n")); \ + return NS_ERROR_NOT_IMPLEMENTED; \ + } + +/* Instantiate the stubs and sentinels */ +#include "xptcstubsdef.inc" + + + +/* + * Function templates for fetching arguments + */ + +template static inline void fetchStack(Type *pRet, uint64_t *&rpuStackArgs) +{ +#ifdef RT_OS_DARWIN /* macOS compacts stack usage. */ + Type *pStackTmp = RT_ALIGN_PT(rpuStackArgs, sizeof(Type), Type *); + *pRet = *pStackTmp; + rpuStackArgs = (uint64_t *)(pStackTmp + 1); +#else + *pRet = (Type)*rpuStackArgs++; +#endif +} + +template static inline void fetchFpr(Type *pRet, uint64_t *pauFprArgs, unsigned &ridxFpr, uint64_t *&rpuStackArgs) +{ + if (ridxFpr < NUM_ARGS_IN_FPRS) + *pRet = (Type)pauFprArgs[ridxFpr++]; + else + fetchStack(pRet, rpuStackArgs); +} + + +template static inline void fetchGpr(Type *pRet, uint64_t *pauGprArgs, unsigned &ridxGpr, uint64_t *&rpuStackArgs) +{ + if (ridxGpr < NUM_ARGS_IN_GPRS) + *pRet = (Type)pauGprArgs[ridxGpr++]; + else + fetchStack(pRet, rpuStackArgs); +} + + +/** + * Called by CommonXPTCStub below after it dumps registers and locates + * arguments on the stack (if any). + */ +DECL_NO_INLINE(extern "C", nsresult) +CommonXPTCStubCWorker(nsXPTCStubBase *pThis, uint32_t idxMethod, uint64_t *pauGprArgs, uint64_t *pauFprArgs, uint64_t *puStackArgs) +{ + AssertReturn(pThis, NS_ERROR_UNEXPECTED); + + /* Get method information: */ + nsIInterfaceInfo *pInterfaceInfo = NULL; + nsresult hrc = pThis->GetInterfaceInfo(&pInterfaceInfo); + AssertReturn(NS_SUCCEEDED(hrc), hrc); + AssertReturn(pInterfaceInfo, NS_ERROR_UNEXPECTED); + + const nsXPTMethodInfo *pMethodInfo; + hrc = pInterfaceInfo->GetMethodInfo((PRUint16)idxMethod, &pMethodInfo); + AssertReturn(NS_SUCCEEDED(hrc), hrc); + AssertReturn(pMethodInfo, NS_ERROR_UNEXPECTED); + + /* Allocate dispatcher parameter array. */ + PRUint8 const cParams = pMethodInfo->GetParamCount(); + nsXPTCMiniVariant aParamsStatic[8]; + nsXPTCMiniVariant *paParams; + if (cParams <= RT_ELEMENTS(aParamsStatic)) + paParams = aParamsStatic; + else + { + paParams = (nsXPTCMiniVariant *)alloca(sizeof(paParams[0]) * cParams); + AssertReturn(paParams, NS_ERROR_UNEXPECTED); + } + + /* + * Populate the dispatcher parameter array. + */ + unsigned idxGprArgs = 1; /* The 'pThis' pointer (x0) is not included in cParams. */ + unsigned idxFprArgs = 0; + for (PRUint8 i = 0; i < cParams; i++) + { + const nsXPTParamInfo &rParam = pMethodInfo->GetParam(i); + if (rParam.IsOut()) + fetchGpr(&paParams[i].val.p, pauGprArgs, idxGprArgs, puStackArgs); + else + { + const nsXPTType Type = rParam.GetType(); + switch (Type) + { + case nsXPTType::T_I8: fetchGpr(&paParams[i].val.i8, pauGprArgs, idxGprArgs, puStackArgs); break; + case nsXPTType::T_I16: fetchGpr(&paParams[i].val.i16, pauGprArgs, idxGprArgs, puStackArgs); break; + case nsXPTType::T_I32: fetchGpr(&paParams[i].val.i32, pauGprArgs, idxGprArgs, puStackArgs); break; + case nsXPTType::T_I64: fetchGpr(&paParams[i].val.i64, pauGprArgs, idxGprArgs, puStackArgs); break; + case nsXPTType::T_U8: fetchGpr(&paParams[i].val.u8, pauGprArgs, idxGprArgs, puStackArgs); break; + case nsXPTType::T_U16: fetchGpr(&paParams[i].val.u16, pauGprArgs, idxGprArgs, puStackArgs); break; + case nsXPTType::T_U32: fetchGpr(&paParams[i].val.u32, pauGprArgs, idxGprArgs, puStackArgs); break; + case nsXPTType::T_U64: fetchGpr(&paParams[i].val.u64, pauGprArgs, idxGprArgs, puStackArgs); break; + case nsXPTType::T_BOOL: fetchGpr(&paParams[i].val.b, pauGprArgs, idxGprArgs, puStackArgs); break; + case nsXPTType::T_CHAR: fetchGpr(&paParams[i].val.c, pauGprArgs, idxGprArgs, puStackArgs); break; + case nsXPTType::T_WCHAR: fetchGpr(&paParams[i].val.wc, pauGprArgs, idxGprArgs, puStackArgs); break; + + case nsXPTType::T_FLOAT: fetchFpr(&paParams[i].val.f, pauFprArgs, idxFprArgs, puStackArgs); break; + case nsXPTType::T_DOUBLE: fetchFpr(&paParams[i].val.d, pauFprArgs, idxFprArgs, puStackArgs); break; + + default: + if (!Type.IsArithmetic()) + fetchGpr(&paParams[i].val.p, pauGprArgs, idxGprArgs, puStackArgs); + else + AssertMsgFailedReturn(("%#x idxMethod=%#x\n",(unsigned)Type, idxMethod), NS_ERROR_UNEXPECTED); + break; + } + } + } + + /* + * Dispatch the method call. + */ + hrc = pThis->CallMethod((PRUint16)idxMethod, pMethodInfo, paParams); + + NS_RELEASE(pInterfaceInfo); + return hrc; + +} + +#if 0 +extern "C" nsresult CommonXPTCStubTest(uint64_t x0, + uint64_t x1, + uint64_t x2, + uint64_t x3, + uint64_t x4, + uint64_t x5, + uint64_t x6, + uint64_t x7) +{ + uint64_t aGprs[8]; + aGprs[0] = x0; + aGprs[1] = x1; + aGprs[2] = x2; + aGprs[3] = x3; + aGprs[4] = x4; + aGprs[5] = x5; + aGprs[6] = x6; + aGprs[7] = x7; + + return CommonXPTCStubCWorker((nsXPTCStubBase *)x0, x1, aGprs, aGprs, aGprs); +} +#endif + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_arm_netbsd.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_arm_netbsd.cpp new file mode 100644 index 00000000..47c09a42 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_arm_netbsd.cpp @@ -0,0 +1,145 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Implement shared vtbl methods. */ + +#include "xptcprivate.h" + +nsresult +PrepareAndDispatch(nsXPTCStubBase* self, uint32 methodIndex, PRUint32* args) +{ +#define PARAM_BUFFER_COUNT 16 + + nsXPTCMiniVariant paramBuffer[PARAM_BUFFER_COUNT]; + nsXPTCMiniVariant* dispatchParams = NULL; + nsIInterfaceInfo* iface_info = NULL; + const nsXPTMethodInfo* info; + PRUint8 paramCount; + PRUint8 i; + nsresult result = NS_ERROR_FAILURE; + + NS_ASSERTION(self,"no self"); + + self->GetInterfaceInfo(&iface_info); + NS_ASSERTION(iface_info,"no interface info"); + + iface_info->GetMethodInfo(PRUint16(methodIndex), &info); + NS_ASSERTION(info,"no interface info"); + + paramCount = info->GetParamCount(); + + // setup variant array pointer + if(paramCount > PARAM_BUFFER_COUNT) + dispatchParams = new nsXPTCMiniVariant[paramCount]; + else + dispatchParams = paramBuffer; + NS_ASSERTION(dispatchParams,"no place for params"); + + PRUint32* ap = args; + for(i = 0; i < paramCount; i++, ap++) + { + const nsXPTParamInfo& param = info->GetParam(i); + const nsXPTType& type = param.GetType(); + nsXPTCMiniVariant* dp = &dispatchParams[i]; + + if(param.IsOut() || !type.IsArithmetic()) + { + dp->val.p = (void*) *ap; + continue; + } + // else + switch(type) + { + case nsXPTType::T_I8 : dp->val.i8 = *((PRInt8*) ap); break; + case nsXPTType::T_I16 : dp->val.i16 = *((PRInt16*) ap); break; + case nsXPTType::T_I32 : dp->val.i32 = *((PRInt32*) ap); break; + case nsXPTType::T_I64 : dp->val.i64 = *((PRInt64*) ap); ap++; break; + case nsXPTType::T_U8 : dp->val.u8 = *((PRUint8*) ap); break; + case nsXPTType::T_U16 : dp->val.u16 = *((PRUint16*)ap); break; + case nsXPTType::T_U32 : dp->val.u32 = *((PRUint32*)ap); break; + case nsXPTType::T_U64 : dp->val.u64 = *((PRUint64*)ap); ap++; break; + case nsXPTType::T_FLOAT : dp->val.f = *((float*) ap); break; + case nsXPTType::T_DOUBLE : dp->val.d = *((double*) ap); ap++; break; + case nsXPTType::T_BOOL : dp->val.b = *((PRBool*) ap); break; + case nsXPTType::T_CHAR : dp->val.c = *((char*) ap); break; + case nsXPTType::T_WCHAR : dp->val.wc = *((wchar_t*) ap); break; + default: + NS_ASSERTION(0, "bad type"); + break; + } + } + + result = self->CallMethod((PRUint16)methodIndex, info, dispatchParams); + + NS_RELEASE(iface_info); + + if(dispatchParams != paramBuffer) + delete [] dispatchParams; + + return result; +} + +/* + * These stubs move just move the values passed in registers onto the stack, + * so they are contiguous with values passed on the stack, and then calls + * PrepareAndDispatch() to do the dirty work. + */ + +#define STUB_ENTRY(n) \ +__asm__( \ + ".global _Stub"#n"__14nsXPTCStubBase\n\t" \ +"_Stub"#n"__14nsXPTCStubBase:\n\t" \ + "stmfd sp!, {r1, r2, r3} \n\t" \ + "mov ip, sp \n\t" \ + "stmfd sp!, {fp, ip, lr, pc} \n\t" \ + "sub fp, ip, #4 \n\t" \ + "mov r1, #"#n" \n\t" /* = methodIndex */ \ + "add r2, sp, #16 \n\t" \ + "bl _PrepareAndDispatch__FP14nsXPTCStubBaseUiPUi \n\t" \ + "ldmea fp, {fp, sp, lr} \n\t" \ + "add sp, sp, #12 \n\t" \ + "mov pc, lr \n\t" \ +); + +#define SENTINEL_ENTRY(n) \ +nsresult nsXPTCStubBase::Sentinel##n() \ +{ \ + NS_ASSERTION(0,"nsXPTCStubBase::Sentinel called"); \ + return NS_ERROR_NOT_IMPLEMENTED; \ +} + +#include "xptcstubsdef.inc" diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_ipf32.s b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_ipf32.s new file mode 100644 index 00000000..591e88e5 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_ipf32.s @@ -0,0 +1,124 @@ + +// Select C numeric constant + .radix C + .psr abi32 + .psr msb +// Section has executable code + .section .text, "ax","progbits" +// procedure named 'SharedStub' + .proc SharedStub +// manual bundling + .explicit + + .global PrepareAndDispatch +// .exclass PrepareAndDispatch, @fullyvisible + .type PrepareAndDispatch,@function + +SharedStub:: +// 9 arguments, first 8 are the input arguments of previous +// function call. The last one is methodIndex, and is passed in memory + .prologue + .save ar.pfs , r41 +// allocate 8 input args, 4 local args, and 5 output args + alloc r41 = ar.pfs, 8, 4, 5, 0 // M + .save rp, r40 + mov r40 = rp // I + nop.i 0 ;; // I + + .save ar.unat, r42 + mov r42 = ar.unat // M + .fframe 144 + add sp = -144, sp // A +// unwind table already knows gp, don't need to specify anything + add r43 = 0, gp ;; // A + +// We have possible 8 integer registers and 8 float registers that could +// be arguments. We also have a stack region from the previous +// stack frame that may hold some stack arguments. +// We need to write the integer registers to a memory region, write +// the float registers to a memory region (making sure we don't step +// on NAT while touching the registers). We also mark the memory +// address of the stack arguments. +// We then call PrepareAndDispatch() specifying the three memory +// region pointers. + + + .body + add out0 = 0, in0 // A move self ptr +// 144 bytes = 16 byte stack header + 64 byte int space + 64 byte float space +// current frame is 144 bytes, previous frame is 112 bytes +// restarg is at 144 + 112 + 16 bytes away from current sp +// (current frame + previous frame + previous previous frame header) +// methodIndex is at 144 + 16 bytes away from current sp +// (current frame + previous frame header) + add out4 = 192, sp // A restarg address + add r11 = 160, sp ;; // A address of methodIndex + + ld8 out1 = [r11] // M load methodIndex +// sp + 16 is the start of intargs + add out2 = 16, sp // A address of intargs +// the intargs take up 64 bytes, so sp + 16 + 64 is the start of floatargs + add out3 = 80, sp ;; // A address of floatargs + + add r11 = 0, out2 ;; // A + st8.spill [r11] = in1, 8 // M + add r10 = 0, out3 ;; // A + + st8.spill [r11] = in2, 8 ;; // M + st8.spill [r11] = in3, 8 // M + nop.i 0 ;; // I + + st8.spill [r11] = in4, 8 ;; // M + st8.spill [r11] = in5, 8 // M + nop.i 0 ;; // I + + st8.spill [r11] = in6, 8 ;; // M + st8.spill [r11] = in7 // M + fclass.nm p14,p15 = f8,@nat ;; // F + +(p14) stfd [r10] = f8, 8 // M +(p15) add r10 = 8, r10 // A + fclass.nm p12,p13 = f9,@nat ;; // F + +(p12) stfd [r10] = f9, 8 // M +(p13) add r10 = 8, r10 // A + fclass.nm p14,p15 =f10,@nat ;; // F + +(p14) stfd [r10] = f10, 8 // M +(p15) add r10 = 8, r10 // A + fclass.nm p12,p13 =f11,@nat ;; // F + +(p12) stfd [r10] = f11, 8 // M +(p13) add r10 = 8, r10 // A + fclass.nm p14,p15 =f12,@nat ;; // F + +(p14) stfd [r10] = f12, 8 // M +(p15) add r10 = 8, r10 // A + fclass.nm p12,p13 =f13,@nat ;; // F + +(p12) stfd [r10] = f13, 8 // M +(p13) add r10 = 8, r10 // A + fclass.nm p14,p15 =f14,@nat ;; // F + +(p14) stfd [r10] = f14, 8 // M +(p15) add r10 = 8, r10 // A + fclass.nm p12,p13 =f15,@nat ;; // F + +(p12) stfd [r10] = f15, 8 // M +(p13) add r10 = 8, r10 // A + +// branch to PrepareAndDispatch + br.call.dptk.few rp = PrepareAndDispatch ;; // B + +// epilog + mov ar.unat = r42 // M + mov ar.pfs = r41 // I + mov rp = r40 ;; // I + + add gp = 0, r43 // A + add sp = 144, sp // A + br.ret.dptk.few rp ;; // B + + .endp + + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_ipf64.s b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_ipf64.s new file mode 100644 index 00000000..177b2646 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_ipf64.s @@ -0,0 +1,124 @@ + +// Select C numeric constant + .radix C + .psr abi64 + .psr lsb +// Section has executable code + .section .text, "ax","progbits" +// procedure named 'SharedStub' + .proc SharedStub +// manual bundling + .explicit + + .global PrepareAndDispatch +// .exclass PrepareAndDispatch, @fullyvisible + .type PrepareAndDispatch,@function + +SharedStub:: +// 9 arguments, first 8 are the input arguments of previous +// function call. The last one is methodIndex, and is passed in memory + .prologue + .save ar.pfs , r41 +// allocate 8 input args, 4 local args, and 5 output args + alloc r41 = ar.pfs, 8, 4, 5, 0 // M + .save rp, r40 + mov r40 = rp // I + nop.i 0 ;; // I + + .save ar.unat, r42 + mov r42 = ar.unat // M + .fframe 144 + add sp = -144, sp // A +// unwind table already knows gp, don't need to specify anything + add r43 = 0, gp ;; // A + +// We have possible 8 integer registers and 8 float registers that could +// be arguments. We also have a stack region from the previous +// stack frame that may hold some stack arguments. +// We need to write the integer registers to a memory region, write +// the float registers to a memory region (making sure we don't step +// on NAT while touching the registers). We also mark the memory +// address of the stack arguments. +// We then call PrepareAndDispatch() specifying the three memory +// region pointers. + + + .body + add out0 = 0, in0 // A move self ptr +// 144 bytes = 16 byte stack header + 64 byte int space + 64 byte float space +// current frame is 144 bytes, previous frame is 112 bytes +// restarg is at 144 + 112 + 16 bytes away from current sp +// (current frame + previous frame + previous previous frame header) +// methodIndex is at 144 + 16 bytes away from current sp +// (current frame + previous frame header) + add out4 = 192, sp // A restarg address + add r11 = 160, sp ;; // A address of methodIndex + + ld8 out1 = [r11] // M load methodIndex +// sp + 16 is the start of intargs + add out2 = 16, sp // A address of intargs +// the intargs take up 64 bytes, so sp + 16 + 64 is the start of floatargs + add out3 = 80, sp ;; // A address of floatargs + + add r11 = 0, out2 ;; // A + st8.spill [r11] = in1, 8 // M + add r10 = 0, out3 ;; // A + + st8.spill [r11] = in2, 8 ;; // M + st8.spill [r11] = in3, 8 // M + nop.i 0 ;; // I + + st8.spill [r11] = in4, 8 ;; // M + st8.spill [r11] = in5, 8 // M + nop.i 0 ;; // I + + st8.spill [r11] = in6, 8 ;; // M + st8.spill [r11] = in7 // M + fclass.nm p14,p15 = f8,@nat ;; // F + +(p14) stfd [r10] = f8, 8 // M +(p15) add r10 = 8, r10 // A + fclass.nm p12,p13 = f9,@nat ;; // F + +(p12) stfd [r10] = f9, 8 // M +(p13) add r10 = 8, r10 // A + fclass.nm p14,p15 =f10,@nat ;; // F + +(p14) stfd [r10] = f10, 8 // M +(p15) add r10 = 8, r10 // A + fclass.nm p12,p13 =f11,@nat ;; // F + +(p12) stfd [r10] = f11, 8 // M +(p13) add r10 = 8, r10 // A + fclass.nm p14,p15 =f12,@nat ;; // F + +(p14) stfd [r10] = f12, 8 // M +(p15) add r10 = 8, r10 // A + fclass.nm p12,p13 =f13,@nat ;; // F + +(p12) stfd [r10] = f13, 8 // M +(p13) add r10 = 8, r10 // A + fclass.nm p14,p15 =f14,@nat ;; // F + +(p14) stfd [r10] = f14, 8 // M +(p15) add r10 = 8, r10 // A + fclass.nm p12,p13 =f15,@nat ;; // F + +(p12) stfd [r10] = f15, 8 // M +(p13) add r10 = 8, r10 // A + +// branch to PrepareAndDispatch + br.call.dptk.few rp = PrepareAndDispatch ;; // B + +// epilog + mov ar.unat = r42 // M + mov ar.pfs = r41 // I + mov rp = r40 ;; // I + + add gp = 0, r43 // A + add sp = 144, sp // A + br.ret.dptk.few rp ;; // B + + .endp + + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_irix.s b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_irix.s new file mode 100644 index 00000000..4ca1e542 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_irix.s @@ -0,0 +1,97 @@ + +#include +#include + + .text + .globl PrepareAndDispatch + +LOCALSZ=16 +FRAMESZ=(((NARGSAVE+LOCALSZ)*SZREG)+ALSZ)&ALMASK + +A1OFF=FRAMESZ-(9*SZREG) +A2OFF=FRAMESZ-(8*SZREG) +A3OFF=FRAMESZ-(7*SZREG) +A4OFF=FRAMESZ-(6*SZREG) +A5OFF=FRAMESZ-(5*SZREG) +A6OFF=FRAMESZ-(4*SZREG) +A7OFF=FRAMESZ-(3*SZREG) +GPOFF=FRAMESZ-(2*SZREG) +RAOFF=FRAMESZ-(1*SZREG) + +F13OFF=FRAMESZ-(16*SZREG) +F14OFF=FRAMESZ-(15*SZREG) +F15OFF=FRAMESZ-(14*SZREG) +F16OFF=FRAMESZ-(13*SZREG) +F17OFF=FRAMESZ-(12*SZREG) +F18OFF=FRAMESZ-(11*SZREG) +F19OFF=FRAMESZ-(10*SZREG) + +#define SENTINEL_ENTRY(nn) /* defined in cpp file, not here */ + +#ifdef __GNUC__ +#define STUB_ENTRY(nn) MAKE_STUB(nn, Stub/**/nn/**/__14nsXPTCStubBase) +#else +#define STUB_ENTRY(nn) MAKE_STUB(nn, Stub/**/nn/**/__14nsXPTCStubBaseGv) +#endif + +#define MAKE_STUB(nn, name) \ +NESTED(name, FRAMESZ, ra); \ + SETUP_GP; \ + PTR_SUBU sp, FRAMESZ; \ + SETUP_GP64(GPOFF, name); \ + SAVE_GP(GPOFF); \ + li t0, nn; \ + b sharedstub; \ +.end name; \ + +#include "xptcstubsdef.inc" + + .globl sharedstub + .ent sharedstub +sharedstub: + + REG_S a1, A1OFF(sp) + REG_S a2, A2OFF(sp) + REG_S a3, A3OFF(sp) + REG_S a4, A4OFF(sp) + REG_S a5, A5OFF(sp) + REG_S a6, A6OFF(sp) + REG_S a7, A7OFF(sp) + REG_S ra, RAOFF(sp) + + s.d $f13, F13OFF(sp) + s.d $f14, F14OFF(sp) + s.d $f15, F15OFF(sp) + s.d $f16, F16OFF(sp) + s.d $f17, F17OFF(sp) + s.d $f18, F18OFF(sp) + s.d $f19, F19OFF(sp) + + # t0 is methodIndex + move a1, t0 + + # a2 is stack address where extra function params + # are stored that do not fit in registers + move a2, sp + addi a2, FRAMESZ + + # a3 is stack address of a1..a7 + move a3, sp + addi a3, A1OFF + + # a4 is stack address of f13..f19 + move a4, sp + addi a4, F13OFF + + # PrepareAndDispatch(that, methodIndex, args, gprArgs, fpArgs) + # a0 a1 a2 a3 a4 + # + jal PrepareAndDispatch + + REG_L ra, RAOFF(sp) + REG_L gp, GPOFF(sp) + + PTR_ADDU sp, FRAMESZ + j ra + +.end sharedstub diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_mips.s.m4 b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_mips.s.m4 new file mode 100644 index 00000000..f327adfb --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_mips.s.m4 @@ -0,0 +1,109 @@ +/* -*- Mode: asm; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * Version: MPL 1.1 + * + * ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corp, Inc. + * Portions created by the Initial Developer are Copyright (C) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Stuart Parmenter + * Chris Waterson + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* This code is for MIPS using the O32 ABI. */ + +#include +#include + + .text + .globl PrepareAndDispatch + +NARGSAVE=4 # extra space for the callee to use. gccism + # we can put our a0-a3 in our callers space. +LOCALSZ=2 # gp, ra +FRAMESZ=(((NARGSAVE+LOCALSZ)*SZREG)+ALSZ)&ALMASK + +define(STUB_NAME, `Stub'$1`__14nsXPTCStubBase') + +define(STUB_ENTRY, +` .globl 'STUB_NAME($1)` + .align 2 + .type 'STUB_NAME($1)`,@function + .ent 'STUB_NAME($1)`, 0 +'STUB_NAME($1)`: + .frame sp, FRAMESZ, ra + .set noreorder + .cpload t9 + .set reorder + subu sp, FRAMESZ + .cprestore 16 + li t0, '$1` + b sharedstub +.end 'STUB_NAME($1)` + +') + +define(SENTINEL_ENTRY, `') + +include(xptcstubsdef.inc) + + .globl sharedstub + .ent sharedstub +sharedstub: + + REG_S ra, 20(sp) + + REG_S a0, 24(sp) + REG_S a1, 28(sp) + REG_S a2, 32(sp) + REG_S a3, 36(sp) + + # t0 is methodIndex + move a1, t0 + + # put the start of a1, a2, a3, and stack + move a2, sp + addi a2, 24 # have a2 point to sp + 24 (where a0 is) + + # PrepareAndDispatch(that, methodIndex, args) + # a0 a1 a2 + # + jal PrepareAndDispatch + + REG_L ra, 20(sp) + REG_L a1, 28(sp) + REG_L a2, 32(sp) + + addu sp, FRAMESZ + j ra + +.end sharedstub diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_openvms_alpha.s b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_openvms_alpha.s new file mode 100644 index 00000000..9f04d4c4 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_openvms_alpha.s @@ -0,0 +1,115 @@ +;* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- +;* +;* The contents of this file are subject to the Netscape 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/NPL/ +;* +;* 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.org code. +;* +;* The Initial Developer of the Original Code is Netscape +;* Communications Corporation. Portions created by Netscape are +;* Copyright (C) 1999 Netscape Communications Corporation. All +;* Rights Reserved. +;* +;* Contributor(s): +;*/ + +; Implement shared vtbl methods. + + .title "STUBS" "Stub Code" + + MBIT = "__14nsXPTCStubBasexv" ; this is the mangled part of the name + +; The layout of the linkage section is important. First comes +; PrepareAndDispatch, and then the Procedure Descriptors for the stubs. Each +; is known to be 16 bytes long, and we use this fact to be able to locate the +; PrepareAndDispatch linkage pair from any of the stubs. + + .PSECT $LINK$, OCTA, NOPIC, CON, REL, LCL, NOSHR, NOEXE, RD, NOWRT + .LINKAGE_PAIR PrepareAndDispatch + LINKOFF = 16 ; first stub lp will be 16 bytes away + +; STUB_ENTRY createa a routine nsXPTCStubBase::Stub() where n is the +; argument passed in to STUB_ENTRY. It puts its stub number into R1 and then +; jumps into SharedStub. It does it this way because we don't want to mess +; up the arguments that may be on the stack. In order that we can find +; our way around the linkage section, we subtract our offset from the +; start of the linkage section (LINKOFF) from our own PV, thus giving +; us the PV os the first entry in the linkage section (this should be +; PrepareAndDispatch); + + .macro STUB_ENTRY n + $routine Stub'n%MBIT%, kind=null + mov LINKOFF, r1 ; distance from lp for PrepareAndDispatch + subq r27,r1,r27 ; subtract it from address of our proc desc + mov n,r1 ; stub number is passed in r1 + br SharedStub ; off to common code + $end_routine + LINKOFF = LINKOFF + 16 ; we just put 16 bytes into linkage section + .endm STUB_ENTRY + +; SENTINEL_ENTRY is in the C++ module. We need to define a empty macro +; here to keep the assembler happy. + .macro SENTINEL_ENTRY n + .endm SENTINEL_ENTRY + + .PSECT $CODE$, OCTA, PIC, CON, REL, LCL, SHR, EXE, NORD, NOWRT + +; +; SharedStub() +; Collects arguments and calls PrepareAndDispatch. +; +; r1 - The "methodIndex" +; r27 - points to the first entry in the linkage section, which by design +; is the linkage pair for PrepareAndDispatch. +; +; Arguments are passed in a non-standard way so that we don't disturb the +; original arguments that were passed in to the stub. Since some args (if +; there were more than 6) will already be on the stack, the stub had to not +; only preserve R16-R21, but also preserve the stack too. +; + +SharedStub:: + subq sp,96,sp ; get some stack space for the args and saves + stq r26,0(sp) ; save r26 (the return address) + + ; + ; Store arguments passed via registers to the stack. + ; Floating point registers are stored as doubles and converted + ; to floats in PrepareAndDispatch if necessary. + ; + stt f17,16(sp) ; floating point registers + stt f18,24(sp) + stt f19,32(sp) + stt f20,40(sp) + stt f21,48(sp) + stq r17,56(sp) ; integer registers + stq r18,64(sp) + stq r19,72(sp) + stq r20,80(sp) + stq r21,88(sp) + + ; + ; Call PrepareAndDispatch function. + ; + mov r1,r17 ; pass "methodIndex" + addq sp,16,r18 ; pass "args" + mov 3,r25 ; number of args into AI + + LDQ R26, 0(R27) ; get entry point address from linkage pair + LDQ R27, 8(R27) ; get procedure descriptor address from lp + JSR R26, R26 + + ldq r26, 0(sp) ; restore return address + addq sp,96,sp ; return stack space + ret r26 ; and we're outta here + + .include "xptcstubsdef_asm.vms" + + .end diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_osf1_alpha.s b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_osf1_alpha.s new file mode 100644 index 00000000..3bef9b1b --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_osf1_alpha.s @@ -0,0 +1,75 @@ + .text + .align 5 + .globl SharedStub + .ent SharedStub +SharedStub: + .frame $30, 96, $26, 0 + .mask 0x4000000,-96 + ldgp $29,0($27) +SharedStubXv: + subq $30,96,$30 + stq $26,0($30) + .prologue 1 + stt $f17,16($30) + stt $f18,24($30) + stt $f19,32($30) + stt $f20,40($30) + stt $f21,48($30) + stq $17,56($30) + stq $18,64($30) + stq $19,72($30) + stq $20,80($30) + stq $21,88($30) + bis $1,$1,$17 + addq $30,16,$18 + bsr $26,PrepareAndDispatch + ldq $26,0($30) + addq $30,96,$30 + ret $31,($26),1 + .end SharedStub + +/* + The C preprocessor doesn't handle # and ## if run with -std or -std0. + + If -std then __STDC__ is 0 [default] (K&R behavior) + If -std0 then __STDC__ is undefined (K&R behavior) + If -std1 then __STDC__ is 1 (ANSI preprocessor) +*/ + +#if __STDC__ +#define STUB_ENTRY(n) ;\ + .text ;\ + .align 5 ;\ + .globl Stub##n##__14nsXPTCStubBase ;\ + .globl Stub##n##__14nsXPTCStubBaseXv ;\ + .ent Stub##n##__14nsXPTCStubBase ;\ +Stub##n##__14nsXPTCStubBase: ;\ + .frame $30,0,$26,0 ;\ + ldgp $29,0($27) ;\ + .prologue 1 ;\ +Stub##n##__14nsXPTCStubBaseXv: ;\ + lda $1,n ;\ + br $31,SharedStubXv ;\ + .end Stub##n##__14nsXPTCStubBase \ + +#else +#define STUB_ENTRY(n) ;\ + .text ;\ + .align 5 ;\ + .globl Stub/**/n/**/__14nsXPTCStubBase ;\ + .globl Stub/**/n/**/__14nsXPTCStubBaseXv ;\ + .ent Stub/**/n/**/__14nsXPTCStubBase ;\ +Stub/**/n/**/__14nsXPTCStubBase: ;\ + .frame $30,0,$26,0 ;\ + ldgp $29,0($27) ;\ + .prologue 1 ;\ +Stub/**/n/**/__14nsXPTCStubBaseXv: ;\ + lda $1,n ;\ + br $31,SharedStubXv ;\ + .end Stub/**/n/**/__14nsXPTCStubBase \ + +#endif + +#define SENTINEL_ENTRY(n) \ + +#include "xptcstubsdef.inc" diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_pa32.s b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_pa32.s new file mode 100644 index 00000000..9e86848f --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_pa32.s @@ -0,0 +1,68 @@ + .LEVEL 1.1 + +curframesz .EQU 128 +; SharedStub has stack size of 128 bytes + +lastframesz .EQU 64 +; the StubN C++ function has a small stack size of 64 bytes + + .SPACE $TEXT$,SORT=8 + .SUBSPA $CODE$,QUAD=0,ALIGN=4,ACCESS=0x2c,CODE_ONLY,SORT=24 +SharedStub + .PROC + .CALLINFO CALLER,FRAME=80,SAVE_RP,ARGS_SAVED + + .ENTRY + STW %rp,-20(%sp) + LDO 128(%sp),%sp + + STW %r19,-32(%r30) + STW %r26,-36-curframesz(%r30) ; save arg0 in previous frame + + LDO -80(%r30),%r28 + FSTD,MA %fr5,8(%r28) ; save darg0 + FSTD,MA %fr7,8(%r28) ; save darg1 + FSTW,MA %fr4L,4(%r28) ; save farg0 + FSTW,MA %fr5L,4(%r28) ; save farg1 + FSTW,MA %fr6L,4(%r28) ; save farg2 + FSTW,MA %fr7L,4(%r28) ; save farg3 + + ; Former value of register 26 is already properly saved by StubN, + ; but register 25-23 are not because of the arguments mismatch + STW %r25,-40-curframesz-lastframesz(%r30) ; save r25 + STW %r24,-44-curframesz-lastframesz(%r30) ; save r24 + STW %r23,-48-curframesz-lastframesz(%r30) ; save r23 + COPY %r26,%r25 ; method index is arg1 + LDW -36-curframesz-lastframesz(%r30),%r26 ; self is arg0 + LDO -40-curframesz-lastframesz(%r30),%r24 ; normal args is arg2 + LDO -80(%r30),%r23 ; floating args is arg3 + + BL .+8,%r2 + ADDIL L'PrepareAndDispatch-$PIC_pcrel$0+4,%r2 + LDO R'PrepareAndDispatch-$PIC_pcrel$1+8(%r1),%r1 +$PIC_pcrel$0 + LDSID (%r1),%r31 +$PIC_pcrel$1 + MTSP %r31,%sr0 + .CALL ARGW0=GR,ARGW1=GR,ARGW2=GR,ARGW3=GR,RTNVAL=GR +;in=23-26;out=28; + BLE 0(%sr0,%r1) + COPY %r31,%r2 + + LDW -32(%r30),%r19 + + LDW -148(%sp),%rp + BVE (%rp) + .EXIT + LDO -128(%sp),%sp + + + .PROCEND ;in=26;out=28; + + .ALIGN 8 + .SPACE $TEXT$ + .SUBSPA $CODE$ + .IMPORT PrepareAndDispatch,CODE + .EXPORT SharedStub,ENTRY,PRIV_LEV=3,ARGW0=GR,RTNVAL=GR,LONG_RETURN + .END + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_ppc_aix.s b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_ppc_aix.s new file mode 100644 index 00000000..667da705 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_ppc_aix.s @@ -0,0 +1,117 @@ + # + # -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + # + # The contents of this file are subject to the Netscape 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/NPL/ + # + # 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.org code. + # + # The Initial Developer of the Original Code is Netscape + # Communications Corporation. Portions created by Netscape are + # Copyright (C) 1999 Netscape Communications Corporation. All + # Rights Reserved. + # + # Contributor(s): + # + +.set r0,0; .set sp,1; .set RTOC,2; .set r3,3; .set r4,4 +.set r5,5; .set r6,6; .set r7,7; .set r8,8; .set r9,9 +.set r10,10; .set r11,11; .set r12,12; .set r13,13; .set r14,14 +.set r15,15; .set r16,16; .set r17,17; .set r18,18; .set r19,19 +.set r20,20; .set r21,21; .set r22,22; .set r23,23; .set r24,24 +.set r25,25; .set r26,26; .set r27,27; .set r28,28; .set r29,29 +.set r30,30; .set r31,31 +.set f0,0; .set f1,1; .set f2,2; .set f3,3; .set f4,4 +.set f5,5; .set f6,6; .set f7,7; .set f8,8; .set f9,9 +.set f10,10; .set f11,11; .set f12,12; .set f13,13; .set f14,14 +.set f15,15; .set f16,16; .set f17,17; .set f18,18; .set f19,19 +.set f20,20; .set f21,21; .set f22,22; .set f23,23; .set f24,24 +.set f25,25; .set f26,26; .set f27,27; .set f28,28; .set f29,29 +.set f30,30; .set f31,31 + + + + .rename H.10.NO_SYMBOL{PR},"" + .rename H.18.SharedStub{TC},"SharedStub" + + +# .text section + + .csect H.10.NO_SYMBOL{PR} + .globl .SharedStub + .globl SharedStub{DS} + .extern .PrepareAndDispatch + + +#jimbo csect CODE{PR} +# +# on entry SharedStub has the method selector in r12, the rest of the original +# parameters are in r3 thru r10 and f1 thru f13 +# +#jimbo import .PrepareAndDispatch + +.SharedStub: + mflr r0 + stw r0,8(sp) + + mr r12,r3 # Move methodIndex into r12 for LATER + lwz r3,104(sp) # Get the 'original' r3 + + stwu sp,-176(sp) # room for linkage (24), fprData (104), gprData(28) + # outgoing params to PrepareAndDispatch (20) + + stw r4,44(sp) + stw r5,48(sp) + stw r6,52(sp) + stw r7,56(sp) + stw r8,60(sp) + stw r9,64(sp) + stw r10,68(sp) + stfd f1,72(sp) + stfd f2,80(sp) + stfd f3,88(sp) + stfd f4,96(sp) + stfd f5,104(sp) + stfd f6,112(sp) + stfd f7,120(sp) + stfd f8,128(sp) + stfd f9,136(sp) + stfd f10,144(sp) + stfd f11,152(sp) + stfd f12,156(sp) + stfd f13,164(sp) + + addi r6,sp,44 # gprData + addi r7,sp,72 # fprData + # r3 has the 'self' pointer already + mr r4,r12 # methodIndex selector (it is now LATER) + addi r5,sp,312 # pointer to callers args area, beyond r3-r10 mapped range + + bl .PrepareAndDispatch + nop + + lwz r0,184(sp) + addi sp,sp,176 + mtlr r0 + blr + +# .data section + + .toc # 0x00000038 +T.18.SharedStub: + .tc H.18.SharedStub{TC},SharedStub{DS} + + .csect SharedStub{DS} + .long .SharedStub # "\0\0\0\0" + .long TOC{TC0} # "\0\0\0008" + .long 0x00000000 # "\0\0\0\0" +# End csect SharedStub{DS} + +# .bss section diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_ppc_aix64.s b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_ppc_aix64.s new file mode 100644 index 00000000..94245d5e --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_ppc_aix64.s @@ -0,0 +1,137 @@ +# ***** BEGIN LICENSE BLOCK ***** +# +# Version: MPL 1.1/LGPL 2.1/GPL 2.0 +# +# 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.org code. +# +# The Initial Developer of the Original Code is IBM Corporation. +# Portions created by IBM are +# Copyright (C) 2002, International Business Machines Corporation. +# All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of 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 LGPL or the GPL. 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 ***** + +.set r0,0; .set sp,1; .set RTOC,2; .set r3,3; .set r4,4 +.set r5,5; .set r6,6; .set r7,7; .set r8,8; .set r9,9 +.set r10,10; .set r11,11; .set r12,12; .set r13,13; .set r14,14 +.set r15,15; .set r16,16; .set r17,17; .set r18,18; .set r19,19 +.set r20,20; .set r21,21; .set r22,22; .set r23,23; .set r24,24 +.set r25,25; .set r26,26; .set r27,27; .set r28,28; .set r29,29 +.set r30,30; .set r31,31 +.set f0,0; .set f1,1; .set f2,2; .set f3,3; .set f4,4 +.set f5,5; .set f6,6; .set f7,7; .set f8,8; .set f9,9 +.set f10,10; .set f11,11; .set f12,12; .set f13,13; .set f14,14 +.set f15,15; .set f16,16; .set f17,17; .set f18,18; .set f19,19 +.set f20,20; .set f21,21; .set f22,22; .set f23,23; .set f24,24 +.set f25,25; .set f26,26; .set f27,27; .set f28,28; .set f29,29 +.set f30,30; .set f31,31 + + + .rename H.10.NO_SYMBOL{PR},"" + .rename H.18.SharedStub{TC},"SharedStub" + + +# .text section + + .csect H.10.NO_SYMBOL{PR} + .globl .SharedStub + .globl SharedStub{DS} + .extern .PrepareAndDispatch + + +#jimbo csect CODE{PR} +# +# on entry SharedStub has the method selector in r12, the rest of the original +# parameters are in r3 thru r10 and f1 thru f13 +# +#jimbo import .PrepareAndDispatch + +.SharedStub: + mflr r0 + std r0,16(sp) + + mr r12,r3 # Move methodIndex into r12 for LATER + ld r3,176(sp) # Get the 'original' r3 (load 'this' into r3) + + stdu sp,-248(sp) # room for linkage (24*2), fprData (104), + # gprData(28*2), outgoing params to + # PrepareAndDispatch (40) + + std r4,88(sp) # link area (48) + PrepareAndDispatch parms (40) + std r5,96(sp) + std r6,104(sp) + std r7,112(sp) + std r8,120(sp) + std r9,128(sp) + std r10,136(sp) + stfd f1,144(sp) + stfd f2,152(sp) + stfd f3,160(sp) + stfd f4,168(sp) + stfd f5,176(sp) + stfd f6,184(sp) + stfd f7,192(sp) + stfd f8,200(sp) + stfd f9,208(sp) + stfd f10,216(sp) + stfd f11,224(sp) + stfd f12,232(sp) + stfd f13,240(sp) + + addi r6,sp,88 # gprData + addi r7,sp,144 # fprData + # r3 has the 'self' pointer already + mr r4,r12 # methodIndex selector (it is now LATER) + addi r5,sp,488 # pointer to callers args area, beyond r3-r10 + # mapped range + # 32bit: 176 (stack-distance) 64bit: 248 (stack-distance) + # 104 (this ptr offset) 176 + # 32 (8*4 for r3-r10) 64 (8*8) + # --- --- + # 312 488 + + bl .PrepareAndDispatch + nop + + ld r0,264(sp) # 248+16 + addi sp,sp,248 + mtlr r0 + blr + +# .data section + + .toc # 0x00000038 +T.18.SharedStub: + .tc H.18.SharedStub{TC},SharedStub{DS} + + .csect SharedStub{DS} + .llong .SharedStub # "\0\0\0\0" + .llong TOC{TC0} # "\0\0\0008" + .llong 0x00000000 # "\0\0\0\0" +# End csect SharedStub{DS} + +# .bss section diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_ppc_darwin.s.m4 b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_ppc_darwin.s.m4 new file mode 100644 index 00000000..60dbd7c3 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_ppc_darwin.s.m4 @@ -0,0 +1,126 @@ +/* -*- Mode: asm; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999-2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * 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 ***** */ + + .text + .globl _SharedStub + +define(STUB_MANGLED_ENTRY, +` .globl '$2` + .align 2 +'$2`: + addi r12, 0, '$1` + b _SharedStub +') + +define(STUB_ENTRY, +`#ifdef HAVE_GCC3_ABI + .if '$1` < 10 +STUB_MANGLED_ENTRY('$1`, `__ZN14nsXPTCStubBase5Stub'$1`Ev') + .elseif '$1` < 100 +STUB_MANGLED_ENTRY('$1`, `__ZN14nsXPTCStubBase6Stub'$1`Ev') + .elseif '$1` < 1000 +STUB_MANGLED_ENTRY('$1`, `__ZN14nsXPTCStubBase7Stub'$1`Ev') + .else + .err "Stub'$1` >= 1000 not yet supported." + .endif +#else /* !defined(HAVE_GCC3_ABI) */ +STUB_MANGLED_ENTRY('$1`, `_Stub'$1`__14nsXPTCStubBase') +#endif /* !defined(HAVE_GCC3_ABI) */ +') + +define(SENTINEL_ENTRY, `') + +include(xptcstubsdef.inc) + +_SharedStub: + mflr r0 + stw r0,8(r1) + + stwu r1,-176(r1) + + stw r4,44(r1) + stw r5,48(r1) + stw r6,52(r1) + stw r7,56(r1) + stw r8,60(r1) + stw r9,64(r1) + stw r10,68(r1) + stfd f1,72(r1) + stfd f2,80(r1) + stfd f3,88(r1) + stfd f4,96(r1) + stfd f5,104(r1) + stfd f6,112(r1) + stfd f7,120(r1) + stfd f8,128(r1) + stfd f9,136(r1) + stfd f10,144(r1) + stfd f11,152(r1) + stfd f12,156(r1) + stfd f13,164(r1) + + addi r6,r1,44 + addi r7,r1,72 + + mr r4,r12 + addi r5,r1,232 + + bl L_PrepareAndDispatch$stub + nop + + lwz r0,184(r1) + addi r1,r1,176 + mtlr r0 + blr + +.picsymbol_stub +L_PrepareAndDispatch$stub: + .indirect_symbol _PrepareAndDispatch + mflr r0 + bcl 20,31,L1$pb +L1$pb: + mflr r11 + addis r11,r11,ha16(L1$lz-L1$pb) + mtlr r0 + lwz r12,lo16(L1$lz-L1$pb)(r11) + mtctr r12 + addi r11,r11,lo16(L1$lz-L1$pb) + bctr +.lazy_symbol_pointer +L1$lz: + .indirect_symbol _PrepareAndDispatch + .long dyld_stub_binding_helper diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_ppc_linux.s b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_ppc_linux.s new file mode 100644 index 00000000..fc85bdb9 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_ppc_linux.s @@ -0,0 +1,89 @@ +// -*- Mode: Asm -*- +// +// The contents of this file are subject to the Netscape 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/NPL/ +// +// 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.org code. +// +// The Initial Developer of the Original Code is Netscape +// Communications Corporation. Portions created by Netscape are +// Copyright (C) 1999 Netscape Communications Corporation. All +// Rights Reserved. +// +// Contributor(s): +// Franz.Sirl-kernel@lauterbach.com (Franz Sirl) +// beard@netscape.com (Patrick Beard) +// waterson@netscape.com (Chris Waterson) +// + +.set r0,0; .set sp,1; .set RTOC,2; .set r3,3; .set r4,4 +.set r5,5; .set r6,6; .set r7,7; .set r8,8; .set r9,9 +.set r10,10; .set r11,11; .set r12,12; .set r13,13; .set r14,14 +.set r15,15; .set r16,16; .set r17,17; .set r18,18; .set r19,19 +.set r20,20; .set r21,21; .set r22,22; .set r23,23; .set r24,24 +.set r25,25; .set r26,26; .set r27,27; .set r28,28; .set r29,29 +.set r30,30; .set r31,31 +.set f0,0; .set f1,1; .set f2,2; .set f3,3; .set f4,4 +.set f5,5; .set f6,6; .set f7,7; .set f8,8; .set f9,9 +.set f10,10; .set f11,11; .set f12,12; .set f13,13; .set f14,14 +.set f15,15; .set f16,16; .set f17,17; .set f18,18; .set f19,19 +.set f20,20; .set f21,21; .set f22,22; .set f23,23; .set f24,24 +.set f25,25; .set f26,26; .set f27,27; .set f28,28; .set f29,29 +.set f30,30; .set f31,31 + + .section ".text" + .align 2 + .globl SharedStub + .type SharedStub,@function + +SharedStub: + stwu sp,-112(sp) // room for + // linkage (8), + // gprData (32), + // fprData (64), + // stack alignment(8) + mflr r0 + stw r0,116(sp) // save LR backchain + + stw r4,12(sp) // save GP registers + stw r5,16(sp) // (n.b. that we don't save r3 + stw r6,20(sp) // because PrepareAndDispatch() is savvy) + stw r7,24(sp) + stw r8,28(sp) + stw r9,32(sp) + stw r10,36(sp) + + stfd f1,40(sp) // save FP registers + stfd f2,48(sp) + stfd f3,56(sp) + stfd f4,64(sp) + stfd f5,72(sp) + stfd f6,80(sp) + stfd f7,88(sp) + stfd f8,96(sp) + + // r3 has the 'self' pointer already + + mr r4,r11 // r4 <= methodIndex selector, passed + // via r11 in the nsXPTCStubBase::StubXX() call + + addi r5,sp,120 // r5 <= pointer to callers args area, + // beyond r3-r10/f1-f8 mapped range + + addi r6,sp,8 // r6 <= gprData + addi r7,sp,40 // r7 <= fprData + + bl PrepareAndDispatch@local // Go! + + lwz r0,116(sp) // restore LR + mtlr r0 + la sp,112(sp) // clean up the stack + blr + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_ppc_netbsd.s b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_ppc_netbsd.s new file mode 100644 index 00000000..f94aac4f --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_ppc_netbsd.s @@ -0,0 +1,89 @@ +# -*- Mode: Asm -*- +# +# The contents of this file are subject to the Netscape 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/NPL/ +# +# 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.org code. +# +# The Initial Developer of the Original Code is Netscape +# Communications Corporation. Portions created by Netscape are +# Copyright (C) 1999 Netscape Communications Corporation. All +# Rights Reserved. +# +# Contributor(s): +# Franz.Sirl-kernel@lauterbach.com (Franz Sirl) +# beard@netscape.com (Patrick Beard) +# waterson@netscape.com (Chris Waterson) +# + +.set r0,0; .set sp,1; .set RTOC,2; .set r3,3; .set r4,4 +.set r5,5; .set r6,6; .set r7,7; .set r8,8; .set r9,9 +.set r10,10; .set r11,11; .set r12,12; .set r13,13; .set r14,14 +.set r15,15; .set r16,16; .set r17,17; .set r18,18; .set r19,19 +.set r20,20; .set r21,21; .set r22,22; .set r23,23; .set r24,24 +.set r25,25; .set r26,26; .set r27,27; .set r28,28; .set r29,29 +.set r30,30; .set r31,31 +.set f0,0; .set f1,1; .set f2,2; .set f3,3; .set f4,4 +.set f5,5; .set f6,6; .set f7,7; .set f8,8; .set f9,9 +.set f10,10; .set f11,11; .set f12,12; .set f13,13; .set f14,14 +.set f15,15; .set f16,16; .set f17,17; .set f18,18; .set f19,19 +.set f20,20; .set f21,21; .set f22,22; .set f23,23; .set f24,24 +.set f25,25; .set f26,26; .set f27,27; .set f28,28; .set f29,29 +.set f30,30; .set f31,31 + + .section ".text" + .align 2 + .globl SharedStub + .type SharedStub,@function + +SharedStub: + stwu sp,-112(sp) # room for + # linkage (8), + # gprData (32), + # fprData (64), + # stack alignment(8) + mflr r0 + stw r0,116(sp) # save LR backchain + + stw r4,12(sp) # save GP registers + stw r5,16(sp) # (n.b. that we don't save r3 + stw r6,20(sp) # because PrepareAndDispatch() is savvy) + stw r7,24(sp) + stw r8,28(sp) + stw r9,32(sp) + stw r10,36(sp) + + stfd f1,40(sp) # save FP registers + stfd f2,48(sp) + stfd f3,56(sp) + stfd f4,64(sp) + stfd f5,72(sp) + stfd f6,80(sp) + stfd f7,88(sp) + stfd f8,96(sp) + + # r3 has the 'self' pointer already + + mr r4,r11 # r4 <= methodIndex selector, passed + # via r11 in the nsXPTCStubBase::StubXX() call + + addi r5,sp,120 # r5 <= pointer to callers args area, + # beyond r3-r10/f1-f8 mapped range + + addi r6,sp,8 # r6 <= gprData + addi r7,sp,40 # r7 <= fprData + + bl PrepareAndDispatch@local # Go! + + lwz r0,116(sp) # restore LR + mtlr r0 + la sp,112(sp) # clean up the stack + blr + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_sparc_netbsd.s b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_sparc_netbsd.s new file mode 100644 index 00000000..4a8a4698 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_sparc_netbsd.s @@ -0,0 +1,65 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * The contents of this file are subject to the Netscape 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/NPL/ + * + * 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.org code. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1999 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + */ + + .global SharedStub + +/* + in the frame for the function that called SharedStub are the + rest of the parameters we need + +*/ + +SharedStub: +! we don't create a new frame yet, but work within the frame of the calling +! function to give ourselves the other parameters we want + + mov %o0, %o1 ! shuffle the index up to 2nd place + mov %i0, %o0 ! the original 'this' + add %fp, 72, %o2 ! previous stack top adjusted to the first argument slot (beyond 'this') +! save off the original incoming parameters that arrived in +! registers, the ABI guarantees the space for us to do this + st %i1, [%fp + 72] + st %i2, [%fp + 76] + st %i3, [%fp + 80] + st %i4, [%fp + 84] + st %i5, [%fp + 88] +! now we can build our own stack frame + save %sp,-(64 + 32),%sp ! room for the register window and + ! struct pointer, rounded up to 0 % 32 +! our function now appears to have been called +! as SharedStub(nsISupports* that, PRUint32 index, PRUint32* args) +! so we can just copy these through + + mov %i0, %o0 + mov %i1, %o1 + mov %i2, %o2 + call PrepareAndDispatch + nop + mov %o0,%i0 ! propagate return value + b .LL1 + nop +.LL1: + ret + restore + + .size SharedStub, .-SharedStub + .type SharedStub, #function diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_sparc_solaris.s b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_sparc_solaris.s new file mode 100644 index 00000000..4a8a4698 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_sparc_solaris.s @@ -0,0 +1,65 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * The contents of this file are subject to the Netscape 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/NPL/ + * + * 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.org code. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1999 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + */ + + .global SharedStub + +/* + in the frame for the function that called SharedStub are the + rest of the parameters we need + +*/ + +SharedStub: +! we don't create a new frame yet, but work within the frame of the calling +! function to give ourselves the other parameters we want + + mov %o0, %o1 ! shuffle the index up to 2nd place + mov %i0, %o0 ! the original 'this' + add %fp, 72, %o2 ! previous stack top adjusted to the first argument slot (beyond 'this') +! save off the original incoming parameters that arrived in +! registers, the ABI guarantees the space for us to do this + st %i1, [%fp + 72] + st %i2, [%fp + 76] + st %i3, [%fp + 80] + st %i4, [%fp + 84] + st %i5, [%fp + 88] +! now we can build our own stack frame + save %sp,-(64 + 32),%sp ! room for the register window and + ! struct pointer, rounded up to 0 % 32 +! our function now appears to have been called +! as SharedStub(nsISupports* that, PRUint32 index, PRUint32* args) +! so we can just copy these through + + mov %i0, %o0 + mov %i1, %o1 + mov %i2, %o2 + call PrepareAndDispatch + nop + mov %o0,%i0 ! propagate return value + b .LL1 + nop +.LL1: + ret + restore + + .size SharedStub, .-SharedStub + .type SharedStub, #function diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_sparcv9_solaris.s b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_sparcv9_solaris.s new file mode 100644 index 00000000..e3bbcf8b --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_sparcv9_solaris.s @@ -0,0 +1,67 @@ +/* -*- Mode: asm; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * 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.org code. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 2001 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * Stuart Parmenter + */ + + .global SharedStub + +/* + in the frame for the function that called SharedStub are the + rest of the parameters we need + +*/ + +SharedStub: +! we don't create a new frame yet, but work within the frame of the calling +! function to give ourselves the other parameters we want + + mov %o0, %o1 ! shuffle the index up to 2nd place + mov %i0, %o0 ! the original 'this' + add %fp, 0x7ff + 136, %o2 ! previous stack top adjusted to the first argument slot (beyond 'this') + +! save off the original incoming parameters that arrived in +! registers, the ABI guarantees the space for us to do this + stx %i1, [%fp + 0x7ff + 136] + stx %i2, [%fp + 0x7ff + 144] + stx %i3, [%fp + 0x7ff + 152] + stx %i4, [%fp + 0x7ff + 160] + stx %i5, [%fp + 0x7ff + 168] +! now we can build our own stack frame + save %sp,-(128 + 64),%sp ! room for the register window and + ! struct pointer, rounded up to 0 % 64 +! our function now appears to have been called +! as SharedStub(nsISupports* that, PRUint32 index, PRUint32* args) +! so we can just copy these through + + mov %i0, %o0 + mov %i1, %o1 + mov %i2, %o2 + call PrepareAndDispatch + nop + mov %o0,%i0 ! propagate return value + b .LL1 + nop +.LL1: + ret + restore + + .size SharedStub, .-SharedStub + .type SharedStub, #function diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_gcc_x86_unix.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_gcc_x86_unix.cpp new file mode 100644 index 00000000..351ee512 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_gcc_x86_unix.cpp @@ -0,0 +1,202 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Implement shared vtbl methods. */ + +#ifdef __GNUC__ /* Gnu Compiler. */ + +#include "xptcprivate.h" +#include "xptc_platforms_unixish_x86.h" +#include "xptc_gcc_x86_unix.h" + +extern "C" { +static nsresult ATTRIBUTE_USED +__attribute__ ((regparm (3))) +PrepareAndDispatch(uint32 methodIndex, nsXPTCStubBase* self, PRUint32* args) +{ +#define PARAM_BUFFER_COUNT 16 + + nsXPTCMiniVariant paramBuffer[PARAM_BUFFER_COUNT]; + nsXPTCMiniVariant* dispatchParams = NULL; + nsIInterfaceInfo* iface_info = NULL; + const nsXPTMethodInfo* info = NULL; + PRUint8 paramCount; + PRUint8 i; + nsresult result = NS_ERROR_FAILURE; + + NS_ASSERTION(self,"no self"); + + self->GetInterfaceInfo(&iface_info); + NS_ASSERTION(iface_info,"no interface info"); + if (!iface_info) + return NS_ERROR_UNEXPECTED; + + iface_info->GetMethodInfo(PRUint16(methodIndex), &info); + NS_ASSERTION(info,"no method info"); + if (!info) + return NS_ERROR_UNEXPECTED; + + paramCount = info->GetParamCount(); + + // setup variant array pointer + if(paramCount > PARAM_BUFFER_COUNT) + dispatchParams = new nsXPTCMiniVariant[paramCount]; + else + dispatchParams = paramBuffer; + NS_ASSERTION(dispatchParams,"no place for params"); + if (!dispatchParams) + return NS_ERROR_OUT_OF_MEMORY; + + PRUint32* ap = args; + for(i = 0; i < paramCount; i++, ap++) + { + const nsXPTParamInfo& param = info->GetParam(i); + const nsXPTType& type = param.GetType(); + nsXPTCMiniVariant* dp = &dispatchParams[i]; + + if(param.IsOut() || !type.IsArithmetic()) + { + dp->val.p = (void*) *ap; + continue; + } + // else + dp->val.p = (void*) *ap; + switch(type) + { + case nsXPTType::T_I64 : dp->val.i64 = *((PRInt64*) ap); ap++; break; + case nsXPTType::T_U64 : dp->val.u64 = *((PRUint64*)ap); ap++; break; + case nsXPTType::T_DOUBLE : dp->val.d = *((double*) ap); ap++; break; + } + } + + result = self->CallMethod((PRUint16)methodIndex, info, dispatchParams); + + NS_RELEASE(iface_info); + + if(dispatchParams != paramBuffer) + delete [] dispatchParams; + + return result; +} +} // extern "C" + +// NOTE! See xptc_gcc_x86_unix.h for the reason this function exists. +#if (__GNUC__ < 3 || (__GNUC__ == 3 && __GNUC_MINOR__ == 0)) +PRUint32 +xptc_PrepareAndDispatch_keeper (void) +{ + PRUint32 dummy1; + nsresult ATTRIBUTE_USED __attribute__ ((regparm (3))) (*dummy2) + (uint32, nsXPTCStubBase *, PRUint32*) = PrepareAndDispatch; +// dummy2 references PrepareAndDispatch, now "use" it + __asm__ __volatile__ ( + "" + : "=&a" (dummy1) + : "g" (dummy2) + ); + return dummy1 & 0xF0F00000; +} +#endif + +#if defined(__GXX_ABI_VERSION) && __GXX_ABI_VERSION >= 100 /* G++ V3 ABI */ +// gcc3 mangling tends to insert the length of the method name +#define STUB_ENTRY(n) \ +asm(".text\n\t" \ + ".align 2\n\t" \ + ".if " #n " < 10\n\t" \ + ".globl " SYMBOL_UNDERSCORE "_ZN14nsXPTCStubBase5Stub" #n "Ev\n\t" \ + ".type " SYMBOL_UNDERSCORE "_ZN14nsXPTCStubBase5Stub" #n "Ev,@function\n" \ + SYMBOL_UNDERSCORE "_ZN14nsXPTCStubBase5Stub" #n "Ev:\n\t" \ + ".elseif " #n " < 100\n\t" \ + ".globl " SYMBOL_UNDERSCORE "_ZN14nsXPTCStubBase6Stub" #n "Ev\n\t" \ + ".type " SYMBOL_UNDERSCORE "_ZN14nsXPTCStubBase6Stub" #n "Ev,@function\n" \ + SYMBOL_UNDERSCORE "_ZN14nsXPTCStubBase6Stub" #n "Ev:\n\t" \ + ".elseif " #n " < 1000\n\t" \ + ".globl " SYMBOL_UNDERSCORE "_ZN14nsXPTCStubBase7Stub" #n "Ev\n\t" \ + ".type " SYMBOL_UNDERSCORE "_ZN14nsXPTCStubBase7Stub" #n "Ev,@function\n" \ + SYMBOL_UNDERSCORE "_ZN14nsXPTCStubBase7Stub" #n "Ev:\n\t" \ + ".else\n\t" \ + ".err \"stub number " #n " >= 1000 not yet supported\"\n\t" \ + ".endif\n\t" \ + "movl $" #n ", %eax\n\t" \ + "jmp " SYMBOL_UNDERSCORE "SharedStub\n\t" \ + ".if " #n " < 10\n\t" \ + ".size " SYMBOL_UNDERSCORE "_ZN14nsXPTCStubBase5Stub" #n "Ev,.-" SYMBOL_UNDERSCORE "_ZN14nsXPTCStubBase5Stub" #n "Ev\n\t" \ + ".elseif " #n " < 100\n\t" \ + ".size " SYMBOL_UNDERSCORE "_ZN14nsXPTCStubBase6Stub" #n "Ev,.-" SYMBOL_UNDERSCORE "_ZN14nsXPTCStubBase6Stub" #n "Ev\n\t" \ + ".else\n\t" \ + ".size " SYMBOL_UNDERSCORE "_ZN14nsXPTCStubBase7Stub" #n "Ev,.-" SYMBOL_UNDERSCORE "_ZN14nsXPTCStubBase7Stub" #n "Ev\n\t" \ + ".endif"); +#else +#define STUB_ENTRY(n) \ +asm(".text\n\t" \ + ".align 2\n\t" \ + ".globl " SYMBOL_UNDERSCORE "Stub" #n "__14nsXPTCStubBase\n\t" \ + ".type " SYMBOL_UNDERSCORE "Stub" #n "__14nsXPTCStubBase,@function\n" \ + SYMBOL_UNDERSCORE "Stub" #n "__14nsXPTCStubBase:\n\t" \ + "movl $" #n ", %eax\n\t" \ + "jmp " SYMBOL_UNDERSCORE "SharedStub\n\t" \ + ".size " SYMBOL_UNDERSCORE "Stub" #n "__14nsXPTCStubBase,.-" SYMBOL_UNDERSCORE "Stub" #n "__14nsXPTCStubBase"); +#endif + +// static nsresult SharedStub(PRUint32 methodIndex) __attribute__((regparm(1))) +asm(".text\n\t" + ".align 2\n\t" + ".type " SYMBOL_UNDERSCORE "SharedStub,@function\n\t" + SYMBOL_UNDERSCORE "SharedStub:\n\t" + "leal 0x08(%esp), %ecx\n\t" + "movl 0x04(%esp), %edx\n\t" + "jmp " SYMBOL_UNDERSCORE "PrepareAndDispatch\n\t" + ".size " SYMBOL_UNDERSCORE "SharedStub,.-" SYMBOL_UNDERSCORE "SharedStub"); + +#define SENTINEL_ENTRY(n) \ +nsresult nsXPTCStubBase::Sentinel##n() \ +{ \ + NS_ASSERTION(0,"nsXPTCStubBase::Sentinel called"); \ + return NS_ERROR_NOT_IMPLEMENTED; \ +} + +#include "xptcstubsdef.inc" + +void +xptc_dummy() +{ +} + +#else +#error "can't find a compiler to use" +#endif /* __GNUC__ */ diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_ipf32.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_ipf32.cpp new file mode 100644 index 00000000..844f55dd --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_ipf32.cpp @@ -0,0 +1,185 @@ + +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "xptcprivate.h" + +#include +#include + +// "This code is for IA64 only" + +/* Implement shared vtbl methods. */ + +extern "C" nsresult +PrepareAndDispatch(nsXPTCStubBase* self, PRUint32 methodIndex, + uint64_t* intargs, uint64_t* floatargs, uint64_t* restargs) +{ + +#define PARAM_BUFFER_COUNT 16 + + nsXPTCMiniVariant paramBuffer[PARAM_BUFFER_COUNT]; + nsXPTCMiniVariant* dispatchParams = NULL; + nsIInterfaceInfo* iface_info = NULL; + const nsXPTMethodInfo* info; + nsresult result = NS_ERROR_FAILURE; + uint64_t* iargs = intargs; + uint64_t* fargs = floatargs; + PRUint8 paramCount; + PRUint8 i; + + NS_ASSERTION(self,"no self"); + + self->GetInterfaceInfo(&iface_info); + NS_ASSERTION(iface_info,"no interface info"); + + iface_info->GetMethodInfo(PRUint16(methodIndex), &info); + NS_ASSERTION(info,"no interface info"); + + paramCount = info->GetParamCount(); + + // setup variant array pointer + if(paramCount > PARAM_BUFFER_COUNT) + dispatchParams = new nsXPTCMiniVariant[paramCount]; + else + dispatchParams = paramBuffer; + NS_ASSERTION(dispatchParams,"no place for params"); + + for(i = 0; i < paramCount; ++i) + { + int isfloat = 0; + const nsXPTParamInfo& param = info->GetParam(i); + const nsXPTType& type = param.GetType(); + nsXPTCMiniVariant* dp = &dispatchParams[i]; + + if(param.IsOut() || !type.IsArithmetic()) + { +#ifdef __LP64__ + /* 64 bit pointer mode */ + dp->val.p = (void*) *iargs; +#else + /* 32 bit pointer mode */ + uint32_t* adr = (uint32_t*) iargs; + dp->val.p = (void*) (*(adr+1)); +#endif + } + else + switch(type) + { + case nsXPTType::T_I8 : dp->val.i8 = *(iargs); break; + case nsXPTType::T_I16 : dp->val.i16 = *(iargs); break; + case nsXPTType::T_I32 : dp->val.i32 = *(iargs); break; + case nsXPTType::T_I64 : dp->val.i64 = *(iargs); break; + case nsXPTType::T_U8 : dp->val.u8 = *(iargs); break; + case nsXPTType::T_U16 : dp->val.u16 = *(iargs); break; + case nsXPTType::T_U32 : dp->val.u32 = *(iargs); break; + case nsXPTType::T_U64 : dp->val.u64 = *(iargs); break; + case nsXPTType::T_FLOAT : + isfloat = 1; + if (i < 7) + dp->val.f = (float) *((double*) fargs); /* register */ + else + dp->val.u32 = *(fargs); /* memory */ + break; + case nsXPTType::T_DOUBLE : + isfloat = 1; + dp->val.u64 = *(fargs); + break; + case nsXPTType::T_BOOL : dp->val.b = *(iargs); break; + case nsXPTType::T_CHAR : dp->val.c = *(iargs); break; + case nsXPTType::T_WCHAR : dp->val.wc = *(iargs); break; + default: + NS_ASSERTION(0, "bad type"); + break; + } + if (i < 7) + { + /* we are parsing register arguments */ + if (i == 6) + { + // run out of register arguments, move on to memory arguments + iargs = restargs; + fargs = restargs; + } + else + { + ++iargs; // advance one integer register slot + if (isfloat) ++fargs; // advance float register slot if isfloat + } + } + else + { + /* we are parsing memory arguments */ + ++iargs; + ++fargs; + } + } + + result = self->CallMethod((PRUint16) methodIndex, info, dispatchParams); + + NS_RELEASE(iface_info); + + if(dispatchParams != paramBuffer) + delete [] dispatchParams; + + return result; +} + +extern "C" int SharedStub(PRUint64,PRUint64,PRUint64,PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); + +/* Variable a0-a7 were put there so we can have access to the 8 input + registers on Stubxyz entry */ + +#define STUB_ENTRY(n) \ +nsresult nsXPTCStubBase::Stub##n(PRUint64 a1, \ +PRUint64 a2,PRUint64 a3,PRUint64 a4,PRUint64 a5,PRUint64 a6,PRUint64 a7) \ +{ uint64_t a0 = (uint64_t) this; \ + return SharedStub(a0,a1,a2,a3,a4,a5,a6,a7,(PRUint64) n); \ +} + +#define SENTINEL_ENTRY(n) \ +nsresult nsXPTCStubBase::Sentinel##n() \ +{ \ + NS_ASSERTION(0,"nsXPTCStubBase::Sentinel called"); \ + return NS_ERROR_NOT_IMPLEMENTED; \ +} + +#include "xptcstubsdef.inc" + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_ipf64.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_ipf64.cpp new file mode 100644 index 00000000..6a11f692 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_ipf64.cpp @@ -0,0 +1,186 @@ + +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "xptcprivate.h" + +#include +#include +#include + +// "This code is for IA64 only" + +/* Implement shared vtbl methods. */ + +extern "C" nsresult +PrepareAndDispatch(nsXPTCStubBase* self, PRUint32 methodIndex, + uint64_t* intargs, uint64_t* floatargs, uint64_t* restargs) +{ + +#define PARAM_BUFFER_COUNT 16 + + nsXPTCMiniVariant paramBuffer[PARAM_BUFFER_COUNT]; + nsXPTCMiniVariant* dispatchParams = NULL; + nsIInterfaceInfo* iface_info = NULL; + const nsXPTMethodInfo* info; + nsresult result = NS_ERROR_FAILURE; + uint64_t* iargs = intargs; + uint64_t* fargs = floatargs; + PRUint8 paramCount; + PRUint8 i; + + NS_ASSERTION(self,"no self"); + + self->GetInterfaceInfo(&iface_info); + NS_ASSERTION(iface_info,"no interface info"); + + iface_info->GetMethodInfo(PRUint16(methodIndex), &info); + NS_ASSERTION(info,"no interface info"); + + paramCount = info->GetParamCount(); + + // setup variant array pointer + if(paramCount > PARAM_BUFFER_COUNT) + dispatchParams = new nsXPTCMiniVariant[paramCount]; + else + dispatchParams = paramBuffer; + NS_ASSERTION(dispatchParams,"no place for params"); + + for(i = 0; i < paramCount; ++i) + { + int isfloat = 0; + const nsXPTParamInfo& param = info->GetParam(i); + const nsXPTType& type = param.GetType(); + nsXPTCMiniVariant* dp = &dispatchParams[i]; + + if(param.IsOut() || !type.IsArithmetic()) + { +#ifdef __LP64__ + /* 64 bit pointer mode */ + dp->val.p = (void*) *iargs; +#else + /* 32 bit pointer mode */ + uint32_t* adr = (uint32_t*) iargs; + dp->val.p = (void*) (*(adr+1)); +#endif + } + else + switch(type) + { + case nsXPTType::T_I8 : dp->val.i8 = *(iargs); break; + case nsXPTType::T_I16 : dp->val.i16 = *(iargs); break; + case nsXPTType::T_I32 : dp->val.i32 = *(iargs); break; + case nsXPTType::T_I64 : dp->val.i64 = *(iargs); break; + case nsXPTType::T_U8 : dp->val.u8 = *(iargs); break; + case nsXPTType::T_U16 : dp->val.u16 = *(iargs); break; + case nsXPTType::T_U32 : dp->val.u32 = *(iargs); break; + case nsXPTType::T_U64 : dp->val.u64 = *(iargs); break; + case nsXPTType::T_FLOAT : + isfloat = 1; + if (i < 7) + dp->val.f = (float) *((double*) fargs); /* register */ + else + dp->val.u32 = *(fargs); /* memory */ + break; + case nsXPTType::T_DOUBLE : + isfloat = 1; + dp->val.u64 = *(fargs); + break; + case nsXPTType::T_BOOL : dp->val.b = *(iargs); break; + case nsXPTType::T_CHAR : dp->val.c = *(iargs); break; + case nsXPTType::T_WCHAR : dp->val.wc = *(iargs); break; + default: + NS_ASSERTION(0, "bad type"); + break; + } + if (i < 7) + { + /* we are parsing register arguments */ + if (i == 6) + { + // run out of register arguments, move on to memory arguments + iargs = restargs; + fargs = restargs; + } + else + { + ++iargs; // advance one integer register slot + if (isfloat) ++fargs; // advance float register slot if isfloat + } + } + else + { + /* we are parsing memory arguments */ + ++iargs; + ++fargs; + } + } + + result = self->CallMethod((PRUint16) methodIndex, info, dispatchParams); + + NS_RELEASE(iface_info); + + if(dispatchParams != paramBuffer) + delete [] dispatchParams; + + return result; +} + +extern "C" int SharedStub(PRUint64,PRUint64,PRUint64,PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); + +/* Variable a0-a7 were put there so we can have access to the 8 input + registers on Stubxyz entry */ + +#define STUB_ENTRY(n) \ +nsresult nsXPTCStubBase::Stub##n(PRUint64 a1, \ +PRUint64 a2,PRUint64 a3,PRUint64 a4,PRUint64 a5,PRUint64 a6,PRUint64 a7) \ +{ uint64_t a0 = (uint64_t) this; \ + return SharedStub(a0,a1,a2,a3,a4,a5,a6,a7,(PRUint64) n); \ +} + +#define SENTINEL_ENTRY(n) \ +nsresult nsXPTCStubBase::Sentinel##n() \ +{ \ + NS_ASSERTION(0,"nsXPTCStubBase::Sentinel called"); \ + return NS_ERROR_NOT_IMPLEMENTED; \ +} + +#include "xptcstubsdef.inc" + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_irix.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_irix.cpp new file mode 100644 index 00000000..556b5bbe --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_irix.cpp @@ -0,0 +1,226 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "xptcprivate.h" + +#if defined(IRIX) + +#if (_MIPS_SIM != _ABIN32) +#error "This code is for IRIX N32 only" +#endif + +/* + * This is for IRIX N32 ABI + * + * When we're called, the "gp" registers are stored in gprData and + * the "fp" registers are stored in fprData. There are 8 regs + * available which coorespond to the first 7 parameters of the + * function and the "this" pointer. If there are additional parms, + * they are stored on the stack at address "args". + * + */ +extern "C" nsresult +PrepareAndDispatch(nsXPTCStubBase* self, PRUint32 methodIndex, PRUint64* args, + PRUint64 *gprData, double *fprData) +{ +#define PARAM_BUFFER_COUNT 16 +#define PARAM_GPR_COUNT 7 +#define PARAM_FPR_COUNT 7 + + nsXPTCMiniVariant paramBuffer[PARAM_BUFFER_COUNT]; + nsXPTCMiniVariant* dispatchParams = NULL; + nsIInterfaceInfo* iface_info = NULL; + const nsXPTMethodInfo* info; + PRUint8 paramCount; + PRUint8 i; + nsresult result = NS_ERROR_FAILURE; + + NS_ASSERTION(self,"no self"); + + self->GetInterfaceInfo(&iface_info); + NS_ASSERTION(iface_info,"no interface info"); + + iface_info->GetMethodInfo(PRUint16(methodIndex), &info); + NS_ASSERTION(info,"no interface info"); + + paramCount = info->GetParamCount(); + + // setup variant array pointer + if(paramCount > PARAM_BUFFER_COUNT) + dispatchParams = new nsXPTCMiniVariant[paramCount]; + else + dispatchParams = paramBuffer; + NS_ASSERTION(dispatchParams,"no place for params"); + + PRUint64* ap = args; + PRUint32 iCount = 0; + for(i = 0; i < paramCount; i++) + { + const nsXPTParamInfo& param = info->GetParam(i); + const nsXPTType& type = param.GetType(); + nsXPTCMiniVariant* dp = &dispatchParams[i]; + + if(param.IsOut() || !type.IsArithmetic()) + { + if (iCount < PARAM_GPR_COUNT) + dp->val.p = (void*)gprData[iCount++]; + else + dp->val.p = (void*)*ap++; + continue; + } + // else + switch(type) + { + case nsXPTType::T_I8: + if (iCount < PARAM_GPR_COUNT) + dp->val.i8 = (PRInt8)gprData[iCount++]; + else + dp->val.i8 = (PRInt8)*ap++; + break; + + case nsXPTType::T_I16: + if (iCount < PARAM_GPR_COUNT) + dp->val.i16 = (PRInt16)gprData[iCount++]; + else + dp->val.i16 = (PRInt16)*ap++; + break; + + case nsXPTType::T_I32: + if (iCount < PARAM_GPR_COUNT) + dp->val.i32 = (PRInt32)gprData[iCount++]; + else + dp->val.i32 = (PRInt32)*ap++; + break; + + case nsXPTType::T_I64: + if (iCount < PARAM_GPR_COUNT) + dp->val.i64 = (PRInt64)gprData[iCount++]; + else + dp->val.i64 = (PRInt64)*ap++; + break; + + case nsXPTType::T_U8: + if (iCount < PARAM_GPR_COUNT) + dp->val.u8 = (PRUint8)gprData[iCount++]; + else + dp->val.u8 = (PRUint8)*ap++; + break; + + case nsXPTType::T_U16: + if (iCount < PARAM_GPR_COUNT) + dp->val.u16 = (PRUint16)gprData[iCount++]; + else + dp->val.u16 = (PRUint16)*ap++; + break; + + case nsXPTType::T_U32: + if (iCount < PARAM_GPR_COUNT) + dp->val.u32 = (PRUint32)gprData[iCount++]; + else + dp->val.u32 = (PRUint32)*ap++; + break; + + case nsXPTType::T_U64: + if (iCount < PARAM_GPR_COUNT) + dp->val.u64 = (PRUint64)gprData[iCount++]; + else + dp->val.u64 = (PRUint64)*ap++; + break; + + case nsXPTType::T_FLOAT: + if (iCount < PARAM_FPR_COUNT) + dp->val.f = (double)fprData[iCount++]; + else + dp->val.f = *((double*)ap++); + break; + + case nsXPTType::T_DOUBLE: + if (iCount < PARAM_FPR_COUNT) + dp->val.d = (double)fprData[iCount++]; + else + dp->val.d = *((double*)ap++); + break; + + case nsXPTType::T_BOOL: + if (iCount < PARAM_GPR_COUNT) + dp->val.b = (PRBool)gprData[iCount++]; + else + dp->val.b = (PRBool)*ap++; + break; + + case nsXPTType::T_CHAR: + if (iCount < PARAM_GPR_COUNT) + dp->val.c = (char)gprData[iCount++]; + else + dp->val.c = (char)*ap++; + break; + + case nsXPTType::T_WCHAR: + if (iCount < PARAM_GPR_COUNT) + dp->val.wc = (wchar_t)gprData[iCount++]; + else + dp->val.wc = (wchar_t)*ap++; + break; + + default: + NS_ASSERTION(0, "bad type"); + break; + } + } + + result = self->CallMethod((PRUint16)methodIndex, info, dispatchParams); + + NS_RELEASE(iface_info); + + if(dispatchParams != paramBuffer) + delete [] dispatchParams; + + return result; +} + +#define STUB_ENTRY(n) /* defined in the assembly file */ + +#define SENTINEL_ENTRY(n) \ +nsresult nsXPTCStubBase::Sentinel##n() \ +{ \ + NS_ASSERTION(0,"nsXPTCStubBase::Sentinel called"); \ + return NS_ERROR_NOT_IMPLEMENTED; \ +} + +#include "xptcstubsdef.inc" + +#endif diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_linux_alpha.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_linux_alpha.cpp new file mode 100644 index 00000000..e5b1c642 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_linux_alpha.cpp @@ -0,0 +1,236 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Glen Nakamura + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Implement shared vtbl methods. */ + +#include "xptcprivate.h" + +/* Prototype specifies unmangled function name and disables unused warning */ +static nsresult +PrepareAndDispatch(nsXPTCStubBase* self, uint32 methodIndex, PRUint64* args) +__asm__("PrepareAndDispatch") __attribute__((unused)); + +static nsresult +PrepareAndDispatch(nsXPTCStubBase* self, uint32 methodIndex, PRUint64* args) +{ + const PRUint8 PARAM_BUFFER_COUNT = 16; + const PRUint8 NUM_ARG_REGS = 6-1; // -1 for "this" pointer + + nsXPTCMiniVariant paramBuffer[PARAM_BUFFER_COUNT]; + nsXPTCMiniVariant* dispatchParams = NULL; + nsIInterfaceInfo* iface_info = NULL; + const nsXPTMethodInfo* info; + PRUint8 paramCount; + PRUint8 i; + nsresult result = NS_ERROR_FAILURE; + + NS_ASSERTION(self,"no self"); + + self->GetInterfaceInfo(&iface_info); + NS_ASSERTION(iface_info,"no interface info"); + + iface_info->GetMethodInfo(PRUint16(methodIndex), &info); + NS_ASSERTION(info,"no interface info"); + + paramCount = info->GetParamCount(); + + // setup variant array pointer + if(paramCount > PARAM_BUFFER_COUNT) + dispatchParams = new nsXPTCMiniVariant[paramCount]; + else + dispatchParams = paramBuffer; + NS_ASSERTION(dispatchParams,"no place for params"); + + // args[0] to args[NUM_ARG_REGS] hold floating point register values + PRUint64* ap = args + NUM_ARG_REGS; + for(i = 0; i < paramCount; i++, ap++) + { + const nsXPTParamInfo& param = info->GetParam(i); + const nsXPTType& type = param.GetType(); + nsXPTCMiniVariant* dp = &dispatchParams[i]; + + if(param.IsOut() || !type.IsArithmetic()) + { + dp->val.p = (void*) *ap; + continue; + } + // else + switch(type) + { + case nsXPTType::T_I8 : dp->val.i8 = (PRInt8) *ap; break; + case nsXPTType::T_I16 : dp->val.i16 = (PRInt16) *ap; break; + case nsXPTType::T_I32 : dp->val.i32 = (PRInt32) *ap; break; + case nsXPTType::T_I64 : dp->val.i64 = (PRInt64) *ap; break; + case nsXPTType::T_U8 : dp->val.u8 = (PRUint8) *ap; break; + case nsXPTType::T_U16 : dp->val.u16 = (PRUint16) *ap; break; + case nsXPTType::T_U32 : dp->val.u32 = (PRUint32) *ap; break; + case nsXPTType::T_U64 : dp->val.u64 = (PRUint64) *ap; break; + case nsXPTType::T_FLOAT : + if(i < NUM_ARG_REGS) + { + // floats passed via registers are stored as doubles + // in the first NUM_ARG_REGS entries in args + dp->val.u64 = (PRUint64) args[i]; + dp->val.f = (float) dp->val.d; // convert double to float + } + else + dp->val.u32 = (PRUint32) *ap; + break; + case nsXPTType::T_DOUBLE : + // doubles passed via registers are also stored + // in the first NUM_ARG_REGS entries in args + dp->val.u64 = (i < NUM_ARG_REGS) ? args[i] : *ap; + break; + case nsXPTType::T_BOOL : dp->val.b = (PRBool) *ap; break; + case nsXPTType::T_CHAR : dp->val.c = (char) *ap; break; + case nsXPTType::T_WCHAR : dp->val.wc = (PRUnichar) *ap; break; + default: + NS_ASSERTION(0, "bad type"); + break; + } + } + + result = self->CallMethod((PRUint16)methodIndex, info, dispatchParams); + + NS_RELEASE(iface_info); + + if(dispatchParams != paramBuffer) + delete [] dispatchParams; + + return result; +} + +/* + * SharedStub() + * Collects arguments and calls PrepareAndDispatch. The "methodIndex" is + * passed to this function via $1 to preserve the argument registers. + */ +__asm__( + "#### SharedStub ####\n" +".text\n\t" + ".align 5\n\t" + ".ent SharedStub\n" +"SharedStub:\n\t" + ".frame $30,96,$26,0\n\t" + ".mask 0x4000000,-96\n\t" + "ldgp $29,0($27)\n" +"$SharedStub..ng:\n\t" + "subq $30,96,$30\n\t" + "stq $26,0($30)\n\t" + ".prologue 1\n\t" + + /* + * Store arguments passed via registers to the stack. + * Floating point registers are stored as doubles and converted + * to floats in PrepareAndDispatch if necessary. + */ + "stt $f17,16($30)\n\t" /* floating point registers */ + "stt $f18,24($30)\n\t" + "stt $f19,32($30)\n\t" + "stt $f20,40($30)\n\t" + "stt $f21,48($30)\n\t" + "stq $17,56($30)\n\t" /* integer registers */ + "stq $18,64($30)\n\t" + "stq $19,72($30)\n\t" + "stq $20,80($30)\n\t" + "stq $21,88($30)\n\t" + + /* + * Call PrepareAndDispatch function. + */ + "bis $1,$1,$17\n\t" /* pass "methodIndex" */ + "addq $30,16,$18\n\t" /* pass "args" */ + "bsr $26,$PrepareAndDispatch..ng\n\t" + + "ldq $26,0($30)\n\t" + "addq $30,96,$30\n\t" + "ret $31,($26),1\n\t" + ".end SharedStub" + ); + +/* + * nsresult nsXPTCStubBase::Stub##n() + * Sets register $1 to "methodIndex" and jumps to SharedStub. + */ +#define STUB_MANGLED_ENTRY(n, symbol) \ + "#### Stub"#n" ####" "\n\t" \ + ".text" "\n\t" \ + ".align 5" "\n\t" \ + ".globl " symbol "\n\t" \ + ".ent " symbol "\n" \ +symbol ":" "\n\t" \ + ".frame $30,0,$26,0" "\n\t" \ + "ldgp $29,0($27)" "\n" \ +"$" symbol "..ng:" "\n\t" \ + ".prologue 1" "\n\t" \ + "lda $1,"#n "\n\t" \ + "br $31,$SharedStub..ng" "\n\t" \ + ".end " symbol + +#if defined(__GXX_ABI_VERSION) && __GXX_ABI_VERSION >= 100 /* G++ V3 ABI */ + +#define STUB_ENTRY(n) \ +__asm__( \ + ".if "#n" < 10" "\n\t" \ + STUB_MANGLED_ENTRY(n, "_ZN14nsXPTCStubBase5Stub"#n"Ev") "\n\t" \ + ".elseif "#n" < 100" "\n\t" \ + STUB_MANGLED_ENTRY(n, "_ZN14nsXPTCStubBase6Stub"#n"Ev") "\n\t" \ + ".elseif "#n" < 1000" "\n\t" \ + STUB_MANGLED_ENTRY(n, "_ZN14nsXPTCStubBase7Stub"#n"Ev") "\n\t" \ + ".else" "\n\t" \ + ".err \"Stub"#n" >= 1000 not yet supported.\"" "\n\t" \ + ".endif" \ + ); + +#else /* not G++ V3 ABI */ + +#define STUB_ENTRY(n) \ +__asm__( \ + STUB_MANGLED_ENTRY(n, "Stub"#n"__14nsXPTCStubBase") \ + ); + +#endif /* G++ V3 ABI */ + +#define SENTINEL_ENTRY(n) \ +nsresult nsXPTCStubBase::Sentinel##n() \ +{ \ + NS_ASSERTION(0,"nsXPTCStubBase::Sentinel called"); \ + return NS_ERROR_NOT_IMPLEMENTED; \ +} + +#include "xptcstubsdef.inc" diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_linux_m68k.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_linux_m68k.cpp new file mode 100644 index 00000000..eb094762 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_linux_m68k.cpp @@ -0,0 +1,146 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Implement shared vtbl methods. */ + +#include "xptcprivate.h" + +extern "C" { + nsresult + PrepareAndDispatch(nsXPTCStubBase* self, uint32 methodIndex, uint32* args) + { +#define PARAM_BUFFER_COUNT 16 + + nsXPTCMiniVariant paramBuffer[PARAM_BUFFER_COUNT]; + nsXPTCMiniVariant* dispatchParams = NULL; + nsIInterfaceInfo* iface_info = NULL; + const nsXPTMethodInfo* info; + PRUint8 paramCount; + PRUint8 i; + nsresult result = NS_ERROR_FAILURE; + + NS_ASSERTION(self,"no self"); + + self->GetInterfaceInfo(&iface_info); + NS_ASSERTION(iface_info,"no interface info"); + + iface_info->GetMethodInfo(PRUint16(methodIndex), &info); + NS_ASSERTION(info,"no interface info"); + + paramCount = info->GetParamCount(); + + // setup variant array pointer + if(paramCount > PARAM_BUFFER_COUNT) + dispatchParams = new nsXPTCMiniVariant[paramCount]; + else + dispatchParams = paramBuffer; + NS_ASSERTION(dispatchParams,"no place for params"); + + PRUint32* ap = args; + for(i = 0; i < paramCount; i++, ap++) + { + const nsXPTParamInfo& param = info->GetParam(i); + const nsXPTType& type = param.GetType(); + nsXPTCMiniVariant* dp = &dispatchParams[i]; + + if(param.IsOut() || !type.IsArithmetic()) + { + dp->val.p = (void*) *ap; + continue; + } + + switch(type) + { + // the 8 and 16 bit types will have been promoted to 32 bits before + // being pushed onto the stack. Since the 68k is big endian, we + // need to skip over the leading high order bytes. + case nsXPTType::T_I8 : dp->val.i8 = *(((PRInt8*) ap) + 3); break; + case nsXPTType::T_I16 : dp->val.i16 = *(((PRInt16*) ap) + 1); break; + case nsXPTType::T_I32 : dp->val.i32 = *((PRInt32*) ap); break; + case nsXPTType::T_I64 : dp->val.i64 = *((PRInt64*) ap); ap++; break; + case nsXPTType::T_U8 : dp->val.u8 = *(((PRUint8*) ap) + 3); break; + case nsXPTType::T_U16 : dp->val.u16 = *(((PRUint16*)ap) + 1); break; + case nsXPTType::T_U32 : dp->val.u32 = *((PRUint32*)ap); break; + case nsXPTType::T_U64 : dp->val.u64 = *((PRUint64*)ap); ap++; break; + case nsXPTType::T_FLOAT : dp->val.f = *((float*) ap); break; + case nsXPTType::T_DOUBLE : dp->val.d = *((double*) ap); ap++; break; + case nsXPTType::T_BOOL : dp->val.b = *((PRBool*) ap); break; + case nsXPTType::T_CHAR : dp->val.c = *(((char*) ap) + 3); break; + case nsXPTType::T_WCHAR : dp->val.wc = *((wchar_t*) ap); break; + default: + NS_ASSERTION(0, "bad type"); + break; + } + } + + result = self->CallMethod((PRUint16)methodIndex, info, dispatchParams); + + NS_RELEASE(iface_info); + + if(dispatchParams != paramBuffer) + delete [] dispatchParams; + + return result; + } +} + +#define STUB_ENTRY(n) \ +nsresult nsXPTCStubBase::Stub##n() \ +{ \ + register nsresult result; \ + __asm__ __volatile__( \ + "lea %/a6@(12), %/a0\n\t" /* args */ \ + "movl %/a0, %/sp@-\n\t" \ + "movl #"#n", %/sp@-\n\t" /* method index */ \ + "movl %/a6@(8), %/sp@-\n\t" /* this */ \ + "jbsr PrepareAndDispatch\n\t" \ + "movl %/d0, %0\n\t" \ + "addl #12, %/sp" \ + : "=d" (result) /* %0 */ \ + : \ + : "a0", "a1", "d0", "d1", "memory" ); \ + return result; \ +} + +#define SENTINEL_ENTRY(n) \ +nsresult nsXPTCStubBase::Sentinel##n() \ +{ \ + NS_ASSERTION(0,"nsXPTCStubBase::Sentinel called"); \ + return NS_ERROR_NOT_IMPLEMENTED; \ +} + +#include "xptcstubsdef.inc" diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_linux_s390.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_linux_s390.cpp new file mode 100644 index 00000000..0f8502cd --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_linux_s390.cpp @@ -0,0 +1,220 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Implement shared vtbl methods. */ + +#include "xptcprivate.h" + +static nsresult +PrepareAndDispatch(nsXPTCStubBase* self, uint32 methodIndex, + PRUint32* a_gpr, PRUint64 *a_fpr, PRUint32 *a_ov) +{ +#define PARAM_BUFFER_COUNT 16 + + nsXPTCMiniVariant paramBuffer[PARAM_BUFFER_COUNT]; + nsXPTCMiniVariant* dispatchParams = NULL; + nsIInterfaceInfo* iface_info = NULL; + const nsXPTMethodInfo* info; + PRUint8 paramCount; + PRUint8 i; + nsresult result = NS_ERROR_FAILURE; + + NS_ASSERTION(self,"no self"); + + self->GetInterfaceInfo(&iface_info); + NS_ASSERTION(iface_info,"no interface info"); + + iface_info->GetMethodInfo(PRUint16(methodIndex), &info); + NS_ASSERTION(info,"no interface info"); + + paramCount = info->GetParamCount(); + + // setup variant array pointer + if(paramCount > PARAM_BUFFER_COUNT) + dispatchParams = new nsXPTCMiniVariant[paramCount]; + else + dispatchParams = paramBuffer; + NS_ASSERTION(dispatchParams,"no place for params"); + + PRUint32 gpr = 1, fpr = 0; + + for(i = 0; i < paramCount; i++) + { + const nsXPTParamInfo& param = info->GetParam(i); + const nsXPTType& type = param.GetType(); + nsXPTCMiniVariant* dp = &dispatchParams[i]; + + if(param.IsOut() || !type.IsArithmetic()) + { + if (gpr < 5) + dp->val.p = (void*) *a_gpr++, gpr++; + else + dp->val.p = (void*) *a_ov++; + continue; + } + // else + switch(type) + { + case nsXPTType::T_I8 : + if (gpr < 5) + dp->val.i8 = *((PRInt32*) a_gpr), a_gpr++, gpr++; + else + dp->val.i8 = *((PRInt32*) a_ov ), a_ov++; + break; + case nsXPTType::T_I16 : + if (gpr < 5) + dp->val.i16 = *((PRInt32*) a_gpr), a_gpr++, gpr++; + else + dp->val.i16 = *((PRInt32*) a_ov ), a_ov++; + break; + case nsXPTType::T_I32 : + if (gpr < 5) + dp->val.i32 = *((PRInt32*) a_gpr), a_gpr++, gpr++; + else + dp->val.i32 = *((PRInt32*) a_ov ), a_ov++; + break; + case nsXPTType::T_I64 : + if (gpr < 4) + dp->val.i64 = *((PRInt64*) a_gpr), a_gpr+=2, gpr+=2; + else + dp->val.i64 = *((PRInt64*) a_ov ), a_ov+=2, gpr=5; + break; + case nsXPTType::T_U8 : + if (gpr < 5) + dp->val.u8 = *((PRUint32*)a_gpr), a_gpr++, gpr++; + else + dp->val.u8 = *((PRUint32*)a_ov ), a_ov++; + break; + case nsXPTType::T_U16 : + if (gpr < 5) + dp->val.u16 = *((PRUint32*)a_gpr), a_gpr++, gpr++; + else + dp->val.u16 = *((PRUint32*)a_ov ), a_ov++; + break; + case nsXPTType::T_U32 : + if (gpr < 5) + dp->val.u32 = *((PRUint32*)a_gpr), a_gpr++, gpr++; + else + dp->val.u32 = *((PRUint32*)a_ov ), a_ov++; + break; + case nsXPTType::T_U64 : + if (gpr < 4) + dp->val.u64 = *((PRUint64*)a_gpr), a_gpr+=2, gpr+=2; + else + dp->val.u64 = *((PRUint64*)a_ov ), a_ov+=2, gpr=5; + break; + case nsXPTType::T_FLOAT : + if (fpr < 2) + dp->val.f = *((float*) a_fpr), a_fpr++, fpr++; + else + dp->val.f = *((float*) a_ov ), a_ov++; + break; + case nsXPTType::T_DOUBLE : + if (fpr < 2) + dp->val.d = *((double*) a_fpr), a_fpr++, fpr++; + else + dp->val.d = *((double*) a_ov ), a_ov+=2; + break; + case nsXPTType::T_BOOL : + if (gpr < 5) + dp->val.b = *((PRUint32*)a_gpr), a_gpr++, gpr++; + else + dp->val.b = *((PRUint32*)a_ov ), a_ov++; + break; + case nsXPTType::T_CHAR : + if (gpr < 5) + dp->val.c = *((PRUint32*)a_gpr), a_gpr++, gpr++; + else + dp->val.c = *((PRUint32*)a_ov ), a_ov++; + break; + case nsXPTType::T_WCHAR : + if (gpr < 5) + dp->val.wc = *((PRUint32*)a_gpr), a_gpr++, gpr++; + else + dp->val.wc = *((PRUint32*)a_ov ), a_ov++; + break; + default: + NS_ASSERTION(0, "bad type"); + break; + } + } + + result = self->CallMethod((PRUint16)methodIndex, info, dispatchParams); + + NS_RELEASE(iface_info); + + if(dispatchParams != paramBuffer) + delete [] dispatchParams; + + return result; +} + +#define STUB_ENTRY(n) \ +nsresult nsXPTCStubBase::Stub##n() \ +{ \ + PRUint32 a_gpr[4]; \ + PRUint64 a_fpr[2]; \ + PRUint32 *a_ov; \ + \ + __asm__ __volatile__ \ + ( \ + "l %0,0(15)\n\t" \ + "ahi %0,96\n\t" \ + "stm 3,6,0(%3)\n\t" \ + "std 0,%1\n\t" \ + "std 2,%2\n\t" \ + : "=&a" (a_ov), \ + "=m" (a_fpr[0]), \ + "=m" (a_fpr[1]) \ + : "a" (a_gpr) \ + : "memory", "cc", \ + "3", "4", "5", "6" \ + ); \ + \ + return PrepareAndDispatch(this, n, a_gpr, a_fpr, a_ov); \ +} + +#define SENTINEL_ENTRY(n) \ +nsresult nsXPTCStubBase::Sentinel##n() \ +{ \ + NS_ASSERTION(0,"nsXPTCStubBase::Sentinel called"); \ + return NS_ERROR_NOT_IMPLEMENTED; \ +} + +#include "xptcstubsdef.inc" + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_linux_s390x.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_linux_s390x.cpp new file mode 100644 index 00000000..9a645dd1 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_linux_s390x.cpp @@ -0,0 +1,224 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Implement shared vtbl methods. */ + +#include "xptcprivate.h" + +static nsresult +PrepareAndDispatch(nsXPTCStubBase* self, uint32 methodIndex, + PRUint64* a_gpr, PRUint64 *a_fpr, PRUint64 *a_ov) +{ +#define PARAM_BUFFER_COUNT 16 + + nsXPTCMiniVariant paramBuffer[PARAM_BUFFER_COUNT]; + nsXPTCMiniVariant* dispatchParams = NULL; + nsIInterfaceInfo* iface_info = NULL; + const nsXPTMethodInfo* info; + PRUint8 paramCount; + PRUint8 i; + nsresult result = NS_ERROR_FAILURE; + + NS_ASSERTION(self,"no self"); + + self->GetInterfaceInfo(&iface_info); + NS_ASSERTION(iface_info,"no interface info"); + + iface_info->GetMethodInfo(PRUint16(methodIndex), &info); + NS_ASSERTION(info,"no interface info"); + + paramCount = info->GetParamCount(); + + // setup variant array pointer + if(paramCount > PARAM_BUFFER_COUNT) + dispatchParams = new nsXPTCMiniVariant[paramCount]; + else + dispatchParams = paramBuffer; + NS_ASSERTION(dispatchParams,"no place for params"); + + PRUint32 gpr = 1, fpr = 0; + + for(i = 0; i < paramCount; i++) + { + const nsXPTParamInfo& param = info->GetParam(i); + const nsXPTType& type = param.GetType(); + nsXPTCMiniVariant* dp = &dispatchParams[i]; + + if(param.IsOut() || !type.IsArithmetic()) + { + if (gpr < 5) + dp->val.p = (void*) *a_gpr++, gpr++; + else + dp->val.p = (void*) *a_ov++; + continue; + } + // else + switch(type) + { + case nsXPTType::T_I8 : + if (gpr < 5) + dp->val.i8 = *((PRInt64*) a_gpr), a_gpr++, gpr++; + else + dp->val.i8 = *((PRInt64*) a_ov ), a_ov++; + break; + case nsXPTType::T_I16 : + if (gpr < 5) + dp->val.i16 = *((PRInt64*) a_gpr), a_gpr++, gpr++; + else + dp->val.i16 = *((PRInt64*) a_ov ), a_ov++; + break; + case nsXPTType::T_I32 : + if (gpr < 5) + dp->val.i32 = *((PRInt64*) a_gpr), a_gpr++, gpr++; + else + dp->val.i32 = *((PRInt64*) a_ov ), a_ov++; + break; + case nsXPTType::T_I64 : + if (gpr < 5) + dp->val.i64 = *((PRInt64*) a_gpr), a_gpr++, gpr++; + else + dp->val.i64 = *((PRInt64*) a_ov ), a_ov++; + break; + case nsXPTType::T_U8 : + if (gpr < 5) + dp->val.u8 = *((PRUint64*)a_gpr), a_gpr++, gpr++; + else + dp->val.u8 = *((PRUint64*)a_ov ), a_ov++; + break; + case nsXPTType::T_U16 : + if (gpr < 5) + dp->val.u16 = *((PRUint64*)a_gpr), a_gpr++, gpr++; + else + dp->val.u16 = *((PRUint64*)a_ov ), a_ov++; + break; + case nsXPTType::T_U32 : + if (gpr < 5) + dp->val.u32 = *((PRUint64*)a_gpr), a_gpr++, gpr++; + else + dp->val.u32 = *((PRUint64*)a_ov ), a_ov++; + break; + case nsXPTType::T_U64 : + if (gpr < 5) + dp->val.u64 = *((PRUint64*)a_gpr), a_gpr++, gpr++; + else + dp->val.u64 = *((PRUint64*)a_ov ), a_ov++; + break; + case nsXPTType::T_FLOAT : + if (fpr < 4) + dp->val.f = *((float*) a_fpr), a_fpr++, fpr++; + else + dp->val.f = *(((float*) a_ov )+1), a_ov++; + break; + case nsXPTType::T_DOUBLE : + if (fpr < 4) + dp->val.d = *((double*) a_fpr), a_fpr++, fpr++; + else + dp->val.d = *((double*) a_ov ), a_ov++; + break; + case nsXPTType::T_BOOL : + if (gpr < 5) + dp->val.b = *((PRUint64*)a_gpr), a_gpr++, gpr++; + else + dp->val.b = *((PRUint64*)a_ov ), a_ov++; + break; + case nsXPTType::T_CHAR : + if (gpr < 5) + dp->val.c = *((PRUint64*)a_gpr), a_gpr++, gpr++; + else + dp->val.c = *((PRUint64*)a_ov ), a_ov++; + break; + case nsXPTType::T_WCHAR : + if (gpr < 5) + dp->val.wc = *((PRUint64*)a_gpr), a_gpr++, gpr++; + else + dp->val.wc = *((PRUint64*)a_ov ), a_ov++; + break; + default: + NS_ASSERTION(0, "bad type"); + break; + } + } + + result = self->CallMethod((PRUint16)methodIndex, info, dispatchParams); + + NS_RELEASE(iface_info); + + if(dispatchParams != paramBuffer) + delete [] dispatchParams; + + return result; +} + +#define STUB_ENTRY(n) \ +nsresult nsXPTCStubBase::Stub##n() \ +{ \ + PRUint64 a_gpr[4]; \ + PRUint64 a_fpr[4]; \ + PRUint64 *a_ov; \ + \ + __asm__ __volatile__ \ + ( \ + "lg %0,0(15)\n\t" \ + "aghi %0,160\n\t" \ + "stmg 3,6,0(%5)\n\t"\ + "std 0,%1\n\t" \ + "std 2,%2\n\t" \ + "std 4,%3\n\t" \ + "std 6,%4\n\t" \ + : "=&a" (a_ov), \ + "=m" (a_fpr[0]), \ + "=m" (a_fpr[1]), \ + "=m" (a_fpr[2]), \ + "=m" (a_fpr[3]) \ + : "a" (a_gpr) \ + : "memory", "cc", \ + "3", "4", "5", "6" \ + ); \ + \ + return PrepareAndDispatch(this, n, a_gpr, a_fpr, a_ov); \ +} + +#define SENTINEL_ENTRY(n) \ +nsresult nsXPTCStubBase::Sentinel##n() \ +{ \ + NS_ASSERTION(0,"nsXPTCStubBase::Sentinel called"); \ + return NS_ERROR_NOT_IMPLEMENTED; \ +} + +#include "xptcstubsdef.inc" + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_mips.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_mips.cpp new file mode 100644 index 00000000..4d60f7be --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_mips.cpp @@ -0,0 +1,131 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * Version: MPL 1.1 + * + * ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corp, Inc. + * Portions created by the Initial Developer are Copyright (C) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Stuart Parmenter + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "xptcprivate.h" + +/* + * This is for MIPS O32 ABI + * Args contains a0-3 and then the stack. + * Because a0 is 'this', we want to skip it + */ +extern "C" nsresult +PrepareAndDispatch(nsXPTCStubBase* self, PRUint32 methodIndex, PRUint32* args) +{ + args++; // always skip over a0 + +#define PARAM_BUFFER_COUNT 16 + + nsXPTCMiniVariant paramBuffer[PARAM_BUFFER_COUNT]; + nsXPTCMiniVariant* dispatchParams = NULL; + nsIInterfaceInfo* iface_info = NULL; + const nsXPTMethodInfo* info; + PRUint8 paramCount; + PRUint8 i; + nsresult result = NS_ERROR_FAILURE; + + NS_ASSERTION(self,"no self"); + + self->GetInterfaceInfo(&iface_info); + NS_ASSERTION(iface_info,"no interface info"); + + iface_info->GetMethodInfo(PRUint16(methodIndex), &info); + NS_ASSERTION(info,"no interface info"); + + paramCount = info->GetParamCount(); + + // setup variant array pointer + if(paramCount > PARAM_BUFFER_COUNT) + dispatchParams = new nsXPTCMiniVariant[paramCount]; + else + dispatchParams = paramBuffer; + NS_ASSERTION(dispatchParams,"no place for params"); + + PRUint32* ap = args; + for(i = 0; i < paramCount; i++, ap++) + { + const nsXPTParamInfo& param = info->GetParam(i); + const nsXPTType& type = param.GetType(); + nsXPTCMiniVariant* dp = &dispatchParams[i]; + + if(param.IsOut() || !type.IsArithmetic()) + { + dp->val.p = (void*) *ap; + continue; + } + + dp->val.p = (void*) *ap; + + switch(type) + { + case nsXPTType::T_I64 : + if ((PRWord)ap & 4) ap++; + dp->val.i64 = *((PRInt64*) ap); ap++; + break; + case nsXPTType::T_U64 : + if ((PRWord)ap & 4) ap++; + dp->val.u64 = *((PRInt64*) ap); ap++; + break; + case nsXPTType::T_DOUBLE: + if ((PRWord)ap & 4) ap++; + dp->val.d = *((double*) ap); ap++; + break; + } + } + + result = self->CallMethod((PRUint16)methodIndex, info, dispatchParams); + + NS_RELEASE(iface_info); + + if(dispatchParams != paramBuffer) + delete [] dispatchParams; + + return result; +} + +#define STUB_ENTRY(n) // done in the .s file + +#define SENTINEL_ENTRY(n) \ +nsresult nsXPTCStubBase::Sentinel##n() \ +{ \ + NS_ASSERTION(0,"nsXPTCStubBase::Sentinel called"); \ + return NS_ERROR_NOT_IMPLEMENTED; \ +} + +#include "xptcstubsdef.inc" diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_netbsd_m68k.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_netbsd_m68k.cpp new file mode 100644 index 00000000..4069a6bc --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_netbsd_m68k.cpp @@ -0,0 +1,147 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Implement shared vtbl methods. */ + +#include "xptcprivate.h" + +#if !defined(__NetBSD__) || !defined(__m68k__) +#error This code is for NetBSD/m68k only +#endif + +extern "C" { + static nsresult + PrepareAndDispatch(nsXPTCStubBase* self, uint32 methodIndex, uint32* args) + { +#define PARAM_BUFFER_COUNT 16 + + nsXPTCMiniVariant paramBuffer[PARAM_BUFFER_COUNT]; + nsXPTCMiniVariant* dispatchParams = NULL; + nsIInterfaceInfo* iface_info = NULL; + const nsXPTMethodInfo* info; + PRUint8 paramCount; + PRUint8 i; + nsresult result = NS_ERROR_FAILURE; + + NS_ASSERTION(self,"no self"); + + self->GetInterfaceInfo(&iface_info); + NS_ASSERTION(iface_info,"no interface info"); + + iface_info->GetMethodInfo(PRUint16(methodIndex), &info); + NS_ASSERTION(info,"no interface info"); + + paramCount = info->GetParamCount(); + + // setup variant array pointer + if(paramCount > PARAM_BUFFER_COUNT) + dispatchParams = new nsXPTCMiniVariant[paramCount]; + else + dispatchParams = paramBuffer; + NS_ASSERTION(dispatchParams,"no place for params"); + + PRUint32* ap = args; + for(i = 0; i < paramCount; i++, ap++) + { + const nsXPTParamInfo& param = info->GetParam(i); + const nsXPTType& type = param.GetType(); + nsXPTCMiniVariant* dp = &dispatchParams[i]; + + if(param.IsOut() || !type.IsArithmetic()) + { + dp->val.p = (void*) *ap; + continue; + } + + switch(type) + { + // the 8 and 16 bit types will have been promoted to 32 bits before + // being pushed onto the stack. Since the 68k is big endian, we + // need to skip over the leading high order bytes. + case nsXPTType::T_I8 : dp->val.i8 = *(((PRInt8*) ap) + 3); break; + case nsXPTType::T_I16 : dp->val.i16 = *(((PRInt16*) ap) + 1); break; + case nsXPTType::T_I32 : dp->val.i32 = *((PRInt32*) ap); break; + case nsXPTType::T_I64 : dp->val.i64 = *((PRInt64*) ap); ap++; break; + case nsXPTType::T_U8 : dp->val.u8 = *(((PRUint8*) ap) + 3); break; + case nsXPTType::T_U16 : dp->val.u16 = *(((PRUint16*)ap) + 1); break; + case nsXPTType::T_U32 : dp->val.u32 = *((PRUint32*)ap); break; + case nsXPTType::T_U64 : dp->val.u64 = *((PRUint64*)ap); ap++; break; + case nsXPTType::T_FLOAT : dp->val.f = *((float*) ap); break; + case nsXPTType::T_DOUBLE : dp->val.d = *((double*) ap); ap++; break; + case nsXPTType::T_BOOL : dp->val.b = *((PRBool*) ap); break; + case nsXPTType::T_CHAR : dp->val.c = *(((char*) ap) + 3); break; + // wchar_t is an int (32 bits) on NetBSD + case nsXPTType::T_WCHAR : dp->val.wc = *((wchar_t*) ap); break; + default: + NS_ASSERTION(0, "bad type"); + break; + } + } + + result = self->CallMethod((PRUint16)methodIndex, info, dispatchParams); + + NS_RELEASE(iface_info); + + if(dispatchParams != paramBuffer) + delete [] dispatchParams; + + return result; + } +} + +#define STUB_ENTRY(n) \ +__asm__( \ + ".global _Stub"#n"__14nsXPTCStubBase\n\t" \ +"_Stub"#n"__14nsXPTCStubBase:\n\t" \ + "link a6,#0 \n\t" \ + "lea a6@(12), a0 \n\t" /* pointer to args */ \ + "movl a0, sp@- \n\t" \ + "movl #"#n", sp@- \n\t" /* method index */ \ + "movl a6@(8), sp@- \n\t" /* this */ \ + "jbsr _PrepareAndDispatch \n\t" \ + "unlk a6 \n\t" \ + "rts \n\t" \ +); + +#define SENTINEL_ENTRY(n) \ +nsresult nsXPTCStubBase::Sentinel##n() \ +{ \ + NS_ASSERTION(0,"nsXPTCStubBase::Sentinel called"); \ + return NS_ERROR_NOT_IMPLEMENTED; \ +} + +#include "xptcstubsdef.inc" diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_openvms_alpha.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_openvms_alpha.cpp new file mode 100644 index 00000000..c4d1b364 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_openvms_alpha.cpp @@ -0,0 +1,147 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Implement shared vtbl methods. */ + +#include "xptcprivate.h" + +extern "C" { + +nsresult +PrepareAndDispatch(nsXPTCStubBase* self, uint32 methodIndex, PRUint64* args) +{ + const PRUint8 PARAM_BUFFER_COUNT = 16; + const PRUint8 NUM_ARG_REGS = 6-1; // -1 for "this" pointer + + nsXPTCMiniVariant paramBuffer[PARAM_BUFFER_COUNT]; + nsXPTCMiniVariant* dispatchParams = NULL; + nsIInterfaceInfo* iface_info = NULL; + const nsXPTMethodInfo* info; + PRUint8 paramCount; + PRUint8 i; + nsresult result = NS_ERROR_FAILURE; + + NS_ASSERTION(self,"no self"); + + self->GetInterfaceInfo(&iface_info); + NS_ASSERTION(iface_info,"no interface info"); + + iface_info->GetMethodInfo(PRUint16(methodIndex), &info); + NS_ASSERTION(info,"no interface info"); + + paramCount = info->GetParamCount(); + + // setup variant array pointer + if(paramCount > PARAM_BUFFER_COUNT) + dispatchParams = new nsXPTCMiniVariant[paramCount]; + else + dispatchParams = paramBuffer; + NS_ASSERTION(dispatchParams,"no place for params"); + + // args[0] to args[NUM_ARG_REGS] hold floating point register values + PRUint64* ap = args + NUM_ARG_REGS; + for(i = 0; i < paramCount; i++, ap++) + { + const nsXPTParamInfo& param = info->GetParam(i); + const nsXPTType& type = param.GetType(); + nsXPTCMiniVariant* dp = &dispatchParams[i]; + + if(param.IsOut() || !type.IsArithmetic()) + { + dp->val.p = (void*) *ap; + continue; + } + // else + switch(type) + { + case nsXPTType::T_I8 : dp->val.i8 = (PRInt8) *ap; break; + case nsXPTType::T_I16 : dp->val.i16 = (PRInt16) *ap; break; + case nsXPTType::T_I32 : dp->val.i32 = (PRInt32) *ap; break; + case nsXPTType::T_I64 : dp->val.i64 = (PRInt64) *ap; break; + case nsXPTType::T_U8 : dp->val.u8 = (PRUint8) *ap; break; + case nsXPTType::T_U16 : dp->val.u16 = (PRUint16) *ap; break; + case nsXPTType::T_U32 : dp->val.u32 = (PRUint32) *ap; break; + case nsXPTType::T_U64 : dp->val.u64 = (PRUint64) *ap; break; + case nsXPTType::T_FLOAT : + if(i < NUM_ARG_REGS) + { + // floats passed via registers are stored as doubles + // in the first NUM_ARG_REGS entries in args + dp->val.u64 = (PRUint64) args[i]; + dp->val.f = (float) dp->val.d; // convert double to float + } + else + dp->val.u32 = (PRUint32) *ap; + break; + case nsXPTType::T_DOUBLE : + // doubles passed via registers are also stored + // in the first NUM_ARG_REGS entries in args + dp->val.u64 = (i < NUM_ARG_REGS) ? args[i] : *ap; + break; + case nsXPTType::T_BOOL : dp->val.b = (PRBool) *ap; break; + case nsXPTType::T_CHAR : dp->val.c = (char) *ap; break; + case nsXPTType::T_WCHAR : dp->val.wc = (PRUnichar) *ap; break; + default: + NS_ASSERTION(0, "bad type"); + break; + } + } + + result = self->CallMethod((PRUint16)methodIndex, info, dispatchParams); + + NS_RELEASE(iface_info); + + if(dispatchParams != paramBuffer) + delete [] dispatchParams; + + return result; +} + +} + +#define STUB_ENTRY(n) /* This is in the ASM file */ + +#define SENTINEL_ENTRY(n) \ +nsresult nsXPTCStubBase::Sentinel##n() \ +{ \ + NS_ASSERTION(0,"nsXPTCStubBase::Sentinel called"); \ + return NS_ERROR_NOT_IMPLEMENTED; \ +} + +#include "xptcstubsdef.inc" + + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_osf1_alpha.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_osf1_alpha.cpp new file mode 100644 index 00000000..cd8fe40b --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_osf1_alpha.cpp @@ -0,0 +1,149 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Implement shared vtbl methods. */ + +/* contributed by Glen Nakamura */ + +#include "xptcprivate.h" + +extern "C" nsresult +PrepareAndDispatch(nsXPTCStubBase* self, uint32 methodIndex, PRUint64* args) +{ + const PRUint8 PARAM_BUFFER_COUNT = 16; + const PRUint8 NUM_ARG_REGS = 6-1; // -1 for "this" pointer + + nsXPTCMiniVariant paramBuffer[PARAM_BUFFER_COUNT]; + nsXPTCMiniVariant* dispatchParams = NULL; + nsIInterfaceInfo* iface_info = NULL; + const nsXPTMethodInfo* info; + PRUint8 paramCount; + PRUint8 i; + nsresult result = NS_ERROR_FAILURE; + + NS_ASSERTION(self,"no self"); + + self->GetInterfaceInfo(&iface_info); + NS_ASSERTION(iface_info,"no interface info"); + + iface_info->GetMethodInfo(PRUint16(methodIndex), &info); + NS_ASSERTION(info,"no interface info"); + + paramCount = info->GetParamCount(); + + // setup variant array pointer + if(paramCount > PARAM_BUFFER_COUNT) + dispatchParams = new nsXPTCMiniVariant[paramCount]; + else + dispatchParams = paramBuffer; + NS_ASSERTION(dispatchParams,"no place for params"); + + // args[0] to args[NUM_ARG_REGS] hold floating point register values + PRUint64* ap = args + NUM_ARG_REGS; + for(i = 0; i < paramCount; i++, ap++) + { + const nsXPTParamInfo& param = info->GetParam(i); + const nsXPTType& type = param.GetType(); + nsXPTCMiniVariant* dp = &dispatchParams[i]; + + if(param.IsOut() || !type.IsArithmetic()) + { + dp->val.p = (void*) *ap; + continue; + } + // else + switch(type) + { + case nsXPTType::T_I8 : dp->val.i8 = (PRInt8) *ap; break; + case nsXPTType::T_I16 : dp->val.i16 = (PRInt16) *ap; break; + case nsXPTType::T_I32 : dp->val.i32 = (PRInt32) *ap; break; + case nsXPTType::T_I64 : dp->val.i64 = (PRInt64) *ap; break; + case nsXPTType::T_U8 : dp->val.u8 = (PRUint8) *ap; break; + case nsXPTType::T_U16 : dp->val.u16 = (PRUint16) *ap; break; + case nsXPTType::T_U32 : dp->val.u32 = (PRUint32) *ap; break; + case nsXPTType::T_U64 : dp->val.u64 = (PRUint64) *ap; break; + case nsXPTType::T_FLOAT : + if(i < NUM_ARG_REGS) + { + // floats passed via registers are stored as doubles + // in the first NUM_ARG_REGS entries in args + dp->val.u64 = (PRUint64) args[i]; + dp->val.f = (float) dp->val.d; // convert double to float + } + else + dp->val.u32 = (PRUint32) *ap; + break; + case nsXPTType::T_DOUBLE : + // doubles passed via registers are also stored + // in the first NUM_ARG_REGS entries in args + dp->val.u64 = (i < NUM_ARG_REGS) ? args[i] : *ap; + break; + case nsXPTType::T_BOOL : dp->val.b = (PRBool) *ap; break; + case nsXPTType::T_CHAR : dp->val.c = (char) *ap; break; + case nsXPTType::T_WCHAR : dp->val.wc = (PRUnichar) *ap; break; + default: + NS_ASSERTION(0, "bad type"); + break; + } + } + + result = self->CallMethod((PRUint16)methodIndex, info, dispatchParams); + + NS_RELEASE(iface_info); + + if(dispatchParams != paramBuffer) + delete [] dispatchParams; + + return result; +} + +/* + * nsresult nsXPTCStubBase::Stub##n() ;\ + * Sets arguments to registers and calls PrepareAndDispatch. + * This is defined in the ASM file. + */ +#define STUB_ENTRY(n) \ + +#define SENTINEL_ENTRY(n) \ +nsresult nsXPTCStubBase::Sentinel##n() \ +{ \ + NS_ASSERTION(0,"nsXPTCStubBase::Sentinel called"); \ + return NS_ERROR_NOT_IMPLEMENTED; \ +} + +#include "xptcstubsdef.inc" + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_pa32.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_pa32.cpp new file mode 100644 index 00000000..b3a42442 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_pa32.cpp @@ -0,0 +1,176 @@ + +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Implement shared vtbl methods. */ + +#include "xptcprivate.h" + +#if _HPUX +#error "This code is for HP-PA RISC 32 bit mode only" +#endif + +extern "C" nsresult +PrepareAndDispatch(nsXPTCStubBase* self, PRUint32 methodIndex, + PRUint32* args, PRUint32* floatargs) +{ + + typedef struct { + uint32 hi; + uint32 lo; + } DU; + +#define PARAM_BUFFER_COUNT 16 + + nsXPTCMiniVariant paramBuffer[PARAM_BUFFER_COUNT]; + nsXPTCMiniVariant* dispatchParams = NULL; + nsIInterfaceInfo* iface_info = NULL; + const nsXPTMethodInfo* info; + PRInt32 regwords = 1; /* self pointer is not in the variant records */ + nsresult result = NS_ERROR_FAILURE; + PRUint8 paramCount; + PRUint8 i; + + NS_ASSERTION(self,"no self"); + + self->GetInterfaceInfo(&iface_info); + NS_ASSERTION(iface_info,"no interface info"); + + iface_info->GetMethodInfo(PRUint16(methodIndex), &info); + NS_ASSERTION(info,"no interface info"); + + paramCount = info->GetParamCount(); + + // setup variant array pointer + if(paramCount > PARAM_BUFFER_COUNT) + dispatchParams = new nsXPTCMiniVariant[paramCount]; + else + dispatchParams = paramBuffer; + NS_ASSERTION(dispatchParams,"no place for params"); + + for(i = 0; i < paramCount; ++i, --args) + { + const nsXPTParamInfo& param = info->GetParam(i); + const nsXPTType& type = param.GetType(); + nsXPTCMiniVariant* dp = &dispatchParams[i]; + + if(param.IsOut() || !type.IsArithmetic()) + { + dp->val.p = (void*) *args; + ++regwords; + continue; + } + switch(type) + { + case nsXPTType::T_I8 : dp->val.i8 = *((PRInt32*) args); break; + case nsXPTType::T_I16 : dp->val.i16 = *((PRInt32*) args); break; + case nsXPTType::T_I32 : dp->val.i32 = *((PRInt32*) args); break; + case nsXPTType::T_DOUBLE : + if (regwords & 1) + { + ++regwords; /* align on double word */ + --args; + } + if (regwords == 0 || regwords == 2) + { + dp->val.d=*((double*) (floatargs + regwords)); + --args; + } + else + { + dp->val.d = *((double*) --args); + } + regwords += 2; + continue; + case nsXPTType::T_U64 : + case nsXPTType::T_I64 : + if (regwords & 1) + { + ++regwords; /* align on double word */ + --args; + } + ((DU *)dp)->lo = *((PRUint32*) args); + ((DU *)dp)->hi = *((PRUint32*) --args); + regwords += 2; + continue; + case nsXPTType::T_FLOAT : + if (regwords >= 4) + dp->val.f = *((float*) args); + else + dp->val.f = *((float*) floatargs+4+regwords); + break; + case nsXPTType::T_U8 : dp->val.u8 = *((PRUint32*) args); break; + case nsXPTType::T_U16 : dp->val.u16 = *((PRUint32*) args); break; + case nsXPTType::T_U32 : dp->val.u32 = *((PRUint32*) args); break; + case nsXPTType::T_BOOL : dp->val.b = *((PRBool*) args); break; + case nsXPTType::T_CHAR : dp->val.c = *((PRUint32*) args); break; + case nsXPTType::T_WCHAR : dp->val.wc = *((PRInt32*) args); break; + default: + NS_ASSERTION(0, "bad type"); + break; + } + ++regwords; + } + + result = self->CallMethod((PRUint16) methodIndex, info, dispatchParams); + + NS_RELEASE(iface_info); + + if(dispatchParams != paramBuffer) + delete [] dispatchParams; + + return result; +} + +extern "C" int SharedStub(int); + +#define STUB_ENTRY(n) \ +nsresult nsXPTCStubBase::Stub##n() \ +{ \ + return SharedStub(n); \ +} + +#define SENTINEL_ENTRY(n) \ +nsresult nsXPTCStubBase::Sentinel##n() \ +{ \ + NS_ASSERTION(0,"nsXPTCStubBase::Sentinel called"); \ + return NS_ERROR_NOT_IMPLEMENTED; \ +} + +#include "xptcstubsdef.inc" + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_ppc_aix.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_ppc_aix.cpp new file mode 100644 index 00000000..870669d7 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_ppc_aix.cpp @@ -0,0 +1,228 @@ +/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Implement shared vtbl methods. */ + +#include "xptcprivate.h" + +#if defined(AIX) + +/* + For PPC (AIX & MAC), the first 8 integral and the first 13 f.p. parameters + arrive in a separate chunk of data that has been loaded from the registers. + The args pointer has been set to the start of the parameters BEYOND the ones + arriving in registers +*/ +extern "C" nsresult +PrepareAndDispatch(nsXPTCStubBase* self, PRUint32 methodIndex, PRUint32* args, PRUint32 *gprData, double *fprData) +{ + typedef struct { + uint32 hi; + uint32 lo; // have to move 64 bit entities as 32 bit halves since + } DU; // stack slots are not guaranteed 16 byte aligned + +#define PARAM_BUFFER_COUNT 16 +#define PARAM_GPR_COUNT 7 + + nsXPTCMiniVariant paramBuffer[PARAM_BUFFER_COUNT]; + nsXPTCMiniVariant* dispatchParams = NULL; + nsIInterfaceInfo* iface_info = NULL; + const nsXPTMethodInfo* info; + PRUint8 paramCount; + PRUint8 i; + nsresult result = NS_ERROR_FAILURE; + + NS_ASSERTION(self,"no self"); + + self->GetInterfaceInfo(&iface_info); + NS_ASSERTION(iface_info,"no interface info"); + + iface_info->GetMethodInfo(PRUint16(methodIndex), &info); + NS_ASSERTION(info,"no interface info"); + + paramCount = info->GetParamCount(); + + // setup variant array pointer + if(paramCount > PARAM_BUFFER_COUNT) + dispatchParams = new nsXPTCMiniVariant[paramCount]; + else + dispatchParams = paramBuffer; + NS_ASSERTION(dispatchParams,"no place for params"); + + PRUint32* ap = args; + PRUint32 iCount = 0; + PRUint32 fpCount = 0; + for(i = 0; i < paramCount; i++) + { + const nsXPTParamInfo& param = info->GetParam(i); + const nsXPTType& type = param.GetType(); + nsXPTCMiniVariant* dp = &dispatchParams[i]; + + if(param.IsOut() || !type.IsArithmetic()) + { + if (iCount < PARAM_GPR_COUNT) + dp->val.p = (void*) gprData[iCount++]; + else + dp->val.p = (void*) *ap++; + continue; + } + // else + switch(type) + { + case nsXPTType::T_I8 : if (iCount < PARAM_GPR_COUNT) + dp->val.i8 = (PRInt8) gprData[iCount++]; + else + dp->val.i8 = (PRInt8) *ap++; + break; + case nsXPTType::T_I16 : if (iCount < PARAM_GPR_COUNT) + dp->val.i16 = (PRInt16) gprData[iCount++]; + else + dp->val.i16 = (PRInt16) *ap++; + break; + case nsXPTType::T_I32 : if (iCount < PARAM_GPR_COUNT) + dp->val.i32 = (PRInt32) gprData[iCount++]; + else + dp->val.i32 = (PRInt32) *ap++; + break; + case nsXPTType::T_I64 : if (iCount < PARAM_GPR_COUNT) + ((DU *)dp)->hi = (PRInt32) gprData[iCount++]; + else + ((DU *)dp)->hi = (PRInt32) *ap++; + if (iCount < PARAM_GPR_COUNT) + ((DU *)dp)->lo = (PRUint32) gprData[iCount++]; + else + ((DU *)dp)->lo = (PRUint32) *ap++; + break; + case nsXPTType::T_U8 : if (iCount < PARAM_GPR_COUNT) + dp->val.u8 = (PRUint8) gprData[iCount++]; + else + dp->val.u8 = (PRUint8) *ap++; + break; + case nsXPTType::T_U16 : if (iCount < PARAM_GPR_COUNT) + dp->val.u16 = (PRUint16) gprData[iCount++]; + else + dp->val.u16 = (PRUint16) *ap++; + break; + case nsXPTType::T_U32 : if (iCount < PARAM_GPR_COUNT) + dp->val.u32 = (PRUint32) gprData[iCount++]; + else + dp->val.u32 = (PRUint32) *ap++; + break; + case nsXPTType::T_U64 : if (iCount < PARAM_GPR_COUNT) + ((DU *)dp)->hi = (PRUint32) gprData[iCount++]; + else + ((DU *)dp)->hi = (PRUint32) *ap++; + if (iCount < PARAM_GPR_COUNT) + ((DU *)dp)->lo = (PRUint32) gprData[iCount++]; + else + ((DU *)dp)->lo = (PRUint32) *ap++; + break; + case nsXPTType::T_FLOAT : if (fpCount < 13) { + dp->val.f = (float) fprData[fpCount++]; + if (iCount < PARAM_GPR_COUNT) + ++iCount; + else + ++ap; + } + else + dp->val.f = *((float*) ap++); + break; + case nsXPTType::T_DOUBLE : if (fpCount < 13) { + dp->val.d = (double) fprData[fpCount++]; + if (iCount < PARAM_GPR_COUNT) + ++iCount; + else + ++ap; + if (iCount < PARAM_GPR_COUNT) + ++iCount; + else + ++ap; + } + else { + dp->val.f = *((double*) ap); + ap += 2; + } + break; + case nsXPTType::T_BOOL : if (iCount < PARAM_GPR_COUNT) + dp->val.b = (PRBool) gprData[iCount++]; + else + dp->val.b = (PRBool) *ap++; + break; + case nsXPTType::T_CHAR : if (iCount < PARAM_GPR_COUNT) + dp->val.c = (char) gprData[iCount++]; + else + dp->val.c = (char) *ap++; + break; + case nsXPTType::T_WCHAR : if (iCount < PARAM_GPR_COUNT) + dp->val.wc = (wchar_t) gprData[iCount++]; + else + dp->val.wc = (wchar_t) *ap++; + break; + default: + NS_ASSERTION(0, "bad type"); + break; + } + } + + result = self->CallMethod((PRUint16)methodIndex, info, dispatchParams); + + NS_RELEASE(iface_info); + + if(dispatchParams != paramBuffer) + delete [] dispatchParams; + + return result; +} + +extern "C" int SharedStub(int); + +#define STUB_ENTRY(n) \ +nsresult nsXPTCStubBase::Stub##n() \ +{ \ + return SharedStub(n); \ +} \ + +#define SENTINEL_ENTRY(n) \ +nsresult nsXPTCStubBase::Sentinel##n() \ +{ \ + NS_ASSERTION(0,"nsXPTCStubBase::Sentinel called"); \ + return NS_ERROR_NOT_IMPLEMENTED; \ +} + +#include "xptcstubsdef.inc" + +#endif /* AIX */ diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_ppc_aix64.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_ppc_aix64.cpp new file mode 100644 index 00000000..cf2ddba9 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_ppc_aix64.cpp @@ -0,0 +1,215 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/LGPL 2.1/GPL 2.0 + * + * 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.org code. + * + * The Initial Developer of the Original Code is IBM Corporation. + * Portions created by IBM are + * Copyright (C) 2002, International Business Machines Corporation. + * All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 LGPL or the GPL. 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 ***** */ + +/* Implement shared vtbl methods. */ + +#include "xptcprivate.h" + +#if defined(AIX) + +/* + For PPC (AIX & MAC), the first 8 integral and the first 13 f.p. parameters + arrive in a separate chunk of data that has been loaded from the registers. + The args pointer has been set to the start of the parameters BEYOND the ones + arriving in registers +*/ +extern "C" nsresult +PrepareAndDispatch(nsXPTCStubBase* self, PRUint64 methodIndex, PRUint64* args, PRUint64 *gprData, double *fprData) +{ + +#define PARAM_BUFFER_COUNT 16 +#define PARAM_GPR_COUNT 7 + + nsXPTCMiniVariant paramBuffer[PARAM_BUFFER_COUNT]; + nsXPTCMiniVariant* dispatchParams = NULL; + nsIInterfaceInfo* iface_info = NULL; + const nsXPTMethodInfo* info; + PRUint8 paramCount; + PRUint8 i; + nsresult result = NS_ERROR_FAILURE; + + NS_ASSERTION(self,"no self"); + + self->GetInterfaceInfo(&iface_info); + NS_ASSERTION(iface_info,"no interface info"); + + iface_info->GetMethodInfo(PRUint16(methodIndex), &info); + NS_ASSERTION(info,"no interface info"); + + paramCount = info->GetParamCount(); + + // setup variant array pointer + if(paramCount > PARAM_BUFFER_COUNT) + dispatchParams = new nsXPTCMiniVariant[paramCount]; + else + dispatchParams = paramBuffer; + NS_ASSERTION(dispatchParams,"no place for params"); + + PRUint64* ap = args; + PRUint32 iCount = 0; + PRUint32 fpCount = 0; + for(i = 0; i < paramCount; i++) + { + const nsXPTParamInfo& param = info->GetParam(i); + const nsXPTType& type = param.GetType(); + nsXPTCMiniVariant* dp = &dispatchParams[i]; + + if(param.IsOut() || !type.IsArithmetic()) + { + if (iCount < PARAM_GPR_COUNT) + dp->val.p = (void*) gprData[iCount++]; + else + dp->val.p = (void*) *ap++; + continue; + } + // else + switch(type) + { + case nsXPTType::T_I8 : if (iCount < PARAM_GPR_COUNT) + dp->val.i8 = (PRInt8) gprData[iCount++]; + else + dp->val.i8 = (PRInt8) *ap++; + break; + case nsXPTType::T_I16 : if (iCount < PARAM_GPR_COUNT) + dp->val.i16 = (PRInt16) gprData[iCount++]; + else + dp->val.i16 = (PRInt16) *ap++; + break; + case nsXPTType::T_I32 : if (iCount < PARAM_GPR_COUNT) + dp->val.i32 = (PRInt32) gprData[iCount++]; + else + dp->val.i32 = (PRInt32) *ap++; + break; + case nsXPTType::T_I64 : if (iCount < PARAM_GPR_COUNT) + dp->val.i64 = (PRInt64) gprData[iCount++]; + else + dp->val.i64 = (PRInt64) *ap++; + break; + case nsXPTType::T_U8 : if (iCount < PARAM_GPR_COUNT) + dp->val.u8 = (PRUint8) gprData[iCount++]; + else + dp->val.u8 = (PRUint8) *ap++; + break; + case nsXPTType::T_U16 : if (iCount < PARAM_GPR_COUNT) + dp->val.u16 = (PRUint16) gprData[iCount++]; + else + dp->val.u16 = (PRUint16) *ap++; + break; + case nsXPTType::T_U32 : if (iCount < PARAM_GPR_COUNT) + dp->val.u32 = (PRUint32) gprData[iCount++]; + else + dp->val.u32 = (PRUint32) *ap++; + break; + case nsXPTType::T_U64 : if (iCount < PARAM_GPR_COUNT) + dp->val.u64 = (PRUint64) gprData[iCount++]; + else + dp->val.u64 = (PRUint64) *ap++; + break; + case nsXPTType::T_FLOAT : if (fpCount < 13) { + dp->val.f = (float) fprData[fpCount++]; + if (iCount < PARAM_GPR_COUNT) + ++iCount; + else + ++ap; + } + else + dp->val.f = *((float*) ap++); + break; + case nsXPTType::T_DOUBLE : if (fpCount < 13) { + dp->val.d = (double) fprData[fpCount++]; + if (iCount < PARAM_GPR_COUNT) + ++iCount; + else + ++ap; + if (iCount < PARAM_GPR_COUNT) + ++iCount; + else + ++ap; + } + else { + dp->val.f = *((double*) ap); + ap += 2; + } + break; + case nsXPTType::T_BOOL : if (iCount < PARAM_GPR_COUNT) + dp->val.b = (PRBool) gprData[iCount++]; + else + dp->val.b = (PRBool) *ap++; + break; + case nsXPTType::T_CHAR : if (iCount < PARAM_GPR_COUNT) + dp->val.c = (char) gprData[iCount++]; + else + dp->val.c = (char) *ap++; + break; + case nsXPTType::T_WCHAR : if (iCount < PARAM_GPR_COUNT) + dp->val.wc = (wchar_t) gprData[iCount++]; + else + dp->val.wc = (wchar_t) *ap++; + break; + default: + NS_ASSERTION(0, "bad type"); + break; + } + } + + result = self->CallMethod((PRUint16)methodIndex, info, dispatchParams); + + NS_RELEASE(iface_info); + + if(dispatchParams != paramBuffer) + delete [] dispatchParams; + + return result; +} + +extern "C" int SharedStub(int); + +#define STUB_ENTRY(n) \ +nsresult nsXPTCStubBase::Stub##n() \ +{ \ + return SharedStub(n); \ +} \ + +#define SENTINEL_ENTRY(n) \ +nsresult nsXPTCStubBase::Sentinel##n() \ +{ \ + NS_ASSERTION(0,"nsXPTCStubBase::Sentinel called"); \ + return NS_ERROR_NOT_IMPLEMENTED; \ +} + +#include "xptcstubsdef.inc" + +#endif /* AIX */ diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_ppc_linux.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_ppc_linux.cpp new file mode 100644 index 00000000..b1c98571 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_ppc_linux.cpp @@ -0,0 +1,253 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Franz.Sirl-kernel@lauterbach.com (Franz Sirl) + * beard@netscape.com (Patrick Beard) + * waterson@netscape.com (Chris Waterson) + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +// Implement shared vtbl methods. + +#include "xptcprivate.h" + +// The Linux/PPC ABI (aka PPC/SYSV ABI) passes the first 8 integral +// parameters and the first 8 floating point parameters in registers +// (r3-r10 and f1-f8), no stack space is allocated for these by the +// caller. The rest of the parameters are passed in the callers stack +// area. The stack pointer has to retain 16-byte alignment, longlongs +// and doubles are aligned on 8-byte boundaries. + +#define PARAM_BUFFER_COUNT 16 +#define GPR_COUNT 8 +#define FPR_COUNT 8 + +// PrepareAndDispatch() is called by SharedStub() and calls the actual method. +// +// - 'args[]' contains the arguments passed on stack +// - 'gprData[]' contains the arguments passed in integer registers +// - 'fprData[]' contains the arguments passed in floating point registers +// +// The parameters are mapped into an array of type 'nsXPTCMiniVariant' +// and then the method gets called. + +extern "C" nsresult +PrepareAndDispatch(nsXPTCStubBase* self, + PRUint32 methodIndex, + PRUint32* args, + PRUint32 *gprData, + double *fprData) +{ + nsXPTCMiniVariant paramBuffer[PARAM_BUFFER_COUNT]; + nsXPTCMiniVariant* dispatchParams = NULL; + nsIInterfaceInfo* iface_info = NULL; + const nsXPTMethodInfo* info; + PRUint32 paramCount; + PRUint32 i; + nsresult result = NS_ERROR_FAILURE; + + NS_ASSERTION(self,"no self"); + + self->GetInterfaceInfo(&iface_info); + NS_ASSERTION(iface_info,"no interface info"); + if (! iface_info) + return NS_ERROR_UNEXPECTED; + + iface_info->GetMethodInfo(PRUint16(methodIndex), &info); + NS_ASSERTION(info,"no method info"); + if (! info) + return NS_ERROR_UNEXPECTED; + + paramCount = info->GetParamCount(); + + // setup variant array pointer + if(paramCount > PARAM_BUFFER_COUNT) + dispatchParams = new nsXPTCMiniVariant[paramCount]; + else + dispatchParams = paramBuffer; + + NS_ASSERTION(dispatchParams,"no place for params"); + if (! dispatchParams) + return NS_ERROR_OUT_OF_MEMORY; + + PRUint32* ap = args; + PRUint32 gpr = 1; // skip one GPR register + PRUint32 fpr = 0; + PRUint32 tempu32; + PRUint64 tempu64; + + for(i = 0; i < paramCount; i++) { + const nsXPTParamInfo& param = info->GetParam(i); + const nsXPTType& type = param.GetType(); + nsXPTCMiniVariant* dp = &dispatchParams[i]; + + if (!param.IsOut() && type == nsXPTType::T_DOUBLE) { + if (fpr < FPR_COUNT) + dp->val.d = fprData[fpr++]; + else { + if ((PRUint32) ap & 4) ap++; // doubles are 8-byte aligned on stack + dp->val.d = *(double*) ap; + ap += 2; + } + continue; + } + else if (!param.IsOut() && type == nsXPTType::T_FLOAT) { + if (fpr < FPR_COUNT) + dp->val.f = (float) fprData[fpr++]; // in registers floats are passed as doubles + else + dp->val.f = *(float*) ap++; + continue; + } + else if (!param.IsOut() && (type == nsXPTType::T_I64 + || type == nsXPTType::T_U64)) { + if (gpr & 1) gpr++; // longlongs are aligned in odd/even register pairs, eg. r5/r6 + if ((gpr + 1) < GPR_COUNT) { + tempu64 = *(PRUint64*) &gprData[gpr]; + gpr += 2; + } + else { + if ((PRUint32) ap & 4) ap++; // longlongs are 8-byte aligned on stack + tempu64 = *(PRUint64*) ap; + ap += 2; + } + } + else { + if (gpr < GPR_COUNT) + tempu32 = gprData[gpr++]; + else + tempu32 = *ap++; + } + + if(param.IsOut() || !type.IsArithmetic()) { + dp->val.p = (void*) tempu32; + continue; + } + + switch(type) { + case nsXPTType::T_I8: dp->val.i8 = (PRInt8) tempu32; break; + case nsXPTType::T_I16: dp->val.i16 = (PRInt16) tempu32; break; + case nsXPTType::T_I32: dp->val.i32 = (PRInt32) tempu32; break; + case nsXPTType::T_I64: dp->val.i64 = (PRInt64) tempu64; break; + case nsXPTType::T_U8: dp->val.u8 = (PRUint8) tempu32; break; + case nsXPTType::T_U16: dp->val.u16 = (PRUint16) tempu32; break; + case nsXPTType::T_U32: dp->val.u32 = (PRUint32) tempu32; break; + case nsXPTType::T_U64: dp->val.u64 = (PRUint64) tempu64; break; + case nsXPTType::T_BOOL: dp->val.b = (PRBool) tempu32; break; + case nsXPTType::T_CHAR: dp->val.c = (char) tempu32; break; + case nsXPTType::T_WCHAR: dp->val.wc = (wchar_t) tempu32; break; + + default: + NS_ASSERTION(0, "bad type"); + break; + } + } + + result = self->CallMethod((PRUint16) methodIndex, info, dispatchParams); + + NS_RELEASE(iface_info); + + if (dispatchParams != paramBuffer) + delete [] dispatchParams; + + return result; +} + +// Load r11 with the constant 'n' and branch to SharedStub(). +// +// XXX Yes, it's ugly that we're relying on gcc's name-mangling here; +// however, it's quick, dirty, and'll break when the ABI changes on +// us, which is what we want ;-). + +#if __GXX_ABI_VERSION < 100 +// gcc-2 version +# define STUB_ENTRY(n) \ +__asm__ ( \ + ".section \".text\" \n\t" \ + ".align 2 \n\t" \ + ".globl Stub"#n"__14nsXPTCStubBase \n\t" \ + ".type Stub"#n"__14nsXPTCStubBase,@function \n\n" \ + \ +"Stub"#n"__14nsXPTCStubBase: \n\t" \ + "li 11,"#n" \n\t" \ + "b SharedStub@local \n" \ +); +#else +// gcc-3 version +// +// As G++3 ABI contains the length of the functionname in the mangled +// name, it is difficult to get a generic assembler mechanism like +// in the G++ 2.95 case. +// Create names would be like: +// _ZN14nsXPTCStubBase5Stub1Ev +// _ZN14nsXPTCStubBase6Stub12Ev +// _ZN14nsXPTCStubBase7Stub123Ev +// _ZN14nsXPTCStubBase8Stub1234Ev +// etc. +// Use assembler directives to get the names right... + +# define STUB_ENTRY(n) \ +__asm__ ( \ + ".align 2 \n\t" \ + ".if "#n" < 10 \n\t" \ + ".globl _ZN14nsXPTCStubBase5Stub"#n"Ev \n\t" \ + ".type _ZN14nsXPTCStubBase5Stub"#n"Ev,@function \n\n" \ +"_ZN14nsXPTCStubBase5Stub"#n"Ev: \n\t" \ + \ + ".elseif "#n" < 100 \n\t" \ + ".globl _ZN14nsXPTCStubBase6Stub"#n"Ev \n\t" \ + ".type _ZN14nsXPTCStubBase6Stub"#n"Ev,@function \n\n" \ +"_ZN14nsXPTCStubBase6Stub"#n"Ev: \n\t" \ + \ + ".elseif "#n" < 1000 \n\t" \ + ".globl _ZN14nsXPTCStubBase7Stub"#n"Ev \n\t" \ + ".type _ZN14nsXPTCStubBase7Stub"#n"Ev,@function \n\n" \ +"_ZN14nsXPTCStubBase7Stub"#n"Ev: \n\t" \ + \ + ".else \n\t" \ + ".err \"stub number "#n" >= 1000 not yet supported\"\n" \ + ".endif \n\t" \ + \ + "li 11,"#n" \n\t" \ + "b SharedStub@local \n" \ +); +#endif + +#define SENTINEL_ENTRY(n) \ +nsresult nsXPTCStubBase::Sentinel##n() \ +{ \ + NS_ASSERTION(0,"nsXPTCStubBase::Sentinel called"); \ + return NS_ERROR_NOT_IMPLEMENTED; \ +} + +#include "xptcstubsdef.inc" diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_ppc_netbsd.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_ppc_netbsd.cpp new file mode 100644 index 00000000..68d572ca --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_ppc_netbsd.cpp @@ -0,0 +1,217 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Franz.Sirl-kernel@lauterbach.com (Franz Sirl) + * beard@netscape.com (Patrick Beard) + * waterson@netscape.com (Chris Waterson) + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +// Implement shared vtbl methods. + +#include "xptcprivate.h" + +// The Linux/PPC ABI (aka PPC/SYSV ABI) passes the first 8 integral +// parameters and the first 8 floating point parameters in registers +// (r3-r10 and f1-f8), no stack space is allocated for these by the +// caller. The rest of the parameters are passed in the callers stack +// area. The stack pointer has to retain 16-byte alignment, longlongs +// and doubles are aligned on 8-byte boundaries. + +#define PARAM_BUFFER_COUNT 16 +#define GPR_COUNT 8 +#define FPR_COUNT 8 + +// PrepareAndDispatch() is called by SharedStub() and calls the actual method. +// +// - 'args[]' contains the arguments passed on stack +// - 'gprData[]' contains the arguments passed in integer registers +// - 'fprData[]' contains the arguments passed in floating point registers +// +// The parameters are mapped into an array of type 'nsXPTCMiniVariant' +// and then the method gets called. + +extern "C" nsresult +PrepareAndDispatch(nsXPTCStubBase* self, + PRUint32 methodIndex, + PRUint32* args, + PRUint32 *gprData, + double *fprData) +{ + nsXPTCMiniVariant paramBuffer[PARAM_BUFFER_COUNT]; + nsXPTCMiniVariant* dispatchParams = NULL; + nsIInterfaceInfo* iface_info = NULL; + const nsXPTMethodInfo* info; + PRUint32 paramCount; + PRUint32 i; + nsresult result = NS_ERROR_FAILURE; + + NS_ASSERTION(self,"no self"); + + self->GetInterfaceInfo(&iface_info); + NS_ASSERTION(iface_info,"no interface info"); + if (! iface_info) + return NS_ERROR_UNEXPECTED; + + iface_info->GetMethodInfo(PRUint16(methodIndex), &info); + NS_ASSERTION(info,"no method info"); + if (! info) + return NS_ERROR_UNEXPECTED; + + paramCount = info->GetParamCount(); + + // setup variant array pointer + if(paramCount > PARAM_BUFFER_COUNT) + dispatchParams = new nsXPTCMiniVariant[paramCount]; + else + dispatchParams = paramBuffer; + + NS_ASSERTION(dispatchParams,"no place for params"); + if (! dispatchParams) + return NS_ERROR_OUT_OF_MEMORY; + + PRUint32* ap = args; + PRUint32 gpr = 1; // skip one GPR register + PRUint32 fpr = 0; + PRUint32 tempu32; + PRUint64 tempu64; + + for(i = 0; i < paramCount; i++) { + const nsXPTParamInfo& param = info->GetParam(i); + const nsXPTType& type = param.GetType(); + nsXPTCMiniVariant* dp = &dispatchParams[i]; + + if (!param.IsOut() && type == nsXPTType::T_DOUBLE) { + if (fpr < FPR_COUNT) + dp->val.d = fprData[fpr++]; + else { + if ((PRUint32) ap & 4) ap++; // doubles are 8-byte aligned on stack + dp->val.d = *(double*) ap; + ap += 2; + if (gpr < GPR_COUNT) + gpr += 2; + } + continue; + } + else if (!param.IsOut() && type == nsXPTType::T_FLOAT) { + if (fpr < FPR_COUNT) + dp->val.f = (float) fprData[fpr++]; // in registers floats are passed as doubles + else { + dp->val.f = *(float*) ap; + ap += 1; + if (gpr < GPR_COUNT) + gpr += 1; + } + continue; + } + else if (!param.IsOut() && (type == nsXPTType::T_I64 + || type == nsXPTType::T_U64)) { + if (gpr & 1) gpr++; // longlongs are aligned in odd/even register pairs, eg. r5/r6 + if ((gpr + 1) < GPR_COUNT) { + tempu64 = *(PRUint64*) &gprData[gpr]; + gpr += 2; + } + else { + if ((PRUint32) ap & 4) ap++; // longlongs are 8-byte aligned on stack + tempu64 = *(PRUint64*) ap; + ap += 2; + } + } + else { + if (gpr < GPR_COUNT) + tempu32 = gprData[gpr++]; + else + tempu32 = *ap++; + } + + if(param.IsOut() || !type.IsArithmetic()) { + dp->val.p = (void*) tempu32; + continue; + } + + switch(type) { + case nsXPTType::T_I8: dp->val.i8 = (PRInt8) tempu32; break; + case nsXPTType::T_I16: dp->val.i16 = (PRInt16) tempu32; break; + case nsXPTType::T_I32: dp->val.i32 = (PRInt32) tempu32; break; + case nsXPTType::T_I64: dp->val.i64 = (PRInt64) tempu64; break; + case nsXPTType::T_U8: dp->val.u8 = (PRUint8) tempu32; break; + case nsXPTType::T_U16: dp->val.u16 = (PRUint16) tempu32; break; + case nsXPTType::T_U32: dp->val.u32 = (PRUint32) tempu32; break; + case nsXPTType::T_U64: dp->val.u64 = (PRUint64) tempu64; break; + case nsXPTType::T_BOOL: dp->val.b = (PRBool) tempu32; break; + case nsXPTType::T_CHAR: dp->val.c = (char) tempu32; break; + case nsXPTType::T_WCHAR: dp->val.wc = (wchar_t) tempu32; break; + + default: + NS_ASSERTION(0, "bad type"); + break; + } + } + + result = self->CallMethod((PRUint16) methodIndex, info, dispatchParams); + + NS_RELEASE(iface_info); + + if (dispatchParams != paramBuffer) + delete [] dispatchParams; + + return result; +} + +// Load r11 with the constant 'n' and branch to SharedStub(). +// +// XXX Yes, it's ugly that we're relying on gcc's name-mangling here; +// however, it's quick, dirty, and'll break when the ABI changes on +// us, which is what we want ;-). + +#define STUB_ENTRY(n) \ +__asm__ ( \ + ".section \".text\" \n\t" \ + ".align 2 \n\t" \ + ".globl Stub"#n"__14nsXPTCStubBase \n\t" \ + ".type Stub"#n"__14nsXPTCStubBase,@function \n\n" \ + \ +"Stub"#n"__14nsXPTCStubBase: \n\t" \ + "li 11,"#n" \n\t" \ + "b SharedStub@local \n" \ +); + +#define SENTINEL_ENTRY(n) \ +nsresult nsXPTCStubBase::Sentinel##n() \ +{ \ + NS_ASSERTION(0,"nsXPTCStubBase::Sentinel called"); \ + return NS_ERROR_NOT_IMPLEMENTED; \ +} + +#include "xptcstubsdef.inc" diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_ppc_rhapsody.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_ppc_rhapsody.cpp new file mode 100644 index 00000000..fcf96d4f --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_ppc_rhapsody.cpp @@ -0,0 +1,254 @@ +/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Implement shared vtbl methods. */ + +#include "xptcprivate.h" + +/* + For mac, the first 8 integral and the first 13 f.p. parameters arrive + in a separate chunk of data that has been loaded from the registers. The + args pointer has been set to the start of the parameters BEYOND the ones + arriving in registers +*/ +extern "C" nsresult +PrepareAndDispatch(nsXPTCStubBase* self, PRUint32 methodIndex, PRUint32* args, PRUint32 *gprData, double *fprData) +{ +#define PARAM_BUFFER_COUNT 16 +#define PARAM_GPR_COUNT 7 + + // fprintf(stderr, "PrepareAndDispatch %p, %d, %p, %p, %p\n", self, methodIndex, args, gprData, fprData); + + nsXPTCMiniVariant paramBuffer[PARAM_BUFFER_COUNT]; + nsXPTCMiniVariant* dispatchParams = NULL; + nsIInterfaceInfo* iface_info = NULL; + const nsXPTMethodInfo* info; + PRUint8 paramCount; + PRUint8 i; + nsresult result = NS_ERROR_FAILURE; + + NS_ASSERTION(self,"no self"); + + self->GetInterfaceInfo(&iface_info); + NS_ASSERTION(iface_info,"no interface info"); + + iface_info->GetMethodInfo(PRUint16(methodIndex), &info); + NS_ASSERTION(info,"no interface info"); + + paramCount = info->GetParamCount(); + + // setup variant array pointer + if(paramCount > PARAM_BUFFER_COUNT) + dispatchParams = new nsXPTCMiniVariant[paramCount]; + else + dispatchParams = paramBuffer; + NS_ASSERTION(dispatchParams,"no place for params"); + + PRUint32* ap = args; + PRUint32 iCount = 0; + PRUint32 fpCount = 0; + for(i = 0; i < paramCount; i++) + { + const nsXPTParamInfo& param = info->GetParam(i); + const nsXPTType& type = param.GetType(); + nsXPTCMiniVariant* dp = &dispatchParams[i]; + + if(param.IsOut() || !type.IsArithmetic()) + { + if (iCount < PARAM_GPR_COUNT) + dp->val.p = (void*) gprData[iCount++]; + else + dp->val.p = (void*) *ap++; + continue; + } + // else + switch(type) + { + case nsXPTType::T_I8 : if (iCount < PARAM_GPR_COUNT) + dp->val.i8 = (PRInt8) gprData[iCount++]; + else + dp->val.i8 = (PRInt8) *ap++; + break; + case nsXPTType::T_I16 : if (iCount < PARAM_GPR_COUNT) + dp->val.i16 = (PRInt16) gprData[iCount++]; + else + dp->val.i16 = (PRInt16) *ap++; + break; + case nsXPTType::T_I32 : if (iCount < PARAM_GPR_COUNT) + dp->val.i32 = (PRInt32) gprData[iCount++]; + else + dp->val.i32 = (PRInt32) *ap++; + break; + + case nsXPTType::T_I64 : + { + PRUint64 tempu64; + if (iCount & 1) iCount++; // longlongs are aligned in odd/even register pairs, eg. r5/r6 + if ((iCount + 1) < PARAM_GPR_COUNT) { + tempu64 = *(PRUint64*) &gprData[iCount]; + iCount += 2; + } + else { + if ((PRUint32) ap & 4) ap++; // longlongs are 8-byte aligned on stack + tempu64 = *(PRUint64*) ap; + ap += 2; + } + dp->val.i64 = (PRUint64)tempu64; + } + break; + +#if 0 + case nsXPTType::T_I64 : if (iCount < PARAM_GPR_COUNT) + dp->val.i64.hi = (PRInt32) gprData[iCount++]; + else + dp->val.i64.hi = (PRInt32) *ap++; + if (iCount < PARAM_GPR_COUNT) + dp->val.i64.lo = (PRUint32) gprData[iCount++]; + else + dp->val.i64.lo = (PRUint32) *ap++; + break; +#endif + case nsXPTType::T_U8 : if (iCount < PARAM_GPR_COUNT) + dp->val.i8 = (PRUint8) gprData[iCount++]; + else + dp->val.i8 = (PRUint8) *ap++; + break; + case nsXPTType::T_U16 : if (iCount < PARAM_GPR_COUNT) + dp->val.i16 = (PRUint16) gprData[iCount++]; + else + dp->val.i16 = (PRUint16) *ap++; + break; + case nsXPTType::T_U32 : if (iCount < PARAM_GPR_COUNT) + dp->val.i32 = (PRUint32) gprData[iCount++]; + else + dp->val.i32 = (PRUint32) *ap++; + break; + + case nsXPTType::T_U64 : +#if 0 + if (iCount < PARAM_GPR_COUNT) + dp->val.i64.hi = (PRUint32) gprData[iCount++]; + else + dp->val.i64.hi = (PRUint32) *ap++; + if (iCount < PARAM_GPR_COUNT) + dp->val.i64.lo = (PRUint32) gprData[iCount++]; + else + dp->val.i64.lo = (PRUint32) *ap++; +#endif + { + PRUint64 tempu64; + if (iCount & 1) iCount++; // longlongs are aligned in odd/even register pairs, eg. r5/r6 + if ((iCount + 1) < PARAM_GPR_COUNT) { + tempu64 = *(PRUint64*) &gprData[iCount]; + iCount += 2; + } + else { + if ((PRUint32) ap & 4) ap++; // longlongs are 8-byte aligned on stack + tempu64 = *(PRUint64*) ap; + ap += 2; + } + dp->val.i64 = (PRUint64)tempu64; + } + break; + case nsXPTType::T_FLOAT : if (fpCount < 13) { + dp->val.f = (float) fprData[fpCount++]; + if (iCount < PARAM_GPR_COUNT) + ++iCount; + else + ++ap; + } + else + dp->val.f = *((float*) ap++); + break; + case nsXPTType::T_DOUBLE : if (fpCount < 13) { + dp->val.d = (double) fprData[fpCount++]; + if (iCount < PARAM_GPR_COUNT) + ++iCount; + else + ++ap; + if (iCount < PARAM_GPR_COUNT) + ++iCount; + else + ++ap; + } + else { + dp->val.f = *((double*) ap); + ap += 2; + } + break; + case nsXPTType::T_BOOL : if (iCount < PARAM_GPR_COUNT) + dp->val.b = (PRBool) gprData[iCount++]; + else + dp->val.b = (PRBool) *ap++; + break; + case nsXPTType::T_CHAR : if (iCount < PARAM_GPR_COUNT) + dp->val.c = (char) gprData[iCount++]; + else + dp->val.c = (char) *ap++; + break; + case nsXPTType::T_WCHAR : if (iCount < PARAM_GPR_COUNT) + dp->val.wc = (wchar_t) gprData[iCount++]; + else + dp->val.wc = (wchar_t) *ap++; + break; + default: + NS_ASSERTION(0, "bad type"); + break; + } + } + + result = self->CallMethod((PRUint16)methodIndex, info, dispatchParams); + + NS_RELEASE(iface_info); + + if(dispatchParams != paramBuffer) + delete [] dispatchParams; + + return result; +} + + +#define STUB_ENTRY(n) +#define SENTINEL_ENTRY(n) \ +nsresult nsXPTCStubBase::Sentinel##n() \ +{ \ + NS_ASSERTION(0,"nsXPTCStubBase::Sentinel called"); \ + return NS_ERROR_NOT_IMPLEMENTED; \ +} + + +#include "xptcstubsdef.inc" diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_sparc_netbsd.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_sparc_netbsd.cpp new file mode 100644 index 00000000..cbed6041 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_sparc_netbsd.cpp @@ -0,0 +1,146 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Implement shared vtbl methods. */ + +#include "xptcprivate.h" + +#if defined(sparc) || defined(__sparc__) + +extern "C" nsresult +PrepareAndDispatch(nsXPTCStubBase* self, uint32 methodIndex, uint32* args) +{ + + typedef struct { + uint32 hi; + uint32 lo; + } DU; // have to move 64 bit entities as 32 bit halves since + // stack slots are not guaranteed 16 byte aligned + +#define PARAM_BUFFER_COUNT 16 + + nsXPTCMiniVariant paramBuffer[PARAM_BUFFER_COUNT]; + nsXPTCMiniVariant* dispatchParams = NULL; + nsIInterfaceInfo* iface_info = NULL; + const nsXPTMethodInfo* info; + PRUint8 paramCount; + PRUint8 i; + nsresult result = NS_ERROR_FAILURE; + + NS_ASSERTION(self,"no self"); + + self->GetInterfaceInfo(&iface_info); + NS_ASSERTION(iface_info,"no interface info"); + + iface_info->GetMethodInfo(PRUint16(methodIndex), &info); + NS_ASSERTION(info,"no interface info"); + + paramCount = info->GetParamCount(); + + // setup variant array pointer + if(paramCount > PARAM_BUFFER_COUNT) + dispatchParams = new nsXPTCMiniVariant[paramCount]; + else + dispatchParams = paramBuffer; + NS_ASSERTION(dispatchParams,"no place for params"); + + PRUint32* ap = args; + for(i = 0; i < paramCount; i++, ap++) + { + const nsXPTParamInfo& param = info->GetParam(i); + const nsXPTType& type = param.GetType(); + nsXPTCMiniVariant* dp = &dispatchParams[i]; + + if(param.IsOut() || !type.IsArithmetic()) + { + dp->val.p = (void*) *ap; + continue; + } + // else + switch(type) + { + case nsXPTType::T_I8 : dp->val.i8 = *((PRInt32*) ap); break; + case nsXPTType::T_I16 : dp->val.i16 = *((PRInt32*) ap); break; + case nsXPTType::T_I32 : dp->val.i32 = *((PRInt32*) ap); break; + case nsXPTType::T_DOUBLE : + case nsXPTType::T_U64 : + case nsXPTType::T_I64 : ((DU *)dp)->hi = ((DU *)ap)->hi; + ((DU *)dp)->lo = ((DU *)ap)->lo; + ap++; + break; + case nsXPTType::T_U8 : dp->val.u8 = *((PRUint32*) ap); break; + case nsXPTType::T_U16 : dp->val.u16 = *((PRUint32*)ap); break; + case nsXPTType::T_U32 : dp->val.u32 = *((PRUint32*)ap); break; + case nsXPTType::T_FLOAT : dp->val.f = *((float*) ap); break; + case nsXPTType::T_BOOL : dp->val.b = *((PRBool*) ap); break; + case nsXPTType::T_CHAR : dp->val.c = *((PRUint32*) ap); break; + case nsXPTType::T_WCHAR : dp->val.wc = *((PRInt32*) ap); break; + default: + NS_ASSERTION(0, "bad type"); + break; + } + } + + result = self->CallMethod((PRUint16)methodIndex, info, dispatchParams); + + NS_RELEASE(iface_info); + + if(dispatchParams != paramBuffer) + delete [] dispatchParams; + + return result; +} + +extern "C" int SharedStub(int, int*); + +#define STUB_ENTRY(n) \ +nsresult nsXPTCStubBase::Stub##n() \ +{ \ + int dummy; /* defeat tail-call optimization */ \ + return SharedStub(n, &dummy); \ +} + +#define SENTINEL_ENTRY(n) \ +nsresult nsXPTCStubBase::Sentinel##n() \ +{ \ + NS_ASSERTION(0,"nsXPTCStubBase::Sentinel called"); \ + return NS_ERROR_NOT_IMPLEMENTED; \ +} + +#include "xptcstubsdef.inc" + +#endif /* sparc || __sparc__ */ diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_sparc_solaris.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_sparc_solaris.cpp new file mode 100644 index 00000000..cbed6041 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_sparc_solaris.cpp @@ -0,0 +1,146 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Implement shared vtbl methods. */ + +#include "xptcprivate.h" + +#if defined(sparc) || defined(__sparc__) + +extern "C" nsresult +PrepareAndDispatch(nsXPTCStubBase* self, uint32 methodIndex, uint32* args) +{ + + typedef struct { + uint32 hi; + uint32 lo; + } DU; // have to move 64 bit entities as 32 bit halves since + // stack slots are not guaranteed 16 byte aligned + +#define PARAM_BUFFER_COUNT 16 + + nsXPTCMiniVariant paramBuffer[PARAM_BUFFER_COUNT]; + nsXPTCMiniVariant* dispatchParams = NULL; + nsIInterfaceInfo* iface_info = NULL; + const nsXPTMethodInfo* info; + PRUint8 paramCount; + PRUint8 i; + nsresult result = NS_ERROR_FAILURE; + + NS_ASSERTION(self,"no self"); + + self->GetInterfaceInfo(&iface_info); + NS_ASSERTION(iface_info,"no interface info"); + + iface_info->GetMethodInfo(PRUint16(methodIndex), &info); + NS_ASSERTION(info,"no interface info"); + + paramCount = info->GetParamCount(); + + // setup variant array pointer + if(paramCount > PARAM_BUFFER_COUNT) + dispatchParams = new nsXPTCMiniVariant[paramCount]; + else + dispatchParams = paramBuffer; + NS_ASSERTION(dispatchParams,"no place for params"); + + PRUint32* ap = args; + for(i = 0; i < paramCount; i++, ap++) + { + const nsXPTParamInfo& param = info->GetParam(i); + const nsXPTType& type = param.GetType(); + nsXPTCMiniVariant* dp = &dispatchParams[i]; + + if(param.IsOut() || !type.IsArithmetic()) + { + dp->val.p = (void*) *ap; + continue; + } + // else + switch(type) + { + case nsXPTType::T_I8 : dp->val.i8 = *((PRInt32*) ap); break; + case nsXPTType::T_I16 : dp->val.i16 = *((PRInt32*) ap); break; + case nsXPTType::T_I32 : dp->val.i32 = *((PRInt32*) ap); break; + case nsXPTType::T_DOUBLE : + case nsXPTType::T_U64 : + case nsXPTType::T_I64 : ((DU *)dp)->hi = ((DU *)ap)->hi; + ((DU *)dp)->lo = ((DU *)ap)->lo; + ap++; + break; + case nsXPTType::T_U8 : dp->val.u8 = *((PRUint32*) ap); break; + case nsXPTType::T_U16 : dp->val.u16 = *((PRUint32*)ap); break; + case nsXPTType::T_U32 : dp->val.u32 = *((PRUint32*)ap); break; + case nsXPTType::T_FLOAT : dp->val.f = *((float*) ap); break; + case nsXPTType::T_BOOL : dp->val.b = *((PRBool*) ap); break; + case nsXPTType::T_CHAR : dp->val.c = *((PRUint32*) ap); break; + case nsXPTType::T_WCHAR : dp->val.wc = *((PRInt32*) ap); break; + default: + NS_ASSERTION(0, "bad type"); + break; + } + } + + result = self->CallMethod((PRUint16)methodIndex, info, dispatchParams); + + NS_RELEASE(iface_info); + + if(dispatchParams != paramBuffer) + delete [] dispatchParams; + + return result; +} + +extern "C" int SharedStub(int, int*); + +#define STUB_ENTRY(n) \ +nsresult nsXPTCStubBase::Stub##n() \ +{ \ + int dummy; /* defeat tail-call optimization */ \ + return SharedStub(n, &dummy); \ +} + +#define SENTINEL_ENTRY(n) \ +nsresult nsXPTCStubBase::Sentinel##n() \ +{ \ + NS_ASSERTION(0,"nsXPTCStubBase::Sentinel called"); \ + return NS_ERROR_NOT_IMPLEMENTED; \ +} + +#include "xptcstubsdef.inc" + +#endif /* sparc || __sparc__ */ diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_sparcv9_solaris.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_sparcv9_solaris.cpp new file mode 100644 index 00000000..f64b309e --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_sparcv9_solaris.cpp @@ -0,0 +1,139 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Stuart Parmenter + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Implement shared vtbl methods. */ + +#include "xptcprivate.h" + +#if defined(sparc) || defined(__sparc__) + +extern "C" nsresult +PrepareAndDispatch(nsXPTCStubBase* self, PRUint64 methodIndex, PRUint64* args) +{ + +#define PARAM_BUFFER_COUNT 16 + + nsXPTCMiniVariant paramBuffer[PARAM_BUFFER_COUNT]; + nsXPTCMiniVariant* dispatchParams = NULL; + nsIInterfaceInfo* iface_info = NULL; + const nsXPTMethodInfo* info; + PRUint8 paramCount; + PRUint8 i; + nsresult result = NS_ERROR_FAILURE; + + NS_ASSERTION(self,"no self"); + + self->GetInterfaceInfo(&iface_info); + NS_ASSERTION(iface_info,"no interface info"); + + iface_info->GetMethodInfo(PRUint16(methodIndex), &info); + NS_ASSERTION(info,"no interface info"); + + paramCount = info->GetParamCount(); + + // setup variant array pointer + if(paramCount > PARAM_BUFFER_COUNT) + dispatchParams = new nsXPTCMiniVariant[paramCount]; + else + dispatchParams = paramBuffer; + NS_ASSERTION(dispatchParams,"no place for params"); + + PRUint64* ap = args; + for(i = 0; i < paramCount; i++, ap++) + { + const nsXPTParamInfo& param = info->GetParam(i); + const nsXPTType& type = param.GetType(); + nsXPTCMiniVariant* dp = &dispatchParams[i]; + + if(param.IsOut() || !type.IsArithmetic()) + { + dp->val.p = (void*) *ap; + continue; + } + // else + switch(type) + { + case nsXPTType::T_I8 : dp->val.i8 = *((PRInt32*) ap); break; + case nsXPTType::T_I16 : dp->val.i16 = *((PRInt32*) ap); break; + case nsXPTType::T_I32 : dp->val.i32 = *((PRInt32*) ap); break; + case nsXPTType::T_DOUBLE : dp->val.d = *((double*) ap); break; + case nsXPTType::T_U64 : dp->val.u64 = *((PRUint64*) ap); break; + case nsXPTType::T_I64 : dp->val.i64 = *((PRInt64*) ap); break; + case nsXPTType::T_U8 : dp->val.u8 = *((PRUint32*) ap); break; + case nsXPTType::T_U16 : dp->val.u16 = *((PRUint32*)ap); break; + case nsXPTType::T_U32 : dp->val.u32 = *((PRUint32*)ap); break; + case nsXPTType::T_FLOAT : dp->val.f = *((float*) ap); break; + case nsXPTType::T_BOOL : dp->val.b = *((PRBool*) ap); break; + case nsXPTType::T_CHAR : dp->val.c = *((PRUint32*) ap); break; + case nsXPTType::T_WCHAR : dp->val.wc = *((PRInt32*) ap); break; + default: + NS_ASSERTION(0, "bad type"); + break; + } + } + + result = self->CallMethod((PRUint16)methodIndex, info, dispatchParams); + + NS_RELEASE(iface_info); + + if(dispatchParams != paramBuffer) + delete [] dispatchParams; + + return result; +} + +extern "C" int SharedStub(int, int*); + +#define STUB_ENTRY(n) \ +nsresult nsXPTCStubBase::Stub##n() \ +{ \ + int dummy; /* defeat tail-call optimization */ \ + return SharedStub(n, &dummy); \ +} + +#define SENTINEL_ENTRY(n) \ +nsresult nsXPTCStubBase::Sentinel##n() \ +{ \ + NS_ASSERTION(0,"nsXPTCStubBase::Sentinel called"); \ + return NS_ERROR_NOT_IMPLEMENTED; \ +} + +#include "xptcstubsdef.inc" + +#endif /* sparc || __sparc__ */ diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_unixish_x86.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_unixish_x86.cpp new file mode 100644 index 00000000..91c5c5db --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_unixish_x86.cpp @@ -0,0 +1,188 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Implement shared vtbl methods. */ + +#include "xptcprivate.h" +#include "xptc_platforms_unixish_x86.h" +/*#include "xptiprivate.h"*/ + +static nsresult +PrepareAndDispatch(nsXPTCStubBase* self, uint32 methodIndex, PRUint32* args) +{ +#define PARAM_BUFFER_COUNT 16 + + nsXPTCMiniVariant paramBuffer[PARAM_BUFFER_COUNT]; + nsXPTCMiniVariant* dispatchParams = NULL; + nsIInterfaceInfo* iface_info = NULL; + const nsXPTMethodInfo* info = NULL; + PRUint8 paramCount; + PRUint8 i; + nsresult result = NS_ERROR_FAILURE; + + NS_ASSERTION(self,"no self"); + + self->GetInterfaceInfo(&iface_info); + NS_ASSERTION(iface_info,"no interface info"); + if (!iface_info) + return NS_ERROR_UNEXPECTED; + + iface_info->GetMethodInfo(PRUint16(methodIndex), &info); + NS_ASSERTION(info,"no method info"); + if (!info) + return NS_ERROR_UNEXPECTED; + + paramCount = info->GetParamCount(); + + // setup variant array pointer + if(paramCount > PARAM_BUFFER_COUNT) + dispatchParams = new nsXPTCMiniVariant[paramCount]; + else + dispatchParams = paramBuffer; + NS_ASSERTION(dispatchParams,"no place for params"); + if (!dispatchParams) + return NS_ERROR_OUT_OF_MEMORY; + + PRUint32* ap = args; + for(i = 0; i < paramCount; i++, ap++) + { + const nsXPTParamInfo& param = info->GetParam(i); + const nsXPTType& type = param.GetType(); + nsXPTCMiniVariant* dp = &dispatchParams[i]; + + if(param.IsOut() || !type.IsArithmetic()) + { + dp->val.p = (void*) *ap; + continue; + } + // else + dp->val.p = (void*) *ap; + switch(type) + { + case nsXPTType::T_I64 : dp->val.i64 = *((PRInt64*) ap); ap++; break; + case nsXPTType::T_U64 : dp->val.u64 = *((PRUint64*)ap); ap++; break; + case nsXPTType::T_DOUBLE : dp->val.d = *((double*) ap); ap++; break; + } + } + + result = self->CallMethod((PRUint16)methodIndex, info, dispatchParams); + + NS_RELEASE(iface_info); + + if(dispatchParams != paramBuffer) + delete [] dispatchParams; + + return result; +} + +#ifdef __GNUC__ /* Gnu Compiler. */ + +#ifdef KEEP_STACK_16_BYTE_ALIGNED +/* Make sure the stack is 16-byte aligned. Do that by aligning to 16 bytes and + * then subtracting 4 so the three subsequent pushes result in a 16-byte aligned + * stack. */ +#define ALIGN_STACK_DECL \ + unsigned int saved_esp = 0; /* VBOX: Initialize it to shut up half a million gcc warnings on darwin. + * ALIGN_STACK_REGS_OUT/IN are a bit bogus, so the warning is probably correct. */ + +#define ALIGN_STACK_SAVE \ + "movl %%esp, %3\n\t" + +#define ALIGN_STACK_ALIGN \ + "addl $0x4, %%esp\n\t" \ + "andl $0xfffffff0, %%esp\n\t" \ + "subl $0x4, %%esp\n\t" + +#define STACK_RESTORE \ + "movl %3, %%esp\n" + +#define ALIGN_STACK_REGS_IN \ + , "=r"(saved_esp) /* 3 */ + +#define ALIGN_STACK_REGS_OUT \ + , "3"(saved_esp) + +#else +#define ALIGN_STACK_DECL +#define ALIGN_STACK_SAVE +#define ALIGN_STACK_ALIGN +#define STACK_RESTORE \ + "addl $12, %%esp\n" +#define ALIGN_STACK_REGS_IN +#define ALIGN_STACK_REGS_OUT +#endif + +#define STUB_ENTRY(n) \ +nsresult nsXPTCStubBase::Stub##n() \ +{ \ + register nsresult (*method) (nsXPTCStubBase *, uint32, PRUint32 *) = PrepareAndDispatch; \ + int temp0, temp1; \ + register nsresult result; \ + ALIGN_STACK_DECL \ + __asm__ __volatile__( \ + ALIGN_STACK_SAVE \ + ALIGN_STACK_ALIGN \ + "leal 0x0c(%%ebp), %%ecx\n\t" /* args */ \ + "pushl %%ecx\n\t" \ + "pushl $"#n"\n\t" /* method index */ \ + "movl 0x08(%%ebp), %%ecx\n\t" /* this */ \ + "pushl %%ecx\n\t" \ + "call *%%edx\n\t" /* PrepareAndDispatch */ \ + STACK_RESTORE /* "addl $12, %%esp" or restore saved */ \ + : "=a" (result), /* %0 */ \ + "=&c" (temp0), /* %1 */ \ + "=d" (temp1) /* %2 */ \ + ALIGN_STACK_REGS_IN \ + : "2" (method) /* %2 */ \ + ALIGN_STACK_REGS_OUT \ + : "memory" \ + ); \ + return result; \ +} + +#else +#error "can't find a compiler to use" +#endif /* __GNUC__ */ + +#define SENTINEL_ENTRY(n) \ +nsresult nsXPTCStubBase::Sentinel##n() \ +{ \ + NS_ASSERTION(0,"nsXPTCStubBase::Sentinel called"); \ + return NS_ERROR_NOT_IMPLEMENTED; \ +} + +#include "xptcstubsdef.inc" diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_unsupported.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_unsupported.cpp new file mode 100644 index 00000000..0eea6567 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_unsupported.cpp @@ -0,0 +1,56 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Implement shared vtbl methods. */ + +#include "xptcprivate.h" + +#define STUB_ENTRY(n) \ +nsresult nsXPTCStubBase::Stub##n() \ +{ \ + NS_ASSERTION(0,"nsXPTCStubBase::Stub called on unsupported platform"); \ + return NS_ERROR_NOT_IMPLEMENTED; \ +} + +#define SENTINEL_ENTRY(n) \ +nsresult nsXPTCStubBase::Sentinel##n() \ +{ \ + NS_ASSERTION(0,"nsXPTCStubBase::Sentinel called"); \ + return NS_ERROR_NOT_IMPLEMENTED; \ +} + +#include "xptcstubsdef.inc" diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_x86_64_linux.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_x86_64_linux.cpp new file mode 100644 index 00000000..3381c48e --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_x86_64_linux.cpp @@ -0,0 +1,242 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** 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.org Code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +// Implement shared vtbl methods. + +#include "xptcprivate.h" + +// The Linux/x86-64 ABI passes the first 6 integer parameters and the +// first 8 floating point parameters in registers (rdi, rsi, rdx, rcx, +// r8, r9 and xmm0-xmm7), no stack space is allocated for these by the +// caller. The rest of the parameters are passed in the callers stack +// area. + +const PRUint32 PARAM_BUFFER_COUNT = 16; +const PRUint32 GPR_COUNT = 6; +const PRUint32 FPR_COUNT = 8; + +// PrepareAndDispatch() is called by SharedStub() and calls the actual method. +// +// - 'args[]' contains the arguments passed on stack +// - 'gpregs[]' contains the arguments passed in integer registers +// - 'fpregs[]' contains the arguments passed in floating point registers +// +// The parameters are mapped into an array of type 'nsXPTCMiniVariant' +// and then the method gets called. + +extern "C" nsresult +PrepareAndDispatch(nsXPTCStubBase * self, PRUint32 methodIndex, + PRUint64 * args, PRUint64 * gpregs, double *fpregs) +{ + nsXPTCMiniVariant paramBuffer[PARAM_BUFFER_COUNT]; + nsXPTCMiniVariant* dispatchParams = NULL; + nsIInterfaceInfo* iface_info = NULL; + const nsXPTMethodInfo* info = NULL; + PRUint32 paramCount; + PRUint32 i; + nsresult result = NS_ERROR_FAILURE; + + NS_ASSERTION(self,"no self"); + + self->GetInterfaceInfo(&iface_info); + NS_ASSERTION(iface_info,"no interface info"); + if (!iface_info) + return NS_ERROR_UNEXPECTED; + + iface_info->GetMethodInfo(PRUint16(methodIndex), &info); + NS_ASSERTION(info,"no method info"); + if (!info) + return NS_ERROR_UNEXPECTED; + + paramCount = info->GetParamCount(); + + // setup variant array pointer + if (paramCount > PARAM_BUFFER_COUNT) + dispatchParams = new nsXPTCMiniVariant[paramCount]; + else + dispatchParams = paramBuffer; + + NS_ASSERTION(dispatchParams,"no place for params"); + if (!dispatchParams) + return NS_ERROR_OUT_OF_MEMORY; + + PRUint64* ap = args; + PRUint32 nr_gpr = 1; // skip one GPR register for 'that' + PRUint32 nr_fpr = 0; + PRUint64 value; + + for (i = 0; i < paramCount; i++) { + const nsXPTParamInfo& param = info->GetParam(i); + const nsXPTType& type = param.GetType(); + nsXPTCMiniVariant* dp = &dispatchParams[i]; + + if (!param.IsOut() && type == nsXPTType::T_DOUBLE) { + if (nr_fpr < FPR_COUNT) + dp->val.d = fpregs[nr_fpr++]; + else + dp->val.d = *(double*) ap++; + continue; + } + else if (!param.IsOut() && type == nsXPTType::T_FLOAT) { + if (nr_fpr < FPR_COUNT) + // The value in %xmm register is already prepared to + // be retrieved as a float. Therefore, we pass the + // value verbatim, as a double without conversion. + dp->val.d = *(double*) ap++; + else + dp->val.f = *(float*) ap++; + continue; + } + else { + if (nr_gpr < GPR_COUNT) + value = gpregs[nr_gpr++]; + else + value = *ap++; + } + + if (param.IsOut() || !type.IsArithmetic()) { + dp->val.p = (void*) value; + continue; + } + + switch (type) { + case nsXPTType::T_I8: dp->val.i8 = (PRInt8) value; break; + case nsXPTType::T_I16: dp->val.i16 = (PRInt16) value; break; + case nsXPTType::T_I32: dp->val.i32 = (PRInt32) value; break; + case nsXPTType::T_I64: dp->val.i64 = (PRInt64) value; break; + case nsXPTType::T_U8: dp->val.u8 = (PRUint8) value; break; + case nsXPTType::T_U16: dp->val.u16 = (PRUint16) value; break; + case nsXPTType::T_U32: dp->val.u32 = (PRUint32) value; break; + case nsXPTType::T_U64: dp->val.u64 = (PRUint64) value; break; + case nsXPTType::T_BOOL: dp->val.b = (PRBool) value; break; + case nsXPTType::T_CHAR: dp->val.c = (char) value; break; + case nsXPTType::T_WCHAR: dp->val.wc = (wchar_t) value; break; + + default: + NS_ASSERTION(0, "bad type"); + break; + } + } + + result = self->CallMethod((PRUint16) methodIndex, info, dispatchParams); + + NS_RELEASE(iface_info); + + if (dispatchParams != paramBuffer) + delete [] dispatchParams; + + return result; +} + +#if defined(__GXX_ABI_VERSION) && __GXX_ABI_VERSION >= 100 /* G++ V3 ABI */ +// Linux/x86-64 uses gcc >= 3.1 +#define STUB_ENTRY(n) \ +asm(".section \".text\"\n\t" \ + ".align 2\n\t" \ + ".if " #n " < 10\n\t" \ + ".globl _ZN14nsXPTCStubBase5Stub" #n "Ev\n\t" \ + ".type _ZN14nsXPTCStubBase5Stub" #n "Ev,@function\n" \ + "_ZN14nsXPTCStubBase5Stub" #n "Ev:\n\t" \ + ".elseif " #n " < 100\n\t" \ + ".globl _ZN14nsXPTCStubBase6Stub" #n "Ev\n\t" \ + ".type _ZN14nsXPTCStubBase6Stub" #n "Ev,@function\n" \ + "_ZN14nsXPTCStubBase6Stub" #n "Ev:\n\t" \ + ".elseif " #n " < 1000\n\t" \ + ".globl _ZN14nsXPTCStubBase7Stub" #n "Ev\n\t" \ + ".type _ZN14nsXPTCStubBase7Stub" #n "Ev,@function\n" \ + "_ZN14nsXPTCStubBase7Stub" #n "Ev:\n\t" \ + ".else\n\t" \ + ".err \"stub number " #n " >= 1000 not yet supported\"\n\t" \ + ".endif\n\t" \ + "movl $" #n ", %eax\n\t" \ + "jmp SharedStub\n\t" \ + ".if " #n " < 10\n\t" \ + ".size _ZN14nsXPTCStubBase5Stub" #n "Ev,.-_ZN14nsXPTCStubBase5Stub" #n "Ev\n\t" \ + ".elseif " #n " < 100\n\t" \ + ".size _ZN14nsXPTCStubBase6Stub" #n "Ev,.-_ZN14nsXPTCStubBase6Stub" #n "Ev\n\t" \ + ".else\n\t" \ + ".size _ZN14nsXPTCStubBase7Stub" #n "Ev,.-_ZN14nsXPTCStubBase7Stub" #n "Ev\n\t" \ + ".endif"); + +// static nsresult SharedStub(PRUint32 methodIndex) +asm(".section \".text\"\n\t" + ".align 2\n\t" + ".type SharedStub,@function\n\t" + "SharedStub:\n\t" + // make room for gpregs (48), fpregs (64) + "pushq %rbp\n\t" + "movq %rsp,%rbp\n\t" + "subq $112,%rsp\n\t" + // save GP registers + "movq %rdi,-112(%rbp)\n\t" + "movq %rsi,-104(%rbp)\n\t" + "movq %rdx, -96(%rbp)\n\t" + "movq %rcx, -88(%rbp)\n\t" + "movq %r8 , -80(%rbp)\n\t" + "movq %r9 , -72(%rbp)\n\t" + "leaq -112(%rbp),%rcx\n\t" + // save FP registers + "movsd %xmm0,-64(%rbp)\n\t" + "movsd %xmm1,-56(%rbp)\n\t" + "movsd %xmm2,-48(%rbp)\n\t" + "movsd %xmm3,-40(%rbp)\n\t" + "movsd %xmm4,-32(%rbp)\n\t" + "movsd %xmm5,-24(%rbp)\n\t" + "movsd %xmm6,-16(%rbp)\n\t" + "movsd %xmm7, -8(%rbp)\n\t" + "leaq -64(%rbp),%r8\n\t" + // rdi has the 'self' pointer already + "movl %eax,%esi\n\t" + "leaq 16(%rbp),%rdx\n\t" + "call PrepareAndDispatch@plt\n\t" + "leave\n\t" + "ret\n\t" + ".size SharedStub,.-SharedStub"); + +#define SENTINEL_ENTRY(n) \ +nsresult nsXPTCStubBase::Sentinel##n() \ +{ \ + NS_ASSERTION(0,"nsXPTCStubBase::Sentinel called"); \ + return NS_ERROR_NOT_IMPLEMENTED; \ +} + +#include "xptcstubsdef.inc" + +#else +#error "Unsupported compiler. Use gcc >= 3.1 for Linux/x86-64." +#endif /* __GNUC__ */ diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_x86_64_solaris.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_x86_64_solaris.cpp new file mode 100644 index 00000000..59e0202f --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_x86_64_solaris.cpp @@ -0,0 +1,271 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** 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.org Code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +// Implement shared vtbl methods. + +#include "xptcprivate.h" + +// The Linux/x86-64 ABI passes the first 6 integer parameters and the +// first 8 floating point parameters in registers (rdi, rsi, rdx, rcx, +// r8, r9 and xmm0-xmm7), no stack space is allocated for these by the +// caller. The rest of the parameters are passed in the callers stack +// area. +// Solaris does the same, just the assembler may differ. + +const PRUint32 PARAM_BUFFER_COUNT = 16; +const PRUint32 GPR_COUNT = 6; +const PRUint32 FPR_COUNT = 8; + +// PrepareAndDispatch() is called by SharedStub() and calls the actual method. +// +// - 'args[]' contains the arguments passed on stack +// - 'gpregs[]' contains the arguments passed in integer registers +// - 'fpregs[]' contains the arguments passed in floating point registers +// +// The parameters are mapped into an array of type 'nsXPTCMiniVariant' +// and then the method gets called. + +extern "C" nsresult +PrepareAndDispatch(nsXPTCStubBase * self, PRUint32 methodIndex, + PRUint64 * args, PRUint64 * gpregs, double *fpregs) +{ + nsXPTCMiniVariant paramBuffer[PARAM_BUFFER_COUNT]; + nsXPTCMiniVariant* dispatchParams = NULL; + nsIInterfaceInfo* iface_info = NULL; + const nsXPTMethodInfo* info; + PRUint32 paramCount; + PRUint32 i; + nsresult result = NS_ERROR_FAILURE; + + NS_ASSERTION(self,"no self"); + + self->GetInterfaceInfo(&iface_info); + NS_ASSERTION(iface_info,"no interface info"); + if (!iface_info) + return NS_ERROR_UNEXPECTED; + + iface_info->GetMethodInfo(PRUint16(methodIndex), &info); + NS_ASSERTION(info,"no method info"); + if (!info) + return NS_ERROR_UNEXPECTED; + + paramCount = info->GetParamCount(); + + // setup variant array pointer + if (paramCount > PARAM_BUFFER_COUNT) + dispatchParams = new nsXPTCMiniVariant[paramCount]; + else + dispatchParams = paramBuffer; + + NS_ASSERTION(dispatchParams,"no place for params"); + if (!dispatchParams) + return NS_ERROR_OUT_OF_MEMORY; + + PRUint64* ap = args; + PRUint32 nr_gpr = 1; // skip one GPR register for 'that' + PRUint32 nr_fpr = 0; + PRUint64 value; + + for (i = 0; i < paramCount; i++) { + const nsXPTParamInfo& param = info->GetParam(i); + const nsXPTType& type = param.GetType(); + nsXPTCMiniVariant* dp = &dispatchParams[i]; + + if (!param.IsOut() && type == nsXPTType::T_DOUBLE) { + if (nr_fpr < FPR_COUNT) + dp->val.d = fpregs[nr_fpr++]; + else + dp->val.d = *(double*) ap++; + continue; + } + else if (!param.IsOut() && type == nsXPTType::T_FLOAT) { + if (nr_fpr < FPR_COUNT) + // The value in %xmm register is already prepared to + // be retrieved as a float. Therefore, we pass the + // value verbatim, as a double without conversion. + dp->val.d = *(double*) ap++; + else + dp->val.f = *(float*) ap++; + continue; + } + else { + if (nr_gpr < GPR_COUNT) + value = gpregs[nr_gpr++]; + else + value = *ap++; + } + + if (param.IsOut() || !type.IsArithmetic()) { + dp->val.p = (void*) value; + continue; + } + + switch (type) { + case nsXPTType::T_I8: dp->val.i8 = (PRInt8) value; break; + case nsXPTType::T_I16: dp->val.i16 = (PRInt16) value; break; + case nsXPTType::T_I32: dp->val.i32 = (PRInt32) value; break; + case nsXPTType::T_I64: dp->val.i64 = (PRInt64) value; break; + case nsXPTType::T_U8: dp->val.u8 = (PRUint8) value; break; + case nsXPTType::T_U16: dp->val.u16 = (PRUint16) value; break; + case nsXPTType::T_U32: dp->val.u32 = (PRUint32) value; break; + case nsXPTType::T_U64: dp->val.u64 = (PRUint64) value; break; + case nsXPTType::T_BOOL: dp->val.b = (PRBool) value; break; + case nsXPTType::T_CHAR: dp->val.c = (char) value; break; + case nsXPTType::T_WCHAR: dp->val.wc = (wchar_t) value; break; + + default: + NS_ASSERTION(0, "bad type"); + break; + } + } + + result = self->CallMethod((PRUint16) methodIndex, info, dispatchParams); + + NS_RELEASE(iface_info); + + if (dispatchParams != paramBuffer) + delete [] dispatchParams; + + return result; +} + +#include + +#if defined(__GXX_ABI_VERSION) && __GXX_ABI_VERSION >= 100 /* G++ V3 ABI */ +// Solaris/x86-64 uses gcc >= 3.1 +#define STUB_ENTRY(n,m) \ +asm(".section .text\n\t" \ + ".align 2\n\t" \ + ".globl _ZN14nsXPTCStubBase" #m "Stub" #n "Ev\n\t" \ + ".type _ZN14nsXPTCStubBase" #m "Stub" #n "Ev,@function\n" \ + "_ZN14nsXPTCStubBase" #m "Stub" #n "Ev:\n\t" \ + "movl $" #n ", %eax\n\t" \ + "jmp SharedStub\n\t" \ + ".size _ZN14nsXPTCStubBase" #m "Stub" #n "Ev,.-_ZN14nsXPTCStubBase" #m "Stub" #n "Ev\n\t" \ + ) + +#define STUB_ENTRY_10(n10,m) \ + STUB_ENTRY(n10##0,m); \ + STUB_ENTRY(n10##1,m); \ + STUB_ENTRY(n10##2,m); \ + STUB_ENTRY(n10##3,m); \ + STUB_ENTRY(n10##4,m); \ + STUB_ENTRY(n10##5,m); \ + STUB_ENTRY(n10##6,m); \ + STUB_ENTRY(n10##7,m); \ + STUB_ENTRY(n10##8,m); \ + STUB_ENTRY(n10##9,m) +STUB_ENTRY_10(,5); +STUB_ENTRY_10(1,6); +STUB_ENTRY_10(2,6); +STUB_ENTRY_10(3,6); +STUB_ENTRY_10(4,6); +STUB_ENTRY_10(5,6); +STUB_ENTRY_10(6,6); +STUB_ENTRY_10(7,6); +STUB_ENTRY_10(8,6); +STUB_ENTRY_10(9,6); +STUB_ENTRY_10(10,7); +STUB_ENTRY_10(11,7); +STUB_ENTRY_10(12,7); +STUB_ENTRY_10(13,7); +STUB_ENTRY_10(14,7); +STUB_ENTRY_10(15,7); +STUB_ENTRY_10(16,7); +STUB_ENTRY_10(17,7); +STUB_ENTRY_10(18,7); +STUB_ENTRY_10(19,7); +STUB_ENTRY_10(20,7); +STUB_ENTRY_10(21,7); +STUB_ENTRY_10(22,7); +STUB_ENTRY_10(23,7); +STUB_ENTRY_10(24,7); + + +// static nsresult SharedStub(PRUint32 methodIndex) +asm(".section .text\n\t" + ".align 2\n\t" + ".type SharedStub,@function\n\t" + "SharedStub:\n\t" + // make room for gpregs (48), fpregs (64) + "pushq %rbp\n\t" + "movq %rsp,%rbp\n\t" + "subq $112,%rsp\n\t" + // save GP registers + "movq %rdi,-112(%rbp)\n\t" + "movq %rsi,-104(%rbp)\n\t" + "movq %rdx, -96(%rbp)\n\t" + "movq %rcx, -88(%rbp)\n\t" + "movq %r8 , -80(%rbp)\n\t" + "movq %r9 , -72(%rbp)\n\t" + "leaq -112(%rbp),%rcx\n\t" + // save FP registers + "movsd %xmm0,-64(%rbp)\n\t" + "movsd %xmm1,-56(%rbp)\n\t" + "movsd %xmm2,-48(%rbp)\n\t" + "movsd %xmm3,-40(%rbp)\n\t" + "movsd %xmm4,-32(%rbp)\n\t" + "movsd %xmm5,-24(%rbp)\n\t" + "movsd %xmm6,-16(%rbp)\n\t" + "movsd %xmm7, -8(%rbp)\n\t" + "leaq -64(%rbp),%r8\n\t" + // rdi has the 'self' pointer already + "movl %eax,%esi\n\t" + "leaq 16(%rbp),%rdx\n\t" + "call PrepareAndDispatch@plt\n\t" + "leave\n\t" + "ret\n\t" + ".size SharedStub,.-SharedStub"); + + +#define SENTINEL_ENTRY(n) \ +nsresult nsXPTCStubBase::Sentinel##n() \ +{ \ + NS_ASSERTION(0,"nsXPTCStubBase::Sentinel called"); \ + return NS_ERROR_NOT_IMPLEMENTED; \ +} + +SENTINEL_ENTRY(0) +SENTINEL_ENTRY(1) +SENTINEL_ENTRY(2) +SENTINEL_ENTRY(3) +SENTINEL_ENTRY(4) + +#else +#error "Unsupported compiler. Use gcc >= 3.1 for Linux/x86-64." +#endif /* __GNUC__ */ diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_x86_solaris.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_x86_solaris.cpp new file mode 100644 index 00000000..d4ae7667 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_x86_solaris.cpp @@ -0,0 +1,165 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** 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.org Code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Implement shared vtbl methods. */ + +#include "xptcprivate.h" +#include "xptc_platforms_unixish_x86.h" + +static nsresult +PrepareAndDispatch(nsXPTCStubBase* self, uint32 methodIndex, PRUint32* args) +{ +#define PARAM_BUFFER_COUNT 16 + + nsXPTCMiniVariant paramBuffer[PARAM_BUFFER_COUNT]; + nsXPTCMiniVariant* dispatchParams = NULL; + nsIInterfaceInfo* iface_info = NULL; + const nsXPTMethodInfo* info = NULL; + PRUint8 paramCount; + PRUint8 i; + nsresult result = NS_ERROR_FAILURE; + + NS_ASSERTION(self,"no self"); + + self->GetInterfaceInfo(&iface_info); + NS_ASSERTION(iface_info,"no interface info"); + if (!iface_info) + return NS_ERROR_UNEXPECTED; + + iface_info->GetMethodInfo(PRUint16(methodIndex), &info); + NS_ASSERTION(info,"no method info"); + if (!info) + return NS_ERROR_UNEXPECTED; + + paramCount = info->GetParamCount(); + + // setup variant array pointer + if(paramCount > PARAM_BUFFER_COUNT) + dispatchParams = new nsXPTCMiniVariant[paramCount]; + else + dispatchParams = paramBuffer; + NS_ASSERTION(dispatchParams,"no place for params"); + if (!dispatchParams) + return NS_ERROR_OUT_OF_MEMORY; + + PRUint32* ap = args; + for(i = 0; i < paramCount; i++, ap++) + { + const nsXPTParamInfo& param = info->GetParam(i); + const nsXPTType& type = param.GetType(); + nsXPTCMiniVariant* dp = &dispatchParams[i]; + + if(param.IsOut() || !type.IsArithmetic()) + { + dp->val.p = (void*) *ap; + continue; + } + // else + dp->val.p = (void*) *ap; + switch(type) + { + case nsXPTType::T_I64 : dp->val.i64 = *((PRInt64*) ap); ap++; break; + case nsXPTType::T_U64 : dp->val.u64 = *((PRUint64*)ap); ap++; break; + case nsXPTType::T_DOUBLE : dp->val.d = *((double*) ap); ap++; break; + } + } + + result = self->CallMethod((PRUint16)methodIndex, info, dispatchParams); + + NS_RELEASE(iface_info); + + if(dispatchParams != paramBuffer) + delete [] dispatchParams; + + return result; +} + +#ifdef __GNUC__ /* Gnu Compiler. */ +#define STUB_ENTRY(n) \ +nsresult nsXPTCStubBase::Stub##n() \ +{ \ + register nsresult (*method) (nsXPTCStubBase *, uint32, PRUint32 *) = PrepareAndDispatch; \ + int temp0, temp1; \ + register nsresult result; \ + __asm__ __volatile__( \ + "leal 0x0c(%%ebp), %%ecx\n\t" /* args */ \ + "pushl %%ecx\n\t" \ + "pushl $"#n"\n\t" /* method index */ \ + "movl 0x08(%%ebp), %%ecx\n\t" /* this */ \ + "pushl %%ecx\n\t" \ + "call *%%edx\n\t" /* PrepareAndDispatch */ \ + "addl $12, %%esp" \ + : "=a" (result), /* %0 */ \ + "=&c" (temp0), /* %1 */ \ + "=d" (temp1) /* %2 */ \ + : "2" (method) /* %2 */ \ + : "memory" ); \ + return result; \ +} + +#elif defined(__SUNPRO_CC) /* Sun Workshop Compiler. */ + +#define STUB_ENTRY(n) \ +nsresult nsXPTCStubBase::Stub##n() \ +{ \ + asm ( \ + "\n\t leal 0x0c(%ebp), %ecx\t / args" \ + "\n\t pushl %ecx" \ + "\n\t pushl $"#n"\t / method index" \ + "\n\t movl 0x08(%ebp), %ecx\t / this" \ + "\n\t pushl %ecx" \ + "\n\t call __1cSPrepareAndDispatch6FpnOnsXPTCStubBase_IpI_I_\t / PrepareAndDispatch" \ + "\n\t addl $12, %esp" \ + ); \ +/* result == %eax */ \ + if(0) /* supress "*** is expected to return a value." error */ \ + return 0; \ +} + +#else +#error "can't find a compiler to use" +#endif /* __GNUC__ */ + +#define SENTINEL_ENTRY(n) \ +nsresult nsXPTCStubBase::Sentinel##n() \ +{ \ + NS_ASSERTION(0,"nsXPTCStubBase::Sentinel called"); \ + return NS_ERROR_NOT_IMPLEMENTED; \ +} + +#include "xptcstubsdef.inc" diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/win32/.cvsignore b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/win32/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/win32/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/win32/Makefile.in b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/win32/Makefile.in new file mode 100644 index 00000000..0de74ee2 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/win32/Makefile.in @@ -0,0 +1,82 @@ +# +# ***** 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.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of 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 ***** + +DEPTH = ../../../../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = xpcom +LIBRARY_NAME = xptcmd + +# +# The default is this buildable, but non-functioning code. +# +ifdef GNU_CXX +CPPSRCS = \ + ../unix/xptcinvoke_gcc_x86_unix.cpp \ + xptcstubs.cpp \ + $(NULL) +LOCAL_INCLUDES = -I$(srcdir)/../unix +DEFINES += -DMOZ_USE_STDCALL -DMOZ_NEED_LEADING_UNDERSCORE +else +CPPSRCS = xptcinvoke.cpp xptcstubs.cpp +endif + + +# Force use of PIC +FORCE_USE_PIC = 1 + +include $(topsrcdir)/config/config.mk + +ifeq ($(CPU),ALPHA) +CPPSRCS := xptcinvoke_alpha.cpp xptcstubs_alpha.cpp +ASFILES := xptcinvoke_asm_alpha.s xptcstubs_asm_alpha.s +AS := asaxp +ASFLAGS += /I../../..public +endif + +# we don't want the shared lib, but we want to force the creation of a static lib. +FORCE_STATIC_LIB = 1 + +include $(topsrcdir)/config/rules.mk + +DEFINES += -DEXPORT_XPTC_API -D_IMPL_NS_COM -D_IMPL_NS_BASE + +LOCAL_INCLUDES += -I$(srcdir)/../.. diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/win32/xptcinvoke.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/win32/xptcinvoke.cpp new file mode 100644 index 00000000..9fbf2f94 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/win32/xptcinvoke.cpp @@ -0,0 +1,107 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Platform specific code to invoke XPCOM methods on native objects */ + +#include "xptcprivate.h" + +#ifndef WIN32 +#error "This code is for Win32 only" +#endif + +static void __fastcall +invoke_copy_to_stack(PRUint32* d, PRUint32 paramCount, nsXPTCVariant* s) +{ + for(; paramCount > 0; paramCount--, d++, s++) + { + if(s->IsPtrData()) + { + *((void**)d) = s->ptr; + continue; + } + switch(s->type) + { + case nsXPTType::T_I8 : *((PRInt8*) d) = s->val.i8; break; + case nsXPTType::T_I16 : *((PRInt16*) d) = s->val.i16; break; + case nsXPTType::T_I32 : *((PRInt32*) d) = s->val.i32; break; + case nsXPTType::T_I64 : *((PRInt64*) d) = s->val.i64; d++; break; + case nsXPTType::T_U8 : *((PRUint8*) d) = s->val.u8; break; + case nsXPTType::T_U16 : *((PRUint16*)d) = s->val.u16; break; + case nsXPTType::T_U32 : *((PRUint32*)d) = s->val.u32; break; + case nsXPTType::T_U64 : *((PRUint64*)d) = s->val.u64; d++; break; + case nsXPTType::T_FLOAT : *((float*) d) = s->val.f; break; + case nsXPTType::T_DOUBLE : *((double*) d) = s->val.d; d++; break; + case nsXPTType::T_BOOL : *((PRBool*) d) = s->val.b; break; + case nsXPTType::T_CHAR : *((char*) d) = s->val.c; break; + case nsXPTType::T_WCHAR : *((wchar_t*) d) = s->val.wc; break; + default: + // all the others are plain pointer types + *((void**)d) = s->val.p; + break; + } + } +} + +#pragma warning(disable : 4035) // OK to have no return value +__declspec(naked) XPTC_PUBLIC_API(nsresult) +XPTC_InvokeByIndex(nsISupports* that, PRUint32 methodIndex, + PRUint32 paramCount, nsXPTCVariant* params) +{ + __asm { + push ebp + mov ebp,esp + mov edx,paramCount // Save paramCount for later + test edx,edx // maybe we don't have any params to copy + jz noparams + mov eax,edx + shl eax,3 // *= 8 (max possible param size) + sub esp,eax // make space for params + mov ecx,esp + push params + call invoke_copy_to_stack // fastcall, ecx = d, edx = paramCount, params is on the stack +noparams: + mov ecx,that // instance in ecx + push ecx // push this + mov edx,[ecx] // vtable in edx + mov eax,methodIndex + call [edx][eax*4] // stdcall, i.e. callee cleans up stack. + mov esp,ebp + pop ebp + ret + } +} +#pragma warning(default : 4035) // restore default diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/win32/xptcinvoke_alpha.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/win32/xptcinvoke_alpha.cpp new file mode 100644 index 00000000..06334ac0 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/win32/xptcinvoke_alpha.cpp @@ -0,0 +1,171 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Platform specific code to invoke XPCOM methods on native objects */ + +/* contributed by bob meader */ + +#include "xptcprivate.h" + +extern "C" uint32 +invoke_count_words(PRUint32 paramCount, nsXPTCVariant* s) +{ + return(paramCount*2); +} + +extern "C" void +invoke_copy_to_stack(PRUint64* d, PRUint32 paramCount, + nsXPTCVariant* s, PRUint64 *regs) +{ +#define N_ARG_REGS 5 /* 6 regs minus 1 for "this" ptr */ + + for (PRUint32 i = 0; i < paramCount; i++, s++) + { + if (s->IsPtrData()) { + if (i < N_ARG_REGS) + regs[i] = (PRUint32)s->ptr; + else + *((PRUint32*)d++) = (PRUint32)s->ptr; + continue; + } + switch (s->type) { + // + // signed types first + // + case nsXPTType::T_I8: + if (i < N_ARG_REGS) + ((PRInt64*)regs)[i] = s->val.i8; + else + *((PRInt8 *)d++) = s->val.i8; + break; + case nsXPTType::T_I16: + if (i < N_ARG_REGS) + ((PRInt64*)regs)[i] = s->val.i16; + else + *((PRInt16 *)d++) = s->val.i16; + break; + case nsXPTType::T_I32: + if (i < N_ARG_REGS) + ((PRInt64*)regs)[i] = s->val.i32; + else + *((PRUint32*)d++) = s->val.i32; + break; + case nsXPTType::T_I64: + if (i < N_ARG_REGS) + ((PRInt64*)regs)[i] = s->val.i64; + else + *((PRInt64*)d++) = s->val.i64; + break; + // + // unsigned types next + // + case nsXPTType::T_U8: + if (i < N_ARG_REGS) + regs[i] = s->val.u8; + else + *((PRUint8 *)d++) = s->val.u8; + break; + case nsXPTType::T_U16: + if (i < N_ARG_REGS) + regs[i] = s->val.u16; + else + *((PRUint16 *)d++) = s->val.u16; + break; + case nsXPTType::T_U32: + if (i < N_ARG_REGS) + regs[i] = s->val.u32; + else + *((PRUint32*)d++) = s->val.u32; + break; + case nsXPTType::T_U64: + if (i < N_ARG_REGS) + regs[i] = s->val.u64; + else + *((PRUint64*)d++) = s->val.u64; + break; + case nsXPTType::T_FLOAT: + if (i < N_ARG_REGS) + ((double*)regs)[i] = s->val.f; + else + *((float*)d++) = s->val.f; + break; + case nsXPTType::T_DOUBLE: + if (i < N_ARG_REGS) + ((double*)regs)[i] = s->val.d; + else + *((double*)d++) = s->val.d; + break; + case nsXPTType::T_BOOL: + if (i < N_ARG_REGS) + regs[i] = s->val.b; + else + *((PRBool*)d++) = s->val.b; + break; + case nsXPTType::T_CHAR: + if (i < N_ARG_REGS) + regs[i] = s->val.c; + else + *((char*)d++) = s->val.c; + break; + case nsXPTType::T_WCHAR: + if (i < N_ARG_REGS) + regs[i] = s->val.wc; + else + *((wchar_t*)d++) = s->val.wc; + break; + default: + // all the others are plain pointer types + if (i < N_ARG_REGS) + regs[i] = (PRUint32)s->val.p; + else + *((PRUint32*)d++) = (PRUint32)s->val.p; + break; + } + } +} + +extern "C" nsresult XPTC__InvokebyIndex(nsISupports* that, PRUint32 methodIndex, + PRUint32 paramCount, nsXPTCVariant* params); + +extern "C" +XPTC_PUBLIC_API(nsresult) +XPTC_InvokeByIndex(nsISupports* that, PRUint32 methodIndex, + PRUint32 paramCount, nsXPTCVariant* params) +{ + return XPTC__InvokebyIndex(that, methodIndex, paramCount, params); +} + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/win32/xptcinvoke_asm_alpha.s b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/win32/xptcinvoke_asm_alpha.s new file mode 100644 index 00000000..7f8b343b --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/win32/xptcinvoke_asm_alpha.s @@ -0,0 +1,128 @@ +.text +.globl invoke_count_words +.globl invoke_copy_to_stack + +#define v0 $0 +#define t0 $1 +#define t1 $2 +#define t2 $3 +#define t3 $4 +#define s0 $9 +#define fp $15 +#define a0 $16 +#define a1 $17 +#define a2 $18 +#define a3 $19 +#define a4 $20 +#define a5 $21 +#define t9 $23 +#define ra $26 +#define gp $29 +#define sp $30 +#define zero $31 +#define f0 $f0 + +#define LOCALSZ 7 +#define NARG 2 +#define SZREG 8 +#define FRAMESZ ((NARG+LOCALSZ)*SZREG) +RAOFF=FRAMESZ-(1*SZREG) +A0OFF=FRAMESZ-(2*SZREG) +A1OFF=FRAMESZ-(3*SZREG) +A2OFF=FRAMESZ-(4*SZREG) +A3OFF=FRAMESZ-(5*SZREG) +S0OFF=FRAMESZ-(6*SZREG) +GPOFF=FRAMESZ-(7*SZREG) + +// +// Nested +// XPTC__InvokebyIndex( that, methodIndex, paramCount, params) +// a0 a1 a2 a3 +// + .text + .align 4 + .globl XPTC__InvokebyIndex + .ent XPTC__InvokebyIndex,0 +XPTC__InvokebyIndex: + .frame sp, FRAMESZ, ra + subl sp,FRAMESZ,sp // allocate stack space for structure + stq ra, RAOFF(sp) + stq a0, A0OFF(sp) + stq a1, A1OFF(sp) + stq a2, A2OFF(sp) + stq a3, A3OFF(sp) + stq s0, S0OFF(sp) +// stq gp, GPOFF(sp) Don't think I am to save gp + + // invoke_count_words(paramCount, params) + bis a2,zero,a0 // move a2 into a0 + bis a3,zero,a1 // move a3 into a1 + bsr ra,invoke_count_words + + // invoke_copy_to_stack + ldq a1, A2OFF(sp) // a1 = paramCount + ldq a2, A3OFF(sp) // a2 = params + + // save sp before we copy the params to the stack + bis sp,zero,t0 // t0 = sp + + // assume full size of 8 bytes per param to be safe + sll v0,4,v0 //v0 = 8 bytes * num params + subl sp,v0,sp //sp = sp - v0 + bis sp,zero,a0 //a0 = param stack address + + // create temporary stack space to write int and fp regs + subl sp,64,sp //sp = sp -64 // (64 = 8 regs of eight bytes) + bis sp,zero,a3 // a3 = sp + + // save the old sp and save the arg stack + subl sp,16,sp //sp = sp -16 + stq t0,0(sp) + stq a0,8(sp) + // copy the param into the stack areas + bsr ra,invoke_copy_to_stack + + ldq t3,8(sp) // get previous a0 + ldq sp,0(sp) // get orig sp back + + ldq a0,A0OFF(sp) // a0 = that + ldq a1,A1OFF(sp) // a1 = methodIndex + + // calculate jmp address from method index + ldl t1,0(a0) // t1 = *that + sll a1,2,a1 // a1 = 4*index + addl t1,a1,t9 + ldl t9,0(t9) // t9=*(that + 4*index) + + // get register save area from invoke_copy_to_stack + subl t3,64,t1 + + // a1..a5 and f17..f21 should now be set to what + // invoke_copy_to_stack told us. skip a0 and f16 + // because that's the "this" pointer + + ldq a1,0(t1) + ldq a2,8(t1) + ldq a3,16(t1) + ldq a4,24(t1) + ldq a5,32(t1) + + ldt $f17,0(t1) + ldt $f18,8(t1) + ldt $f19,16(t1) + ldt $f20,24(t1) + ldt $f21,32(t1) + + // save away our stack point and create + // the stack pointer for the function + bis sp,zero,s0 + bis t3,zero,sp + jsr ra,(t9) + bis s0,zero,sp + ldq ra,RAOFF(sp) + ldq s0,S0OFF(sp) + addl sp,FRAMESZ,sp + ret + +.end XPTC__InvokebyIndex + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/win32/xptcstubs.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/win32/xptcstubs.cpp new file mode 100644 index 00000000..bd5ab975 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/win32/xptcstubs.cpp @@ -0,0 +1,202 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Implement shared vtbl methods. */ + +#include "xptcprivate.h" + +#ifndef WIN32 +#error "This code is for Win32 only" +#endif + +extern "C" { + +static nsresult __stdcall +PrepareAndDispatch(nsXPTCStubBase* self, PRUint32 methodIndex, + PRUint32* args, PRUint32* stackBytesToPop) +{ +#define PARAM_BUFFER_COUNT 16 + + nsXPTCMiniVariant paramBuffer[PARAM_BUFFER_COUNT]; + nsXPTCMiniVariant* dispatchParams = NULL; + nsIInterfaceInfo* iface_info = NULL; + const nsXPTMethodInfo* info = NULL; + PRUint8 paramCount; + PRUint8 i; + nsresult result = NS_ERROR_FAILURE; + + // If anything fails before stackBytesToPop can be set then + // the failure is completely catastrophic! + + NS_ASSERTION(self,"no self"); + + self->GetInterfaceInfo(&iface_info); + NS_ASSERTION(iface_info,"no interface info"); + + iface_info->GetMethodInfo(PRUint16(methodIndex), &info); + NS_ASSERTION(info,"no interface info"); + + paramCount = info->GetParamCount(); + + // setup variant array pointer + if(paramCount > PARAM_BUFFER_COUNT) + dispatchParams = new nsXPTCMiniVariant[paramCount]; + else + dispatchParams = paramBuffer; + NS_ASSERTION(dispatchParams,"no place for params"); + + PRUint32* ap = args; + for(i = 0; i < paramCount; i++, ap++) + { + const nsXPTParamInfo& param = info->GetParam(i); + const nsXPTType& type = param.GetType(); + nsXPTCMiniVariant* dp = &dispatchParams[i]; + + if(param.IsOut() || !type.IsArithmetic()) + { + dp->val.p = (void*) *ap; + continue; + } + // else + switch(type) + { + case nsXPTType::T_I8 : dp->val.i8 = *((PRInt8*) ap); break; + case nsXPTType::T_I16 : dp->val.i16 = *((PRInt16*) ap); break; + case nsXPTType::T_I32 : dp->val.i32 = *((PRInt32*) ap); break; + case nsXPTType::T_I64 : dp->val.i64 = *((PRInt64*) ap); ap++; break; + case nsXPTType::T_U8 : dp->val.u8 = *((PRUint8*) ap); break; + case nsXPTType::T_U16 : dp->val.u16 = *((PRUint16*)ap); break; + case nsXPTType::T_U32 : dp->val.u32 = *((PRUint32*)ap); break; + case nsXPTType::T_U64 : dp->val.u64 = *((PRUint64*)ap); ap++; break; + case nsXPTType::T_FLOAT : dp->val.f = *((float*) ap); break; + case nsXPTType::T_DOUBLE : dp->val.d = *((double*) ap); ap++; break; + case nsXPTType::T_BOOL : dp->val.b = *((PRBool*) ap); break; + case nsXPTType::T_CHAR : dp->val.c = *((char*) ap); break; + case nsXPTType::T_WCHAR : dp->val.wc = *((wchar_t*) ap); break; + default: + NS_ASSERTION(0, "bad type"); + break; + } + } + *stackBytesToPop = ((PRUint32)ap) - ((PRUint32)args); + + result = self->CallMethod((PRUint16)methodIndex, info, dispatchParams); + + NS_RELEASE(iface_info); + + if(dispatchParams != paramBuffer) + delete [] dispatchParams; + + return result; +} + +} // extern "C" + +// declspec(naked) is broken in gcc +#ifndef __GNUC__ +static +__declspec(naked) +void SharedStub(void) +{ + __asm { + push ebp // set up simple stack frame + mov ebp, esp // stack has: ebp/vtbl_index/retaddr/this/args + push ecx // make room for a ptr + lea eax, [ebp-4] // pointer to stackBytesToPop + push eax + lea eax, [ebp+12] // pointer to args + push eax + push ecx // vtbl_index + mov eax, [ebp+8] // this + push eax + call PrepareAndDispatch + mov edx, [ebp+4] // return address + mov ecx, [ebp-4] // stackBytesToPop + add ecx, 8 // for 'this' and return address + mov esp, ebp + pop ebp + add esp, ecx // fix up stack pointer + jmp edx // simulate __stdcall return + } +} + +// these macros get expanded (many times) in the file #included below +#define STUB_ENTRY(n) \ +__declspec(naked) nsresult __stdcall nsXPTCStubBase::Stub##n() \ +{ __asm mov ecx, n __asm jmp SharedStub } + +#else + +#define STUB_ENTRY(n) \ +nsresult __stdcall nsXPTCStubBase::Stub##n() \ +{ \ + PRUint32 *args, stackBytesToPop = 0; \ + nsresult result = 0; \ + nsXPTCStubBase *obj; \ + __asm__ __volatile__ ( \ + "leal 0x0c(%%ebp), %%ecx\n\t" /* args */ \ + "movl 0x08(%%ebp), %%edx\n\t" /* this */ \ + : "=c" (args), \ + "=d" (obj)); \ + result = PrepareAndDispatch(obj, n, args, &stackBytesToPop); \ + return result; \ +} + +#endif /* __GNUC__ */ + +#define SENTINEL_ENTRY(n) \ +nsresult __stdcall nsXPTCStubBase::Sentinel##n() \ +{ \ + NS_ASSERTION(0,"nsXPTCStubBase::Sentinel called"); \ + return NS_ERROR_NOT_IMPLEMENTED; \ +} + +#ifdef _MSC_VER +#pragma warning(disable : 4035) // OK to have no return value +#endif +#include "xptcstubsdef.inc" +#ifdef _MSC_VER +#pragma warning(default : 4035) // restore default +#endif + +void +#ifdef __GNUC__ +__cdecl +#endif +xptc_dummy() +{ +} diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/win32/xptcstubs_alpha.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/win32/xptcstubs_alpha.cpp new file mode 100644 index 00000000..69a10e70 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/win32/xptcstubs_alpha.cpp @@ -0,0 +1,228 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Implement shared vtbl methods. */ + +#include "xptcprivate.h" + +/* contributed by bob meader */ + +/* + * This is for Alpha /NT 32 bits + * + * When we're called, the "gp" registers are stored in gprData and + * the "fp" registers are stored in fprData. There are 6 regs + * available which coorespond to the first 5 parameters of the + * function and the "this" pointer. If there are additional parms, + * they are stored on the stack at address "args". + * + */ +extern "C" nsresult +PrepareAndDispatch(nsXPTCStubBase* self, PRUint32 methodIndex, PRUint64* args, + PRUint64 *gprData, double *fprData) +{ +#define PARAM_BUFFER_COUNT 16 +#define PARAM_GPR_COUNT 5 +#define PARAM_FPR_COUNT 5 + + nsXPTCMiniVariant paramBuffer[PARAM_BUFFER_COUNT]; + nsXPTCMiniVariant* dispatchParams = NULL; + nsIInterfaceInfo* iface_info = NULL; + const nsXPTMethodInfo* info; + PRUint8 paramCount; + PRUint8 i; + nsresult result = NS_ERROR_FAILURE; + + NS_ASSERTION(self,"no self"); + + self->GetInterfaceInfo(&iface_info); + NS_ASSERTION(iface_info,"no interface info"); + + iface_info->GetMethodInfo(PRUint16(methodIndex), &info); + NS_ASSERTION(info,"no interface info"); + + paramCount = info->GetParamCount(); + + // setup variant array pointer + if(paramCount > PARAM_BUFFER_COUNT) + dispatchParams = new nsXPTCMiniVariant[paramCount]; + else + dispatchParams = paramBuffer; + NS_ASSERTION(dispatchParams,"no place for params"); + + PRUint64* ap = args; + PRUint32 iCount = 0; + for(i = 0; i < paramCount; i++) + { + const nsXPTParamInfo& param = info->GetParam(i); + const nsXPTType& type = param.GetType(); + nsXPTCMiniVariant* dp = &dispatchParams[i]; + + if(param.IsOut() || !type.IsArithmetic()) + { + if (iCount < PARAM_GPR_COUNT) + dp->val.p = (void*)gprData[iCount++]; + else + dp->val.p = (void*)ap++; + continue; + } + // else + switch(type) + { + case nsXPTType::T_I8: + if (iCount < PARAM_GPR_COUNT) + dp->val.i8 = (PRInt8)gprData[iCount++]; + else + dp->val.i8 = *((PRInt8*)ap++); + break; + + case nsXPTType::T_I16: + if (iCount < PARAM_GPR_COUNT) + dp->val.i16 = (PRInt16)gprData[iCount++]; + else + dp->val.i16 = *((PRInt16*)ap++); + break; + + case nsXPTType::T_I32: + if (iCount < PARAM_GPR_COUNT) + dp->val.i32 = (PRInt32)gprData[iCount++]; + else + dp->val.i32 = *((PRInt32*)ap++); + break; + + case nsXPTType::T_I64: + if (iCount < PARAM_GPR_COUNT) + dp->val.i64 = (PRInt64)gprData[iCount++]; + else + dp->val.i64 = *((PRInt64*)ap++); + break; + + case nsXPTType::T_U8: + if (iCount < PARAM_GPR_COUNT) + dp->val.u8 = (PRUint8)gprData[iCount++]; + else + dp->val.u8 = *((PRUint8*)ap++); + break; + + case nsXPTType::T_U16: + if (iCount < PARAM_GPR_COUNT) + dp->val.u16 = (PRUint16)gprData[iCount++]; + else + dp->val.u16 = *((PRUint16*)ap++); + break; + + case nsXPTType::T_U32: + if (iCount < PARAM_GPR_COUNT) + dp->val.u32 = (PRUint32)gprData[iCount++]; + else + dp->val.u32 = *((PRUint32*)ap++); + break; + + case nsXPTType::T_U64: + if (iCount < PARAM_GPR_COUNT) + dp->val.u64 = (PRUint64)gprData[iCount++]; + else + dp->val.u64 = (PRUint64)*ap++; + break; + + case nsXPTType::T_FLOAT: + if (iCount < PARAM_FPR_COUNT) + dp->val.f = (float)fprData[iCount++]; + else + dp->val.f = *((float*)ap++); + break; + + case nsXPTType::T_DOUBLE: + if (iCount < PARAM_FPR_COUNT) + dp->val.d = (double)fprData[iCount++]; + else + dp->val.d = *((double*)ap++); + break; + + case nsXPTType::T_BOOL: + if (iCount < PARAM_GPR_COUNT) + dp->val.b = (PRBool)gprData[iCount++]; + else + dp->val.b = *((PRBool*)ap++); + break; + + case nsXPTType::T_CHAR: + if (iCount < PARAM_GPR_COUNT) + dp->val.c = (char)gprData[iCount++]; + else + dp->val.c = *((char*)ap++); + break; + + case nsXPTType::T_WCHAR: + if (iCount < PARAM_GPR_COUNT) + dp->val.wc = (wchar_t)gprData[iCount++]; + else + dp->val.wc = *((wchar_t*)ap++); + break; + + default: + NS_ASSERTION(0, "bad type"); + break; + } + } + + result = self->CallMethod((PRUint16)methodIndex, info, dispatchParams); + + NS_RELEASE(iface_info); + + if(dispatchParams != paramBuffer) + delete [] dispatchParams; + + return result; +} + +#define STUB_ENTRY(n) /* defined in the assembly file */ + +#define SENTINEL_ENTRY(n) \ +nsresult nsXPTCStubBase::Sentinel##n() \ +{ \ + NS_ASSERTION(0,"nsXPTCStubBase::Sentinel called"); \ + return NS_ERROR_NOT_IMPLEMENTED; \ +} + +#include "xptcstubsdef.inc" + +void +xptc_dummy() +{ +} + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/win32/xptcstubs_asm_alpha.s b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/win32/xptcstubs_asm_alpha.s new file mode 100644 index 00000000..5f8f861d --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/win32/xptcstubs_asm_alpha.s @@ -0,0 +1,120 @@ + +#define v0 $0 // return value register +#define t0 $1 // caller saved (temporary) registers +#define t1 $2 // +#define t2 $3 // +#define t3 $4 // +#define t4 $5 // +#define t5 $6 // +#define t6 $7 // +#define t7 $8 // +#define s0 $9 // callee saved (nonvolatile) registers +#define a0 $16 // argument registers +#define a1 $17 // +#define a2 $18 // +#define a3 $19 // +#define a4 $20 // +#define a5 $21 // +#define t8 $22 // caller saved (temporary) registers +#define t9 $23 // +#define t10 $24 // +#define t11 $25 // +#define ra $26 // return address register +#define sp $30 // stack pointer register +#define zero $31 // zero register +#define f16 $f16 // argument registers +#define f17 $f17 // +#define f18 $f18 // +#define f19 $f19 // +#define f20 $f20 // +#define f21 $f21 // + +#define NARGSAVE 2 +#define LOCALSZ 16 +#define SZREG 8 +#define FRAMESZ (NARGSAVE+LOCALSZ)*SZREG + + .text + .globl PrepareAndDispatch + +A1OFF=FRAMESZ-(9*SZREG) +A2OFF=FRAMESZ-(8*SZREG) +A3OFF=FRAMESZ-(7*SZREG) +A4OFF=FRAMESZ-(6*SZREG) +A5OFF=FRAMESZ-(5*SZREG) +A6OFF=FRAMESZ-(4*SZREG) //not used +A7OFF=FRAMESZ-(3*SZREG) //not used +GPOFF=FRAMESZ-(2*SZREG) //not used +RAOFF=FRAMESZ-(1*SZREG) + +F16OFF=FRAMESZ-(16*SZREG) //not used +F17OFF=FRAMESZ-(15*SZREG) +F18OFF=FRAMESZ-(14*SZREG) +F19OFF=FRAMESZ-(13*SZREG) +F20OFF=FRAMESZ-(12*SZREG) +F21OFF=FRAMESZ-(11*SZREG) +F22OFF=FRAMESZ-(10*SZREG) // not used + +#define NESTED_ENTRY(Name, fsize, retrg) \ + .text; \ + .align 4; \ + .globl Name; \ + .ent Name, 0; \ +Name:; \ + .frame sp, fsize, retrg; + +#define SENTINEL_ENTRY(nn) +#define STUB_ENTRY(nn) MAKE_PART(nn,@nsXPTCStubBase@@UAAIXZ ) + +#define MAKE_PART(aa, bb) MAKE_STUB(aa, ?Stub##aa##bb ) + +#define MAKE_STUB(nn, name) \ +NESTED_ENTRY(name, FRAMESZ,ra); \ + subl sp,FRAMESZ,sp; \ + mov nn,t0; \ + jmp sharedstub; \ +.end name; + +#include "xptcstubsdef.inc" + + .globl sharedstub + .ent sharedstub +sharedstub: + stq a1,A1OFF(sp) + stq a2,A2OFF(sp) + stq a3,A3OFF(sp) + stq a4,A4OFF(sp) + stq a5,A5OFF(sp) + stq ra,RAOFF(sp) + + stt f17,F17OFF(sp) + stt f18,F18OFF(sp) + stt f19,F19OFF(sp) + stt f20,F20OFF(sp) + stt f21,F21OFF(sp) + + // t0 is methodIndex + bis t0,zero,a1 // a1 = methodIndex + + // a2 is stack address where extra function params + // are stored that do not fit in registers + bis sp,zero,a2 //a2 = sp + addl a2,FRAMESZ,a2 //a2+=FRAMESZ + + // a3 is stack addrss of a1..a5 + bis sp,zero,a3 //a3 = sp + addl a3,A1OFF,a3 //a3+=A1OFF + + // a4 is stack address of f17..f21 + bis sp,zero,a4 //a4 = sp + addl a4,F17OFF,a4 //a4+=F17OFF + + // PrepareAndDispatch(that, methodIndex, args, gprArgs, fpArgs) + // a0 a1 a2 a3 a4 + bsr PrepareAndDispatch + ldq ra,RAOFF(sp) + addl sp,FRAMESZ,sp + ret + +.end sharedstub + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/xptcall.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/xptcall.cpp new file mode 100644 index 00000000..f25a94e5 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/xptcall.cpp @@ -0,0 +1,62 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* entry point wrappers. */ + +#if defined(XP_MAC) +#pragma export on +#endif + +#include "xptcprivate.h" + +// This method is never called and is only here so the compiler +// will generate a vtbl for this class. +// *Needed by the Irix implementation.* +NS_IMETHODIMP nsXPTCStubBase::QueryInterface(REFNSIID aIID, + void** aInstancePtr) +{ + NS_ASSERTION(0,"wowa! nsXPTCStubBase::QueryInterface called"); + return NS_ERROR_FAILURE; +} +#if defined(XP_MAC) +#pragma export off +#endif + +void +xptc_dummy2() +{ +} diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/xptcprivate.h b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/xptcprivate.h new file mode 100644 index 00000000..3691fa0a --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/xptcprivate.h @@ -0,0 +1,45 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* All the xptcall private declarations - only include locally. */ + +#ifndef xptcprivate_h___ +#define xptcprivate_h___ + +#include "xptcall.h" + +#endif /* xptcprivate_h___ */ diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/status.html b/src/libs/xpcom18a4/xpcom/reflect/xptcall/status.html new file mode 100644 index 00000000..e3686999 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/status.html @@ -0,0 +1,404 @@ + + +xptcall Porting Status + + +

xptcall Porting Status

+ +

What is this?

+ +This is a status page for the multiplatform porting of xptcall. +xptcall has a +FAQ +and a +Porting Guide. + +

+ +This is being maintained by John Bandhauer <jband@netscape.com>. +Feel free to email me with questions or to volunteer to contribute xptcall code for any platform. + +

+ +Mike Shaver <shaver@mozilla.org> +is the best contact regarding 'nix (Unix, Linux, Finux, etc.) ports of xptcall. + +

Status

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
StatusPlatformContributors and ? Possible ContributorsNotes
DoneWin32 x86Contributed code! +John Bandhauer <jband@netscape.com> + +win32
DoneLinux x86Contributed code! +John Bandhauer <jband@netscape.com>
+Contributed code! +Ulrich Drepper <drepper@cygnus.com> +
unix +
DoneFreeBSD and NetBSD x86Contributed code! +Christoph Toshok <toshok@hungry.com>,
+Contributed code! +John Bandhauer <jband@netscape.com>
unix (same as Linux 86 code)
DoneBSD/OS x86Contributed code! +Bert Driehuis <bert_driehuis@nl.compuware.com>unix (same as Linux 86 code) +Bert contributed patches that *should* do the right thing for all the unixish-x86 +versions of this code for GCC 2.7 or 2.8 vs. EGCS 1.1. He notes that the vtbl +scheme is different. He is hoping that others will help test the changes using +these two compilers on the various platforms where this same code is used. +Bert's details +
DoneMac PPCContributed code! + Roger Lawrence <rogerl@netscape.com>,
+Contributed code! +Patrick Beard <beard@netscape.com> +
mac (passing tests and checked in)
DoneSolaris SparcContributed code! +Roger Lawrence <rogerl@netscape.com>,
+Contributed code! +Chris McAfee <mcafee@netscape.com> +
unix This is checked in and working.
DoneSolaris Sparc v9 (64bit)Contributed code! +Stuart Parmenter <pavlov@netscape.com>,
+Contributed code! +Chris Seawood <cls@seawood.org> +
unix This is checked in and (pavlov claims!) working.
DoneOS/2Contributed code! +John Fairhurst <mjf35@cam.ac.uk>I never heard exactly who did what. But mozilla has been working on OS/2 +for a long time now. +
DoneOpenVMS AlphaContributed code! +Colin R. Blake <colin@theblakes.com> +Colin says this is passing all the tests on OpenVMS Alpha! +
DoneNT AlphaContributed code! +bob meader <bob@guiduck.com> +bob writes:
+Enclosed is xptcall for alpha/nt target.. +

+It is a variation of the IRIS port (only targeted for win32). +

+Notice the last 2 files (the change to mozilla\xpcom\build\makefile.win and +mozilla\xpcom\build) are needed because I was unable to figure how to do a +"declspecexport" from the assembler ASAXP ... if some knows how to do that then +those last 2 files won't be needed. +

+I have had someone look over this code at bridge.com (the entry point to +compaq/gem compiler team) and this code was given the OK. I consider it "done". +

+This code lives in the files where the name includes 'alpha' in the win32 directory.
+

DoneLinux ARMStarted +Stefan Hanske<sh990154@mail.uni-greifswald.de>
+? +Matthew Wilcox <willy@bofh.ai>
+Stefan's code is checked in and he says it is working. +
DoneLinux Sparc +Contributed code! +Anton Blanchard <anton@progsoc.uts.edu.au>, +
+Contributed code! +Roger Lawrence <rogerl@netscape.com>, +
+Maybe +Brandon Ehle <ehle.3@osu.edu> +
+Anton contributed patches to Roger's Sparc code. Anton says it works and passes the tests! +(24-Aug-1999) Brandon writes: I've finished testing XPTCALL Sparc Linux on 12 different Sparc machines and it checks out good. +
DoneLinux PPC +Contributed code! +Patrick Beard <beard@netscape.com>
+Contributed code! +Chris Waterson <waterson@netscape.com>
+Contributed code! +Franz Sirl <Franz.Sirl-kernel@lauterbach.com>
+? +Jason Y. Sproul <jsproul@condor.fddi.wesleyan.edu>
+ ? + Sean Chitwood <darkmane@w-link.net>
+waterson said: Mozilla runs on Linux/PPC +
DoneLinux Alpha +Contributed code! +Glen Nakamura <glen.nakamura@usa.net>
+Contributed code! +Dan Morril <morrildl@nycap.rr.com>
+
+Glen writes: +

+I am attaching a patch which contains my Linux Alpha xptcall code. +It passes TestXPTCInvoke and TestXPC on my machine which runs +kernel 2.2.7, glibc 2.1.1, and egcs 1.1.2. I have not tested it +with older GNU compilers such as gcc 2.8.x. From looking at the +Linux x86 code, I gather that the vtable layout is a little different +for those compilers and the code will need minor modifications +in order to work properly. +

+I am not sure how much of the code can be used for OpenVMS Alpha +and/or Digital UNIX. Currently the code is dependent on the g++ +name mangling convention and a few GNU extensions so I'm not sure +how useful it will be for the other systems. Hopefully the +comments in the code are detailed enough to help people attempting +a port. +

+

DoneSunOS x86 +Contributed code! +Arthur Jones <aljones@lbl.gov>
+? +Philip Pokorny <ppokorny@mindspring.com>
+
+The word I hear is that this is working and done +
DoneHP-UX +Contributed code! +Thomas Wang <wang@cup.hp.com>
+Contributed code! +Mike Gleeson <mgleeson1@netscape.com> +
I hear that this code is checked in and working. Though, there is some +doubt - see bug +#17997 +
DoneAIX PPCContributed code! +Jim Dunn <jdunn@netscape.com>Philip K. Warren writes:
+ +We have gone through several releases of AIX without any problems. +
DoneIrixContributed code! +Jason Heirtzler <jasonh@m7.engr.sgi.com>
+
Jason has declared this done. Jason is no longer working at SGI and will +not be maintaining this code. There is some doubt as to whether or not this is +working for everyone - see bug +#10061. +Mike Shaver <shaver@mozilla.org> +is the interim maintainer until someone more suitable can be found. +
DoneBeOS x86Contributed code! +Duncan Wilcox <duncan@be.com>
+
+unix (yet another reuse of the Linux 86 code!)
+Duncan says this is all working. He did the code for old cfront style 'this' adjustment for others to use too! +
HELP!BeOS PPC--
DoneCompaq Tru64 UNIX (Digital UNIX)Contributed code! +Steve Streeter <streeter@zk3.dec.com>
+
Code passes the tests and is checked in.
WorkingNeutrio x86Contributed code! +Jerry L. Kirk <Jerry.Kirk@Nexwarecorp.com>
+
+Patches for xptc*_unixish_x86.cpp checked in. Waiting for verification that this is really finished. +
InvestigatingSCO UW7 and OSR5 +Investigating +J. Kean Johnston <jkj@sco.com>
+Investigating +Evan Hunt <evanh@sco.com>
+
Recent (Feb-2001) email from jkj@sco.com suggests that work will be occuring soon.
WorksNetBSD/m68kContributed code! +Dave Huang <khym@bga.com>
+
+Dave's changes are in the tree. Waiting for verification that it is really finished.
Partially WorkingNetBSD/arm32Investigating +Mike Pumford <mpumford@black-star.demon.co.uk> +Mike writes:
+I have started porting to the platform based on the code for Linux ARM. The +InvokeByIndex code works correctly when used with TestXPTCInvoke. I am +currently working on making TestXPC function correctly. +

+I am doing the porting work with egcs-1.1.2 on NetBSD 1.4P (NetBSD-current +snapshot from a couple of days ago). +

HELP!linux/ia64-bug 40950
HELP!All others!--
+ +

+ +Note: I've used the symbol (?) to +indicate people who have expressed an interest in possibly contributing code. +Just because these people are listed here does not mean that they have commited +themselves to do the work. If you would like to contribute then let me +know. Feel free to email these folks and offer to help or find out what's going +on. We're all in this together. + +

+ +


+Author: John Bandhauer <jband@netscape.com>
+Last modified: 3 February 2003 + + + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/tests/.cvsignore b/src/libs/xpcom18a4/xpcom/reflect/xptcall/tests/.cvsignore new file mode 100644 index 00000000..177fd905 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/tests/.cvsignore @@ -0,0 +1,2 @@ +Makefile +TestXPTCInvoke diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/tests/Makefile.in b/src/libs/xpcom18a4/xpcom/reflect/xptcall/tests/Makefile.in new file mode 100644 index 00000000..a1bf16ca --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/tests/Makefile.in @@ -0,0 +1,64 @@ +# +# ***** 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.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of 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 ***** + +DEPTH = ../../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = TestXPTC +SIMPLE_PROGRAMS = TestXPTCInvoke$(BIN_SUFFIX) +REQUIRES = xpcom \ + $(NULL) + +CPPSRCS = TestXPTCInvoke.cpp + +LIBS = \ + $(XPCOM_LIBS) \ + $(NSPR_LIBS) \ + $(NULL) + +include $(topsrcdir)/config/rules.mk + +# For _write(). +ifeq ($(OS_ARCH),BSD_OS) +OS_LIBS += -lgcc +endif + + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/tests/TestXPTCInvoke.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/tests/TestXPTCInvoke.cpp new file mode 100644 index 00000000..79e4bc08 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/tests/TestXPTCInvoke.cpp @@ -0,0 +1,1464 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Pierre Phaneuf + * Stuart Parmenter + * Chris Seawood + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Invoke tests xptcall. */ + +#include +#include "xptcall.h" +#include "prlong.h" +#include "prinrval.h" +#include "nsMemory.h" + +// forward declration +static int DoMultipleInheritenceTest(int rcExit); +static int DoMultipleInheritenceTest2(int rcExit); +static void DoSpeedTest(); + + +#include + +static char g_szDirect[16384]; +static char g_szInvoke[16384]; +static char *g_pszBuffer = NULL; +static void bufprintf(const char *pszFormat, ...) +{ + va_list va; + va_start(va, pszFormat); + vprintf(pszFormat, va); + va_end(va); + if (g_pszBuffer) + { + size_t cchBuf = strlen(g_pszBuffer); + ssize_t cbLeft = (ssize_t)sizeof(g_szDirect) - (ssize_t)cchBuf; + if (cbLeft > 0) + { + va_list va; + va_start(va, pszFormat); + vsnprintf(&g_pszBuffer[cchBuf], (size_t)cbLeft, pszFormat, va); + va_end(va); + } + } +} + +static void setbuffer(bool fDirect) +{ + g_pszBuffer = fDirect ? g_szDirect : g_szInvoke; + *g_pszBuffer = '\0'; +} + +static int comparebuffers(int rcExit) +{ + if (strcmp(g_szDirect, g_szInvoke) == 0) + return rcExit; + size_t offLine = 0; + unsigned iLine = 1; + for (size_t off = 0; ; off++) + { + char chDirect = g_szDirect[off]; + char chInvoke = g_szInvoke[off]; + if (chDirect == chInvoke) + { + if (!chDirect) + return rcExit; + if (chDirect == '\n') + { + offLine = off + 1; + iLine++; + } + } + else + { + size_t cchDirectLine = RTStrOffCharOrTerm(&g_szDirect[offLine], '\n'); + size_t cchInvokeLine = RTStrOffCharOrTerm(&g_szInvoke[offLine], '\n'); + printf("direct and invoke runs differs on line %u!\n", iLine); + printf("direct: %*.*s\n", (int)cchDirectLine, (int)cchDirectLine, &g_szDirect[offLine]); + printf("invoke: %*.*s\n", (int)cchInvokeLine, (int)cchInvokeLine, &g_szInvoke[offLine]); + + return 1; + } + + } + printf("direct and invoke runs differs!\n"); + return 1; +} + + +// {AAC1FB90-E099-11d2-984E-006008962422} +#define INVOKETESTTARGET_IID \ +{ 0xaac1fb90, 0xe099, 0x11d2, \ + { 0x98, 0x4e, 0x0, 0x60, 0x8, 0x96, 0x24, 0x22 } } + + +class InvokeTestTargetInterface : public nsISupports +{ +public: + NS_DEFINE_STATIC_IID_ACCESSOR(INVOKETESTTARGET_IID) + NS_IMETHOD AddTwoInts(PRInt32 p1, PRInt32 p2, PRInt32* retval) = 0; + NS_IMETHOD MultTwoInts(PRInt32 p1, PRInt32 p2, PRInt32* retval) = 0; + NS_IMETHOD AddTwoLLs(PRInt64 p1, PRInt64 p2, PRInt64* retval) = 0; + NS_IMETHOD MultTwoLLs(PRInt64 p1, PRInt64 p2, PRInt64* retval) = 0; + + NS_IMETHOD AddManyInts(PRInt32 p1, PRInt32 p2, PRInt32 p3, PRInt32 p4, + PRInt32 p5, PRInt32 p6, PRInt32 p7, PRInt32 p8, + PRInt32 p9, PRInt32 p10, PRInt32* retval) = 0; + + NS_IMETHOD AddTwoFloats(float p1, float p2, float* retval) = 0; + + NS_IMETHOD AddManyDoubles(double p1, double p2, double p3, double p4, + double p5, double p6, double p7, double p8, + double p9, double p10, double* retval) = 0; + + NS_IMETHOD AddManyFloats(float p1, float p2, float p3, float p4, + float p5, float p6, float p7, float p8, + float p9, float p10, float* retval) = 0; + + NS_IMETHOD AddManyManyFloats(float p1, float p2, float p3, float p4, + float p5, float p6, float p7, float p8, + float p9, float p10, float p11, float p12, + float p13, float p14, float p15, float p16, + float p17, float p18, float p19, float p20, + float *retval) = 0; + + NS_IMETHOD AddMixedInts(PRInt64 p1, PRInt32 p2, PRInt64 p3, PRInt32 p4, + PRInt32 p5, PRInt64 p6, PRInt32 p7, PRInt32 p8, + PRInt64 p9, PRInt32 p10, PRInt64* retval) = 0; + + NS_IMETHOD AddMixedInts2(PRInt32 p1, PRInt64 p2, PRInt32 p3, PRInt64 p4, + PRInt64 p5, PRInt32 p6, PRInt64 p7, PRInt64 p8, + PRInt32 p9, PRInt64 p10, PRInt64* retval) = 0; + + NS_IMETHOD AddMixedFloats(float p1, float p2, double p3, double p4, + float p5, float p6, double p7, double p8, + float p9, double p10, float p11, + double *retval) = 0; + + NS_IMETHOD PassTwoStrings(const char* s1, const char* s2, char** retval) = 0; + +}; + +class InvokeTestTarget : public InvokeTestTargetInterface +{ +public: + NS_DECL_ISUPPORTS + NS_IMETHOD AddTwoInts(PRInt32 p1, PRInt32 p2, PRInt32* retval); + NS_IMETHOD MultTwoInts(PRInt32 p1, PRInt32 p2, PRInt32* retval); + NS_IMETHOD AddTwoLLs(PRInt64 p1, PRInt64 p2, PRInt64* retval); + NS_IMETHOD MultTwoLLs(PRInt64 p1, PRInt64 p2, PRInt64* retval); + + NS_IMETHOD AddManyInts(PRInt32 p1, PRInt32 p2, PRInt32 p3, PRInt32 p4, + PRInt32 p5, PRInt32 p6, PRInt32 p7, PRInt32 p8, + PRInt32 p9, PRInt32 p10, PRInt32* retval); + + NS_IMETHOD AddTwoFloats(float p1, float p2, float* retval); + + NS_IMETHOD AddManyDoubles(double p1, double p2, double p3, double p4, + double p5, double p6, double p7, double p8, + double p9, double p10, double* retval); + + NS_IMETHOD AddManyFloats(float p1, float p2, float p3, float p4, + float p5, float p6, float p7, float p8, + float p9, float p10, float* retval); + + NS_IMETHOD AddMixedInts(PRInt64 p1, PRInt32 p2, PRInt64 p3, PRInt32 p4, + PRInt32 p5, PRInt64 p6, PRInt32 p7, PRInt32 p8, + PRInt64 p9, PRInt32 p10, PRInt64* retval); + + NS_IMETHOD AddMixedInts2(PRInt32 p1, PRInt64 p2, PRInt32 p3, PRInt64 p4, + PRInt64 p5, PRInt32 p6, PRInt64 p7, PRInt64 p8, + PRInt32 p9, PRInt64 p10, PRInt64* retval); + + NS_IMETHOD AddMixedFloats(float p1, float p2, double p3, double p4, + float p5, float p6, double p7, double p8, + float p9, double p10, float p11, + double *retval); + + NS_IMETHOD AddManyManyFloats(float p1, float p2, float p3, float p4, + float p5, float p6, float p7, float p8, + float p9, float p10, float p11, float p12, + float p13, float p14, float p15, float p16, + float p17, float p18, float p19, float p20, + float *retval); + + NS_IMETHOD PassTwoStrings(const char* s1, const char* s2, char** retval); + + InvokeTestTarget(); +}; + +NS_IMPL_ISUPPORTS1(InvokeTestTarget, InvokeTestTargetInterface) + +InvokeTestTarget::InvokeTestTarget() +{ + NS_ADDREF_THIS(); +} + +NS_IMETHODIMP +InvokeTestTarget::AddTwoInts(PRInt32 p1, PRInt32 p2, PRInt32* retval) +{ + *retval = p1 + p2; + return NS_OK; +} + +NS_IMETHODIMP +InvokeTestTarget::MultTwoInts(PRInt32 p1, PRInt32 p2, PRInt32* retval) +{ + *retval = p1 * p2; + return NS_OK; +} + +NS_IMETHODIMP +InvokeTestTarget::AddTwoLLs(PRInt64 p1, PRInt64 p2, PRInt64* retval) +{ + LL_ADD(*retval, p1, p2); + return NS_OK; +} + +NS_IMETHODIMP +InvokeTestTarget::MultTwoLLs(PRInt64 p1, PRInt64 p2, PRInt64* retval) +{ + LL_MUL(*retval, p1, p2); + return NS_OK; +} + +NS_IMETHODIMP +InvokeTestTarget::AddManyInts(PRInt32 p1, PRInt32 p2, PRInt32 p3, PRInt32 p4, + PRInt32 p5, PRInt32 p6, PRInt32 p7, PRInt32 p8, + PRInt32 p9, PRInt32 p10, PRInt32* retval) +{ +#ifdef DEBUG_TESTINVOKE + printf("%d, %d, %d, %d, %d, %d, %d, %d, %d, %d\n", + p1, p2, p3, p4, p5, p6, p7, p8, p9, p10); +#endif + *retval = p1 + p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9 + p10; + return NS_OK; +} + +NS_IMETHODIMP +InvokeTestTarget::AddTwoFloats(float p1, float p2, float *retval) +{ +#ifdef DEBUG_TESTINVOKE + printf("%f, %f\n", p1, p2); +#endif + *retval = p1 + p2; + return NS_OK; +} + +NS_IMETHODIMP +InvokeTestTarget::AddManyDoubles(double p1, double p2, double p3, double p4, + double p5, double p6, double p7, double p8, + double p9, double p10, double* retval) +{ +#ifdef DEBUG_TESTINVOKE + printf("%lf, %lf, %lf, %lf, %lf, %lf, %lf, %lf, %lf, %lf\n", + p1, p2, p3, p4, p5, p6, p7, p8, p9, p10); +#endif + *retval = p1 + p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9 + p10; + return NS_OK; +} + +NS_IMETHODIMP +InvokeTestTarget::AddManyFloats(float p1, float p2, float p3, float p4, + float p5, float p6, float p7, float p8, + float p9, float p10, float* retval) +{ +#ifdef DEBUG_TESTINVOKE + printf("%f, %f, %f, %f, %f, %f, %f, %f, %f, %f\n", + p1, p2, p3, p4, p5, p6, p7, p8, p9, p10); +#endif + *retval = p1 + p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9 + p10; + return NS_OK; +} + +NS_IMETHODIMP +InvokeTestTarget::AddMixedFloats(float p1, float p2, double p3, double p4, + float p5, float p6, double p7, double p8, + float p9, double p10, float p11, + double *retval) +{ +#ifdef DEBUG_TESTINVOKE + printf("%f, %f, %lf, %lf, %f, %f, %lf, %lf, %f, %lf, %f\n", + p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11); +#endif + *retval = p1 + p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9 + p10 + p11; + return NS_OK; +} + +NS_IMETHODIMP +InvokeTestTarget::AddManyManyFloats(float p1, float p2, float p3, float p4, + float p5, float p6, float p7, float p8, + float p9, float p10, float p11, float p12, + float p13, float p14, float p15, float p16, + float p17, float p18, float p19, float p20, + float *retval) +{ +#ifdef DEBUG_TESTINVOKE + printf("%f, %f, %f, %f, %f, %f, %f, %f, %f, %f, " + "%f, %f, %f, %f, %f, %f, %f, %f, %f, %f\n", + p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, + p11, p12, p13, p14, p15, p16, p17, p18, p19, p20); +#endif + *retval = p1 + p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9 + p10 + + p11 + p12 + p13 + p14 + p15 + p16 + p17 + p18 + p19 + p20; + return NS_OK; +} + +NS_IMETHODIMP +InvokeTestTarget::AddMixedInts(PRInt64 p1, PRInt32 p2, PRInt64 p3, PRInt32 p4, + PRInt32 p5, PRInt64 p6, PRInt32 p7, PRInt32 p8, + PRInt64 p9, PRInt32 p10, PRInt64* retval) +{ + *retval = p1 + p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9 + p10; + return NS_OK; +} + +NS_IMETHODIMP +InvokeTestTarget::AddMixedInts2(PRInt32 p1, PRInt64 p2, PRInt32 p3, PRInt64 p4, + PRInt64 p5, PRInt32 p6, PRInt64 p7, PRInt64 p8, + PRInt32 p9, PRInt64 p10, PRInt64* retval) +{ + *retval = p1 + p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9 + p10; + return NS_OK; +} + +NS_IMETHODIMP +InvokeTestTarget::PassTwoStrings(const char* s1, const char* s2, char** retval) +{ + const char milk[] = "milk"; + char *ret = (char*)nsMemory::Alloc(sizeof(milk)); + if (!ret) + return NS_ERROR_OUT_OF_MEMORY; + strncpy(ret, milk, sizeof(milk)); + printf("\t%s %s", s1, s2); + *retval = ret; + return NS_OK; +} + +int main() +{ + InvokeTestTarget *test = new InvokeTestTarget(); + + /* here we make the global 'check for alloc failure' checker happy */ + if(!test) + return 1; + + PRInt32 out, tmp32 = 0; + PRInt64 out64; + printf("calling direct:\n"); + setbuffer(true); + if(NS_SUCCEEDED(test->AddTwoInts(1,1,&out))) + bufprintf("\t1 + 1 = %d\n", out); + else + bufprintf("\tFAILED"); + PRInt64 one, two; + LL_I2L(one, 1); + LL_I2L(two, 2); + if(NS_SUCCEEDED(test->AddTwoLLs(one,one,&out64))) + { + LL_L2I(tmp32, out64); + bufprintf("\t1L + 1L = %d\n", (int)tmp32); + } + else + bufprintf("\tFAILED"); + if(NS_SUCCEEDED(test->MultTwoInts(2,2,&out))) + bufprintf("\t2 * 2 = %d\n", out); + else + bufprintf("\tFAILED"); + if(NS_SUCCEEDED(test->MultTwoLLs(two,two,&out64))) + { + LL_L2I(tmp32, out64); + bufprintf("\t2L * 2L = %d\n", (int)tmp32); + } + else + bufprintf("\tFAILED"); + + double outD; + float outF; + PRInt32 outI; + char *outS; + + if(NS_SUCCEEDED(test->AddManyInts(1,2,3,4,5,6,7,8,9,10,&outI))) + bufprintf("\t1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 = %d\n", outI); + else + bufprintf("\tFAILED"); + + if(NS_SUCCEEDED(test->AddTwoFloats(1,2,&outF))) + bufprintf("\t1 + 2 = %ff\n", (double)outF); + else + bufprintf("\tFAILED"); + + if(NS_SUCCEEDED(test->AddManyDoubles(1,2,3,4,5,6,7,8,9,10,&outD))) + bufprintf("\t1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 = %f\n", outD); + else + bufprintf("\tFAILED"); + + if(NS_SUCCEEDED(test->AddManyFloats(1,2,3,4,5,6,7,8,9,10,&outF))) + bufprintf("\t1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 = %ff\n", (double)outF); + else + bufprintf("\tFAILED"); + + if(NS_SUCCEEDED(test->AddManyManyFloats(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,&outF))) + bufprintf("\t1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + 16 + 17 + 18 + 19 + 20 = %ff\n", (double)outF); + else + bufprintf("\tFAILED"); + + if(NS_SUCCEEDED(test->AddMixedInts(1,2,3,4,5,6,7,8,9,10,&out64))) + { + LL_L2I(tmp32, out64); + bufprintf("\t1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 = %d\n", (int)tmp32); + } + else + bufprintf("\tFAILED"); + + if(NS_SUCCEEDED(test->AddMixedInts2(1,2,3,4,5,6,7,8,9,10,&out64))) + { + LL_L2I(tmp32, out64); + bufprintf("\t1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 = %d\n", (int)tmp32); + } + else + bufprintf("\tFAILED"); + + if(NS_SUCCEEDED(test->AddMixedFloats(1,2,3,4,5,6,7,8,9,10,11,&outD))) + bufprintf("\t1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 = %f\n", (double)outD); + else + bufprintf("\tFAILED"); + + if (NS_SUCCEEDED(test->PassTwoStrings("moo","cow",&outS))) { + bufprintf(" = %s\n", outS); + nsMemory::Free(outS); + } else + bufprintf("\tFAILED"); + + printf("calling via invoke:\n"); + setbuffer(false); + + nsXPTCVariant var[21]; + + var[0].val.i32 = 1; + var[0].type = nsXPTType::T_I32; + var[0].flags = 0; + + var[1].val.i32 = 1; + var[1].type = nsXPTType::T_I32; + var[1].flags = 0; + + var[2].val.i32 = 0; + var[2].type = nsXPTType::T_I32; + var[2].flags = nsXPTCVariant::PTR_IS_DATA; + var[2].ptr = &var[2].val.i32; + + if(NS_SUCCEEDED(XPTC_InvokeByIndex(test, 3, 3, var))) + bufprintf("\t1 + 1 = %d\n", var[2].val.i32); + else + bufprintf("\tFAILED"); + + LL_I2L(var[0].val.i64, 1); + var[0].type = nsXPTType::T_I64; + var[0].flags = 0; + + LL_I2L(var[1].val.i64, 1); + var[1].type = nsXPTType::T_I64; + var[1].flags = 0; + + LL_I2L(var[2].val.i64, 0); + var[2].type = nsXPTType::T_I64; + var[2].flags = nsXPTCVariant::PTR_IS_DATA; + var[2].ptr = &var[2].val.i64; + + if(NS_SUCCEEDED(XPTC_InvokeByIndex(test, 5, 3, var))) + bufprintf("\t1L + 1L = %d\n", (int)var[2].val.i64); + else + bufprintf("\tFAILED"); + + var[0].val.i32 = 2; + var[0].type = nsXPTType::T_I32; + var[0].flags = 0; + + var[1].val.i32 = 2; + var[1].type = nsXPTType::T_I32; + var[1].flags = 0; + + var[2].val.i32 = 0; + var[2].type = nsXPTType::T_I32; + var[2].flags = nsXPTCVariant::PTR_IS_DATA; + var[2].ptr = &var[2].val.i32; + + if(NS_SUCCEEDED(XPTC_InvokeByIndex(test, 4, 3, var))) + bufprintf("\t2 * 2 = %d\n", var[2].val.i32); + else + bufprintf("\tFAILED"); + + LL_I2L(var[0].val.i64,2); + var[0].type = nsXPTType::T_I64; + var[0].flags = 0; + + LL_I2L(var[1].val.i64,2); + var[1].type = nsXPTType::T_I64; + var[1].flags = 0; + + LL_I2L(var[2].val.i64,0); + var[2].type = nsXPTType::T_I64; + var[2].flags = nsXPTCVariant::PTR_IS_DATA; + var[2].ptr = &var[2].val.i64; + + if(NS_SUCCEEDED(XPTC_InvokeByIndex(test, 6, 3, var))) + bufprintf("\t2L * 2L = %d\n", (int)var[2].val.i64); + else + bufprintf("\tFAILED"); + + var[0].val.i32 = 1; + var[0].type = nsXPTType::T_I32; + var[0].flags = 0; + + var[1].val.i32 = 2; + var[1].type = nsXPTType::T_I32; + var[1].flags = 0; + + var[2].val.i32 = 3; + var[2].type = nsXPTType::T_I32; + var[2].flags = 0; + + var[3].val.i32 = 4; + var[3].type = nsXPTType::T_I32; + var[3].flags = 0; + + var[4].val.i32 = 5; + var[4].type = nsXPTType::T_I32; + var[4].flags = 0; + + var[5].val.i32 = 6; + var[5].type = nsXPTType::T_I32; + var[5].flags = 0; + + var[6].val.i32 = 7; + var[6].type = nsXPTType::T_I32; + var[6].flags = 0; + + var[7].val.i32 = 8; + var[7].type = nsXPTType::T_I32; + var[7].flags = 0; + + var[8].val.i32 = 9; + var[8].type = nsXPTType::T_I32; + var[8].flags = 0; + + var[9].val.i32 = 10; + var[9].type = nsXPTType::T_I32; + var[9].flags = 0; + + var[10].val.i32 = 0; + var[10].type = nsXPTType::T_I32; + var[10].flags = nsXPTCVariant::PTR_IS_DATA; + var[10].ptr = &var[10].val.i32; + + if(NS_SUCCEEDED(XPTC_InvokeByIndex(test, 7, 11, var))) + bufprintf("\t1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 = %d\n", + var[10].val.i32); + + var[0].val.f = 1.0f; + var[0].type = nsXPTType::T_FLOAT; + var[0].flags = 0; + + var[1].val.f = 2.0f; + var[1].type = nsXPTType::T_FLOAT; + var[1].flags = 0; + + var[2].val.f = 0.0f; + var[2].type = nsXPTType::T_FLOAT; + var[2].flags = nsXPTCVariant::PTR_IS_DATA; + var[2].ptr = &var[2].val.f; + + if(NS_SUCCEEDED(XPTC_InvokeByIndex(test, 8, 3, var))) + bufprintf("\t1 + 2 = %ff\n", + (double) var[2].val.f); + + + var[0].val.d = 1.0; + var[0].type = nsXPTType::T_DOUBLE; + var[0].flags = 0; + + var[1].val.d = 2.0; + var[1].type = nsXPTType::T_DOUBLE; + var[1].flags = 0; + + var[2].val.d = 3.0; + var[2].type = nsXPTType::T_DOUBLE; + var[2].flags = 0; + + var[3].val.d = 4.0; + var[3].type = nsXPTType::T_DOUBLE; + var[3].flags = 0; + + var[4].val.d = 5.0; + var[4].type = nsXPTType::T_DOUBLE; + var[4].flags = 0; + + var[5].val.d = 6.0; + var[5].type = nsXPTType::T_DOUBLE; + var[5].flags = 0; + + var[6].val.d = 7.0; + var[6].type = nsXPTType::T_DOUBLE; + var[6].flags = 0; + + var[7].val.d = 8.0; + var[7].type = nsXPTType::T_DOUBLE; + var[7].flags = 0; + + var[8].val.d = 9.0; + var[8].type = nsXPTType::T_DOUBLE; + var[8].flags = 0; + + var[9].val.d = 10.0; + var[9].type = nsXPTType::T_DOUBLE; + var[9].flags = 0; + + var[10].val.d = 0.0; + var[10].type = nsXPTType::T_DOUBLE; + var[10].flags = nsXPTCVariant::PTR_IS_DATA; + var[10].ptr = &var[10].val.d; + + if(NS_SUCCEEDED(XPTC_InvokeByIndex(test, 9, 11, var))) + bufprintf("\t1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 = %f\n", + var[10].val.d); + else + bufprintf("\tFAILED"); + + var[0].val.f = 1.0f; + var[0].type = nsXPTType::T_FLOAT; + var[0].flags = 0; + + var[1].val.f = 2.0f; + var[1].type = nsXPTType::T_FLOAT; + var[1].flags = 0; + + var[2].val.f = 3.0f; + var[2].type = nsXPTType::T_FLOAT; + var[2].flags = 0; + + var[3].val.f = 4.0f; + var[3].type = nsXPTType::T_FLOAT; + var[3].flags = 0; + + var[4].val.f = 5.0f; + var[4].type = nsXPTType::T_FLOAT; + var[4].flags = 0; + + var[5].val.f = 6.0f; + var[5].type = nsXPTType::T_FLOAT; + var[5].flags = 0; + + var[6].val.f = 7.0f; + var[6].type = nsXPTType::T_FLOAT; + var[6].flags = 0; + + var[7].val.f = 8.0f; + var[7].type = nsXPTType::T_FLOAT; + var[7].flags = 0; + + var[8].val.f = 9.0f; + var[8].type = nsXPTType::T_FLOAT; + var[8].flags = 0; + + var[9].val.f = 10.0f; + var[9].type = nsXPTType::T_FLOAT; + var[9].flags = 0; + + var[10].val.f = 0.0f; + var[10].type = nsXPTType::T_FLOAT; + var[10].flags = nsXPTCVariant::PTR_IS_DATA; + var[10].ptr = &var[10].val.f; + + if(NS_SUCCEEDED(XPTC_InvokeByIndex(test, 10, 11, var))) + bufprintf("\t1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 = %ff\n", + (double) var[10].val.f); + else + bufprintf("\tFAILED"); + + var[0].val.f = 1.0f; + var[0].type = nsXPTType::T_FLOAT; + var[0].flags = 0; + + var[1].val.f = 2.0f; + var[1].type = nsXPTType::T_FLOAT; + var[1].flags = 0; + + var[2].val.f = 3.0f; + var[2].type = nsXPTType::T_FLOAT; + var[2].flags = 0; + + var[3].val.f = 4.0f; + var[3].type = nsXPTType::T_FLOAT; + var[3].flags = 0; + + var[4].val.f = 5.0f; + var[4].type = nsXPTType::T_FLOAT; + var[4].flags = 0; + + var[5].val.f = 6.0f; + var[5].type = nsXPTType::T_FLOAT; + var[5].flags = 0; + + var[6].val.f = 7.0f; + var[6].type = nsXPTType::T_FLOAT; + var[6].flags = 0; + + var[7].val.f = 8.0f; + var[7].type = nsXPTType::T_FLOAT; + var[7].flags = 0; + + var[8].val.f = 9.0f; + var[8].type = nsXPTType::T_FLOAT; + var[8].flags = 0; + + var[9].val.f = 10.0f; + var[9].type = nsXPTType::T_FLOAT; + var[9].flags = 0; + + var[10].val.f = 11.0f; + var[10].type = nsXPTType::T_FLOAT; + var[10].flags = 0; + + var[11].val.f = 12.0f; + var[11].type = nsXPTType::T_FLOAT; + var[11].flags = 0; + + var[12].val.f = 13.0f; + var[12].type = nsXPTType::T_FLOAT; + var[12].flags = 0; + + var[13].val.f = 14.0f; + var[13].type = nsXPTType::T_FLOAT; + var[13].flags = 0; + + var[14].val.f = 15.0f; + var[14].type = nsXPTType::T_FLOAT; + var[14].flags = 0; + + var[15].val.f = 16.0f; + var[15].type = nsXPTType::T_FLOAT; + var[15].flags = 0; + + var[16].val.f = 17.0f; + var[16].type = nsXPTType::T_FLOAT; + var[16].flags = 0; + + var[17].val.f = 18.0f; + var[17].type = nsXPTType::T_FLOAT; + var[17].flags = 0; + + var[18].val.f = 19.0f; + var[18].type = nsXPTType::T_FLOAT; + var[18].flags = 0; + + var[19].val.f = 20.0f; + var[19].type = nsXPTType::T_FLOAT; + var[19].flags = 0; + + var[20].val.f = 0.0f; + var[20].type = nsXPTType::T_FLOAT; + var[20].flags = nsXPTCVariant::PTR_IS_DATA; + var[20].ptr = &var[20].val.f; + + if(NS_SUCCEEDED(XPTC_InvokeByIndex(test, 11, 21, var))) + bufprintf("\t1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + 16 + 17 + 18 + 19 + 20 = %ff\n", + (double) var[20].val.f); + + var[0].val.i64 = 1; + var[0].type = nsXPTType::T_I64; + var[0].flags = 0; + + var[1].val.i32 = 2; + var[1].type = nsXPTType::T_I32; + var[1].flags = 0; + + var[2].val.i64 = 3; + var[2].type = nsXPTType::T_I64; + var[2].flags = 0; + + var[3].val.i32 = 4; + var[3].type = nsXPTType::T_I32; + var[3].flags = 0; + + var[4].val.i32 = 5; + var[4].type = nsXPTType::T_I32; + var[4].flags = 0; + + var[5].val.i64 = 6; + var[5].type = nsXPTType::T_I64; + var[5].flags = 0; + + var[6].val.i32 = 7; + var[6].type = nsXPTType::T_I32; + var[6].flags = 0; + + var[7].val.i32 = 8; + var[7].type = nsXPTType::T_I32; + var[7].flags = 0; + + var[8].val.i64 = 9; + var[8].type = nsXPTType::T_I64; + var[8].flags = 0; + + var[9].val.i32 = 10; + var[9].type = nsXPTType::T_I32; + var[9].flags = 0; + + var[10].val.i64 = 0; + var[10].type = nsXPTType::T_I64; + var[10].flags = nsXPTCVariant::PTR_IS_DATA; + var[10].ptr = &var[10].val.i64; + + if(NS_SUCCEEDED(XPTC_InvokeByIndex(test, 12, 11, var))) + bufprintf("\t1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 = %d\n", + (int)var[10].val.i64); + else + bufprintf("\tFAILED"); + + var[0].val.i32 = 1; + var[0].type = nsXPTType::T_I32; + var[0].flags = 0; + + var[1].val.i64 = 2; + var[1].type = nsXPTType::T_I64; + var[1].flags = 0; + + var[2].val.i32 = 3; + var[2].type = nsXPTType::T_I32; + var[2].flags = 0; + + var[3].val.i64 = 4; + var[3].type = nsXPTType::T_I64; + var[3].flags = 0; + + var[4].val.i64 = 5; + var[4].type = nsXPTType::T_I64; + var[4].flags = 0; + + var[5].val.i32 = 6; + var[5].type = nsXPTType::T_I32; + var[5].flags = 0; + + var[6].val.i64 = 7; + var[6].type = nsXPTType::T_I64; + var[6].flags = 0; + + var[7].val.i64 = 8; + var[7].type = nsXPTType::T_I64; + var[7].flags = 0; + + var[8].val.i32 = 9; + var[8].type = nsXPTType::T_I32; + var[8].flags = 0; + + var[9].val.i64 = 10; + var[9].type = nsXPTType::T_I64; + var[9].flags = 0; + + var[10].val.i64 = 0; + var[10].type = nsXPTType::T_I64; + var[10].flags = nsXPTCVariant::PTR_IS_DATA; + var[10].ptr = &var[10].val.i64; + + if(NS_SUCCEEDED(XPTC_InvokeByIndex(test, 13, 11, var))) + bufprintf("\t1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 = %d\n", + (int)var[10].val.i64); + else + bufprintf("\tFAILED"); + + var[0].val.f = 1.0f; + var[0].type = nsXPTType::T_FLOAT; + var[0].flags = 0; + + var[1].val.f = 2.0f; + var[1].type = nsXPTType::T_FLOAT; + var[1].flags = 0; + + var[2].val.d = 3.0; + var[2].type = nsXPTType::T_DOUBLE; + var[2].flags = 0; + + var[3].val.d = 4.0; + var[3].type = nsXPTType::T_DOUBLE; + var[3].flags = 0; + + var[4].val.f = 5.0f; + var[4].type = nsXPTType::T_FLOAT; + var[4].flags = 0; + + var[5].val.f = 6.0f; + var[5].type = nsXPTType::T_FLOAT; + var[5].flags = 0; + + var[6].val.d = 7.0; + var[6].type = nsXPTType::T_DOUBLE; + var[6].flags = 0; + + var[7].val.d = 8.0; + var[7].type = nsXPTType::T_DOUBLE; + var[7].flags = 0; + + var[8].val.f = 9.0f; + var[8].type = nsXPTType::T_FLOAT; + var[8].flags = 0; + + var[9].val.d = 10.0; + var[9].type = nsXPTType::T_DOUBLE; + var[9].flags = 0; + + var[10].val.f = 11.0f; + var[10].type = nsXPTType::T_FLOAT; + var[10].flags = 0; + + var[11].val.d = 0.0; + var[11].type = nsXPTType::T_DOUBLE; + var[11].flags = nsXPTCVariant::PTR_IS_DATA; + var[11].ptr = &var[11].val.d; + + if(NS_SUCCEEDED(XPTC_InvokeByIndex(test, 14, 12, var))) + bufprintf("\t1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 = %f\n", + var[11].val.d); + else + bufprintf("\tFAILED"); + + var[0].val.p = (void*)"moo"; + var[0].type = nsXPTType::T_CHAR_STR; + var[0].flags = 0; + + var[1].val.p = (void*)"cow"; + var[1].type = nsXPTType::T_CHAR_STR; + var[1].flags = 0; + + var[2].val.p = 0; + var[2].type = nsXPTType::T_CHAR_STR; + var[2].flags = nsXPTCVariant::PTR_IS_DATA; + var[2].ptr = &var[2].val.p; + + if(NS_SUCCEEDED(XPTC_InvokeByIndex(test, 15, 3, var))) + { + bufprintf(" = %s\n", var[2].val.p); + nsMemory::Free(var[2].val.p); + } + else + bufprintf("\tFAILED"); + int rcExit = comparebuffers(0); + + rcExit = DoMultipleInheritenceTest(rcExit); + rcExit = DoMultipleInheritenceTest2(rcExit); + // Disabled by default - takes too much time on slow machines + //DoSpeedTest(); + + NS_RELEASE(test); + + return rcExit; +} + +/***************************************************************************/ +/***************************************************************************/ +/***************************************************************************/ + +// {491C65A0-3317-11d3-9885-006008962422} +#define FOO_IID \ +{ 0x491c65a0, 0x3317, 0x11d3, \ + { 0x98, 0x85, 0x0, 0x60, 0x8, 0x96, 0x24, 0x22 } } + +// {491C65A1-3317-11d3-9885-006008962422} +#define BAR_IID \ +{ 0x491c65a1, 0x3317, 0x11d3, \ + { 0x98, 0x85, 0x0, 0x60, 0x8, 0x96, 0x24, 0x22 } } + +/***************************/ + +class nsIFoo : public nsISupports +{ +public: + NS_DEFINE_STATIC_IID_ACCESSOR(FOO_IID) + NS_IMETHOD FooMethod1(PRInt32 i) = 0; + NS_IMETHOD FooMethod2(PRInt32 i) = 0; +}; + +class nsIBar : public nsISupports +{ +public: + NS_DEFINE_STATIC_IID_ACCESSOR(BAR_IID) + NS_IMETHOD BarMethod1(PRInt32 i) = 0; + NS_IMETHOD BarMethod2(PRInt32 i) = 0; +}; + +/***************************/ + +class FooImpl : public nsIFoo +{ +public: + NS_IMETHOD FooMethod1(PRInt32 i); + NS_IMETHOD FooMethod2(PRInt32 i); + + FooImpl(); + +protected: + ~FooImpl() {} + +public: + virtual const char* ImplName() = 0; + + int SomeData1; + int SomeData2; + const char* Name; +}; + +class BarImpl : public nsIBar +{ +public: + NS_IMETHOD BarMethod1(PRInt32 i); + NS_IMETHOD BarMethod2(PRInt32 i); + + BarImpl(); + +protected: + ~BarImpl() {} + +public: + virtual const char * ImplName() = 0; + + int SomeData1; + int SomeData2; + const char* Name; +}; + +/***************************/ + +FooImpl::FooImpl() : Name("FooImpl") +{ +} + +NS_IMETHODIMP FooImpl::FooMethod1(PRInt32 i) +{ + bufprintf("\tFooImpl::FooMethod1 called with i == %d, %s part of a %s\n", + i, Name, ImplName()); + return NS_OK; +} + +NS_IMETHODIMP FooImpl::FooMethod2(PRInt32 i) +{ + bufprintf("\tFooImpl::FooMethod2 called with i == %d, %s part of a %s\n", + i, Name, ImplName()); + return NS_OK; +} + +/***************************/ + +BarImpl::BarImpl() : Name("BarImpl") +{ +} + +NS_IMETHODIMP BarImpl::BarMethod1(PRInt32 i) +{ + bufprintf("\tBarImpl::BarMethod1 called with i == %d, %s part of a %s\n", + i, Name, ImplName()); + return NS_OK; +} + +NS_IMETHODIMP BarImpl::BarMethod2(PRInt32 i) +{ + bufprintf("\tBarImpl::BarMethod2 called with i == %d, %s part of a %s\n", + i, Name, ImplName()); + return NS_OK; +} + +/***************************/ + +class FooBarImpl : public FooImpl, public BarImpl +{ +public: + NS_DECL_ISUPPORTS + + const char* ImplName(); + + FooBarImpl(); + +private: + ~FooBarImpl() {} + +public: + const char* MyName; +}; + +FooBarImpl::FooBarImpl() : MyName("FooBarImpl") +{ + NS_ADDREF_THIS(); +} + +const char* FooBarImpl::ImplName() +{ + return MyName; +} + +NS_IMETHODIMP +FooBarImpl::QueryInterface(REFNSIID aIID, void** aInstancePtr) +{ + if (NULL == aInstancePtr) { + return NS_ERROR_NULL_POINTER; + } + + *aInstancePtr = NULL; + + + if (aIID.Equals(NS_GET_IID(nsIFoo))) { + *aInstancePtr = (void*) NS_STATIC_CAST(nsIFoo*,this); + NS_ADDREF_THIS(); + return NS_OK; + } + if (aIID.Equals(NS_GET_IID(nsIBar))) { + *aInstancePtr = (void*) NS_STATIC_CAST(nsIBar*,this); + NS_ADDREF_THIS(); + return NS_OK; + } + + if (aIID.Equals(NS_GET_IID(nsISupports))) { + *aInstancePtr = (void*) NS_STATIC_CAST(nsISupports*, + NS_STATIC_CAST(nsIFoo*,this)); + NS_ADDREF_THIS(); + return NS_OK; + } + return NS_NOINTERFACE; +} + +NS_IMPL_ADDREF(FooBarImpl) +NS_IMPL_RELEASE(FooBarImpl) + + +static int DoMultipleInheritenceTest(int rcExit) +{ + FooBarImpl* impl = new FooBarImpl(); + if(!impl) + return 1; + + nsIFoo* foo; + nsIBar* bar; + + nsXPTCVariant var[1]; + + printf("\n"); + if(NS_SUCCEEDED(impl->QueryInterface(NS_GET_IID(nsIFoo), (void**)&foo)) && + NS_SUCCEEDED(impl->QueryInterface(NS_GET_IID(nsIBar), (void**)&bar))) + { + printf("impl == %p\n", impl); + printf("foo == %p\n", foo); + printf("bar == %p\n", bar); + + printf("Calling Foo...\n"); + printf("direct calls:\n"); + setbuffer(true); + foo->FooMethod1(1); + foo->FooMethod2(2); + + printf("invoke calls:\n"); + setbuffer(false); + var[0].val.i32 = 1; + var[0].type = nsXPTType::T_I32; + var[0].flags = 0; + XPTC_InvokeByIndex(foo, 3, 1, var); + + var[0].val.i32 = 2; + var[0].type = nsXPTType::T_I32; + var[0].flags = 0; + XPTC_InvokeByIndex(foo, 4, 1, var); + + rcExit = comparebuffers(rcExit); + printf("\n"); + + printf("Calling Bar...\n"); + printf("direct calls:\n"); + setbuffer(true); + bar->BarMethod1(1); + bar->BarMethod2(2); + + printf("invoke calls:\n"); + setbuffer(false); + var[0].val.i32 = 1; + var[0].type = nsXPTType::T_I32; + var[0].flags = 0; + XPTC_InvokeByIndex(bar, 3, 1, var); + + var[0].val.i32 = 2; + var[0].type = nsXPTType::T_I32; + var[0].flags = 0; + XPTC_InvokeByIndex(bar, 4, 1, var); + + rcExit = comparebuffers(rcExit); + printf("\n"); + + NS_RELEASE(foo); + NS_RELEASE(bar); + } + else + rcExit = 1; + NS_RELEASE(impl); + return rcExit; +} +/***************************************************************************/ +/***************************************************************************/ +/***************************************************************************/ +/* This is a variation on the theme submitted by duncan@be.com (Duncan Wilcox). +* He was seeing the other test work and this test not work. They should both +* Work on any given platform +*/ + +class nsIFoo2 : public nsISupports +{ +public: + NS_IMETHOD FooMethod1(PRInt32 i) = 0; + NS_IMETHOD FooMethod2(PRInt32 i) = 0; +}; + +class nsIBar2 : public nsISupports +{ +public: + NS_IMETHOD BarMethod1(PRInt32 i) = 0; + NS_IMETHOD BarMethod2(PRInt32 i) = 0; +}; + +class FooBarImpl2 : public nsIFoo2, public nsIBar2 +{ +public: + // Foo interface + NS_IMETHOD FooMethod1(PRInt32 i); + NS_IMETHOD FooMethod2(PRInt32 i); + + // Bar interface + NS_IMETHOD BarMethod1(PRInt32 i); + NS_IMETHOD BarMethod2(PRInt32 i); + + NS_DECL_ISUPPORTS + + FooBarImpl2(); + +private: + ~FooBarImpl2() {} + +public: + PRInt32 value; +}; + +FooBarImpl2::FooBarImpl2() : value(0x12345678) +{ + NS_ADDREF_THIS(); +} + +NS_IMETHODIMP FooBarImpl2::FooMethod1(PRInt32 i) +{ + bufprintf("\tFooBarImpl2::FooMethod1 called with i == %d, local value = %x\n", + i, value); + return NS_OK; +} + +NS_IMETHODIMP FooBarImpl2::FooMethod2(PRInt32 i) +{ + bufprintf("\tFooBarImpl2::FooMethod2 called with i == %d, local value = %x\n", + i, value); + return NS_OK; +} + +NS_IMETHODIMP FooBarImpl2::BarMethod1(PRInt32 i) +{ + bufprintf("\tFooBarImpl2::BarMethod1 called with i == %d, local value = %x\n", + i, value); + return NS_OK; +} + +NS_IMETHODIMP FooBarImpl2::BarMethod2(PRInt32 i) +{ + bufprintf("\tFooBarImpl2::BarMethod2 called with i == %d, local value = %x\n", + i, value); + return NS_OK; +} + +NS_IMETHODIMP +FooBarImpl2::QueryInterface(REFNSIID aIID, void** aInstancePtr) +{ + if (NULL == aInstancePtr) { + return NS_ERROR_NULL_POINTER; + } + + *aInstancePtr = NULL; + + + if (aIID.Equals(NS_GET_IID(nsIFoo))) { + *aInstancePtr = (void*) NS_STATIC_CAST(nsIFoo2*,this); + NS_ADDREF_THIS(); + return NS_OK; + } + if (aIID.Equals(NS_GET_IID(nsIBar))) { + *aInstancePtr = (void*) NS_STATIC_CAST(nsIBar2*,this); + NS_ADDREF_THIS(); + return NS_OK; + } + + if (aIID.Equals(NS_GET_IID(nsISupports))) { + *aInstancePtr = (void*) NS_STATIC_CAST(nsISupports*, + NS_STATIC_CAST(nsIFoo2*,this)); + NS_ADDREF_THIS(); + return NS_OK; + } + return NS_NOINTERFACE; +} + +NS_IMPL_ADDREF(FooBarImpl2) +NS_IMPL_RELEASE(FooBarImpl2) + +static int DoMultipleInheritenceTest2(int rcExit) +{ + FooBarImpl2* impl = new FooBarImpl2(); + if(!impl) + return 1; + + nsIFoo2* foo; + nsIBar2* bar; + + nsXPTCVariant var[1]; + + printf("\n"); + if(NS_SUCCEEDED(impl->QueryInterface(NS_GET_IID(nsIFoo), (void**)&foo)) && + NS_SUCCEEDED(impl->QueryInterface(NS_GET_IID(nsIBar), (void**)&bar))) + { + printf("impl == %p\n", impl); + printf("foo == %p\n", foo); + printf("bar == %p\n", bar); + + printf("Calling Foo...\n"); + printf("direct calls:\n"); + setbuffer(true); + foo->FooMethod1(1); + foo->FooMethod2(2); + + printf("invoke calls:\n"); + setbuffer(false); + var[0].val.i32 = 1; + var[0].type = nsXPTType::T_I32; + var[0].flags = 0; + XPTC_InvokeByIndex(foo, 3, 1, var); + + var[0].val.i32 = 2; + var[0].type = nsXPTType::T_I32; + var[0].flags = 0; + XPTC_InvokeByIndex(foo, 4, 1, var); + + rcExit = comparebuffers(rcExit); + printf("\n"); + + printf("Calling Bar...\n"); + printf("direct calls:\n"); + setbuffer(true); + bar->BarMethod1(1); + bar->BarMethod2(2); + + printf("invoke calls:\n"); + setbuffer(false); + var[0].val.i32 = 1; + var[0].type = nsXPTType::T_I32; + var[0].flags = 0; + XPTC_InvokeByIndex(bar, 3, 1, var); + + var[0].val.i32 = 2; + var[0].type = nsXPTType::T_I32; + var[0].flags = 0; + XPTC_InvokeByIndex(bar, 4, 1, var); + + rcExit = comparebuffers(rcExit); + printf("\n"); + + NS_RELEASE(foo); + NS_RELEASE(bar); + } + else + rcExit = 1; + NS_RELEASE(impl); + return rcExit; +} + +static void DoSpeedTest() +{ + InvokeTestTarget *test = new InvokeTestTarget(); + + nsXPTCVariant var[3]; + + var[0].val.i32 = 1; + var[0].type = nsXPTType::T_I32; + var[0].flags = 0; + + var[1].val.i32 = 1; + var[1].type = nsXPTType::T_I32; + var[1].flags = 0; + + var[2].val.i32 = 0; + var[2].type = nsXPTType::T_I32; + var[2].flags = nsXPTCVariant::PTR_IS_DATA; + var[2].ptr = &var[2].val.i32; + + PRInt32 in1 = 1; + PRInt32 in2 = 1; + PRInt32 out; + + // Crank this number down if your platform is slow :) + static const int count = 100000000; + int i; + PRIntervalTime start; + PRIntervalTime interval_direct; + PRIntervalTime interval_invoke; + + printf("Speed test...\n\n"); + printf("Doing %d direct call iterations...\n", count); + start = PR_IntervalNow(); + for(i = count; i; i--) + (void)test->AddTwoInts(in1, in2, &out); + interval_direct = PR_IntervalNow() - start; + + printf("Doing %d invoked call iterations...\n", count); + start = PR_IntervalNow(); + for(i = count; i; i--) + (void)XPTC_InvokeByIndex(test, 3, 3, var); + interval_invoke = PR_IntervalNow() - start; + + printf(" direct took %0.2f seconds\n", + (double)interval_direct/(double)PR_TicksPerSecond()); + printf(" invoke took %0.2f seconds\n", + (double)interval_invoke/(double)PR_TicksPerSecond()); + printf(" So, invoke overhead was ~ %0.2f seconds (~ %0.0f%%)\n", + (double)(interval_invoke-interval_direct)/(double)PR_TicksPerSecond(), + (double)(interval_invoke-interval_direct)/(double)interval_invoke*100); +} diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptinfo/.cvsignore b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptinfo/Makefile.in b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/Makefile.in new file mode 100644 index 00000000..d7e3b9c8 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/Makefile.in @@ -0,0 +1,49 @@ +# +# ***** 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.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1999 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of 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 ***** + +DEPTH = ../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = xpcom +DIRS = public src + +include $(topsrcdir)/config/rules.mk + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptinfo/public/.cvsignore b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/public/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/public/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptinfo/public/Makefile.in b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/public/Makefile.in new file mode 100644 index 00000000..dbf13d8b --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/public/Makefile.in @@ -0,0 +1,66 @@ +# +# ***** 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.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1999 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of 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 ***** + +DEPTH = ../../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = xpcom + +XPIDL_MODULE = xpcom_xpti + +GRE_MODULE = 1 + +EXPORTS = \ + xptinfo.h \ + $(NULL) + +XPIDLSRCS = \ + nsIInterfaceInfo.idl \ + nsIInterfaceInfoManager.idl \ + nsIXPTLoader.idl \ + $(NULL) + +EXPORTS := $(addprefix $(srcdir)/, $(EXPORTS)) + +include $(topsrcdir)/config/rules.mk + +CFLAGS += -DEXPORT_XPCI_API + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptinfo/public/nsIInterfaceInfo.idl b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/public/nsIInterfaceInfo.idl new file mode 100644 index 00000000..f77dbcfc --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/public/nsIInterfaceInfo.idl @@ -0,0 +1,137 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* The nsIInterfaceInfo public declaration. */ + + +#include "nsISupports.idl" + +// forward declaration of non-XPCOM types + +[ptr] native nsXPTMethodInfoPtr(nsXPTMethodInfo); +[ptr] native nsXPTConstantPtr(nsXPTConstant); +[ptr] native nsXPTParamInfoPtr(nsXPTParamInfo); + native nsXPTType(nsXPTType); + +// We bend the rules to do a [shared] nsIID (but this is never scriptable) +[ptr] native nsIIDPtrShared(nsIID); + +%{C++ +class nsXPTMethodInfo; +class nsXPTConstant; +class nsXPTParamInfo; +class nsXPTType; +%} + +/* this is NOT intended to be scriptable */ +[uuid(215DBE04-94A7-11d2-BA58-00805F8A5DD7)] +interface nsIInterfaceInfo : nsISupports +{ + readonly attribute string name; + readonly attribute nsIIDPtr InterfaceIID; + + PRBool isScriptable(); + + readonly attribute nsIInterfaceInfo parent; + + /** + * These include counts for parent (and all ancestors). + */ + readonly attribute PRUint16 methodCount; + readonly attribute PRUint16 constantCount; + + /** + * These include methods and constants for parent (and all ancestors). + * + * These do *not* make copies ***explicit bending of XPCOM rules***. + */ + + void getMethodInfo(in PRUint16 index, + [shared, retval] out nsXPTMethodInfoPtr info); + + void getMethodInfoForName(in string methodName, out PRUint16 index, + [shared, retval] out nsXPTMethodInfoPtr info); + + void getConstant(in PRUint16 index, + [shared, retval] out nsXPTConstantPtr constant); + + + /** + * Get the interface information or iid associated with a param of some + * method in this interface. + */ + + nsIInterfaceInfo getInfoForParam(in PRUint16 methodIndex, + [const] in nsXPTParamInfoPtr param); + + nsIIDPtr getIIDForParam(in PRUint16 methodIndex, + [const] in nsXPTParamInfoPtr param); + + + /** + * These do *not* make copies ***explicit bending of XPCOM rules***. + */ + + nsXPTType getTypeForParam(in PRUint16 methodIndex, + [const] in nsXPTParamInfoPtr param, + in PRUint16 dimension); + + PRUint8 getSizeIsArgNumberForParam(in PRUint16 methodIndex, + [const] in nsXPTParamInfoPtr param, + in PRUint16 dimension); + + PRUint8 getLengthIsArgNumberForParam(in PRUint16 methodIndex, + [const] in nsXPTParamInfoPtr param, + in PRUint16 dimension); + + PRUint8 getInterfaceIsArgNumberForParam(in PRUint16 methodIndex, + [const] in nsXPTParamInfoPtr param); + + PRBool isIID(in nsIIDPtr IID); + + void getNameShared([shared,retval] out string name); + void getIIDShared([shared,retval] out nsIIDPtrShared iid); + + PRBool isFunction(); + + PRBool hasAncestor(in nsIIDPtr iid); + + [notxpcom] nsresult getIIDForParamNoAlloc(in PRUint16 methodIndex, + [const] in nsXPTParamInfoPtr param, + out nsIID iid); +}; + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptinfo/public/nsIInterfaceInfoManager.idl b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/public/nsIInterfaceInfoManager.idl new file mode 100644 index 00000000..48277691 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/public/nsIInterfaceInfoManager.idl @@ -0,0 +1,85 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* The nsIInterfaceInfoManager public declaration. */ + + +#include "nsISupports.idl" +#include "nsIInterfaceInfo.idl" +#include "nsIEnumerator.idl" +#include "nsISimpleEnumerator.idl" + +/* this is NOT intended to be scriptable */ +[uuid(8B161900-BE2B-11d2-9831-006008962422)] +interface nsIInterfaceInfoManager : nsISupports +{ + nsIInterfaceInfo getInfoForIID(in nsIIDPtr iid); + nsIInterfaceInfo getInfoForName(in string name); + + nsIIDPtr getIIDForName(in string name); + string getNameForIID(in nsIIDPtr iid); + + nsIEnumerator enumerateInterfaces(); + + void autoRegisterInterfaces(); + + nsIEnumerator enumerateInterfacesWhoseNamesStartWith(in string prefix); +}; + +[uuid(0ee22850-bc6a-11d5-9134-0010a4e73d9a)] +interface nsIInterfaceInfoSuperManager : nsIInterfaceInfoManager +{ + void addAdditionalManager(in nsIInterfaceInfoManager manager); + void removeAdditionalManager(in nsIInterfaceInfoManager manager); + + PRBool hasAdditionalManagers(); + nsISimpleEnumerator enumerateAdditionalManagers(); +}; + +%{C++ +#define NS_INTERFACEINFOMANAGER_SERVICE_CLASSNAME \ + "Interface Information Manager Service" + +#define NS_INTERFACEINFOMANAGER_SERVICE_CID \ + { /* 13bef784-f8e0-4f96-85c1-09f9ef4f9a19 */ \ + 0x13bef784, 0xf8e0, 0x4f96, \ + {0x85, 0xc1, 0x09, 0xf9, 0xef, 0x4f, 0x9a, 0x19} } + +#define NS_INTERFACEINFOMANAGER_SERVICE_CONTRACTID \ + "@mozilla.org/xpti/interfaceinfomanager-service;1" +%} + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptinfo/public/nsIXPTLoader.idl b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/public/nsIXPTLoader.idl new file mode 100644 index 00000000..8918daa3 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/public/nsIXPTLoader.idl @@ -0,0 +1,100 @@ +/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 the external XPT loader interface. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corp. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * John Bandhauer + * Alec Flett + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsISupports.idl" +#include "nsILocalFile.idl" +#include "nsIInputStream.idl" + +/** + * Implement nsIXPTLoaderSink if you want to enumerate the entries in + * an XPT archive of some kind + */ +[scriptable, uuid(6E48C500-8682-4730-ADD6-7DB693B9E7BA)] +interface nsIXPTLoaderSink : nsISupports { + + /** + * called by the loader for each entry in the archive + * @param itemName the name of this particular item in the archive + * @param index the index of the item inthe archive + * @param stream contains the contents of the xpt file + */ + void foundEntry(in string itemName, + in long index, + in nsIInputStream xptData); +}; + +/** + * The XPT loader interface: implemented by a loader to grab an input + * stream which will be consumed by the interface loader. + */ +[scriptable, uuid(368A15D9-17A9-4c2b-AC3D-A35B3A22B876)] +interface nsIXPTLoader : nsISupports { + /** + * enumerate entries in the given archive + * for each entry found, the loader will call the sink's + * foundEntry() method with the appropriate information and a + * stream that the consumer can read from + * @param file the file to read from + * @param sink an object which will be called with each file found + * in the file + */ + void enumerateEntries(in nsILocalFile file, + in nsIXPTLoaderSink sink ); + + /** + * Load a specific entry from the archive + * @param file the file to read from + * @param name the name of the xpt within the file + * @return an input stream that will read the raw xpt data from + * the file + */ + nsIInputStream loadEntry(in nsILocalFile file, + in string name); +}; + + +%{C++ + +// the first part of the contractID for any loader +// append the type of loader that you need, such as "zip" +#define NS_XPTLOADER_CONTRACTID_PREFIX \ + "@mozilla.org/xptinfo/loader;1&type=" + +%} diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptinfo/public/xptinfo.h b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/public/xptinfo.h new file mode 100644 index 00000000..076482a6 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/public/xptinfo.h @@ -0,0 +1,281 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* XPTI_PUBLIC_API and XPTI_GetInterfaceInfoManager declarations. */ + +#ifndef xptiinfo_h___ +#define xptiinfo_h___ + +#include "prtypes.h" +#include "xpt_struct.h" + +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +#define XPTI_GetInterfaceInfoManager VBoxNsxpXPTI_GetInterfaceInfoManager +#define XPTI_FreeInterfaceInfoManager VBoxNsxpXPTI_FreeInterfaceInfoManager +#endif /* VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + +/* + * The linkage of XPTI API functions differs depending on whether the file is + * used within the XPTI library or not. Any source file within the XPTI + * library should define EXPORT_XPTI_API whereas any client of the library + * should not. + */ +#ifdef EXPORT_XPTI_API +#define XPTI_PUBLIC_API(t) PR_IMPLEMENT(t) +#define XPTI_PUBLIC_DATA(t) PR_IMPLEMENT_DATA(t) +#if defined(_WIN32) +# define XPTI_EXPORT __declspec(dllexport) +#elif defined(XP_OS2) && defined(__declspec) +# define XPTI_EXPORT __declspec(dllexport) +#elif defined(XP_OS2_VACPP) +# define XPTI_EXPORT extern +#else +# define XPTI_EXPORT +#endif +#else +#if defined(_WIN32) +# define XPTI_PUBLIC_API(t) __declspec(dllimport) t +# define XPTI_PUBLIC_DATA(t) __declspec(dllimport) t +# define XPTI_EXPORT __declspec(dllimport) +#elif defined(XP_OS2) && defined(__declspec) +# define XPTI_PUBLIC_API(t) __declspec(dllimport) t +# define XPTI_PUBLIC_DATA(t) __declspec(dllimport) t +# define XPTI_EXPORT __declspec(dllimport) +#elif defined(XP_OS2_VACPP) +# define XPTI_PUBLIC_API(t) extern t +# define XPTI_PUBLIC_DATA(t) extern t +# define XPTI_EXPORT extern +#else +# define XPTI_PUBLIC_API(t) PR_IMPLEMENT(t) +# define XPTI_PUBLIC_DATA(t) t +# define XPTI_EXPORT +#endif +#endif +#define XPTI_FRIEND_API(t) XPTI_PUBLIC_API(t) +#define XPTI_FRIEND_DATA(t) XPTI_PUBLIC_DATA(t) + +class nsIInterfaceInfoManager; +PR_BEGIN_EXTERN_C +// Even if this is a service, it is cool to provide a direct accessor +XPTI_PUBLIC_API(nsIInterfaceInfoManager*) +XPTI_GetInterfaceInfoManager(); + +// Even if this is a service, it is cool to provide a direct accessor +XPTI_PUBLIC_API(void) +XPTI_FreeInterfaceInfoManager(); +PR_END_EXTERN_C + + + +// Flyweight wrapper classes for xpt_struct.h structs. +// Everything here is dependent upon - and sensitive to changes in - +// xpcom/typelib/xpt/public/xpt_struct.h! + +class nsXPTType : public XPTTypeDescriptorPrefix +{ +// NO DATA - this a flyweight wrapper +public: + nsXPTType() + {} // random contents + nsXPTType(const XPTTypeDescriptorPrefix& prefix) + {*(XPTTypeDescriptorPrefix*)this = prefix;} + + nsXPTType(const uint8& prefix) + {*(uint8*)this = prefix;} + + nsXPTType& operator=(uint8 val) + {flags = val; return *this;} + + nsXPTType& operator=(const nsXPTType& other) + {flags = other.flags; return *this;} + + operator uint8() const + {return flags;} + + PRBool IsPointer() const + {return 0 != (XPT_TDP_IS_POINTER(flags));} + + PRBool IsUniquePointer() const + {return 0 != (XPT_TDP_IS_UNIQUE_POINTER(flags));} + + PRBool IsReference() const + {return 0 != (XPT_TDP_IS_REFERENCE(flags));} + + PRBool IsArithmetic() const // terminology from Harbison/Steele + {return flags <= T_WCHAR;} + + PRBool IsInterfacePointer() const + { switch (TagPart()) { + default: + return PR_FALSE; + case T_INTERFACE: + case T_INTERFACE_IS: + return PR_TRUE; + } + } + + PRBool IsArray() const + {return (PRBool) TagPart() == T_ARRAY;} + + // 'Dependent' means that params of this type are dependent upon other + // params. e.g. an T_INTERFACE_IS is dependent upon some other param at + // runtime to say what the interface type of this param really is. + PRBool IsDependent() const + { switch (TagPart()) { + default: + return PR_FALSE; + case T_INTERFACE_IS: + case TD_ARRAY: + case T_PSTRING_SIZE_IS: + case T_PWSTRING_SIZE_IS: + return PR_TRUE; + } + } + + uint8 TagPart() const + {return (uint8) (flags & XPT_TDP_TAGMASK);} + + enum + { + T_I8 = TD_INT8 , + T_I16 = TD_INT16 , + T_I32 = TD_INT32 , + T_I64 = TD_INT64 , + T_U8 = TD_UINT8 , + T_U16 = TD_UINT16 , + T_U32 = TD_UINT32 , + T_U64 = TD_UINT64 , + T_FLOAT = TD_FLOAT , + T_DOUBLE = TD_DOUBLE , + T_BOOL = TD_BOOL , + T_CHAR = TD_CHAR , + T_WCHAR = TD_WCHAR , + T_VOID = TD_VOID , + T_IID = TD_PNSIID , + T_DOMSTRING = TD_DOMSTRING , + T_CHAR_STR = TD_PSTRING , + T_WCHAR_STR = TD_PWSTRING , + T_INTERFACE = TD_INTERFACE_TYPE , + T_INTERFACE_IS = TD_INTERFACE_IS_TYPE, + T_ARRAY = TD_ARRAY , + T_PSTRING_SIZE_IS = TD_PSTRING_SIZE_IS , + T_PWSTRING_SIZE_IS = TD_PWSTRING_SIZE_IS , + T_UTF8STRING = TD_UTF8STRING , + T_CSTRING = TD_CSTRING , + T_ASTRING = TD_ASTRING + }; +// NO DATA - this a flyweight wrapper +}; + +class nsXPTParamInfo : public XPTParamDescriptor +{ +// NO DATA - this a flyweight wrapper +public: + nsXPTParamInfo(const XPTParamDescriptor& desc) + {*(XPTParamDescriptor*)this = desc;} + + + PRBool IsIn() const {return 0 != (XPT_PD_IS_IN(flags));} + PRBool IsOut() const {return 0 != (XPT_PD_IS_OUT(flags));} + PRBool IsRetval() const {return 0 != (XPT_PD_IS_RETVAL(flags));} + PRBool IsShared() const {return 0 != (XPT_PD_IS_SHARED(flags));} + PRBool IsDipper() const {return 0 != (XPT_PD_IS_DIPPER(flags));} + const nsXPTType GetType() const {return type.prefix;} + + // NOTE: other activities on types are done via methods on nsIInterfaceInfo + +private: + nsXPTParamInfo(); // no implementation +// NO DATA - this a flyweight wrapper +}; + +class nsXPTMethodInfo : public XPTMethodDescriptor +{ +// NO DATA - this a flyweight wrapper +public: + nsXPTMethodInfo(const XPTMethodDescriptor& desc) + {*(XPTMethodDescriptor*)this = desc;} + + PRBool IsGetter() const {return 0 != (XPT_MD_IS_GETTER(flags) );} + PRBool IsSetter() const {return 0 != (XPT_MD_IS_SETTER(flags) );} + PRBool IsNotXPCOM() const {return 0 != (XPT_MD_IS_NOTXPCOM(flags));} + PRBool IsConstructor() const {return 0 != (XPT_MD_IS_CTOR(flags) );} + PRBool IsHidden() const {return 0 != (XPT_MD_IS_HIDDEN(flags) );} + const char* GetName() const {return name;} + uint8 GetParamCount() const {return num_args;} + /* idx was index before I got _sick_ of the warnings on Unix, sorry jband */ + const nsXPTParamInfo GetParam(uint8 idx) const + { + NS_PRECONDITION(idx < GetParamCount(),"bad arg"); + return params[idx]; + } + const nsXPTParamInfo GetResult() const + {return *result;} +private: + nsXPTMethodInfo(); // no implementation +// NO DATA - this a flyweight wrapper +}; + + +// forward declaration +struct nsXPTCMiniVariant; + +class nsXPTConstant : public XPTConstDescriptor +{ +// NO DATA - this a flyweight wrapper +public: + nsXPTConstant(const XPTConstDescriptor& desc) + {*(XPTConstDescriptor*)this = desc;} + + const char* GetName() const + {return name;} + + const nsXPTType GetType() const + {return type.prefix;} + + // XXX this is ugly. But sometimes you gotta do what you gotta do. + // A reinterpret_cast won't do the trick here. And this plain C cast + // works correctly and is safe enough. + // See http://bugzilla.mozilla.org/show_bug.cgi?id=49641 + const nsXPTCMiniVariant* GetValue() const + {return (nsXPTCMiniVariant*) &value;} +private: + nsXPTConstant(); // no implementation +// NO DATA - this a flyweight wrapper +}; + +#endif /* xptiinfo_h___ */ diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/.cvsignore b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/Makefile.in b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/Makefile.in new file mode 100644 index 00000000..de5fd9b1 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/Makefile.in @@ -0,0 +1,75 @@ +# +# ***** 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.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of 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 ***** + +DEPTH = ../../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = xpcom +LIBRARY_NAME = xptinfo +REQUIRES = \ + string \ + $(NULL) + +CPPSRCS = \ + xptiFile.cpp \ + xptiInterfaceInfo.cpp \ + xptiInterfaceInfoManager.cpp \ + xptiManifest.cpp \ + xptiMisc.cpp \ + xptiTypelibGuts.cpp \ + xptiWorkingSet.cpp \ + xptiZipItem.cpp \ + xptiZipLoader.cpp \ + $(NULL) + +# we don't want the shared lib, but we want to force the creation of a static lib. +FORCE_STATIC_LIB = 1 + +# Force use of PIC +FORCE_USE_PIC = 1 + +include $(topsrcdir)/config/rules.mk + +# For nsManifestLineReader class. +LOCAL_INCLUDES = -I$(srcdir)/../../../ds + +DEFINES += -DEXPORT_XPTI_API -DEXPORT_XPT_API -D_IMPL_NS_COM -D_IMPL_NS_BASE + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/TODO b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/TODO new file mode 100644 index 00000000..c5bb1c64 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/TODO @@ -0,0 +1,20 @@ +/* jband - 03/24/00 - */ + +- DOCS +- improve error handling + - should some errors really be warnings? + - should autoreg support additional channel to recieve warnings so that + an installer can decide whether or not to accept the consequences of + leaving the newly installed files in place? +- verification of interfaces (warnings and/or errors) + - verify that repeated interfaces are identical in all ways + - verify that interface names are always one-to-one with iids +- check for truncated xpt files and version problems + - http://bugzilla.mozilla.org/show_bug.cgi?id=33193 +- TESTS! + - e.g. verify the merge stuff really works for various inputs. + - we really need a set of .xpt and .zip files and code that does an array + of autoreg and interfaceinof use activitities to test various corners + of the system. +- better autoreg logging +- use only 32 bits for file size? diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiFile.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiFile.cpp new file mode 100644 index 00000000..50362c75 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiFile.cpp @@ -0,0 +1,113 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mike McCabe + * John Bandhauer + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Implementation of xptiFile. */ + +#include "xptiprivate.h" + +MOZ_DECL_CTOR_COUNTER(xptiFile) + +xptiFile::xptiFile() + : +#ifdef DEBUG + mDEBUG_WorkingSet(nsnull), +#endif + mSize(), + mDate(), + mName(nsnull), + mGuts(nsnull), + mDirectory(0) +{ + // empty + MOZ_COUNT_CTOR(xptiFile); +} + +xptiFile::xptiFile(const nsInt64& aSize, + const nsInt64& aDate, + PRUint32 aDirectory, + const char* aName, + xptiWorkingSet* aWorkingSet) + : +#ifdef DEBUG + mDEBUG_WorkingSet(aWorkingSet), +#endif + mSize(aSize), + mDate(aDate), + mName(aName), + mGuts(nsnull), + mDirectory(aDirectory) +{ + NS_ASSERTION(aWorkingSet,"bad param"); + mName = XPT_STRDUP(aWorkingSet->GetStringArena(), aName); + + MOZ_COUNT_CTOR(xptiFile); +} + +xptiFile::xptiFile(const xptiFile& r, xptiWorkingSet* aWorkingSet) + : +#ifdef DEBUG + mDEBUG_WorkingSet(aWorkingSet), +#endif + mSize(r.mSize), + mDate(r.mDate), + mName(nsnull), + mGuts(nsnull), + mDirectory(r.mDirectory) +{ + NS_ASSERTION(aWorkingSet,"bad param"); + mName = XPT_STRDUP(aWorkingSet->GetStringArena(), r.mName); + + MOZ_COUNT_CTOR(xptiFile); +} + +xptiFile::~xptiFile() +{ + MOZ_COUNT_DTOR(xptiFile); +} + +PRBool +xptiFile::SetHeader(XPTHeader* aHeader, xptiWorkingSet* aWorkingSet) +{ + NS_ASSERTION(!mGuts,"bad state"); + NS_ASSERTION(aHeader,"bad param"); + NS_ASSERTION(aWorkingSet,"bad param"); + + mGuts = xptiTypelibGuts::NewGuts(aHeader, aWorkingSet); + return mGuts != nsnull; +} diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiInterfaceInfo.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiInterfaceInfo.cpp new file mode 100644 index 00000000..69bf86df --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiInterfaceInfo.cpp @@ -0,0 +1,819 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mike McCabe + * John Bandhauer + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Implementation of xptiInterfaceEntry and xptiInterfaceInfo. */ + +#include "xptiprivate.h" + +/***************************************************************************/ +// Debug Instrumentation... + +#ifdef SHOW_INFO_COUNT_STATS +static int DEBUG_TotalInfos = 0; +static int DEBUG_CurrentInfos = 0; +static int DEBUG_MaxInfos = 0; +static int DEBUG_MonitorEntryCount = 0; + +#define LOG_INFO_CREATE(t) \ + DEBUG_TotalInfos++; \ + DEBUG_CurrentInfos++; \ + if(DEBUG_MaxInfos < DEBUG_CurrentInfos) \ + DEBUG_MaxInfos = DEBUG_CurrentInfos /* no ';' */ + +#define LOG_INFO_DESTROY(t) \ + DEBUG_CurrentInfos-- /* no ';' */ + +#define LOG_INFO_MONITOR_ENTRY \ + DEBUG_MonitorEntryCount++ /* no ';' */ + +#else /* SHOW_INFO_COUNT_STATS */ + +#define LOG_INFO_CREATE(t) ((void)0) +#define LOG_INFO_DESTROY(t) ((void)0) +#define LOG_INFO_MONITOR_ENTRY ((void)0) +#endif /* SHOW_INFO_COUNT_STATS */ + +#ifdef DEBUG +// static +void xptiInterfaceInfo::DEBUG_ShutdownNotification() +{ +#ifdef SHOW_INFO_COUNT_STATS + printf("iiii %d total xptiInterfaceInfos created\n", DEBUG_TotalInfos); + printf("iiii %d max xptiInterfaceInfos alive at one time\n", DEBUG_MaxInfos); + printf("iiii %d xptiInterfaceInfos still alive\n", DEBUG_CurrentInfos); + printf("iiii %d times locked\n", DEBUG_MonitorEntryCount); +#endif +} +#endif /* DEBUG */ + +/***************************************************************************/ + +// static +xptiInterfaceEntry* +xptiInterfaceEntry::NewEntry(const char* name, + int nameLength, + const nsID& iid, + const xptiTypelib& typelib, + xptiWorkingSet* aWorkingSet) +{ + void* place = XPT_MALLOC(aWorkingSet->GetStructArena(), + sizeof(xptiInterfaceEntry) + nameLength); + if(!place) + return nsnull; + return new(place) xptiInterfaceEntry(name, nameLength, iid, typelib); +} + +// static +xptiInterfaceEntry* +xptiInterfaceEntry::NewEntry(const xptiInterfaceEntry& r, + const xptiTypelib& typelib, + xptiWorkingSet* aWorkingSet) +{ + size_t nameLength = PL_strlen(r.mName); + void* place = XPT_MALLOC(aWorkingSet->GetStructArena(), + sizeof(xptiInterfaceEntry) + nameLength); + if(!place) + return nsnull; + return new(place) xptiInterfaceEntry(r, nameLength, typelib); +} + + +xptiInterfaceEntry::xptiInterfaceEntry(const char* name, + size_t nameLength, + const nsID& iid, + const xptiTypelib& typelib) + : mIID(iid), + mTypelib(typelib), + mInfo(nsnull), + mFlags(uint8(0)) +{ + memcpy(mName, name, nameLength); +} + +xptiInterfaceEntry::xptiInterfaceEntry(const xptiInterfaceEntry& r, + size_t nameLength, + const xptiTypelib& typelib) + : mIID(r.mIID), + mTypelib(typelib), + mInfo(nsnull), + mFlags(r.mFlags) +{ + SetResolvedState(NOT_RESOLVED); + memcpy(mName, r.mName, nameLength); +} + +PRBool +xptiInterfaceEntry::Resolve(xptiWorkingSet* aWorkingSet /* = nsnull */) +{ + nsAutoLock lock(xptiInterfaceInfoManager::GetResolveLock()); + return ResolveLocked(aWorkingSet); +} + +PRBool +xptiInterfaceEntry::ResolveLocked(xptiWorkingSet* aWorkingSet /* = nsnull */) +{ + int resolvedState = GetResolveState(); + + if(resolvedState == FULLY_RESOLVED) + return PR_TRUE; + if(resolvedState == RESOLVE_FAILED) + return PR_FALSE; + + xptiInterfaceInfoManager* mgr = + xptiInterfaceInfoManager::GetInterfaceInfoManagerNoAddRef(); + + if(!mgr) + return PR_FALSE; + + if(!aWorkingSet) + { + aWorkingSet = mgr->GetWorkingSet(); + } + + if(resolvedState == NOT_RESOLVED) + { + LOG_RESOLVE(("! begin resolve of %s\n", mName)); + // Make a copy of mTypelib because the underlying memory will change! + xptiTypelib typelib = mTypelib; + + // We expect our PartiallyResolveLocked() to get called before + // this returns. + if(!mgr->LoadFile(typelib, aWorkingSet)) + { + SetResolvedState(RESOLVE_FAILED); + return PR_FALSE; + } + // The state was changed by LoadFile to PARTIALLY_RESOLVED, so this + // ...falls through... + } + + NS_ASSERTION(GetResolveState() == PARTIALLY_RESOLVED, "bad state!"); + + // Finish out resolution by finding parent and Resolving it so + // we can set the info we get from it. + + PRUint16 parent_index = mInterface->mDescriptor->parent_interface; + + if(parent_index) + { + xptiInterfaceEntry* parent = + aWorkingSet->GetTypelibGuts(mInterface->mTypelib)-> + GetEntryAt(parent_index - 1); + + if(!parent || !parent->EnsureResolvedLocked()) + { + xptiTypelib aTypelib = mInterface->mTypelib; + mInterface = nsnull; + mTypelib = aTypelib; + SetResolvedState(RESOLVE_FAILED); + return PR_FALSE; + } + + mInterface->mParent = parent; + + mInterface->mMethodBaseIndex = + parent->mInterface->mMethodBaseIndex + + parent->mInterface->mDescriptor->num_methods; + + mInterface->mConstantBaseIndex = + parent->mInterface->mConstantBaseIndex + + parent->mInterface->mDescriptor->num_constants; + + } + LOG_RESOLVE(("+ complete resolve of %s\n", mName)); + + SetResolvedState(FULLY_RESOLVED); + return PR_TRUE; +} + +// This *only* gets called by xptiInterfaceInfoManager::LoadFile (while locked). +PRBool +xptiInterfaceEntry::PartiallyResolveLocked(XPTInterfaceDescriptor* aDescriptor, + xptiWorkingSet* aWorkingSet) +{ + NS_ASSERTION(GetResolveState() == NOT_RESOLVED, "bad state"); + + LOG_RESOLVE(("~ partial resolve of %s\n", mName)); + + xptiInterfaceGuts* iface = + xptiInterfaceGuts::NewGuts(aDescriptor, mTypelib, aWorkingSet); + + if(!iface) + return PR_FALSE; + + mInterface = iface; + +#ifdef DEBUG + if(!DEBUG_ScriptableFlagIsValid()) + { + NS_ERROR("unexpected scriptable flag!"); + SetScriptableFlag(XPT_ID_IS_SCRIPTABLE(mInterface->mDescriptor->flags)); + } +#endif + + SetResolvedState(PARTIALLY_RESOLVED); + return PR_TRUE; +} + +/**************************************************/ +// These non-virtual methods handle the delegated nsIInterfaceInfo methods. + +nsresult +xptiInterfaceEntry::GetName(char **name) +{ + // It is not necessary to Resolve because this info is read from manifest. + *name = (char*) nsMemory::Clone(mName, PL_strlen(mName)+1); + return *name ? NS_OK : NS_ERROR_OUT_OF_MEMORY; +} + +nsresult +xptiInterfaceEntry::GetIID(nsIID **iid) +{ + // It is not necessary to Resolve because this info is read from manifest. + *iid = (nsIID*) nsMemory::Clone(&mIID, sizeof(nsIID)); + return *iid ? NS_OK : NS_ERROR_OUT_OF_MEMORY; +} + +nsresult +xptiInterfaceEntry::IsScriptable(PRBool* result) +{ + // It is not necessary to Resolve because this info is read from manifest. + NS_ASSERTION(DEBUG_ScriptableFlagIsValid(), "scriptable flag out of sync!"); + *result = GetScriptableFlag(); + return NS_OK; +} + +nsresult +xptiInterfaceEntry::IsFunction(PRBool* result) +{ + if(!EnsureResolved()) + return NS_ERROR_UNEXPECTED; + + *result = XPT_ID_IS_FUNCTION(GetInterfaceGuts()->mDescriptor->flags); + return NS_OK; +} + +nsresult +xptiInterfaceEntry::GetMethodCount(uint16* count) +{ + if(!EnsureResolved()) + return NS_ERROR_UNEXPECTED; + + *count = mInterface->mMethodBaseIndex + + mInterface->mDescriptor->num_methods; + return NS_OK; +} + +nsresult +xptiInterfaceEntry::GetConstantCount(uint16* count) +{ + if(!EnsureResolved()) + return NS_ERROR_UNEXPECTED; + + *count = mInterface->mConstantBaseIndex + + mInterface->mDescriptor->num_constants; + return NS_OK; +} + +nsresult +xptiInterfaceEntry::GetMethodInfo(uint16 index, const nsXPTMethodInfo** info) +{ + if(!EnsureResolved()) + return NS_ERROR_UNEXPECTED; + + if(index < mInterface->mMethodBaseIndex) + return mInterface->mParent->GetMethodInfo(index, info); + + if(index >= mInterface->mMethodBaseIndex + + mInterface->mDescriptor->num_methods) + { + NS_ERROR("bad param"); + *info = NULL; + return NS_ERROR_INVALID_ARG; + } + + // else... + *info = NS_REINTERPRET_CAST(nsXPTMethodInfo*, + &mInterface->mDescriptor-> + method_descriptors[index - + mInterface->mMethodBaseIndex]); + return NS_OK; +} + +nsresult +xptiInterfaceEntry::GetMethodInfoForName(const char* methodName, uint16 *index, + const nsXPTMethodInfo** result) +{ + if(!EnsureResolved()) + return NS_ERROR_UNEXPECTED; + + // This is a slow algorithm, but this is not expected to be called much. + for(uint16 i = 0; i < mInterface->mDescriptor->num_methods; ++i) + { + const nsXPTMethodInfo* info; + info = NS_REINTERPRET_CAST(nsXPTMethodInfo*, + &mInterface->mDescriptor-> + method_descriptors[i]); + if (PL_strcmp(methodName, info->GetName()) == 0) { + *index = i + mInterface->mMethodBaseIndex; + *result = info; + return NS_OK; + } + } + + if(mInterface->mParent) + return mInterface->mParent->GetMethodInfoForName(methodName, index, result); + else + { + *index = 0; + *result = 0; + return NS_ERROR_INVALID_ARG; + } +} + +nsresult +xptiInterfaceEntry::GetConstant(uint16 index, const nsXPTConstant** constant) +{ + if(!EnsureResolved()) + return NS_ERROR_UNEXPECTED; + + if(index < mInterface->mConstantBaseIndex) + return mInterface->mParent->GetConstant(index, constant); + + if(index >= mInterface->mConstantBaseIndex + + mInterface->mDescriptor->num_constants) + { + NS_PRECONDITION(0, "bad param"); + *constant = NULL; + return NS_ERROR_INVALID_ARG; + } + + // else... + *constant = + NS_REINTERPRET_CAST(nsXPTConstant*, + &mInterface->mDescriptor-> + const_descriptors[index - + mInterface->mConstantBaseIndex]); + return NS_OK; +} + +// this is a private helper + +nsresult +xptiInterfaceEntry::GetEntryForParam(PRUint16 methodIndex, + const nsXPTParamInfo * param, + xptiInterfaceEntry** entry) +{ + if(!EnsureResolved()) + return NS_ERROR_UNEXPECTED; + + if(methodIndex < mInterface->mMethodBaseIndex) + return mInterface->mParent->GetEntryForParam(methodIndex, param, entry); + + if(methodIndex >= mInterface->mMethodBaseIndex + + mInterface->mDescriptor->num_methods) + { + NS_ERROR("bad param"); + return NS_ERROR_INVALID_ARG; + } + + const XPTTypeDescriptor *td = ¶m->type; + + while (XPT_TDP_TAG(td->prefix) == TD_ARRAY) { + td = &mInterface->mDescriptor->additional_types[td->type.additional_type]; + } + + if(XPT_TDP_TAG(td->prefix) != TD_INTERFACE_TYPE) { + NS_ERROR("not an interface"); + return NS_ERROR_INVALID_ARG; + } + + xptiInterfaceEntry* theEntry = + mInterface->mWorkingSet->GetTypelibGuts(mInterface->mTypelib)-> + GetEntryAt(td->type.iface - 1); + + // This can happen if a declared interface is not available at runtime. + if(!theEntry) + { + NS_WARNING("Declared InterfaceInfo not found"); + *entry = nsnull; + return NS_ERROR_FAILURE; + } + + *entry = theEntry; + return NS_OK; +} + +nsresult +xptiInterfaceEntry::GetInfoForParam(uint16 methodIndex, + const nsXPTParamInfo *param, + nsIInterfaceInfo** info) +{ + xptiInterfaceEntry* entry; + nsresult rv = GetEntryForParam(methodIndex, param, &entry); + if(NS_FAILED(rv)) + return rv; + + xptiInterfaceInfo* theInfo; + rv = entry->GetInterfaceInfo(&theInfo); + if(NS_FAILED(rv)) + return rv; + + *info = NS_STATIC_CAST(nsIInterfaceInfo*, theInfo); + return NS_OK; +} + +nsresult +xptiInterfaceEntry::GetIIDForParam(uint16 methodIndex, + const nsXPTParamInfo* param, nsIID** iid) +{ + xptiInterfaceEntry* entry; + nsresult rv = GetEntryForParam(methodIndex, param, &entry); + if(NS_FAILED(rv)) + return rv; + return entry->GetIID(iid); +} + +nsresult +xptiInterfaceEntry::GetIIDForParamNoAlloc(PRUint16 methodIndex, + const nsXPTParamInfo * param, + nsIID *iid) +{ + xptiInterfaceEntry* entry; + nsresult rv = GetEntryForParam(methodIndex, param, &entry); + if(NS_FAILED(rv)) + return rv; + *iid = entry->mIID; + return NS_OK; +} + +// this is a private helper +nsresult +xptiInterfaceEntry::GetTypeInArray(const nsXPTParamInfo* param, + uint16 dimension, + const XPTTypeDescriptor** type) +{ + NS_ASSERTION(IsFullyResolved(), "bad state"); + + const XPTTypeDescriptor *td = ¶m->type; + const XPTTypeDescriptor *additional_types = + mInterface->mDescriptor->additional_types; + + for (uint16 i = 0; i < dimension; i++) { + if(XPT_TDP_TAG(td->prefix) != TD_ARRAY) { + NS_ERROR("bad dimension"); + return NS_ERROR_INVALID_ARG; + } + td = &additional_types[td->type.additional_type]; + } + + *type = td; + return NS_OK; +} + +nsresult +xptiInterfaceEntry::GetTypeForParam(uint16 methodIndex, + const nsXPTParamInfo* param, + uint16 dimension, + nsXPTType* type) +{ + if(!EnsureResolved()) + return NS_ERROR_UNEXPECTED; + + if(methodIndex < mInterface->mMethodBaseIndex) + return mInterface->mParent-> + GetTypeForParam(methodIndex, param, dimension, type); + + if(methodIndex >= mInterface->mMethodBaseIndex + + mInterface->mDescriptor->num_methods) + { + NS_ERROR("bad index"); + return NS_ERROR_INVALID_ARG; + } + + const XPTTypeDescriptor *td; + + if(dimension) { + nsresult rv = GetTypeInArray(param, dimension, &td); + if(NS_FAILED(rv)) + return rv; + } + else + td = ¶m->type; + + *type = nsXPTType(td->prefix); + return NS_OK; +} + +nsresult +xptiInterfaceEntry::GetSizeIsArgNumberForParam(uint16 methodIndex, + const nsXPTParamInfo* param, + uint16 dimension, + uint8* argnum) +{ + if(!EnsureResolved()) + return NS_ERROR_UNEXPECTED; + + if(methodIndex < mInterface->mMethodBaseIndex) + return mInterface->mParent-> + GetSizeIsArgNumberForParam(methodIndex, param, dimension, argnum); + + if(methodIndex >= mInterface->mMethodBaseIndex + + mInterface->mDescriptor->num_methods) + { + NS_ERROR("bad index"); + return NS_ERROR_INVALID_ARG; + } + + const XPTTypeDescriptor *td; + + if(dimension) { + nsresult rv = GetTypeInArray(param, dimension, &td); + if(NS_FAILED(rv)) + return rv; + } + else + td = ¶m->type; + + // verify that this is a type that has size_is + switch (XPT_TDP_TAG(td->prefix)) { + case TD_ARRAY: + case TD_PSTRING_SIZE_IS: + case TD_PWSTRING_SIZE_IS: + break; + default: + NS_ERROR("not a size_is"); + return NS_ERROR_INVALID_ARG; + } + + *argnum = td->argnum; + return NS_OK; +} + +nsresult +xptiInterfaceEntry::GetLengthIsArgNumberForParam(uint16 methodIndex, + const nsXPTParamInfo* param, + uint16 dimension, + uint8* argnum) +{ + if(!EnsureResolved()) + return NS_ERROR_UNEXPECTED; + + if(methodIndex < mInterface->mMethodBaseIndex) + return mInterface->mParent-> + GetLengthIsArgNumberForParam(methodIndex, param, dimension, argnum); + + if(methodIndex >= mInterface->mMethodBaseIndex + + mInterface->mDescriptor->num_methods) + { + NS_ERROR("bad index"); + return NS_ERROR_INVALID_ARG; + } + + const XPTTypeDescriptor *td; + + if(dimension) { + nsresult rv = GetTypeInArray(param, dimension, &td); + if(NS_FAILED(rv)) { + return rv; + } + } + else + td = ¶m->type; + + // verify that this is a type that has length_is + switch (XPT_TDP_TAG(td->prefix)) { + case TD_ARRAY: + case TD_PSTRING_SIZE_IS: + case TD_PWSTRING_SIZE_IS: + break; + default: + NS_ERROR("not a length_is"); + return NS_ERROR_INVALID_ARG; + } + + *argnum = td->argnum2; + return NS_OK; +} + +nsresult +xptiInterfaceEntry::GetInterfaceIsArgNumberForParam(uint16 methodIndex, + const nsXPTParamInfo* param, + uint8* argnum) +{ + if(!EnsureResolved()) + return NS_ERROR_UNEXPECTED; + + if(methodIndex < mInterface->mMethodBaseIndex) + return mInterface->mParent-> + GetInterfaceIsArgNumberForParam(methodIndex, param, argnum); + + if(methodIndex >= mInterface->mMethodBaseIndex + + mInterface->mDescriptor->num_methods) + { + NS_ERROR("bad index"); + return NS_ERROR_INVALID_ARG; + } + + const XPTTypeDescriptor *td = ¶m->type; + + while (XPT_TDP_TAG(td->prefix) == TD_ARRAY) { + td = &mInterface->mDescriptor-> + additional_types[td->type.additional_type]; + } + + if(XPT_TDP_TAG(td->prefix) != TD_INTERFACE_IS_TYPE) { + NS_ERROR("not an iid_is"); + return NS_ERROR_INVALID_ARG; + } + + *argnum = td->argnum; + return NS_OK; +} + +/* PRBool isIID (in nsIIDPtr IID); */ +nsresult +xptiInterfaceEntry::IsIID(const nsIID * IID, PRBool *_retval) +{ + // It is not necessary to Resolve because this info is read from manifest. + *_retval = mIID.Equals(*IID); + return NS_OK; +} + +/* void getNameShared ([shared, retval] out string name); */ +nsresult +xptiInterfaceEntry::GetNameShared(const char **name) +{ + // It is not necessary to Resolve because this info is read from manifest. + *name = mName; + return NS_OK; +} + +/* void getIIDShared ([shared, retval] out nsIIDPtrShared iid); */ +nsresult +xptiInterfaceEntry::GetIIDShared(const nsIID * *iid) +{ + // It is not necessary to Resolve because this info is read from manifest. + *iid = &mIID; + return NS_OK; +} + +/* PRBool hasAncestor (in nsIIDPtr iid); */ +nsresult +xptiInterfaceEntry::HasAncestor(const nsIID * iid, PRBool *_retval) +{ + *_retval = PR_FALSE; + + for(xptiInterfaceEntry* current = this; + current; + current = current->mInterface->mParent) + { + if(current->mIID.Equals(*iid)) + { + *_retval = PR_TRUE; + break; + } + if(!current->EnsureResolved()) + return NS_ERROR_UNEXPECTED; + } + + return NS_OK; +} + +/***************************************************/ + +nsresult +xptiInterfaceEntry::GetInterfaceInfo(xptiInterfaceInfo** info) +{ + nsAutoMonitor lock(xptiInterfaceInfoManager::GetInfoMonitor()); + LOG_INFO_MONITOR_ENTRY; + +#ifdef SHOW_INFO_COUNT_STATS + static int callCount = 0; + if(!(++callCount%100)) + printf("iiii %d xptiInterfaceInfos currently alive\n", DEBUG_CurrentInfos); +#endif + + if(!mInfo) + { + mInfo = new xptiInterfaceInfo(this); + if(!mInfo) + { + *info = nsnull; + return NS_ERROR_OUT_OF_MEMORY; + } + } + + NS_ADDREF(*info = mInfo); + return NS_OK; +} + +void +xptiInterfaceEntry::LockedInvalidateInterfaceInfo() +{ + if(mInfo) + { + mInfo->Invalidate(); + mInfo = nsnull; + } +} + +/***************************************************************************/ + +NS_IMPL_QUERY_INTERFACE1(xptiInterfaceInfo, nsIInterfaceInfo) + +xptiInterfaceInfo::xptiInterfaceInfo(xptiInterfaceEntry* entry) + : mEntry(entry), mParent(nsnull) +{ + LOG_INFO_CREATE(this); +} + +xptiInterfaceInfo::~xptiInterfaceInfo() +{ + LOG_INFO_DESTROY(this); + NS_IF_RELEASE(mParent); + NS_ASSERTION(!mEntry, "bad state in dtor"); +} + +nsrefcnt +xptiInterfaceInfo::AddRef(void) +{ + nsrefcnt cnt = (nsrefcnt) PR_AtomicIncrement((PRInt32*)&mRefCnt); + NS_LOG_ADDREF(this, cnt, "xptiInterfaceInfo", sizeof(*this)); + return cnt; +} + +nsrefcnt +xptiInterfaceInfo::Release(void) +{ + xptiInterfaceEntry* entry = mEntry; + nsrefcnt cnt = (nsrefcnt) PR_AtomicDecrement((PRInt32*)&mRefCnt); + NS_LOG_RELEASE(this, cnt, "xptiInterfaceInfo"); + if(!cnt) + { + nsAutoMonitor lock(xptiInterfaceInfoManager::GetInfoMonitor()); + LOG_INFO_MONITOR_ENTRY; + + // If GetInterfaceInfo added and *released* a reference before we + // acquired the monitor then 'this' might already be dead. In that + // case we would not want to try to access any instance data. We + // would want to bail immediately. If 'this' is already dead then the + // entry will no longer have a pointer to 'this'. So, we can protect + // ourselves from danger without more aggressive locking. + if(entry && !entry->InterfaceInfoEquals(this)) + return 0; + + // If GetInterfaceInfo added a reference before we acquired the monitor + // then we want to bail out of here without destorying the object. + if(mRefCnt) + return 1; + + if(mEntry) + { + mEntry->LockedInterfaceInfoDeathNotification(); + mEntry = nsnull; + } + + NS_DELETEXPCOM(this); + return 0; + } + return cnt; +} + +/***************************************************************************/ diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiInterfaceInfoManager.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiInterfaceInfoManager.cpp new file mode 100644 index 00000000..5ae06914 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiInterfaceInfoManager.cpp @@ -0,0 +1,2126 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mike McCabe + * John Bandhauer + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Implementation of xptiInterfaceInfoManager. */ + +#include "xptiprivate.h" +#include "nsDependentString.h" +#include "nsString.h" + +#define NS_ZIPLOADER_CONTRACTID NS_XPTLOADER_CONTRACTID_PREFIX "zip" + +NS_IMPL_THREADSAFE_ISUPPORTS2(xptiInterfaceInfoManager, + nsIInterfaceInfoManager, + nsIInterfaceInfoSuperManager) + +static xptiInterfaceInfoManager* gInterfaceInfoManager = nsnull; +#ifdef DEBUG +static int gCallCount = 0; +#endif + +// static +xptiInterfaceInfoManager* +xptiInterfaceInfoManager::GetInterfaceInfoManagerNoAddRef() +{ + if(!gInterfaceInfoManager) + { + nsCOMPtr searchPath; + BuildFileSearchPath(getter_AddRefs(searchPath)); + if(!searchPath) + { + NS_ERROR("can't get xpt search path!"); + return nsnull; + } + + gInterfaceInfoManager = new xptiInterfaceInfoManager(searchPath); + if(gInterfaceInfoManager) + NS_ADDREF(gInterfaceInfoManager); + if(!gInterfaceInfoManager->IsValid()) + { + NS_RELEASE(gInterfaceInfoManager); + } + else + { + PRBool mustAutoReg = + !xptiManifest::Read(gInterfaceInfoManager, + &gInterfaceInfoManager->mWorkingSet); +#ifdef DEBUG + { + // This sets what will be returned by GetOpenLogFile(). + xptiAutoLog autoLog(gInterfaceInfoManager, + gInterfaceInfoManager->mAutoRegLogFile, PR_TRUE); + LOG_AUTOREG(("debug build forced autoreg after %s load of manifest\n", mustAutoReg ? "FAILED" : "successful")); + + mustAutoReg = PR_TRUE; + } +#endif // DEBUG + if(mustAutoReg) + gInterfaceInfoManager->AutoRegisterInterfaces(); + } + } + return gInterfaceInfoManager; +} + +void +xptiInterfaceInfoManager::FreeInterfaceInfoManager() +{ + if(gInterfaceInfoManager) + gInterfaceInfoManager->LogStats(); + + NS_IF_RELEASE(gInterfaceInfoManager); +} + +PRBool +xptiInterfaceInfoManager::IsValid() +{ + return mWorkingSet.IsValid() && + mResolveLock && + mAutoRegLock && + mInfoMonitor && + mAdditionalManagersLock; +} + +xptiInterfaceInfoManager::xptiInterfaceInfoManager(nsISupportsArray* aSearchPath) + : mWorkingSet(aSearchPath), + mOpenLogFile(nsnull), + mResolveLock(PR_NewLock()), + mAutoRegLock(PR_NewLock()), + mInfoMonitor(nsAutoMonitor::NewMonitor("xptiInfoMonitor")), + mAdditionalManagersLock(PR_NewLock()), + mSearchPath(aSearchPath) +{ + const char* statsFilename = PR_GetEnv("MOZILLA_XPTI_STATS"); + if(statsFilename) + { + mStatsLogFile = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID); + if(mStatsLogFile && + NS_SUCCEEDED(mStatsLogFile->InitWithNativePath(nsDependentCString(statsFilename)))) + { + printf("* Logging xptinfo stats to: %s\n", statsFilename); + } + else + { + printf("* Failed to create xptinfo stats file: %s\n", statsFilename); + mStatsLogFile = nsnull; + } + } + + const char* autoRegFilename = PR_GetEnv("MOZILLA_XPTI_REGLOG"); + if(autoRegFilename) + { + mAutoRegLogFile = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID); + if(mAutoRegLogFile && + NS_SUCCEEDED(mAutoRegLogFile->InitWithNativePath(nsDependentCString(autoRegFilename)))) + { + printf("* Logging xptinfo autoreg to: %s\n", autoRegFilename); + } + else + { + printf("* Failed to create xptinfo autoreg file: %s\n", autoRegFilename); + mAutoRegLogFile = nsnull; + } + } +} + +xptiInterfaceInfoManager::~xptiInterfaceInfoManager() +{ + // We only do this on shutdown of the service. + mWorkingSet.InvalidateInterfaceInfos(); + + if(mResolveLock) + PR_DestroyLock(mResolveLock); + if(mAutoRegLock) + PR_DestroyLock(mAutoRegLock); + if(mInfoMonitor) + nsAutoMonitor::DestroyMonitor(mInfoMonitor); + if(mAdditionalManagersLock) + PR_DestroyLock(mAdditionalManagersLock); + + gInterfaceInfoManager = nsnull; +#ifdef DEBUG + xptiInterfaceInfo::DEBUG_ShutdownNotification(); + gCallCount = 0; +#endif +} + +static nsresult +GetDirectoryFromDirService(const char* codename, nsILocalFile** aDir) +{ + NS_ASSERTION(codename,"loser!"); + NS_ASSERTION(aDir,"loser!"); + + nsresult rv; + nsCOMPtr dirService = + do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv); + if (NS_FAILED(rv)) return rv; + + return dirService->Get(codename, NS_GET_IID(nsILocalFile), (void**) aDir); +} + +static PRBool +AppendFromDirServiceList(const char* codename, nsISupportsArray* aPath) +{ + NS_ASSERTION(codename,"loser!"); + NS_ASSERTION(aPath,"loser!"); + + nsCOMPtr dirService = + do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID); + if(!dirService) + return PR_FALSE; + + nsCOMPtr fileList; + dirService->Get(codename, NS_GET_IID(nsISimpleEnumerator), + getter_AddRefs(fileList)); + if(!fileList) + return PR_FALSE; + + PRBool more; + while(NS_SUCCEEDED(fileList->HasMoreElements(&more)) && more) + { + nsCOMPtr dir; + fileList->GetNext(getter_AddRefs(dir)); + if(!dir || !aPath->AppendElement(dir)) + return PR_FALSE; + } + + return PR_TRUE; +} + +// static +PRBool xptiInterfaceInfoManager::BuildFileSearchPath(nsISupportsArray** aPath) +{ +#ifdef DEBUG + NS_ASSERTION(!gCallCount++, "Expected only one call!"); +#endif + + nsCOMPtr searchPath; + NS_NewISupportsArray(getter_AddRefs(searchPath)); + if(!searchPath) + return PR_FALSE; + + nsCOMPtr compDir; + + // Always put components directory first + + if(NS_FAILED(GetDirectoryFromDirService(NS_XPCOM_COMPONENT_DIR, + getter_AddRefs(compDir))) || + !searchPath->AppendElement(compDir)) + { + return PR_FALSE; + } + + // Add additional plugins dirs + // No error checking here since this is optional in some embeddings + + // Add the GRE's component directory to searchPath if the + // application is using an GRE. + // An application indicates that it's using an GRE by returning + // a valid nsIFile via it's directory service provider interface. + // + // Please see http://www.mozilla.org/projects/embedding/MRE.html + // for more info. on GREs + // + nsCOMPtr greComponentDirectory; + nsresult rv = GetDirectoryFromDirService(NS_GRE_COMPONENT_DIR, + getter_AddRefs(greComponentDirectory)); + if(NS_SUCCEEDED(rv) && greComponentDirectory) + { + // make sure we only append a directory if its a different one + PRBool equalsCompDir = PR_FALSE; + greComponentDirectory->Equals(compDir, &equalsCompDir); + + if(!equalsCompDir) + searchPath->AppendElement(greComponentDirectory); + } + + (void)AppendFromDirServiceList(NS_XPCOM_COMPONENT_DIR_LIST, searchPath); + (void)AppendFromDirServiceList(NS_APP_PLUGINS_DIR_LIST, searchPath); + + NS_ADDREF(*aPath = searchPath); + return PR_TRUE; +} + +PRBool +xptiInterfaceInfoManager::GetCloneOfManifestLocation(nsILocalFile** aFile) +{ + // We *trust* that this will not change! + nsCOMPtr lf; + nsresult rv = GetDirectoryFromDirService(NS_XPCOM_XPTI_REGISTRY_FILE, + getter_AddRefs(lf)); + + if (NS_FAILED(rv)) return PR_FALSE; + + rv = xptiCloneLocalFile(lf, aFile); + if (NS_FAILED(rv)) return PR_FALSE; + return PR_TRUE; +} + +PRBool +xptiInterfaceInfoManager::GetApplicationDir(nsILocalFile** aDir) +{ + // We *trust* that this will not change! + return NS_SUCCEEDED(GetDirectoryFromDirService(NS_XPCOM_CURRENT_PROCESS_DIR, aDir)); +} + +PRBool +xptiInterfaceInfoManager::BuildFileList(nsISupportsArray* aSearchPath, + nsISupportsArray** aFileList) +{ + NS_ASSERTION(aFileList, "loser!"); + + nsresult rv; + + nsCOMPtr fileList = + do_CreateInstance(NS_SUPPORTSARRAY_CONTRACTID); + if(!fileList) + return PR_FALSE; + + PRUint32 pathCount; + if(NS_FAILED(aSearchPath->Count(&pathCount))) + return PR_FALSE; + + for(PRUint32 i = 0; i < pathCount; i++) + { + nsCOMPtr dir; + rv = xptiCloneElementAsLocalFile(aSearchPath, i, getter_AddRefs(dir)); + if(NS_FAILED(rv) || !dir) + return PR_FALSE; + + nsCOMPtr entries; + rv = dir->GetDirectoryEntries(getter_AddRefs(entries)); + if(NS_FAILED(rv) || !entries) + continue; + + PRUint32 count = 0; + PRBool hasMore; + while(NS_SUCCEEDED(entries->HasMoreElements(&hasMore)) && hasMore) + { + nsCOMPtr sup; + entries->GetNext(getter_AddRefs(sup)); + if(!sup) + return PR_FALSE; + nsCOMPtr file = do_QueryInterface(sup); + if(!file) + return PR_FALSE; + + PRBool isFile; + if(NS_FAILED(file->IsFile(&isFile)) || !isFile) + { + continue; + } + + nsCAutoString name; + if(NS_FAILED(file->GetNativeLeafName(name))) + return PR_FALSE; + + if(xptiFileType::IsUnknown(name.get())) + continue; + + LOG_AUTOREG(("found file: %s\n", name.get())); + + if(!fileList->InsertElementAt(file, count)) + return PR_FALSE; + ++count; + } + } + + NS_ADDREF(*aFileList = fileList); + return PR_TRUE; +} + +XPTHeader* +xptiInterfaceInfoManager::ReadXPTFile(nsILocalFile* aFile, + xptiWorkingSet* aWorkingSet) +{ + NS_ASSERTION(aFile, "loser!"); + + XPTHeader *header = nsnull; + char *whole = nsnull; + PRFileDesc* fd = nsnull; + XPTState *state = nsnull; + XPTCursor cursor; + PRInt32 flen; + PRInt64 fileSize; + + PRBool saveFollowLinks; + aFile->GetFollowLinks(&saveFollowLinks); + aFile->SetFollowLinks(PR_TRUE); + + if(NS_FAILED(aFile->GetFileSize(&fileSize)) || !(flen = nsInt64(fileSize))) + { + aFile->SetFollowLinks(saveFollowLinks); + return nsnull; + } + + whole = new char[flen]; + if (!whole) + { + aFile->SetFollowLinks(saveFollowLinks); + return nsnull; + } + + // all exits from on here should be via 'goto out' + + if(NS_FAILED(aFile->OpenNSPRFileDesc(PR_RDONLY, 0444, &fd)) || !fd) + { + goto out; + } + + if(flen > PR_Read(fd, whole, flen)) + { + goto out; + } + + if(!(state = XPT_NewXDRState(XPT_DECODE, whole, flen))) + { + goto out; + } + + if(!XPT_MakeCursor(state, XPT_HEADER, 0, &cursor)) + { + goto out; + } + + if (!XPT_DoHeader(aWorkingSet->GetStructArena(), &cursor, &header)) + { + header = nsnull; + goto out; + } + + out: + if(fd) + PR_Close(fd); + if(state) + XPT_DestroyXDRState(state); + if(whole) + delete [] whole; + aFile->SetFollowLinks(saveFollowLinks); + return header; +} + +PRBool +xptiInterfaceInfoManager::LoadFile(const xptiTypelib& aTypelibRecord, + xptiWorkingSet* aWorkingSet) +{ + if(!aWorkingSet) + aWorkingSet = &mWorkingSet; + + if(!aWorkingSet->IsValid()) + return PR_FALSE; + + xptiFile* fileRecord = &aWorkingSet->GetFileAt(aTypelibRecord.GetFileIndex()); + xptiZipItem* zipItem = nsnull; + + nsCOMPtr file; + if(NS_FAILED(aWorkingSet->GetCloneOfDirectoryAt(fileRecord->GetDirectory(), + getter_AddRefs(file))) || !file) + return PR_FALSE; + + if(NS_FAILED(file->AppendNative(nsDependentCString(fileRecord->GetName())))) + return PR_FALSE; + + XPTHeader* header; + + if(aTypelibRecord.IsZip()) + { + zipItem = &aWorkingSet->GetZipItemAt(aTypelibRecord.GetZipItemIndex()); + + // See the big comment below in the 'non-zip' case... + if(zipItem->GetGuts()) + { + NS_ERROR("Trying to load an xpt file from a zip twice"); + + // Force an autoreg on next run + (void) xptiManifest::Delete(this); + + return PR_FALSE; + } + + LOG_LOAD(("# loading zip item %s::%s\n", fileRecord->GetName(), zipItem->GetName())); + + nsCOMPtr loader = + do_GetService(NS_ZIPLOADER_CONTRACTID); + + if (loader) { + nsresult rv; + + nsCOMPtr stream; + rv = loader->LoadEntry(file, zipItem->GetName(), + getter_AddRefs(stream)); + + if (NS_FAILED(rv)) + return PR_FALSE; + + header = + xptiZipLoader::ReadXPTFileFromInputStream(stream, aWorkingSet); + } else { + header = nsnull; + NS_WARNING("Could not load XPT Zip loader"); + } + } + else + { + // The file would only have guts already if we previously failed to + // find an interface info in a file where the manifest claimed it was + // going to be. + // + // Normally, when the file gets loaded (and the guts set) then all + // interfaces would also be resolved. So, if we are here again for + // the same file then there must have been some interface that was + // expected but not present. Now we are explicitly trying to find it + // and it isn't going to be there this time either. + // + // This is an assertion style error in a DEBUG build because it shows + // that we failed to detect this in autoreg. For release builds (where + // autoreg is not run on every startup) it is just bad. But by returning + // PR_FALSE we mark this interface as RESOLVE_FAILED and get on with + // things without crashing or anything. + // + // We don't want to do an autoreg here because this is too much of an + // edge case (and in that odd case it might autoreg multiple times if + // many interfaces had been removed). But, by deleting the manifest we + // force the system to get it right on the next run. + + if(fileRecord->GetGuts()) + { + NS_ERROR("Trying to load an xpt file twice"); + + // Force an autoreg on next run + (void) xptiManifest::Delete(this); + + return PR_FALSE; + } + + LOG_LOAD(("^ loading file %s\n", fileRecord->GetName())); + header = ReadXPTFile(file, aWorkingSet); + } + + if(!header) + return PR_FALSE; + + + if(aTypelibRecord.IsZip()) + { + // This also allocs zipItem.GetGuts() used below. + if(!zipItem->SetHeader(header, aWorkingSet)) + return PR_FALSE; + } + else + { + // This also allocs fileRecord.GetGuts() used below. + if(!fileRecord->SetHeader(header, aWorkingSet)) + return PR_FALSE; + } + + // For each interface in the header we want to find the xptiInterfaceInfo + // object and set its resolution info. + + for(PRUint16 i = 0; i < header->num_interfaces; i++) + { + static const nsID zeroIID = + { 0x0, 0x0, 0x0, { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 } }; + + XPTInterfaceDirectoryEntry* iface = header->interface_directory + i; + + xptiHashEntry* hashEntry; + + if(!iface->iid.Equals(zeroIID)) + { + hashEntry = (xptiHashEntry*) + PL_DHashTableOperate(aWorkingSet->mIIDTable, + &iface->iid, PL_DHASH_LOOKUP); + } + else + { + hashEntry = (xptiHashEntry*) + PL_DHashTableOperate(aWorkingSet->mNameTable, + iface->name, PL_DHASH_LOOKUP); + } + + xptiInterfaceEntry* entry = + PL_DHASH_ENTRY_IS_FREE(hashEntry) ? nsnull : hashEntry->value; + + if(!entry) + { + // This one is just not resolved anywhere! + continue; + } + + if(aTypelibRecord.IsZip()) + zipItem->GetGuts()->SetEntryAt(i, entry); + else + fileRecord->GetGuts()->SetEntryAt(i, entry); + + XPTInterfaceDescriptor* descriptor = iface->interface_descriptor; + + if(descriptor && aTypelibRecord.Equals(entry->GetTypelibRecord())) + entry->PartiallyResolveLocked(descriptor, aWorkingSet); + } + return PR_TRUE; +} + +static int +IndexOfFileWithName(const char* aName, const xptiWorkingSet* aWorkingSet) +{ + NS_ASSERTION(aName, "loser!"); + + for(PRUint32 i = 0; i < aWorkingSet->GetFileCount(); ++i) + { + if(0 == PL_strcmp(aName, aWorkingSet->GetFileAt(i).GetName())) + return i; + } + return -1; +} + +static int +IndexOfDirectoryOfFile(nsISupportsArray* aSearchPath, nsILocalFile* aFile) +{ + nsCOMPtr parent; + aFile->GetParent(getter_AddRefs(parent)); + if(parent) + { + PRUint32 count = 0; + aSearchPath->Count(&count); + NS_ASSERTION(count, "broken search path! bad count"); + for(PRUint32 i = 0; i < count; i++) + { + nsCOMPtr current; + aSearchPath->QueryElementAt(i, NS_GET_IID(nsIFile), + getter_AddRefs(current)); + NS_ASSERTION(current, "broken search path! bad element"); + PRBool same; + if(NS_SUCCEEDED(parent->Equals(current, &same)) && same) + return (int) i; + } + } + NS_ERROR("file not in search directory!"); + return -1; +} + +struct SortData +{ + nsISupportsArray* mSearchPath; + xptiWorkingSet* mWorkingSet; +}; + +PR_STATIC_CALLBACK(int) +xptiSortFileList(const void * p1, const void *p2, void * closure) +{ + nsILocalFile* pFile1 = *((nsILocalFile**) p1); + nsILocalFile* pFile2 = *((nsILocalFile**) p2); + SortData* data = (SortData*) closure; + + nsCAutoString name1; + nsCAutoString name2; + + if(NS_FAILED(pFile1->GetNativeLeafName(name1))) + { + NS_ERROR("way bad, with no happy out!"); + return 0; + } + if(NS_FAILED(pFile2->GetNativeLeafName(name2))) + { + NS_ERROR("way bad, with no happy out!"); + return 0; + } + + int index1 = IndexOfFileWithName(name1.get(), data->mWorkingSet); + int index2 = IndexOfFileWithName(name2.get(), data->mWorkingSet); + + // Get these now in case we need them later. + PRBool isXPT1 = xptiFileType::IsXPT(name1.get()); + PRBool isXPT2 = xptiFileType::IsXPT(name2.get()); + int nameOrder = Compare(name1, name2); + + // both in workingSet, preserve old order + if(index1 != -1 && index2 != -1) + return index1 - index2; + + if(index1 != -1) + return 1; + + if(index2 != -1) + return -1; + + // neither is in workingset + + // check how they compare in search path order + + int dirIndex1 = IndexOfDirectoryOfFile(data->mSearchPath, pFile1); + int dirIndex2 = IndexOfDirectoryOfFile(data->mSearchPath, pFile2); + + if(dirIndex1 != dirIndex2) + return dirIndex1 - dirIndex2; + + // .xpt files come before archives (.zip, .jar, etc) + if(isXPT1 &&!isXPT2) + return -1; + + if(!isXPT1 && isXPT2) + return 1; + + // neither element is in the workingSet and both are same type and in + // the same directory, sort by size + + PRInt64 size1; + PRInt64 size2; + + if(NS_FAILED(pFile1->GetFileSize(&size1))) + { + NS_ERROR("way bad, with no happy out!"); + return 0; + } + if(NS_FAILED(pFile2->GetFileSize(&size2))) + { + NS_ERROR("way bad, with no happy out!"); + return 0; + } + + // by size with largest first, or by name if size is the same + int sizeDiff = int(PRInt32(nsInt64(size2) - nsInt64(size1))); + return sizeDiff != 0 ? sizeDiff : nameOrder; +} + +nsILocalFile** +xptiInterfaceInfoManager::BuildOrderedFileArray(nsISupportsArray* aSearchPath, + nsISupportsArray* aFileList, + xptiWorkingSet* aWorkingSet) +{ + // We want to end up with a file list that starts with the files from + // aWorkingSet (but only those that are in aFileList) in the order in + // which they appeared in aWorkingSet-> Following those files will be those + // files in aFileList which are not in aWorkingSet-> These additional + // files will be ordered by file size (larger first) but all .xpt files + // will preceed all zipfile of those files not already in the working set. + // To do this we will do a fancy sort on a copy of aFileList. + + nsILocalFile** orderedFileList = nsnull; + PRUint32 countOfFilesInFileList; + PRUint32 i; + + NS_ASSERTION(aFileList, "loser!"); + NS_ASSERTION(aWorkingSet, "loser!"); + NS_ASSERTION(aWorkingSet->IsValid(), "loser!"); + + if(NS_FAILED(aFileList->Count(&countOfFilesInFileList)) || + 0 == countOfFilesInFileList) + return nsnull; + + orderedFileList = (nsILocalFile**) + XPT_MALLOC(aWorkingSet->GetStructArena(), + sizeof(nsILocalFile*) * countOfFilesInFileList); + + if(!orderedFileList) + return nsnull; + + // fill our list for sorting + for(i = 0; i < countOfFilesInFileList; ++i) + { + nsCOMPtr file; + aFileList->QueryElementAt(i, NS_GET_IID(nsILocalFile), getter_AddRefs(file)); + NS_ASSERTION(file, "loser!"); + + // Intentionally NOT addref'd cuz we know these are pinned in aFileList. + orderedFileList[i] = file.get(); + } + + // sort the filelist + + SortData sortData = {aSearchPath, aWorkingSet}; + NS_QuickSort(orderedFileList, countOfFilesInFileList, sizeof(nsILocalFile*), + xptiSortFileList, &sortData); + + return orderedFileList; +} + +xptiInterfaceInfoManager::AutoRegMode +xptiInterfaceInfoManager::DetermineAutoRegStrategy(nsISupportsArray* aSearchPath, + nsISupportsArray* aFileList, + xptiWorkingSet* aWorkingSet) +{ + NS_ASSERTION(aFileList, "loser!"); + NS_ASSERTION(aWorkingSet, "loser!"); + NS_ASSERTION(aWorkingSet->IsValid(), "loser!"); + + PRUint32 countOfFilesInWorkingSet = aWorkingSet->GetFileCount(); + PRUint32 countOfFilesInFileList; + PRUint32 i; + PRUint32 k; + + if(0 == countOfFilesInWorkingSet) + { + // Loading manifest might have failed. Better safe... + return FULL_VALIDATION_REQUIRED; + } + + if(NS_FAILED(aFileList->Count(&countOfFilesInFileList))) + { + NS_ERROR("unexpected!"); + return FULL_VALIDATION_REQUIRED; + } + + if(countOfFilesInFileList == countOfFilesInWorkingSet) + { + // try to determine if *no* files are new or changed. + + PRBool same = PR_TRUE; + for(i = 0; i < countOfFilesInFileList && same; ++i) + { + nsCOMPtr file; + aFileList->QueryElementAt(i, NS_GET_IID(nsILocalFile), getter_AddRefs(file)); + NS_ASSERTION(file, "loser!"); + + PRInt64 size; + PRInt64 date; + nsCAutoString name; + PRUint32 directory; + + if(NS_FAILED(file->GetFileSize(&size)) || + NS_FAILED(file->GetLastModifiedTime(&date)) || + NS_FAILED(file->GetNativeLeafName(name)) || + !aWorkingSet->FindDirectoryOfFile(file, &directory)) + { + NS_ERROR("unexpected!"); + return FULL_VALIDATION_REQUIRED; + } + + for(k = 0; k < countOfFilesInWorkingSet; ++k) + { + xptiFile& target = aWorkingSet->GetFileAt(k); + + if(directory == target.GetDirectory() && + name.Equals(target.GetName())) + { + if(nsInt64(size) != target.GetSize() || + nsInt64(date) != target.GetDate()) + same = PR_FALSE; + break; + } + } + // failed to find our file in the workingset? + if(k == countOfFilesInWorkingSet) + same = PR_FALSE; + } + if(same) + return NO_FILES_CHANGED; + } + else if(countOfFilesInFileList > countOfFilesInWorkingSet) + { + // try to determine if the only changes are additional new files + // XXX Wimping out and doing this as a separate walk through the lists. + + PRBool same = PR_TRUE; + + for(i = 0; i < countOfFilesInWorkingSet && same; ++i) + { + xptiFile& target = aWorkingSet->GetFileAt(i); + + for(k = 0; k < countOfFilesInFileList; ++k) + { + nsCOMPtr file; + aFileList->QueryElementAt(k, NS_GET_IID(nsILocalFile), getter_AddRefs(file)); + NS_ASSERTION(file, "loser!"); + + nsCAutoString name; + PRInt64 size; + PRInt64 date; + if(NS_FAILED(file->GetFileSize(&size)) || + NS_FAILED(file->GetLastModifiedTime(&date)) || + NS_FAILED(file->GetNativeLeafName(name))) + { + NS_ERROR("unexpected!"); + return FULL_VALIDATION_REQUIRED; + } + + PRBool sameName = name.Equals(target.GetName()); + if(sameName) + { + if(nsInt64(size) != target.GetSize() || + nsInt64(date) != target.GetDate()) + same = PR_FALSE; + break; + } + } + // failed to find our file in the file list? + if(k == countOfFilesInFileList) + same = PR_FALSE; + } + if(same) + return FILES_ADDED_ONLY; + } + + return FULL_VALIDATION_REQUIRED; +} + +PRBool +xptiInterfaceInfoManager::AddOnlyNewFilesFromFileList(nsISupportsArray* aSearchPath, + nsISupportsArray* aFileList, + xptiWorkingSet* aWorkingSet) +{ + nsILocalFile** orderedFileArray; + PRUint32 countOfFilesInFileList; + PRUint32 i; + + NS_ASSERTION(aFileList, "loser!"); + NS_ASSERTION(aWorkingSet, "loser!"); + NS_ASSERTION(aWorkingSet->IsValid(), "loser!"); + + if(NS_FAILED(aFileList->Count(&countOfFilesInFileList))) + return PR_FALSE; + NS_ASSERTION(countOfFilesInFileList, "loser!"); + NS_ASSERTION(countOfFilesInFileList > aWorkingSet->GetFileCount(), "loser!"); + + orderedFileArray = BuildOrderedFileArray(aSearchPath, aFileList, aWorkingSet); + + if(!orderedFileArray) + return PR_FALSE; + + // Make enough space in aWorkingset for additions to xptiFile array. + + if(!aWorkingSet->ExtendFileArray(countOfFilesInFileList)) + return PR_FALSE; + + // For each file that is not already in our working set, add any valid + // interfaces that don't conflict with previous interfaces added. + for(i = 0; i < countOfFilesInFileList; i++) + { + nsILocalFile* file = orderedFileArray[i]; + + nsCAutoString name; + PRInt64 size; + PRInt64 date; + PRUint32 dir; + if(NS_FAILED(file->GetFileSize(&size)) || + NS_FAILED(file->GetLastModifiedTime(&date)) || + NS_FAILED(file->GetNativeLeafName(name)) || + !aWorkingSet->FindDirectoryOfFile(file, &dir)) + { + return PR_FALSE; + } + + + if(xptiWorkingSet::NOT_FOUND != aWorkingSet->FindFile(dir, name.get())) + { + // This file was found in the working set, so skip it. + continue; + } + + LOG_AUTOREG((" finding interfaces in new file: %s\n", name.get())); + + xptiFile fileRecord; + fileRecord = xptiFile(nsInt64(size), nsInt64(date), dir, + name.get(), aWorkingSet); + + if(xptiFileType::IsXPT(fileRecord.GetName())) + { + XPTHeader* header = ReadXPTFile(file, aWorkingSet); + if(!header) + { + // XXX do something! + NS_ERROR(""); + continue; + } + + + xptiTypelib typelibRecord; + typelibRecord.Init(aWorkingSet->GetFileCount()); + + PRBool AddedFile = PR_FALSE; + + if(header->major_version >= XPT_MAJOR_INCOMPATIBLE_VERSION) + { + NS_ASSERTION(!header->num_interfaces,"bad libxpt"); + LOG_AUTOREG((" file is version %d.%d Type file of version %d.0 or higher can not be read.\n", (int)header->major_version, (int)header->minor_version, (int)XPT_MAJOR_INCOMPATIBLE_VERSION)); + } + + for(PRUint16 k = 0; k < header->num_interfaces; k++) + { + xptiInterfaceEntry* entry = nsnull; + + if(!VerifyAndAddEntryIfNew(aWorkingSet, + header->interface_directory + k, + typelibRecord, + &entry)) + return PR_FALSE; + + if(!entry) + continue; + + // If this is the first interface we found for this file then + // setup the fileRecord for the header and infos. + if(!AddedFile) + { + if(!fileRecord.SetHeader(header, aWorkingSet)) + { + // XXX that would be bad. + return PR_FALSE; + } + AddedFile = PR_TRUE; + } + fileRecord.GetGuts()->SetEntryAt(k, entry); + } + + // This will correspond to typelibRecord above. + aWorkingSet->AppendFile(fileRecord); + } + else // its another kind of archive + { + nsCOMPtr loader = + do_GetService(NS_ZIPLOADER_CONTRACTID); + + if (loader) { + nsresult rv; + + nsCOMPtr sink = + new xptiZipLoaderSink(this, aWorkingSet); + if (!sink) + return PR_FALSE; + + rv = loader->EnumerateEntries(file, sink); + if (NS_FAILED(rv)) + return PR_FALSE; + // This will correspond to typelibRecord used in + // xptiInterfaceInfoManager::FoundEntry. + aWorkingSet->AppendFile(fileRecord); + } else { + NS_WARNING("Could not load XPT Zip loader"); + } + } + } + + return PR_TRUE; +} + +PRBool +xptiInterfaceInfoManager::DoFullValidationMergeFromFileList(nsISupportsArray* aSearchPath, + nsISupportsArray* aFileList, + xptiWorkingSet* aWorkingSet) +{ + nsILocalFile** orderedFileArray; + PRUint32 countOfFilesInFileList; + PRUint32 i; + + NS_ASSERTION(aFileList, "loser!"); + + if(!aWorkingSet->IsValid()) + return PR_FALSE; + + if(NS_FAILED(aFileList->Count(&countOfFilesInFileList))) + return PR_FALSE; + + if(!countOfFilesInFileList) + { + // maybe there are no xpt files to register. + // a minimal install would have this case. + return PR_TRUE; + } + + orderedFileArray = BuildOrderedFileArray(aSearchPath, aFileList, aWorkingSet); + + if(!orderedFileArray) + return PR_FALSE; + + // DEBUG_DumpFileArray(orderedFileArray, countOfFilesInFileList); + + // Make space in aWorkingset for a new xptiFile array. + + if(!aWorkingSet->NewFileArray(countOfFilesInFileList)) + return PR_FALSE; + + aWorkingSet->ClearZipItems(); + aWorkingSet->ClearHashTables(); + + // For each file, add any valid interfaces that don't conflict with + // previous interfaces added. + for(i = 0; i < countOfFilesInFileList; i++) + { + nsILocalFile* file = orderedFileArray[i]; + + nsCAutoString name; + PRInt64 size; + PRInt64 date; + PRUint32 dir; + if(NS_FAILED(file->GetFileSize(&size)) || + NS_FAILED(file->GetLastModifiedTime(&date)) || + NS_FAILED(file->GetNativeLeafName(name)) || + !aWorkingSet->FindDirectoryOfFile(file, &dir)) + { + return PR_FALSE; + } + + LOG_AUTOREG((" finding interfaces in file: %s\n", name.get())); + + xptiFile fileRecord; + fileRecord = xptiFile(nsInt64(size), nsInt64(date), dir, + name.get(), aWorkingSet); + +// printf("* found %s\n", fileRecord.GetName()); + + + if(xptiFileType::IsXPT(fileRecord.GetName())) + { + XPTHeader* header = ReadXPTFile(file, aWorkingSet); + if(!header) + { + // XXX do something! + NS_ERROR("Unable to read an XPT file, turn logging on to see which file"); + LOG_AUTOREG((" unable to read file\n")); + continue; + } + + xptiTypelib typelibRecord; + typelibRecord.Init(aWorkingSet->GetFileCount()); + + PRBool AddedFile = PR_FALSE; + + if(header->major_version >= XPT_MAJOR_INCOMPATIBLE_VERSION) + { + NS_ASSERTION(!header->num_interfaces,"bad libxpt"); + LOG_AUTOREG((" file is version %d.%d Type file of version %d.0 or higher can not be read.\n", (int)header->major_version, (int)header->minor_version, (int)XPT_MAJOR_INCOMPATIBLE_VERSION)); + } + + for(PRUint16 k = 0; k < header->num_interfaces; k++) + { + xptiInterfaceEntry* entry = nsnull; + + if(!VerifyAndAddEntryIfNew(aWorkingSet, + header->interface_directory + k, + typelibRecord, + &entry)) + return PR_FALSE; + + if(!entry) + continue; + + // If this is the first interface we found for this file then + // setup the fileRecord for the header and infos. + if(!AddedFile) + { + if(!fileRecord.SetHeader(header, aWorkingSet)) + { + // XXX that would be bad. + return PR_FALSE; + } + AddedFile = PR_TRUE; + } + fileRecord.GetGuts()->SetEntryAt(k, entry); + } + + // This will correspond to typelibRecord above. + aWorkingSet->AppendFile(fileRecord); + } + + else + { + nsCOMPtr loader = + do_GetService(NS_ZIPLOADER_CONTRACTID); + + if (loader) { + nsresult rv; + + nsCOMPtr sink = + new xptiZipLoaderSink(this, aWorkingSet); + if (!sink) + return PR_FALSE; + + rv = loader->EnumerateEntries(file, sink); + if (NS_FAILED(rv)) + return PR_FALSE; + // This will correspond to typelibRecord used in + // xptiInterfaceInfoManager::FoundEntry. + aWorkingSet->AppendFile(fileRecord); + } else { + NS_WARNING("Could not load XPT Zip loader"); + } + } + } + return PR_TRUE; +} + +NS_IMPL_ISUPPORTS1(xptiZipLoaderSink, nsIXPTLoaderSink) + +// implement nsIXPTLoader +NS_IMETHODIMP +xptiZipLoaderSink::FoundEntry(const char* entryName, + PRInt32 index, + nsIInputStream *aStream) +{ + XPTHeader *header = + xptiZipLoader::ReadXPTFileFromInputStream(aStream, mWorkingSet); + if (!header) + return NS_ERROR_OUT_OF_MEMORY; + + if (!mManager->FoundZipEntry(entryName, index, header, mWorkingSet)) + return NS_ERROR_FAILURE; + + return NS_OK; +} + +// implement xptiEntrySink +PRBool +xptiInterfaceInfoManager::FoundZipEntry(const char* entryName, + int index, + XPTHeader* header, + xptiWorkingSet* aWorkingSet) +{ + + NS_ASSERTION(entryName, "loser!"); + NS_ASSERTION(header, "loser!"); + NS_ASSERTION(aWorkingSet, "loser!"); + + int countOfInterfacesAddedForItem = 0; + xptiZipItem zipItemRecord(entryName, aWorkingSet); + + LOG_AUTOREG((" finding interfaces in file: %s\n", entryName)); + + if(header->major_version >= XPT_MAJOR_INCOMPATIBLE_VERSION) + { + NS_ASSERTION(!header->num_interfaces,"bad libxpt"); + LOG_AUTOREG((" file is version %d.%d. Type file of version %d.0 or higher can not be read.\n", (int)header->major_version, (int)header->minor_version, (int)XPT_MAJOR_INCOMPATIBLE_VERSION)); + } + + if(!header->num_interfaces) + { + // We are not interested in files without interfaces. + return PR_TRUE; + } + + xptiTypelib typelibRecord; + typelibRecord.Init(aWorkingSet->GetFileCount(), + aWorkingSet->GetZipItemCount()); + + for(PRUint16 k = 0; k < header->num_interfaces; k++) + { + xptiInterfaceEntry* entry = nsnull; + + if(!VerifyAndAddEntryIfNew(aWorkingSet, + header->interface_directory + k, + typelibRecord, + &entry)) + return PR_FALSE; + + if(!entry) + continue; + + // If this is the first interface we found for this item + // then setup the zipItemRecord for the header and infos. + if(!countOfInterfacesAddedForItem) + { + // XXX fix this! + if(!zipItemRecord.SetHeader(header, aWorkingSet)) + { + // XXX that would be bad. + return PR_FALSE; + } + } + + // zipItemRecord.GetGuts()->SetEntryAt(k, entry); + ++countOfInterfacesAddedForItem; + } + + if(countOfInterfacesAddedForItem) + { + if(!aWorkingSet->GetZipItemFreeSpace()) + { + if(!aWorkingSet->ExtendZipItemArray( + aWorkingSet->GetZipItemCount() + 20)) + { + // out of space! + return PR_FALSE; + } + } + aWorkingSet->AppendZipItem(zipItemRecord); + } + return PR_TRUE; +} + +PRBool +xptiInterfaceInfoManager::VerifyAndAddEntryIfNew(xptiWorkingSet* aWorkingSet, + XPTInterfaceDirectoryEntry* iface, + const xptiTypelib& typelibRecord, + xptiInterfaceEntry** entryAdded) +{ + NS_ASSERTION(iface, "loser!"); + NS_ASSERTION(entryAdded, "loser!"); + + *entryAdded = nsnull; + + if(!iface->interface_descriptor) + { + // Not resolved, ignore this one. + // XXX full logging might note this... + return PR_TRUE; + } + + xptiHashEntry* hashEntry = (xptiHashEntry*) + PL_DHashTableOperate(aWorkingSet->mIIDTable, &iface->iid, PL_DHASH_LOOKUP); + + xptiInterfaceEntry* entry = + PL_DHASH_ENTRY_IS_FREE(hashEntry) ? nsnull : hashEntry->value; + + if(entry) + { + // XXX validate this info to find possible inconsistencies + LOG_AUTOREG((" ignoring repeated interface: %s\n", iface->name)); + return PR_TRUE; + } + + // Build a new xptiInterfaceEntry object and hook it up. + + entry = xptiInterfaceEntry::NewEntry(iface->name, strlen(iface->name), + iface->iid, + typelibRecord, aWorkingSet); + if(!entry) + { + // XXX bad! + return PR_FALSE; + } + + //XXX We should SetHeader too as part of the validation, no? + entry->SetScriptableFlag(XPT_ID_IS_SCRIPTABLE(iface->interface_descriptor->flags)); + + // Add our entry to the iid hashtable. + + hashEntry = (xptiHashEntry*) + PL_DHashTableOperate(aWorkingSet->mNameTable, + entry->GetTheName(), PL_DHASH_ADD); + if(hashEntry) + hashEntry->value = entry; + + // Add our entry to the name hashtable. + + hashEntry = (xptiHashEntry*) + PL_DHashTableOperate(aWorkingSet->mIIDTable, + entry->GetTheIID(), PL_DHASH_ADD); + if(hashEntry) + hashEntry->value = entry; + + *entryAdded = entry; + + LOG_AUTOREG((" added interface: %s\n", iface->name)); + + return PR_TRUE; +} + +// local struct used to pass two pointers as one pointer +struct TwoWorkingSets +{ + TwoWorkingSets(xptiWorkingSet* src, xptiWorkingSet* dest) + : aSrcWorkingSet(src), aDestWorkingSet(dest) {} + + xptiWorkingSet* aSrcWorkingSet; + xptiWorkingSet* aDestWorkingSet; +}; + +PR_STATIC_CALLBACK(PLDHashOperator) +xpti_Merger(PLDHashTable *table, PLDHashEntryHdr *hdr, + PRUint32 number, void *arg) +{ + xptiInterfaceEntry* srcEntry = ((xptiHashEntry*)hdr)->value; + xptiWorkingSet* aSrcWorkingSet = ((TwoWorkingSets*)arg)->aSrcWorkingSet; + xptiWorkingSet* aDestWorkingSet = ((TwoWorkingSets*)arg)->aDestWorkingSet; + + xptiHashEntry* hashEntry = (xptiHashEntry*) + PL_DHashTableOperate(aDestWorkingSet->mIIDTable, + srcEntry->GetTheIID(), PL_DHASH_LOOKUP); + + xptiInterfaceEntry* destEntry = + PL_DHASH_ENTRY_IS_FREE(hashEntry) ? nsnull : hashEntry->value; + + if(destEntry) + { + // Let's see if this is referring to the same exact typelib + + const char* destFilename = + aDestWorkingSet->GetTypelibFileName(destEntry->GetTypelibRecord()); + + const char* srcFilename = + aSrcWorkingSet->GetTypelibFileName(srcEntry->GetTypelibRecord()); + + if(0 == PL_strcmp(destFilename, srcFilename) && + (destEntry->GetTypelibRecord().GetZipItemIndex() == + srcEntry->GetTypelibRecord().GetZipItemIndex())) + { + // This is the same item. + // But... Let's make sure they didn't change the interface name. + // There are wacky developers that do stuff like that! + if(0 == PL_strcmp(destEntry->GetTheName(), srcEntry->GetTheName())) + return PL_DHASH_NEXT; + } + } + + // Clone the xptiInterfaceEntry into our destination WorkingSet. + + xptiTypelib typelibRecord; + + uint16 fileIndex = srcEntry->GetTypelibRecord().GetFileIndex(); + uint16 zipItemIndex = srcEntry->GetTypelibRecord().GetZipItemIndex(); + + fileIndex += aDestWorkingSet->mFileMergeOffsetMap[fileIndex]; + + // If it is not a zipItem, then the original index is fine. + if(srcEntry->GetTypelibRecord().IsZip()) + zipItemIndex += aDestWorkingSet->mZipItemMergeOffsetMap[zipItemIndex]; + + typelibRecord.Init(fileIndex, zipItemIndex); + + destEntry = xptiInterfaceEntry::NewEntry(*srcEntry, typelibRecord, + aDestWorkingSet); + if(!destEntry) + { + // XXX bad! should log + return PL_DHASH_NEXT; + } + + + // Add our entry to the iid hashtable. + + hashEntry = (xptiHashEntry*) + PL_DHashTableOperate(aDestWorkingSet->mNameTable, + destEntry->GetTheName(), PL_DHASH_ADD); + if(hashEntry) + hashEntry->value = destEntry; + + // Add our entry to the name hashtable. + + hashEntry = (xptiHashEntry*) + PL_DHashTableOperate(aDestWorkingSet->mIIDTable, + destEntry->GetTheIID(), PL_DHASH_ADD); + if(hashEntry) + hashEntry->value = destEntry; + + return PL_DHASH_NEXT; +} + +PRBool +xptiInterfaceInfoManager::MergeWorkingSets(xptiWorkingSet* aDestWorkingSet, + xptiWorkingSet* aSrcWorkingSet) +{ + + PRUint32 i; + + // Combine file lists. + + PRUint32 originalFileCount = aDestWorkingSet->GetFileCount(); + PRUint32 additionalFileCount = aSrcWorkingSet->GetFileCount(); + + // Create a new array big enough to hold both lists and copy existing files + + if(additionalFileCount) + { + if(!aDestWorkingSet->ExtendFileArray(originalFileCount + + additionalFileCount)) + return PR_FALSE; + + // Now we are where we started, but we know we have enough space. + + // Prepare offset array for later fixups. + // NOTE: Storing with dest, but alloc'ing from src. This is intentional. + aDestWorkingSet->mFileMergeOffsetMap = (PRUint32*) + XPT_CALLOC(aSrcWorkingSet->GetStructArena(), + additionalFileCount * sizeof(PRUint32)); + if(!aDestWorkingSet->mFileMergeOffsetMap) + return PR_FALSE; + } + + for(i = 0; i < additionalFileCount; ++i) + { + xptiFile& srcFile = aSrcWorkingSet->GetFileAt(i); + PRUint32 k; + for(k = 0; k < originalFileCount; ++k) + { + // If file (with same name, date, and time) is in both lists + // then reuse that record. + xptiFile& destFile = aDestWorkingSet->GetFileAt(k); + if(srcFile.Equals(destFile)) + { + aDestWorkingSet->mFileMergeOffsetMap[i] = k - i; + break; + } + } + if(k == originalFileCount) + { + // No match found, tack it on the end. + + PRUint32 newIndex = aDestWorkingSet->GetFileCount(); + + aDestWorkingSet->AppendFile(xptiFile(srcFile, aDestWorkingSet)); + + // Fixup the merge offset map. + aDestWorkingSet->mFileMergeOffsetMap[i] = newIndex - i; + } + } + + // Combine ZipItem lists. + + PRUint32 originalZipItemCount = aDestWorkingSet->GetZipItemCount(); + PRUint32 additionalZipItemCount = aSrcWorkingSet->GetZipItemCount(); + + // Create a new array big enough to hold both lists and copy existing ZipItems + + if(additionalZipItemCount) + { + if(!aDestWorkingSet->ExtendZipItemArray(originalZipItemCount + + additionalZipItemCount)) + return PR_FALSE; + + // Now we are where we started, but we know we have enough space. + + // Prepare offset array for later fixups. + // NOTE: Storing with dest, but alloc'ing from src. This is intentional. + aDestWorkingSet->mZipItemMergeOffsetMap = (PRUint32*) + XPT_CALLOC(aSrcWorkingSet->GetStructArena(), + additionalZipItemCount * sizeof(PRUint32)); + if(!aDestWorkingSet->mZipItemMergeOffsetMap) + return PR_FALSE; + } + + for(i = 0; i < additionalZipItemCount; ++i) + { + xptiZipItem& srcZipItem = aSrcWorkingSet->GetZipItemAt(i); + PRUint32 k; + for(k = 0; k < originalZipItemCount; ++k) + { + // If ZipItem (with same name) is in both lists + // then reuse that record. + xptiZipItem& destZipItem = aDestWorkingSet->GetZipItemAt(k); + if(srcZipItem.Equals(destZipItem)) + { + aDestWorkingSet->mZipItemMergeOffsetMap[i] = k - i; + break; + } + } + if(k == originalZipItemCount) + { + // No match found, tack it on the end. + + PRUint32 newIndex = aDestWorkingSet->GetZipItemCount(); + + aDestWorkingSet->AppendZipItem( + xptiZipItem(srcZipItem, aDestWorkingSet)); + + // Fixup the merge offset map. + aDestWorkingSet->mZipItemMergeOffsetMap[i] = newIndex - i; + } + } + + // Migrate xptiInterfaceInfos + + TwoWorkingSets sets(aSrcWorkingSet, aDestWorkingSet); + + PL_DHashTableEnumerate(aSrcWorkingSet->mNameTable, xpti_Merger, &sets); + + return PR_TRUE; +} + +PRBool +xptiInterfaceInfoManager::DEBUG_DumpFileList(nsISupportsArray* aFileList) +{ + PRUint32 count; + + if(NS_FAILED(aFileList->Count(&count))) + return PR_FALSE; + + for(PRUint32 i = 0; i < count; i++) + { + nsCOMPtr file; + aFileList->QueryElementAt(i, NS_GET_IID(nsILocalFile), getter_AddRefs(file)); + if(!file) + return PR_FALSE; + + nsCAutoString name; + if(NS_FAILED(file->GetNativeLeafName(name))) + return PR_FALSE; + + printf("* found %s\n", name.get()); + } + return PR_TRUE; +} + +PRBool +xptiInterfaceInfoManager::DEBUG_DumpFileListInWorkingSet(xptiWorkingSet* aWorkingSet) +{ + for(PRUint16 i = 0; i < aWorkingSet->GetFileCount(); ++i) + { + xptiFile& record = aWorkingSet->GetFileAt(i); + + printf("! has %s\n", record.GetName()); + } + return PR_TRUE; +} + +PRBool +xptiInterfaceInfoManager::DEBUG_DumpFileArray(nsILocalFile** aFileArray, + PRUint32 count) +{ + // dump the sorted list + for(PRUint32 i = 0; i < count; ++i) + { + nsILocalFile* file = aFileArray[i]; + + nsCAutoString name; + if(NS_FAILED(file->GetNativeLeafName(name))) + return PR_FALSE; + + printf("found file: %s\n", name.get()); + } + return PR_TRUE; +} + +/***************************************************************************/ + +// static +void +xptiInterfaceInfoManager::WriteToLog(const char *fmt, ...) +{ + if(!gInterfaceInfoManager) + return; + + PRFileDesc* fd = gInterfaceInfoManager->GetOpenLogFile(); + if(fd) + { + va_list ap; + va_start(ap, fmt); + PR_vfprintf(fd, fmt, ap); + va_end(ap); + } +} + +PR_STATIC_CALLBACK(PLDHashOperator) +xpti_ResolvedFileNameLogger(PLDHashTable *table, PLDHashEntryHdr *hdr, + PRUint32 number, void *arg) +{ + xptiInterfaceEntry* entry = ((xptiHashEntry*)hdr)->value; + xptiInterfaceInfoManager* mgr = (xptiInterfaceInfoManager*) arg; + + if(entry->IsFullyResolved()) + { + xptiWorkingSet* aWorkingSet = mgr->GetWorkingSet(); + PRFileDesc* fd = mgr->GetOpenLogFile(); + + const xptiTypelib& typelib = entry->GetTypelibRecord(); + const char* filename = + aWorkingSet->GetFileAt(typelib.GetFileIndex()).GetName(); + + if(typelib.IsZip()) + { + const char* zipItemName = + aWorkingSet->GetZipItemAt(typelib.GetZipItemIndex()).GetName(); + PR_fprintf(fd, "xpti used interface: %s from %s::%s\n", + entry->GetTheName(), filename, zipItemName); + } + else + { + PR_fprintf(fd, "xpti used interface: %s from %s\n", + entry->GetTheName(), filename); + } + } + return PL_DHASH_NEXT; +} + +void +xptiInterfaceInfoManager::LogStats() +{ + PRUint32 i; + + // This sets what will be returned by GetOpenLogFile(). + xptiAutoLog autoLog(this, mStatsLogFile, PR_FALSE); + + PRFileDesc* fd = GetOpenLogFile(); + if(!fd) + return; + + // Show names of xpt (only) files from which at least one interface + // was resolved. + + PRUint32 fileCount = mWorkingSet.GetFileCount(); + for(i = 0; i < fileCount; ++i) + { + xptiFile& f = mWorkingSet.GetFileAt(i); + if(f.GetGuts()) + PR_fprintf(fd, "xpti used file: %s\n", f.GetName()); + } + + PR_fprintf(fd, "\n"); + + // Show names of xptfiles loaded from zips from which at least + // one interface was resolved. + + PRUint32 zipItemCount = mWorkingSet.GetZipItemCount(); + for(i = 0; i < zipItemCount; ++i) + { + xptiZipItem& zi = mWorkingSet.GetZipItemAt(i); + if(zi.GetGuts()) + PR_fprintf(fd, "xpti used file from zip: %s\n", zi.GetName()); + } + + PR_fprintf(fd, "\n"); + + // Show name of each interface that was fully resolved and the name + // of the file and (perhaps) zip from which it was loaded. + + PL_DHashTableEnumerate(mWorkingSet.mNameTable, + xpti_ResolvedFileNameLogger, this); + +} + +/***************************************************************************/ + +// this is a private helper +static nsresult +EntryToInfo(xptiInterfaceEntry* entry, nsIInterfaceInfo **_retval) +{ + xptiInterfaceInfo* info; + nsresult rv; + + if(!entry) + { + *_retval = nsnull; + return NS_ERROR_FAILURE; + } + + rv = entry->GetInterfaceInfo(&info); + if(NS_FAILED(rv)) + return rv; + + // Transfer the AddRef done by GetInterfaceInfo. + *_retval = NS_STATIC_CAST(nsIInterfaceInfo*, info); + return NS_OK; +} + +/* nsIInterfaceInfo getInfoForIID (in nsIIDPtr iid); */ +NS_IMETHODIMP xptiInterfaceInfoManager::GetInfoForIID(const nsIID * iid, nsIInterfaceInfo **_retval) +{ + NS_ASSERTION(iid, "bad param"); + NS_ASSERTION(_retval, "bad param"); + + xptiHashEntry* hashEntry = (xptiHashEntry*) + PL_DHashTableOperate(mWorkingSet.mIIDTable, iid, PL_DHASH_LOOKUP); + + xptiInterfaceEntry* entry = + PL_DHASH_ENTRY_IS_FREE(hashEntry) ? nsnull : hashEntry->value; + + return EntryToInfo(entry, _retval); +} + +/* nsIInterfaceInfo getInfoForName (in string name); */ +NS_IMETHODIMP xptiInterfaceInfoManager::GetInfoForName(const char *name, nsIInterfaceInfo **_retval) +{ + NS_ASSERTION(name, "bad param"); + NS_ASSERTION(_retval, "bad param"); + + xptiHashEntry* hashEntry = (xptiHashEntry*) + PL_DHashTableOperate(mWorkingSet.mNameTable, name, PL_DHASH_LOOKUP); + + xptiInterfaceEntry* entry = + PL_DHASH_ENTRY_IS_FREE(hashEntry) ? nsnull : hashEntry->value; + + return EntryToInfo(entry, _retval); +} + +/* nsIIDPtr getIIDForName (in string name); */ +NS_IMETHODIMP xptiInterfaceInfoManager::GetIIDForName(const char *name, nsIID * *_retval) +{ + NS_ASSERTION(name, "bad param"); + NS_ASSERTION(_retval, "bad param"); + + xptiHashEntry* hashEntry = (xptiHashEntry*) + PL_DHashTableOperate(mWorkingSet.mNameTable, name, PL_DHASH_LOOKUP); + + xptiInterfaceEntry* entry = + PL_DHASH_ENTRY_IS_FREE(hashEntry) ? nsnull : hashEntry->value; + + if(!entry) + { + *_retval = nsnull; + return NS_ERROR_FAILURE; + } + + return entry->GetIID(_retval); +} + +/* string getNameForIID (in nsIIDPtr iid); */ +NS_IMETHODIMP xptiInterfaceInfoManager::GetNameForIID(const nsIID * iid, char **_retval) +{ + NS_ASSERTION(iid, "bad param"); + NS_ASSERTION(_retval, "bad param"); + + xptiHashEntry* hashEntry = (xptiHashEntry*) + PL_DHashTableOperate(mWorkingSet.mIIDTable, iid, PL_DHASH_LOOKUP); + + xptiInterfaceEntry* entry = + PL_DHASH_ENTRY_IS_FREE(hashEntry) ? nsnull : hashEntry->value; + + if(!entry) + { + *_retval = nsnull; + return NS_ERROR_FAILURE; + } + + return entry->GetName(_retval); +} + +PR_STATIC_CALLBACK(PLDHashOperator) +xpti_ArrayAppender(PLDHashTable *table, PLDHashEntryHdr *hdr, + PRUint32 number, void *arg) +{ + xptiInterfaceEntry* entry = ((xptiHashEntry*)hdr)->value; + nsISupportsArray* array = (nsISupportsArray*) arg; + + nsCOMPtr ii; + if(NS_SUCCEEDED(EntryToInfo(entry, getter_AddRefs(ii)))) + array->AppendElement(ii); + return PL_DHASH_NEXT; +} + +/* nsIEnumerator enumerateInterfaces (); */ +NS_IMETHODIMP xptiInterfaceInfoManager::EnumerateInterfaces(nsIEnumerator **_retval) +{ + // I didn't want to incur the size overhead of using nsHashtable just to + // make building an enumerator easier. So, this code makes a snapshot of + // the table using an nsISupportsArray and builds an enumerator for that. + // We can afford this transient cost. + + nsCOMPtr array; + NS_NewISupportsArray(getter_AddRefs(array)); + if(!array) + return NS_ERROR_UNEXPECTED; + + PL_DHashTableEnumerate(mWorkingSet.mNameTable, xpti_ArrayAppender, array); + + return array->Enumerate(_retval); +} + +struct ArrayAndPrefix +{ + nsISupportsArray* array; + const char* prefix; + PRUint32 length; +}; + +PR_STATIC_CALLBACK(PLDHashOperator) +xpti_ArrayPrefixAppender(PLDHashTable *table, PLDHashEntryHdr *hdr, + PRUint32 number, void *arg) +{ + xptiInterfaceEntry* entry = ((xptiHashEntry*)hdr)->value; + ArrayAndPrefix* args = (ArrayAndPrefix*) arg; + + const char* name = entry->GetTheName(); + if(name != PL_strnstr(name, args->prefix, args->length)) + return PL_DHASH_NEXT; + + nsCOMPtr ii; + if(NS_SUCCEEDED(EntryToInfo(entry, getter_AddRefs(ii)))) + args->array->AppendElement(ii); + return PL_DHASH_NEXT; +} + +/* nsIEnumerator enumerateInterfacesWhoseNamesStartWith (in string prefix); */ +NS_IMETHODIMP xptiInterfaceInfoManager::EnumerateInterfacesWhoseNamesStartWith(const char *prefix, nsIEnumerator **_retval) +{ + nsCOMPtr array; + NS_NewISupportsArray(getter_AddRefs(array)); + if(!array) + return NS_ERROR_UNEXPECTED; + + ArrayAndPrefix args = {array, prefix, PL_strlen(prefix)}; + PL_DHashTableEnumerate(mWorkingSet.mNameTable, xpti_ArrayPrefixAppender, &args); + + return array->Enumerate(_retval); +} + +/* void autoRegisterInterfaces (); */ +NS_IMETHODIMP xptiInterfaceInfoManager::AutoRegisterInterfaces() +{ + nsCOMPtr fileList; + AutoRegMode mode; + PRBool ok; + + nsAutoLock lock(xptiInterfaceInfoManager::GetAutoRegLock(this)); + + xptiWorkingSet workingSet(mSearchPath); + if(!workingSet.IsValid()) + return NS_ERROR_UNEXPECTED; + + // This sets what will be returned by GetOpenLogFile(). + xptiAutoLog autoLog(this, mAutoRegLogFile, PR_TRUE); + + LOG_AUTOREG(("start AutoRegister\n")); + + // We re-read the manifest rather than muck with the 'live' one. + // It is OK if this fails. + // XXX But we should track failure as a warning. + ok = xptiManifest::Read(this, &workingSet); + + LOG_AUTOREG(("read of manifest %s\n", ok ? "successful" : "FAILED")); + + // Grovel for all the typelibs we can find (in .xpt or .zip, .jar,...). + if(!BuildFileList(mSearchPath, getter_AddRefs(fileList)) || !fileList) + return NS_ERROR_UNEXPECTED; + + // DEBUG_DumpFileList(fileList); + + // Check to see how much work we need to do. + mode = DetermineAutoRegStrategy(mSearchPath, fileList, &workingSet); + + switch(mode) + { + case NO_FILES_CHANGED: + LOG_AUTOREG(("autoreg strategy: no files changed\n")); + LOG_AUTOREG(("successful end of AutoRegister\n")); + return NS_OK; + case FILES_ADDED_ONLY: + LOG_AUTOREG(("autoreg strategy: files added only\n")); + if(!AddOnlyNewFilesFromFileList(mSearchPath, fileList, &workingSet)) + { + LOG_AUTOREG(("FAILED to add new files\n")); + return NS_ERROR_UNEXPECTED; + } + break; + case FULL_VALIDATION_REQUIRED: + LOG_AUTOREG(("autoreg strategy: doing full validation merge\n")); + if(!DoFullValidationMergeFromFileList(mSearchPath, fileList, &workingSet)) + { + LOG_AUTOREG(("FAILED to do full validation\n")); + return NS_ERROR_UNEXPECTED; + } + break; + default: + NS_ERROR("switch missing a case"); + return NS_ERROR_UNEXPECTED; + } + + // Failure to write the manifest is not fatal in production builds. + // However, this would require the next startup to find and read all the + // xpt files. This will make that startup slower. If this ever becomes a + // chronic problem for anyone, then we'll want to figure out why! + + if(!xptiManifest::Write(this, &workingSet)) + { + LOG_AUTOREG(("FAILED to write manifest\n")); + NS_ERROR("Failed to write xpti manifest!"); + } + + if(!MergeWorkingSets(&mWorkingSet, &workingSet)) + { + LOG_AUTOREG(("FAILED to merge into live workingset\n")); + return NS_ERROR_UNEXPECTED; + } + +// DEBUG_DumpFileListInWorkingSet(mWorkingSet); + + LOG_AUTOREG(("successful end of AutoRegister\n")); + + return NS_OK; +} + +/***************************************************************************/ + +class xptiAdditionalManagersEnumerator : public nsISimpleEnumerator +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSISIMPLEENUMERATOR + + xptiAdditionalManagersEnumerator(); + + PRBool SizeTo(PRUint32 likelyCount) {return mArray.SizeTo(likelyCount);} + PRBool AppendElement(nsIInterfaceInfoManager* element); + +private: + ~xptiAdditionalManagersEnumerator() {} + + nsSupportsArray mArray; + PRUint32 mIndex; + PRUint32 mCount; +}; + +NS_IMPL_ISUPPORTS1(xptiAdditionalManagersEnumerator, nsISimpleEnumerator) + +xptiAdditionalManagersEnumerator::xptiAdditionalManagersEnumerator() + : mIndex(0), mCount(0) +{ +} + +PRBool xptiAdditionalManagersEnumerator::AppendElement(nsIInterfaceInfoManager* element) +{ + if(!mArray.AppendElement(NS_STATIC_CAST(nsISupports*, element))) + return PR_FALSE; + mCount++; + return PR_TRUE; +} + +/* boolean hasMoreElements (); */ +NS_IMETHODIMP xptiAdditionalManagersEnumerator::HasMoreElements(PRBool *_retval) +{ + *_retval = mIndex < mCount; + return NS_OK; +} + +/* nsISupports getNext (); */ +NS_IMETHODIMP xptiAdditionalManagersEnumerator::GetNext(nsISupports **_retval) +{ + if(!(mIndex < mCount)) + { + NS_ERROR("Bad nsISimpleEnumerator caller!"); + return NS_ERROR_FAILURE; + } + + *_retval = mArray.ElementAt(mIndex++); + return *_retval ? NS_OK : NS_ERROR_FAILURE; +} + +/***************************************************************************/ + +/* void addAdditionalManager (in nsIInterfaceInfoManager manager); */ +NS_IMETHODIMP xptiInterfaceInfoManager::AddAdditionalManager(nsIInterfaceInfoManager *manager) +{ + nsCOMPtr weakRef = do_GetWeakReference(manager); + nsISupports* ptrToAdd = weakRef ? + NS_STATIC_CAST(nsISupports*, weakRef) : + NS_STATIC_CAST(nsISupports*, manager); + { // scoped lock... + nsAutoLock lock(mAdditionalManagersLock); + PRInt32 index; + nsresult rv = mAdditionalManagers.GetIndexOf(ptrToAdd, &index); + if(NS_FAILED(rv) || -1 != index) + return NS_ERROR_FAILURE; + if(!mAdditionalManagers.AppendElement(ptrToAdd)) + return NS_ERROR_OUT_OF_MEMORY; + } + return NS_OK; +} + +/* void removeAdditionalManager (in nsIInterfaceInfoManager manager); */ +NS_IMETHODIMP xptiInterfaceInfoManager::RemoveAdditionalManager(nsIInterfaceInfoManager *manager) +{ + nsCOMPtr weakRef = do_GetWeakReference(manager); + nsISupports* ptrToRemove = weakRef ? + NS_STATIC_CAST(nsISupports*, weakRef) : + NS_STATIC_CAST(nsISupports*, manager); + { // scoped lock... + nsAutoLock lock(mAdditionalManagersLock); + if(!mAdditionalManagers.RemoveElement(ptrToRemove)) + return NS_ERROR_FAILURE; + } + return NS_OK; +} + +/* PRBool hasAdditionalManagers (); */ +NS_IMETHODIMP xptiInterfaceInfoManager::HasAdditionalManagers(PRBool *_retval) +{ + PRUint32 count; + nsresult rv = mAdditionalManagers.Count(&count); + *_retval = count != 0; + return rv; +} + +/* nsISimpleEnumerator enumerateAdditionalManagers (); */ +NS_IMETHODIMP xptiInterfaceInfoManager::EnumerateAdditionalManagers(nsISimpleEnumerator **_retval) +{ + nsAutoLock lock(mAdditionalManagersLock); + + PRUint32 count; + nsresult rv = mAdditionalManagers.Count(&count); + if(NS_FAILED(rv)) + return rv; + + nsCOMPtr enumerator = + new xptiAdditionalManagersEnumerator(); + if(!enumerator) + return NS_ERROR_OUT_OF_MEMORY; + + enumerator->SizeTo(count); + + for(PRUint32 i = 0; i < count; /* i incremented in the loop body */) + { + nsCOMPtr raw = + dont_AddRef(mAdditionalManagers.ElementAt(i++)); + if(!raw) + return NS_ERROR_FAILURE; + nsCOMPtr weakRef = do_QueryInterface(raw); + if(weakRef) + { + nsCOMPtr manager = + do_QueryReferent(weakRef); + if(manager) + { + if(!enumerator->AppendElement(manager)) + return NS_ERROR_FAILURE; + } + else + { + // The manager is no more. Remove the element. + if(!mAdditionalManagers.RemoveElementAt(--i)) + return NS_ERROR_FAILURE; + count--; + } + } + else + { + // We *know* we put a pointer to either a nsIWeakReference or + // an nsIInterfaceInfoManager into the array, so we can avoid an + // extra QI here and just do a cast. + if(!enumerator->AppendElement( + NS_REINTERPRET_CAST(nsIInterfaceInfoManager*, raw.get()))) + return NS_ERROR_FAILURE; + } + } + + NS_ADDREF(*_retval = enumerator); + return NS_OK; +} + +/***************************************************************************/ + +XPTI_PUBLIC_API(nsIInterfaceInfoManager*) +XPTI_GetInterfaceInfoManager() +{ + nsIInterfaceInfoManager* iim = + xptiInterfaceInfoManager::GetInterfaceInfoManagerNoAddRef(); + NS_IF_ADDREF(iim); + return iim; +} + +XPTI_PUBLIC_API(void) +XPTI_FreeInterfaceInfoManager() +{ + xptiInterfaceInfoManager::FreeInterfaceInfoManager(); +} + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiManifest.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiManifest.cpp new file mode 100644 index 00000000..03ab7029 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiManifest.cpp @@ -0,0 +1,710 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mike McCabe + * John Bandhauer + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Implementation of xptiManifest. */ + +#include "xptiprivate.h" +#include "nsManifestLineReader.h" +#include "nsString.h" + +static const char g_Disclaimer[] = "# Generated file. ** DO NOT EDIT! **"; + +static const char g_TOKEN_Files[] = "Files"; +static const char g_TOKEN_ArchiveItems[] = "ArchiveItems"; +static const char g_TOKEN_Interfaces[] = "Interfaces"; +static const char g_TOKEN_Header[] = "Header"; +static const char g_TOKEN_Version[] = "Version"; +static const char g_TOKEN_AppDir[] = "AppDir"; +static const char g_TOKEN_Directories[] = "Directories"; + +static const int g_VERSION_MAJOR = 2; +static const int g_VERSION_MINOR = 0; + +/***************************************************************************/ + +static PRBool +GetCurrentAppDirString(xptiInterfaceInfoManager* aMgr, nsACString &aStr) +{ + nsCOMPtr appDir; + aMgr->GetApplicationDir(getter_AddRefs(appDir)); + if(appDir) + return NS_SUCCEEDED(appDir->GetPersistentDescriptor(aStr)); + return PR_FALSE; +} + +static PRBool +CurrentAppDirMatchesPersistentDescriptor(xptiInterfaceInfoManager* aMgr, + const char *inStr) +{ + nsCOMPtr appDir; + aMgr->GetApplicationDir(getter_AddRefs(appDir)); + + nsCOMPtr descDir; + nsresult rv = NS_NewNativeLocalFile(EmptyCString(), PR_FALSE, getter_AddRefs(descDir)); + if(NS_FAILED(rv)) + return PR_FALSE; + + rv = descDir->SetPersistentDescriptor(nsDependentCString(inStr)); + if(NS_FAILED(rv)) + return PR_FALSE; + + PRBool matches; + rv = appDir->Equals(descDir, &matches); + return NS_SUCCEEDED(rv) && matches; +} + +PR_STATIC_CALLBACK(PLDHashOperator) +xpti_InterfaceWriter(PLDHashTable *table, PLDHashEntryHdr *hdr, + PRUint32 number, void *arg) +{ + xptiInterfaceEntry* entry = ((xptiHashEntry*)hdr)->value; + PRFileDesc* fd = (PRFileDesc*) arg; + + char* iidStr = entry->GetTheIID()->ToString(); + if(!iidStr) + return PL_DHASH_STOP; + + const xptiTypelib& typelib = entry->GetTypelibRecord(); + + PRBool success = PR_fprintf(fd, "%d,%s,%s,%d,%d,%d\n", + (int) number, + entry->GetTheName(), + iidStr, + (int) typelib.GetFileIndex(), + (int) (typelib.IsZip() ? + typelib.GetZipItemIndex() : -1), + (int) entry->GetScriptableFlag()); + + nsCRT::free(iidStr); + + return success ? PL_DHASH_NEXT : PL_DHASH_STOP; +} + + +// static +PRBool xptiManifest::Write(xptiInterfaceInfoManager* aMgr, + xptiWorkingSet* aWorkingSet) +{ + + PRBool succeeded = PR_FALSE; + PRFileDesc* fd = nsnull; + PRUint32 i; + PRUint32 size32; + PRIntn interfaceCount = 0; + nsCAutoString appDirString; + + nsCOMPtr tempFile; + if(!aMgr->GetCloneOfManifestLocation(getter_AddRefs(tempFile)) || !tempFile) + return PR_FALSE; + + nsCAutoString originalLeafName; + tempFile->GetNativeLeafName(originalLeafName); + + nsCAutoString leafName; + leafName.Assign(originalLeafName + NS_LITERAL_CSTRING(".tmp")); + + tempFile->SetNativeLeafName(leafName); + + // All exits via "goto out;" from here on... + if(NS_FAILED(tempFile-> + OpenNSPRFileDesc(PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE, + 0600, &fd)) || !fd) + { + goto out; + } + + // write file header comments + + if(!PR_fprintf(fd, "%s\n", g_Disclaimer)) + goto out; + + // write the [Header] block, version number, and appdir. + + if(!PR_fprintf(fd, "\n[%s,%d]\n", g_TOKEN_Header, 2)) + goto out; + + if(!PR_fprintf(fd, "%d,%s,%d,%d\n", + 0, g_TOKEN_Version, g_VERSION_MAJOR, g_VERSION_MINOR)) + goto out; + + GetCurrentAppDirString(aMgr, appDirString); + if(appDirString.IsEmpty()) + goto out; + + if(!PR_fprintf(fd, "%d,%s,%s\n", + 1, g_TOKEN_AppDir, appDirString.get())) + goto out; + + // write Directories list + + if(!PR_fprintf(fd, "\n[%s,%d]\n", + g_TOKEN_Directories, + (int) aWorkingSet->GetDirectoryCount())) + goto out; + + for(i = 0; i < aWorkingSet->GetDirectoryCount(); i++) + { + nsCOMPtr dir; + nsCAutoString str; + + aWorkingSet->GetDirectoryAt(i, getter_AddRefs(dir)); + if(!dir) + goto out; + + dir->GetPersistentDescriptor(str); + if(str.IsEmpty()) + goto out; + + if(!PR_fprintf(fd, "%d,%s\n", (int) i, str.get())) + goto out; + } + + // write Files list + + if(!PR_fprintf(fd, "\n[%s,%d]\n", + g_TOKEN_Files, + (int) aWorkingSet->GetFileCount())) + goto out; + + for(i = 0; i < aWorkingSet->GetFileCount(); i++) + { + const xptiFile& file = aWorkingSet->GetFileAt(i); + + LL_L2UI(size32, file.GetSize()); + + if(!PR_fprintf(fd, "%d,%s,%d,%u,%lld\n", + (int) i, + file.GetName(), + (int) file.GetDirectory(), + size32, PRInt64(file.GetDate()))) + goto out; + } + + // write ArchiveItems list + + if(!PR_fprintf(fd, "\n[%s,%d]\n", + g_TOKEN_ArchiveItems, + (int) aWorkingSet->GetZipItemCount())) + goto out; + + for(i = 0; i < aWorkingSet->GetZipItemCount(); i++) + { + if(!PR_fprintf(fd, "%d,%s\n", + (int) i, + aWorkingSet->GetZipItemAt(i).GetName())) + goto out; + } + + // write the Interfaces list + + interfaceCount = aWorkingSet->mNameTable->entryCount; + + if(!PR_fprintf(fd, "\n[%s,%d]\n", + g_TOKEN_Interfaces, + (int) interfaceCount)) + goto out; + + if(interfaceCount != (PRIntn) + PL_DHashTableEnumerate(aWorkingSet->mNameTable, + xpti_InterfaceWriter, fd)) + goto out; + + + if(PR_SUCCESS == PR_Close(fd)) + { + succeeded = PR_TRUE; + } + fd = nsnull; + +out: + if(fd) + PR_Close(fd); + + if(succeeded) + { + // delete the old file and rename this + nsCOMPtr mainFile; + if(!aMgr->GetCloneOfManifestLocation(getter_AddRefs(mainFile)) || !mainFile) + return PR_FALSE; + + PRBool exists; + if(NS_FAILED(mainFile->Exists(&exists))) + return PR_FALSE; + + if(exists && NS_FAILED(mainFile->Remove(PR_FALSE))) + return PR_FALSE; + + nsCOMPtr parent; + mainFile->GetParent(getter_AddRefs(parent)); + + // MoveTo means rename. + if(NS_FAILED(tempFile->MoveToNative(parent, originalLeafName))) + return PR_FALSE; + } + + return succeeded; +} + +/***************************************************************************/ +/***************************************************************************/ + +static char* +ReadManifestIntoMemory(xptiInterfaceInfoManager* aMgr, + PRUint32* pLength) +{ + PRFileDesc* fd = nsnull; + PRInt32 flen; + PRInt64 fileSize; + char* whole = nsnull; + PRBool success = PR_FALSE; + + nsCOMPtr aFile; + if(!aMgr->GetCloneOfManifestLocation(getter_AddRefs(aFile)) || !aFile) + return nsnull; + +#ifdef DEBUG + { + static PRBool shown = PR_FALSE; + + nsCAutoString path; + if(!shown && NS_SUCCEEDED(aFile->GetNativePath(path)) && !path.IsEmpty()) + { + fprintf(stderr, "Type Manifest File: %s\n", path.get()); + shown = PR_TRUE; + } + } +#endif + + if(NS_FAILED(aFile->GetFileSize(&fileSize)) || !(flen = nsInt64(fileSize))) + return nsnull; + + whole = new char[flen]; + if (!whole) + return nsnull; + + // All exits from on here should be via 'goto out' + + if(NS_FAILED(aFile->OpenNSPRFileDesc(PR_RDONLY, 0444, &fd)) || !fd) + goto out; + + if(flen > PR_Read(fd, whole, flen)) + goto out; + + success = PR_TRUE; + + out: + if(fd) + PR_Close(fd); + + if(!success) + { + delete [] whole; + return nsnull; + } + + *pLength = flen; + return whole; +} + +static +PRBool ReadSectionHeader(nsManifestLineReader& reader, + const char *token, int minCount, int* count) +{ + while(1) + { + if(!reader.NextLine()) + break; + if(*reader.LinePtr() == '[') + { + char* p = reader.LinePtr() + (reader.LineLength() - 1); + if(*p != ']') + break; + *p = 0; + + char* values[2]; + int lengths[2]; + if(2 != reader.ParseLine(values, lengths, 2)) + break; + + // ignore the leading '[' + if(0 != PL_strcmp(values[0]+1, token)) + break; + + if((*count = atoi(values[1])) < minCount) + break; + + return PR_TRUE; + } + } + return PR_FALSE; +} + + +// static +PRBool xptiManifest::Read(xptiInterfaceInfoManager* aMgr, + xptiWorkingSet* aWorkingSet) +{ + int i; + char* whole = nsnull; + PRBool succeeded = PR_FALSE; + PRUint32 flen = 0; + nsManifestLineReader reader; + xptiHashEntry* hashEntry; + int headerCount = 0; + int dirCount = 0; + int fileCount = 0; + int zipItemCount = -1; + int interfaceCount = 0; + int dir; + int flags; + char* values[6]; // 6 is currently the max items we need to parse + int lengths[6]; + PRUint32 size32; + PRInt64 size; + PRInt64 date; + + whole = ReadManifestIntoMemory(aMgr, &flen); + if(!whole) + return PR_FALSE; + + reader.Init(whole, flen); + + // All exits from here on should be via 'goto out' + + // Look for "Header" section + + // This version accepts only version 1,0. We also freak if the header + // has more than one entry. The rationale is that we want to force an + // autoreg if the xpti.dat file was written by *any* other version of + // the software. Future versions may wish to support updating older + // manifests in some interesting way. + + if(!ReadSectionHeader(reader, g_TOKEN_Header, 2, &headerCount)) + goto out; + + if(headerCount != 2) + goto out; + + // Verify the version number + + if(!reader.NextLine()) + goto out; + + // index,VersionLiteral,major,minor + if(4 != reader.ParseLine(values, lengths, 4)) + goto out; + + // index + if(0 != atoi(values[0])) + goto out; + + // VersionLiteral + if(0 != PL_strcmp(values[1], g_TOKEN_Version)) + goto out; + + // major + if(g_VERSION_MAJOR != atoi(values[2])) + goto out; + + // minor + if(g_VERSION_MINOR != atoi(values[3])) + goto out; + + // Verify the application directory + + if(!reader.NextLine()) + goto out; + + // index,AppDirLiteral,directoryname + if(3 != reader.ParseLine(values, lengths, 3)) + goto out; + + // index + if(1 != atoi(values[0])) + goto out; + + // AppDirLiteral + if(0 != PL_strcmp(values[1], g_TOKEN_AppDir)) + goto out; + + if(!CurrentAppDirMatchesPersistentDescriptor(aMgr, values[2])) + goto out; + + // Look for "Directories" section + + if(!ReadSectionHeader(reader, g_TOKEN_Directories, 1, &dirCount)) + goto out; + else + { + // To validate that the directory list matches the current search path + // we first confirm that the list lengths match. + + nsCOMPtr searchPath; + aMgr->GetSearchPath(getter_AddRefs(searchPath)); + + PRUint32 searchPathCount; + searchPath->Count(&searchPathCount); + + if(dirCount != (int) searchPathCount) + goto out; + } + + // Read the directory records + + for(i = 0; i < dirCount; ++i) + { + if(!reader.NextLine()) + goto out; + + // index,directoryname + if(2 != reader.ParseLine(values, lengths, 2)) + goto out; + + // index + if(i != atoi(values[0])) + goto out; + + // directoryname + if(!aWorkingSet->DirectoryAtMatchesPersistentDescriptor(i, values[1])) + goto out; + } + + // Look for "Files" section + + if(!ReadSectionHeader(reader, g_TOKEN_Files, 1, &fileCount)) + goto out; + + + // Alloc room in the WorkingSet for the filearray. + + if(!aWorkingSet->NewFileArray(fileCount)) + goto out; + + // Read the file records + + for(i = 0; i < fileCount; ++i) + { + if(!reader.NextLine()) + goto out; + + // index,filename,dirIndex,dilesSize,filesDate + if(5 != reader.ParseLine(values, lengths, 5)) + goto out; + + // index + if(i != atoi(values[0])) + goto out; + + // filename + if(!*values[1]) + goto out; + + // dirIndex + dir = atoi(values[2]); + if(dir < 0 || dir > dirCount) + goto out; + + // fileSize + size32 = atoi(values[3]); + if(size32 <= 0) + goto out; + LL_UI2L(size, size32); + + // fileDate + date = nsCRT::atoll(values[4]); + if(LL_IS_ZERO(date)) + goto out; + + // Append a new file record to the array. + + aWorkingSet->AppendFile( + xptiFile(nsInt64(size), nsInt64(date), dir, values[1], aWorkingSet)); + } + + // Look for "ZipItems" section + + if(!ReadSectionHeader(reader, g_TOKEN_ArchiveItems, 0, &zipItemCount)) + goto out; + + // Alloc room in the WorkingSet for the zipItemarray. + + if(zipItemCount) + if(!aWorkingSet->NewZipItemArray(zipItemCount)) + goto out; + + // Read the zipItem records + + for(i = 0; i < zipItemCount; ++i) + { + if(!reader.NextLine()) + goto out; + + // index,filename + if(2 != reader.ParseLine(values, lengths, 2)) + goto out; + + // index + if(i != atoi(values[0])) + goto out; + + // filename + if(!*values[1]) + goto out; + + // Append a new zipItem record to the array. + + aWorkingSet->AppendZipItem(xptiZipItem(values[1], aWorkingSet)); + } + + // Look for "Interfaces" section + + if(!ReadSectionHeader(reader, g_TOKEN_Interfaces, 1, &interfaceCount)) + goto out; + + // Read the interface records + + for(i = 0; i < interfaceCount; ++i) + { + int fileIndex; + int zipItemIndex; + nsIID iid; + xptiInterfaceEntry* entry; + xptiTypelib typelibRecord; + + if(!reader.NextLine()) + goto out; + + // index,interfaceName,iid,fileIndex,zipIndex,flags + if(6 != reader.ParseLine(values, lengths, 6)) + goto out; + + // index + if(i != atoi(values[0])) + goto out; + + // interfaceName + if(!*values[1]) + goto out; + + // iid + if(!iid.Parse(values[2])) + goto out; + + // fileIndex + fileIndex = atoi(values[3]); + if(fileIndex < 0 || fileIndex >= fileCount) + goto out; + + // zipIndex (NOTE: -1 is a valid value) + zipItemIndex = atoi(values[4]); + if(zipItemIndex < -1 || zipItemIndex >= zipItemCount) + goto out; + + // flags + flags = atoi(values[5]); + if(flags != 0 && flags != 1) + goto out; + + // Build an InterfaceInfo and hook it in. + + if(zipItemIndex == -1) + typelibRecord.Init(fileIndex); + else + typelibRecord.Init(fileIndex, zipItemIndex); + + entry = xptiInterfaceEntry::NewEntry(values[1], lengths[1], + iid, typelibRecord, + aWorkingSet); + if(!entry) + goto out; + + entry->SetScriptableFlag(flags==1); + + // Add our entry to the iid hashtable. + + hashEntry = (xptiHashEntry*) + PL_DHashTableOperate(aWorkingSet->mNameTable, + entry->GetTheName(), PL_DHASH_ADD); + if(hashEntry) + hashEntry->value = entry; + + // Add our entry to the name hashtable. + + hashEntry = (xptiHashEntry*) + PL_DHashTableOperate(aWorkingSet->mIIDTable, + entry->GetTheIID(), PL_DHASH_ADD); + if(hashEntry) + hashEntry->value = entry; + } + + // success! + + succeeded = PR_TRUE; + + out: + if(whole) + delete [] whole; + + if(!succeeded) + { + // Cleanup the WorkingSet on failure. + aWorkingSet->InvalidateInterfaceInfos(); + aWorkingSet->ClearHashTables(); + aWorkingSet->ClearFiles(); + } + return succeeded; +} + +// static +PRBool xptiManifest::Delete(xptiInterfaceInfoManager* aMgr) +{ + nsCOMPtr aFile; + if(!aMgr->GetCloneOfManifestLocation(getter_AddRefs(aFile)) || !aFile) + return PR_FALSE; + + PRBool exists; + if(NS_FAILED(aFile->Exists(&exists))) + return PR_FALSE; + + if(exists && NS_FAILED(aFile->Remove(PR_FALSE))) + return PR_FALSE; + + return PR_TRUE; +} + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiMisc.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiMisc.cpp new file mode 100644 index 00000000..a1dbf5c3 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiMisc.cpp @@ -0,0 +1,164 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mike McCabe + * John Bandhauer + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Implementation of misc. xpti stuff. */ + +#include "xptiprivate.h" + +struct xptiFileTypeEntry +{ + const char* name; + int len; + xptiFileType::Type type; +}; + +static const xptiFileTypeEntry g_Entries[] = + { + {".xpt", 4, xptiFileType::XPT}, + {".zip", 4, xptiFileType::ZIP}, + {".jar", 4, xptiFileType::ZIP}, + {nsnull, 0, xptiFileType::UNKNOWN} + }; + +// static +xptiFileType::Type xptiFileType::GetType(const char* name) +{ + NS_ASSERTION(name, "loser!"); + int len = PL_strlen(name); + for(const xptiFileTypeEntry* p = g_Entries; p->name; p++) + { + if(len > p->len && 0 == PL_strcasecmp(p->name, &(name[len - p->len]))) + return p->type; + } + return UNKNOWN; +} + +/***************************************************************************/ + +MOZ_DECL_CTOR_COUNTER(xptiAutoLog) + +xptiAutoLog::xptiAutoLog(xptiInterfaceInfoManager* mgr, + nsILocalFile* logfile, PRBool append) + : mMgr(nsnull), mOldFileDesc(nsnull) +{ + MOZ_COUNT_CTOR(xptiAutoLog); + + if(mgr && logfile) + { + PRFileDesc* fd; + if(NS_SUCCEEDED(logfile-> + OpenNSPRFileDesc(PR_WRONLY | PR_CREATE_FILE | PR_APPEND | + (append ? 0 : PR_TRUNCATE), + 0600, &fd)) && fd) + { +#ifdef DEBUG + m_DEBUG_FileDesc = fd; +#endif + mMgr = mgr; + mOldFileDesc = mMgr->SetOpenLogFile(fd); + if(append) + PR_Seek(fd, 0, PR_SEEK_END); + WriteTimestamp(fd, "++++ start logging "); + + } + else + { +#ifdef DEBUG + printf("xpti failed to open log file for writing\n"); +#endif + } + } +} + +xptiAutoLog::~xptiAutoLog() +{ + MOZ_COUNT_DTOR(xptiAutoLog); + + if(mMgr) + { + PRFileDesc* fd = mMgr->SetOpenLogFile(mOldFileDesc); + NS_ASSERTION(fd == m_DEBUG_FileDesc, "bad unravel"); + if(fd) + { + WriteTimestamp(fd, "---- end logging "); + PR_Close(fd); + } + } +} + +void xptiAutoLog::WriteTimestamp(PRFileDesc* fd, const char* msg) +{ + PRExplodedTime expTime; + PR_ExplodeTime(PR_Now(), PR_LocalTimeParameters, &expTime); + char time[128]; + PR_FormatTimeUSEnglish(time, 128, "%Y-%m-%d-%H:%M:%S", &expTime); + PR_fprintf(fd, "\n%s %s\n\n", msg, time); +} + +/***************************************************************************/ + +nsresult +xptiCloneLocalFile(nsILocalFile* aLocalFile, + nsILocalFile** aCloneLocalFile) +{ + nsresult rv; + nsCOMPtr cloneRaw; + + rv = aLocalFile->Clone(getter_AddRefs(cloneRaw)); + if(NS_FAILED(rv)) + return rv; + + return CallQueryInterface(cloneRaw, aCloneLocalFile); +} + + +nsresult +xptiCloneElementAsLocalFile(nsISupportsArray* aArray, PRUint32 aIndex, + nsILocalFile** aLocalFile) +{ + nsresult rv; + nsCOMPtr original; + + rv = aArray->QueryElementAt(aIndex, NS_GET_IID(nsILocalFile), + getter_AddRefs(original)); + if(NS_FAILED(rv)) + return rv; + + return xptiCloneLocalFile(original, aLocalFile); +} diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiTypelibGuts.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiTypelibGuts.cpp new file mode 100644 index 00000000..50956585 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiTypelibGuts.cpp @@ -0,0 +1,63 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mike McCabe + * John Bandhauer + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Implementation of xptiTypelibGuts. */ + +#include "xptiprivate.h" + +// static +xptiTypelibGuts* +xptiTypelibGuts::NewGuts(XPTHeader* aHeader, + xptiWorkingSet* aWorkingSet) +{ + NS_ASSERTION(aHeader, "bad param"); + void* place = XPT_MALLOC(aWorkingSet->GetStructArena(), + sizeof(xptiTypelibGuts) + + (sizeof(xptiInterfaceEntry*) * + (aHeader->num_interfaces - 1))); + if(!place) + return nsnull; + return new(place) xptiTypelibGuts(aHeader); +} + +xptiTypelibGuts::xptiTypelibGuts(XPTHeader* aHeader) + : mHeader(aHeader) +{ + // empty +} diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiWorkingSet.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiWorkingSet.cpp new file mode 100644 index 00000000..b9602726 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiWorkingSet.cpp @@ -0,0 +1,432 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mike McCabe + * John Bandhauer + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Implementation of xptiWorkingSet. */ + +#include "xptiprivate.h" +#include "nsString.h" + +#define XPTI_STRING_ARENA_BLOCK_SIZE (1024 * 1) +#define XPTI_STRUCT_ARENA_BLOCK_SIZE (1024 * 1) +#define XPTI_HASHTABLE_SIZE 128 + +/***************************************************************************/ + +PR_STATIC_CALLBACK(const void*) +IIDGetKey(PLDHashTable *table, PLDHashEntryHdr *entry) +{ + return ((xptiHashEntry*)entry)->value->GetTheIID(); +} + +PR_STATIC_CALLBACK(PLDHashNumber) +IIDHash(PLDHashTable *table, const void *key) +{ + return (PLDHashNumber) ((const nsIID*)key)->m0; +} + +PR_STATIC_CALLBACK(PRBool) +IIDMatch(PLDHashTable *table, + const PLDHashEntryHdr *entry, + const void *key) +{ + const nsIID* iid1 = ((xptiHashEntry*)entry)->value->GetTheIID(); + const nsIID* iid2 = (const nsIID*)key; + + return iid1 == iid2 || iid1->Equals(*iid2); +} + +const static struct PLDHashTableOps IIDTableOps = +{ + PL_DHashAllocTable, + PL_DHashFreeTable, + IIDGetKey, + IIDHash, + IIDMatch, + PL_DHashMoveEntryStub, + PL_DHashClearEntryStub, + PL_DHashFinalizeStub +}; + +/***************************************************************************/ + +PR_STATIC_CALLBACK(const void*) +NameGetKey(PLDHashTable *table, PLDHashEntryHdr *entry) +{ + return ((xptiHashEntry*)entry)->value->GetTheName(); +} + +PR_STATIC_CALLBACK(PRBool) +NameMatch(PLDHashTable *table, + const PLDHashEntryHdr *entry, + const void *key) +{ + const char* str1 = ((xptiHashEntry*)entry)->value->GetTheName(); + const char* str2 = (const char*) key; + return str1 == str2 || 0 == PL_strcmp(str1, str2); +} + +static const struct PLDHashTableOps NameTableOps = +{ + PL_DHashAllocTable, + PL_DHashFreeTable, + NameGetKey, + PL_DHashStringKey, + NameMatch, + PL_DHashMoveEntryStub, + PL_DHashClearEntryStub, + PL_DHashFinalizeStub +}; + +/***************************************************************************/ + +MOZ_DECL_CTOR_COUNTER(xptiWorkingSet) + +xptiWorkingSet::xptiWorkingSet(nsISupportsArray* aDirectories) + : mFileCount(0), + mMaxFileCount(0), + mFileArray(nsnull), + mZipItemCount(0), + mMaxZipItemCount(0), + mZipItemArray(nsnull), + mStringArena(XPT_NewArena(XPTI_STRING_ARENA_BLOCK_SIZE, sizeof(char), + "xptiWorkingSet strings")), + mStructArena(XPT_NewArena(XPTI_STRUCT_ARENA_BLOCK_SIZE, sizeof(double), + "xptiWorkingSet structs")), + mDirectories(aDirectories), + mNameTable(PL_NewDHashTable(&NameTableOps, nsnull, sizeof(xptiHashEntry), + XPTI_HASHTABLE_SIZE)), + mIIDTable(PL_NewDHashTable(&IIDTableOps, nsnull, sizeof(xptiHashEntry), + XPTI_HASHTABLE_SIZE)), + mFileMergeOffsetMap(nsnull), + mZipItemMergeOffsetMap(nsnull) +{ + MOZ_COUNT_CTOR(xptiWorkingSet); + // do nothing else... +} + +PRBool +xptiWorkingSet::IsValid() const +{ + return (mFileCount == 0 || mFileArray) && + (mZipItemCount == 0 || mZipItemArray) && + mStringArena && + mStructArena && + mNameTable && + mIIDTable; +} + +PR_STATIC_CALLBACK(PLDHashOperator) +xpti_Remover(PLDHashTable *table, PLDHashEntryHdr *hdr, + PRUint32 number, void *arg) +{ + return PL_DHASH_REMOVE; +} + +PR_STATIC_CALLBACK(PLDHashOperator) +xpti_Invalidator(PLDHashTable *table, PLDHashEntryHdr *hdr, + PRUint32 number, void *arg) +{ + xptiInterfaceEntry* entry = ((xptiHashEntry*)hdr)->value; + entry->LockedInvalidateInterfaceInfo(); + return PL_DHASH_NEXT; +} + +void +xptiWorkingSet::InvalidateInterfaceInfos() +{ + if(mNameTable) + { + nsAutoMonitor lock(xptiInterfaceInfoManager::GetInfoMonitor()); + PL_DHashTableEnumerate(mNameTable, xpti_Invalidator, nsnull); + } +} + +void +xptiWorkingSet::ClearHashTables() +{ + if(mNameTable) + PL_DHashTableEnumerate(mNameTable, xpti_Remover, nsnull); + + if(mIIDTable) + PL_DHashTableEnumerate(mIIDTable, xpti_Remover, nsnull); +} + +void +xptiWorkingSet::ClearFiles() +{ + if(mFileArray) + delete [] mFileArray; + mFileArray = nsnull; + mMaxFileCount = 0; + mFileCount = 0; +} + +void +xptiWorkingSet::ClearZipItems() +{ + if(mZipItemArray) + delete [] mZipItemArray; + mZipItemArray = nsnull; + mMaxZipItemCount = 0; + mZipItemCount = 0; +} + +xptiWorkingSet::~xptiWorkingSet() +{ + MOZ_COUNT_DTOR(xptiWorkingSet); + + ClearFiles(); + ClearZipItems(); + ClearHashTables(); + + if(mNameTable) + PL_DHashTableDestroy(mNameTable); + + if(mIIDTable) + PL_DHashTableDestroy(mIIDTable); + + if(mFileArray) + delete [] mFileArray; + + if(mZipItemArray) + delete [] mZipItemArray; + + // Destroy arenas last in case they are referenced in other members' dtors. + + if(mStringArena) + { +#ifdef DEBUG + XPT_DumpStats(mStringArena); +#endif + XPT_DestroyArena(mStringArena); + } + + if(mStructArena) + { +#ifdef DEBUG + XPT_DumpStats(mStructArena); +#endif + XPT_DestroyArena(mStructArena); + } +} + +PRUint32 +xptiWorkingSet::FindFile(PRUint32 dir, const char* name) +{ + if(mFileArray) + { + for(PRUint32 i = 0; i < mFileCount;++i) + { + xptiFile& file = mFileArray[i]; + if(file.GetDirectory() == dir && + 0 == PL_strcmp(name, file.GetName())) + { + return i; + } + } + } + return NOT_FOUND; +} + +PRBool +xptiWorkingSet::NewFileArray(PRUint32 count) +{ + if(mFileArray) + delete [] mFileArray; + mFileCount = 0; + mFileArray = new xptiFile[count]; + if(!mFileArray) + { + mMaxFileCount = 0; + return PR_FALSE; + } + mMaxFileCount = count; + return PR_TRUE; +} + +PRBool +xptiWorkingSet::ExtendFileArray(PRUint32 count) +{ + if(mFileArray && count < mMaxFileCount) + return PR_TRUE; + + xptiFile* newArray = new xptiFile[count]; + if(!newArray) + return PR_FALSE; + + if(mFileArray) + { + for(PRUint32 i = 0; i < mFileCount; ++i) + newArray[i] = mFileArray[i]; + delete [] mFileArray; + } + mFileArray = newArray; + mMaxFileCount = count; + return PR_TRUE; +} + +/***************************************************************************/ + +PRUint32 +xptiWorkingSet::FindZipItemWithName(const char* name) +{ + if(mZipItemArray) + { + for(PRUint32 i = 0; i < mZipItemCount;++i) + if(0 == PL_strcmp(name, mZipItemArray[i].GetName())) + return i; + } + return NOT_FOUND; +} + +PRBool +xptiWorkingSet::NewZipItemArray(PRUint32 count) +{ + if(mZipItemArray) + delete [] mZipItemArray; + mZipItemCount = 0; + mZipItemArray = new xptiZipItem[count]; + if(!mZipItemArray) + { + mMaxZipItemCount = 0; + return PR_FALSE; + } + mMaxZipItemCount = count; + return PR_TRUE; +} + +PRBool +xptiWorkingSet::ExtendZipItemArray(PRUint32 count) +{ + if(mZipItemArray && count < mMaxZipItemCount) + return PR_TRUE; + + xptiZipItem* newArray = new xptiZipItem[count]; + if(!newArray) + return PR_FALSE; + + if(mZipItemArray) + { + for(PRUint32 i = 0; i < mZipItemCount; ++i) + newArray[i] = mZipItemArray[i]; + delete [] mZipItemArray; + } + mZipItemArray = newArray; + mMaxZipItemCount = count; + return PR_TRUE; +} + +/***************************************************************************/ +// Directory stuff... + +PRUint32 xptiWorkingSet::GetDirectoryCount() +{ + PRUint32 count = 0; + mDirectories->Count(&count); + return count; +} + +nsresult xptiWorkingSet::GetCloneOfDirectoryAt(PRUint32 i, nsILocalFile** dir) +{ + return xptiCloneElementAsLocalFile(mDirectories, i, dir); +} + +nsresult xptiWorkingSet::GetDirectoryAt(PRUint32 i, nsILocalFile** dir) +{ + return mDirectories->QueryElementAt(i, NS_GET_IID(nsILocalFile), (void**)dir); +} + +PRBool xptiWorkingSet::FindDirectory(nsILocalFile* dir, PRUint32* index) +{ + PRUint32 count; + nsresult rv = mDirectories->Count(&count); + if(NS_FAILED(rv)) + return PR_FALSE; + + for(PRUint32 i = 0; i < count; i++) + { + PRBool same; + nsCOMPtr current; + mDirectories->QueryElementAt(i, NS_GET_IID(nsILocalFile), + getter_AddRefs(current)); + if(!current || NS_FAILED(current->Equals(dir, &same))) + break; + if(same) + { + *index = i; + return PR_TRUE; + } + } + return PR_FALSE; +} + +PRBool xptiWorkingSet::FindDirectoryOfFile(nsILocalFile* file, PRUint32* index) +{ + nsCOMPtr dirAbstract; + file->GetParent(getter_AddRefs(dirAbstract)); + if(!dirAbstract) + return PR_FALSE; + nsCOMPtr dir = do_QueryInterface(dirAbstract); + if(!dir) + return PR_FALSE; + return FindDirectory(dir, index); +} + +PRBool xptiWorkingSet::DirectoryAtMatchesPersistentDescriptor(PRUint32 i, + const char* inDesc) +{ + nsCOMPtr dir; + GetDirectoryAt(i, getter_AddRefs(dir)); + if(!dir) + return PR_FALSE; + + nsCOMPtr descDir; + nsresult rv = NS_NewNativeLocalFile(EmptyCString(), PR_FALSE, getter_AddRefs(descDir)); + if(NS_FAILED(rv)) + return PR_FALSE; + + rv = descDir->SetPersistentDescriptor(nsDependentCString(inDesc)); + if(NS_FAILED(rv)) + return PR_FALSE; + + PRBool matches; + rv = dir->Equals(descDir, &matches); + return NS_SUCCEEDED(rv) && matches; +} + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiZipItem.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiZipItem.cpp new file mode 100644 index 00000000..c9a6178b --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiZipItem.cpp @@ -0,0 +1,102 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mike McCabe + * John Bandhauer + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Implementation of xptiZipItem. */ + +#include "xptiprivate.h" + +MOZ_DECL_CTOR_COUNTER(xptiZipItem) + +xptiZipItem::xptiZipItem() + : +#ifdef DEBUG + mDEBUG_WorkingSet(nsnull), +#endif + mName(nsnull), + mGuts(nsnull) +{ + MOZ_COUNT_CTOR(xptiZipItem); + // empty +} + +xptiZipItem::xptiZipItem(const char* aName, + xptiWorkingSet* aWorkingSet) + + : +#ifdef DEBUG + mDEBUG_WorkingSet(aWorkingSet), +#endif + mName(aName), + mGuts(nsnull) +{ + MOZ_COUNT_CTOR(xptiZipItem); + + NS_ASSERTION(aWorkingSet,"bad param"); + mName = XPT_STRDUP(aWorkingSet->GetStringArena(), aName); +} + +xptiZipItem::xptiZipItem(const xptiZipItem& r, xptiWorkingSet* aWorkingSet) + : +#ifdef DEBUG + mDEBUG_WorkingSet(aWorkingSet), +#endif + mName(nsnull), + mGuts(nsnull) +{ + MOZ_COUNT_CTOR(xptiZipItem); + + NS_ASSERTION(aWorkingSet,"bad param"); + mName = XPT_STRDUP(aWorkingSet->GetStringArena(), r.mName); +} + +xptiZipItem::~xptiZipItem() +{ + MOZ_COUNT_DTOR(xptiZipItem); +} + +PRBool +xptiZipItem::SetHeader(XPTHeader* aHeader, xptiWorkingSet* aWorkingSet) +{ + NS_ASSERTION(!mGuts,"bad state"); + NS_ASSERTION(aHeader,"bad param"); + NS_ASSERTION(aWorkingSet,"bad param"); + + mGuts = xptiTypelibGuts::NewGuts(aHeader, aWorkingSet); + return mGuts != nsnull; +} diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiZipLoader.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiZipLoader.cpp new file mode 100644 index 00000000..caba49d5 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiZipLoader.cpp @@ -0,0 +1,113 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mike McCabe + * John Bandhauer + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Implementation of xptiZipLoader. */ + +#include "xptiprivate.h" + +XPTHeader* +xptiZipLoader::ReadXPTFileFromInputStream(nsIInputStream *stream, + xptiWorkingSet* aWorkingSet) +{ + XPTCursor cursor; + PRUint32 totalRead = 0; + XPTState *state = nsnull; + XPTHeader *header = nsnull; + + PRUint32 flen; + stream->Available(&flen); + + char *whole = new char[flen]; + if (!whole) + { + return nsnull; + } + + // all exits from on here should be via 'goto out' + + while(flen - totalRead) + { + PRUint32 avail; + PRUint32 read; + + if(NS_FAILED(stream->Available(&avail))) + { + goto out; + } + + if(avail > flen) + { + goto out; + } + + if(NS_FAILED(stream->Read(whole+totalRead, avail, &read))) + { + goto out; + } + + totalRead += read; + } + + // Go ahead and close the stream now. + stream = nsnull; + + if(!(state = XPT_NewXDRState(XPT_DECODE, whole, flen))) + { + goto out; + } + + if(!XPT_MakeCursor(state, XPT_HEADER, 0, &cursor)) + { + goto out; + } + + if (!XPT_DoHeader(aWorkingSet->GetStructArena(), &cursor, &header)) + { + header = nsnull; + goto out; + } + + out: + if(state) + XPT_DestroyXDRState(state); + if(whole) + delete [] whole; + return header; +} + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiprivate.h b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiprivate.h new file mode 100644 index 00000000..3d159c2c --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiprivate.h @@ -0,0 +1,981 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mike McCabe + * John Bandhauer + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Library-private header for Interface Info system. */ + +#ifndef xptiprivate_h___ +#define xptiprivate_h___ + +#include "nscore.h" +#include "nsISupports.h" + +// this after nsISupports, to pick up IID +// so that xpt stuff doesn't try to define it itself... +#include "xpt_struct.h" +#include "xpt_xdr.h" + +#include "nsIInterfaceInfo.h" +#include "nsIInterfaceInfoManager.h" +#include "xptinfo.h" +#include "nsIXPTLoader.h" + +#include "nsIServiceManager.h" +#include "nsILocalFile.h" +#include "nsIDirectoryService.h" +#include "nsDirectoryServiceDefs.h" +#include "nsAppDirectoryServiceDefs.h" +#include "nsIWeakReference.h" + +#include "nsCRT.h" +#include "nsMemory.h" + +#include "nsISupportsArray.h" +#include "nsSupportsArray.h" +#include "nsInt64.h" + +#include "nsQuickSort.h" + +#include "nsXPIDLString.h" + +#include "nsIInputStream.h" + +#include "nsAutoLock.h" + +#include "pldhash.h" +#include "plstr.h" +#include "prprf.h" +#include "prio.h" +#include "prtime.h" +#include "prenv.h" + +#include +#include + +/***************************************************************************/ + +#if 0 && defined(DEBUG_jband) +#define LOG_RESOLVE(x) printf x +#define LOG_LOAD(x) printf x +#define LOG_AUTOREG(x) do{printf x; xptiInterfaceInfoManager::WriteToLog x;}while(0) +#else +#define LOG_RESOLVE(x) ((void)0) +#define LOG_LOAD(x) ((void)0) +#define LOG_AUTOREG(x) xptiInterfaceInfoManager::WriteToLog x +#endif + +#if 1 && defined(DEBUG_jband) +#define SHOW_INFO_COUNT_STATS +#endif + +/***************************************************************************/ + +class xptiFile; +class xptiInterfaceInfo; +class xptiInterfaceInfoManager; +class xptiInterfaceEntry; +class xptiInterfaceGuts; +class xptiTypelibGuts; +class xptiWorkingSet; + +/***************************************************************************/ + +class xptiTypelib +{ +public: + // No ctors or dtors so that we can be in a union in xptiInterfaceInfo. + // Allow automatic shallow copies. + + uint16 GetFileIndex() const {return mFileIndex;} + uint16 GetZipItemIndex() const {return mZipItemIndex;} + + enum {NOT_ZIP = 0xffff}; + + PRBool IsZip() const {return mZipItemIndex != NOT_ZIP;} + + void Init(uint16 aFileIndex, uint16 aZipItemIndex = NOT_ZIP) + {mFileIndex = aFileIndex; mZipItemIndex = aZipItemIndex;} + + PRBool Equals(const xptiTypelib& r) const + {return mFileIndex == r.mFileIndex && + mZipItemIndex == r.mZipItemIndex;} + +private: + uint16 mFileIndex; + uint16 mZipItemIndex; +}; + +/***************************************************************************/ + +// No virtuals. +// These are always constructed in the struct arena using placement new. +// dtor need not be called. + +class xptiTypelibGuts +{ +public: + static xptiTypelibGuts* NewGuts(XPTHeader* aHeader, + xptiWorkingSet* aWorkingSet); + + XPTHeader* GetHeader() {return mHeader;} + PRUint16 GetEntryCount() const {return mHeader->num_interfaces;} + + void SetEntryAt(PRUint16 i, xptiInterfaceEntry* ptr) + { + NS_ASSERTION(mHeader,"bad state!"); + NS_ASSERTION(i < GetEntryCount(),"bad param!"); + mEntryArray[i] = ptr; + } + + xptiInterfaceEntry* GetEntryAt(PRUint16 i) const + { + NS_ASSERTION(mHeader,"bad state!"); + NS_ASSERTION(i < GetEntryCount(),"bad param!"); + return mEntryArray[i]; + } + +private: + xptiTypelibGuts(); // not implemented + xptiTypelibGuts(XPTHeader* aHeader); + ~xptiTypelibGuts() {} + void* operator new(size_t, void* p) CPP_THROW_NEW {return p;} + +private: + XPTHeader* mHeader; // hold pointer into arena + xptiInterfaceEntry* mEntryArray[1]; // Always last. Sized to fit. +}; + +/***************************************************************************/ + +class xptiFile +{ +public: + const nsInt64& GetSize() const {return mSize;} + const nsInt64& GetDate() const {return mDate;} + const char* GetName() const {return mName;} + /*const*/ PRUint32 GetDirectory() const {return mDirectory;} + xptiTypelibGuts* GetGuts() {return mGuts;} + + xptiFile(); + + xptiFile(const nsInt64& aSize, + const nsInt64& aDate, + PRUint32 aDirectory, + const char* aName, + xptiWorkingSet* aWorkingSet); + + xptiFile(const xptiFile& r, xptiWorkingSet* aWorkingSet); + + ~xptiFile(); + + PRBool SetHeader(XPTHeader* aHeader, xptiWorkingSet* aWorkingSet); + + PRBool Equals(const xptiFile& r) const + { + return mDirectory == r.mDirectory && + mSize == r.mSize && + mDate == r.mDate && + 0 == PL_strcmp(mName, r.mName); + } + + xptiFile(const xptiFile& r) {CopyFields(r);} + xptiFile& operator= (const xptiFile& r) + { + if(this != &r) + CopyFields(r); + return *this; + } + +private: + void CopyFields(const xptiFile& r) + { +#ifdef DEBUG + // If 'this' has a workingset then it better match that of the assigner. + NS_ASSERTION(!mDEBUG_WorkingSet || + mDEBUG_WorkingSet == r.mDEBUG_WorkingSet, + "illegal xptiFile assignment"); + mDEBUG_WorkingSet = r.mDEBUG_WorkingSet; +#endif + + mSize = r.mSize; + mDate = r.mDate; + mName = r.mName; + mDirectory = r.mDirectory; + mGuts = r.mGuts; + } + +private: +#ifdef DEBUG + xptiWorkingSet* mDEBUG_WorkingSet; +#endif + nsInt64 mSize; + nsInt64 mDate; + const char* mName; // hold pointer into arena from initializer + xptiTypelibGuts* mGuts; // hold pointer into arena + PRUint32 mDirectory; +}; + +/***************************************************************************/ + +class xptiZipItem +{ +public: + const char* GetName() const {return mName;} + xptiTypelibGuts* GetGuts() {return mGuts;} + + xptiZipItem(); + + xptiZipItem(const char* aName, + xptiWorkingSet* aWorkingSet); + + xptiZipItem(const xptiZipItem& r, xptiWorkingSet* aWorkingSet); + + ~xptiZipItem(); + + PRBool SetHeader(XPTHeader* aHeader, xptiWorkingSet* aWorkingSet); + + PRBool Equals(const xptiZipItem& r) const + { + return 0 == PL_strcmp(mName, r.mName); + } + + xptiZipItem(const xptiZipItem& r) {CopyFields(r);} + xptiZipItem& operator= (const xptiZipItem& r) + { + if(this != &r) + CopyFields(r); + return *this; + } + +private: + void CopyFields(const xptiZipItem& r) + { +#ifdef DEBUG + // If 'this' has a workingset then it better match that of the assigner. + NS_ASSERTION(!mDEBUG_WorkingSet || + mDEBUG_WorkingSet == r.mDEBUG_WorkingSet, + "illegal xptiFile assignment"); + mDEBUG_WorkingSet = r.mDEBUG_WorkingSet; +#endif + + mName = r.mName; + mGuts = r.mGuts; + } + +private: +#ifdef DEBUG + xptiWorkingSet* mDEBUG_WorkingSet; +#endif + const char* mName; // hold pointer into arena from initializer + xptiTypelibGuts* mGuts; // hold pointer into arena +}; + +/***************************************************************************/ + +class xptiWorkingSet +{ +public: + xptiWorkingSet(); // not implmented + xptiWorkingSet(nsISupportsArray* aDirectories); + ~xptiWorkingSet(); + + PRBool IsValid() const; + + void InvalidateInterfaceInfos(); + void ClearHashTables(); + void ClearFiles(); + void ClearZipItems(); + + // utility methods... + + xptiTypelibGuts* GetTypelibGuts(const xptiTypelib& typelib) + { + return typelib.IsZip() ? + GetZipItemAt(typelib.GetZipItemIndex()).GetGuts() : + GetFileAt(typelib.GetFileIndex()).GetGuts(); + } + + enum {NOT_FOUND = 0xffffffff}; + + // FileArray stuff... + + PRUint32 GetFileCount() const {return mFileCount;} + PRUint32 GetFileFreeSpace() + {return mFileArray ? mMaxFileCount - mFileCount : 0;} + + PRUint32 FindFile(PRUint32 dir, const char* name); + + PRUint32 GetTypelibDirectoryIndex(const xptiTypelib& typelib) + { + return GetFileAt(typelib.GetFileIndex()).GetDirectory(); + } + + const char* GetTypelibFileName(const xptiTypelib& typelib) + { + return GetFileAt(typelib.GetFileIndex()).GetName(); + } + + xptiFile& GetFileAt(PRUint32 i) const + { + NS_ASSERTION(mFileArray, "bad state!"); + NS_ASSERTION(i < mFileCount, "bad param!"); + return mFileArray[i]; + } + + void SetFileAt(PRUint32 i, const xptiFile& r) + { + NS_ASSERTION(mFileArray, "bad state!"); + NS_ASSERTION(i < mFileCount, "bad param!"); + mFileArray[i] = r; + } + + void AppendFile(const xptiFile& r) + { + NS_ASSERTION(mFileArray, "bad state!"); + NS_ASSERTION(mFileCount < mMaxFileCount, "bad param!"); + mFileArray[mFileCount++] = r; + } + + PRBool NewFileArray(PRUint32 count); + PRBool ExtendFileArray(PRUint32 count); + + // ZipItemArray stuff... + + PRUint32 GetZipItemCount() const {return mZipItemCount;} + PRUint32 GetZipItemFreeSpace() + {return mZipItemArray ? mMaxZipItemCount - mZipItemCount : 0;} + + PRUint32 FindZipItemWithName(const char* name); + + xptiZipItem& GetZipItemAt(PRUint32 i) const + { + NS_ASSERTION(mZipItemArray, "bad state!"); + NS_ASSERTION(i < mZipItemCount, "bad param!"); + return mZipItemArray[i]; + } + + void SetZipItemAt(PRUint32 i, const xptiZipItem& r) + { + NS_ASSERTION(mZipItemArray, "bad state!"); + NS_ASSERTION(i < mZipItemCount, "bad param!"); + mZipItemArray[i] = r; + } + + void AppendZipItem(const xptiZipItem& r) + { + NS_ASSERTION(mZipItemArray, "bad state!"); + NS_ASSERTION(mZipItemCount < mMaxZipItemCount, "bad param!"); + mZipItemArray[mZipItemCount++] = r; + } + + PRBool NewZipItemArray(PRUint32 count); + PRBool ExtendZipItemArray(PRUint32 count); + + // Directory stuff... + + PRUint32 GetDirectoryCount(); + nsresult GetCloneOfDirectoryAt(PRUint32 i, nsILocalFile** dir); + nsresult GetDirectoryAt(PRUint32 i, nsILocalFile** dir); + PRBool FindDirectory(nsILocalFile* dir, PRUint32* index); + PRBool FindDirectoryOfFile(nsILocalFile* file, PRUint32* index); + PRBool DirectoryAtMatchesPersistentDescriptor(PRUint32 i, const char* desc); + + // Arena stuff... + + XPTArena* GetStringArena() {return mStringArena;} + XPTArena* GetStructArena() {return mStructArena;} + + +private: + PRUint32 mFileCount; + PRUint32 mMaxFileCount; + xptiFile* mFileArray; // using new[] and delete[] + + PRUint32 mZipItemCount; + PRUint32 mMaxZipItemCount; + xptiZipItem* mZipItemArray; // using new[] and delete[] + + XPTArena* mStringArena; + XPTArena* mStructArena; + + nsCOMPtr mDirectories; + +public: + // XXX make these private with accessors + PLDHashTable* mNameTable; + PLDHashTable* mIIDTable; + PRUint32* mFileMergeOffsetMap; // always in an arena + PRUint32* mZipItemMergeOffsetMap; // always in an arena +}; + +/***************************************************************************/ + +class xptiInterfaceGuts +{ +public: + uint16 mMethodBaseIndex; + uint16 mConstantBaseIndex; + xptiInterfaceEntry* mParent; + XPTInterfaceDescriptor* mDescriptor; + xptiTypelib mTypelib; + xptiWorkingSet* mWorkingSet; + + static xptiInterfaceGuts* NewGuts(XPTInterfaceDescriptor* aDescriptor, + const xptiTypelib& aTypelib, + xptiWorkingSet* aWorkingSet) + { + void* place = XPT_MALLOC(aWorkingSet->GetStructArena(), + sizeof(xptiInterfaceGuts)); + if(!place) + return nsnull; + return new(place) xptiInterfaceGuts(aDescriptor, aTypelib, aWorkingSet); + } + +private: + void* operator new(size_t, void* p) CPP_THROW_NEW {return p;} + xptiInterfaceGuts(XPTInterfaceDescriptor* aDescriptor, + const xptiTypelib& aTypelib, + xptiWorkingSet* aWorkingSet) + : mMethodBaseIndex(0), + mConstantBaseIndex(0), + mParent(nsnull), + mDescriptor(aDescriptor), + mTypelib(aTypelib), + mWorkingSet(aWorkingSet) {} + + ~xptiInterfaceGuts() {} +}; + +/***************************************************************************/ + +// This class exists to help xptiInterfaceInfo store a 4-state (2 bit) value +// and a set of bitflags in one 8bit value. See below. + +class xptiInfoFlags +{ + enum {STATE_MASK = 3}; +public: + xptiInfoFlags(uint8 n) : mData(n) {} + xptiInfoFlags(const xptiInfoFlags& r) : mData(r.mData) {} + + static uint8 GetStateMask() + {return uint8(STATE_MASK);} + + void Clear() + {mData = 0;} + + uint8 GetData() const + {return mData;} + + uint8 GetState() const + {return mData & GetStateMask();} + + void SetState(uint8 state) + {mData &= ~GetStateMask(); mData |= state;} + + void SetFlagBit(uint8 flag, PRBool on) + {if(on) + mData |= ~GetStateMask() & flag; + else + mData &= GetStateMask() | ~flag;} + + PRBool GetFlagBit(uint8 flag) const + {return (mData & flag) ? PR_TRUE : PR_FALSE;} + +private: + uint8 mData; +}; + +/****************************************************/ + +// No virtual methods. +// We always create in the struct arena and construct using "placement new". +// No members need dtor calls. + +class xptiInterfaceEntry +{ +public: + static xptiInterfaceEntry* NewEntry(const char* name, + int nameLength, + const nsID& iid, + const xptiTypelib& typelib, + xptiWorkingSet* aWorkingSet); + + static xptiInterfaceEntry* NewEntry(const xptiInterfaceEntry& r, + const xptiTypelib& typelib, + xptiWorkingSet* aWorkingSet); + + enum { + NOT_RESOLVED = 0, + PARTIALLY_RESOLVED = 1, + FULLY_RESOLVED = 2, + RESOLVE_FAILED = 3 + }; + + // Additional bit flags... + enum {SCRIPTABLE = 4}; + + uint8 GetResolveState() const {return mFlags.GetState();} + + PRBool IsFullyResolved() const + {return GetResolveState() == (uint8) FULLY_RESOLVED;} + + PRBool HasInterfaceRecord() const + {int s = (int) GetResolveState(); + return (s == PARTIALLY_RESOLVED || s == FULLY_RESOLVED) && mInterface;} + + const xptiTypelib& GetTypelibRecord() const + {return HasInterfaceRecord() ? mInterface->mTypelib : mTypelib;} + + xptiInterfaceGuts* GetInterfaceGuts() const + {return HasInterfaceRecord() ? mInterface : nsnull;} + +#ifdef DEBUG + PRBool DEBUG_ScriptableFlagIsValid() const + {int s = (int) GetResolveState(); + if((s == PARTIALLY_RESOLVED || s == FULLY_RESOLVED) && mInterface) + { + if(XPT_ID_IS_SCRIPTABLE(mInterface->mDescriptor->flags)) + return GetScriptableFlag(); + return !GetScriptableFlag(); + } + return PR_TRUE; + } +#endif + + void SetScriptableFlag(PRBool on) + {mFlags.SetFlagBit(uint8(SCRIPTABLE),on);} + PRBool GetScriptableFlag() const + {return mFlags.GetFlagBit(uint8(SCRIPTABLE));} + + const nsID* GetTheIID() const {return &mIID;} + const char* GetTheName() const {return mName;} + + PRBool EnsureResolved(xptiWorkingSet* aWorkingSet = nsnull) + {return IsFullyResolved() ? PR_TRUE : Resolve(aWorkingSet);} + + PRBool PartiallyResolveLocked(XPTInterfaceDescriptor* aDescriptor, + xptiWorkingSet* aWorkingSet); + + nsresult GetInterfaceInfo(xptiInterfaceInfo** info); + PRBool InterfaceInfoEquals(const xptiInterfaceInfo* info) const + {return info == mInfo;} + + void LockedInvalidateInterfaceInfo(); + void LockedInterfaceInfoDeathNotification() {mInfo = nsnull;} + + ////////////////////// + // These non-virtual methods handle the delegated nsIInterfaceInfo methods. + + nsresult GetName(char * *aName); + nsresult GetIID(nsIID * *aIID); + nsresult IsScriptable(PRBool *_retval); + // Except this one. + //nsresult GetParent(nsIInterfaceInfo * *aParent); + nsresult GetMethodCount(PRUint16 *aMethodCount); + nsresult GetConstantCount(PRUint16 *aConstantCount); + nsresult GetMethodInfo(PRUint16 index, const nsXPTMethodInfo * *info); + nsresult GetMethodInfoForName(const char *methodName, PRUint16 *index, const nsXPTMethodInfo * *info); + nsresult GetConstant(PRUint16 index, const nsXPTConstant * *constant); + nsresult GetInfoForParam(PRUint16 methodIndex, const nsXPTParamInfo * param, nsIInterfaceInfo **_retval); + nsresult GetIIDForParam(PRUint16 methodIndex, const nsXPTParamInfo * param, nsIID * *_retval); + nsresult GetTypeForParam(PRUint16 methodIndex, const nsXPTParamInfo * param, PRUint16 dimension, nsXPTType *_retval); + nsresult GetSizeIsArgNumberForParam(PRUint16 methodIndex, const nsXPTParamInfo * param, PRUint16 dimension, PRUint8 *_retval); + nsresult GetLengthIsArgNumberForParam(PRUint16 methodIndex, const nsXPTParamInfo * param, PRUint16 dimension, PRUint8 *_retval); + nsresult GetInterfaceIsArgNumberForParam(PRUint16 methodIndex, const nsXPTParamInfo * param, PRUint8 *_retval); + nsresult IsIID(const nsIID * IID, PRBool *_retval); + nsresult GetNameShared(const char **name); + nsresult GetIIDShared(const nsIID * *iid); + nsresult IsFunction(PRBool *_retval); + nsresult HasAncestor(const nsIID * iid, PRBool *_retval); + nsresult GetIIDForParamNoAlloc(PRUint16 methodIndex, const nsXPTParamInfo * param, nsIID *iid); + + ////////////////////// + +private: + xptiInterfaceEntry(); // not implemented + + xptiInterfaceEntry(const char* name, + size_t nameLength, + const nsID& iid, + const xptiTypelib& typelib); + + xptiInterfaceEntry(const xptiInterfaceEntry& r, + size_t nameLength, + const xptiTypelib& typelib); + ~xptiInterfaceEntry(); + + void* operator new(size_t, void* p) CPP_THROW_NEW {return p;} + + void SetResolvedState(int state) + {mFlags.SetState(uint8(state));} + + PRBool Resolve(xptiWorkingSet* aWorkingSet = nsnull); + + // We only call these "*Locked" variants after locking. This is done to + // allow reentrace as files are loaded and various interfaces resolved + // without having to worry about the locked state. + + PRBool EnsureResolvedLocked(xptiWorkingSet* aWorkingSet = nsnull) + {return IsFullyResolved() ? PR_TRUE : ResolveLocked(aWorkingSet);} + PRBool ResolveLocked(xptiWorkingSet* aWorkingSet = nsnull); + + // private helpers + + nsresult GetEntryForParam(PRUint16 methodIndex, + const nsXPTParamInfo * param, + xptiInterfaceEntry** entry); + + nsresult GetTypeInArray(const nsXPTParamInfo* param, + uint16 dimension, + const XPTTypeDescriptor** type); + +private: + nsID mIID; + union { + xptiTypelib mTypelib; // Valid only until resolved. + xptiInterfaceGuts* mInterface; // Valid only after resolved. + }; + xptiInterfaceInfo* mInfo; // May come and go. + xptiInfoFlags mFlags; + char mName[1]; // Always last. Sized to fit. +}; + +struct xptiHashEntry : public PLDHashEntryHdr +{ + xptiInterfaceEntry* value; +}; + +/****************************************************/ + +class xptiInterfaceInfo : public nsIInterfaceInfo +{ +public: + NS_DECL_ISUPPORTS + + // Use delegation to implement (most!) of nsIInterfaceInfo. + NS_IMETHOD GetName(char * *aName) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetName(aName); } + NS_IMETHOD GetInterfaceIID(nsIID * *aIID) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetIID(aIID); } + NS_IMETHOD IsScriptable(PRBool *_retval) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->IsScriptable(_retval); } + // Except this one. + NS_IMETHOD GetParent(nsIInterfaceInfo * *aParent) + { + if(!EnsureResolved() || !EnsureParent()) + return NS_ERROR_UNEXPECTED; + NS_IF_ADDREF(*aParent = mParent); + return NS_OK; + } + NS_IMETHOD GetMethodCount(PRUint16 *aMethodCount) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetMethodCount(aMethodCount); } + NS_IMETHOD GetConstantCount(PRUint16 *aConstantCount) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetConstantCount(aConstantCount); } + NS_IMETHOD GetMethodInfo(PRUint16 index, const nsXPTMethodInfo * *info) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetMethodInfo(index, info); } + NS_IMETHOD GetMethodInfoForName(const char *methodName, PRUint16 *index, const nsXPTMethodInfo * *info) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetMethodInfoForName(methodName, index, info); } + NS_IMETHOD GetConstant(PRUint16 index, const nsXPTConstant * *constant) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetConstant(index, constant); } + NS_IMETHOD GetInfoForParam(PRUint16 methodIndex, const nsXPTParamInfo * param, nsIInterfaceInfo **_retval) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetInfoForParam(methodIndex, param, _retval); } + NS_IMETHOD GetIIDForParam(PRUint16 methodIndex, const nsXPTParamInfo * param, nsIID * *_retval) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetIIDForParam(methodIndex, param, _retval); } + NS_IMETHOD GetTypeForParam(PRUint16 methodIndex, const nsXPTParamInfo * param, PRUint16 dimension, nsXPTType *_retval) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetTypeForParam(methodIndex, param, dimension, _retval); } + NS_IMETHOD GetSizeIsArgNumberForParam(PRUint16 methodIndex, const nsXPTParamInfo * param, PRUint16 dimension, PRUint8 *_retval) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetSizeIsArgNumberForParam(methodIndex, param, dimension, _retval); } + NS_IMETHOD GetLengthIsArgNumberForParam(PRUint16 methodIndex, const nsXPTParamInfo * param, PRUint16 dimension, PRUint8 *_retval) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetLengthIsArgNumberForParam(methodIndex, param, dimension, _retval); } + NS_IMETHOD GetInterfaceIsArgNumberForParam(PRUint16 methodIndex, const nsXPTParamInfo * param, PRUint8 *_retval) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetInterfaceIsArgNumberForParam(methodIndex, param, _retval); } + NS_IMETHOD IsIID(const nsIID * IID, PRBool *_retval) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->IsIID(IID, _retval); } + NS_IMETHOD GetNameShared(const char **name) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetNameShared(name); } + NS_IMETHOD GetIIDShared(const nsIID * *iid) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetIIDShared(iid); } + NS_IMETHOD IsFunction(PRBool *_retval) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->IsFunction(_retval); } + NS_IMETHOD HasAncestor(const nsIID * iid, PRBool *_retval) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->HasAncestor(iid, _retval); } + NS_IMETHOD GetIIDForParamNoAlloc(PRUint16 methodIndex, const nsXPTParamInfo * param, nsIID *iid) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetIIDForParamNoAlloc(methodIndex, param, iid); } + +public: + xptiInterfaceInfo(xptiInterfaceEntry* entry); + + void Invalidate() + {NS_IF_RELEASE(mParent); mEntry = nsnull;} + +#ifdef DEBUG + static void DEBUG_ShutdownNotification(); +#endif + +private: + + ~xptiInterfaceInfo(); + + // Note that mParent might still end up as nsnull if we don't have one. + PRBool EnsureParent(xptiWorkingSet* aWorkingSet = nsnull) + { + NS_ASSERTION(mEntry && mEntry->IsFullyResolved(), "bad EnsureParent call"); + return mParent || !mEntry->GetInterfaceGuts()->mParent || BuildParent(); + } + + PRBool EnsureResolved(xptiWorkingSet* aWorkingSet = nsnull) + { + return mEntry && mEntry->EnsureResolved(aWorkingSet); + } + + PRBool BuildParent() + { + NS_ASSERTION(mEntry && + mEntry->IsFullyResolved() && + !mParent && + mEntry->GetInterfaceGuts()->mParent, + "bad BuildParent call"); + return NS_SUCCEEDED(mEntry->GetInterfaceGuts()->mParent-> + GetInterfaceInfo(&mParent)); + } + + xptiInterfaceInfo(); // not implemented + +private: + xptiInterfaceEntry* mEntry; + xptiInterfaceInfo* mParent; +}; + +/***************************************************************************/ + +class xptiManifest +{ +public: + static PRBool Read(xptiInterfaceInfoManager* aMgr, + xptiWorkingSet* aWorkingSet); + + static PRBool Write(xptiInterfaceInfoManager* aMgr, + xptiWorkingSet* aWorkingSet); + + static PRBool Delete(xptiInterfaceInfoManager* aMgr); + +private: + xptiManifest(); // no implementation +}; + +/***************************************************************************/ + +class xptiZipLoaderSink : public nsIXPTLoaderSink +{ +public: + xptiZipLoaderSink(xptiInterfaceInfoManager* aMgr, + xptiWorkingSet* aWorkingSet) : + mManager(aMgr), + mWorkingSet(aWorkingSet) {} + + NS_DECL_ISUPPORTS + NS_DECL_NSIXPTLOADERSINK + +private: + ~xptiZipLoaderSink() {} + + xptiInterfaceInfoManager* mManager; + xptiWorkingSet* mWorkingSet; + +}; + +class xptiZipLoader +{ +public: + xptiZipLoader(); // not implemented + + static XPTHeader* + ReadXPTFileFromInputStream(nsIInputStream *stream, + xptiWorkingSet* aWorkingSet); + +}; + + +/***************************************************************************/ + +class xptiFileType +{ +public: + enum Type {UNKNOWN = -1, XPT = 0, ZIP = 1 }; + + static Type GetType(const char* name); + + static PRBool IsUnknown(const char* name) + {return GetType(name) == UNKNOWN;} + + static PRBool IsXPT(const char* name) + {return GetType(name) == XPT;} + + static PRBool IsZip(const char* name) + {return GetType(name) == ZIP;} +private: + xptiFileType(); // no implementation +}; + +/***************************************************************************/ + +// We use this is as a fancy way to open a logfile to be used within the scope +// of some given function where it is instantiated. + +class xptiAutoLog +{ +public: + xptiAutoLog(); // not implemented + xptiAutoLog(xptiInterfaceInfoManager* mgr, + nsILocalFile* logfile, PRBool append); + ~xptiAutoLog(); +private: + void WriteTimestamp(PRFileDesc* fd, const char* msg); + + xptiInterfaceInfoManager* mMgr; + PRFileDesc* mOldFileDesc; +#ifdef DEBUG + PRFileDesc* m_DEBUG_FileDesc; +#endif +}; + +/***************************************************************************/ + +class xptiInterfaceInfoManager + : public nsIInterfaceInfoSuperManager +{ + NS_DECL_ISUPPORTS + NS_DECL_NSIINTERFACEINFOMANAGER + NS_DECL_NSIINTERFACEINFOSUPERMANAGER + + // helper + PRBool + FoundZipEntry(const char* entryName, + int index, + XPTHeader* header, + xptiWorkingSet* aWorkingSet); + +public: + static xptiInterfaceInfoManager* GetInterfaceInfoManagerNoAddRef(); + static void FreeInterfaceInfoManager(); + + xptiWorkingSet* GetWorkingSet() {return &mWorkingSet;} + PRFileDesc* GetOpenLogFile() {return mOpenLogFile;} + PRFileDesc* SetOpenLogFile(PRFileDesc* fd) + {PRFileDesc* temp = mOpenLogFile; mOpenLogFile = fd; return temp;} + + PRBool LoadFile(const xptiTypelib& aTypelibRecord, + xptiWorkingSet* aWorkingSet = nsnull); + + PRBool GetApplicationDir(nsILocalFile** aDir); + PRBool GetCloneOfManifestLocation(nsILocalFile** aDir); + + void GetSearchPath(nsISupportsArray** aSearchPath) + {NS_ADDREF(*aSearchPath = mSearchPath);} + + static PRLock* GetResolveLock(xptiInterfaceInfoManager* self = nsnull) + {if(!self && !(self = GetInterfaceInfoManagerNoAddRef())) + return nsnull; + return self->mResolveLock;} + + static PRLock* GetAutoRegLock(xptiInterfaceInfoManager* self = nsnull) + {if(!self && !(self = GetInterfaceInfoManagerNoAddRef())) + return nsnull; + return self->mAutoRegLock;} + + static PRMonitor* GetInfoMonitor(xptiInterfaceInfoManager* self = nsnull) + {if(!self && !(self = GetInterfaceInfoManagerNoAddRef())) + return nsnull; + return self->mInfoMonitor;} + + static void WriteToLog(const char *fmt, ...); + +private: + ~xptiInterfaceInfoManager(); + xptiInterfaceInfoManager(); // not implmented + xptiInterfaceInfoManager(nsISupportsArray* aSearchPath); + + enum AutoRegMode { + NO_FILES_CHANGED = 0, + FILES_ADDED_ONLY, + FULL_VALIDATION_REQUIRED + }; + + PRBool IsValid(); + + PRBool BuildFileList(nsISupportsArray* aSearchPath, + nsISupportsArray** aFileList); + + nsILocalFile** BuildOrderedFileArray(nsISupportsArray* aSearchPath, + nsISupportsArray* aFileList, + xptiWorkingSet* aWorkingSet); + + XPTHeader* ReadXPTFile(nsILocalFile* aFile, xptiWorkingSet* aWorkingSet); + + AutoRegMode DetermineAutoRegStrategy(nsISupportsArray* aSearchPath, + nsISupportsArray* aFileList, + xptiWorkingSet* aWorkingSet); + + PRBool AddOnlyNewFilesFromFileList(nsISupportsArray* aSearchPath, + nsISupportsArray* aFileList, + xptiWorkingSet* aWorkingSet); + + PRBool DoFullValidationMergeFromFileList(nsISupportsArray* aSearchPath, + nsISupportsArray* aFileList, + xptiWorkingSet* aWorkingSet); + + PRBool VerifyAndAddEntryIfNew(xptiWorkingSet* aWorkingSet, + XPTInterfaceDirectoryEntry* iface, + const xptiTypelib& typelibRecord, + xptiInterfaceEntry** entryAdded); + + PRBool MergeWorkingSets(xptiWorkingSet* aDestWorkingSet, + xptiWorkingSet* aSrcWorkingSet); + + void LogStats(); + + PRBool DEBUG_DumpFileList(nsISupportsArray* aFileList); + PRBool DEBUG_DumpFileArray(nsILocalFile** aFileArray, PRUint32 count); + PRBool DEBUG_DumpFileListInWorkingSet(xptiWorkingSet* aWorkingSet); + + static PRBool BuildFileSearchPath(nsISupportsArray** aPath); + +private: + xptiWorkingSet mWorkingSet; + nsCOMPtr mStatsLogFile; + nsCOMPtr mAutoRegLogFile; + PRFileDesc* mOpenLogFile; + PRLock* mResolveLock; + PRLock* mAutoRegLock; + PRMonitor* mInfoMonitor; + PRLock* mAdditionalManagersLock; + nsSupportsArray mAdditionalManagers; + nsCOMPtr mSearchPath; +}; + +/***************************************************************************/ +// utilities... + +nsresult xptiCloneLocalFile(nsILocalFile* aLocalFile, + nsILocalFile** aCloneLocalFile); + +nsresult xptiCloneElementAsLocalFile(nsISupportsArray* aArray, PRUint32 aIndex, + nsILocalFile** aLocalFile); + +#endif /* xptiprivate_h___ */ diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptinfo/tests/.cvsignore b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/tests/.cvsignore new file mode 100644 index 00000000..f29041e6 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/tests/.cvsignore @@ -0,0 +1,2 @@ +Makefile +TestInterfaceInfo diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptinfo/tests/Makefile.in b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/tests/Makefile.in new file mode 100644 index 00000000..9b7f1ed4 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/tests/Makefile.in @@ -0,0 +1,58 @@ +# +# ***** 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.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of 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 ***** + +DEPTH = ../../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = xpcom + +SIMPLE_PROGRAMS = TestInterfaceInfo$(BIN_SUFFIX) + +CPPSRCS = TestInterfaceInfo.cpp + +LIBS = \ + $(XPCOM_LIBS) \ + $(NSPR_LIBS) \ + $(NULL) + +include $(topsrcdir)/config/rules.mk + +DEFINES += -DEXPORT_XPTI_API diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptinfo/tests/TestInterfaceInfo.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/tests/TestInterfaceInfo.cpp new file mode 100644 index 00000000..75005c50 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/tests/TestInterfaceInfo.cpp @@ -0,0 +1,146 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Some simple smoke tests of the typelib loader. */ + +#include "nscore.h" + +#include "nsISupports.h" +#include "nsIInterfaceInfo.h" +#include "nsIInterfaceInfoManager.h" +#include "xptinfo.h" + +#include + +// This file expects the nsInterfaceInfoManager to be able to discover +// .xpt files corresponding to those in xpcom/idl. Currently this +// means setting XPTDIR in the environment to some directory +// containing these files. + +int main (int argc, char **argv) { + int i; + nsIID *iid1, *iid2, *iid3; + char *name1, *name2, *name3; + nsIInterfaceInfo *info2, *info3, *info4, *info5; + + nsIInterfaceInfoManager *iim = XPTI_GetInterfaceInfoManager(); + + fprintf(stderr, "\ngetting iid for 'nsISupports'\n"); + iim->GetIIDForName("nsISupports", &iid1); + iim->GetNameForIID(iid1, &name1); + fprintf(stderr, "%s iid %s\n", name1, iid1->ToString()); + + fprintf(stderr, "\ngetting iid for 'nsIInputStream'\n"); + iim->GetIIDForName("nsIInputStream", &iid2); + iim->GetNameForIID(iid2, &name2); + fprintf(stderr, "%s iid %s\n", name2, iid2->ToString()); + + fprintf(stderr, "iid: %s, name: %s\n", iid1->ToString(), name1); + fprintf(stderr, "iid: %s, name: %s\n", iid2->ToString(), name2); + + fprintf(stderr, "\ngetting info for iid2 from above\n"); + iim->GetInfoForIID(iid2, &info2); +#ifdef DEBUG +// ((nsInterfaceInfo *)info2)->print(stderr); +#endif + + fprintf(stderr, "\ngetting iid for 'nsIInputStream'\n"); + iim->GetIIDForName("nsIInputStream", &iid3); + iim->GetNameForIID(iid3, &name3); + fprintf(stderr, "%s iid %s\n", name3, iid2->ToString()); + iim->GetInfoForIID(iid3, &info3); +#ifdef DEBUG +// ((nsInterfaceInfo *)info3)->print(stderr); +#endif + + fprintf(stderr, "\ngetting info for name 'nsIBidirectionalEnumerator'\n"); + iim->GetInfoForName("nsIBidirectionalEnumerator", &info4); +#ifdef DEBUG +// ((nsInterfaceInfo *)info4)->print(stderr); +#endif + + fprintf(stderr, "\nparams work?\n"); + fprintf(stderr, "\ngetting info for name 'nsIServiceManager'\n"); + iim->GetInfoForName("nsIServiceManager", &info5); +#ifdef DEBUG +// ((nsInterfaceInfo *)info5)->print(stderr); +#endif + + // XXX: nsIServiceManager is no more; what do we test with? + if (info5 == NULL) { + fprintf(stderr, "\nNo nsIServiceManager; cannot continue.\n"); + return 1; + } + + uint16 methodcount; + info5->GetMethodCount(&methodcount); + const nsXPTMethodInfo *mi; + for (i = 0; i < methodcount; i++) { + info5->GetMethodInfo(i, &mi); + fprintf(stderr, "method %d, name %s\n", i, mi->GetName()); + } + + // 7 is GetServiceWithListener, which has juicy params. + info5->GetMethodInfo(7, &mi); +// uint8 paramcount = mi->GetParamCount(); + + nsXPTParamInfo param2 = mi->GetParam(2); + // should be IID for nsIShutdownListener + nsIID *nsISL; + info5->GetIIDForParam(7, ¶m2, &nsISL); +// const nsIID *nsISL = param2.GetInterfaceIID(info5); + fprintf(stderr, "iid assoc'd with param 2 of method 7 of GetServiceWithListener - %s\n", nsISL->ToString()); + // if we look up the name? + char *nsISLname; + iim->GetNameForIID(nsISL, &nsISLname); + fprintf(stderr, "which is called %s\n", nsISLname); + + fprintf(stderr, "\nhow about one defined in a different typelib\n"); + nsXPTParamInfo param3 = mi->GetParam(3); + // should be IID for nsIShutdownListener + nsIID *nsISS; + info5->GetIIDForParam(7, ¶m3, &nsISS); +// const nsIID *nsISS = param3.GetInterfaceIID(info5); + fprintf(stderr, "iid assoc'd with param 3 of method 7 of GetServiceWithListener - %s\n", nsISS->ToString()); + // if we look up the name? + char *nsISSname; + iim->GetNameForIID(nsISS, &nsISSname); + fprintf(stderr, "which is called %s\n", nsISSname); + + return 0; +} + diff --git a/src/libs/xpcom18a4/xpcom/sample/.cvsignore b/src/libs/xpcom18a4/xpcom/sample/.cvsignore new file mode 100644 index 00000000..d1f93146 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/sample/.cvsignore @@ -0,0 +1,2 @@ +Makefile +nsTestSample diff --git a/src/libs/xpcom18a4/xpcom/sample/Makefile.in b/src/libs/xpcom18a4/xpcom/sample/Makefile.in new file mode 100644 index 00000000..5510e795 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/sample/Makefile.in @@ -0,0 +1,113 @@ +# +# ***** 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.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of 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 ***** + +DEPTH = ../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = xpcomsample +XPIDL_MODULE = xpcomsample +LIBRARY_NAME = xpcomsample +SHORT_LIBNAME = xpcomsmp + +IS_COMPONENT = 1 +MODULE_NAME = nsSampleModule + +# Ensure that the xpcom classes that we build +# do not export themselves +DEFINES += -DXPCOM_GLUE + + +REQUIRES = string \ + xpcom \ + $(NULL) + +CPPSRCS = \ + nsSample.cpp \ + nsSampleModule.cpp \ + $(NULL) + +XPIDLSRCS = nsISample.idl + +TESTCPPSRCS = nsTestSample.cpp + +CPPSRCS += $(TESTCPPSRCS) + +SIMPLE_PROGRAMS = $(TESTCPPSRCS:.cpp=$(BIN_SUFFIX)) + +include $(topsrcdir)/config/config.mk + +EXTRA_COMPONENTS = nsSample.js + +# separate libraries linked in. +EXTRA_DSO_LDOPTS = \ + $(DIST)/lib/$(LIB_PREFIX)xpcomglue.$(LIB_SUFFIX) \ + $(NSPR_LIBS) \ + $(NULL) + +LIBS = \ + $(DIST)/lib/$(LIB_PREFIX)xpcomglue.$(LIB_SUFFIX) \ + $(NSPR_LIBS) \ + $(NULL) + +# Needed to resolve __yylex (?) +ifeq ($(OS_ARCH)$(OS_RELEASE),FreeBSD2) +LIBS += -lpcap +endif + +# Need to link with CoreFoundation on Mac +ifneq (,$(filter mac cocoa,$(MOZ_WIDGET_TOOLKIT))) +EXTRA_DSO_LDOPTS += \ + $(TK_LIBS) \ + $(NULL) + +LIBS += \ + $(TK_LIBS) \ + $(NULL) +endif + +include $(topsrcdir)/config/rules.mk + +libs:: $(TARGETS) + $(INSTALL) $(srcdir)/xpconnect-sample.html $(DIST)/bin/res/samples + +install:: $(TARGETS) + $(SYSINSTALL) $(IFLAGS1) $(srcdir)/xpconnect-sample.html $(DESTDIR)$(mozappdir)/res/samples + diff --git a/src/libs/xpcom18a4/xpcom/sample/nsISample.idl b/src/libs/xpcom18a4/xpcom/sample/nsISample.idl new file mode 100644 index 00000000..22454e7b --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/sample/nsISample.idl @@ -0,0 +1,66 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/** + * A sample of XPConnect. This file contains a sample interface. + * + */ + +#include "nsISupports.idl" + +/** + * The uuid is a unique number identifying the interface normally + * called IID. It can be generated as follows: + * + * Windows: guidgen.exe + * Unix: uuidgen which comes with e2fsprogs package + * Mac: ??? + * All platform: Using irc, connect to irc.mozilla.org and type in + * /join #mozilla + * /msg mozbot uuid + * + */ +[scriptable, uuid(7CB5B7A1-07D7-11d3-BDE2-000064657374)] +interface nsISample : nsISupports +{ + attribute string value; + void writeValue(in string aPrefix); + void poke(in string aValue); +}; + + + diff --git a/src/libs/xpcom18a4/xpcom/sample/nsSample.cpp b/src/libs/xpcom18a4/xpcom/sample/nsSample.cpp new file mode 100644 index 00000000..ac3d8449 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/sample/nsSample.cpp @@ -0,0 +1,181 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Pierre Phaneuf + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + + +/** + * + * A sample of XPConnect. This file contains an implementation nsSample + * of the interface nsISample. + * + */ +#include + +#include "nsSample.h" +#include "nsMemory.h" + +#include "nsEmbedString.h" +//////////////////////////////////////////////////////////////////////// + +nsSampleImpl::nsSampleImpl() : mValue(nsnull) +{ + mValue = (char*)nsMemory::Clone("initial value", 14); +} + +nsSampleImpl::~nsSampleImpl() +{ + if (mValue) + nsMemory::Free(mValue); +} + +/** + * NS_IMPL_ISUPPORTS1 expands to a simple implementation of the nsISupports + * interface. This includes a proper implementation of AddRef, Release, + * and QueryInterface. If this class supported more interfaces than just + * nsISupports, + * you could use NS_IMPL_ADDREF() and NS_IMPL_RELEASE() to take care of the + * simple stuff, but you would have to create QueryInterface on your own. + * nsSampleFactory.cpp is an example of this approach. + * Notice that the second parameter to the macro is name of the interface, and + * NOT the #defined IID. + * + * The _CI variant adds support for nsIClassInfo, which permits introspection + * and interface flattening. + */ +NS_IMPL_ISUPPORTS1_CI(nsSampleImpl, nsISample) + +/** + * Notice that in the protoype for this function, the NS_IMETHOD macro was + * used to declare the return type. For the implementation, the return + * type is declared by NS_IMETHODIMP + */ +NS_IMETHODIMP +nsSampleImpl::GetValue(char** aValue) +{ + NS_PRECONDITION(aValue != nsnull, "null ptr"); + if (! aValue) + return NS_ERROR_NULL_POINTER; + + if (mValue) { + /** + * GetValue's job is to return data known by an instance of + * nsSampleImpl to the outside world. If we were to simply return + * a pointer to data owned by this instance, and the client were to + * free it, bad things would surely follow. + * On the other hand, if we create a new copy of the data for our + * client, and it turns out that client is implemented in JavaScript, + * there would be no way to free the buffer. The solution to the + * buffer ownership problem is the nsMemory singleton. Any buffer + * returned by an XPCOM method should be allocated by the nsMemory. + * This convention lets things like JavaScript reflection do their + * job, and simplifies the way C++ clients deal with returned buffers. + */ + *aValue = (char*) nsMemory::Clone(mValue, strlen(mValue) + 1); + if (! *aValue) + return NS_ERROR_NULL_POINTER; + } + else { + *aValue = nsnull; + } + return NS_OK; +} + +NS_IMETHODIMP +nsSampleImpl::SetValue(const char* aValue) +{ + NS_PRECONDITION(aValue != nsnull, "null ptr"); + if (! aValue) + return NS_ERROR_NULL_POINTER; + + if (mValue) { + nsMemory::Free(mValue); + } + + /** + * Another buffer passing convention is that buffers passed INTO your + * object ARE NOT YOURS. Keep your hands off them, unless they are + * declared "inout". If you want to keep the value for posterity, + * you will have to make a copy of it. + */ + mValue = (char*) nsMemory::Clone(aValue, strlen(aValue) + 1); + return NS_OK; +} + +NS_IMETHODIMP +nsSampleImpl::Poke(const char* aValue) +{ + return SetValue((char*) aValue); +} + + +static void GetStringValue(nsACString& aValue) +{ + NS_CStringSetData(aValue, "GetValue"); +} + +NS_IMETHODIMP +nsSampleImpl::WriteValue(const char* aPrefix) +{ + NS_PRECONDITION(aPrefix != nsnull, "null ptr"); + if (! aPrefix) + return NS_ERROR_NULL_POINTER; + + printf("%s %s\n", aPrefix, mValue); + + // This next part illustrates the nsEmbedString: + nsEmbedString foopy; + foopy.Append(PRUnichar('f')); + foopy.Append(PRUnichar('o')); + foopy.Append(PRUnichar('o')); + foopy.Append(PRUnichar('p')); + foopy.Append(PRUnichar('y')); + + const PRUnichar* f = foopy.get(); + PRUint32 l = foopy.Length(); + printf("%c%c%c%c%c %d\n", char(f[0]), char(f[1]), char(f[2]), char(f[3]), char(f[4]), l); + + nsEmbedCString foopy2; + GetStringValue(foopy2); + + //foopy2.AppendLiteral("foopy"); + const char* f2 = foopy2.get(); + PRUint32 l2 = foopy2.Length(); + + printf("%s %d\n", f2, l2); + + return NS_OK; +} diff --git a/src/libs/xpcom18a4/xpcom/sample/nsSample.h b/src/libs/xpcom18a4/xpcom/sample/nsSample.h new file mode 100644 index 00000000..40dec0b3 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/sample/nsSample.h @@ -0,0 +1,129 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/** + * A sample of XPConnect. This file is the header of an implementation + * nsSample of the nsISample interface. + * + */ + +#include "nsISample.h" + +/** + * SampleImpl is an implementation of the nsISample interface. In XPCOM, + * there can be more than one implementation of an given interface. Class + * IDs (CIDs) uniquely identify a particular implementation of an interface. + * Interface IDs (IIDs) uniquely identify an interface. + * + * The CID is also a unique number that looks just like an IID + * and uniquely identifies an implementation + * {7CB5B7A0-07D7-11d3-BDE2-000064657374} + */ + +#define NS_SAMPLE_CID \ +{ 0x7cb5b7a0, 0x7d7, 0x11d3, { 0xbd, 0xe2, 0x0, 0x0, 0x64, 0x65, 0x73, 0x74 } } + +#define NS_SAMPLE_CONTRACTID "@mozilla.org/sample;1" + + +class nsSampleImpl : public nsISample +{ +public: + nsSampleImpl(); + + /** + * This macro expands into a declaration of the nsISupports interface. + * Every XPCOM component needs to implement nsISupports, as it acts + * as the gateway to other interfaces this component implements. You + * could manually declare QueryInterface, AddRef, and Release instead + * of using this macro, but why? + */ + // nsISupports interface + NS_DECL_ISUPPORTS + + /** + * This macro is defined in the nsISample.h file, and is generated + * automatically by the xpidl compiler. It expands to + * declarations of all of the methods required to implement the + * interface. xpidl will generate a NS_DECL_[INTERFACENAME] macro + * for each interface that it processes. + * + * The methods of nsISample are discussed individually below, but + * commented out (because this macro already defines them.) + */ + NS_DECL_NSISAMPLE + + /** + * The following is an explanation of how the interface header + * file expands to for a c++ implementation. NS_DELC_NSISAMPLE + * takes care of defining the right c++ implementation. + * + * The following if provided for more understanding. + * + * NS_IMETHOD expands to the standard XPCOM return type. XPCOM methods + * should never return any other type. The return value is used + * behind the scenes by the XPConnect runtime to figure out if the call + * failed in any way. + * These methods were generated by "attribute string Value" in + * nsISample.idl. When reflected into JavaScript, XPCOM will use these + * calls as Getter/Setter ops, so that they can be called transparently + * as "sample.Value='foo';" and "var val = sample.Value" + */ + /* NS_IMETHOD GetValue(char * *aValue); */ + /* NS_IMETHOD SetValue(char * aValue); */ + + /** + * The const came from the "in" specifier in nsISample.idl. "in" + * specifies that the value of this parameter is used only for input, + * this method is not allowed to modify the contents of the buffer. + */ + /* NS_IMETHOD WriteValue(const char *aPrefix); */ + + /** + * nsISample.idl specifies all of it's string types as string, instead + * of wstring (wide string), the Unicode type. If the world were a + * perfect place, all normal strings in XPCOM interfaces would be unicode. + * If this type had been specified as wstring, it would appear as + * PRUnichar * in C++, which is the NSPR type for unicode characters. + */ + /* NS_IMETHOD Poke(const char* aValue); */ + +private: + ~nsSampleImpl(); + + char* mValue; +}; diff --git a/src/libs/xpcom18a4/xpcom/sample/nsSample.js b/src/libs/xpcom18a4/xpcom/sample/nsSample.js new file mode 100644 index 00000000..1cc9a091 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/sample/nsSample.js @@ -0,0 +1,130 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +/* + * No magic constructor behaviour, as is de rigeur for XPCOM. + * If you must perform some initialization, and it could possibly fail (even + * due to an out-of-memory condition), you should use an Init method, which + * can convey failure appropriately (thrown exception in JS, + * NS_FAILED(nsresult) return in C++). + * + * In JS, you can actually cheat, because a thrown exception will cause the + * CreateInstance call to fail in turn, but not all languages are so lucky. + * (Though ANSI C++ provides exceptions, they are verboten in Mozilla code + * for portability reasons -- and even when you're building completely + * platform-specific code, you can't throw across an XPCOM method boundary.) + */ +function mySample() { /* big comment for no code, eh? */ } + +/* decorate prototype to provide ``class'' methods and property accessors */ +mySample.prototype = { + /* + * get and set are new Magic in JS1.5, borrowing the intent -- if not + * the exact syntax -- from the JS2 design. They define accessors for + * properties on the JS object, follow the expected rules for prototype + * delegation, and make a mean cup of coffee. + */ + get value() { return this.val; }, + set value(newval) { return this.val = newval; }, + + writeValue: function (aPrefix) { + debug("mySample::writeValue => " + aPrefix + this.val + "\n"); + }, + poke: function (aValue) { this.val = aValue; }, + + QueryInterface: function (iid) { + if (iid.equals(Components.interfaces.nsISample) || + iid.equals(Components.interfaces.nsISupports)) + return this; + + Components.returnCode = Components.results.NS_ERROR_NO_INTERFACE; + return null; + }, + + val: "" +} + +var myModule = { + firstTime: true, + + /* + * RegisterSelf is called at registration time (component installation + * or the only-until-release startup autoregistration) and is responsible + * for notifying the component manager of all components implemented in + * this module. The fileSpec, location and type parameters are mostly + * opaque, and should be passed on to the registerComponent call + * unmolested. + */ + registerSelf: function (compMgr, fileSpec, location, type) { + if (this.firstTime) { + debug("*** Deferring registration of sample JS components\n"); + this.firstTime = false; + throw Components.results.NS_ERROR_FACTORY_REGISTER_AGAIN; + } + debug("*** Registering sample JS components\n"); + compMgr = compMgr.QueryInterface(Components.interfaces.nsIComponentRegistrar); + compMgr.registerFactoryLocation(this.myCID, + "Sample JS Component", + this.myProgID, + fileSpec, + location, + type); + }, + + /* + * The GetClassObject method is responsible for producing Factory objects + */ + getClassObject: function (compMgr, cid, iid) { + if (!cid.equals(this.myCID)) + throw Components.results.NS_ERROR_NO_INTERFACE; + + if (!iid.equals(Components.interfaces.nsIFactory)) + throw Components.results.NS_ERROR_NOT_IMPLEMENTED; + + return this.myFactory; + }, + + /* CID for this class */ + myCID: Components.ID("{dea98e50-1dd1-11b2-9344-8902b4805a2e}"), + + /* ProgID for this class */ + myProgID: "@mozilla.org/jssample;1", + + /* factory object */ + myFactory: { + /* + * Construct an instance of the interface specified by iid, possibly + * aggregating it with the provided outer. (If you don't know what + * aggregation is all about, you don't need to. It reduces even the + * mightiest of XPCOM warriors to snivelling cowards.) + */ + createInstance: function (outer, iid) { + debug("CI: " + iid + "\n"); + if (outer != null) + throw Components.results.NS_ERROR_NO_AGGREGATION; + + return (new mySample()).QueryInterface(iid); + } + }, + + /* + * The canUnload method signals that the component is about to be unloaded. + * C++ components can return false to indicate that they don't wish to be + * unloaded, but the return value from JS components' canUnload is ignored: + * mark-and-sweep will keep everything around until it's no longer in use, + * making unconditional ``unload'' safe. + * + * You still need to provide a (likely useless) canUnload method, though: + * it's part of the nsIModule interface contract, and the JS loader _will_ + * call it. + */ + canUnload: function(compMgr) { + debug("*** Unloading sample JS components\n"); + return true; + } +}; + +function NSGetModule(compMgr, fileSpec) { + return myModule; +} + + diff --git a/src/libs/xpcom18a4/xpcom/sample/nsSampleModule.cpp b/src/libs/xpcom18a4/xpcom/sample/nsSampleModule.cpp new file mode 100644 index 00000000..f02b9a5c --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/sample/nsSampleModule.cpp @@ -0,0 +1,131 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Suresh Duddu + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsIGenericFactory.h" + +#include "nsSample.h" + +//////////////////////////////////////////////////////////////////////// +// NOTE this file supercedes nsSampleFactory.cpp. nsSampleFactory has +// extensive comments, but it has been CVS removed to reduce clutter +// in this sample. It's available to the interested via CVS history: +// cvs up nsSampleFactory.cpp -r 1.10 +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +// With the below sample, you can define an implementation glue +// that talks with xpcom for creation of component nsSampleImpl +// that implement the interface nsISample. This can be extended for +// any number of components. +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +// Define the contructor function for the object nsSampleImpl +// +// What this does is defines a function nsSampleImplConstructor which we +// will specific in the nsModuleComponentInfo table. This function will +// be used by the generic factory to create an instance of nsSampleImpl. +// +// NOTE: This creates an instance of nsSampleImpl by using the default +// constructor nsSampleImpl::nsSampleImpl() +// +NS_GENERIC_FACTORY_CONSTRUCTOR(nsSampleImpl) + +//////////////////////////////////////////////////////////////////////// +// Define a table of CIDs implemented by this module along with other +// information like the function to create an instance, contractid, and +// class name. +// +// The Registration and Unregistration proc are optional in the structure. +// +static NS_METHOD nsSampleRegistrationProc(nsIComponentManager *aCompMgr, + nsIFile *aPath, + const char *registryLocation, + const char *componentType, + const nsModuleComponentInfo *info) +{ + // Do any registration specific activity like adding yourself to a + // category. The Generic Module will take care of registering your + // component with xpcom. You dont need to do that. Only any component + // specific additional activity needs to be done here. + + // This functions is optional. If you dont need it, dont add it to the structure. + + return NS_OK; +} + +static NS_METHOD nsSampleUnregistrationProc(nsIComponentManager *aCompMgr, + nsIFile *aPath, + const char *registryLocation, + const nsModuleComponentInfo *info) +{ + // Undo any component specific registration like adding yourself to a + // category here. The Generic Module will take care of unregistering your + // component from xpcom. You dont need to do that. Only any component + // specific additional activity needs to be done here. + + // This functions is optional. If you dont need it, dont add it to the structure. + + // Return value is not used from this function. + return NS_OK; +} + +// For each class that wishes to support nsIClassInfo, add a line like this +NS_DECL_CLASSINFO(nsSampleImpl) + +static const nsModuleComponentInfo components[] = +{ + { "Sample Component", NS_SAMPLE_CID, NS_SAMPLE_CONTRACTID, nsSampleImplConstructor, + nsSampleRegistrationProc /* NULL if you dont need one */, + nsSampleUnregistrationProc /* NULL if you dont need one */, + NULL /* no factory destructor */, + NS_CI_INTERFACE_GETTER_NAME(nsSampleImpl), + NULL /* no language helper */, + &NS_CLASSINFO_NAME(nsSampleImpl) + } +}; + +//////////////////////////////////////////////////////////////////////// +// Implement the NSGetModule() exported function for your module +// and the entire implementation of the module object. +// +// NOTE: If you want to use the module shutdown to release any +// module specific resources, use the macro +// NS_IMPL_NSGETMODULE_WITH_DTOR() instead of the vanilla +// NS_IMPL_NSGETMODULE() +// +NS_IMPL_NSGETMODULE(nsSampleModule, components) diff --git a/src/libs/xpcom18a4/xpcom/sample/nsTestSample.cpp b/src/libs/xpcom18a4/xpcom/sample/nsTestSample.cpp new file mode 100644 index 00000000..edf9ce78 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/sample/nsTestSample.cpp @@ -0,0 +1,158 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Suresh Duddi + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + + +/** + * A Test application that exercises the sample moudule. This is intented + * to be a sample application for using xpcom standalone. + */ + +#include + +#include "nsISample.h" +#include "nsIServiceManager.h" +#include "nsIComponentRegistrar.h" + +#ifdef XPCOM_GLUE +#include "nsXPCOMGlue.h" +#include "nsMemory.h" +#else +#include "nsXPIDLString.h" +#endif + +#define NS_SAMPLE_CONTRACTID "@mozilla.org/sample;1" + +int +main(void) +{ + nsresult rv; + +#ifdef XPCOM_GLUE + XPCOMGlueStartup(nsnull); +#endif + + // Initialize XPCOM + nsCOMPtr servMan; + rv = NS_InitXPCOM2(getter_AddRefs(servMan), nsnull, nsnull); + if (NS_FAILED(rv)) + { + printf("ERROR: XPCOM intialization error [%x].\n", rv); + return -1; + } + // register all components in our default component directory + nsCOMPtr registrar = do_QueryInterface(servMan); + NS_ASSERTION(registrar, "Null nsIComponentRegistrar"); + registrar->AutoRegister(nsnull); + + nsCOMPtr manager = do_QueryInterface(registrar); + NS_ASSERTION(registrar, "Null nsIComponentManager"); + + // Create an instance of our component + nsCOMPtr mysample; + rv = manager->CreateInstanceByContractID(NS_SAMPLE_CONTRACTID, + nsnull, + NS_GET_IID(nsISample), + getter_AddRefs(mysample)); + if (NS_FAILED(rv)) + { + printf("ERROR: Cannot create instance of component " NS_SAMPLE_CONTRACTID " [%x].\n" + "Debugging hint:\n" + "\tsetenv NSPR_LOG_MODULES nsComponentManager:5\n" + "\tsetenv NSPR_LOG_FILE xpcom.log\n" + "\t./nsTestSample\n" + "\t.\n", + rv); + return -2; + } + + // Call methods on our sample to test it out. + rv = mysample->WriteValue("Inital print:"); + if (NS_FAILED(rv)) + { + printf("ERROR: Calling nsISample::WriteValue() [%x]\n", rv); + return -3; + } + + const char *testValue = "XPCOM defies gravity"; + rv = mysample->SetValue(testValue); + if (NS_FAILED(rv)) + { + printf("ERROR: Calling nsISample::SetValue() [%x]\n", rv); + return -3; + } + printf("Set value to: %s\n", testValue); +#ifndef XPCOM_GLUE + nsXPIDLCString str; + rv = mysample->GetValue(getter_Copies(str)); +#else + char *str; + rv = mysample->GetValue(&str); +#endif + + if (NS_FAILED(rv)) + { + printf("ERROR: Calling nsISample::GetValue() [%x]\n", rv); + return -3; + } + if (strcmp(str, testValue)) + { + printf("Test FAILED.\n"); + return -4; + } + +#ifdef XPCOM_GLUE + nsMemory::Free(str); +#endif + rv = mysample->WriteValue("Final print :"); + printf("Test passed.\n"); + + // All nsCOMPtr's must be deleted prior to calling shutdown XPCOM + // as we should not hold references passed XPCOM Shutdown. + servMan = 0; + registrar = 0; + manager = 0; + mysample = 0; + + // Shutdown XPCOM + NS_ShutdownXPCOM(nsnull); + +#ifdef XPCOM_GLUE + XPCOMGlueShutdown(); +#endif + return 0; +} diff --git a/src/libs/xpcom18a4/xpcom/sample/win32.order b/src/libs/xpcom18a4/xpcom/sample/win32.order new file mode 100644 index 00000000..bf181a81 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/sample/win32.order @@ -0,0 +1 @@ +_NSGetModule ; 1 diff --git a/src/libs/xpcom18a4/xpcom/sample/xpconnect-sample.html b/src/libs/xpcom18a4/xpcom/sample/xpconnect-sample.html new file mode 100644 index 00000000..78e91be1 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/sample/xpconnect-sample.html @@ -0,0 +1,220 @@ + +
XPConnect Sample + +

+Ariel Blackenroth <arielb@rice.edu> +
+Michael Ang <mang@subcarrier.org> +
+Last modified + +

+ +

In the spirit of "worse is better" this somewhat rough guide is being +released to the world. It will be expanded upon and improved. + +

XPConnect allows JavaScript +to transparantly access and manipulate XPCOM objects; this communication +between JavaScript and +native code is done by having their interfaces defined in the XPIDL interface +definition language. See the Roadmap +for documentation on XPCOM, XPConnect, XPTCall and XPIDL for more information. + +

Overview + +

+This sample demonstrates accessing a XPCOM object through XPConnect. +The JavaScript executed when this page loads creates an instance +of the object by +using the Components object, then accesses it through +the nsISample interface by calling QueryInterface: +
+

+netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+var sample = Components.classes["@mozilla.org/sample;1"].createInstance();
+sample = sample.QueryInterface(Components.interfaces.nsISample);
+
+ +

+The buttons on the form are connected to JavaScript event handlers which +call the methods defined in C++. + + +

nsISample.idl +

This is the interface declaration for the XPCOM object. It defines +two functions, their parameters, and one attribute. It also defines +the interface's id. The idl file is compiled by the xpidl compiler +into a C++ header, nsISample.h and a .xpt file which is a binary representation +of the interface used at runtime. +
attribute string value; +
void writeValue(in string aPrefix); +
void poke(in string aValue); +

nsSample.cpp +

This contains the implementation of nsISample.idl. SampleImpl +inherits from nsISample.h, the header dynamically created by the xpidl +compiler. The attribute Value has been expanded into a get and set +and the return values have been modified to NS_IMETHOD, a success status +for the method. The macro NS_DECL_ISUPPORTS, defined in mozilla/xpcom/public/nsISupportsUtils.h +defines the inherited methods from nsISupports.h. +
NS_IMPL_ISUPPORTS1(SampleImpl, nsISample) +
In the constructor, the macro NS_INIT_REFCNT is called which sets the +reference count to 0.

+Note that the methods in the C++ bindings use InterCaps style, while the IDL +and JavaScript versions should use interCaps naming. The JavaScript binding +matches the case of the IDL, except QueryInterface. +

nsSampleFactory.cpp +

This is the class which builds the instance of the nsSample class. +The COM framework uses factories to create instance of implementations +rather than having the implementations instatiate themselves in order to +increase portability of code. This factory inherits from nsFactory, +which is also an XPCOM object. To gain more knowledge of factories +see the generic +factory document or the Modularization techniques document. +

nsSample.js +

This file implements the nsISample interface, and associated factory glue, +in JavaScript. + +

Compiling the idl + +

The XPIDL compiler (xpidl on Unix, xpidl.exe on Windows, and a CodeWarrior plugin on Mac) +is compiled at build time (except on Mac) thus +you will have to build mozilla in order to test this out. If you +have already built mozilla then the compiler will be located at mozilla\dist\WIN32_D.OBJ\bin\xpidl.exe. + +

Once you have the XPIDL compiler enter the following command at your +prompt: +
D:\mozilla\xpcom\sample>d:\mozilla\dist\WIN32_D.OBJ\bin\xpidl -I +d:\mozilla\dist\idl -m header nsISample.idl + +

The -I d:\mozilla\dist\idl points the compiler to the folder +containing the other idl files, needed because nsISample.idl inherits from +nsISupports.idl. The -m header instruction tells the compiler +to build the C++ header. To build the .xpt file substitute -m +typelib. + +

+For more information on compilation see the xpidl +compiler page. + +

Building the Sample + +

To build the Sample just enter +
d:\mozilla\xpcom\sample>nmake /f makefile.win + +

In order to do this you need to have your environment variables set +correctly. See the Build +page for more information. + +

Running the sample +

Using Mozilla, load +resource://res/samples/xpconnect-sample.html (i.e. what +you're reading now). Pay attention +to the console when clicking "write". Notice that the value +printed is calculated in C++ code defined in nsSample.cpp. + + + + +

+

+ + + + + + + +
+ +

+JavaScript and form source: + + +

+<script>
+/* to use nsSample.js version, use "@mozilla.org/jssample;1" */
+netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+var sample = Components.classes["@mozilla.org/sample;1"].createInstance();
+sample = sample.QueryInterface(Components.interfaces.nsISample);
+dump("sample = " + sample + "\n");
+
+function get()
+{
+  netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");  var field = document.getElementById('Value');
+  field.value = sample.value;
+}
+
+function set()
+{
+  netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");  var field = document.getElementById('Value');
+  sample.value = field.value;
+}
+
+function poke()
+{
+  netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");  var field = document.getElementById('Value');
+  sample.poke(field.value);
+}
+
+function sampleWrite()
+{
+  netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+  sample.writeValue("here is what I'm writing: ");
+}
+</script>
+
+<form name="form">
+<input type="button" value="Get" onclick="get();">
+<input type="button" value="Set" onclick="set();">
+<input type="button" value="Poke" onclick="poke();">
+<input type="text" id="Value">
+<input type="button" value="Write" onclick="sampleWrite();">
+<form>
+
+
+ +

+


+Resources: + +
+Comments to: +Michael Ang <mang@subcarrier.org> diff --git a/src/libs/xpcom18a4/xpcom/string/.cvsignore b/src/libs/xpcom18a4/xpcom/string/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/xpcom/string/Makefile.in b/src/libs/xpcom18a4/xpcom/string/Makefile.in new file mode 100644 index 00000000..6a664cb9 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/Makefile.in @@ -0,0 +1,54 @@ +# +# ***** 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. +# Portions created by the Initial Developer are Copyright (C) 2001 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Johnny Stenback (original author) +# +# Alternatively, the contents of this file may be used under the terms of +# either of 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 ***** + +DEPTH = ../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = string +DIRS = public src + +#ifdef ENABLE_TESTS +#DIRS += \ +# tests +#endif + +include $(topsrcdir)/config/rules.mk diff --git a/src/libs/xpcom18a4/xpcom/string/README.html b/src/libs/xpcom18a4/xpcom/string/README.html new file mode 100644 index 00000000..1fdcfdd1 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/README.html @@ -0,0 +1,44 @@ + + + +

managing sequences of characters

+

+ +

+ + diff --git a/src/libs/xpcom18a4/xpcom/string/doc/README.html b/src/libs/xpcom18a4/xpcom/string/doc/README.html new file mode 100644 index 00000000..154b7969 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/doc/README.html @@ -0,0 +1,44 @@ + + + +

documentation aimed at programmers who are clients of the string library

+

+ +

+ + diff --git a/src/libs/xpcom18a4/xpcom/string/doc/string-guide.html b/src/libs/xpcom18a4/xpcom/string/doc/string-guide.html new file mode 100644 index 00000000..41dbd217 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/doc/string-guide.html @@ -0,0 +1,2508 @@ + + + + an incomplete guide to mozilla/string + + + + + + + +

an incomplete guide to mozilla/string

+

This document is now deprecated in favor of The new string guide.

+
+

by Scott Collins +

last modified 8 April 2001 +

+ +
+

+

Abstract

+ This document provides + an introduction to the design and use of the string classes in mozilla, + detailed information on their implementation and how one may extend them, + and answers to frequently asked questions about strings. +

+
+ + + +

contents

+ + + +

+ Please direct all comments, requests, and contributions to, + in order of preference, + the tracking bug #70076 for this document, + the author scc@mozilla.org, and/or + the newsgroup news:netscape.public.mozilla.xpcom + (should there be a strings newsgroup?) +

+ +
+

+ A note to potential editors: + don't even consider modifying this document with an HTML editor. + That would destroy the internal formatting, + and make patches unmanagable. +

+
+ + + + + +
+

user's guide

+ +
+

+ Strings in mozilla are a world apart from char*s. + If you don't know why they are different, + this section is the place for you to start. + If you're already familiar with the hierarchy of string classes in mozilla, + then you might want to skip ahead to the implementor's guide + or the FAQ. +

+
+ + + +

introduction

+

what and what isn't a string?

+

+ A string is an opaque container holding a, possibly zero length, linear sequence of characters. + Understanding the implications of this statement is the foundation for understanding all mozilla's string classes. +

+ +

readable and writable

+

dependent strings

+

flat strings

+

encoding

+

sharing

+ +

using the string classes correctly; using the correct string class

+

basic string operations

+

comparison

+

concatenation

+

substrings

+

find and replace

+

conversions

+

calling a function that expects a different kind of string

+

converting between string classes

+

converting between encodings

+

selecting the right string class

+

user string classes

+

selecting the right string class for a parameter

+

selecting the right string class for a local variable

+

selecting the right string class for a member variable

+

selecting the right string class for a return value

+

selecting the right string class in IDL

+

dont's

+ +

using string iterators

+

what is an iterator?

+

reading iterators and writing iterators

+

`chunky' iterating for efficiency

+

copy_string, character sources and sinks

+

encoding conversion iterators

+ +

summary

+ + + +
+

implementor's guide

+ +
+

+ +

+
+ +
+
    + +
+
+ + + + +
+

frequently asked questions

+ +
+
+ +
+
    + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
you have some chars
you want'x'char c"foo"char* cpnsACString& cs
char. [] [] extract a character
PRUnichar PRUnichar('x') PRUnichar(c)convert encoding, extract a character
char* & & & . get a pointer
PRUnichar*convert encoding, get a pointer
nsACString NS_LITERAL_CSTRING("x") make a string NS_LITERAL_CSTRING("foo") make a string .
nsAString NS_LITERAL_STRING("x") convert encoding NS_LITERAL_STRING("foo")convert encoding
to call printf. call printf
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
you have some PRUnichars
you wantPRUnichar wPRUnichar* wpnsAString& s
char
PRUnichar [] extract a character
char*
PRUnichar* & get a pointer
nsACString
nsAString
to call printf call printf
+ +
+
+
+ is there any string doc? +
+
+ Yes, you're soaking in it! +
+ + + + +
+ I have a string, how do I get a pointer to the characters? +
+
+ You want to avoid this situation. + In your own interfaces, prefer string types over raw pointers. + Any interface that wants to process a string using a single pointer is making two expensive assumptions. + First, that the string is stored in one contiguous hunk; and + second, that the string is zero-terminated. + If this isn't the case, + then to get a pointer, storage must be allocated and the entire string must be copied to it and zero-terminated. + You may not be able to avoid needing a pointer when interacting with system calls. +
+
+ Some string classes guarantee that they are `flat'. + That is, that their data is stored in one contiguous zero-terminated hunk. + This does not imply that there are no embedded nulls. Caveat emptor. + All strings that explicitly promise flatness + inherit from the class nsAFlatString + or nsAFlatCString + and can produce a constant pointer to their data with the get() member function. + Even strings that don't explicitly promise to be flat + may happen to be flat. + The helper function PromiseFlatString will produce + a const dependent string that is guaranteed to be flat. + If you use this on a string that already happens to be flat, + the result is simply a reference through to that string. + Otherwise, + PromiseFlatString does the work to allocate, copy, terminate, and manage + a temporary flat string. + Since the result of PromiseFlatString is a temporary, + you must be careful not to get and hold a pointer to its data for longer than the temporary itself lives. +
+
+
+
+  /* I have a string, how do I get a pointer to the characters? */
+
+extern void EvilNarrowOSFunction( const char* );    // evil OS routines that want a pointers
+extern void EvilWideOSFunction( const PRUnichar* );
+
+void func( const nsAString& aString, const nsACString& aCString )
+  {
+    EvilWideOSFunction( NS_LITERAL_STRING("Hello, World!").get() );
+      // literal strings are flat already (as are |nsString|s, et al), just use |.get()|
+
+    EvilWideOSFunction( PromiseFlatString(aString).get() );
+      // for strings that don't explicitly guarantee flatness, use |PromiseFlatString|
+
+
+      // beware holding the pointer for longer than the life of the promise
+    const PRUnichar* wp = PromiseFlatString(aString).get(); // BAD! |wp| dangles
+    EvilWideOSFunction(wp);
+
+      // if you really need to use the pointer from |PromiseFlatString| in more than one expression...
+    const nsAFlatString& flat = PromiseFlatString(aString);
+    EvilWideOSFunction(flat.get());
+    SomeOtherFunction(flat.get());
+
+      // similarly for |char| strings
+    EvilNarrowOSFunction( PromiseFlatCString(aCString).get() );
+  }
+
+
+
+ + + + +
+ How do I get a particular character out of a string? +
+
+ Flat strings provide operator[] and CharAt(). + All strings provide First(), Last(), and access with iterators. + Don't promise a string flat just to do character indexing. + Prefer, instead, to get an iterator and advance it to the position you care about. +
+
+
+
+  /* How do I get a particular character out of a string? */
+
+PRUnichar Get5thCharacterOf( const nsAString& aString )
+  {
+    if ( aString.Length() >= 5 )
+      {
+        nsAString::const_iterator iter;
+        aString.BeginReading(iter); // make |iter| point to the beginning of |aString|
+        iter.advance(5);
+        return *iter;
+      }
+
+    return PRUnichar(0);
+  }
+
+
+
+
+ Using iterators isn't as bad as the example above makes it feel. + The typical use is for advancing through a string, examining many characters. +
+ + + + +
+ How do I convert from one encoding to another? +
+
+
+ + + + +
+ How do I create a string? +
+
+
+ + + +
+ What is the best way to return a string? +
+
+

+ There are several reasonable ways to produce a string result from a function. + If you are already holding the answer as a sharable string, + you can simply return that string (pass-by-value). + Otherwise, + the most efficient and flexible way to return a string is + to assign your result into a non-const reference parameter. + Don't bother to create a sharable string from scratch with your generated result. +

+

+ Why? + The two things you want to minimize in string manipulation are, + in order of importance, + heap allocation, and + moving characters around. +

+
+
+
+
+  /* What is the best way to return a string? */
+
+class foo
+  {
+    public:
+      // ...
+      void GetShortName( nsAString& aResult ) const;
+      nsCommonString GetFullName() const;
+      
+    private:
+      nsCommonString    mFullName;
+
+      const PRUnichar*  mShortName;
+      PRUint32          mShortNameLength;
+      
+  };
+
+nsCommonString
+foo::GetFullName() const
+  {
+    return mFullName;
+  }
+
+void
+foo::GetShortName( nsAString& aResult ) const
+  {
+    aResult = DependentString(mShortName, mShortNameLength);
+  }
+
+
+
+ + +
+ How do I printf a string, e.g., for debugging. +
+
+ If your string is already narrow, you just have to worry about making it flat, and then getting a pointer. +
+
+ If your string happens to be wide, + you'll need to convert it before you can printf something reasonable. + If it's just for debugging, + you probably wouldn't care if something odd was printed in the case of a Unicode character that didn't have + an ASCII equivalent. (If you have a UTF-8 terminal, the result is + perfectly legible and nothing odd is printed.) + The simplest thing in this case is to make a temporary conversion using NS_ConvertUTF16toUTF8. + The result is conveniently flat already, so getting the pointer is simple. + Remember not to hold onto the pointer you get out of this beyond the lifetime of temporary. +
+
+
+
+  /* How do I |printf| a string? */
+
+
+void PrintSomeStrings( const nsAString& aString, const PRUnichar* aKey, const nsACString& aCString )
+  {
+      // |printf|ing a narrow string is easy
+    printf("%s\n", PromiseFlatCString(aCString).get());     // GOOD
+
+      // the simplest way to get a |printf|-able |const char*| out of a string
+    printf("%s\n", NS_ConvertUTF16toUTF8(aKey).get());       // GOOD
+
+      // works just as well with an formal wide string type...
+    printf("%s\n", NS_ConvertUTF16toUTF8(aString).get());
+
+
+      // But don't hold onto the pointer longer than the lifetime of the temporary!
+    const char* cstring = NS_ConvertUTF16toUTF8(aKey).get(); // BAD! |cstring| is dangling
+    printf("%s\n", cstring);
+  }
+
+
+
+ +
+ +

+ Here are the email answers I have yet to format into the FAQ. + Some of the URLs may be out-dated or moved. + The messages are in order from oldest to newest. +

+

[Note : In June, 2003, these emails were modified +to better reflect what is stored in 'wide' string +classes (UTF-16 string instead of UCS-2) and what +related methods do as a part of the patch for bug 183156. +Therefore, they're a little different from the original emails +written by Scott Collins] +

+
+
+Date: Thu, 13 Apr 2000 19:41:47 -0400
+
+ +

Encoding Wars + +

This message is all about strings and the various encodings that might +be used to interpret their contents, the ramifications of that, and +where we're heading. The point of this message is to say what we're +currently thinking, and get feedback. I apologize in advance for the +rambling, and for the fact that this message may accidentally mix +discussion of how things are and how they will be. + +

There are many different possible encodings. Three in common use in +the Mozilla source base are: ASCII, UTF-16, and UTF-8. In ASCII, every + +character fits in 7-bits and is typically stored in an 8-bit byte. We +usually represent ASCII strings with nsCStrings, nsXPIDLCStrings, +or char string literals. In UTF-16, characters occupy one 16-bit code unit ( + +BMPcharacters) +or two 16-bit code units +( +non-BMP characters). +We usually represent UTF-16 strings as nsStrings, etc., i.e., two-byte +or `wide' strings. UTF-8 is a multi-byte encoding. A character might +occupy one, two, three, or four bytes. It is easiest to store and +manipulate such a string within a single-byte or `narrow' string +implementation. + +

None of our current string implementations know the encoding of the +data they hold at any given moment. An nsCString might legitimately +hold data encoded in ASCII, UTF-8 or even EBCDIC for that matter. + +

Operations that convert from one encoding to another, or operations +that are encoding sensitive (e.g., to_upper), rightly belong in +i18n. The fact that our current string interfaces automatically and +implicitly convert between wide and narrow strings is actually the +source of many errors in two particular categories: (1) unintended +extra work, (2) mistaken re-encoding, e.g., accidentally `converting' +a UTF-8 string to UTF-16 by pretending the UTF-8 string is ASCII and then +padding with '\0's. + +

We've known these were bad for a long time, and have been trying to +find the right way to fix them. The current thinking is to just byte +the bullet and eliminate implicit conversions. That has interesting +ramifications. + +

+
+void foo( const nsString&  aUTF16string );
+
+foo("hello"); // works!  constructs a temporary |nsString| by
+              // converting the ASCII literal with padding.
+              // Note: this requires an allocation
+
+
+ +

Though we've always hated this form since it requires a heap +allocation. In current code, we recommend + +

+
+foo( nsAutoString("hello") );
+
+
+ +

which still copy/converts, but at least it probably doesn't need to do +a heap allocation. In the best of all worlds, no conversion, copying, +or allocation would be necessary. To do that, you would need to be +able to directly specify a UTF-16 string, e.g., with the L"hello" +notation, and wrap that in an interface that just held a pointer. +E.g., something like + +

+
+void foo( const nsAReadableString&  aUTF16string );
+
+foo( nsLiteralString(L"hello") );
+
+
+ +

There are problems with this example, however. The L notation +specifically makes objects that are arrays of wchar_t, which under +GCC is a 4-byte element. This leads to incompatibility with JS, and +the annoyance of possibly bloated storage (I'm sort of minimizing the +situation here. It's worse that I make it sound). More about tricks +to get around this in a bit, but first, let me talk about what to do +in the meantime while we're just getting rid of implicit constructors. + Initially to get around this problem (what problem? The problem that +foo("hello") stopped compiling on my machine when I threw the +switch) I made a routine called NS_ConvertToString which looked like +this + +

+
+inline
+nsAutoString
+NS_ConvertToString( const char* anASCIIstring )
+  {
+    nsAutoString aUCS2string;
+    aUCS2string.AssignWithConversion(anASCIIstring);
+    return aUCS2string;
+  }
+
+
+ +

Which lets me write + +

+
+foo( NS_ConvertToString("hello") );
+
+
+ +

This was OK, but in discussion there were concerns about performance +on machines that didn't inline well, and issues about naming. In +that meeting we came up with an alternate naming strategy that we +think has room for growth and an implementation more likely to be +efficient on every platform. The implementation is to define a new +class that derives from nsAutoString, but allows construction from a +char* + +

+
+class NS_ConvertASCIItoUTF16 : public nsAutoString
+  {
+    public:
+      NS_ConvertASCIItoUTF16( const char* );
+      // ...
+  };
+
+
+ +

Which gives identical (though renamed) notation for calling foo: + +

+
+foo( NS_ConvertASCIItoUTF16("hello") );
+
+
+ +

It looks like a function call to an explicit encoding conversion. It +acts like a function call to an explicit encoding conversion. It is +a function call to an explicit encoding conversion. We think that +this naming pattern has room for growth. In the meeting, we concluded +that the best representation for encoding conversions is a family of +functions, and NS_ConvertASCIItoUTF16 fits right in. We think that +XPCOM probably can't live without the ASCII to UTF-16 conversion (though +as explicit as possible) but that all others rightly belong in i18n +land. + +

You can probably deduce from the clues in NS_ConvertToString, above, +that constructors weren't the only thing that became explicit. +Assignment, appending, comparison, et al, got renamed so that when +assigning, appending, or comparing to a value in a different encoding +the `WithConversion' form must be used. E.g., + +

+
+nsString aUTF16string;
+nsCString anASCIIstring;
+// ...
+
+aUTF16string += anASCIIstring;  // Currently legal, but not for long
+aUTF16string.Append(anASCIIstring); // same
+
+aUTF16string.AppendWithConversion(anASCIIstring); // the new way
+
+if ( aUTF16string == anASCIIstring ) // Sorry, this is going away too
+  // ...
+
+if ( aUTF16string.EqualsWithConversion(anASCIIstring) )
+  // ...
+
+
+ +

Yes, it's long and annoying. Just like the extra work you were +implicitly asking to have done, perhaps incorrectly. There are other +reasons to rename these functions. When nsString and nsCString +defined a ton of, e.g., Appends each there was no problem, because +nobody wanted to override Append. Now, with strings inheriting from +abstract base classes we immediately run into the problem that +overriding and overloading don't mix very well in C++. Because of a +feature of C++ called name hiding, it is problematic to override only +a single signature of a name overloaded in a base class. The base +nsAWritableString provides several Appends, all for objects of +(hopefully) the same encoding. nsString can't easily add a bunch of +new Appends (the converting ones) without running face first into +the name hiding problem. The discussion of the fix for this is mostly +unrelated to encoding issues, so I'll defer it to another post. + +

In hindsight, after the meeting, it seemed clear that all the +`WithConversion' forms would be better named + +

+
+xxxConvertingASCIItoUTF16
+xxxConvertingUTF16toASCII
+
+
+ +

however, the real goal (probably) is to move most such conversions +into i18n. Just bringing attention to the previously implicit +conversions is a good first step. Renaming these conversions as just +suggested is probably the right thing to do, though it sort of +validates them, which I'm not sure we really want. This is a decision +we need to discuss further. + +

Now, back to the string literal problem above. One possible solution +is to use a macro. Imagine + +

+
+NS_LITERAL_STRING("Hello")
+
+
+ +

which on a machine where the L trick works, turns into + +

+
+nsLiteralString(L"Hello")
+
+
+ +

but on a machine where there is trouble, turns into something less +appealing, but more likely to work, like + +

+
+NS_ConvertASCIItoUTF16("Hello")
+
+
+ +

Another solution is to add a compilation step that fixes L strings +on bad platforms to be non-L strings, but padded with \0s. E.g., +L"Hello" gets preprocessed into "\000H\000e\000l\000l\000o\000". +This solution is more annoying to the developer, where the prior +solution is more annoying during the runtime. + +

Before we go to too much trouble on this specific feature, we will +probably want to do more measurement to see just how much and how +often we are converting constant literal strings, and why. + + +

I'm currently ripping through the tree fixing things to use the +`WithConversion' forms where appropriate. I was also converting +things to use NS_ConvertToString where appropriate; unless I get +talked out of it, I want to switch midstream to +NS_ConvertASCIItoUTF16, then go back and fix up the +NS_ConvertToString instances later. I've set things up so I can +check in as I go. After all these conversions have been done, I'll be +able to throw the switch (what switch? NEW_STRING_APIS) which will +make nsString inherit from nsAWritableString, etc. and allow us to +start exploiting these other opportunities (e.g., for literal strings, +shared strings, etc. See +http://bugzilla.mozilla.org/show_bug.cgi?id=28221 for details and +reasoning.) + +

I guess I'm expecting comments on: + +

    +
  • how really annoying this whole topic is +
  • how bad L"xxx" is +
  • whether to move forward with NS_ConvertASCIItoUTF16 +
  • whether we should move to xxxConvertingASCIItoUTF16 etc instead + of `WithConverting' +
  • arguments about where encoding conversions should live +
  • arguments about whether going between 1 and 2 byte storage is an + encoding conversion +
  • questions about stuff I didn't mention or didn't explain well +
  • pointing out stuff I'm just plain wrong about, or things I forgot +
  • etc +
+ +

So as not to jumble the discussion, I'll be separately posting other +requests for comments about specific features of the design of the new +string hierarchy. + +

I hope this helps keep everybody filled in on what we're thinking and +able to point out what we're forgetting or screwing up :-) + + + + + +


+
+Date: Wed, 19 Apr 2000 21:12:47 -0400
+Subject: more string info
+
+ +

news://news.mozilla.org/scc-705460.16423913042000@news.mozilla.org + + + + + +


+
+Date: Fri, 26 May 2000 15:31:37 -0400
+Subject: Re: Question on ==
+
+ +

I would prefer you compare with Equals (which should really be named +IsEqualTo) rather than operator==() because of this: + +

+
+char* a;
+char* b;
+
+// ...
+
+if ( a == b )
+  // ...
+
+
+ +

Comparing two raw `string' pointers doesn't compare the characters +they point to, but instead compares the bits of the pointers. For +this reason, I may eventually make comparison of a string with a +pointer using operators just go away. + + + + + +


+
+Date: Wed, 14 Jun 2000 14:38:55 -0400
+Subject: Re: Fix to XprtDefs.h
+
+ +

Yes, we're aware that turning off wchar_t support makes wchar_t be +a synonym for unsigned short under Metrowerks. We know that the +current version of VC++ also makes these types equivalent. In theory, +though, the types are distinct even when they are the same size and +shape. By using real wchar_t support, we are forced to recognize +the distinction and navigate it appropriately with reinterpret_cast +(via NS_REINTERPRET_CAST). The win here is that we aren't caught by +compiler changes that suddenly make some set of compilers compliant +and therefore break our code. We will add an autoconf test that lets +UNIX compilers opt in to our string scheme when they have an +appropriately shaped wchar_t. If these happen to be compliant +compilers, all will be well. If they don't, the casts don't hurt, +because they are type correct. We are writing our code to meet the +standard as we move forward. + +

The win for us is realized by the following macros + +

+
+#ifdef HAVE_CPP_2BYTE_WCHAR_T
+  #define NS_LITERAL_STRING(s)  nsLiteralString(L##s, \
+                      (sizeof(L##s)/sizeof(wchar_t))-1)
+#else
+  #define NS_LITERAL_STRING(s)  NS_ConvertASCIItoUTF16(s, \
+                       sizeof(s)-1)
+#endif
+
+
+ +

An nsLiteralString points directly to the literal characters. No +copying, no conversion, and the length calculation happens at compile +time. This has turned out to be as large a savings as 15% of code +space and 8% of data space, net, in our string test harness It's +faster as well, again by eliminating the copying, conversion, and +length calculation. We don't know yet what those numbers translate +into in our real code base, but we have high hopes. + +

I don't want to be in the position to ask you to change your code. I +don't think it's appropriate for me to do so. The AIM application +that is your client is our client as well. They need to resolve this +difference between us in whatever way they think best. That may mean +asking you if changing your apis is the right thing to do. Or it may +mean applying the casts. Our code-base and yours, Justin, are more +like cousins. I don't think you should have to change just to conform +to us. You may think my arguments for using real wchar_t have +merit, and adopt similar usage just because you agree; but I think the +only obligation you have is to follow the technical solution you think +is right for your code. + +

If you decide to make this api change, it will mean shipping a new +binary (on Mac) for your library to clients who want to switch over to +the new api (since the name mangling will be different, and therefore, +the link requirements will change). + +

Hope this helps, + + + + + +


+
+Date: Thu, 15 Jun 2000 19:36:55 -0400
+Subject: Re: Checkin approval for bug 32336
+
+ +
+
+S.Equals(NS_LITERAL_STRING("bar"), PR_TRUE, 3)
+
+
+ +

doesn't compile because there is no three parameter form for Equals. + For all definitions of Equals on strings, see "nsAReadableString.h" + +

http://lxr.mozilla.org/seamonkey/source/xpcom/ds/nsAReadableString.h + +

There is an EqualsWithConversion that takes three parameters. + +

http://lxr.mozilla.org/seamonkey/source/xpcom/ds/nsString2.h#731 + +

It is ``EqualsWithConversion'' because it admits the possibility of an +encoding specific transformation, in this case to provide +case-insensitive comparison. This also wouldn't compile, however, +since, at the moment, an nsLiteralString doesn't provide an operator +to produce a const PRUnichar* (though perhaps it should), and it +doesn't satisfy the other interfaces that match this call, e.g., a +const nsString&. + +

Perhaps I need to move case-insensitive comparison up out of +nsString into a global encoding specific transformations and +algorithms file (which was on its way anyway as Waterson, knows); this +use is one bit of evidence to support this. In the short term, this +can be fixed (if we think the current behavior is wrong) by providing +operator const CharT*() const on literal string. + +

If you can live with out case-folding, the earlier form is preferred + +

+
+S == NS_LITERAL_STRING("bar")
+
+
+ +

if you can't, then one of the fixes I mentioned is in order. + + + + + +


+
+Date: Thu, 15 Jun 2000 19:47:12 -0400
+Subject: Re: [Fwd: how to use nsString ?]
+
+ + + +

Apologies. Documentation mentioning strings is getting out of date. +Here are some specific answers. + + +

+ +

...is now perhaps best expressed as + + nsString URLString( NS_LITERAL_STRING("http://www.mozilla.org") ); + +

since an nsString is a sequence of 2-byte wide characters, and the +routines that implicitly convert 1-byte sequences (like the literal +sequence you specified, "http:...") are now gone. + +

Up until not too long ago, one would have had to say + +

+
+nsString URLString;
+URLString.AssignWithConversion("http://www.mozilla.org");
+
+
+ +

The NS_LITERAL_STRING construction is new machinery that has the +potential to make many operations much more efficient. + +

+ +

SetString was a synonym for Assign or assignment with +operator=(), it too went away. The equivalent is the second +example I gave above, that is, the one with AssignWithConversion. + +

Assign still exists. AssignWithConversion takes on that +functionality for assignments that require encoding transformations +(e.g., from ASCII to UTF16). SetString is gone, since it was always +a synonym for Assign. + +

Learn more about the general APIs for strings that we are trying to +move to by examining + +http://lxr.mozilla.org/seamonkey/source/xpcom/ds/nsAReadableString.h +http://lxr.mozilla.org/seamonkey/source/xpcom/ds/nsAWritableString.h + +

Hope this helps, + + + + + +


+
+Date: Thu, 15 Jun 2000 21:26:51 -0400
+Subject: Re: Checkin approval for bug 32336
+
+ + + +

This is what substrings are for. In that case, you could use + +

+
+Substring(S, 0, 3) == NS_LITERAL_STRING("bar")
+
+
+ +

As for case-folding, it's best if you can case-fold everything up +front, instead of doing it repeatedly. I'll have to get back to you +on a general solution to that problem, or what my schedule for getting +it checked in would be. I'm sorry, I know that's not what you needed +to hear. If the source string is an nsString, you can continue to +exploit its implementation of these routines, e.g., ToLower all +up-front. + +

Hope this helps, + + + + + +


+
+Date: Mon, 19 Jun 2000 14:23:47 -0400
+Subject: Re: string fu
+
+ + + +

What would you prefer? That extracting a character not in the string +always return CharT(0)? Can't do it for two reasons: (1) 0 may be +a valid character in a particular encoding, so it can't be used in +general as a ``no character at that position'' marker; and (2) I can't +control what an individual string implementation does when asked to +get an out-of-bounds fragment, it's explicitly undefined. That means +the result of CharAt is explicitly undefined for indexes outside the +defined contents of the string. As a debugging convenience, I have +made this assert, but it has always been the case that retrieving such +a character had undefined results ... even in [the old] code. + +

OK, you might say, well at least let me ask for a character that is +only off the end by one. E.g., Last of an empty string. Reason (1) +from above still applies. How bad is it to say, for the case you gave + +

+
+PRBool needsDelim = PR_FALSE;
+if ( !path.IsEmpty() )
+  {
+    PRUnichar last = path.Last();
+    needsDelim = !(last == '/' || last == '\\');
+  }
+
+
+ +

In general, you probably want to opt out of a whole lot of work when +the source string is empty. It is slightly less convenient, but it +doesn't tie us to a bunch of implementation specific mojo. + + +

+ +

This is an annoying property of auto strings, e.g., that they always +have an allocated buffer. I'm happy to fix this bug, however, be +aware that GetUnicode and GetBuffer are artifacts of [the old] +implementation that we don't want to support. They are not part of +the abstract interface. We will keep them no longer than we have to. +They don't support our multi-fragment paradigm. People who require a +contiguous hunk of characters in the future, and are unwilling to +switch over to chunky-iterators, may be forced to copy the string to +their own buffer. There will be an implementation of narrow character +string that guarantees contiguous allocation and a zero-terminator, +much as nsCString does now, for compatibility with platform uses, +but this won't be the default string class. + + + + + +


+
+Date: Mon, 19 Jun 2000 17:22:31 -0400
+
+ +

Clarifying String Sematics + +

Recently, I added an assert to the string operations that extract +characters, namely First(), Last(), CharAt(), and +operator[](). This assert fires when any of these routines are used +to access a character outside the defined contents of the string. For +First() and Last() that means whenever they are applied to an +empty string. For CharAt() and operator[](), that means whenever +they are used to access an index outside the range of +0..Length()-1. There have been some complaints, however, the +result was always undefined. What follows is extracted from an email +exchange between me and warren on this topic. I hope it clarifies +strings semantics + +

Warren writes: +

+ +

I replied: +

+ +

Warren also asks: +

+ +

And I reply: +

+ +

In a later message, Chris Waterson asks a related question +

+ +

And I reply: +

+ +

Hope this makes sense, + + + + +


+
+Date: Tue, 20 Jun 2000 04:05:31 -0400
+Subject: Re: NS_LITERAL_STRING is broken
+
+ +

The behavior you describe sounds exactly like when you say + +

+
+const char* foobar = "foobar";
+
+... NS_LITERAL_STRING(foobar).get() ...
+
+
+ +

because in this case, the thing passed in is a const char*. +NS_LITERAL_STRING is not meant to be used in this way. It is only +meant to be used around a " delimited string. The type of such is +const char[N] where N is the number of characters in the string + 1 +for the zero terminator it helpfully adds. sizeof such a type is +N. + +

Are you sure you had the actual string as an argument, as in your +example to me? Or could the actual code have been like my sample, +above? + + + + + +


+
+Date: Thu, 29 Jun 2000 13:35:10 -0400
+Subject: Re: a fix
+
+ + + + +

Dave, + +

please read + + news://news.mozilla.org/scc-314ABF.14261619062000@news.mozilla.org + +

It's just plain wrong to let people try to index into a string outside +its defined contents. I can't just return '\0' or PRUnichar('\0') +there as that could be a legal value to have somewhere in your +string for some encodings ... and the encoding is not specified. So +your patch has the basic problem of defeating my plan to stop people +from doing this bad thing. + +

The second problem with your patch is that you use the symbolic +constant nsnull, which is ostensibly a pointer value; Last returns +a character. nsnull is not appropriate for that purpose. In fact, +C++ gurus pretty much eschew the use of symbolic constants for 0. +NULL is to be avoided. nsnull is wrong-headed in that it presumes +we could have some other application specific value for NULL. We +can't, it would never work. It's just wasted brain-print. Always use +0 for these situations, and if you want to communicate the fact that +something is a pointer type, either use a comment or a +(construction-style) cast, like so (graded examples from worst to +best:) + +

    +
  • F: FindChildByNameWithHint("Chuck", nsnull); + +
  • D: FindChildByNameWithHint("Chuck", NULL); + +
  • C: FindChildByNameWithHint("Chuck", /* Child* */ 0); + +
  • B: typedef Child* Child_ptr; + FindChildByNameWithHint("Chuck", Child_ptr(0)); + +
  • A: FindChildByNameWithHint("Chuck", 0); +
+ +

Don't let this discourage you; keep up the good work :-) + + + + + +


+
+Date: Tue, 8 Aug 2000 23:47:16 -0400
+Subject: Re: nsWritingIterator?
+
+ + + + http://ScottCollins.net/Journal/discussion/string_iterators.html + +

does this help? + +

I can personally walk you through any specific scenario you need. + + + + + +


+
+Date: Wed, 9 Aug 2000 02:35:03 -0400
+Subject: Re: nsWritingIterator?
+
+ +

You got it right... it's nsWritingIterator for whichever +character type you care about, either char or PRUnichar. You +_can_ use this iterator like a character pointer ... that is, you can +dereference it, assign into its dereference, etc. It is more +efficient, though, to directly address a particular range of +characters around where it points by asking it for its actual +character pointer with get, and knowing that there are +size_forward() characters available ahead of that pointer and +size_backward() characters available behind it. After examining +those characters by hand, you can advance the iterator beyond the +characters you have examined (and possibly into the next chunk, should +one exist) by adding into it (with +=) the count of the characters you +have processed. + +

Here are three examples of running through a string and modifying some +of the characters in it. All use nsWritingIterators. + + +

+
+  // inefficient, but works in a pinch:
+  //  iterators can hide all details of chunks by acting like
+  //  a raw character pointer
+
+nsWritingIterator<PRUnichar> s = S.BeginWriting();
+nsWritingIterator<PRUnichar> done_with_string = S.EndWriting();
+
+  // for each character in the string |S|
+while ( s != done_with_string )
+  {
+      // if the character is lower case, capitalize it
+    if ( 'a' <= *s && *s <= 'z' )
+      *s = *s -'a' + 'A';
+  }
+
+
+
+
+  // efficient
+  //  iterators provide a mechanism by which you can process
+  //  a chunk-at-a-time
+
+nsWritingIterator<PRUnichar> iter = S.BeginWriting();
+nsWritingIterator<PRUnichar> done_with_string = S.EndWriting();
+
+  // for each chunk of the string
+while ( iter != done_with_string )
+  {
+    size_t N = iter.size_forward();  // # of chars in this chunk
+    PRUnichar* s = iter.get();
+    PRUnichar* done_with_chunk = s + N;
+
+      // for each character in this chunk
+    for ( ; s < done_with_chunk; ++s )
+      {
+         // if the character is lower case, capitalize it
+       if ( 'a' <= *s && *s <= 'z' )
+          *s = *s - 'a' + 'A';
+      } 
+
+      // advance the iterator past characters
+      //  we examined (and into the next chunk, if any)
+    s += N;
+  }
+
+
+
+  // elegant
+  //  pull your transformation into a `sink', and |copy_string|
+  //  will efficiently pump any kind of string into it
+
+struct Capitalize
+  {
+      // inline
+    PRUint32
+    write( PRUnichar* s, PRUint32 N )
+        // processes one chunk, called repeatedly by |copy_string|
+      {
+        PRUnichar* done_with_chunk = s + N;
+
+         // for each character in this chunk
+        for ( ; s < done_with_chunk; ++s )
+          {
+              // if the character is lower case, capitalize it
+            if ( 'a' <= *s && *s <= 'z' )
+              *s = *s - 'a' + 'A';
+          }
+      }
+  };
+
+copy_string(S.BeginWriting(), S.EndWriting(), Capitalize());
+
+
+ + + +

Does this show it better? + + + + + +


+
+Date: Thu, 17 Aug 2000 18:23:22 -0400
+
+ + + +

I'll explain things in a little more detail than you need, then so +that some of the stuff you see in these headers will make more sense. +I'll also answer your questions out of order. + +

First: the string hierarchy looks like this + +http://ScottCollins.net/Journal/discussion/string_hierarchy.gif + +

The two most important headers are: + +http://lxr.mozilla.org/seamonkey/source/xpcom/ds/nsAReadableString.h +http://lxr.mozilla.org/seamonkey/source/xpcom/ds/nsAWritableString.h + +

These abstract classes, nsAReadable[C]String, and +nsAWritable[C]String are typically what you will want to use in the +interfaces of new code. If you write a piece of code that takes a +string for input, consider, e.g., + +

+
+void consumes_a_string( const nsAReadableString&  aInput );
+
+
+ +

If you write a piece of code that modifies a string, consider + +

+
+void modifies_a_string( nsAWritableString&  aResult );
+
+
+ + +

When creating your own classes, member strings will typically be +nsStrings. When you can't avoid creating a short string that you +need only temporarily during a function, you will typically use +nsAutoString. When someone passes you a raw pointer, or a raw +pointer and a length, representing a buffer of characters that you may +examine, but won't own, you can treat it like a string by wrapping it +in an nsLiteralString, e.g., + +

+
+void
+reads_a_buffer( const PRUnichar* aInput, PRUint32 aInputLength )
+  {
+    nsLiteralString input(aInput, aInputLength);
+      // doesn't allocate or copy
+
+    // ...
+  }
+
+
+ +

You will use nsLiteralString around quoted constant strings as well, +though typically through the NS_LITERAL_STRING macro, to avoid doing +a length calculation + +

+
+NS_LITERAL_STRING("x")
+
+
+ +

expands to + +

+
+nsLiteralString(L"x", (sizeof(L"x")/sizeof(PRUnichar) - 1))
+
+
+ +

if L notation works as needed on your platform. + +Those are the basics. Now onto your questions: + + +

+ + +

L"abc " makes a an object that is a const wchar_t[5], and none of +the string code knows about wchar_t. The main reason is that +wchar_t is not necessarily the right size (it can be 4 bytes under +gcc). If you wrap these constant expressions in NS_LITERAL_STRING, +as described above, you should get the right thing, e.g., + +

+
+str1 += NS_LITERAL_STRING("abc ") + str2 + NS_LITERAL_STRING("def");
+
+
+ + + + +

This one, I have a quick and easy explanation for. If function was +declared like this + +

+
+function( const nsAReadableString&  )
+
+
+ +

then, no problem, since a nsPromiseConcatenation (which was the +result of adding those two things together) is a readable string. +No other objects need to be created; no copying needs to be performed. + +

In all cases, we want the creation of nsStrings et al, to be +explicit, since creation is unbelievably expensive, requiring heap +allocation, locks, copying, etc. + +

I hope this answers both your posts, + + + + + +


+
+Date: Thu, 17 Aug 2000 20:57:08 -0400
+Subject: re our conversation
+
+ + return ToNewUnicode( nsLiteralCString(buffer) ); + + + + + + +
+
+Date: Fri, 18 Aug 2000 02:52:45 -0400
+Subject: Re: More questions and new string API
+
+ + + +

Unfortunately, NS_LITERAL_STRINGs definition is not particularly +amenable to this use. Instead, you would have to say something like +this: + +

+
+const nsAReadableString&
+foo()
+  {
+#ifdef HAVE_CPP_2BYTE_WCHAR_T
+    static nsLiteralString static_foo(L"x", 1);
+#else
+    static nsLiteralString static_foo;
+    static PRBool initialized = PR_FALSE;
+    if ( !initialized )
+      {
+        static_foo.AssignWithConversion("x", 1);
+        initialized = PR_TRUE;
+      }
+#endif
+    return static_foo;
+  }
+
+
+ + + + +

I don't know what errors you are getting; but it probably doesn't work +because a reference isn't an assignable type. This is just a guess. +You may need to use + +

+
+map
+
+
+ +

If you actually want the map to manage ownership of the keys, then +you'll want to use a concrete type, e.g., + +

+
+map
+
+
+ +

or perhaps + +

+
+map
+
+
+ +

Or maybe there's something else wrong. Send me the error messages. +If you end up using a pointer, then of course you'll have to supply a +comparison function to the map template. You won't be satisfied +with the default comparison of pointers :-) Sorry I couldn't answer +this one more completely. + + +

+ +

The problem with this scenario is that an nsAReadableString doesn't +promise that all its data is contiguous, nor that it is +zero-terminated, which is what I suspect you want in this case. If +the function you want to call can take {pointer, length} tuples, and +can consume the string in hunks without zero termination ... then you +can use copy_string to pump the string into your function, see + + http://ScottCollins.net/Journal/discussion/string_iterators.html + +

If not, and you absolutely have to have a contiguous zero-terminated +buffer, then there is a new facility (part of the DOMAPI branch) that +does what you need. It's not checked in on the trunk; it should +be in early next week. It is nsPromiseFlatString. This class +promises a contiguous zero-terminated buffer; and has an operator +PRUnichar* to produce a pointer to that buffer automatically. If the +underlying class is one that happens to be a single fragment and +zero-terminated, then, like nsPromiseSubstring and +nsPromiseConcatenation, this class merely holds a reference into the +original data. If, however, the underlying string is multi-fragment +or not zero-terminated, then nsPromiseFlatString allocates a +contiguous buffer of appropriate size and copies the fragmented string +data to it. So given + +

+
+void ReadBuffer( PRUnichar* );
+
+
+ +

You can call this as efficiently as possible with an arbitrary string +like so + +

+
+ReadBuffer( nsPromiseFlatString(aString) );
+
+
+ + +

If the function you are calling needs to take ownership of the buffer +you hand it, then you will probably call ToNewUnicode like so + +

+
+void ConsumeBuffer( PRUnichar* );
+
+ConsumeBuffer( ToNewUnicode(aString) );
+
+
+ +

The global function ToNewUnicode is declared in "nsReadableUtils.h", +and was only recently added to the build. It is currently being used +in the DOMAPI branch. It is part of the build, but the file +"dlldeps.c" in XPCOM may need to be modified to ensure it is exported +on your platform if you are building the tip. + +Needless to say, you want to avoid functions that require bare +pointers for several reasons: (a) they typically assume +zero-termination, which is not guaranteed by the normal encodings; (b) +they require contiguous allocation, which may not be possible; (c) +they scan for the end of the string, at linear cost (if the encoding +makes it possible at all), when the length could be known in advance. +If you have to do it, the above mechanisms work, but be aware of the +cost and the potential need to copy. + + +

+ +

nsAReadableString is an abstract type. So you can't have a concrete +instance of it. All strings in the hierarchy are readable strings. +If you just want a reference to a readable string, you can say, e.g., + +

+
+struct foo
+  {
+    const nsAReadableString&  mString;
+    // ...
+
+    foo( const nsAReadableString&  aString ) : mString(aString) { }
+  };
+
+
+ +

...similarly with pointers; but I suspect you are looking for +something more concrete. An nsString is a nsAReadableString, and +is the typical thing you want as a member variable. An nsAutoString +is also an nsAReadableString and is typically what you would use for +a short (in length) temporary (in lifetime) local variable, as I +mentioned in my previous post. + + +

+ +

Yes, though remember, an nsLiteralString assumes the lifetime of the +underlying data is under someone else's control. If the called +function gives you a buffer that you need to delete, you will have +to manage that yourself. Currently, people often use nsXPIDLString +to handle that. XPIDL strings are not part of the hierarchy. They +are only used as a sort of string-auto_ptr. However, I'm +integrating their functionality into nsString. There is no problem +in wrapping the same pointer in both as two separate local variables, +one to give you the readable interface, and one to manage the +lifetime. + +

If it's OK with you, I'd like to post this reply (including your +quoted questions) to n.p.m.xpcom and also put a copy near the string +iterator discussion I provided a link to above, so that other people +with similar questions can see these answers. + +

Hope this helps, + + + + + +


+
+Date: Sun, 3 Sep 2000 03:52:17 -0400
+
+ +

In article <8nu9m2$eo14@secnews.netscape.com>, "Jon Smirl" + wrote: + +> I have the new strings up and running in my app. They work as +> advertised and +> I haven't found any bugs. Thanks for the good job in designing and +> implementing them. Here's are a summary of issues I've encountered +> so far... + +

Thanks, and I appreciate your comments and insights. + + +> +> 1) Should there be a nsSegmentedString derived from nsString instead +> of building segment support into nsString? None of my strings are +> segmented but +> I keep executing code that is supports it. nsPromiseFlatString would +> be trivial in the non-segmented case. + +

The general case is that a string does not promise to have contiguous +data. A specific case is that, for some implementations, it does. +You couldn't do it the other way around, because a segmented string +couldn't satisfy all the promises of a flat string. However, through +the use of chunky iterators, operating on strings that happen to be +flat is very efficient. In fact, nsPromiseFlatString is trivial in +the non-segmented case. In addition, I'll be adding an abstract flat +class into the hierarchy, which will present additional interface ... +in your local routines where you actually have declared a concrete +string instance that happens to be flat, the compiler will give you +the benefit of using the flat specific routines (e.g., a substring +object over a flat string is simpler than the general purpose +substring). I need to be cautious about this, though, since I don't +automatically want people propagating the flat type through their +interfaces. That would put us in the same boat we're in right now ... +where routines only work on a specific kind of string, which denies +other parts of the code the opportunity to use an implementation +beneficial to its specific needs, and typically for no good reason. + +> +> 2) Should nsAWritableString have a way to get the buffer and then +> return it? +> I need to get the buffer to pass it to OS calls. I'm doing this now +> by passing around nsStrings instead of the interface. If I just use +> the interface I encur an extra copy since I have to use a temporary +> buffer. + +

A specific string implementation could promise this, but in general, a +writable could not. After all, a writable doesn't even guarantee +contiguous storage. To some degree, this is what +nsPromiseFlatString is for. However, this is a readable promise +only. It will also be the case that ns[C]Strings, in the very near +future will be able to just assume ownership of an arbitrary buffer +allocated on the free store with the XPCOM allocators ... getting one +to give up its buffer, on the other hand, presents some problems. Do +you have a lot of places where the system writes into your string +buffer space? Or do you have a lot of system routines that return you +new buffers? I can imagine using nsPromiseFlatString for this, but +what happens when the OS alters the underlying data? If the promise +had generated that flat data on behalf of a multi-fragment string, +should it now put the changes back? It's possible to do, I just want +to know if it's correct to allow this situation to happen. + + + +> +> 3) There needs to be a NS_LITERAL_CHAR() to go along with +> NS_LITERAL_STRING(). + +

OK. + + + +> Having NS_LITERAL_STRING() all over the code clutters +> it up and makes it hard to tell what the code is doing, could we +> have a standard short alias for this? + +

Yes, I'll try to think of something ... perhaps NS_LSTR? + + +> 4) nsLiteralString should support n.ToInteger(&error); + +

ToInteger is actually a bad interface. It's only good if your +entire string is the number; this encourages you to edit your string +until it is one, or perhaps copy the numeric part to another string. +Better if you just sscanf a string (don't know if I can provide +that in the general case, but I'm thinking about it), or else use +regular C++ extractors (which wouldn't be too hard for me to +provide), or else I could give you a ToInteger that works on a pair +of iterators, extracting the integer from the digits between them. + +> +> 5) There should be a global define for an interface to a readonly +> empty string. + +

Yes, there will be. + + +> +> 6) Something is wrong with concatenation.... + +

Hopefully I've fixed this now. + + + +> 8) A forward definition is missing in the h files + +

I'll check it out. + + + +

My understanding is that you have already found the answers to your +other questions. + +

I hope this helps, + + + + +


+
+Date: Wed, 20 Sep 2000 17:32:13 -0400
+Subject: Re: how to free an nsString::ToNewCString
+
+ + + +

nsMemory::Free + + + + + +


+ +

You use several NS_ConvertASCIItoUTF16("...").get(), these should be + + NS_LITERAL_STRING("...").get() + +

Don't do this to the very first case where you aren't wrapping an actual literal string. +The first instance would should exploit NS_LITERAL_STRING technology as well, +around the initial declarations of the strings ... probably want to do this with +NS_NAMED_LITERAL_STRING. + + + +


+
+Date: Thu, 12 Oct 2000 00:57:28 -0400
+Subject: string answers
+
+ +
+
+nsresult
+DoSomething( nsAWritableString&  answer )
+  {
+    nsresult rv;
+
+    nsXPIDLString registry_data;
+    Fetch("key", getter_Shares(registry_data));
+
+    nsLiteralString path(not_my_string);
+
+    PRInt32 first_colon = path.FindChar(PRUnichar(':'));
+    if ( first_colon != -1 )
+      {
+        // convert ... extract path from |path|
+        nsCOMPtr localFile( do_CreateInstance(CID, &rv)
+);
+        if ( localFile )
+          {
+           
+localFile->SetPersistentDescriptor(NS_ConvertUTF16toUTF8(path));
+
+            nsXPIDLString converted_path;
+            localFile->GetUnicodePath(getter_Copies(converted_path));
+            answer = converted_path.get();
+          }
+      }
+    else
+      {
+        answer = path;
+      }
+
+
+    return rv;
+  }
+
+
+ + + + + +
+
+Date: Thu, 12 Oct 2000 02:03:49 -0400
+Subject: Re: and the answer is ...
+
+ +

You can see from the line of code that you're on, that this should +have been fine. nsMemory::Alloc would be asked to allocate a 1 byte +object. But it failed trying to allocate that. Which suggests that +the allocator was busy and non-reentrant and the debugger tried to +misuse it. Yes? + +

Of course, this doesn't solve your problem. Perhaps we need to go +back to the idea of a function that returns a pointer to the first +hunk of the string. + +

+
+const char*
+debug_string( const nsAReadableCString& aCString )
+  {
+    nsReadingIterator<char> iter;
+    aCString.BeginReading(iter);
+    return aCString.IsEmpty() ? "" : iter.get();
+  }
+
+
+ +

This code should work regardless of what the allocator is doing. The +downsides are (a) it only returns the first hunk of the string, in the +case of a multi-fragment string; and (b) that hunk might not be +zero-terminated. + +

Hope this helps, + + + + + +


+
+Date: Thu, 12 Oct 2000 08:30:32 -0400
+Subject: Re: Self healing the cache :-)
+
+ +

At 3:04 PM -0400 10/11/00, Mike Shaver wrote: +

+ +

Macro ugliness makes NS_LITERAL_STRING inappropriate for use over +other macros. In other words: + +

+
+NS_LITERAL_STRING("foo")
+
+
+ +

is good. + +

+
+#define FOO "foo"
+NS_LITERAL_STRING(FOO)
+
+
+ +

is bad. Why? Because it turns into + +

+
+nsLiteralString(LFOO, sizeof(LFOO)...
+
+
+ +

and there is no LFOO. Sorry. If you have to do this to a +macro-ized string, do the magic by hand, e.g., + +

+
+nsLiteralString(FOO, sizeof(FOO)/sizeof(PRUnichar)
+                                          + sizeof(PRUnichar('\0')))
+
+
+ +

or else if you don't care that nsLiteralString will scan for the +length, just say + +

+
+nsLiteralString(FOO)
+
+
+ +

Hope this helps, + + + + + +


+
+Date: Thu, 12 Oct 2000 08:36:14 -0400
+Subject: Re: Self healing the cache :-)
+
+ +

Actually, I'm not even sure you can do it by hand, since you didn't + +

+
+#define FOO L"foo"
+
+
+ +

and can't do that cross-platform. The other way around this is to +define a global instead of a macro, that is, instead of saying + +

+
+#define FOO "foo"
+
+
+ +

at the top of your file, say + +

+
+NS_NAMED_LITERAL_STRING(FOO, "foo")
+
+
+ +

or else, if the macro was used only in one spot ... perhaps you could +just eliminate the macro in favor of NS_NAMED_LITERAL in situ. + +

Arghh. In this case, you may be stuck with the extra work of +AssignWithConversion. + + + + + +


+
+Date: Sun, 3 Dec 2000 16:38:07 -0400
+Subject: Re: another copy_string question
+
+ + + +

No, there isn't. But you could move such special processing into the +destructor of the sink. Remember, the sink is passed by reference, so +you can exactly control its lifetime. + +

+
+{
+  MySink sink;
+  nsReadingIterator<PRUnichar> sourceStart = aStr.BeginReading();
+  nsReadingIterator<PRUnichar> sourceEnd = aStr.EndReading();
+  copy_string(sourceStart, sourceEnd, sink);
+    // |sink| destructor executed here
+}
+
+
+ +

Hope this helps, + + + + + +


+
+Date: Fri, 15 Dec 2000 20:02:08 -0400
+Subject: fragment of code
+
+ +
+
+nsPromiseFlatString flatKey(aReadable);
+
+flatKey.get()
+
+
+ + + + + + +
+
+Date: Tue, 16 Jan 2001 16:47:37 -0400
+Subject: Re: a few string questions...
+
+ +>I've accumulated a few questions I've been wanting to ask you, mostly +>about string stuff. Nothing urgent, but I want to ask them before I +>forget. So here goes...: +> +>1) Is it acceptable to use nsLiteralCString or nsLiteralString on +>something that's not a literal? This can be useful in some places, +>for example, to convert a char* to PRUnichar*: +> +>PRUnichar* new = ToNewUnicode(nsLiteralCString(myCharPtr)); + +

This is explicitly allowed. That's why I'm proposing to change the +names of those classes to nsLocal[C]String. + + +>2) Should nsString2x.h and nsString2x.cpp go away? They look like a +>never-completed rewrite or something... + +

Yes. They should go away. They are uncompleted [old] bullshit, +exactly as you diagnosed. + +

I'll look into the other two questions. + + + + + +


+
+Date: Thu, 1 Feb 2001 15:12:41 -0400
+Subject: Re: [Fwd: bad string, bad string]
+
+ +

We've been removing implicit conversion operators because they +_always_ lead to trouble. Usually they make it harder to pick the +right function when overloading is involved and in the past they have +led to huge performance suckage because we ended up doing conversions +when we didn't need to because the implicit operator made us pick the +wrong function. + +

It's borderline when the class implements something that is so +close, as with a guaranteed flat string or an nsCOMPtr ... but the +general recommendation is to avoid implicit conversions. + +

See bug #53057. + + + + + +


+
+Date: Tue, 6 Feb 2001 18:52:23 -0400
+Subject: seeking review for bug #57087
+
+ +

bug: + http://bugzilla.mozilla.org/show_bug.cgi?id=57087 + + patch: + http://bugzilla.mozilla.org/showattachment.cgi?attach_id=24576 + +

This patch is supposed to add the ability to define very long literal +strings more easily by breaking lines, e.g., + +

+
+NS_MULTILINE_LITERAL( NS_L("This is the start of a very long line")
+                      NS_L(" which actually continues across")
+                      NS_L(" a couple more.") )
+
+
+ +

The main danger in this scheme is callers who omit the inner NS_L +wrapping. Though I believe this will be caught at compile time as the +wrong type initializer. + +

Seeking input from everybody, and waterson in particular. + + + + + +


+
+Date: Wed, 14 Feb 2001 16:09:10 -0400
+Subject: Re: Question...
+
+ +

There are some utilities in "xpcom/ds/nsReadableUtils.h". In +particular, if you want to get back a new heap-allocated ASCII string +with the minimal work, you would say + +

+
+PRUnichar* sourceChars = ...;
+
+char* destChars = ToNewCString(nsLiteralString(sourceChars));
+
+
+ + +

It's more efficient if you happen to already know the length. If you +don't, don't bother counting, that's what I'll do in the constructor +for nsLiteralString. If you do, then call like this + +

+
+destChars = ToNewCString( nsLiteralString(sourceChars, length) );
+
+
+ +

Other routines in that file will help you if, for instance, you wanted +to translate into a buffer you had already allocated. + +

Hope this helps, + + + + + +


+
+Date: Fri, 23 Feb 2001 03:12:58 -0400
+Subject: string snippet
+
+ +
+
+nsCString aInput;
+
+
+
+nsReadingIterator<char> search_start;
+aInput.BeginReading(search_start);
+
+nsReadingIterator<char> search_end;
+aInput.EndReading(search_end);
+
+if ( FindCharInReadable(':', search_start, search_end) )
+  {
+    ++search_start;
+    return ToNewCString( Substring(aInput, search_start, search_end)
+);
+  }
+
+
+ + + + + + +
+
+Date: Wed, 7 Mar 2001 19:44:08 -0400
+Subject: string help
+
+ +

Here you go, Mike: + + http://scottcollins.net/journal/discussion/mjudge-scratch.cpp + + + + + + +


+
+Date: Fri, 9 Mar 2001 20:56:07 -0400
+Subject: Re: string assertions
+
+ +

If you get an iterator into a string and you advance it all the way to +the end of the string, and then keep trying to advance it, you hit +this assert. This could happen, for example if you tried to copy 10 +characters out of a 9 character string. I've tried to make this +impossible to get to. As far as I know, all my routines trim requests +in advance of manipulating iterators. When you see this, you should +get the stack. That will take you right to the bad spot. + + + + + +


+
+Date: Sat, 31 Mar 2001 11:04:03 -0400
+Subject: Re: Sun bustage and string advice
+
+ +

You do know you are comparing two pointers now? It seems unlikely +those two pointers would ever be the same pointer. You probably want +to say something like + +

+
+NS_LITERAL_STRING("foo").Equals(aTopic) // or
+
+NS_LITERAL_STRING("foo") == nsLiteralString(aTopic)
+
+
+ +

...so that you compare the contents of two strings. Right now, +you're just testing to see if two pointers both point to the same +location in memory. A lot of people make this mistake. I would like +to make it obvious to people that comparing two pointers does not +compare strings. Can you tell me what gave you that impression so +that I can figure out how to better educate people not to do this? By +the way, it's not that I don't want to make this compare two +strings; it's that in C++, you can't override operations for built-in +types. And pointers are built-in types. So I can't make +operator==(const PRUnichar*, const PRUnichar*) do anything different +than it already does, which is the same thing it does for any other +pointer. + + + + + + +

+ + + + + + + + + diff --git a/src/libs/xpcom18a4/xpcom/string/public/.cvsignore b/src/libs/xpcom18a4/xpcom/string/public/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/public/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/xpcom/string/public/Makefile.in b/src/libs/xpcom18a4/xpcom/string/public/Makefile.in new file mode 100644 index 00000000..d3582bcc --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/public/Makefile.in @@ -0,0 +1,86 @@ +# vim:set ts=8 sw=8 sts=8 noet: +# +# ***** 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. +# Portions created by the Initial Developer are Copyright (C) 2001 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Johnny Stenback (original author) +# Scott Collins +# +# Alternatively, the contents of this file may be used under the terms of +# either of 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 ***** + +DEPTH = ../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = string + +EXPORTS = \ + nsAString.h \ + nsAlgorithm.h \ + nsCharTraits.h \ + nsDependentString.h \ + nsDependentSubstring.h \ + nsLiteralString.h \ + nsObsoleteAString.h \ + nsPrintfCString.h \ + nsPromiseFlatString.h \ + nsReadableUtils.h \ + nsString.h \ + nsStringFwd.h \ + nsStringIterator.h \ + nsSubstring.h \ + nsSubstringTuple.h \ + nsTAString.h \ + nsTDependentString.h \ + nsTDependentSubstring.h \ + nsTObsoleteAString.h \ + nsTPromiseFlatString.h \ + nsTString.h \ + nsTSubstring.h \ + nsTSubstringTuple.h \ + nsUTF8Utils.h \ + nsXPIDLString.h \ + string-template-def-unichar.h \ + string-template-def-char.h \ + string-template-undef.h \ + $(NULL) + +SDK_HEADERS = \ + nsStringAPI.h \ + nsEmbedString.h \ + $(NULL) + +include $(topsrcdir)/config/rules.mk diff --git a/src/libs/xpcom18a4/xpcom/string/public/nsAString.h b/src/libs/xpcom18a4/xpcom/string/public/nsAString.h new file mode 100644 index 00000000..3675989c --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/public/nsAString.h @@ -0,0 +1,96 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* ***** 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 IBM Corporation. + * Portions created by IBM Corporation are Copyright (C) 2003 + * IBM Corporation. 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 ***** */ + +#ifndef nsAString_h___ +#define nsAString_h___ + +#ifndef nsStringFwd_h___ +#include "nsStringFwd.h" +#endif + +#ifndef nsStringIterator_h___ +#include "nsStringIterator.h" +#endif + +#ifndef nsObsoleteAString_h___ +#include "nsObsoleteAString.h" +#endif + +// If some platform(s) can't handle our template that matches literal strings, +// then we'll disable it on those platforms. +#ifndef NS_DISABLE_LITERAL_TEMPLATE +# if (defined(_MSC_VER) && (_MSC_VER < 1310)) || (defined(__SUNPRO_CC) & (__SUNPRO_CC < 0x560)) || (defined(__HP_aCC) && (__HP_aCC <= 012100)) +# define NS_DISABLE_LITERAL_TEMPLATE +# endif +#endif /* !NS_DISABLE_LITERAL_TEMPLATE */ + +#include + + // declare nsAString +#include "string-template-def-unichar.h" +#include "nsTAString.h" +#include "string-template-undef.h" + + + // declare nsACString +#include "string-template-def-char.h" +#include "nsTAString.h" +#include "string-template-undef.h" + + + /** + * ASCII case-insensitive comparator. (for Unicode case-insensitive + * comparision, see nsUnicharUtils.h) + */ +class NS_COM nsCaseInsensitiveCStringComparator + : public nsCStringComparator + { + public: + typedef char char_type; + + virtual int operator()( const char_type*, const char_type*, PRUint32 length ) const; + virtual int operator()( char_type, char_type ) const; + }; + + + // included here for backwards compatibility +#ifndef nsSubstringTuple_h___ +#include "nsSubstringTuple.h" +#endif + +#endif // !defined(nsAString_h___) diff --git a/src/libs/xpcom18a4/xpcom/string/public/nsAlgorithm.h b/src/libs/xpcom18a4/xpcom/string/public/nsAlgorithm.h new file mode 100644 index 00000000..e81e6f57 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/public/nsAlgorithm.h @@ -0,0 +1,131 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Scott Collins (original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +#ifndef nsAlgorithm_h___ +#define nsAlgorithm_h___ + +#ifndef nsCharTraits_h___ +#include "nsCharTraits.h" + // for |nsCharSourceTraits|, |nsCharSinkTraits| +#endif + +#ifndef prtypes_h___ +#include "prtypes.h" + // for |PRUint32|... +#endif + +#ifndef nsDebug_h___ +#include "nsDebug.h" + // for NS_ASSERTION +#endif + +template +inline +const T& +NS_MIN( const T& a, const T& b ) + { + return b < a ? b : a; + } + +template +inline +const T& +NS_MAX( const T& a, const T& b ) + { + return a > b ? a : b; + } + +template +inline +PRUint32 +NS_COUNT( InputIterator& first, const InputIterator& last, const T& value ) + { + PRUint32 result = 0; + for ( ; first != last; ++first ) + if ( *first == value ) + ++result; + return result; + } + +template +inline +OutputIterator& +copy_string( InputIterator& first, const InputIterator& last, OutputIterator& result ) + { + typedef nsCharSourceTraits source_traits; + typedef nsCharSinkTraits sink_traits; + + while ( first != last ) + { + PRInt32 count_copied = PRInt32(sink_traits::write(result, source_traits::read(first), source_traits::readable_distance(first, last))); + NS_ASSERTION(count_copied > 0, "|copy_string| will never terminate"); + source_traits::advance(first, count_copied); + } + + return result; + } + +template +OutputIterator& +copy_string_backward( const InputIterator& first, InputIterator& last, OutputIterator& result ) + { + while ( first != last ) + { + last.normalize_backward(); + result.normalize_backward(); + PRUint32 lengthToCopy = PRUint32( NS_MIN(last.size_backward(), result.size_backward()) ); + if ( first.fragment().mStart == last.fragment().mStart ) + lengthToCopy = NS_MIN(lengthToCopy, PRUint32(last.get() - first.get())); + + NS_ASSERTION(lengthToCopy, "|copy_string_backward| will never terminate"); + +#ifdef _MSC_VER + // XXX Visual C++ can't stomach 'typename' where it rightfully should + nsCharTraits::move(result.get()-lengthToCopy, last.get()-lengthToCopy, lengthToCopy); +#else + nsCharTraits::move(result.get()-lengthToCopy, last.get()-lengthToCopy, lengthToCopy); +#endif + + last.advance( -PRInt32(lengthToCopy) ); + result.advance( -PRInt32(lengthToCopy) ); + } + + return result; + } + +#endif // !defined(nsAlgorithm_h___) diff --git a/src/libs/xpcom18a4/xpcom/string/public/nsCharTraits.h b/src/libs/xpcom18a4/xpcom/string/public/nsCharTraits.h new file mode 100644 index 00000000..e7713c95 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/public/nsCharTraits.h @@ -0,0 +1,784 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Scott Collins (original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +#ifndef nsCharTraits_h___ +#define nsCharTraits_h___ + +#include + // for |EOF|, |WEOF| + +#define FORCED_CPP_2BYTE_WCHAR_T + // disable special optimizations for now through this hack + +#if defined(HAVE_CPP_2BYTE_WCHAR_T) && !defined(FORCED_CPP_2BYTE_WCHAR_T) +#define USE_CPP_WCHAR_FUNCS +#endif + +#ifdef USE_CPP_WCHAR_FUNCS +#include + // for |wmemset|, et al +#endif + +#include + // for |memcpy|, et al + +#ifndef nscore_h___ +#include "nscore.h" + // for |PRUnichar| +#endif + +#ifndef nsDebug_h__ +#include "nsDebug.h" + // for NS_ASSERTION +#endif + +#ifdef HAVE_CPP_BOOL + typedef bool nsCharTraits_bool; +#else + typedef PRBool nsCharTraits_bool; +#endif + +template struct nsCharTraits {}; + +NS_SPECIALIZE_TEMPLATE +struct nsCharTraits + { + typedef PRUnichar char_type; + typedef PRUint16 unsigned_char_type; + typedef char incompatible_char_type; + + NS_COM static const char_type *sEmptyBuffer; + + static + void + assign( char_type& lhs, char_type rhs ) + { + lhs = rhs; + } + + + // integer representation of characters: + +#ifdef USE_CPP_WCHAR_FUNCS + typedef wint_t int_type; +#else + typedef int int_type; +#endif + + static + char_type + to_char_type( int_type c ) + { + return char_type(c); + } + + static + int_type + to_int_type( char_type c ) + { + return int_type( NS_STATIC_CAST(unsigned_char_type, c) ); + } + + static + nsCharTraits_bool + eq_int_type( int_type lhs, int_type rhs ) + { + return lhs == rhs; + } + + + // |char_type| comparisons: + + static + nsCharTraits_bool + eq( char_type lhs, char_type rhs ) + { + return lhs == rhs; + } + + static + nsCharTraits_bool + lt( char_type lhs, char_type rhs ) + { + return lhs < rhs; + } + + + // operations on s[n] arrays: + + static + char_type* + move( char_type* s1, const char_type* s2, size_t n ) + { + return NS_STATIC_CAST(char_type*, memmove(s1, s2, n * sizeof(char_type))); + } + + static + char_type* + copy( char_type* s1, const char_type* s2, size_t n ) + { + return NS_STATIC_CAST(char_type*, memcpy(s1, s2, n * sizeof(char_type))); + } + + static + char_type* + copyASCII( char_type* s1, const char* s2, size_t n ) + { + for (char_type* s = s1; n--; ++s, ++s2) { + NS_ASSERTION(!(*s2 & ~0x7F), "Unexpected non-ASCII character"); + *s = *s2; + } + return s1; + } + + static + char_type* + assign( char_type* s, size_t n, char_type c ) + { +#ifdef USE_CPP_WCHAR_FUNCS + return NS_STATIC_CAST(char_type*, wmemset(s, to_int_type(c), n)); +#else + char_type* result = s; + while ( n-- ) + assign(*s++, c); + return result; +#endif + } + + static + int + compare( const char_type* s1, const char_type* s2, size_t n ) + { +#ifdef USE_CPP_WCHAR_FUNCS + return wmemcmp(s1, s2, n); +#else + for ( ; n--; ++s1, ++s2 ) + { + if ( !eq(*s1, *s2) ) + return to_int_type(*s1) - to_int_type(*s2); + } + + return 0; +#endif + } + + static + int + compareASCII( const char_type* s1, const char* s2, size_t n ) + { + for ( ; n--; ++s1, ++s2 ) + { + NS_ASSERTION(!(*s2 & ~0x7F), "Unexpected non-ASCII character"); + if ( !eq_int_type(to_int_type(*s1), to_int_type(*s2)) ) + return to_int_type(*s1) - to_int_type(*s2); + } + + return 0; + } + + // this version assumes that s2 is null-terminated and s1 has length n. + // if s1 is shorter than s2 then we return -1; if s1 is longer than s2, + // we return 1. + static + int + compareASCIINullTerminated( const char_type* s1, size_t n, const char* s2 ) + { + for ( ; n--; ++s1, ++s2 ) + { + if ( !*s2 ) + return 1; + NS_ASSERTION(!(*s2 & ~0x7F), "Unexpected non-ASCII character"); + if ( !eq_int_type(to_int_type(*s1), to_int_type(*s2)) ) + return to_int_type(*s1) - to_int_type(*s2); + } + + if ( *s2 ) + return -1; + + return 0; + } + + /** + * Convert c to its lower-case form, but only if the lower-case form is + * ASCII. Otherwise leave it alone. + * + * There are only two non-ASCII Unicode characters whose lowercase + * equivalents are ASCII: KELVIN SIGN and LATIN CAPITAL LETTER I WITH + * DOT ABOVE. So it's a simple matter to handle those explicitly. + */ + static + char_type + ASCIIToLower( char_type c ) + { + if (c < 0x100) + return (c >= 'A' && c <= 'Z') ? c + ('a' - 'A') : c; + else + { + if (c == 0x212A) // KELVIN SIGN + return 'k'; + if (c == 0x0130) // LATIN CAPITAL LETTER I WITH DOT ABOVE + return 'i'; + return c; + } + } + + static + int + compareLowerCaseToASCII( const char_type* s1, const char* s2, size_t n ) + { + for ( ; n--; ++s1, ++s2 ) + { + NS_ASSERTION(!(*s2 & ~0x7F), "Unexpected non-ASCII character"); + NS_ASSERTION(!(*s2 >= 'A' && *s2 <= 'Z'), + "Unexpected uppercase character"); + char_type lower_s1 = ASCIIToLower(*s1); + if ( lower_s1 != to_char_type(*s2) ) + return to_int_type(lower_s1) - to_int_type(*s2); + } + + return 0; + } + + // this version assumes that s2 is null-terminated and s1 has length n. + // if s1 is shorter than s2 then we return -1; if s1 is longer than s2, + // we return 1. + static + int + compareLowerCaseToASCIINullTerminated( const char_type* s1, size_t n, const char* s2 ) + { + for ( ; n--; ++s1, ++s2 ) + { + if ( !*s2 ) + return 1; + NS_ASSERTION(!(*s2 & ~0x7F), "Unexpected non-ASCII character"); + NS_ASSERTION(!(*s2 >= 'A' && *s2 <= 'Z'), + "Unexpected uppercase character"); + char_type lower_s1 = ASCIIToLower(*s1); + if ( lower_s1 != to_char_type(*s2) ) + return to_int_type(lower_s1) - to_int_type(*s2); + } + + if ( *s2 ) + return -1; + + return 0; + } + + static + size_t + length( const char_type* s ) + { +#ifdef USE_CPP_WCHAR_FUNCS + return wcslen(s); +#else + size_t result = 0; + while ( !eq(*s++, char_type(0)) ) + ++result; + return result; +#endif + } + + static + const char_type* + find( const char_type* s, size_t n, char_type c ) + { +#ifdef USE_CPP_WCHAR_FUNCS + return NS_REINTERPRET_CAST(const char_type*, wmemchr(s, to_int_type(c), n)); +#else + while ( n-- ) + { + if ( eq(*s, c) ) + return s; + ++s; + } + + return 0; +#endif + } + +#if 0 + // I/O related: + + typedef streamoff off_type; + typedef streampos pos_type; + typedef mbstate_t state_type; + + static + int_type + eof() + { +#ifdef USE_CPP_WCHAR_FUNCS + return WEOF; +#else + return EOF; +#endif + } + + static + int_type + not_eof( int_type c ) + { + return eq_int_type(c, eof()) ? ~eof() : c; + } + + // static state_type get_state( pos_type ); +#endif + }; + +NS_SPECIALIZE_TEMPLATE +struct nsCharTraits + { + typedef char char_type; + typedef unsigned char unsigned_char_type; + typedef PRUnichar incompatible_char_type; + + NS_COM static const char_type *sEmptyBuffer; + + static + void + assign( char_type& lhs, char_type rhs ) + { + lhs = rhs; + } + + + // integer representation of characters: + + typedef int int_type; + + static + char_type + to_char_type( int_type c ) + { + return char_type(c); + } + + static + int_type + to_int_type( char_type c ) + { + return int_type( NS_STATIC_CAST(unsigned_char_type, c) ); + } + + static + nsCharTraits_bool + eq_int_type( int_type lhs, int_type rhs ) + { + return lhs == rhs; + } + + + // |char_type| comparisons: + + static + nsCharTraits_bool + eq( char_type lhs, char_type rhs ) + { + return lhs == rhs; + } + + static + nsCharTraits_bool + lt( char_type lhs, char_type rhs ) + { + return lhs < rhs; + } + + + // operations on s[n] arrays: + + static + char_type* + move( char_type* s1, const char_type* s2, size_t n ) + { + return NS_STATIC_CAST(char_type*, memmove(s1, s2, n * sizeof(char_type))); + } + + static + char_type* + copy( char_type* s1, const char_type* s2, size_t n ) + { + return NS_STATIC_CAST(char_type*, memcpy(s1, s2, n * sizeof(char_type))); + } + + static + char_type* + copyASCII( char_type* s1, const char* s2, size_t n ) + { + return copy(s1, s2, n); + } + + static + char_type* + assign( char_type* s, size_t n, char_type c ) + { + return NS_STATIC_CAST(char_type*, memset(s, to_int_type(c), n)); + } + + static + int + compare( const char_type* s1, const char_type* s2, size_t n ) + { + return memcmp(s1, s2, n); + } + + static + int + compareASCII( const char_type* s1, const char* s2, size_t n ) + { +#ifdef DEBUG + for (size_t i = 0; i < n; ++i) + { + NS_ASSERTION(!(s2[i] & ~0x7F), "Unexpected non-ASCII character"); + } +#endif + return compare(s1, s2, n); + } + + // this version assumes that s2 is null-terminated and s1 has length n. + // if s1 is shorter than s2 then we return -1; if s1 is longer than s2, + // we return 1. + static + int + compareASCIINullTerminated( const char_type* s1, size_t n, const char* s2 ) + { + // can't use strcmp here because we don't want to stop when s1 + // contains a null + for ( ; n--; ++s1, ++s2 ) + { + if ( !*s2 ) + return 1; + NS_ASSERTION(!(*s2 & ~0x7F), "Unexpected non-ASCII character"); + if ( *s1 != *s2 ) + return to_int_type(*s1) - to_int_type(*s2); + } + + if ( *s2 ) + return -1; + + return 0; + } + + /** + * Convert c to its lower-case form, but only if c is ASCII. + */ + static + char_type + ASCIIToLower( char_type c ) + { + return (c >= 'A' && c <= 'Z') ? (c + ('a' - 'A')) : c; + } + + static + int + compareLowerCaseToASCII( const char_type* s1, const char* s2, size_t n ) + { + for ( ; n--; ++s1, ++s2 ) + { + NS_ASSERTION(!(*s2 & ~0x7F), "Unexpected non-ASCII character"); + NS_ASSERTION(!(*s2 >= 'A' && *s2 <= 'Z'), + "Unexpected uppercase character"); + char_type lower_s1 = ASCIIToLower(*s1); + if ( lower_s1 != *s2 ) + return to_int_type(lower_s1) - to_int_type(*s2); + } + return 0; + } + + // this version assumes that s2 is null-terminated and s1 has length n. + // if s1 is shorter than s2 then we return -1; if s1 is longer than s2, + // we return 1. + static + int + compareLowerCaseToASCIINullTerminated( const char_type* s1, size_t n, const char* s2 ) + { + for ( ; n--; ++s1, ++s2 ) + { + if ( !*s2 ) + return 1; + NS_ASSERTION(!(*s2 & ~0x7F), "Unexpected non-ASCII character"); + NS_ASSERTION(!(*s2 >= 'A' && *s2 <= 'Z'), + "Unexpected uppercase character"); + char_type lower_s1 = ASCIIToLower(*s1); + if ( lower_s1 != *s2 ) + return to_int_type(lower_s1) - to_int_type(*s2); + } + + if ( *s2 ) + return -1; + + return 0; + } + + static + size_t + length( const char_type* s ) + { + return strlen(s); + } + + static + const char_type* + find( const char_type* s, size_t n, char_type c ) + { + return NS_REINTERPRET_CAST(const char_type*, memchr(s, to_int_type(c), n)); + } + +#if 0 + // I/O related: + + typedef streamoff off_type; + typedef streampos pos_type; + typedef mbstate_t state_type; + + static + int_type + eof() + { + return EOF; + } + + static + int_type + not_eof( int_type c ) + { + return eq_int_type(c, eof()) ? ~eof() : c; + } + + // static state_type get_state( pos_type ); +#endif + }; + +template +struct nsCharSourceTraits + { + typedef typename InputIterator::difference_type difference_type; + + static + PRUint32 + readable_distance( const InputIterator& first, const InputIterator& last ) + { + // assumes single fragment + return last.get() - first.get(); + } + + static + const typename InputIterator::value_type* + read( const InputIterator& iter ) + { + return iter.get(); + } + + static + void + advance( InputIterator& s, difference_type n ) + { + s.advance(n); + } + }; + +#ifdef HAVE_CPP_PARTIAL_SPECIALIZATION + +template +struct nsCharSourceTraits + { + typedef ptrdiff_t difference_type; + + static + PRUint32 + readable_distance( CharT* s ) + { + return PRUint32(nsCharTraits::length(s)); +// return numeric_limits::max(); + } + + static + PRUint32 + readable_distance( CharT* first, CharT* last ) + { + return PRUint32(last-first); + } + + static + const CharT* + read( CharT* s ) + { + return s; + } + + static + void + advance( CharT*& s, difference_type n ) + { + s += n; + } + }; + +#else + +NS_SPECIALIZE_TEMPLATE +struct nsCharSourceTraits + { + typedef ptrdiff_t difference_type; + + static + PRUint32 + readable_distance( const char* s ) + { + return PRUint32(nsCharTraits::length(s)); +// return numeric_limits::max(); + } + + static + PRUint32 + readable_distance( const char* first, const char* last ) + { + return PRUint32(last-first); + } + + static + const char* + read( const char* s ) + { + return s; + } + + static + void + advance( const char*& s, difference_type n ) + { + s += n; + } + }; + + +NS_SPECIALIZE_TEMPLATE +struct nsCharSourceTraits + { + typedef ptrdiff_t difference_type; + + static + PRUint32 + readable_distance( const PRUnichar* s ) + { + return PRUint32(nsCharTraits::length(s)); +// return numeric_limits::max(); + } + + static + PRUint32 + readable_distance( const PRUnichar* first, const PRUnichar* last ) + { + return PRUint32(last-first); + } + + static + const PRUnichar* + read( const PRUnichar* s ) + { + return s; + } + + static + void + advance( const PRUnichar*& s, difference_type n ) + { + s += n; + } + }; + +#endif + + +template +struct nsCharSinkTraits + { + static + PRUint32 + write( OutputIterator& iter, const typename OutputIterator::value_type* s, PRUint32 n ) + { + return iter.write(s, n); + } + }; + +#ifdef HAVE_CPP_PARTIAL_SPECIALIZATION + +template +struct nsCharSinkTraits + { + static + PRUint32 + write( CharT*& iter, const CharT* s, PRUint32 n ) + { + nsCharTraits::move(iter, s, n); + iter += n; + return n; + } + }; + +#else + +NS_SPECIALIZE_TEMPLATE +struct nsCharSinkTraits + { + static + PRUint32 + write( char*& iter, const char* s, PRUint32 n ) + { + nsCharTraits::move(iter, s, n); + iter += n; + return n; + } + }; + +NS_SPECIALIZE_TEMPLATE +struct nsCharSinkTraits + { + static + PRUint32 + write( PRUnichar*& iter, const PRUnichar* s, PRUint32 n ) + { + nsCharTraits::move(iter, s, n); + iter += n; + return n; + } + }; + +#endif + +#endif // !defined(nsCharTraits_h___) diff --git a/src/libs/xpcom18a4/xpcom/string/public/nsDependentString.h b/src/libs/xpcom18a4/xpcom/string/public/nsDependentString.h new file mode 100644 index 00000000..22e05b31 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/public/nsDependentString.h @@ -0,0 +1,60 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* ***** 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 IBM Corporation. + * Portions created by IBM Corporation are Copyright (C) 2003 + * IBM Corporation. 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 ***** */ + +#ifndef nsDependentString_h___ +#define nsDependentString_h___ + +#ifndef nsString_h___ +#include "nsString.h" +#endif + +#ifndef nsDebug_h___ +#include "nsDebug.h" +#endif + + // declare nsDependentString +#include "string-template-def-unichar.h" +#include "nsTDependentString.h" +#include "string-template-undef.h" + + // declare nsDependentCString +#include "string-template-def-char.h" +#include "nsTDependentString.h" +#include "string-template-undef.h" + +#endif /* !defined(nsDependentString_h___) */ diff --git a/src/libs/xpcom18a4/xpcom/string/public/nsDependentSubstring.h b/src/libs/xpcom18a4/xpcom/string/public/nsDependentSubstring.h new file mode 100644 index 00000000..c6459436 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/public/nsDependentSubstring.h @@ -0,0 +1,56 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* ***** 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 IBM Corporation. + * Portions created by IBM Corporation are Copyright (C) 2003 + * IBM Corporation. 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 ***** */ + +#ifndef nsDependentSubstring_h___ +#define nsDependentSubstring_h___ + +#ifndef nsSubstring_h___ +#include "nsSubstring.h" +#endif + + // declare nsDependentSubstring +#include "string-template-def-unichar.h" +#include "nsTDependentSubstring.h" +#include "string-template-undef.h" + + // declare nsDependentCSubstring +#include "string-template-def-char.h" +#include "nsTDependentSubstring.h" +#include "string-template-undef.h" + +#endif /* !defined(nsDependentSubstring_h___) */ diff --git a/src/libs/xpcom18a4/xpcom/string/public/nsEmbedString.h b/src/libs/xpcom18a4/xpcom/string/public/nsEmbedString.h new file mode 100644 index 00000000..7af03ee3 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/public/nsEmbedString.h @@ -0,0 +1,158 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 a small implementation of the nsAString and nsACString. + * + * The Initial Developer of the Original Code is + * Peter Annema . + * + * 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 ***** */ + +#ifndef nsEmbedString_h___ +#define nsEmbedString_h___ + +#include "nsStringAPI.h" + +class nsEmbedString : public nsStringContainer + { + public: + typedef nsEmbedString self_type; + typedef nsAString abstract_string_type; + + nsEmbedString() + { + NS_StringContainerInit(*this); + } + + nsEmbedString(const self_type& aString) +#ifdef VBOX + : nsStringContainer() +#endif + { + NS_StringContainerInit(*this); + NS_StringCopy(*this, aString); + } + + explicit + nsEmbedString(const abstract_string_type& aReadable) + { + NS_StringContainerInit(*this); + NS_StringCopy(*this, aReadable); + } + + explicit + nsEmbedString(const char_type* aData, size_type aLength = PR_UINT32_MAX) + { + NS_StringContainerInit(*this); + NS_StringSetData(*this, aData, aLength); + } + + ~nsEmbedString() + { + NS_StringContainerFinish(*this); + } + + const char_type* get() const + { + const char_type* data; + NS_StringGetData(*this, &data); + return data; + } + + self_type& operator=(const self_type& aString) { Assign(aString); return *this; } + self_type& operator=(const abstract_string_type& aReadable) { Assign(aReadable); return *this; } + self_type& operator=(const char_type* aPtr) { Assign(aPtr); return *this; } + self_type& operator=(char_type aChar) { Assign(aChar); return *this; } + }; + +class nsEmbedCString : public nsCStringContainer + { + public: + typedef nsEmbedCString self_type; + typedef nsACString abstract_string_type; + + nsEmbedCString() +#ifdef VBOX + : nsCStringContainer() +#endif + { + NS_CStringContainerInit(*this); + } + + nsEmbedCString(const self_type& aString) +#ifdef VBOX + : nsCStringContainer() +#endif + { + NS_CStringContainerInit(*this); + NS_CStringCopy(*this, aString); + } + + explicit + nsEmbedCString(const abstract_string_type& aReadable) +#ifdef VBOX + : nsCStringContainer() +#endif + { + NS_CStringContainerInit(*this); + NS_CStringCopy(*this, aReadable); + } + + explicit + nsEmbedCString(const char_type* aData, size_type aLength = PR_UINT32_MAX) +#ifdef VBOX + : nsCStringContainer() +#endif + { + NS_CStringContainerInit(*this); + NS_CStringSetData(*this, aData, aLength); + } + + ~nsEmbedCString() + { + NS_CStringContainerFinish(*this); + } + + const char_type* get() const + { + const char_type* data; + NS_CStringGetData(*this, &data); + return data; + } + + self_type& operator=(const self_type& aString) { Assign(aString); return *this; } + self_type& operator=(const abstract_string_type& aReadable) { Assign(aReadable); return *this; } + self_type& operator=(const char_type* aPtr) { Assign(aPtr); return *this; } + self_type& operator=(char_type aChar) { Assign(aChar); return *this; } + }; + +#endif // !defined(nsEmbedString_h___) diff --git a/src/libs/xpcom18a4/xpcom/string/public/nsLiteralString.h b/src/libs/xpcom18a4/xpcom/string/public/nsLiteralString.h new file mode 100644 index 00000000..ba536297 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/public/nsLiteralString.h @@ -0,0 +1,116 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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. + * Portions created by the Initial Developer are Copyright (C) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Scott Collins (original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +#ifndef nsLiteralString_h___ +#define nsLiteralString_h___ + +#ifndef nscore_h___ +#include "nscore.h" +#endif + +#ifndef nsDependentString_h___ +#include "nsDependentString.h" +#endif + + +#if 0 +inline +const nsDependentString +literal_string( const nsAString::char_type* aPtr ) + { + return nsDependentString(aPtr); + } + +inline +const nsDependentString +literal_string( const nsAString::char_type* aPtr, PRUint32 aLength ) + { + return nsDependentString(aPtr, aLength); + } + +inline +const nsDependentCString +literal_string( const nsACString::char_type* aPtr ) + { + return nsDependentCString(aPtr); + } + +inline +const nsDependentCString +literal_string( const nsACString::char_type* aPtr, PRUint32 aLength ) + { + return nsDependentCString(aPtr, aLength); + } +#endif + +#ifdef HAVE_CPP_2BYTE_WCHAR_T + #define NS_LL(s) L##s + #define NS_MULTILINE_LITERAL_STRING(s) nsDependentString(NS_REINTERPRET_CAST(const nsAString::char_type*, s), PRUint32((sizeof(s)/sizeof(wchar_t))-1)) + #define NS_MULTILINE_LITERAL_STRING_INIT(n,s) n(NS_REINTERPRET_CAST(const nsAString::char_type*, s), PRUint32((sizeof(s)/sizeof(wchar_t))-1)) + #define NS_NAMED_MULTILINE_LITERAL_STRING(n,s) const nsDependentString n(NS_REINTERPRET_CAST(const nsAString::char_type*, s), PRUint32((sizeof(s)/sizeof(wchar_t))-1)) + typedef nsDependentString nsLiteralString; +#else + #define NS_LL(s) s + #define NS_MULTILINE_LITERAL_STRING(s) NS_ConvertASCIItoUTF16(s, PRUint32(sizeof(s)-1)) + #define NS_MULTILINE_LITERAL_STRING_INIT(n,s) n(s, PRUint32(sizeof(s)-1)) + #define NS_NAMED_MULTILINE_LITERAL_STRING(n,s) const NS_ConvertASCIItoUTF16 n(s, PRUint32(sizeof(s)-1)) + typedef NS_ConvertASCIItoUTF16 nsLiteralString; +#endif + +/* + * Macro arguments used in concatenation or stringification won't be expanded. + * Therefore, in order for |NS_L(FOO)| to work as expected (which is to expand + * |FOO| before doing whatever |NS_L| needs to do to it) a helper macro needs + * to be inserted in between to allow the macro argument to expand. + * See "3.10.6 Separate Expansion of Macro Arguments" of the CPP manual for a + * more accurate and precise explanation. + */ + +#define NS_L(s) NS_LL(s) + +#define NS_LITERAL_STRING(s) NS_STATIC_CAST(const nsAFlatString&, NS_MULTILINE_LITERAL_STRING(NS_LL(s))) +#define NS_LITERAL_STRING_INIT(n,s) NS_MULTILINE_LITERAL_STRING_INIT(n, NS_LL(s)) +#define NS_NAMED_LITERAL_STRING(n,s) NS_NAMED_MULTILINE_LITERAL_STRING(n, NS_LL(s)) + +#define NS_LITERAL_CSTRING(s) NS_STATIC_CAST(const nsDependentCString&, nsDependentCString(s, PRUint32(sizeof(s)-1))) +#define NS_LITERAL_CSTRING_INIT(n,s) n(s, PRUint32(sizeof(s)-1)) +#define NS_NAMED_LITERAL_CSTRING(n,s) const nsDependentCString n(s, PRUint32(sizeof(s)-1)) + +typedef nsDependentCString nsLiteralCString; + +#endif /* !defined(nsLiteralString_h___) */ diff --git a/src/libs/xpcom18a4/xpcom/string/public/nsObsoleteAString.h b/src/libs/xpcom18a4/xpcom/string/public/nsObsoleteAString.h new file mode 100644 index 00000000..00d5892e --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/public/nsObsoleteAString.h @@ -0,0 +1,102 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* ***** 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 IBM Corporation. + * Portions created by IBM Corporation are Copyright (C) 2003 + * IBM Corporation. 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 ***** */ + +#ifndef nsObsoleteAString_h___ +#define nsObsoleteAString_h___ + +/* + STRING INTERNALS + + This file defines nsObsoleteAString and nsObsoleteACString. These are + abstract classes (interfaces), containing only virtual functions + corresponding to the FROZEN nsA[C]String classes. They exist to provide + the new non-abstract nsA[C]String classes with a mechanism to maintain + backwards binary compatability. + + From a binary point-of-view, the new nsA[C]String classes appear to have a + vtable pointer to the vtable of nsObsoleteA[C]StringThunk. + nsObsoleteA[C]StringThunk is a subclass of nsObsoleteA[C]String that serves + as a simple bridge between the virtual functions that make up the FROZEN + nsA[C]String contract and the new ns[C]Substring, which is now our only + subclass of nsA[C]String. + + The methods on the new nsA[C]String are now all non-virtual. This reduces + codesize at the callsite, and reduces the number of memory dereferences and + jumps required to invoke a method on nsA[C]String. The result is improved + performance and reduced codesize. However, to maintain binary + compatibility, each method on nsA[C]String must check the value of its + vtable to determine if it corresponds to the built-in implementation of + nsObsoleteA[C]String (i.e., the address of the canonical vtable). If it + does, then the vtable can be ignored, and the nsA[C]String object (i.e., + |this|) can be cast to ns[C]Substring directly. In which case, the + nsA[C]String methods can be satisfied by invoking the corresponding methods + directly on ns[C]Substring. If the vtable address does not correspond to + the built-in implementation, then the virtual functions on + nsObsoleteA[C]String must be invoked instead. + + So, if a nsA[C]String reference corresponds to an external implementation + (such as the old nsEmbed[C]String that shipped with previous versions of + Mozilla), then methods invoked on that nsA[C]String will still act like + virtual function calls. This ensures binary compatibility while avoiding + virtual function calls in most cases. + + Finally, nsObsoleteA[C]String (i.e., the FROZEN nsA[C]String vtable) is + now a DEPRECATED interface. See nsStringAPI.h and nsEmbedString.h for + the new preferred way to access nsA[C]String references in an external + component or Gecko embedding application. + */ + +#ifndef nsStringFwd_h___ +#include "nsStringFwd.h" +#endif + +#ifndef nscore_h___ +#include "nscore.h" +#endif + + // declare nsObsoleteAString +#include "string-template-def-unichar.h" +#include "nsTObsoleteAString.h" +#include "string-template-undef.h" + + // declare nsObsoleteACString +#include "string-template-def-char.h" +#include "nsTObsoleteAString.h" +#include "string-template-undef.h" + +#endif // !defined(nsObsoleteAString_h___) diff --git a/src/libs/xpcom18a4/xpcom/string/public/nsPrintfCString.h b/src/libs/xpcom18a4/xpcom/string/public/nsPrintfCString.h new file mode 100644 index 00000000..3f3d04d3 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/public/nsPrintfCString.h @@ -0,0 +1,87 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1994-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +#ifndef nsPrintfCString_h___ +#define nsPrintfCString_h___ + +#ifndef nsString_h___ +#include "nsString.h" +#endif + + + /** + * |nsPrintfCString| lets you use a formated |printf| string as an |const nsACString|. + * + * myCStr += nsPrintfCString("%f", 13.917); + * // ...a general purpose substitute for |AppendFloat| + * + * For longer patterns, you'll want to use the constructor that takes a length + * + * nsPrintfCString(128, "%f, %f, %f, %f, %f, %f, %f, %i, %f", x, y, z, 3.2, j, k, l, 3, 3.1); + * + * Exceding the default size (which you must specify in the constructor, it is not determined) + * causes an allocation, so avoid that. If your formatted string exceeds the allocated space, it is + * cut off at the size of the buffer, no error is reported (and no out-of-bounds writing occurs). + * This class is intended to be useful for numbers and short + * strings, not arbitrary formatting of other strings (e.g., with %s). There is currently no + * wide version of this class, since wide |printf| is not generally available. That means + * to get a wide version of your formatted data, you must, e.g., + * + * CopyASCIItoUTF16(nsPrintfCString("%f", 13.917"), myStr); + * + * That's another good reason to avoid this class for anything but numbers ... as strings can be + * much more efficiently handled with |NS_LITERAL_[C]STRING| and |nsLiteral[C]String|. + */ + +class NS_COM nsPrintfCString : public nsCString + { + typedef nsCString string_type; + + enum { kLocalBufferSize=15 }; + // ought to be large enough for most things ... a |long long| needs at most 20 (so you'd better ask) + // pinkerton suggests 7. We should measure and decide what's appropriate + + public: + // XXX don't these need to be declared CDECL ?? + explicit nsPrintfCString( const char_type* format, ... ); + nsPrintfCString( size_type n, const char_type* format, ...); + + private: + char_type mLocalBuffer[ kLocalBufferSize + 1 ]; + }; + +#endif // !defined(nsPrintfCString_h___) diff --git a/src/libs/xpcom18a4/xpcom/string/public/nsPromiseFlatString.h b/src/libs/xpcom18a4/xpcom/string/public/nsPromiseFlatString.h new file mode 100644 index 00000000..b98aa1a2 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/public/nsPromiseFlatString.h @@ -0,0 +1,56 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* ***** 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 IBM Corporation. + * Portions created by IBM Corporation are Copyright (C) 2003 + * IBM Corporation. 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 ***** */ + +#ifndef nsPromiseFlatString_h___ +#define nsPromiseFlatString_h___ + +#ifndef nsString_h___ +#include "nsString.h" +#endif + + // declare nsPromiseFlatString +#include "string-template-def-unichar.h" +#include "nsTPromiseFlatString.h" +#include "string-template-undef.h" + + // declare nsPromiseFlatCString +#include "string-template-def-char.h" +#include "nsTPromiseFlatString.h" +#include "string-template-undef.h" + +#endif /* !defined(nsPromiseFlatString_h___) */ diff --git a/src/libs/xpcom18a4/xpcom/string/public/nsReadableUtils.h b/src/libs/xpcom18a4/xpcom/string/public/nsReadableUtils.h new file mode 100644 index 00000000..13f94c09 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/public/nsReadableUtils.h @@ -0,0 +1,370 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Scott Collins (original author) + * Johnny Stenbeck + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +#ifndef nsReadableUtils_h___ +#define nsReadableUtils_h___ + + /** + * I guess all the routines in this file are all mis-named. + * According to our conventions, they should be |NS_xxx|. + */ + +#ifndef nsAString_h___ +#include "nsAString.h" +#endif + +inline size_t Distance( const nsReadingIterator& start, const nsReadingIterator& end ) + { + return end.get() - start.get(); + } +inline size_t Distance( const nsReadingIterator& start, const nsReadingIterator& end ) + { + return end.get() - start.get(); + } + +NS_COM void LossyCopyUTF16toASCII( const nsAString& aSource, nsACString& aDest ); +NS_COM void CopyASCIItoUTF16( const nsACString& aSource, nsAString& aDest ); + +NS_COM void LossyCopyUTF16toASCII( const PRUnichar* aSource, nsACString& aDest ); +NS_COM void CopyASCIItoUTF16( const char* aSource, nsAString& aDest ); + +NS_COM void CopyUTF16toUTF8( const nsAString& aSource, nsACString& aDest ); +NS_COM void CopyUTF8toUTF16( const nsACString& aSource, nsAString& aDest ); + +NS_COM void CopyUTF16toUTF8( const PRUnichar* aSource, nsACString& aDest ); +NS_COM void CopyUTF8toUTF16( const char* aSource, nsAString& aDest ); + +NS_COM void LossyAppendUTF16toASCII( const nsAString& aSource, nsACString& aDest ); +NS_COM void AppendASCIItoUTF16( const nsACString& aSource, nsAString& aDest ); + +NS_COM void LossyAppendUTF16toASCII( const PRUnichar* aSource, nsACString& aDest ); +NS_COM void AppendASCIItoUTF16( const char* aSource, nsAString& aDest ); + +NS_COM void AppendUTF16toUTF8( const nsAString& aSource, nsACString& aDest ); +NS_COM void AppendUTF8toUTF16( const nsACString& aSource, nsAString& aDest ); + +NS_COM void AppendUTF16toUTF8( const PRUnichar* aSource, nsACString& aDest ); +NS_COM void AppendUTF8toUTF16( const char* aSource, nsAString& aDest ); + +// Backward compatibility +inline +NS_COM void CopyUCS2toASCII( const nsAString& aSource, nsACString& aDest ) +{ LossyCopyUTF16toASCII(aSource, aDest); } +inline +NS_COM void CopyASCIItoUCS2( const nsACString& aSource, nsAString& aDest ) +{ CopyASCIItoUTF16(aSource, aDest); } + + /** + * Returns a new |char| buffer containing a zero-terminated copy of |aSource|. + * + * Allocates and returns a new |char| buffer which you must free with |nsMemory::Free|. + * Performs a lossy encoding conversion by chopping 16-bit wide characters down to 8-bits wide while copying |aSource| to your new buffer. + * This conversion is not well defined; but it reproduces legacy string behavior. + * The new buffer is zero-terminated, but that may not help you if |aSource| contains embedded nulls. + * + * @param aSource a 16-bit wide string + * @return a new |char| buffer you must free with |nsMemory::Free|. + */ +NS_COM char* ToNewCString( const nsAString& aSource ); + + + /** + * Returns a new |char| buffer containing a zero-terminated copy of |aSource|. + * + * Allocates and returns a new |char| buffer which you must free with |nsMemory::Free|. + * The new buffer is zero-terminated, but that may not help you if |aSource| contains embedded nulls. + * + * @param aSource an 8-bit wide string + * @return a new |char| buffer you must free with |nsMemory::Free|. + */ +NS_COM char* ToNewCString( const nsACString& aSource ); + + /** + * Returns a new |char| buffer containing a zero-terminated copy of |aSource|. + * + * Allocates and returns a new |char| buffer which you must free with + * |nsMemory::Free|. + * Performs an encoding conversion from a UTF-16 string to a UTF-8 string + * copying |aSource| to your new buffer. + * The new buffer is zero-terminated, but that may not help you if |aSource| + * contains embedded nulls. + * + * @param aSource a UTF-16 string (made of PRUnichar's) + * @param aUTF8Count the number of 8-bit units that was returned + * @return a new |char| buffer you must free with |nsMemory::Free|. + */ + +NS_COM char* ToNewUTF8String( const nsAString& aSource, PRUint32 *aUTF8Count = nsnull ); + + + /** + * Returns a new |PRUnichar| buffer containing a zero-terminated copy of + * |aSource|. + * + * Allocates and returns a new |PRUnichar| buffer which you must free with + * |nsMemory::Free|. + * The new buffer is zero-terminated, but that may not help you if |aSource| + * contains embedded nulls. + * + * @param aSource a UTF-16 string + * @return a new |PRUnichar| buffer you must free with |nsMemory::Free|. + */ +NS_COM PRUnichar* ToNewUnicode( const nsAString& aSource ); + + + /** + * Returns a new |PRUnichar| buffer containing a zero-terminated copy of |aSource|. + * + * Allocates and returns a new |PRUnichar| buffer which you must free with |nsMemory::Free|. + * Performs an encoding conversion by 0-padding 8-bit wide characters up to 16-bits wide while copying |aSource| to your new buffer. + * This conversion is not well defined; but it reproduces legacy string behavior. + * The new buffer is zero-terminated, but that may not help you if |aSource| contains embedded nulls. + * + * @param aSource an 8-bit wide string (a C-string, NOT UTF-8) + * @return a new |PRUnichar| buffer you must free with |nsMemory::Free|. + */ +NS_COM PRUnichar* ToNewUnicode( const nsACString& aSource ); + + /** + * Returns a new |PRUnichar| buffer containing a zero-terminated copy + * of |aSource|. + * + * Allocates and returns a new |char| buffer which you must free with + * |nsMemory::Free|. Performs an encoding conversion from UTF-8 to UTF-16 + * while copying |aSource| to your new buffer. This conversion is well defined + * for a valid UTF-8 string. The new buffer is zero-terminated, but that + * may not help you if |aSource| contains embedded nulls. + * + * @param aSource an 8-bit wide string, UTF-8 encoded + * @param aUTF16Count the number of 16-bit units that was returned + * @return a new |PRUnichar| buffer you must free with |nsMemory::Free|. + * (UTF-16 encoded) + */ +NS_COM PRUnichar* UTF8ToNewUnicode( const nsACString& aSource, PRUint32 *aUTF16Count = nsnull ); + + /** + * Copies |aLength| 16-bit code units from the start of |aSource| to the + * |PRUnichar| buffer |aDest|. + * + * After this operation |aDest| is not null terminated. + * + * @param aSource a UTF-16 string + * @param aSrcOffset start offset in the source string + * @param aDest a |PRUnichar| buffer + * @param aLength the number of 16-bit code units to copy + * @return pointer to destination buffer - identical to |aDest| + */ +NS_COM PRUnichar* CopyUnicodeTo( const nsAString& aSource, + PRUint32 aSrcOffset, + PRUnichar* aDest, + PRUint32 aLength ); + + + /** + * Copies 16-bit characters between iterators |aSrcStart| and + * |aSrcEnd| to the writable string |aDest|. Similar to the + * |nsString::Mid| method. + * + * After this operation |aDest| is not null terminated. + * + * @param aSrcStart start source iterator + * @param aSrcEnd end source iterator + * @param aDest destination for the copy + */ +NS_COM void CopyUnicodeTo( const nsAString::const_iterator& aSrcStart, + const nsAString::const_iterator& aSrcEnd, + nsAString& aDest ); + + /** + * Appends 16-bit characters between iterators |aSrcStart| and + * |aSrcEnd| to the writable string |aDest|. + * + * After this operation |aDest| is not null terminated. + * + * @param aSrcStart start source iterator + * @param aSrcEnd end source iterator + * @param aDest destination for the copy + */ +NS_COM void AppendUnicodeTo( const nsAString::const_iterator& aSrcStart, + const nsAString::const_iterator& aSrcEnd, + nsAString& aDest ); + + /** + * Returns |PR_TRUE| if |aString| contains only ASCII characters, that is, characters in the range (0x00, 0x7F). + * + * @param aString a 16-bit wide string to scan + */ +NS_COM PRBool IsASCII( const nsAString& aString ); + + /** + * Returns |PR_TRUE| if |aString| contains only ASCII characters, that is, characters in the range (0x00, 0x7F). + * + * @param aString a 8-bit wide string to scan + */ +NS_COM PRBool IsASCII( const nsACString& aString ); + + + /** + * Returns |PR_TRUE| if |aString| is a valid UTF-8 string. + * XXX This is not bullet-proof and nor an all-purpose UTF-8 validator. + * It is mainly written to replace and roughly equivalent to + * + * str.Equals(NS_ConvertUTF16toUTF8(NS_ConvertUTF8toUTF16(str))) + * + * (see bug 191541) + * As such, it does not check for non-UTF-8 7bit encodings such as + * ISO-2022-JP and HZ. However, it filters out UTF-8 representation + * of surrogate codepoints and non-characters ( 0xFFFE and 0xFFFF + * in planes 0 through 16.) as well as overlong UTF-8 sequences. + * Also note that it regards UTF-8 sequences corresponding to + * codepoints above 0x10FFFF as invalid in accordance with + * http://www.ietf.org/internet-drafts/draft-yergeau-rfc2279bis-04.txt + * + * @param aString an 8-bit wide string to scan + */ +NS_COM PRBool IsUTF8( const nsACString& aString ); + + + /** + * Converts case in place in the argument string. + */ +NS_COM void ToUpperCase( nsACString& ); + +NS_COM void ToLowerCase( nsACString& ); + +NS_COM void ToUpperCase( nsCSubstring& ); + +NS_COM void ToLowerCase( nsCSubstring& ); + + /** + * Converts case from string aSource to aDest. + */ +NS_COM void ToUpperCase( const nsACString& aSource, nsACString& aDest ); + +NS_COM void ToLowerCase( const nsACString& aSource, nsACString& aDest ); + + /** + * Finds the leftmost occurance of |aPattern|, if any in the range |aSearchStart|..|aSearchEnd|. + * + * Returns |PR_TRUE| if a match was found, and adjusts |aSearchStart| and |aSearchEnd| to + * point to the match. If no match was found, returns |PR_FALSE| and makes |aSearchStart == aSearchEnd|. + * + * Currently, this is equivalent to the O(m*n) implementation previously on |ns[C]String|. + * If we need something faster, then we can implement that later. + */ + +NS_COM PRBool FindInReadable( const nsAString& aPattern, nsAString::const_iterator&, nsAString::const_iterator&, const nsStringComparator& = nsDefaultStringComparator() ); +NS_COM PRBool FindInReadable( const nsACString& aPattern, nsACString::const_iterator&, nsACString::const_iterator&, const nsCStringComparator& = nsDefaultCStringComparator() ); + +/* sometimes we don't care about where the string was, just that we + * found it or not */ +inline PRBool FindInReadable( const nsAString& aPattern, const nsAString& aSource, const nsStringComparator& compare = nsDefaultStringComparator() ) +{ + nsAString::const_iterator start, end; + aSource.BeginReading(start); + aSource.EndReading(end); + return FindInReadable(aPattern, start, end, compare); +} + +inline PRBool FindInReadable( const nsACString& aPattern, const nsACString& aSource, const nsCStringComparator& compare = nsDefaultCStringComparator() ) +{ + nsACString::const_iterator start, end; + aSource.BeginReading(start); + aSource.EndReading(end); + return FindInReadable(aPattern, start, end, compare); +} + + +NS_COM PRBool CaseInsensitiveFindInReadable( const nsACString& aPattern, nsACString::const_iterator&, nsACString::const_iterator& ); + + /** + * Finds the rightmost occurance of |aPattern| + * Returns |PR_TRUE| if a match was found, and adjusts |aSearchStart| and |aSearchEnd| to + * point to the match. If no match was found, returns |PR_FALSE| and makes |aSearchStart == aSearchEnd|. + * + * Currently, this is equivalent to the O(m*n) implementation previously on |ns[C]String|. + * If we need something faster, then we can implement that later. + */ +NS_COM PRBool RFindInReadable( const nsAString& aPattern, nsAString::const_iterator&, nsAString::const_iterator&, const nsStringComparator& = nsDefaultStringComparator() ); +NS_COM PRBool RFindInReadable( const nsACString& aPattern, nsACString::const_iterator&, nsACString::const_iterator&, const nsCStringComparator& = nsDefaultCStringComparator() ); + + /** + * Finds the leftmost occurance of |aChar|, if any in the range + * |aSearchStart|..|aSearchEnd|. + * + * Returns |PR_TRUE| if a match was found, and adjusts |aSearchStart| to + * point to the match. If no match was found, returns |PR_FALSE| and + * makes |aSearchStart == aSearchEnd|. + */ +NS_COM PRBool FindCharInReadable( PRUnichar aChar, nsAString::const_iterator& aSearchStart, const nsAString::const_iterator& aSearchEnd ); +NS_COM PRBool FindCharInReadable( char aChar, nsACString::const_iterator& aSearchStart, const nsACString::const_iterator& aSearchEnd ); + + /** + * Finds the number of occurences of |aChar| in the string |aStr| + */ +NS_COM PRUint32 CountCharInReadable( const nsAString& aStr, + PRUnichar aChar ); +NS_COM PRUint32 CountCharInReadable( const nsACString& aStr, + char aChar ); + +NS_COM PRBool +StringBeginsWith( const nsAString& aSource, const nsAString& aSubstring, + const nsStringComparator& aComparator = + nsDefaultStringComparator() ); +NS_COM PRBool +StringBeginsWith( const nsACString& aSource, const nsACString& aSubstring, + const nsCStringComparator& aComparator = + nsDefaultCStringComparator() ); +NS_COM PRBool +StringEndsWith( const nsAString& aSource, const nsAString& aSubstring, + const nsStringComparator& aComparator = + nsDefaultStringComparator() ); +NS_COM PRBool +StringEndsWith( const nsACString& aSource, const nsACString& aSubstring, + const nsCStringComparator& aComparator = + nsDefaultCStringComparator() ); + +NS_COM PRUint32 HashString( const nsAString& aStr ); +NS_COM PRUint32 HashString( const nsACString& aStr ); + +NS_COM const nsAFlatString& EmptyString(); +NS_COM const nsAFlatCString& EmptyCString(); + + +#endif // !defined(nsReadableUtils_h___) diff --git a/src/libs/xpcom18a4/xpcom/string/public/nsString.h b/src/libs/xpcom18a4/xpcom/string/public/nsString.h new file mode 100644 index 00000000..67376d19 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/public/nsString.h @@ -0,0 +1,237 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* ***** 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 IBM Corporation. + * Portions created by IBM Corporation are Copyright (C) 2003 + * IBM Corporation. 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 ***** */ + +#ifndef nsString_h___ +#define nsString_h___ + + +#ifndef nsSubstring_h___ +#include "nsSubstring.h" +#endif + +#ifndef nsDependentSubstring_h___ +#include "nsDependentSubstring.h" +#endif + +#ifndef nsReadableUtils_h___ +#include "nsReadableUtils.h" +#endif + +#include NEW_H + + // enable support for the obsolete string API if not explicitly disabled +#ifndef MOZ_STRING_WITH_OBSOLETE_API +#define MOZ_STRING_WITH_OBSOLETE_API 1 +#endif + +#if MOZ_STRING_WITH_OBSOLETE_API + // radix values for ToInteger/AppendInt +#define kRadix10 (10) +#define kRadix16 (16) +#define kAutoDetect (100) +#define kRadixUnknown (kAutoDetect+1) +#define IGNORE_CASE (PR_TRUE) +#endif + + + // declare nsString, et. al. +#include "string-template-def-unichar.h" +#include "nsTString.h" +#include "string-template-undef.h" + + // declare nsCString, et. al. +#include "string-template-def-char.h" +#include "nsTString.h" +#include "string-template-undef.h" + + + /** + * A helper class that converts a UTF-16 string to ASCII in a lossy manner + */ +class NS_LossyConvertUTF16toASCII : public nsCAutoString + { + public: + explicit + NS_LossyConvertUTF16toASCII( const PRUnichar* aString ) + { + LossyAppendUTF16toASCII(aString, *this); + } + + NS_LossyConvertUTF16toASCII( const PRUnichar* aString, PRUint32 aLength ) + { + LossyAppendUTF16toASCII(Substring(aString, aString + aLength), *this); + } + + explicit + NS_LossyConvertUTF16toASCII( const nsAString& aString ) + { + LossyAppendUTF16toASCII(aString, *this); + } + + private: + // NOT TO BE IMPLEMENTED + NS_LossyConvertUTF16toASCII( char ); + }; + + +class NS_ConvertASCIItoUTF16 : public nsAutoString + { + public: + explicit + NS_ConvertASCIItoUTF16( const char* aCString ) + { + AppendASCIItoUTF16(aCString, *this); + } + + NS_ConvertASCIItoUTF16( const char* aCString, PRUint32 aLength ) + { + AppendASCIItoUTF16(Substring(aCString, aCString + aLength), *this); + } + + explicit + NS_ConvertASCIItoUTF16( const nsACString& aCString ) + { + AppendASCIItoUTF16(aCString, *this); + } + + private: + // NOT TO BE IMPLEMENTED + NS_ConvertASCIItoUTF16( PRUnichar ); + }; + + + /** + * A helper class that converts a UTF-16 string to UTF-8 + */ +class NS_ConvertUTF16toUTF8 : public nsCAutoString + { + public: + explicit + NS_ConvertUTF16toUTF8( const PRUnichar* aString ) + { + AppendUTF16toUTF8(aString, *this); + } + + NS_ConvertUTF16toUTF8( const PRUnichar* aString, PRUint32 aLength ) + { + AppendUTF16toUTF8(Substring(aString, aString + aLength), *this); + } + + explicit + NS_ConvertUTF16toUTF8( const nsAString& aString ) + { + AppendUTF16toUTF8(aString, *this); + } + + private: + // NOT TO BE IMPLEMENTED + NS_ConvertUTF16toUTF8( char ); + }; + + +class NS_ConvertUTF8toUTF16 : public nsAutoString + { + public: + explicit + NS_ConvertUTF8toUTF16( const char* aCString ) + { + AppendUTF8toUTF16(aCString, *this); + } + + NS_ConvertUTF8toUTF16( const char* aCString, PRUint32 aLength ) + { + AppendUTF8toUTF16(Substring(aCString, aCString + aLength), *this); + } + + explicit + NS_ConvertUTF8toUTF16( const nsACString& aCString ) + { + AppendUTF8toUTF16(aCString, *this); + } + + private: + // NOT TO BE IMPLEMENTED + NS_ConvertUTF8toUTF16( PRUnichar ); + }; + + +// the following are included/declared for backwards compatibility + +typedef NS_ConvertUTF16toUTF8 NS_ConvertUCS2toUTF8; +typedef NS_LossyConvertUTF16toASCII NS_LossyConvertUCS2toASCII; +typedef NS_ConvertASCIItoUTF16 NS_ConvertASCIItoUCS2; +typedef NS_ConvertUTF8toUTF16 NS_ConvertUTF8toUCS2; +typedef nsAutoString nsVoidableString; + +#ifndef nsDependentString_h___ +#include "nsDependentString.h" +#endif + +#ifndef nsLiteralString_h___ +#include "nsLiteralString.h" +#endif + +#ifndef nsPromiseFlatString_h___ +#include "nsPromiseFlatString.h" +#endif + +// need to include these for backwards compatibility +#include "nsMemory.h" +#include +#include +#include "plhash.h" + +inline PRInt32 MinInt(PRInt32 x, PRInt32 y) + { + return NS_MIN(x, y); + } + +inline PRInt32 MaxInt(PRInt32 x, PRInt32 y) + { + return NS_MAX(x, y); + } + +/** + * Deprecated: don't use |Recycle|, just call |nsMemory::Free| directly + * + * Return the given buffer to the heap manager. Calls allocator::Free() + */ +inline void Recycle( char* aBuffer) { nsMemory::Free(aBuffer); } +inline void Recycle( PRUnichar* aBuffer) { nsMemory::Free(aBuffer); } + +#endif // !defined(nsString_h___) diff --git a/src/libs/xpcom18a4/xpcom/string/public/nsStringAPI.h b/src/libs/xpcom18a4/xpcom/string/public/nsStringAPI.h new file mode 100644 index 00000000..cc0818b6 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/public/nsStringAPI.h @@ -0,0 +1,853 @@ +/* vim:set ts=2 sw=2 et cindent: */ +/* ***** 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 IBM Corporation. + * Portions created by IBM Corporation are Copyright (C) 2003 + * IBM Corporation. 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 ***** */ + +#ifndef nsStringAPI_h__ +#define nsStringAPI_h__ + +/** + * nsStringAPI.h + * + * This file describes a minimal API for working with XPCOM's abstract + * string classes. It divorces the consumer from having any run-time + * dependency on the implementation details of the abstract string types. + */ + +#include "nscore.h" + +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +#define NS_CStringContainerInit VBoxNsxpNS_CStringContainerInit +#define NS_CStringContainerFinish VBoxNsxpNS_CStringContainerFinish +#define NS_CStringCloneData VBoxNsxpNS_CStringCloneData +#define NS_CStringCopy VBoxNsxpNS_CStringCopy +#define NS_CStringGetData VBoxNsxpNS_CStringGetData +#define NS_CStringSetData VBoxNsxpNS_CStringSetData +#define NS_CStringSetDataRange VBoxNsxpNS_CStringSetDataRange +#define NS_UTF16ToCString VBoxNsxpNS_UTF16ToCString +#define NS_CStringToUTF16 VBoxNsxpNS_CStringToUTF16 +#define NS_StringContainerInit VBoxNsxpNS_StringContainerInit +#define NS_StringContainerFinish VBoxNsxpNS_StringContainerFinish +#define NS_StringCloneData VBoxNsxpNS_StringCloneData +#define NS_StringCopy VBoxNsxpNS_StringCopy +#define NS_StringGetData VBoxNsxpNS_StringGetData +#define NS_StringSetData VBoxNsxpNS_StringSetData +#define NS_StringSetDataRange VBoxNsxpNS_StringSetDataRange +#endif /* VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + +#define NS_STRINGAPI(x) extern "C" NS_COM x + +/* The base string types */ +class nsAString; +class nsACString; + +/* ------------------------------------------------------------------------- */ + +/** + * nsStringContainer + * + * This is an opaque data type that is large enough to hold the canonical + * implementation of nsAString. The binary structure of this class is an + * implementation detail. + * + * The string data stored in a string container is always single fragment + * and null-terminated. + * + * Typically, string containers are allocated on the stack for temporary + * use. However, they can also be malloc'd if necessary. In either case, + * a string container is not useful until it has been initialized with a + * call to NS_StringContainerInit. The following example shows how to use + * a string container to call a function that takes a |nsAString &| out-param. + * + * NS_METHOD GetBlah(nsAString &aBlah); + * + * nsresult MyCode() + * { + * nsresult rv; + * + * nsStringContainer sc; + * rv = NS_StringContainerInit(sc); + * if (NS_FAILED(rv)) + * return rv; + * + * rv = GetBlah(sc); + * if (NS_SUCCEEDED(rv)) + * { + * const PRUnichar *data; + * NS_StringGetData(sc, &data); + * // + * // |data| now points to the result of the GetBlah function + * // + * } + * + * NS_StringContainerFinish(sc); + * return rv; + * } + * + * The following example show how to use a string container to pass a string + * parameter to a function taking a |const nsAString &| in-param. + * + * NS_METHOD SetBlah(const nsAString &aBlah); + * + * nsresult MyCode() + * { + * nsresult rv; + * + * nsStringContainer sc; + * rv = NS_StringContainerInit(sc); + * if (NS_FAILED(rv)) + * return rv; + * + * const PRUnichar kData[] = {'x','y','z','\0'}; + * rv = NS_StringSetData(sc, kData, sizeof(kData)/2 - 1); + * if (NS_SUCCEEDED(rv)) + * rv = SetBlah(sc); + * + * NS_StringContainerFinish(sc); + * return rv; + * } + */ +class nsStringContainer; + +/** + * NS_StringContainerInit + * + * @param aContainer string container reference + * @return NS_OK if string container successfully initialized + * + * This function may allocate additional memory for aContainer. When + * aContainer is no longer needed, NS_StringContainerFinish should be called. + * + * @status FROZEN + */ +NS_STRINGAPI(nsresult) +NS_StringContainerInit(nsStringContainer &aContainer); + +/** + * NS_StringContainerFinish + * + * @param aContainer string container reference + * + * This function frees any memory owned by aContainer. + * + * @status FROZEN + */ +NS_STRINGAPI(void) +NS_StringContainerFinish(nsStringContainer &aContainer); + +/* ------------------------------------------------------------------------- */ + +/** + * NS_StringGetData + * + * This function returns a const character pointer to the string's internal + * buffer, the length of the string, and a boolean value indicating whether + * or not the buffer is null-terminated. + * + * @param aStr abstract string reference + * @param aData out param that will hold the address of aStr's + * internal buffer + * @param aTerminated if non-null, this out param will be set to indicate + * whether or not aStr's internal buffer is null- + * terminated + * @return length of aStr's internal buffer + * + * @status FROZEN + */ +NS_STRINGAPI(PRUint32) +NS_StringGetData + (const nsAString &aStr, const PRUnichar **aData, + PRBool *aTerminated = nsnull); + +/** + * NS_StringCloneData + * + * This function returns a null-terminated copy of the string's + * internal buffer. + * + * @param aStr abstract string reference + * @return null-terminated copy of the string's internal buffer + * (it must be free'd using using nsMemory::Free) + * + * @status FROZEN + */ +NS_STRINGAPI(PRUnichar *) +NS_StringCloneData + (const nsAString &aStr); + +/** + * NS_StringSetData + * + * This function copies aData into aStr. + * + * @param aStr abstract string reference + * @param aData character buffer + * @param aDataLength number of characters to copy from source string (pass + * PR_UINT32_MAX to copy until end of aData, designated by + * a null character) + * @return NS_OK if function succeeded + * + * This function does not necessarily null-terminate aStr after copying data + * from aData. The behavior depends on the implementation of the abstract + * string, aStr. If aStr is a reference to a nsStringContainer, then its data + * will be null-terminated by this function. + * + * @status FROZEN + */ +NS_STRINGAPI(nsresult) +NS_StringSetData + (nsAString &aStr, const PRUnichar *aData, + PRUint32 aDataLength = PR_UINT32_MAX); + +/** + * NS_StringSetDataRange + * + * This function copies aData into a section of aStr. As a result it can be + * used to insert new characters into the string. + * + * @param aStr abstract string reference + * @param aCutOffset starting index where the string's existing data + * is to be overwritten (pass PR_UINT32_MAX to cause + * aData to be appended to the end of aStr, in which + * case the value of aCutLength is ignored). + * @param aCutLength number of characters to overwrite starting at + * aCutOffset (pass PR_UINT32_MAX to overwrite until the + * end of aStr). + * @param aData character buffer (pass null to cause this function + * to simply remove the "cut" range) + * @param aDataLength number of characters to copy from source string (pass + * PR_UINT32_MAX to copy until end of aData, designated by + * a null character) + * @return NS_OK if function succeeded + * + * This function does not necessarily null-terminate aStr after copying data + * from aData. The behavior depends on the implementation of the abstract + * string, aStr. If aStr is a reference to a nsStringContainer, then its data + * will be null-terminated by this function. + * + * @status FROZEN + */ +NS_STRINGAPI(nsresult) +NS_StringSetDataRange + (nsAString &aStr, PRUint32 aCutOffset, PRUint32 aCutLength, + const PRUnichar *aData, PRUint32 aDataLength = PR_UINT32_MAX); + +/** + * NS_StringCopy + * + * This function makes aDestStr have the same value as aSrcStr. It is + * provided as an optimization. + * + * @param aDestStr abstract string reference to be modified + * @param aSrcStr abstract string reference containing source string + * @return NS_OK if function succeeded + * + * This function does not necessarily null-terminate aDestStr after copying + * data from aSrcStr. The behavior depends on the implementation of the + * abstract string, aDestStr. If aDestStr is a reference to a + * nsStringContainer, then its data will be null-terminated by this function. + * + * @status FROZEN + */ +NS_STRINGAPI(nsresult) +NS_StringCopy + (nsAString &aDestStr, const nsAString &aSrcStr); + +/** + * NS_StringAppendData + * + * This function appends data to the existing value of aStr. + * + * @param aStr abstract string reference to be modified + * @param aData character buffer + * @param aDataLength number of characters to append (pass PR_UINT32_MAX to + * append until a null-character is encountered) + * @return NS_OK if function succeeded + * + * This function does not necessarily null-terminate aStr upon completion. + * The behavior depends on the implementation of the abstract string, aStr. + * If aStr is a reference to a nsStringContainer, then its data will be null- + * terminated by this function. + */ +inline NS_HIDDEN_(nsresult) +NS_StringAppendData(nsAString &aStr, const PRUnichar *aData, + PRUint32 aDataLength = PR_UINT32_MAX) +{ + return NS_StringSetDataRange(aStr, PR_UINT32_MAX, 0, aData, aDataLength); +} + +/** + * NS_StringInsertData + * + * This function inserts data into the existing value of aStr at the specified + * offset. + * + * @param aStr abstract string reference to be modified + * @param aOffset specifies where in the string to insert aData + * @param aData character buffer + * @param aDataLength number of characters to append (pass PR_UINT32_MAX to + * append until a null-character is encountered) + * @return NS_OK if function succeeded + * + * This function does not necessarily null-terminate aStr upon completion. + * The behavior depends on the implementation of the abstract string, aStr. + * If aStr is a reference to a nsStringContainer, then its data will be null- + * terminated by this function. + */ +inline NS_HIDDEN_(nsresult) +NS_StringInsertData(nsAString &aStr, PRUint32 aOffset, const PRUnichar *aData, + PRUint32 aDataLength = PR_UINT32_MAX) +{ + return NS_StringSetDataRange(aStr, aOffset, 0, aData, aDataLength); +} + +/** + * NS_StringCutData + * + * This function shortens the existing value of aStr, by removing characters + * at the specified offset. + * + * @param aStr abstract string reference to be modified + * @param aCutOffset specifies where in the string to insert aData + * @param aCutLength number of characters to remove + * @return NS_OK if function succeeded + */ +inline NS_HIDDEN_(nsresult) +NS_StringCutData(nsAString &aStr, PRUint32 aCutOffset, PRUint32 aCutLength) +{ + return NS_StringSetDataRange(aStr, aCutOffset, aCutLength, nsnull, 0); +} + +/* ------------------------------------------------------------------------- */ + +/** + * nsCStringContainer + * + * This is an opaque data type that is large enough to hold the canonical + * implementation of nsACString. The binary structure of this class is an + * implementation detail. + * + * The string data stored in a string container is always single fragment + * and null-terminated. + * + * @see nsStringContainer for use cases and further documentation. + */ +class nsCStringContainer; + +/** + * NS_CStringContainerInit + * + * @param aContainer string container reference + * @return NS_OK if string container successfully initialized + * + * This function may allocate additional memory for aContainer. When + * aContainer is no longer needed, NS_CStringContainerFinish should be called. + * + * @status FROZEN + */ +NS_STRINGAPI(nsresult) +NS_CStringContainerInit(nsCStringContainer &aContainer); + +/** + * NS_CStringContainerFinish + * + * @param aContainer string container reference + * + * This function frees any memory owned by aContainer. + * + * @status FROZEN + */ +NS_STRINGAPI(void) +NS_CStringContainerFinish(nsCStringContainer &aContainer); + +/* ------------------------------------------------------------------------- */ + +/** + * NS_CStringGetData + * + * This function returns a const character pointer to the string's internal + * buffer, the length of the string, and a boolean value indicating whether + * or not the buffer is null-terminated. + * + * @param aStr abstract string reference + * @param aData out param that will hold the address of aStr's + * internal buffer + * @param aTerminated if non-null, this out param will be set to indicate + * whether or not aStr's internal buffer is null- + * terminated + * @return length of aStr's internal buffer + * + * @status FROZEN + */ +NS_STRINGAPI(PRUint32) +NS_CStringGetData + (const nsACString &aStr, const char **aData, + PRBool *aTerminated = nsnull); + +/** + * NS_CStringCloneData + * + * This function returns a null-terminated copy of the string's + * internal buffer. + * + * @param aStr abstract string reference + * @return null-terminated copy of the string's internal buffer + * (it must be free'd using using nsMemory::Free) + * + * @status FROZEN + */ +NS_STRINGAPI(char *) +NS_CStringCloneData + (const nsACString &aStr); + +/** + * NS_CStringSetData + * + * This function copies aData into aStr. + * + * @param aStr abstract string reference + * @param aData character buffer + * @param aDataLength number of characters to copy from source string (pass + * PR_UINT32_MAX to copy until end of aData, designated by + * a null character) + * @return NS_OK if function succeeded + * + * This function does not necessarily null-terminate aStr after copying data + * from aData. The behavior depends on the implementation of the abstract + * string, aStr. If aStr is a reference to a nsStringContainer, then its data + * will be null-terminated by this function. + * + * @status FROZEN + */ +NS_STRINGAPI(nsresult) +NS_CStringSetData + (nsACString &aStr, const char *aData, + PRUint32 aDataLength = PR_UINT32_MAX); + +/** + * NS_CStringSetDataRange + * + * This function copies aData into a section of aStr. As a result it can be + * used to insert new characters into the string. + * + * @param aStr abstract string reference + * @param aCutOffset starting index where the string's existing data + * is to be overwritten (pass PR_UINT32_MAX to cause + * aData to be appended to the end of aStr, in which + * case the value of aCutLength is ignored). + * @param aCutLength number of characters to overwrite starting at + * aCutOffset (pass PR_UINT32_MAX to overwrite until the + * end of aStr). + * @param aData character buffer (pass null to cause this function + * to simply remove the "cut" range) + * @param aDataLength number of characters to copy from source string (pass + * PR_UINT32_MAX to copy until end of aData, designated by + * a null character) + * @return NS_OK if function succeeded + * + * This function does not necessarily null-terminate aStr after copying data + * from aData. The behavior depends on the implementation of the abstract + * string, aStr. If aStr is a reference to a nsStringContainer, then its data + * will be null-terminated by this function. + * + * @status FROZEN + */ +NS_STRINGAPI(nsresult) +NS_CStringSetDataRange + (nsACString &aStr, PRUint32 aCutOffset, PRUint32 aCutLength, + const char *aData, PRUint32 aDataLength = PR_UINT32_MAX); + +/** + * NS_CStringCopy + * + * This function makes aDestStr have the same value as aSrcStr. It is + * provided as an optimization. + * + * @param aDestStr abstract string reference to be modified + * @param aSrcStr abstract string reference containing source string + * @return NS_OK if function succeeded + * + * This function does not necessarily null-terminate aDestStr after copying + * data from aSrcStr. The behavior depends on the implementation of the + * abstract string, aDestStr. If aDestStr is a reference to a + * nsStringContainer, then its data will be null-terminated by this function. + * + * @status FROZEN + */ +NS_STRINGAPI(nsresult) +NS_CStringCopy + (nsACString &aDestStr, const nsACString &aSrcStr); + +/** + * NS_CStringAppendData + * + * This function appends data to the existing value of aStr. + * + * @param aStr abstract string reference to be modified + * @param aData character buffer + * @param aDataLength number of characters to append (pass PR_UINT32_MAX to + * append until a null-character is encountered) + * @return NS_OK if function succeeded + * + * This function does not necessarily null-terminate aStr upon completion. + * The behavior depends on the implementation of the abstract string, aStr. + * If aStr is a reference to a nsStringContainer, then its data will be null- + * terminated by this function. + */ +inline NS_HIDDEN_(nsresult) +NS_CStringAppendData(nsACString &aStr, const char *aData, + PRUint32 aDataLength = PR_UINT32_MAX) +{ + return NS_CStringSetDataRange(aStr, PR_UINT32_MAX, 0, aData, aDataLength); +} + +/** + * NS_CStringInsertData + * + * This function inserts data into the existing value of aStr at the specified + * offset. + * + * @param aStr abstract string reference to be modified + * @param aOffset specifies where in the string to insert aData + * @param aData character buffer + * @param aDataLength number of characters to append (pass PR_UINT32_MAX to + * append until a null-character is encountered) + * @return NS_OK if function succeeded + * + * This function does not necessarily null-terminate aStr upon completion. + * The behavior depends on the implementation of the abstract string, aStr. + * If aStr is a reference to a nsStringContainer, then its data will be null- + * terminated by this function. + */ +inline NS_HIDDEN_(nsresult) +NS_CStringInsertData(nsACString &aStr, PRUint32 aOffset, const char *aData, + PRUint32 aDataLength = PR_UINT32_MAX) +{ + return NS_CStringSetDataRange(aStr, aOffset, 0, aData, aDataLength); +} + +/** + * NS_CStringCutData + * + * This function shortens the existing value of aStr, by removing characters + * at the specified offset. + * + * @param aStr abstract string reference to be modified + * @param aCutOffset specifies where in the string to insert aData + * @param aCutLength number of characters to remove + * @return NS_OK if function succeeded + */ +inline NS_HIDDEN_(nsresult) +NS_CStringCutData(nsACString &aStr, PRUint32 aCutOffset, PRUint32 aCutLength) +{ + return NS_CStringSetDataRange(aStr, aCutOffset, aCutLength, nsnull, 0); +} + +/* ------------------------------------------------------------------------- */ + +/** + * Encodings that can be used with the following conversion routines. + */ +enum nsCStringEncoding { + /* Conversion between ASCII and UTF-16 assumes that all bytes in the source + * string are 7-bit ASCII and can be inflated to UTF-16 by inserting null + * bytes. Reverse conversion is done by truncating every other byte. The + * conversion may result in loss and/or corruption of information if the + * strings do not strictly contain ASCII data. */ + NS_CSTRING_ENCODING_ASCII = 0, + + /* Conversion between UTF-8 and UTF-16 is non-lossy. */ + NS_CSTRING_ENCODING_UTF8 = 1, + + /* Conversion from UTF-16 to the native filesystem charset may result in a + * loss of information. No attempt is made to protect against data loss in + * this case. The native filesystem charset applies to strings passed to + * the "Native" method variants on nsIFile and nsILocalFile. */ + NS_CSTRING_ENCODING_NATIVE_FILESYSTEM = 2 +}; + +/** + * NS_CStringToUTF16 + * + * This function converts the characters in a nsACString to an array of UTF-16 + * characters, in the platform endianness. The result is stored in a nsAString + * object. + * + * @param aSource abstract string reference containing source string + * @param aSrcEncoding character encoding of the source string + * @param aDest abstract string reference to hold the result + * + * @status FROZEN + */ +NS_STRINGAPI(nsresult) +NS_CStringToUTF16(const nsACString &aSource, nsCStringEncoding aSrcEncoding, + nsAString &aDest); + +/** + * NS_UTF16ToCString + * + * This function converts the UTF-16 characters in a nsAString to a single-byte + * encoding. The result is stored in a nsACString object. In some cases this + * conversion may be lossy. In such cases, the conversion may succeed with a + * return code indicating loss of information. The exact behavior is not + * specified at this time. + * + * @param aSource abstract string reference containing source string + * @param aDestEncoding character encoding of the resulting string + * @param aDest abstract string reference to hold the result + * + * @status FROZEN + */ +NS_STRINGAPI(nsresult) +NS_UTF16ToCString(const nsAString &aSource, nsCStringEncoding aDestEncoding, + nsACString &aDest); + +/* ------------------------------------------------------------------------- */ + +/** + * Below we define nsAString and nsACString. The "_external" suffix is an + * implementation detail. nsAString_external is the name of the external + * representation of nsAString from the point of view of the Mozilla codebase. + * To a user of this API, nsAString_external is exactly nsAString. + * + * These classes should be treated as abstract classes with unspecified + * structure. The inline methods are provided as helper functions around the + * C-style API provided above. + * + * Do not try to mix these definitions of nsAString and nsACString with the + * internal definition of these classes from nsAString.h in the Mozilla tree. + */ + +#ifndef NS_STRINGAPI_IMPL +#define nsAString_external nsAString +#define nsACString_external nsACString +#endif + +class nsAString_external +{ +#ifndef NS_STRINGAPI_IMPL + +public: + typedef PRUnichar char_type; + typedef nsAString_external self_type; + typedef PRUint32 size_type; + typedef PRUint32 index_type; + + NS_HIDDEN_(const char_type*) BeginReading() const + { + const char_type *data; + NS_StringGetData(*this, &data); + return data; + } + + NS_HIDDEN_(const char_type*) EndReading() const + { + const char_type *data; + PRUint32 len = NS_StringGetData(*this, &data); + return data + len; + } + + NS_HIDDEN_(size_type) Length() const + { + const char_type* data; + return NS_StringGetData(*this, &data); + } + + NS_HIDDEN_(void) Assign(const self_type& aString) + { + NS_StringCopy(*this, aString); + } + NS_HIDDEN_(void) Assign(const char_type* aData, size_type aLength = PR_UINT32_MAX) + { + NS_StringSetData(*this, aData, aLength); + } + NS_HIDDEN_(void) Assign(char_type aChar) + { + NS_StringSetData(*this, &aChar, 1); + } + + NS_HIDDEN_(self_type&) operator=(const self_type& aString) { Assign(aString); return *this; } + NS_HIDDEN_(self_type&) operator=(const char_type* aPtr) { Assign(aPtr); return *this; } + NS_HIDDEN_(self_type&) operator=(char_type aChar) { Assign(aChar); return *this; } + + NS_HIDDEN_(void) Replace( index_type cutStart, size_type cutLength, const char_type* data, size_type length = size_type(-1) ) + { + NS_StringSetDataRange(*this, cutStart, cutLength, data, length); + } + NS_HIDDEN_(void) Replace( index_type cutStart, size_type cutLength, char_type c ) + { + Replace(cutStart, cutLength, &c, 1); + } + NS_HIDDEN_(void) Replace( index_type cutStart, size_type cutLength, const self_type& readable ) + { + const char_type* data; + PRUint32 dataLen = NS_StringGetData(readable, &data); + NS_StringSetDataRange(*this, cutStart, cutLength, data, dataLen); + } + + NS_HIDDEN_(void) Append( char_type c ) { Replace(size_type(-1), 0, c); } + NS_HIDDEN_(void) Append( const char_type* data, size_type length = size_type(-1) ) { Replace(size_type(-1), 0, data, length); } + NS_HIDDEN_(void) Append( const self_type& readable ) { Replace(size_type(-1), 0, readable); } + + NS_HIDDEN_(self_type&) operator+=( char_type c ) { Append(c); return *this; } + NS_HIDDEN_(self_type&) operator+=( const char_type* data ) { Append(data); return *this; } + NS_HIDDEN_(self_type&) operator+=( const self_type& readable ) { Append(readable); return *this; } + + NS_HIDDEN_(void) Insert( char_type c, index_type pos ) { Replace(pos, 0, c); } + NS_HIDDEN_(void) Insert( const char_type* data, index_type pos, size_type length = size_type(-1) ) { Replace(pos, 0, data, length); } + NS_HIDDEN_(void) Insert( const self_type& readable, index_type pos ) { Replace(pos, 0, readable); } + + NS_HIDDEN_(void) Cut( index_type cutStart, size_type cutLength ) { Replace(cutStart, cutLength, nsnull, 0); } + +#endif // NS_STRINGAPI_IMPL + +private: + void *v; +}; + +class nsACString_external +{ +#ifndef NS_STRINGAPI_IMPL + +public: + typedef char char_type; + typedef nsACString_external self_type; + typedef PRUint32 size_type; + typedef PRUint32 index_type; + + NS_HIDDEN_(const char_type*) BeginReading() const + { + const char_type *data; + NS_CStringGetData(*this, &data); + return data; + } + + NS_HIDDEN_(const char_type*) EndReading() const + { + const char_type *data; + PRUint32 len = NS_CStringGetData(*this, &data); + return data + len; + } + + NS_HIDDEN_(size_type) Length() const + { + const char_type* data; + return NS_CStringGetData(*this, &data); + } + + NS_HIDDEN_(void) Assign(const self_type& aString) + { + NS_CStringCopy(*this, aString); + } + NS_HIDDEN_(void) Assign(const char_type* aData, size_type aLength = PR_UINT32_MAX) + { + NS_CStringSetData(*this, aData, aLength); + } + NS_HIDDEN_(void) Assign(char_type aChar) + { + NS_CStringSetData(*this, &aChar, 1); + } + + NS_HIDDEN_(self_type&) operator=(const self_type& aString) { Assign(aString); return *this; } + NS_HIDDEN_(self_type&) operator=(const char_type* aPtr) { Assign(aPtr); return *this; } + NS_HIDDEN_(self_type&) operator=(char_type aChar) { Assign(aChar); return *this; } + + NS_HIDDEN_(void) Replace( index_type cutStart, size_type cutLength, const char_type* data, size_type length = size_type(-1) ) + { + NS_CStringSetDataRange(*this, cutStart, cutLength, data, length); + } + NS_HIDDEN_(void) Replace( index_type cutStart, size_type cutLength, char_type c ) + { + Replace(cutStart, cutLength, &c, 1); + } + NS_HIDDEN_(void) Replace( index_type cutStart, size_type cutLength, const self_type& readable ) + { + const char_type* data; + PRUint32 dataLen = NS_CStringGetData(readable, &data); + NS_CStringSetDataRange(*this, cutStart, cutLength, data, dataLen); + } + + NS_HIDDEN_(void) Append( char_type c ) { Replace(size_type(-1), 0, c); } + NS_HIDDEN_(void) Append( const char_type* data, size_type length = size_type(-1) ) { Replace(size_type(-1), 0, data, length); } + NS_HIDDEN_(void) Append( const self_type& readable ) { Replace(size_type(-1), 0, readable); } + + NS_HIDDEN_(self_type&) operator+=( char_type c ) { Append(c); return *this; } + NS_HIDDEN_(self_type&) operator+=( const char_type* data ) { Append(data); return *this; } + NS_HIDDEN_(self_type&) operator+=( const self_type& readable ) { Append(readable); return *this; } + + NS_HIDDEN_(void) Insert( char_type c, index_type pos ) { Replace(pos, 0, c); } + NS_HIDDEN_(void) Insert( const char_type* data, index_type pos, size_type length = size_type(-1) ) { Replace(pos, 0, data, length); } + NS_HIDDEN_(void) Insert( const self_type& readable, index_type pos ) { Replace(pos, 0, readable); } + + NS_HIDDEN_(void) Cut( index_type cutStart, size_type cutLength ) { Replace(cutStart, cutLength, nsnull, 0); } + +#endif // NS_STRINGAPI_IMPL + +private: + void *v; +}; + +/* ------------------------------------------------------------------------- */ + +/** + * Below we define nsStringContainer and nsCStringContainer. These classes + * have unspecified structure. In most cases, your code should use + * nsEmbedString instead of these classes; however, if you prefer C-style + * programming, then look no further... + */ + +class nsStringContainer : public nsAString_external +{ +private: + void *d1; + PRUint32 d2; + void *d3; + +public: + nsStringContainer() {} // MSVC6 needs this +}; + +class nsCStringContainer : public nsACString_external +{ +private: + void *d1; + PRUint32 d2; + void *d3; + +public: + nsCStringContainer() {} // MSVC6 needs this +}; + +#endif // nsStringAPI_h__ diff --git a/src/libs/xpcom18a4/xpcom/string/public/nsStringFwd.h b/src/libs/xpcom18a4/xpcom/string/public/nsStringFwd.h new file mode 100644 index 00000000..4c664011 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/public/nsStringFwd.h @@ -0,0 +1,96 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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. + * Portions created by the Initial Developer are Copyright (C) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Scott Collins (original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* nsStringFwd.h --- forward declarations for string classes */ + +#ifndef nsStringFwd_h___ +#define nsStringFwd_h___ + +#ifndef nscore_h___ +#include "nscore.h" +#endif + + + /** + * double-byte (PRUnichar) string types + */ + +class nsAString; +class nsObsoleteAString; +class nsSubstring; +class nsSubstringTuple; +class nsString; +class nsAutoString; +class nsDependentString; +class nsDependentSubstring; +class nsPromiseFlatString; +class nsStringComparator; +class nsDefaultStringComparator; +class nsXPIDLString; + + + /** + * single-byte (char) string types + */ + +class nsACString; +class nsObsoleteACString; +class nsCSubstring; +class nsCSubstringTuple; +class nsCString; +class nsCAutoString; +class nsDependentCString; +class nsDependentCSubstring; +class nsPromiseFlatCString; +class nsCStringComparator; +class nsDefaultCStringComparator; +class nsXPIDLCString; + + + /** + * typedefs for backwards compatibility + */ + +typedef nsString nsAFlatString; +typedef nsSubstring nsASingleFragmentString; + +typedef nsCString nsAFlatCString; +typedef nsCSubstring nsASingleFragmentCString; + + +#endif /* !defined(nsStringFwd_h___) */ diff --git a/src/libs/xpcom18a4/xpcom/string/public/nsStringIterator.h b/src/libs/xpcom18a4/xpcom/string/public/nsStringIterator.h new file mode 100644 index 00000000..1848594c --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/public/nsStringIterator.h @@ -0,0 +1,373 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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. + * Portions created by the Initial Developer are Copyright (C) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Scott Collins (original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +#ifndef nsStringIterator_h___ +#define nsStringIterator_h___ + +#ifndef nsCharTraits_h___ +#include "nsCharTraits.h" +#endif + +#ifndef nsAlgorithm_h___ +#include "nsAlgorithm.h" +#endif + +#ifndef nsDebug_h___ +#include "nsDebug.h" +#endif + + /** + * @see nsTAString + */ + +template +class nsReadingIterator + { + public: + typedef nsReadingIterator self_type; + typedef ptrdiff_t difference_type; + typedef CharT value_type; + typedef const CharT* pointer; + typedef const CharT& reference; + + private: + friend class nsAString; + friend class nsACString; + friend class nsSubstring; + friend class nsCSubstring; + + // unfortunately, the API for nsReadingIterator requires that the + // iterator know its start and end positions. this was needed when + // we supported multi-fragment strings, but now it is really just + // extra baggage. we should remove mStart and mEnd at some point. + + const CharT* mStart; + const CharT* mEnd; + const CharT* mPosition; + + public: + nsReadingIterator() { } + // nsReadingIterator( const nsReadingIterator& ); // auto-generated copy-constructor OK + // nsReadingIterator& operator=( const nsReadingIterator& ); // auto-generated copy-assignment operator OK + + inline void normalize_forward() {} + inline void normalize_backward() {} + + pointer + start() const + { + return mStart; + } + + pointer + end() const + { + return mEnd; + } + + pointer + get() const + { + return mPosition; + } + + CharT + operator*() const + { + return *get(); + } + +#if 0 + // An iterator really deserves this, but some compilers (notably IBM VisualAge for OS/2) + // don't like this when |CharT| is a type without members. + pointer + operator->() const + { + return get(); + } +#endif + + self_type& + operator++() + { + ++mPosition; + return *this; + } + + self_type + operator++( int ) + { + self_type result(*this); + ++mPosition; + return result; + } + + self_type& + operator--() + { + --mPosition; + return *this; + } + + self_type + operator--( int ) + { + self_type result(*this); + --mPosition; + return result; + } + + difference_type + size_forward() const + { + return mEnd - mPosition; + } + + difference_type + size_backward() const + { + return mPosition - mStart; + } + + self_type& + advance( difference_type n ) + { + if (n > 0) + { + difference_type step = NS_MIN(n, size_forward()); + + NS_ASSERTION(step>0, "can't advance a reading iterator beyond the end of a string"); + + mPosition += step; + } + else if (n < 0) + { + difference_type step = NS_MAX(n, -size_backward()); + + NS_ASSERTION(step<0, "can't advance (backward) a reading iterator beyond the end of a string"); + + mPosition += step; + } + return *this; + } + }; + + /** + * @see nsTAString + */ + +template +class nsWritingIterator + { + public: + typedef nsWritingIterator self_type; + typedef ptrdiff_t difference_type; + typedef CharT value_type; + typedef CharT* pointer; + typedef CharT& reference; + + private: + friend class nsAString; + friend class nsACString; + friend class nsSubstring; + friend class nsCSubstring; + + // unfortunately, the API for nsWritingIterator requires that the + // iterator know its start and end positions. this was needed when + // we supported multi-fragment strings, but now it is really just + // extra baggage. we should remove mStart and mEnd at some point. + + CharT* mStart; + CharT* mEnd; + CharT* mPosition; + + public: + nsWritingIterator() { } + // nsWritingIterator( const nsWritingIterator& ); // auto-generated copy-constructor OK + // nsWritingIterator& operator=( const nsWritingIterator& ); // auto-generated copy-assignment operator OK + + inline void normalize_forward() {} + inline void normalize_backward() {} + + pointer + start() const + { + return mStart; + } + + pointer + end() const + { + return mEnd; + } + + pointer + get() const + { + return mPosition; + } + + reference + operator*() const + { + return *get(); + } + +#if 0 + // An iterator really deserves this, but some compilers (notably IBM VisualAge for OS/2) + // don't like this when |CharT| is a type without members. + pointer + operator->() const + { + return get(); + } +#endif + + self_type& + operator++() + { + ++mPosition; + return *this; + } + + self_type + operator++( int ) + { + self_type result(*this); + ++mPosition; + return result; + } + + self_type& + operator--() + { + --mPosition; + return *this; + } + + self_type + operator--( int ) + { + self_type result(*this); + --mPosition; + return result; + } + + difference_type + size_forward() const + { + return mEnd - mPosition; + } + + difference_type + size_backward() const + { + return mPosition - mStart; + } + + self_type& + advance( difference_type n ) + { + if (n > 0) + { + difference_type step = NS_MIN(n, size_forward()); + + NS_ASSERTION(step>0, "can't advance a writing iterator beyond the end of a string"); + + mPosition += step; + } + else if (n < 0) + { + difference_type step = NS_MAX(n, -size_backward()); + + NS_ASSERTION(step<0, "can't advance (backward) a writing iterator beyond the end of a string"); + + mPosition += step; + } + return *this; + } + + PRUint32 + write( const value_type* s, PRUint32 n ) + { + NS_ASSERTION(size_forward() > 0, "You can't |write| into an |nsWritingIterator| with no space!"); + + nsCharTraits::move(mPosition, s, n); + advance( difference_type(n) ); + return n; + } + }; + +template +inline +PRBool +operator==( const nsReadingIterator& lhs, const nsReadingIterator& rhs ) + { + return lhs.get() == rhs.get(); + } + +template +inline +PRBool +operator!=( const nsReadingIterator& lhs, const nsReadingIterator& rhs ) + { + return lhs.get() != rhs.get(); + } + + + // + // |nsWritingIterator|s + // + +template +inline +PRBool +operator==( const nsWritingIterator& lhs, const nsWritingIterator& rhs ) + { + return lhs.get() == rhs.get(); + } + +template +inline +PRBool +operator!=( const nsWritingIterator& lhs, const nsWritingIterator& rhs ) + { + return lhs.get() != rhs.get(); + } + +#endif /* !defined(nsStringIterator_h___) */ diff --git a/src/libs/xpcom18a4/xpcom/string/public/nsSubstring.h b/src/libs/xpcom18a4/xpcom/string/public/nsSubstring.h new file mode 100644 index 00000000..35a1a568 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/public/nsSubstring.h @@ -0,0 +1,74 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* ***** 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 IBM Corporation. + * Portions created by IBM Corporation are Copyright (C) 2003 + * IBM Corporation. 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 ***** */ + +#ifndef nsSubstring_h___ +#define nsSubstring_h___ + +#ifndef nsAString_h___ +#include "nsAString.h" +#endif + +#define kNotFound -1 + +// If some platform(s) can't handle our template that matches literal strings, +// then we'll disable it on those platforms. +#ifndef NS_DISABLE_LITERAL_TEMPLATE +# if (defined(_MSC_VER) && (_MSC_VER < 1310)) || (defined(__SUNPRO_CC) & (__SUNPRO_CC < 0x560)) || (defined(__HP_aCC) && (__HP_aCC <= 012100)) +# define NS_DISABLE_LITERAL_TEMPLATE +# endif +#endif /* !NS_DISABLE_LITERAL_TEMPLATE */ + +#include + + // declare nsSubstring +#include "string-template-def-unichar.h" +#include "nsTSubstring.h" +#include "string-template-undef.h" + + + // declare nsCSubstring +#include "string-template-def-char.h" +#include "nsTSubstring.h" +#include "string-template-undef.h" + + +#ifndef nsSubstringTuple_h___ +#include "nsSubstringTuple.h" +#endif + +#endif // !defined(nsSubstring_h___) diff --git a/src/libs/xpcom18a4/xpcom/string/public/nsSubstringTuple.h b/src/libs/xpcom18a4/xpcom/string/public/nsSubstringTuple.h new file mode 100644 index 00000000..8cf6f803 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/public/nsSubstringTuple.h @@ -0,0 +1,56 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* ***** 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 IBM Corporation. + * Portions created by IBM Corporation are Copyright (C) 2003 + * IBM Corporation. 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 ***** */ + +#ifndef nsSubstringTuple_h___ +#define nsSubstringTuple_h___ + +#ifndef nsSubstring_h___ +#include "nsSubstring.h" +#endif + + // declare nsSubstringTuple +#include "string-template-def-unichar.h" +#include "nsTSubstringTuple.h" +#include "string-template-undef.h" + + // declare nsCSubstringTuple +#include "string-template-def-char.h" +#include "nsTSubstringTuple.h" +#include "string-template-undef.h" + +#endif // !defined(nsSubstringTuple_h___) diff --git a/src/libs/xpcom18a4/xpcom/string/public/nsTAString.h b/src/libs/xpcom18a4/xpcom/string/public/nsTAString.h new file mode 100644 index 00000000..93b88443 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/public/nsTAString.h @@ -0,0 +1,618 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* ***** 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 IBM Corporation. + * Portions created by IBM Corporation are Copyright (C) 2003 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Scott Collins (original author) + * 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 ***** */ + + + /** + * The base for string comparators + */ +class NS_COM nsTStringComparator_CharT + { + public: + typedef CharT char_type; + + nsTStringComparator_CharT() {} + + virtual int operator()( const char_type*, const char_type*, PRUint32 length ) const = 0; + virtual int operator()( char_type, char_type ) const = 0; + }; + + + /** + * The default string comparator (case-sensitive comparision) + */ +class NS_COM nsTDefaultStringComparator_CharT + : public nsTStringComparator_CharT + { + public: + typedef CharT char_type; + + nsTDefaultStringComparator_CharT() {} + + virtual int operator()( const char_type*, const char_type*, PRUint32 length ) const; + virtual int operator()( char_type, char_type ) const; + }; + + + /** + * nsTAString is the most abstract class in the string hierarchy. + * + * In its original inception, nsTAString was designed to allow the data + * storage for a string to be separated into multiple fragments. This was + * intended to enable lazy string flattening or avoid string flattening + * altogether in some cases. This abstraction, however, meant that every + * single string operation (including simple operations such as IsEmpty() and + * BeginReading()) required virtual function calls. A virtual destructor was + * also required. This not only meant additional overhead for invoking + * string methods but also added to additional codesize at every callsite (to + * load the virtual function address). + * + * Today nsTAString exists mainly for backwards compatibility of the string + * API. It is restricted to representing a contiguous array of characters, + * where the character array is not necessarily null-terminated. Moreover, + * since nsTAString's virtual function table was frozen for Mozilla 1.0, + * nsTAString necessarily maintains ABI compatibility with older versions of + * Gecko. (nsTObsoleteAString provides that frozen ABI. See + * nsObsoleteAString.h for a description of how we solve the ABI + * compatibility requirement while eliminating virtual function calls on + * nsTAString.) + * + * XPIDL still generates C++ header files with references to nsTAStrings, so + * nsTAString will still be heavily used in real code. + * + * If the opportunity to break ABI compatibility with Mozilla 1.0 were to + * ever arise, our first move should be to make nsTAString equate to + * nsTSubstring. This may in fact be an option today for some Gecko-based + * products. + */ +class nsTAString_CharT + { + public: + + typedef CharT char_type; + typedef nsCharTraits char_traits; + + typedef char_traits::incompatible_char_type incompatible_char_type; + + typedef nsTAString_CharT self_type; + typedef nsTAString_CharT abstract_string_type; + typedef nsTObsoleteAString_CharT obsolete_string_type; + typedef nsTSubstring_CharT substring_type; + typedef nsTSubstringTuple_CharT substring_tuple_type; + + typedef nsReadingIterator const_iterator; + typedef nsWritingIterator iterator; + + typedef nsTStringComparator_CharT comparator_type; + + typedef PRUint32 size_type; + typedef PRUint32 index_type; + + public: + + // this acts like a virtual destructor + NS_COM NS_FASTCALL ~nsTAString_CharT(); + + + /** + * BeginReading/EndReading can be used to get immutable access to the + * string's underlying buffer. EndReading returns a pointer to the + * end of the string's buffer. nsReadableUtils.h provides a collection + * of utility functions that work with these iterators. + */ + + inline const_iterator& BeginReading( const_iterator& iter ) const + { + size_type len = GetReadableBuffer(&iter.mStart); + iter.mEnd = iter.mStart + len; + iter.mPosition = iter.mStart; + return iter; + } + + inline const_iterator& EndReading( const_iterator& iter ) const + { + size_type len = GetReadableBuffer(&iter.mStart); + iter.mEnd = iter.mStart + len; + iter.mPosition = iter.mEnd; + return iter; + } + + + /** + * BeginWriting/EndWriting can be used to get mutable access to the + * string's underlying buffer. EndWriting returns a pointer to the + * end of the string's buffer. This iterator API cannot be used to + * grow a buffer. Use SetLength to resize the string's buffer. + */ + + inline iterator& BeginWriting( iterator& iter ) + { + size_type len = GetWritableBuffer(&iter.mStart); + iter.mEnd = iter.mStart + len; + iter.mPosition = iter.mStart; + return iter; + } + + inline iterator& EndWriting( iterator& iter ) + { + size_type len = GetWritableBuffer(&iter.mStart); + iter.mEnd = iter.mStart + len; + iter.mPosition = iter.mEnd; + return iter; + } + + + /** + * Length checking functions. IsEmpty is a helper function to avoid + * writing code like: |if (str.Length() == 0)| + */ + + NS_COM size_type NS_FASTCALL Length() const; + PRBool IsEmpty() const { return Length() == 0; } + + + /** + * String equality tests. Pass a string comparator if you want to + * control how the strings are compared. By default, a binary + * "case-sensitive" comparision is performed. + */ + + NS_COM PRBool NS_FASTCALL Equals( const self_type& ) const; + NS_COM PRBool NS_FASTCALL Equals( const self_type&, const comparator_type& ) const; + NS_COM PRBool NS_FASTCALL Equals( const char_type* ) const; + NS_COM PRBool NS_FASTCALL Equals( const char_type*, const comparator_type& ) const; + + /** + * An efficient comparison with ASCII that can be used even + * for wide strings. Call this version when you know the + * length of 'data'. + */ + NS_COM PRBool NS_FASTCALL EqualsASCII( const char* data, size_type len ) const; + /** + * An efficient comparison with ASCII that can be used even + * for wide strings. Call this version when 'data' is + * null-terminated. + */ + NS_COM PRBool NS_FASTCALL EqualsASCII( const char* data ) const; + + // EqualsLiteral must ONLY be applied to an actual literal string. + // Do not attempt to use it with a regular char* pointer, or with a char + // array variable. + // The template trick to acquire the array length at compile time without + // using a macro is due to Corey Kosak, with much thanks. +#ifdef NS_DISABLE_LITERAL_TEMPLATE + inline PRBool EqualsLiteral( const char* str ) const + { + return EqualsASCII(str); + } +#else + template + inline PRBool EqualsLiteral( const char (&str)[N] ) const + { + return EqualsASCII(str, N-1); + } + template + inline PRBool EqualsLiteral( char (&str)[N] ) const + { + const char* s = str; + return EqualsASCII(s, N-1); + } +#endif + + // The LowerCaseEquals methods compare the lower case version of + // this string to some ASCII/Literal string. The ASCII string is + // *not* lowercased for you. If you compare to an ASCII or literal + // string that contains an uppercase character, it is guaranteed to + // return false. We will throw assertions too. + NS_COM PRBool NS_FASTCALL LowerCaseEqualsASCII( const char* data, size_type len ) const; + NS_COM PRBool NS_FASTCALL LowerCaseEqualsASCII( const char* data ) const; + + // LowerCaseEqualsLiteral must ONLY be applied to an actual + // literal string. Do not attempt to use it with a regular char* + // pointer, or with a char array variable. Use + // LowerCaseEqualsASCII for them. +#ifdef NS_DISABLE_LITERAL_TEMPLATE + inline PRBool LowerCaseEqualsLiteral( const char* str ) const + { + return LowerCaseEqualsASCII(str); + } +#else + template + inline PRBool LowerCaseEqualsLiteral( const char (&str)[N] ) const + { + return LowerCaseEqualsASCII(str, N-1); + } + template + inline PRBool LowerCaseEqualsLiteral( char (&str)[N] ) const + { + const char* s = str; + return LowerCaseEqualsASCII(s, N-1); + } +#endif + + /** + * A string always references a non-null data pointer. In some + * applications (e.g., the DOM) it is necessary for a string class + * to have some way to distinguish an empty string from a null (or + * void) string. These methods enable support for the concept of + * a void string. + */ + + NS_COM PRBool NS_FASTCALL IsVoid() const; + NS_COM void NS_FASTCALL SetIsVoid( PRBool ); + + + /** + * This method returns true if the string's underlying buffer is + * null-terminated. This should rarely be needed by applications. + * The PromiseFlatTString method should be used to ensure that a + * string's underlying buffer is null-terminated. + */ + + NS_COM PRBool NS_FASTCALL IsTerminated() const; + + + /** + * These are contant time since nsTAString uses flat storage + */ + NS_COM char_type NS_FASTCALL First() const; + NS_COM char_type NS_FASTCALL Last() const; + + + /** + * Returns the number of occurances of the given character. + */ + NS_COM size_type NS_FASTCALL CountChar( char_type ) const; + + + /** + * Locates the offset of the first occurance of the character. Pass a + * non-zero offset to control where the search begins. + */ + + NS_COM PRInt32 NS_FASTCALL FindChar( char_type, index_type offset = 0 ) const; + + + /** + * SetCapacity is not required to do anything; however, it can be used + * as a hint to the implementation to reduce allocations. + * + * SetCapacity(0) is a suggestion to discard all associated storage. + */ + NS_COM void NS_FASTCALL SetCapacity( size_type ); + + + /** + * XXX talk to dbaron about this comment. we do need a method that + * XXX allows someone to resize a string's buffer so that it can be + * XXX populated using writing iterators. SetLength seems to be the + * XXX right method for the job, and we do use it in this capacity + * XXX in certain places. + * + * SetLength is used in two ways: + * 1) to |Cut| a suffix of the string; + * 2) to prepare to |Append| or move characters around. + * + * External callers are not allowed to use |SetLength| in this + * latter capacity, and should prefer |Truncate| for the former. + * In other words, |SetLength| is deprecated for all use outside + * of the string library and the internal use may at some point + * be replaced as well. + * + * This distinction makes me think the two different uses should + * be split into two distinct functions. + */ + NS_COM void NS_FASTCALL SetLength( size_type ); + + + /** + * Can't use |Truncate| to make a string longer! + */ + void Truncate( size_type aNewLength=0 ) + { + NS_ASSERTION(aNewLength <= Length(), "Truncate cannot make string longer"); + SetLength(aNewLength); + } + + + /** + * |Assign| and |operator=| make |this| equivalent to the string or + * buffer given as an argument. If possible, they do this by sharing + * a reference counted buffer (see |nsTSubstring|). If not, they copy + * the buffer into their own buffer. + */ + + NS_COM void NS_FASTCALL Assign( const self_type& readable ); + NS_COM void NS_FASTCALL Assign( const substring_tuple_type& tuple ); + NS_COM void NS_FASTCALL Assign( const char_type* data ); + NS_COM void NS_FASTCALL Assign( const char_type* data, size_type length ); + NS_COM void NS_FASTCALL Assign( char_type c ); + + NS_COM void NS_FASTCALL AssignASCII( const char* data, size_type length ); + NS_COM void NS_FASTCALL AssignASCII( const char* data ); + + // AssignLiteral must ONLY be applied to an actual literal string. + // Do not attempt to use it with a regular char* pointer, or with a char + // array variable. Use AssignASCII for those. +#ifdef NS_DISABLE_LITERAL_TEMPLATE + void AssignLiteral( const char* str ) + { AssignASCII(str); } +#else + template + void AssignLiteral( const char (&str)[N] ) + { AssignASCII(str, N-1); } + template + void AssignLiteral( char (&str)[N] ) + { AssignASCII(str, N-1); } +#endif + + // copy-assignment operator. I must define my own if I don't want the compiler to make me one + self_type& operator=( const self_type& readable ) { Assign(readable); return *this; } + self_type& operator=( const substring_tuple_type& tuple ) { Assign(tuple); return *this; } + self_type& operator=( const char_type* data ) { Assign(data); return *this; } + self_type& operator=( char_type c ) { Assign(c); return *this; } + + + + /** + * |Append|, |operator+=| are used to add characters to the end of this string. + */ + + NS_COM void NS_FASTCALL Append( const self_type& readable ); + NS_COM void NS_FASTCALL Append( const substring_tuple_type& tuple ); + NS_COM void NS_FASTCALL Append( const char_type* data ); + NS_COM void NS_FASTCALL Append( const char_type* data, size_type length ); + NS_COM void NS_FASTCALL Append( char_type c ); + + NS_COM void NS_FASTCALL AppendASCII( const char* data, size_type length ); + NS_COM void NS_FASTCALL AppendASCII( const char* data ); + + // AppendLiteral must ONLY be applied to an actual literal string. + // Do not attempt to use it with a regular char* pointer, or with a char + // array variable. Use AppendASCII for those. +#ifdef NS_DISABLE_LITERAL_TEMPLATE + void AppendLiteral( const char* str ) + { AppendASCII(str); } +#else + template + void AppendLiteral( const char (&str)[N] ) + { AppendASCII(str, N-1); } + template + void AppendLiteral( char (&str)[N] ) + { AppendASCII(str, N-1); } +#endif + + self_type& operator+=( const self_type& readable ) { Append(readable); return *this; } + self_type& operator+=( const substring_tuple_type& tuple ) { Append(tuple); return *this; } + self_type& operator+=( const char_type* data ) { Append(data); return *this; } + self_type& operator+=( char_type c ) { Append(c); return *this; } + + + /** + * |Insert| is used to add characters into this string at a given position. + * NOTE: It's a shame the |pos| parameter isn't at the front of the arg list. + */ + + NS_COM void NS_FASTCALL Insert( const self_type& readable, index_type pos ); + NS_COM void NS_FASTCALL Insert( const substring_tuple_type& tuple, index_type pos ); + NS_COM void NS_FASTCALL Insert( const char_type* data, index_type pos ); + NS_COM void NS_FASTCALL Insert( const char_type* data, index_type pos, size_type length ); + NS_COM void NS_FASTCALL Insert( char_type c, index_type pos ); + + + /** + * |Cut| is used to remove a range of characters from this string. + */ + + NS_COM void NS_FASTCALL Cut( index_type cutStart, size_type cutLength ); + + + /** + * |Replace| is used overwrite a range of characters from this string. + */ + + NS_COM void NS_FASTCALL Replace( index_type cutStart, size_type cutLength, const self_type& readable ); + NS_COM void NS_FASTCALL Replace( index_type cutStart, size_type cutLength, const substring_tuple_type& readable ); + + + /** + * this is public to support automatic conversion of tuple to abstract + * string, which is necessary to support our API. + */ + nsTAString_CharT(const substring_tuple_type& tuple) + : mVTable(obsolete_string_type::sCanonicalVTable) + , mData(nsnull) + , mLength(0) + , mFlags(0) + { + Assign(tuple); + } + + protected: + + friend class nsTSubstringTuple_CharT; + + // GCC 3.2 erroneously needs these (even though they are subclasses!) + friend class nsTSubstring_CharT; + friend class nsTDependentSubstring_CharT; + friend class nsTPromiseFlatString_CharT; + + /** + * the address of our virtual function table. required for backwards + * compatibility with Mozilla 1.0 frozen nsAC?String interface. + */ + const void* mVTable; + + /** + * these fields are "here" only when mVTable == sCanonicalVTable. + * + * they exist to support automatic construction of a nsTAString + * from a nsTSubstringTuple. + */ + char_type* mData; + size_type mLength; + PRUint32 mFlags; + + /** + * nsTAString must be subclassed before it can be instantiated. + */ + nsTAString_CharT(char_type* data, size_type length, PRUint32 flags) + : mVTable(obsolete_string_type::sCanonicalVTable) + , mData(data) + , mLength(length) + , mFlags(flags) + {} + + /** + * optional ctor for use by subclasses. + * + * NOTE: mData and mLength are intentionally left uninitialized. + */ + explicit + nsTAString_CharT(PRUint32 flags) + : mVTable(obsolete_string_type::sCanonicalVTable) + , mFlags(flags) + {} + + /** + * get pointer to internal string buffer (may not be null terminated). + * return length of buffer. + */ + NS_COM size_type NS_FASTCALL GetReadableBuffer( const char_type **data ) const; + NS_COM size_type NS_FASTCALL GetWritableBuffer( char_type **data ); + + /** + * returns true if this tuple is dependent on (i.e., overlapping with) + * the given char sequence. + */ + PRBool NS_FASTCALL IsDependentOn(const char_type *start, const char_type *end) const; + + /** + * we can be converted to a const nsTSubstring (dependent on this) + */ + const substring_type NS_FASTCALL ToSubstring() const; + + /** + * type cast helpers + */ + + const obsolete_string_type* AsObsoleteString() const + { + return NS_REINTERPRET_CAST(const obsolete_string_type*, this); + } + + obsolete_string_type* AsObsoleteString() + { + return NS_REINTERPRET_CAST(obsolete_string_type*, this); + } + + const substring_type* AsSubstring() const + { + return NS_REINTERPRET_CAST(const substring_type*, this); + } + + substring_type* AsSubstring() + { + return NS_REINTERPRET_CAST(substring_type*, this); + } + + private: + + // GCC 2.95.3, EGCS-2.91.66, Sun Workshop/Forte, and IBM VisualAge C++ + // require a public copy-constructor in order to support automatic + // construction of a nsTAString from a nsTSubstringTuple. I believe + // enabling the default copy-constructor is harmless, but I do not want + // it to be enabled by default because that might tempt people into + // using it (where it would be invalid). +#if !defined(__SUNPRO_CC) && \ + !(defined(_AIX) && defined(__IBMCPP__)) && \ + (!defined(__GNUC__) || __GNUC__ > 2 || __GNUC_MINOR__ > 95) + + // NOT TO BE IMPLEMENTED + nsTAString_CharT( const self_type& ); + +#endif + + // NOT TO BE IMPLEMENTED + void operator= ( incompatible_char_type ); + void Assign ( incompatible_char_type ); + void operator+= ( incompatible_char_type ); + void Append ( incompatible_char_type ); + void Insert ( incompatible_char_type, index_type ); + }; + + +NS_COM +int NS_FASTCALL Compare( const nsTAString_CharT& lhs, const nsTAString_CharT& rhs, const nsTStringComparator_CharT& = nsTDefaultStringComparator_CharT() ); + + +inline +PRBool operator!=( const nsTAString_CharT& lhs, const nsTAString_CharT& rhs ) + { + return !lhs.Equals(rhs); + } + +inline +PRBool operator< ( const nsTAString_CharT& lhs, const nsTAString_CharT& rhs ) + { + return Compare(lhs, rhs)< 0; + } + +inline +PRBool operator<=( const nsTAString_CharT& lhs, const nsTAString_CharT& rhs ) + { + return Compare(lhs, rhs)<=0; + } + +inline +PRBool operator==( const nsTAString_CharT& lhs, const nsTAString_CharT& rhs ) + { + return lhs.Equals(rhs); + } + +inline +PRBool operator>=( const nsTAString_CharT& lhs, const nsTAString_CharT& rhs ) + { + return Compare(lhs, rhs)>=0; + } + +inline +PRBool operator> ( const nsTAString_CharT& lhs, const nsTAString_CharT& rhs ) + { + return Compare(lhs, rhs)> 0; + } diff --git a/src/libs/xpcom18a4/xpcom/string/public/nsTDependentString.h b/src/libs/xpcom18a4/xpcom/string/public/nsTDependentString.h new file mode 100644 index 00000000..91a2b53e --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/public/nsTDependentString.h @@ -0,0 +1,137 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* ***** 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 IBM Corporation. + * Portions created by IBM Corporation are Copyright (C) 2003 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Scott Collins (original author) + * 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 ***** */ + + + /** + * nsTDependentString_CharT + * + * Stores a null-terminated, immutable sequence of characters. + * + * Subclass of nsTString that restricts string value to an immutable + * character sequence. This class does not own its data, so the creator + * of objects of this type must take care to ensure that a + * nsTDependentString continues to reference valid memory for the + * duration of its use. + */ +class nsTDependentString_CharT : public nsTString_CharT + { + public: + + typedef nsTDependentString_CharT self_type; + + public: + + /** + * verify restrictions + */ + void AssertValid() + { + NS_ASSERTION(mData, "nsTDependentString must wrap a non-NULL buffer"); + NS_ASSERTION(mLength != size_type(-1), "nsTDependentString has bogus length"); + NS_ASSERTION(mData[mLength] == 0, "nsTDependentString must wrap only null-terminated strings"); + } + + + /** + * constructors + */ + + nsTDependentString_CharT( const char_type* start, const char_type* end ) + : string_type(NS_CONST_CAST(char_type*, start), end - start, F_TERMINATED) + { + AssertValid(); + } + + nsTDependentString_CharT( const char_type* data, PRUint32 length ) + : string_type(NS_CONST_CAST(char_type*, data), length, F_TERMINATED) + { + AssertValid(); + } + + explicit + nsTDependentString_CharT( const char_type* data ) + : string_type(NS_CONST_CAST(char_type*, data), char_traits::length(data), F_TERMINATED) + { + AssertValid(); + } + + explicit + nsTDependentString_CharT( const substring_type& str ) + : string_type(NS_CONST_CAST(char_type*, str.Data()), str.Length(), F_TERMINATED) + { + AssertValid(); + } + + // XXX are you sure?? + // auto-generated copy-constructor OK + // auto-generated copy-assignment operator OK + // auto-generated destructor OK + + + /** + * allow this class to be bound to a different string... + */ + + void Rebind( const char_type* data ) + { + mData = NS_CONST_CAST(char_type*, data); + mLength = char_traits::length(data); + SetDataFlags(F_TERMINATED); + AssertValid(); + } + + void Rebind( const char_type* data, size_type length ) + { + mData = NS_CONST_CAST(char_type*, data); + mLength = length; + SetDataFlags(F_TERMINATED); + AssertValid(); + } + + void Rebind( const char_type* start, const char_type* end ) + { + Rebind(start, end - start); + } + + private: + + // NOT USED + nsTDependentString_CharT( const substring_tuple_type& ); + nsTDependentString_CharT( const abstract_string_type& ); + }; diff --git a/src/libs/xpcom18a4/xpcom/string/public/nsTDependentSubstring.h b/src/libs/xpcom18a4/xpcom/string/public/nsTDependentSubstring.h new file mode 100644 index 00000000..00e5f189 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/public/nsTDependentSubstring.h @@ -0,0 +1,143 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* ***** 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 IBM Corporation. + * Portions created by IBM Corporation are Copyright (C) 2003 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Scott Collins (original author) + * 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 ***** */ + + + /** + * nsTDependentSubstring_CharT + */ +class nsTDependentSubstring_CharT : public nsTSubstring_CharT + { + public: + + typedef nsTDependentSubstring_CharT self_type; + + public: + + NS_COM void Rebind( const abstract_string_type&, PRUint32 startPos, PRUint32 length = size_type(-1) ); + NS_COM void Rebind( const substring_type&, PRUint32 startPos, PRUint32 length = size_type(-1) ); + + void Rebind( const char_type* start, const char_type* end ) + { + NS_ASSERTION(start && end, "nsTDependentSubstring must wrap a non-NULL buffer"); + mData = NS_CONST_CAST(char_type*, start); + mLength = end - start; + SetDataFlags(F_NONE); + } + + nsTDependentSubstring_CharT( const abstract_string_type& str, PRUint32 startPos, PRUint32 length = size_type(-1) ) + : substring_type(F_NONE) + { + Rebind(str, startPos, length); + } + + nsTDependentSubstring_CharT( const substring_type& str, PRUint32 startPos, PRUint32 length = size_type(-1) ) + : substring_type(F_NONE) + { + Rebind(str, startPos, length); + } + + nsTDependentSubstring_CharT( const char_type* start, const char_type* end ) + : substring_type(NS_CONST_CAST(char_type*, start), end - start, F_NONE) {} + + nsTDependentSubstring_CharT( const const_iterator& start, const const_iterator& end ) + : substring_type(NS_CONST_CAST(char_type*, start.get()), end.get() - start.get(), F_NONE) {} + + // auto-generated copy-constructor OK (XXX really?? what about base class copy-ctor?) + + private: + // we're immutable, you can't assign into a substring + void operator=( const self_type& ) NS_DELETE; + + }; + +inline +const nsTDependentSubstring_CharT +Substring( const nsTAString_CharT& str, PRUint32 startPos, PRUint32 length = PRUint32(-1) ) + { + return nsTDependentSubstring_CharT(str, startPos, length); + } + +inline +const nsTDependentSubstring_CharT +Substring( const nsTSubstring_CharT& str, PRUint32 startPos, PRUint32 length = PRUint32(-1) ) + { + return nsTDependentSubstring_CharT(str, startPos, length); + } + +inline +const nsTDependentSubstring_CharT +Substring( const nsReadingIterator& start, const nsReadingIterator& end ) + { + return nsTDependentSubstring_CharT(start.get(), end.get()); + } + +inline +const nsTDependentSubstring_CharT +Substring( const CharT* start, const CharT* end ) + { + return nsTDependentSubstring_CharT(start, end); + } + +inline +const nsTDependentSubstring_CharT +StringHead( const nsTAString_CharT& str, PRUint32 count ) + { + return nsTDependentSubstring_CharT(str, 0, count); + } + +inline +const nsTDependentSubstring_CharT +StringHead( const nsTSubstring_CharT& str, PRUint32 count ) + { + return nsTDependentSubstring_CharT(str, 0, count); + } + +inline +const nsTDependentSubstring_CharT +StringTail( const nsTAString_CharT& str, PRUint32 count ) + { + return nsTDependentSubstring_CharT(str, str.Length() - count, count); + } + +inline +const nsTDependentSubstring_CharT +StringTail( const nsTSubstring_CharT& str, PRUint32 count ) + { + return nsTDependentSubstring_CharT(str, str.Length() - count, count); + } diff --git a/src/libs/xpcom18a4/xpcom/string/public/nsTObsoleteAString.h b/src/libs/xpcom18a4/xpcom/string/public/nsTObsoleteAString.h new file mode 100644 index 00000000..82d5f56c --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/public/nsTObsoleteAString.h @@ -0,0 +1,165 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* ***** 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 IBM Corporation. + * Portions created by IBM Corporation are Copyright (C) 2003 + * IBM Corporation. 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 ***** */ + + + /** + * nsTObsoleteAString_CharT : binary compatible with old nsAC?String vtable + * + * @status FROZEN + */ +class nsTObsoleteAString_CharT + { + public: + /** + * This is holds the address of the vtable for the canonical string + * implementation (i.e., nsTString). + */ + NS_COM static const void *sCanonicalVTable; + + /** + * An |nsFragmentRequest| is used to tell |GetReadableFragment| and + * |GetWritableFragment| what to do. + * + * @see GetReadableFragment + */ + enum nsFragmentRequest { kPrevFragment, kFirstFragment, kLastFragment, kNextFragment, kFragmentAt }; + + /** + * A |nsReadableFragment| provides |const| access to a contiguous hunk of + * string of homogenous units, e.g., bytes (|char|). This doesn't mean it + * represents a flat hunk. It could be a variable length encoding, for + * instance UTF-8. And the fragment itself need not be zero-terminated. + * + * An |nsReadableFragment| is the underlying machinery that lets + * |nsReadingIterator|s work. + * + * @see nsReadingIterator + * @status FROZEN + */ + struct nsReadableFragment + { + const CharT* mStart; + const CharT* mEnd; + const void* mFragmentIdentifier; + + nsReadableFragment() : mStart(0), mEnd(0), mFragmentIdentifier(0) {} + }; + + + /** + * A |nsWritableFragment| provides non-|const| access to a contiguous hunk of + * string of homogenous units, e.g., bytes (|char|). This doesn't mean it + * represents a flat hunk. It could be a variable length encoding, for + * instance UTF-8. And the fragment itself need not be zero-terminated. + * + * An |nsWritableFragment| is the underlying machinery that lets + * |nsWritingIterator|s work. + * + * @see nsWritingIterator + * @status FROZEN + */ + struct nsWritableFragment + { + CharT* mStart; + CharT* mEnd; + void* mFragmentIdentifier; + + nsWritableFragment() : mStart(0), mEnd(0), mFragmentIdentifier(0) {} + }; + + protected: + + typedef CharT char_type; + + typedef void buffer_handle_type; + typedef void shared_buffer_handle_type; + typedef nsReadableFragment const_fragment_type; + typedef nsWritableFragment fragment_type; + + typedef nsTAString_CharT abstract_string_type; + + typedef PRUint32 size_type; + typedef PRUint32 index_type; + + protected: + + friend class nsTAString_CharT; + friend class nsTSubstring_CharT; + + /** here's the old nsAC?String vtable **/ + + virtual ~nsTObsoleteAString_CharT() { } + + virtual PRUint32 GetImplementationFlags() const = 0; + virtual const buffer_handle_type* GetFlatBufferHandle() const = 0; + virtual const buffer_handle_type* GetBufferHandle() const = 0; + virtual const shared_buffer_handle_type* GetSharedBufferHandle() const = 0; + + virtual size_type Length() const = 0; + + virtual PRBool IsVoid() const = 0; + virtual void SetIsVoid( PRBool ) = 0; + + virtual void SetCapacity( size_type ) = 0; + virtual void SetLength( size_type ) = 0; + + virtual void Cut( index_type cutStart, size_type cutLength ) = 0; + + virtual void do_AssignFromReadable( const abstract_string_type& ) = 0; + virtual void do_AssignFromElementPtr( const char_type* ) = 0; + virtual void do_AssignFromElementPtrLength( const char_type*, size_type ) = 0; + virtual void do_AssignFromElement( char_type ) = 0; + + virtual void do_AppendFromReadable( const abstract_string_type& ) = 0; + virtual void do_AppendFromElementPtr( const char_type* ) = 0; + virtual void do_AppendFromElementPtrLength( const char_type*, size_type ) = 0; + virtual void do_AppendFromElement( char_type ) = 0; + + virtual void do_InsertFromReadable( const abstract_string_type&, index_type ) = 0; + virtual void do_InsertFromElementPtr( const char_type*, index_type ) = 0; + virtual void do_InsertFromElementPtrLength( const char_type*, index_type, size_type ) = 0; + virtual void do_InsertFromElement( char_type, index_type ) = 0; + + virtual void do_ReplaceFromReadable( index_type, size_type, const abstract_string_type& ) = 0; + + virtual const char_type* GetReadableFragment( const_fragment_type&, nsFragmentRequest, PRUint32 = 0 ) const = 0; + virtual char_type* GetWritableFragment( fragment_type&, nsFragmentRequest, PRUint32 = 0 ) = 0; + }; + + // forward declare implementation +class nsTObsoleteAStringThunk_CharT; diff --git a/src/libs/xpcom18a4/xpcom/string/public/nsTPromiseFlatString.h b/src/libs/xpcom18a4/xpcom/string/public/nsTPromiseFlatString.h new file mode 100644 index 00000000..6899df7c --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/public/nsTPromiseFlatString.h @@ -0,0 +1,158 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* ***** 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 IBM Corporation. + * Portions created by IBM Corporation are Copyright (C) 2003 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Scott Collins (original author) + * 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 ***** */ + + + /** + * NOTE: + * + * Try to avoid flat strings. |PromiseFlat[C]String| will help you as a last + * resort, and this may be necessary when dealing with legacy or OS calls, + * but in general, requiring a null-terminated array of characters kills many + * of the performance wins the string classes offer. Write your own code to + * use |nsA[C]String&|s for parameters. Write your string proccessing + * algorithms to exploit iterators. If you do this, you will benefit from + * being able to chain operations without copying or allocating and your code + * will be significantly more efficient. Remember, a function that takes an + * |const nsA[C]String&| can always be passed a raw character pointer by + * wrapping it (for free) in a |nsDependent[C]String|. But a function that + * takes a character pointer always has the potential to force allocation and + * copying. + * + * + * How to use it: + * + * A |nsPromiseFlat[C]String| doesn't necessarily own the characters it + * promises. You must never use it to promise characters out of a string + * with a shorter lifespan. The typical use will be something like this: + * + * SomeOSFunction( PromiseFlatCString(aCString).get() ); // GOOD + * + * Here's a BAD use: + * + * const char* buffer = PromiseFlatCString(aCString).get(); + * SomeOSFunction(buffer); // BAD!! |buffer| is a dangling pointer + * + * The only way to make one is with the function |PromiseFlat[C]String|, + * which produce a |const| instance. ``What if I need to keep a promise + * around for a little while?'' you might ask. In that case, you can keep a + * reference, like so + * + * const nsPromiseFlatString& flat = PromiseFlatString(aString); + * // this reference holds the anonymous temporary alive, but remember, + * // it must _still_ have a lifetime shorter than that of |aString| + * + * SomeOSFunction(flat.get()); + * SomeOtherOSFunction(flat.get()); + * + * + * How does it work? + * + * A |nsPromiseFlat[C]String| is just a wrapper for another string. If you + * apply it to a string that happens to be flat, your promise is just a + * dependent reference to the string's data. If you apply it to a non-flat + * string, then a temporary flat string is created for you, by allocating and + * copying. In the event that you end up assigning the result into a sharing + * string (e.g., |nsTString|), the right thing happens. + */ + +class nsTPromiseFlatString_CharT : public nsTString_CharT + { + public: + + typedef nsTPromiseFlatString_CharT self_type; + + private: + + NS_COM void Init( const substring_type& ); + NS_COM void Init( const abstract_string_type& ); + + // NOT TO BE IMPLEMENTED + void operator=( const self_type& ) NS_DELETE; + + // NOT TO BE IMPLEMENTED + nsTPromiseFlatString_CharT() NS_DELETE; + + public: + + explicit + nsTPromiseFlatString_CharT( const substring_type& str ) + : string_type() + { + Init(str); + } + + explicit + nsTPromiseFlatString_CharT( const abstract_string_type& readable ) + : string_type() + { + Init(readable); + } + + explicit + nsTPromiseFlatString_CharT( const substring_tuple_type& tuple ) + : string_type() + { + // nothing else to do here except assign the value of the tuple + // into ourselves. + Assign(tuple); + } + }; + +inline +const nsTPromiseFlatString_CharT +TPromiseFlatString_CharT( const nsTAString_CharT& str ) + { + return nsTPromiseFlatString_CharT(str); + } + + // e.g., PromiseFlatCString(Substring(s)) +inline +const nsTPromiseFlatString_CharT +TPromiseFlatString_CharT( const nsTSubstring_CharT& frag ) + { + return nsTPromiseFlatString_CharT(frag); + } + + // e.g., PromiseFlatCString(a + b) +inline +const nsTPromiseFlatString_CharT +TPromiseFlatString_CharT( const nsTSubstringTuple_CharT& tuple ) + { + return nsTPromiseFlatString_CharT(tuple); + } diff --git a/src/libs/xpcom18a4/xpcom/string/public/nsTString.h b/src/libs/xpcom18a4/xpcom/string/public/nsTString.h new file mode 100644 index 00000000..2ef241b2 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/public/nsTString.h @@ -0,0 +1,721 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* ***** 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 IBM Corporation. + * Portions created by IBM Corporation are Copyright (C) 2003 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Rick Gessner (original author) + * Scott Collins + * 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 ***** */ + + + /** + * This is the canonical null-terminated string class. All subclasses + * promise null-terminated storage. Instances of this class allocate + * strings on the heap. + * + * This class is also known as nsAFlat[C]String, where "flat" is used + * to denote a null-terminated string. + */ +class nsTString_CharT : public nsTSubstring_CharT + { + public: + + typedef nsTString_CharT self_type; + + public: + + /** + * constructors + */ + + nsTString_CharT() + : substring_type() {} + + explicit + nsTString_CharT( char_type c ) + : substring_type() + { + Assign(c); + } + + explicit + nsTString_CharT( const char_type* data, size_type length = size_type(-1) ) + : substring_type() + { + Assign(data, length); + } + + nsTString_CharT( const self_type& str ) + : substring_type() + { + Assign(str); + } + + nsTString_CharT( const substring_tuple_type& tuple ) + : substring_type() + { + Assign(tuple); + } + + explicit + nsTString_CharT( const abstract_string_type& readable ) + : substring_type() + { + Assign(readable); + } + + + // |operator=| does not inherit, so we must define our own + self_type& operator=( char_type c ) { Assign(c); return *this; } + self_type& operator=( const char_type* data ) { Assign(data); return *this; } + self_type& operator=( const self_type& str ) { Assign(str); return *this; } + self_type& operator=( const substring_type& str ) { Assign(str); return *this; } + self_type& operator=( const substring_tuple_type& tuple ) { Assign(tuple); return *this; } + self_type& operator=( const abstract_string_type& readable ) { Assign(readable); return *this; } + + + /** + * returns the null-terminated string + */ + + const char_type* get() const + { + return mData; + } + + + /** + * returns character at specified index. + * + * NOTE: unlike nsTSubstring::CharAt, this function allows you to index + * the null terminator character. + */ + + char_type CharAt( index_type i ) const + { + NS_ASSERTION(i <= mLength, "index exceeds allowable range"); + return mData[i]; + } + + char_type operator[]( index_type i ) const + { + return CharAt(i); + } + + +#if MOZ_STRING_WITH_OBSOLETE_API + + + /** + * Search for the given substring within this string. + * + * @param aString is substring to be sought in this + * @param aIgnoreCase selects case sensitivity + * @param aOffset tells us where in this string to start searching + * @param aCount tells us how far from the offset we are to search. Use + * -1 to search the whole string. + * @return offset in string, or kNotFound + */ + + NS_COM PRInt32 Find( const nsCString& aString, PRBool aIgnoreCase=PR_FALSE, PRInt32 aOffset=0, PRInt32 aCount=-1 ) const; + NS_COM PRInt32 Find( const char* aString, PRBool aIgnoreCase=PR_FALSE, PRInt32 aOffset=0, PRInt32 aCount=-1 ) const; + +#ifdef CharT_is_PRUnichar + NS_COM PRInt32 Find( const nsAFlatString& aString, PRInt32 aOffset=0, PRInt32 aCount=-1 ) const; + NS_COM PRInt32 Find( const PRUnichar* aString, PRInt32 aOffset=0, PRInt32 aCount=-1 ) const; +#endif + + + /** + * This methods scans the string backwards, looking for the given string + * + * @param aString is substring to be sought in this + * @param aIgnoreCase tells us whether or not to do caseless compare + * @param aOffset tells us where in this string to start searching. + * Use -1 to search from the end of the string. + * @param aCount tells us how many iterations to make starting at the + * given offset. + * @return offset in string, or kNotFound + */ + + NS_COM PRInt32 RFind( const nsCString& aString, PRBool aIgnoreCase=PR_FALSE, PRInt32 aOffset=-1, PRInt32 aCount=-1 ) const; + NS_COM PRInt32 RFind( const char* aCString, PRBool aIgnoreCase=PR_FALSE, PRInt32 aOffset=-1, PRInt32 aCount=-1 ) const; + +#ifdef CharT_is_PRUnichar + NS_COM PRInt32 RFind( const nsAFlatString& aString, PRInt32 aOffset=-1, PRInt32 aCount=-1 ) const; + NS_COM PRInt32 RFind( const PRUnichar* aString, PRInt32 aOffset=-1, PRInt32 aCount=-1 ) const; +#endif + + + /** + * Search for given char within this string + * + * @param aChar is the character to search for + * @param aOffset tells us where in this strig to start searching + * @param aCount tells us how far from the offset we are to search. + * Use -1 to search the whole string. + * @return offset in string, or kNotFound + */ + + // PRInt32 FindChar( PRUnichar aChar, PRInt32 aOffset=0, PRInt32 aCount=-1 ) const; + NS_COM PRInt32 RFindChar( PRUnichar aChar, PRInt32 aOffset=-1, PRInt32 aCount=-1 ) const; + + + /** + * This method searches this string for the first character found in + * the given string. + * + * @param aString contains set of chars to be found + * @param aOffset tells us where in this string to start searching + * (counting from left) + * @return offset in string, or kNotFound + */ + + NS_COM PRInt32 FindCharInSet( const char* aString, PRInt32 aOffset=0 ) const; + PRInt32 FindCharInSet( const self_type& aString, PRInt32 aOffset=0 ) const + { + return FindCharInSet(aString.get(), aOffset); + } + +#ifdef CharT_is_PRUnichar + NS_COM PRInt32 FindCharInSet( const PRUnichar* aString, PRInt32 aOffset=0 ) const; +#endif + + + /** + * This method searches this string for the last character found in + * the given string. + * + * @param aString contains set of chars to be found + * @param aOffset tells us where in this string to start searching + * (counting from left) + * @return offset in string, or kNotFound + */ + + NS_COM PRInt32 RFindCharInSet( const char_type* aString, PRInt32 aOffset=-1 ) const; + PRInt32 RFindCharInSet( const self_type& aString, PRInt32 aOffset=-1 ) const + { + return RFindCharInSet(aString.get(), aOffset); + } + + + /** + * Compares a given string to this string. + * + * @param aString is the string to be compared + * @param aIgnoreCase tells us how to treat case + * @param aCount tells us how many chars to compare + * @return -1,0,1 + */ + +#ifdef CharT_is_char + NS_COM PRInt32 Compare( const char* aString, PRBool aIgnoreCase=PR_FALSE, PRInt32 aCount=-1 ) const; +#endif + + + /** + * Equality check between given string and this string. + * + * @param aString is the string to check + * @param aIgnoreCase tells us how to treat case + * @param aCount tells us how many chars to compare + * @return boolean + */ +#ifdef CharT_is_char + PRBool EqualsIgnoreCase( const char* aString, PRInt32 aCount=-1 ) const { + return Compare(aString, PR_TRUE, aCount) == 0; + } +#else + NS_COM PRBool EqualsIgnoreCase( const char* aString, PRInt32 aCount=-1 ) const; + + + /** + * Copies data from internal buffer onto given char* buffer + * + * NOTE: This only copies as many chars as will fit in given buffer (clips) + * @param aBuf is the buffer where data is stored + * @param aBuflength is the max # of chars to move to buffer + * @param aOffset is the offset to copy from + * @return ptr to given buffer + */ + + NS_COM char* ToCString( char* aBuf, PRUint32 aBufLength, PRUint32 aOffset=0 ) const; + +#endif // !CharT_is_PRUnichar + + /** + * Perform string to float conversion. + * + * @param aErrorCode will contain error if one occurs + * @return float rep of string value + */ + NS_COM float ToFloat( PRInt32* aErrorCode ) const; + + + /** + * Perform string to int conversion. + * @param aErrorCode will contain error if one occurs + * @param aRadix tells us which radix to assume; kAutoDetect tells us to determine the radix for you. + * @return int rep of string value, and possible (out) error code + */ + NS_COM PRInt32 ToInteger( PRInt32* aErrorCode, PRUint32 aRadix=kRadix10 ) const; + + + /** + * |Left|, |Mid|, and |Right| are annoying signatures that seem better almost + * any _other_ way than they are now. Consider these alternatives + * + * aWritable = aReadable.Left(17); // ...a member function that returns a |Substring| + * aWritable = Left(aReadable, 17); // ...a global function that returns a |Substring| + * Left(aReadable, 17, aWritable); // ...a global function that does the assignment + * + * as opposed to the current signature + * + * aReadable.Left(aWritable, 17); // ...a member function that does the assignment + * + * or maybe just stamping them out in favor of |Substring|, they are just duplicate functionality + * + * aWritable = Substring(aReadable, 0, 17); + */ + + NS_COM size_type Mid( self_type& aResult, PRUint32 aStartPos, PRUint32 aCount ) const; + + size_type Left( self_type& aResult, size_type aCount ) const + { + return Mid(aResult, 0, aCount); + } + + size_type Right( self_type& aResult, size_type aCount ) const + { + aCount = NS_MIN(mLength, aCount); + return Mid(aResult, mLength - aCount, aCount); + } + + + /** + * Set a char inside this string at given index + * + * @param aChar is the char you want to write into this string + * @param anIndex is the ofs where you want to write the given char + * @return TRUE if successful + */ + + NS_COM PRBool SetCharAt( PRUnichar aChar, PRUint32 aIndex ); + + + /** + * These methods are used to remove all occurances of the + * characters found in aSet from this string. + * + * @param aSet -- characters to be cut from this + */ + NS_COM void StripChars( const char* aSet ); + + + /** + * This method is used to remove all occurances of aChar from this + * string. + * + * @param aChar -- char to be stripped + * @param aOffset -- where in this string to start stripping chars + */ + + NS_COM void StripChar( char_type aChar, PRInt32 aOffset=0 ); + + + /** + * This method strips whitespace throughout the string. + */ + NS_COM void StripWhitespace(); + + + /** + * swaps occurence of 1 string for another + */ + + NS_COM void ReplaceChar( char_type aOldChar, char_type aNewChar ); + NS_COM void ReplaceChar( const char* aSet, char_type aNewChar ); + NS_COM void ReplaceSubstring( const self_type& aTarget, const self_type& aNewValue); + NS_COM void ReplaceSubstring( const char_type* aTarget, const char_type* aNewValue); + + + /** + * This method trims characters found in aTrimSet from + * either end of the underlying string. + * + * @param aSet -- contains chars to be trimmed from both ends + * @param aEliminateLeading + * @param aEliminateTrailing + * @param aIgnoreQuotes -- if true, causes surrounding quotes to be ignored + * @return this + */ + NS_COM void Trim( const char* aSet, PRBool aEliminateLeading=PR_TRUE, PRBool aEliminateTrailing=PR_TRUE, PRBool aIgnoreQuotes=PR_FALSE ); + + /** + * This method strips whitespace from string. + * You can control whether whitespace is yanked from start and end of + * string as well. + * + * @param aEliminateLeading controls stripping of leading ws + * @param aEliminateTrailing controls stripping of trailing ws + */ + NS_COM void CompressWhitespace( PRBool aEliminateLeading=PR_TRUE, PRBool aEliminateTrailing=PR_TRUE ); + + + /** + * assign/append/insert with _LOSSY_ conversion + */ + + NS_COM void AssignWithConversion( const nsTAString_IncompatibleCharT& aString ); + NS_COM void AssignWithConversion( const incompatible_char_type* aData, PRInt32 aLength=-1 ); + + NS_COM void AppendWithConversion( const nsTAString_IncompatibleCharT& aString ); + NS_COM void AppendWithConversion( const incompatible_char_type* aData, PRInt32 aLength=-1 ); + + /** + * Append the given integer to this string + */ + NS_COM void AppendInt( PRInt32 aInteger, PRInt32 aRadix=kRadix10 ); //radix=8,10 or 16 + + /** + * Append the given unsigned integer to this string + */ + inline void AppendInt( PRUint32 aInteger, PRInt32 aRadix = kRadix10 ) + { + AppendInt(PRInt32(aInteger), aRadix); + } + + /** + * Append the given 64-bit integer to this string. + * @param aInteger The integer to append + * @param aRadix The radix to use; can be 8, 10 or 16. + */ + NS_COM void AppendInt( PRInt64 aInteger, PRInt32 aRadix=kRadix10 ); + + /** + * Append the given float to this string + */ + + NS_COM void AppendFloat( double aFloat ); + +#endif // !MOZ_STRING_WITH_OBSOLETE_API + + + protected: + + explicit + nsTString_CharT( PRUint32 flags ) + : substring_type(flags) {} + + // allow subclasses to initialize fields directly + nsTString_CharT( char_type* data, size_type length, PRUint32 flags ) + : substring_type(data, length, flags) {} + }; + + +class nsTFixedString_CharT : public nsTString_CharT + { + public: + + typedef nsTFixedString_CharT self_type; + typedef nsTFixedString_CharT fixed_string_type; + + public: + + /** + * @param data + * fixed-size buffer to be used by the string (the contents of + * this buffer may be modified by the string) + * @param storageSize + * the size of the fixed buffer + * @param length (optional) + * the length of the string already contained in the buffer + */ + + nsTFixedString_CharT( char_type* data, size_type storageSize ) + : string_type(data, char_traits::length(data), F_TERMINATED | F_FIXED | F_CLASS_FIXED) + , mFixedCapacity(storageSize - 1) + , mFixedBuf(data) + {} + + nsTFixedString_CharT( char_type* data, size_type storageSize, size_type length ) + : string_type(data, length, F_TERMINATED | F_FIXED | F_CLASS_FIXED) + , mFixedCapacity(storageSize - 1) + , mFixedBuf(data) + { + // null-terminate + mFixedBuf[length] = char_type(0); + } + + // |operator=| does not inherit, so we must define our own + self_type& operator=( char_type c ) { Assign(c); return *this; } + self_type& operator=( const char_type* data ) { Assign(data); return *this; } + self_type& operator=( const substring_type& str ) { Assign(str); return *this; } + self_type& operator=( const substring_tuple_type& tuple ) { Assign(tuple); return *this; } + self_type& operator=( const abstract_string_type& readable ) { Assign(readable); return *this; } + + protected: + + friend class nsTSubstring_CharT; + + size_type mFixedCapacity; + char_type *mFixedBuf; + }; + + + /** + * nsTAutoString_CharT + * + * Subclass of nsTString_CharT that adds support for stack-based string + * allocation. Do not allocate this class on the heap! ;-) + */ +class nsTAutoString_CharT : public nsTFixedString_CharT + { + public: + + typedef nsTAutoString_CharT self_type; + + public: + + /** + * constructors + */ + + nsTAutoString_CharT() + : fixed_string_type(mStorage, kDefaultStorageSize, 0) + {} + + explicit + nsTAutoString_CharT( char_type c ) + : fixed_string_type(mStorage, kDefaultStorageSize, 0) + { + Assign(c); + } + + explicit + nsTAutoString_CharT( const char_type* data, size_type length = size_type(-1) ) + : fixed_string_type(mStorage, kDefaultStorageSize, 0) + { + Assign(data, length); + } + + nsTAutoString_CharT( const self_type& str ) + : fixed_string_type(mStorage, kDefaultStorageSize, 0) + { + Assign(str); + } + + explicit + nsTAutoString_CharT( const substring_type& str ) + : fixed_string_type(mStorage, kDefaultStorageSize, 0) + { + Assign(str); + } + + nsTAutoString_CharT( const substring_tuple_type& tuple ) + : fixed_string_type(mStorage, kDefaultStorageSize, 0) + { + Assign(tuple); + } + + explicit + nsTAutoString_CharT( const abstract_string_type& readable ) + : fixed_string_type(mStorage, kDefaultStorageSize, 0) + { + Assign(readable); + } + + // |operator=| does not inherit, so we must define our own + self_type& operator=( char_type c ) { Assign(c); return *this; } + self_type& operator=( const char_type* data ) { Assign(data); return *this; } + self_type& operator=( const self_type& str ) { Assign(str); return *this; } + self_type& operator=( const substring_type& str ) { Assign(str); return *this; } + self_type& operator=( const substring_tuple_type& tuple ) { Assign(tuple); return *this; } + self_type& operator=( const abstract_string_type& readable ) { Assign(readable); return *this; } + + enum { kDefaultStorageSize = 64 }; + + private: + + char_type mStorage[kDefaultStorageSize]; + }; + + + /** + * nsTXPIDLString extends nsTString such that: + * + * (1) mData can be null + * (2) objects of this type can be automatically cast to |const CharT*| + * (3) getter_Copies method is supported to adopt data + */ +class nsTXPIDLString_CharT : public nsTString_CharT + { + public: + + typedef nsTXPIDLString_CharT self_type; + + public: + + nsTXPIDLString_CharT() + : string_type(NS_CONST_CAST(char_type*, char_traits::sEmptyBuffer), 0, F_TERMINATED | F_VOIDED) {} + + // copy-constructor required to avoid default + nsTXPIDLString_CharT( const self_type& str ) + : string_type(NS_CONST_CAST(char_type*, char_traits::sEmptyBuffer), 0, F_TERMINATED | F_VOIDED) + { + Assign(str); + } + + // return nsnull if we are voided + const char_type* get() const + { + return (mFlags & F_VOIDED) ? nsnull : mData; + } + + // this case operator is the reason why this class cannot just be a + // typedef for nsTString + operator const char_type*() const + { + return get(); + } + + // need this to diambiguous operator[int] + char_type operator[]( PRInt32 i ) const + { + return CharAt(index_type(i)); + } + + // |operator=| does not inherit, so we must define our own + self_type& operator=( char_type c ) { Assign(c); return *this; } + self_type& operator=( const char_type* data ) { Assign(data); return *this; } + self_type& operator=( const self_type& str ) { Assign(str); return *this; } + self_type& operator=( const substring_type& str ) { Assign(str); return *this; } + self_type& operator=( const substring_tuple_type& tuple ) { Assign(tuple); return *this; } + self_type& operator=( const abstract_string_type& readable ) { Assign(readable); return *this; } + }; + + + /** + * getter_Copies support for use with raw string out params: + * + * NS_IMETHOD GetBlah(char**); + * + * void some_function() + * { + * nsXPIDLCString blah; + * GetBlah(getter_Copies(blah)); + * // ... + * } + */ +class nsTGetterCopies_CharT + { + public: + typedef CharT char_type; + + nsTGetterCopies_CharT(nsTXPIDLString_CharT& str) + : mString(str), mData(nsnull) {} + + ~nsTGetterCopies_CharT() + { + mString.Adopt(mData); // OK if mData is null + } + + operator char_type**() + { + return &mData; + } + + private: + nsTXPIDLString_CharT& mString; + char_type* mData; + }; + +inline +nsTGetterCopies_CharT +getter_Copies( nsTXPIDLString_CharT& aString ) + { + return nsTGetterCopies_CharT(aString); + } + + + /** + * nsTAdoptingString extends nsTXPIDLString such that: + * + * (1) Adopt given string on construction or assignment, i.e. take + * the value of what's given, and make what's given forget its + * value. Note that this class violates constness in a few + * places. Be careful! + */ +class nsTAdoptingString_CharT : public nsTXPIDLString_CharT + { + public: + + typedef nsTAdoptingString_CharT self_type; + + public: + + explicit nsTAdoptingString_CharT() {} + explicit nsTAdoptingString_CharT(char_type* str, size_type length = size_type(-1)) + { + Adopt(str, length); + } + + // copy-constructor required to adopt on copy. Note that this + // will violate the constness of |str| in the operator=() + // call. |str| will be truncated as a side-effect of this + // constructor. + nsTAdoptingString_CharT( const self_type& str ) +#ifdef VBOX /* bird: shut up annoying warnings */ + : nsTXPIDLString_CharT() +#endif + { + *this = str; + } + + // |operator=| does not inherit, so we must define our own + self_type& operator=( const substring_type& str ) { Assign(str); return *this; } + self_type& operator=( const substring_tuple_type& tuple ) { Assign(tuple); return *this; } + self_type& operator=( const abstract_string_type& readable ) { Assign(readable); return *this; } + + // Adopt(), if possible, when assigning to a self_type&. Note + // that this violates the constness of str, str is always + // truncated when this operator is called. + NS_COM self_type& operator=( const self_type& str ); + + private: + // NOT TO BE IMPLEMENTED. + self_type& operator=( const char_type* data ); + self_type& operator=( char_type* data ); + }; + diff --git a/src/libs/xpcom18a4/xpcom/string/public/nsTSubstring.h b/src/libs/xpcom18a4/xpcom/string/public/nsTSubstring.h new file mode 100644 index 00000000..aaaf5a64 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/public/nsTSubstring.h @@ -0,0 +1,575 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* ***** 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 IBM Corporation. + * Portions created by IBM Corporation are Copyright (C) 2003 + * IBM Corporation. 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 ***** */ + + + /** + * nsTSubstring + * + * The base string type. This type is not instantiated directly. A sub- + * class is instantiated instead. For example, see nsTString. + * + * This type works like nsTAString except that it does not have the ABI + * requirements of that interface. Like nsTAString, nsTSubstring + * represents a single contiguous array of characters that may or may not + * be null-terminated. + * + * Many of the accessors on nsTSubstring are inlined as an optimization. + * + * This class is also known as "nsASingleFragmentC?String". + */ +class nsTSubstring_CharT : public nsTAString_CharT + { + public: + + typedef nsTSubstring_CharT self_type; + typedef nsTString_CharT string_type; + + typedef char_type* char_iterator; + typedef const char_type* const_char_iterator; + + public: + + /** + * reading iterators + */ + + const_char_iterator BeginReading() const { return mData; } + const_char_iterator EndReading() const { return mData + mLength; } + + /** + * deprecated reading iterators + */ + + const_iterator& BeginReading( const_iterator& iter ) const + { + iter.mStart = mData; + iter.mEnd = mData + mLength; + iter.mPosition = iter.mStart; + return iter; + } + + const_iterator& EndReading( const_iterator& iter ) const + { + iter.mStart = mData; + iter.mEnd = mData + mLength; + iter.mPosition = iter.mEnd; + return iter; + } + + const_char_iterator& BeginReading( const_char_iterator& iter ) const + { + return iter = mData; + } + + const_char_iterator& EndReading( const_char_iterator& iter ) const + { + return iter = mData + mLength; + } + + + /** + * writing iterators + */ + + char_iterator BeginWriting() { EnsureMutable(); return mData; } + char_iterator EndWriting() { EnsureMutable(); return mData + mLength; } + + /** + * deprecated writing iterators + */ + + iterator& BeginWriting( iterator& iter ) + { + EnsureMutable(); + iter.mStart = mData; + iter.mEnd = mData + mLength; + iter.mPosition = iter.mStart; + return iter; + } + + iterator& EndWriting( iterator& iter ) + { + EnsureMutable(); + iter.mStart = mData; + iter.mEnd = mData + mLength; + iter.mPosition = iter.mEnd; + return iter; + } + + char_iterator& BeginWriting( char_iterator& iter ) + { + EnsureMutable(); + return iter = mData; + } + + char_iterator& EndWriting( char_iterator& iter ) + { + EnsureMutable(); + return iter = mData + mLength; + } + + + /** + * accessors + */ + + // returns pointer to string data (not necessarily null-terminated) + const char_type *Data() const + { + return mData; + } + + size_type Length() const + { + return mLength; + } + + PRBool IsEmpty() const + { + return mLength == 0; + } + + PRBool IsVoid() const + { + return mFlags & F_VOIDED; + } + + PRBool IsTerminated() const + { + return mFlags & F_TERMINATED; + } + + char_type CharAt( index_type i ) const + { + NS_ASSERTION(i < mLength, "index exceeds allowable range"); + return mData[i]; + } + + char_type operator[]( index_type i ) const + { + return CharAt(i); + } + + char_type First() const + { + NS_ASSERTION(mLength > 0, "|First()| called on an empty string"); + return mData[0]; + } + + inline + char_type Last() const + { + NS_ASSERTION(mLength > 0, "|Last()| called on an empty string"); + return mData[mLength - 1]; + } + + NS_COM size_type NS_FASTCALL CountChar( char_type ) const; + NS_COM PRInt32 NS_FASTCALL FindChar( char_type, index_type offset = 0 ) const; + + + /** + * equality + */ + + NS_COM PRBool NS_FASTCALL Equals( const self_type& ) const; + NS_COM PRBool NS_FASTCALL Equals( const self_type&, const comparator_type& ) const; + + NS_COM PRBool NS_FASTCALL Equals( const abstract_string_type& readable ) const; + NS_COM PRBool NS_FASTCALL Equals( const abstract_string_type& readable, const comparator_type& comp ) const; + + NS_COM PRBool NS_FASTCALL Equals( const char_type* data ) const; + NS_COM PRBool NS_FASTCALL Equals( const char_type* data, const comparator_type& comp ) const; + + /** + * An efficient comparison with ASCII that can be used even + * for wide strings. Call this version when you know the + * length of 'data'. + */ + NS_COM PRBool NS_FASTCALL EqualsASCII( const char* data, size_type len ) const; + /** + * An efficient comparison with ASCII that can be used even + * for wide strings. Call this version when 'data' is + * null-terminated. + */ + NS_COM PRBool NS_FASTCALL EqualsASCII( const char* data ) const; + + // EqualsLiteral must ONLY be applied to an actual literal string. + // Do not attempt to use it with a regular char* pointer, or with a char + // array variable. + // The template trick to acquire the array length at compile time without + // using a macro is due to Corey Kosak, with much thanks. +#ifdef NS_DISABLE_LITERAL_TEMPLATE + inline PRBool EqualsLiteral( const char* str ) const + { + return EqualsASCII(str); + } +#else + template + inline PRBool EqualsLiteral( const char (&str)[N] ) const + { + return EqualsASCII(str, N-1); + } + template + inline PRBool EqualsLiteral( char (&str)[N] ) const + { + const char* s = str; + return EqualsASCII(s, N-1); + } +#endif + + // The LowerCaseEquals methods compare the lower case version of + // this string to some ASCII/Literal string. The ASCII string is + // *not* lowercased for you. If you compare to an ASCII or literal + // string that contains an uppercase character, it is guaranteed to + // return false. We will throw assertions too. + NS_COM PRBool NS_FASTCALL LowerCaseEqualsASCII( const char* data, size_type len ) const; + NS_COM PRBool NS_FASTCALL LowerCaseEqualsASCII( const char* data ) const; + + // LowerCaseEqualsLiteral must ONLY be applied to an actual + // literal string. Do not attempt to use it with a regular char* + // pointer, or with a char array variable. Use + // LowerCaseEqualsASCII for them. +#ifdef NS_DISABLE_LITERAL_TEMPLATE + inline PRBool LowerCaseEqualsLiteral( const char* str ) const + { + return LowerCaseEqualsASCII(str); + } +#else + template + inline PRBool LowerCaseEqualsLiteral( const char (&str)[N] ) const + { + return LowerCaseEqualsASCII(str, N-1); + } + template + inline PRBool LowerCaseEqualsLiteral( char (&str)[N] ) const + { + const char* s = str; + return LowerCaseEqualsASCII(s, N-1); + } +#endif + + /** + * assignment + */ + + void Assign( char_type c ) { Assign(&c, 1); } + NS_COM void NS_FASTCALL Assign( const char_type* data, size_type length = size_type(-1) ); + NS_COM void NS_FASTCALL Assign( const self_type& ); + NS_COM void NS_FASTCALL Assign( const substring_tuple_type& ); + NS_COM void NS_FASTCALL Assign( const abstract_string_type& ); + + NS_COM void NS_FASTCALL AssignASCII( const char* data, size_type length ); + NS_COM void NS_FASTCALL AssignASCII( const char* data ); + + // AssignLiteral must ONLY be applied to an actual literal string. + // Do not attempt to use it with a regular char* pointer, or with a char + // array variable. Use AssignASCII for those. +#ifdef NS_DISABLE_LITERAL_TEMPLATE + void AssignLiteral( const char* str ) + { AssignASCII(str); } +#else + template + void AssignLiteral( const char (&str)[N] ) + { AssignASCII(str, N-1); } + template + void AssignLiteral( char (&str)[N] ) + { AssignASCII(str, N-1); } +#endif + + self_type& operator=( char_type c ) { Assign(c); return *this; } + self_type& operator=( const char_type* data ) { Assign(data); return *this; } + self_type& operator=( const self_type& str ) { Assign(str); return *this; } + self_type& operator=( const substring_tuple_type& tuple ) { Assign(tuple); return *this; } + self_type& operator=( const abstract_string_type& readable ) { Assign(readable); return *this; } + + NS_COM void NS_FASTCALL Adopt( char_type* data, size_type length = size_type(-1) ); + + + /** + * buffer manipulation + */ + + void Replace( index_type cutStart, size_type cutLength, char_type c ) { Replace(cutStart, cutLength, &c, 1); } + NS_COM void NS_FASTCALL Replace( index_type cutStart, size_type cutLength, const char_type* data, size_type length = size_type(-1) ); + void Replace( index_type cutStart, size_type cutLength, const self_type& str ) { Replace(cutStart, cutLength, str.Data(), str.Length()); } + NS_COM void NS_FASTCALL Replace( index_type cutStart, size_type cutLength, const substring_tuple_type& tuple ); + NS_COM void NS_FASTCALL Replace( index_type cutStart, size_type cutLength, const abstract_string_type& readable ); + + NS_COM void NS_FASTCALL ReplaceASCII( index_type cutStart, size_type cutLength, const char* data, size_type length = size_type(-1) ); + + void Append( char_type c ) { Replace(mLength, 0, c); } + void Append( const char_type* data, size_type length = size_type(-1) ) { Replace(mLength, 0, data, length); } + void Append( const self_type& str ) { Replace(mLength, 0, str); } + void Append( const substring_tuple_type& tuple ) { Replace(mLength, 0, tuple); } + void Append( const abstract_string_type& readable ) { Replace(mLength, 0, readable); } + + void AppendASCII( const char* data, size_type length = size_type(-1) ) { ReplaceASCII(mLength, 0, data, length); } + + // AppendLiteral must ONLY be applied to an actual literal string. + // Do not attempt to use it with a regular char* pointer, or with a char + // array variable. Use AppendASCII for those. +#ifdef NS_DISABLE_LITERAL_TEMPLATE + void AppendLiteral( const char* str ) + { AppendASCII(str); } +#else + template + void AppendLiteral( const char (&str)[N] ) + { AppendASCII(str, N-1); } + template + void AppendLiteral( char (&str)[N] ) + { AppendASCII(str, N-1); } +#endif + + self_type& operator+=( char_type c ) { Append(c); return *this; } + self_type& operator+=( const char_type* data ) { Append(data); return *this; } + self_type& operator+=( const self_type& str ) { Append(str); return *this; } + self_type& operator+=( const substring_tuple_type& tuple ) { Append(tuple); return *this; } + self_type& operator+=( const abstract_string_type& readable ) { Append(readable); return *this; } + + void Insert( char_type c, index_type pos ) { Replace(pos, 0, c); } + void Insert( const char_type* data, index_type pos, size_type length = size_type(-1) ) { Replace(pos, 0, data, length); } + void Insert( const self_type& str, index_type pos ) { Replace(pos, 0, str); } + void Insert( const substring_tuple_type& tuple, index_type pos ) { Replace(pos, 0, tuple); } + void Insert( const abstract_string_type& readable, index_type pos ) { Replace(pos, 0, readable); } + + void Cut( index_type cutStart, size_type cutLength ) { Replace(cutStart, cutLength, char_traits::sEmptyBuffer, 0); } + + + /** + * buffer sizing + */ + + NS_COM void NS_FASTCALL SetCapacity( size_type capacity ); + + NS_COM void NS_FASTCALL SetLength( size_type ); + + void Truncate( size_type newLength = 0 ) + { + NS_ASSERTION(newLength <= mLength, "Truncate cannot make string longer"); + SetLength(newLength); + } + + + /** + * string data is never null, but can be marked void. if true, the + * string will be truncated. @see nsTSubstring::IsVoid + */ + + NS_COM void NS_FASTCALL SetIsVoid( PRBool ); + + + public: + + /** + * this is public to support automatic conversion of tuple to string + * base type, which helps avoid converting to nsTAString. + */ + nsTSubstring_CharT(const substring_tuple_type& tuple) + : abstract_string_type(nsnull, 0, F_NONE) + { + Assign(tuple); + } + + protected: + + friend class nsTObsoleteAStringThunk_CharT; + friend class nsTAString_CharT; + friend class nsTSubstringTuple_CharT; + + // XXX GCC 3.4 needs this :-( + friend class nsTPromiseFlatString_CharT; + + // default initialization + nsTSubstring_CharT() + : abstract_string_type( + NS_CONST_CAST(char_type*, char_traits::sEmptyBuffer), 0, F_TERMINATED) {} + + // allow subclasses to initialize fields directly + nsTSubstring_CharT( char_type *data, size_type length, PRUint32 flags ) + : abstract_string_type(data, length, flags) {} + + // version of constructor that leaves mData and mLength uninitialized + explicit + nsTSubstring_CharT( PRUint32 flags ) + : abstract_string_type(flags) {} + + // copy-constructor, constructs as dependent on given object + // (NOTE: this is for internal use only) + nsTSubstring_CharT( const self_type& str ) + : abstract_string_type( + str.mData, str.mLength, str.mFlags & (F_TERMINATED | F_VOIDED)) {} + + /** + * this function releases mData and does not change the value of + * any of its member variables. inotherwords, this function acts + * like a destructor. + */ + void NS_FASTCALL Finalize(); + + /** + * this function prepares mData to be mutated. + * + * @param capacity specifies the required capacity of mData + * @param old_data returns null or the old value of mData + * @param old_flags returns 0 or the old value of mFlags + * + * if mData is already mutable and of sufficient capacity, then this + * function will return immediately. otherwise, it will either resize + * mData or allocate a new shared buffer. if it needs to allocate a + * new buffer, then it will return the old buffer and the corresponding + * flags. this allows the caller to decide when to free the old data. + * + * XXX we should expose a way for subclasses to free old_data. + */ + PRBool NS_FASTCALL MutatePrep( size_type capacity, char_type** old_data, PRUint32* old_flags ); + + /** + * this function prepares a section of mData to be modified. if + * necessary, this function will reallocate mData and possibly move + * existing data to open up the specified section. + * + * @param cutStart specifies the starting offset of the section + * @param cutLength specifies the length of the section to be replaced + * @param newLength specifies the length of the new section + * + * for example, suppose mData contains the string "abcdef" then + * + * ReplacePrep(2, 3, 4); + * + * would cause mData to look like "ab____f" where the characters + * indicated by '_' have an unspecified value and can be freely + * modified. this function will null-terminate mData upon return. + */ + void NS_FASTCALL ReplacePrep( index_type cutStart, size_type cutLength, size_type newLength ); + + /** + * returns the number of writable storage units starting at mData. + * the value does not include space for the null-terminator character. + * + * NOTE: this function returns size_type(-1) if mData is immutable. + */ + size_type NS_FASTCALL Capacity() const; + + /** + * this helper function can be called prior to directly manipulating + * the contents of mData. see, for example, BeginWriting. + */ + NS_COM void NS_FASTCALL EnsureMutable(); + + /** + * returns true if this string overlaps with the given string fragment. + */ + PRBool IsDependentOn( const char_type *start, const char_type *end ) const + { + /** + * if it _isn't_ the case that one fragment starts after the other ends, + * or ends before the other starts, then, they conflict: + * + * !(f2.begin >= f1.end || f2.end <= f1.begin) + * + * Simplified, that gives us: + */ + return ( start < (mData + mLength) && end > mData ); + } + + /** + * this helper function stores the specified dataFlags in mFlags + */ + void SetDataFlags(PRUint32 dataFlags) + { + NS_ASSERTION((dataFlags & 0xFFFF0000) == 0, "bad flags"); + mFlags = dataFlags | (mFlags & 0xFFFF0000); + } + + public: + + // mFlags is a bitwise combination of the following flags. the meaning + // and interpretation of these flags is an implementation detail. + // + // NOTE: these flags are declared public _only_ for convenience inside + // the string implementation. + + enum + { + F_NONE = 0, // no flags + + // data flags are in the lower 16-bits + F_TERMINATED = 1 << 0, // IsTerminated returns true + F_VOIDED = 1 << 1, // IsVoid returns true + F_SHARED = 1 << 2, // mData points to a heap-allocated, shared buffer + F_OWNED = 1 << 3, // mData points to a heap-allocated, raw buffer + F_FIXED = 1 << 4, // mData points to a fixed-size writable, dependent buffer + + // class flags are in the upper 16-bits + F_CLASS_FIXED = 1 << 16 // indicates that |this| is of type nsTFixedString + }; + + // + // Some terminology: + // + // "dependent buffer" A dependent buffer is one that the string class + // does not own. The string class relies on some + // external code to ensure the lifetime of the + // dependent buffer. + // + // "shared buffer" A shared buffer is one that the string class + // allocates. When it allocates a shared string + // buffer, it allocates some additional space at + // the beginning of the buffer for additional + // fields, including a reference count and a + // buffer length. See nsStringHeader. + // + // "adopted buffer" An adopted buffer is a raw string buffer + // allocated on the heap (using nsMemory::Alloc) + // of which the string class subsumes ownership. + // + // Some comments about the string flags: + // + // F_SHARED, F_OWNED, and F_FIXED are all mutually exlusive. They + // indicate the allocation type of mData. If none of these flags + // are set, then the string buffer is dependent. + // + // F_SHARED, F_OWNED, or F_FIXED imply F_TERMINATED. This is because + // the string classes always allocate null-terminated buffers, and + // non-terminated substrings are always dependent. + // + // F_VOIDED implies F_TERMINATED, and moreover it implies that mData + // points to char_traits::sEmptyBuffer. Therefore, F_VOIDED is + // mutually exclusive with F_SHARED, F_OWNED, and F_FIXED. + // + }; diff --git a/src/libs/xpcom18a4/xpcom/string/public/nsTSubstringTuple.h b/src/libs/xpcom18a4/xpcom/string/public/nsTSubstringTuple.h new file mode 100644 index 00000000..2ded17d5 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/public/nsTSubstringTuple.h @@ -0,0 +1,113 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* ***** 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 IBM Corporation. + * Portions created by IBM Corporation are Copyright (C) 2003 + * IBM Corporation. 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 ***** */ + + + /** + * nsTSubstringTuple_CharT + * + * Represents a tuple of string fragments. Built as a recursive binary tree. + * It is used to implement the concatenation of two or more string objects. + * + * NOTE: This class is a private implementation detail and should never be + * referenced outside the string code. + */ +class nsTSubstringTuple_CharT + { + public: + + typedef CharT char_type; + typedef nsCharTraits char_traits; + + typedef nsTSubstringTuple_CharT self_type; + typedef nsTSubstring_CharT substring_type; + typedef nsTString_CharT string_type; + typedef nsTAString_CharT abstract_string_type; + typedef nsTObsoleteAString_CharT obsolete_string_type; + + typedef PRUint32 size_type; + + public: + + nsTSubstringTuple_CharT(const abstract_string_type* a, const abstract_string_type* b) + : mHead(nsnull) + , mFragA(a) + , mFragB(b) {} + + nsTSubstringTuple_CharT(const self_type& head, const abstract_string_type* b) + : mHead(&head) + , mFragA(nsnull) // this fragment is ignored when head != nsnull + , mFragB(b) {} + + /** + * computes the aggregate string length + */ + NS_COM size_type Length() const; + + /** + * writes the aggregate string to the given buffer. bufLen is assumed + * to be equal to or greater than the value returned by the Length() + * method. the string written to |buf| is not null-terminated. + */ + NS_COM void WriteTo(char_type *buf, PRUint32 bufLen) const; + + /** + * returns true if this tuple is dependent on (i.e., overlapping with) + * the given char sequence. + */ + NS_COM PRBool IsDependentOn(const char_type *start, const char_type *end) const; + + private: + + const self_type* mHead; + const abstract_string_type* mFragA; + const abstract_string_type* mFragB; + }; + +inline +const nsTSubstringTuple_CharT +operator+(const nsTAString_CharT& a, const nsTAString_CharT& b) + { + return nsTSubstringTuple_CharT(&a, &b); + } + +inline +const nsTSubstringTuple_CharT +operator+(const nsTSubstringTuple_CharT& head, const nsTAString_CharT& b) + { + return nsTSubstringTuple_CharT(head, &b); + } diff --git a/src/libs/xpcom18a4/xpcom/string/public/nsUTF8Utils.h b/src/libs/xpcom18a4/xpcom/string/public/nsUTF8Utils.h new file mode 100644 index 00000000..c91079c2 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/public/nsUTF8Utils.h @@ -0,0 +1,462 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Peter Annema (original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +#ifndef nsUTF8Utils_h_ +#define nsUTF8Utils_h_ + +class UTF8traits + { + public: + static PRBool isASCII(char c) { return (c & 0x80) == 0x00; } + static PRBool isInSeq(char c) { return (c & 0xC0) == 0x80; } + static PRBool is2byte(char c) { return (c & 0xE0) == 0xC0; } + static PRBool is3byte(char c) { return (c & 0xF0) == 0xE0; } + static PRBool is4byte(char c) { return (c & 0xF8) == 0xF0; } + static PRBool is5byte(char c) { return (c & 0xFC) == 0xF8; } + static PRBool is6byte(char c) { return (c & 0xFE) == 0xFC; } + }; + +#define PLANE1_BASE 0x00010000 +#define UCS2_REPLACEMENT_CHAR 0xfffd + +#ifdef __GNUC__ +#define NS_ALWAYS_INLINE __attribute__((always_inline)) +#else +#define NS_ALWAYS_INLINE +#endif + +/** + * A character sink (see |copy_string| in nsAlgorithm.h) for converting + * UTF-8 to UTF-16 + */ +class ConvertUTF8toUTF16 + { + public: + typedef nsACString::char_type value_type; + typedef nsAString::char_type buffer_type; + + ConvertUTF8toUTF16( buffer_type* aBuffer ) + : mStart(aBuffer), mBuffer(aBuffer), mErrorEncountered(PR_FALSE) {} + + size_t Length() const { return mBuffer - mStart; } + + PRUint32 NS_ALWAYS_INLINE write( const value_type* start, PRUint32 N ) + { + if ( mErrorEncountered ) + return N; + + // algorithm assumes utf8 units won't + // be spread across fragments + const value_type* p = start; + const value_type* end = start + N; + buffer_type* out = mBuffer; + for ( ; p != end /* && *p */; ) + { + char c = *p++; + + if ( UTF8traits::isASCII(c) ) + { + *out++ = buffer_type(c); + continue; + } + + PRUint32 ucs4; + PRUint32 minUcs4; + PRInt32 state = 0; + + if ( UTF8traits::is2byte(c) ) + { + ucs4 = (PRUint32(c) << 6) & 0x000007C0L; + state = 1; + minUcs4 = 0x00000080; + } + else if ( UTF8traits::is3byte(c) ) + { + ucs4 = (PRUint32(c) << 12) & 0x0000F000L; + state = 2; + minUcs4 = 0x00000800; + } + else if ( UTF8traits::is4byte(c) ) + { + ucs4 = (PRUint32(c) << 18) & 0x001F0000L; + state = 3; + minUcs4 = 0x00010000; + } + else if ( UTF8traits::is5byte(c) ) + { + ucs4 = (PRUint32(c) << 24) & 0x03000000L; + state = 4; + minUcs4 = 0x00200000; + } + else if ( UTF8traits::is6byte(c) ) + { + ucs4 = (PRUint32(c) << 30) & 0x40000000L; + state = 5; + minUcs4 = 0x04000000; + } + else + { + NS_ERROR("Not a UTF-8 string. This code should only be used for converting from known UTF-8 strings."); + mErrorEncountered = PR_TRUE; + mBuffer = out; + return N; + } + + while ( state-- ) + { + c = *p++; + + if ( UTF8traits::isInSeq(c) ) + { + PRInt32 shift = state * 6; + ucs4 |= (PRUint32(c) & 0x3F) << shift; + } + else + { + NS_ERROR("not a UTF8 string"); + mErrorEncountered = PR_TRUE; + mBuffer = out; + return N; + } + } + + if ( ucs4 < minUcs4 ) + { + // Overlong sequence + *out++ = UCS2_REPLACEMENT_CHAR; + } + else if ( ucs4 <= 0xD7FF ) + { + *out++ = ucs4; + } + else if ( /* ucs4 >= 0xD800 && */ ucs4 <= 0xDFFF ) + { + // Surrogates + *out++ = UCS2_REPLACEMENT_CHAR; + } + else if ( ucs4 == 0xFFFE || ucs4 == 0xFFFF ) + { + // Prohibited characters + *out++ = UCS2_REPLACEMENT_CHAR; + } + else if ( ucs4 >= PLANE1_BASE ) + { + if ( ucs4 >= 0x00110000 ) + *out++ = UCS2_REPLACEMENT_CHAR; + else { + // surrogate, see unicode specification 3.7 for following math. + ucs4 -= PLANE1_BASE; + *out++ = (PRUnichar)(ucs4 >> 10) | 0xd800u; + *out++ = (PRUnichar)(ucs4 & 0x3ff) | 0xdc00u; + } + } + else + { + *out++ = ucs4; + } + } + mBuffer = out; + return p - start; + } + + void write_terminator() + { + *mBuffer = buffer_type(0); + } + + private: + buffer_type* const mStart; + buffer_type* mBuffer; + PRBool mErrorEncountered; + }; + +/** + * A character sink (see |copy_string| in nsAlgorithm.h) for computing + * the length of the UTF-16 string equivalent to a UTF-8 string. + */ +class CalculateUTF8Length + { + public: + typedef nsACString::char_type value_type; + + CalculateUTF8Length() : mLength(0), mErrorEncountered(PR_FALSE) { } + + size_t Length() const { return mLength; } + + PRUint32 NS_ALWAYS_INLINE write( const value_type* start, PRUint32 N ) + { + // ignore any further requests + if ( mErrorEncountered ) + return N; + + // algorithm assumes utf8 units won't + // be spread across fragments + const value_type* p = start; + const value_type* end = start + N; + for ( ; p < end /* && *p */; ++mLength ) + { + if ( UTF8traits::isASCII(*p) ) + p += 1; + else if ( UTF8traits::is2byte(*p) ) + p += 2; + else if ( UTF8traits::is3byte(*p) ) + p += 3; + else if ( UTF8traits::is4byte(*p) ) { + p += 4; + // Because a UTF-8 sequence of 4 bytes represents a codepoint + // greater than 0xFFFF, it will become a surrogate pair in the + // UTF-16 string, so add 1 more to mLength. + // This doesn't happen with is5byte and is6byte because they + // are illegal UTF-8 sequences (greater than 0x10FFFF) so get + // converted to a single replacement character. + // + // XXX: if the 4-byte sequence is an illegal non-shortest form, + // it also gets converted to a replacement character, so + // mLength will be off by one in this case. + ++mLength; + } + else if ( UTF8traits::is5byte(*p) ) + p += 5; + else if ( UTF8traits::is6byte(*p) ) + p += 6; + else + { + break; + } + } + if ( p != end ) + { + NS_ERROR("Not a UTF-8 string. This code should only be used for converting from known UTF-8 strings."); + mErrorEncountered = PR_TRUE; + mLength = 0; + return N; + } + return p - start; + } + + private: + size_t mLength; + PRBool mErrorEncountered; + }; + +/** + * A character sink (see |copy_string| in nsAlgorithm.h) for converting + * UTF-16 to UTF-8. + */ +class ConvertUTF16toUTF8 + { + public: + typedef nsAString::char_type value_type; + typedef nsACString::char_type buffer_type; + + // The error handling here is more lenient than that in + // |ConvertUTF8toUTF16|, but it's that way for backwards + // compatibility. + + ConvertUTF16toUTF8( buffer_type* aBuffer ) + : mStart(aBuffer), mBuffer(aBuffer) {} + + size_t Size() const { return mBuffer - mStart; } + + PRUint32 NS_ALWAYS_INLINE write( const value_type* start, PRUint32 N ) + { + buffer_type *out = mBuffer; // gcc isn't smart enough to do this! + + for (const value_type *p = start, *end = start + N; p < end; ++p ) + { + value_type c = *p; + if (! (c & 0xFF80)) // U+0000 - U+007F + { + *out++ = (char)c; + } + else if (! (c & 0xF800)) // U+0100 - U+07FF + { + *out++ = 0xC0 | (char)(c >> 6); + *out++ = 0x80 | (char)(0x003F & c); + } + else if (0xD800 != (0xF800 & c)) // U+0800 - U+D7FF,U+E000 - U+FFFF + { + *out++ = 0xE0 | (char)(c >> 12); + *out++ = 0x80 | (char)(0x003F & (c >> 6)); + *out++ = 0x80 | (char)(0x003F & c ); + } + else if (0xD800 == (0xFC00 & c)) // U+D800 - U+DBFF + { + // D800- DBFF - High Surrogate + // N = (H- D800) *400 + 10000 + ... + PRUint32 ucs4 = 0x10000 + ((0x03FF & c) << 10); + + ++p; + if (p == end) + { + NS_ERROR("Surrogate pair split between fragments"); + mBuffer = out; + return N; + } + c = *p; + + if (0xDC00 == (0xFC00 & c)) + { + // DC00- DFFF - Low Surrogate + // N += ( L - DC00 ) + ucs4 |= (0x03FF & c); + + // 0001 0000-001F FFFF + *out++ = 0xF0 | (char)(ucs4 >> 18); + *out++ = 0x80 | (char)(0x003F & (ucs4 >> 12)); + *out++ = 0x80 | (char)(0x003F & (ucs4 >> 6)); + *out++ = 0x80 | (char)(0x003F & ucs4); + } + else + { + NS_ERROR("got a High Surrogate but no low surrogate"); + // output nothing. + } + } + else // U+DC00 - U+DFFF + { + // DC00- DFFF - Low Surrogate + NS_ERROR("got a low Surrogate but no high surrogate"); + // output nothing. + } + } + + mBuffer = out; + return N; + } + + void write_terminator() + { + *mBuffer = buffer_type(0); + } + + private: + buffer_type* const mStart; + buffer_type* mBuffer; + }; + +/** + * A character sink (see |copy_string| in nsAlgorithm.h) for computing + * the number of bytes a UTF-16 would occupy in UTF-8. + */ +class CalculateUTF8Size + { + public: + typedef nsAString::char_type value_type; + + CalculateUTF8Size() + : mSize(0) { } + + size_t Size() const { return mSize; } + + PRUint32 NS_ALWAYS_INLINE write( const value_type* start, PRUint32 N ) + { + // Assume UCS2 surrogate pairs won't be spread across fragments. + for (const value_type *p = start, *end = start + N; p < end; ++p ) + { + value_type c = *p; + if (! (c & 0xFF80)) // U+0000 - U+007F + mSize += 1; + else if (! (c & 0xF800)) // U+0100 - U+07FF + mSize += 2; + else if (0xD800 != (0xF800 & c)) // U+0800 - U+D7FF,U+E000 - U+FFFF + mSize += 3; + else if (0xD800 == (0xFC00 & c)) // U+D800 - U+DBFF + { + ++p; + if (p == end) + { + NS_ERROR("Surrogate pair split between fragments"); + return N; + } + c = *p; + + if (0xDC00 == (0xFC00 & c)) + mSize += 4; + else + NS_ERROR("got a high Surrogate but no low surrogate"); + } + else // U+DC00 - U+DFFF + NS_ERROR("got a low Surrogate but no high surrogate"); + } + + return N; + } + + private: + size_t mSize; + }; + +/** + * A character sink that performs a |reinterpret_cast| style conversion + * between character types. + */ +template +class LossyConvertEncoding + { + public: + typedef FromCharT value_type; + + typedef FromCharT input_type; + typedef ToCharT output_type; + + typedef typename nsCharTraits::unsigned_char_type unsigned_input_type; + + public: + LossyConvertEncoding( output_type* aDestination ) : mDestination(aDestination) { } + + PRUint32 + write( const input_type* aSource, PRUint32 aSourceLength ) + { + const input_type* done_writing = aSource + aSourceLength; + while ( aSource < done_writing ) + *mDestination++ = (output_type)(unsigned_input_type)(*aSource++); // use old-style cast to mimic old |ns[C]String| behavior + return aSourceLength; + } + + void + write_terminator() + { + *mDestination = output_type(0); + } + + private: + output_type* mDestination; + }; + +#endif /* !defined(nsUTF8Utils_h_) */ diff --git a/src/libs/xpcom18a4/xpcom/string/public/nsXPIDLString.h b/src/libs/xpcom18a4/xpcom/string/public/nsXPIDLString.h new file mode 100644 index 00000000..c66a2d7a --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/public/nsXPIDLString.h @@ -0,0 +1,46 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* ***** 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 IBM Corporation. + * Portions created by IBM Corporation are Copyright (C) 2003 + * IBM Corporation. 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 ***** */ + +#ifndef nsXPIDLString_h___ +#define nsXPIDLString_h___ + +#ifndef nsString_h___ +#include "nsString.h" +#endif + +#endif /* !defined(nsXPIDLString_h___) */ diff --git a/src/libs/xpcom18a4/xpcom/string/public/string-template-def-char.h b/src/libs/xpcom18a4/xpcom/string/public/string-template-def-char.h new file mode 100644 index 00000000..d0f3a907 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/public/string-template-def-char.h @@ -0,0 +1,58 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* ***** 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 IBM Corporation. + * Portions created by IBM Corporation are Copyright (C) 2003 + * IBM Corporation. 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 ***** */ + +#define CharT char +#define CharT_is_char 1 +#define nsTObsoleteAString_CharT nsObsoleteACString +#define nsTObsoleteAStringThunk_CharT nsObsoleteACStringThunk +#define nsTAString_CharT nsACString +#define nsTAString_IncompatibleCharT nsAString +#define nsTString_CharT nsCString +#define nsTFixedString_CharT nsFixedCString +#define nsTAutoString_CharT nsCAutoString +#define nsTSubstring_CharT nsCSubstring +#define nsTSubstringTuple_CharT nsCSubstringTuple +#define nsTStringComparator_CharT nsCStringComparator +#define nsTDefaultStringComparator_CharT nsDefaultCStringComparator +#define nsTDependentString_CharT nsDependentCString +#define nsTDependentSubstring_CharT nsDependentCSubstring +#define nsTXPIDLString_CharT nsXPIDLCString +#define nsTGetterCopies_CharT nsCGetterCopies +#define nsTAdoptingString_CharT nsAdoptingCString +#define nsTPromiseFlatString_CharT nsPromiseFlatCString +#define TPromiseFlatString_CharT PromiseFlatCString diff --git a/src/libs/xpcom18a4/xpcom/string/public/string-template-def-unichar.h b/src/libs/xpcom18a4/xpcom/string/public/string-template-def-unichar.h new file mode 100644 index 00000000..c966dfbe --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/public/string-template-def-unichar.h @@ -0,0 +1,58 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* ***** 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 IBM Corporation. + * Portions created by IBM Corporation are Copyright (C) 2003 + * IBM Corporation. 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 ***** */ + +#define CharT PRUnichar +#define CharT_is_PRUnichar 1 +#define nsTObsoleteAString_CharT nsObsoleteAString +#define nsTObsoleteAStringThunk_CharT nsObsoleteAStringThunk +#define nsTAString_CharT nsAString +#define nsTAString_IncompatibleCharT nsACString +#define nsTString_CharT nsString +#define nsTFixedString_CharT nsFixedString +#define nsTAutoString_CharT nsAutoString +#define nsTSubstring_CharT nsSubstring +#define nsTSubstringTuple_CharT nsSubstringTuple +#define nsTStringComparator_CharT nsStringComparator +#define nsTDefaultStringComparator_CharT nsDefaultStringComparator +#define nsTDependentString_CharT nsDependentString +#define nsTDependentSubstring_CharT nsDependentSubstring +#define nsTXPIDLString_CharT nsXPIDLString +#define nsTGetterCopies_CharT nsGetterCopies +#define nsTAdoptingString_CharT nsAdoptingString +#define nsTPromiseFlatString_CharT nsPromiseFlatString +#define TPromiseFlatString_CharT PromiseFlatString diff --git a/src/libs/xpcom18a4/xpcom/string/public/string-template-undef.h b/src/libs/xpcom18a4/xpcom/string/public/string-template-undef.h new file mode 100644 index 00000000..45344370 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/public/string-template-undef.h @@ -0,0 +1,59 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* ***** 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 IBM Corporation. + * Portions created by IBM Corporation are Copyright (C) 2003 + * IBM Corporation. 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 ***** */ + +#undef CharT +#undef CharT_is_PRUnichar +#undef CharT_is_char +#undef nsTObsoleteAString_CharT +#undef nsTObsoleteAStringThunk_CharT +#undef nsTAString_CharT +#undef nsTAString_IncompatibleCharT +#undef nsTString_CharT +#undef nsTFixedString_CharT +#undef nsTAutoString_CharT +#undef nsTSubstring_CharT +#undef nsTSubstringTuple_CharT +#undef nsTStringComparator_CharT +#undef nsTDefaultStringComparator_CharT +#undef nsTDependentString_CharT +#undef nsTDependentSubstring_CharT +#undef nsTXPIDLString_CharT +#undef nsTGetterCopies_CharT +#undef nsTAdoptingString_CharT +#undef nsTPromiseFlatString_CharT +#undef TPromiseFlatString_CharT diff --git a/src/libs/xpcom18a4/xpcom/string/src/.cvsignore b/src/libs/xpcom18a4/xpcom/string/src/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/src/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/xpcom/string/src/Makefile.in b/src/libs/xpcom18a4/xpcom/string/src/Makefile.in new file mode 100644 index 00000000..81033c6c --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/src/Makefile.in @@ -0,0 +1,77 @@ +# vim:set ts=8 sw=8 sts=8 noet: +# +# ***** 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. +# Portions created by the Initial Developer are Copyright (C) 2001 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Johnny Stenback (original author) +# Scott Collins +# +# Alternatively, the contents of this file may be used under the terms of +# either of 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 ***** + +DEPTH = ../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = string +LIBRARY_NAME = string_s + +REQUIRES = xpcom \ + $(NULL) + +CPPSRCS = \ + nsAString.cpp \ + nsDependentSubstring.cpp \ + nsObsoleteAStringThunk.cpp \ + nsPrintfCString.cpp \ + nsPromiseFlatString.cpp \ + nsReadableUtils.cpp \ + nsSubstring.cpp \ + nsSubstringTuple.cpp \ + nsString.cpp \ + nsStringComparator.cpp \ + nsStringObsolete.cpp \ + $(NULL) + +# we don't want the shared lib, but we want to force the creation of a +# static lib. +FORCE_STATIC_LIB = 1 + +# Force use of PIC +FORCE_USE_PIC = 1 + +include $(topsrcdir)/config/rules.mk + +DEFINES += -D_IMPL_NS_COM diff --git a/src/libs/xpcom18a4/xpcom/string/src/nsAString.cpp b/src/libs/xpcom18a4/xpcom/string/src/nsAString.cpp new file mode 100644 index 00000000..5b481662 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/src/nsAString.cpp @@ -0,0 +1,51 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* ***** 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 IBM Corporation. + * Portions created by IBM Corporation are Copyright (C) 2003 + * IBM Corporation. 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 "nsAString.h" +#include "nsObsoleteAString.h" +#include "nsString.h" + + // define nsAString +#include "string-template-def-unichar.h" +#include "nsTAString.cpp" +#include "string-template-undef.h" + + // define nsACString +#include "string-template-def-char.h" +#include "nsTAString.cpp" +#include "string-template-undef.h" diff --git a/src/libs/xpcom18a4/xpcom/string/src/nsDependentSubstring.cpp b/src/libs/xpcom18a4/xpcom/string/src/nsDependentSubstring.cpp new file mode 100644 index 00000000..971defc8 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/src/nsDependentSubstring.cpp @@ -0,0 +1,50 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* ***** 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 IBM Corporation. + * Portions created by IBM Corporation are Copyright (C) 2003 + * IBM Corporation. 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 "nsDependentSubstring.h" +#include "nsAlgorithm.h" + + // define nsDependentSubstring +#include "string-template-def-unichar.h" +#include "nsTDependentSubstring.cpp" +#include "string-template-undef.h" + + // define nsDependentCSubstring +#include "string-template-def-char.h" +#include "nsTDependentSubstring.cpp" +#include "string-template-undef.h" diff --git a/src/libs/xpcom18a4/xpcom/string/src/nsObsoleteAStringThunk.cpp b/src/libs/xpcom18a4/xpcom/string/src/nsObsoleteAStringThunk.cpp new file mode 100644 index 00000000..8b511d1e --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/src/nsObsoleteAStringThunk.cpp @@ -0,0 +1,52 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* ***** 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 IBM Corporation. + * Portions created by IBM Corporation are Copyright (C) 2003 + * IBM Corporation. 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 "nsObsoleteAString.h" +#include "nsString.h" + + + // define nsObsoleteAStringThunk +#include "string-template-def-unichar.h" +#include "nsTObsoleteAStringThunk.cpp" +#include "string-template-undef.h" + + + // define nsObsoleteACStringThunk +#include "string-template-def-char.h" +#include "nsTObsoleteAStringThunk.cpp" +#include "string-template-undef.h" diff --git a/src/libs/xpcom18a4/xpcom/string/src/nsPrintfCString.cpp b/src/libs/xpcom18a4/xpcom/string/src/nsPrintfCString.cpp new file mode 100644 index 00000000..8bb06da6 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/src/nsPrintfCString.cpp @@ -0,0 +1,83 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1994-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsPrintfCString.h" +#include +#include "prprf.h" + + +// though these classes define a fixed buffer, they do not set the F_FIXED +// flag. this is because they are not intended to be modified after they have +// been constructed. we could change this but it would require adding a new +// class to the hierarchy, one that both this class and nsCAutoString would +// inherit from. for now, we populate the fixed buffer, and then let the +// nsCString code treat the buffer as if it were a dependent buffer. + +nsPrintfCString::nsPrintfCString( const char_type* format, ... ) + : string_type(mLocalBuffer, 0, F_TERMINATED) + { + va_list ap; + + size_type logical_capacity = kLocalBufferSize; + size_type physical_capacity = logical_capacity + 1; + + va_start(ap, format); + mLength = PR_vsnprintf(mData, physical_capacity, format, ap); + va_end(ap); + } + +nsPrintfCString::nsPrintfCString( size_type n, const char_type* format, ... ) + : string_type(mLocalBuffer, 0, F_TERMINATED) + { + va_list ap; + + // make sure there's at least |n| space + size_type logical_capacity = kLocalBufferSize; + if ( n > logical_capacity ) + { + SetCapacity(n); + if (Capacity() < n) + return; // out of memory !! + logical_capacity = n; + } + size_type physical_capacity = logical_capacity + 1; + + va_start(ap, format); + mLength = PR_vsnprintf(mData, physical_capacity, format, ap); + va_end(ap); + } diff --git a/src/libs/xpcom18a4/xpcom/string/src/nsPromiseFlatString.cpp b/src/libs/xpcom18a4/xpcom/string/src/nsPromiseFlatString.cpp new file mode 100644 index 00000000..aab4f209 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/src/nsPromiseFlatString.cpp @@ -0,0 +1,49 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* ***** 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 IBM Corporation. + * Portions created by IBM Corporation are Copyright (C) 2003 + * IBM Corporation. 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 "nsPromiseFlatString.h" + + // define nsPromiseFlatString +#include "string-template-def-unichar.h" +#include "nsTPromiseFlatString.cpp" +#include "string-template-undef.h" + + // define nsPromiseFlatCString +#include "string-template-def-char.h" +#include "nsTPromiseFlatString.cpp" +#include "string-template-undef.h" diff --git a/src/libs/xpcom18a4/xpcom/string/src/nsReadableUtils.cpp b/src/libs/xpcom18a4/xpcom/string/src/nsReadableUtils.cpp new file mode 100644 index 00000000..24305b6a --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/src/nsReadableUtils.cpp @@ -0,0 +1,1122 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Scott Collins (original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsReadableUtils.h" +#include "nsMemory.h" +#include "nsString.h" +#include "nsUTF8Utils.h" + +NS_COM +void +LossyCopyUTF16toASCII( const nsAString& aSource, nsACString& aDest ) + { + aDest.Truncate(); + LossyAppendUTF16toASCII(aSource, aDest); + } + +NS_COM +void +CopyASCIItoUTF16( const nsACString& aSource, nsAString& aDest ) + { + aDest.Truncate(); + AppendASCIItoUTF16(aSource, aDest); + } + +NS_COM +void +LossyCopyUTF16toASCII( const PRUnichar* aSource, nsACString& aDest ) + { + aDest.Truncate(); + if (aSource) { + LossyAppendUTF16toASCII(nsDependentString(aSource), aDest); + } + } + +NS_COM +void +CopyASCIItoUTF16( const char* aSource, nsAString& aDest ) + { + aDest.Truncate(); + if (aSource) { + AppendASCIItoUTF16(nsDependentCString(aSource), aDest); + } + } + +NS_COM +void +CopyUTF16toUTF8( const nsAString& aSource, nsACString& aDest ) + { + aDest.Truncate(); + AppendUTF16toUTF8(aSource, aDest); + } + +NS_COM +void +CopyUTF8toUTF16( const nsACString& aSource, nsAString& aDest ) + { + aDest.Truncate(); + AppendUTF8toUTF16(aSource, aDest); + } + +NS_COM +void +CopyUTF16toUTF8( const PRUnichar* aSource, nsACString& aDest ) + { + aDest.Truncate(); + AppendUTF16toUTF8(aSource, aDest); + } + +NS_COM +void +CopyUTF8toUTF16( const char* aSource, nsAString& aDest ) + { + aDest.Truncate(); + AppendUTF8toUTF16(aSource, aDest); + } + +NS_COM +void +LossyAppendUTF16toASCII( const nsAString& aSource, nsACString& aDest ) + { + PRUint32 old_dest_length = aDest.Length(); + aDest.SetLength(old_dest_length + aSource.Length()); + + nsAString::const_iterator fromBegin, fromEnd; + + nsACString::iterator dest; + aDest.BeginWriting(dest); + + dest.advance(old_dest_length); + + // right now, this won't work on multi-fragment destinations + LossyConvertEncoding converter(dest.get()); + + copy_string(aSource.BeginReading(fromBegin), aSource.EndReading(fromEnd), converter); + } + +NS_COM +void +AppendASCIItoUTF16( const nsACString& aSource, nsAString& aDest ) + { + PRUint32 old_dest_length = aDest.Length(); + aDest.SetLength(old_dest_length + aSource.Length()); + + nsACString::const_iterator fromBegin, fromEnd; + + nsAString::iterator dest; + aDest.BeginWriting(dest); + + dest.advance(old_dest_length); + + // right now, this won't work on multi-fragment destinations + LossyConvertEncoding converter(dest.get()); + + copy_string(aSource.BeginReading(fromBegin), aSource.EndReading(fromEnd), converter); + } + +NS_COM +void +LossyAppendUTF16toASCII( const PRUnichar* aSource, nsACString& aDest ) + { + if (aSource) { + LossyAppendUTF16toASCII(nsDependentString(aSource), aDest); + } + } + +NS_COM +void +AppendASCIItoUTF16( const char* aSource, nsAString& aDest ) + { + if (aSource) { + AppendASCIItoUTF16(nsDependentCString(aSource), aDest); + } + } + +NS_COM +void +AppendUTF16toUTF8( const nsAString& aSource, nsACString& aDest ) + { + nsAString::const_iterator source_start, source_end; + CalculateUTF8Size calculator; + copy_string(aSource.BeginReading(source_start), + aSource.EndReading(source_end), calculator); + + PRUint32 count = calculator.Size(); + + if (count) + { + PRUint32 old_dest_length = aDest.Length(); + + // Grow the buffer if we need to. + aDest.SetLength(old_dest_length + count); + + nsACString::iterator dest; + aDest.BeginWriting(dest); + + dest.advance(old_dest_length); + + if (count <= (PRUint32)dest.size_forward()) + { + // aDest has enough room in the fragment just past the end + // of its old data that it can hold what we're about to + // append. Append using copy_string(). + + // All ready? Time to convert + + ConvertUTF16toUTF8 converter(dest.get()); + copy_string(aSource.BeginReading(source_start), + aSource.EndReading(source_end), converter); + + if (converter.Size() != count) + { + NS_ERROR("Input invalid or incorrect length was calculated"); + + aDest.SetLength(old_dest_length); + } + } + else + { + // This isn't the fastest way to do this, but it gets + // complicated to convert UTF16 into a fragmented UTF8 + // string, so we'll take the easy way out here in this + // rare situation. + + aDest.Replace(old_dest_length, count, + NS_ConvertUTF16toUTF8(aSource)); + } + } + } + +NS_COM +void +AppendUTF8toUTF16( const nsACString& aSource, nsAString& aDest ) + { + nsACString::const_iterator source_start, source_end; + CalculateUTF8Length calculator; + copy_string(aSource.BeginReading(source_start), + aSource.EndReading(source_end), calculator); + + PRUint32 count = calculator.Length(); + + if (count) + { + PRUint32 old_dest_length = aDest.Length(); + + // Grow the buffer if we need to. + aDest.SetLength(old_dest_length + count); + + nsAString::iterator dest; + aDest.BeginWriting(dest); + + dest.advance(old_dest_length); + + if (count <= (PRUint32)dest.size_forward()) + { + // aDest has enough room in the fragment just past the end + // of its old data that it can hold what we're about to + // append. Append using copy_string(). + + // All ready? Time to convert + + ConvertUTF8toUTF16 converter(dest.get()); + copy_string(aSource.BeginReading(source_start), + aSource.EndReading(source_end), converter); + + if (converter.Length() != count) + { + NS_ERROR("Input wasn't UTF8 or incorrect length was calculated"); + aDest.SetLength(old_dest_length); + } + } + else + { + // This isn't the fastest way to do this, but it gets + // complicated to convert parts of a UTF8 string into a + // UTF16 string, so we'll take the easy way out here in + // this rare situation. + + aDest.Replace(old_dest_length, count, + NS_ConvertUTF8toUTF16(aSource)); + } + } + } + +NS_COM +void +AppendUTF16toUTF8( const PRUnichar* aSource, nsACString& aDest ) + { + if (aSource) { + AppendUTF16toUTF8(nsDependentString(aSource), aDest); + } + } + +NS_COM +void +AppendUTF8toUTF16( const char* aSource, nsAString& aDest ) + { + if (aSource) { + AppendUTF8toUTF16(nsDependentCString(aSource), aDest); + } + } + + + /** + * A helper function that allocates a buffer of the desired character type big enough to hold a copy of the supplied string (plus a zero terminator). + * + * @param aSource an string you will eventually be making a copy of + * @return a new buffer (of the type specified by the second parameter) which you must free with |nsMemory::Free|. + * + */ +template +inline +ToCharT* +AllocateStringCopy( const FromStringT& aSource, ToCharT* ) + { + return NS_STATIC_CAST(ToCharT*, nsMemory::Alloc((aSource.Length()+1) * sizeof(ToCharT))); + } + + +NS_COM +char* +ToNewCString( const nsAString& aSource ) + { + char* result = AllocateStringCopy(aSource, (char*)0); + + nsAString::const_iterator fromBegin, fromEnd; + LossyConvertEncoding converter(result); + copy_string(aSource.BeginReading(fromBegin), aSource.EndReading(fromEnd), converter).write_terminator(); + return result; + } + +NS_COM +char* +ToNewUTF8String( const nsAString& aSource, PRUint32 *aUTF8Count ) + { + nsAString::const_iterator start, end; + CalculateUTF8Size calculator; + copy_string(aSource.BeginReading(start), aSource.EndReading(end), + calculator); + + if (aUTF8Count) + *aUTF8Count = calculator.Size(); + + char *result = NS_STATIC_CAST(char*, + nsMemory::Alloc(calculator.Size() + 1)); + + ConvertUTF16toUTF8 converter(result); + copy_string(aSource.BeginReading(start), aSource.EndReading(end), + converter).write_terminator(); + NS_ASSERTION(calculator.Size() == converter.Size(), "length mismatch"); + + return result; + } + +NS_COM +char* +ToNewCString( const nsACString& aSource ) + { + // no conversion needed, just allocate a buffer of the correct length and copy into it + + char* result = AllocateStringCopy(aSource, (char*)0); + + nsACString::const_iterator fromBegin, fromEnd; + char* toBegin = result; + *copy_string(aSource.BeginReading(fromBegin), aSource.EndReading(fromEnd), toBegin) = char(0); + return result; + } + +NS_COM +PRUnichar* +ToNewUnicode( const nsAString& aSource ) + { + // no conversion needed, just allocate a buffer of the correct length and copy into it + + PRUnichar* result = AllocateStringCopy(aSource, (PRUnichar*)0); + + nsAString::const_iterator fromBegin, fromEnd; + PRUnichar* toBegin = result; + *copy_string(aSource.BeginReading(fromBegin), aSource.EndReading(fromEnd), toBegin) = PRUnichar(0); + return result; + } + +NS_COM +PRUnichar* +ToNewUnicode( const nsACString& aSource ) + { + PRUnichar* result = AllocateStringCopy(aSource, (PRUnichar*)0); + + nsACString::const_iterator fromBegin, fromEnd; + LossyConvertEncoding converter(result); + copy_string(aSource.BeginReading(fromBegin), aSource.EndReading(fromEnd), converter).write_terminator(); + return result; + } + +NS_COM +PRUnichar* +UTF8ToNewUnicode( const nsACString& aSource, PRUint32 *aUTF16Count ) + { + nsACString::const_iterator start, end; + CalculateUTF8Length calculator; + copy_string(aSource.BeginReading(start), aSource.EndReading(end), + calculator); + + if (aUTF16Count) + *aUTF16Count = calculator.Length(); + + PRUnichar *result = NS_STATIC_CAST(PRUnichar*, + nsMemory::Alloc(sizeof(PRUnichar) * (calculator.Length() + 1))); + + ConvertUTF8toUTF16 converter(result); + copy_string(aSource.BeginReading(start), aSource.EndReading(end), + converter).write_terminator(); + NS_ASSERTION(calculator.Length() == converter.Length(), "length mismatch"); + + return result; + } + +NS_COM +PRUnichar* +CopyUnicodeTo( const nsAString& aSource, PRUint32 aSrcOffset, PRUnichar* aDest, PRUint32 aLength ) + { + nsAString::const_iterator fromBegin, fromEnd; + PRUnichar* toBegin = aDest; + copy_string(aSource.BeginReading(fromBegin).advance( PRInt32(aSrcOffset) ), aSource.BeginReading(fromEnd).advance( PRInt32(aSrcOffset+aLength) ), toBegin); + return aDest; + } + +NS_COM +void +CopyUnicodeTo( const nsAString::const_iterator& aSrcStart, + const nsAString::const_iterator& aSrcEnd, + nsAString& aDest ) + { + nsAString::iterator writer; + aDest.SetLength(Distance(aSrcStart, aSrcEnd)); + aDest.BeginWriting(writer); + nsAString::const_iterator fromBegin(aSrcStart); + + copy_string(fromBegin, aSrcEnd, writer); + } + +NS_COM +void +AppendUnicodeTo( const nsAString::const_iterator& aSrcStart, + const nsAString::const_iterator& aSrcEnd, + nsAString& aDest ) + { + nsAString::iterator writer; + PRUint32 oldLength = aDest.Length(); + aDest.SetLength(oldLength + Distance(aSrcStart, aSrcEnd)); + aDest.BeginWriting(writer).advance(oldLength); + nsAString::const_iterator fromBegin(aSrcStart); + + copy_string(fromBegin, aSrcEnd, writer); + } + +NS_COM +PRBool +IsASCII( const nsAString& aString ) + { + static const PRUnichar NOT_ASCII = PRUnichar(~0x007F); + + + // Don't want to use |copy_string| for this task, since we can stop at the first non-ASCII character + + nsAString::const_iterator done_reading; + aString.EndReading(done_reading); + + // for each chunk of |aString|... + PRUint32 fragmentLength = 0; + nsAString::const_iterator iter; + for ( aString.BeginReading(iter); iter != done_reading; iter.advance( PRInt32(fragmentLength) ) ) + { + fragmentLength = PRUint32(iter.size_forward()); + const PRUnichar* c = iter.get(); + const PRUnichar* fragmentEnd = c + fragmentLength; + + // for each character in this chunk... + while ( c < fragmentEnd ) + if ( *c++ & NOT_ASCII ) + return PR_FALSE; + } + + return PR_TRUE; + } + +NS_COM +PRBool +IsASCII( const nsACString& aString ) + { + static const char NOT_ASCII = char(~0x7F); + + + // Don't want to use |copy_string| for this task, since we can stop at the first non-ASCII character + + nsACString::const_iterator done_reading; + aString.EndReading(done_reading); + + // for each chunk of |aString|... + PRUint32 fragmentLength = 0; + nsACString::const_iterator iter; + for ( aString.BeginReading(iter); iter != done_reading; iter.advance( PRInt32(fragmentLength) ) ) + { + fragmentLength = PRUint32(iter.size_forward()); + const char* c = iter.get(); + const char* fragmentEnd = c + fragmentLength; + + // for each character in this chunk... + while ( c < fragmentEnd ) + if ( *c++ & NOT_ASCII ) + return PR_FALSE; + } + + return PR_TRUE; + } + +NS_COM +PRBool +IsUTF8( const nsACString& aString ) + { + nsReadingIterator done_reading; + aString.EndReading(done_reading); + + PRInt32 state = 0; + PRBool overlong = PR_FALSE; + PRBool surrogate = PR_FALSE; + PRBool nonchar = PR_FALSE; + PRUint16 olupper = 0; // overlong byte upper bound. + PRUint16 slower = 0; // surrogate byte lower bound. + + // for each chunk of |aString|... + PRUint32 fragmentLength = 0; + nsReadingIterator iter; + + for ( aString.BeginReading(iter); iter != done_reading; iter.advance( PRInt32(fragmentLength) ) ) + { + fragmentLength = PRUint32(iter.size_forward()); + const char* ptr = iter.get(); + const char* fragmentEnd = ptr + fragmentLength; + + // for each character in this chunk... + while ( ptr < fragmentEnd ) + { + PRUint8 c; + + if (0 == state) + { + c = *ptr++; + + if ( UTF8traits::isASCII(c) ) + continue; + + if ( c <= 0xC1 ) // [80-BF] where not expected, [C0-C1] for overlong. + return PR_FALSE; + else if ( UTF8traits::is2byte(c) ) + state = 1; + else if ( UTF8traits::is3byte(c) ) + { + state = 2; + if ( c == 0xE0 ) // to exclude E0[80-9F][80-BF] + { + overlong = PR_TRUE; + olupper = 0x9F; + } + else if ( c == 0xED ) // ED[A0-BF][80-BF] : surrogate codepoint + { + surrogate = PR_TRUE; + slower = 0xA0; + } + else if ( c == 0xEF ) // EF BF [BE-BF] : non-character + nonchar = PR_TRUE; + } + else if ( c <= 0xF4 ) // XXX replace /w UTF8traits::is4byte when it's updated to exclude [F5-F7].(bug 199090) + { + state = 3; + nonchar = PR_TRUE; + if ( c == 0xF0 ) // to exclude F0[80-8F][80-BF]{2} + { + overlong = PR_TRUE; + olupper = 0x8F; + } + else if ( c == 0xF4 ) // to exclude F4[90-BF][80-BF] + { + // actually not surrogates but codepoints beyond 0x10FFFF + surrogate = PR_TRUE; + slower = 0x90; + } + } + else + return PR_FALSE; // Not UTF-8 string + } + + while (ptr < fragmentEnd && state) + { + c = *ptr++; + --state; + + // non-character : EF BF [BE-BF] or F[0-7] [89AB]F BF [BE-BF] + if ( nonchar && ( (!state && c < 0xBE) || + (state == 1 && c != 0xBF) || + (state == 2 && 0x0F != (0x0F & c)) )) + nonchar = PR_FALSE; + + if ( !UTF8traits::isInSeq(c) || (overlong && c <= olupper) || + (surrogate && slower <= c) || (nonchar && !state) ) + return PR_FALSE; // Not UTF-8 string + overlong = surrogate = PR_FALSE; + } + } + } + return !state; // state != 0 at the end indicates an invalid UTF-8 seq. + } + + /** + * A character sink for in-place case conversion. + */ +class ConvertToUpperCase + { + public: + typedef char value_type; + + PRUint32 + write( const char* aSource, PRUint32 aSourceLength ) + { + char* cp = NS_CONST_CAST(char*,aSource); + const char* end = aSource + aSourceLength; + while (cp != end) { + char ch = *cp; + if ((ch >= 'a') && (ch <= 'z')) + *cp = ch - ('a' - 'A'); + ++cp; + } + return aSourceLength; + } + }; + +NS_COM +void +ToUpperCase( nsACString& aCString ) + { + nsACString::iterator fromBegin, fromEnd; + ConvertToUpperCase converter; + copy_string(aCString.BeginWriting(fromBegin), aCString.EndWriting(fromEnd), converter); + } + +NS_COM +void +ToUpperCase( nsCSubstring& aCString ) + { + ConvertToUpperCase converter; + char* start; + converter.write(aCString.BeginWriting(start), aCString.Length()); + } + + /** + * A character sink for copying with case conversion. + */ +class CopyToUpperCase + { + public: + typedef char value_type; + + CopyToUpperCase( nsACString::iterator& aDestIter ) + : mIter(aDestIter) + { + } + + PRUint32 + write( const char* aSource, PRUint32 aSourceLength ) + { + PRUint32 len = PR_MIN(PRUint32(mIter.size_forward()), aSourceLength); + char* cp = mIter.get(); + const char* end = aSource + len; + while (aSource != end) { + char ch = *aSource; + if ((ch >= 'a') && (ch <= 'z')) + *cp = ch - ('a' - 'A'); + else + *cp = ch; + ++aSource; + ++cp; + } + mIter.advance(len); + return len; + } + + protected: + nsACString::iterator& mIter; + }; + +NS_COM +void +ToUpperCase( const nsACString& aSource, nsACString& aDest ) + { + nsACString::const_iterator fromBegin, fromEnd; + nsACString::iterator toBegin; + aDest.SetLength(aSource.Length()); + CopyToUpperCase converter(aDest.BeginWriting(toBegin)); + copy_string(aSource.BeginReading(fromBegin), aSource.EndReading(fromEnd), converter); + } + + /** + * A character sink for case conversion. + */ +class ConvertToLowerCase + { + public: + typedef char value_type; + + PRUint32 + write( const char* aSource, PRUint32 aSourceLength ) + { + char* cp = NS_CONST_CAST(char*,aSource); + const char* end = aSource + aSourceLength; + while (cp != end) { + char ch = *cp; + if ((ch >= 'A') && (ch <= 'Z')) + *cp = ch + ('a' - 'A'); + ++cp; + } + return aSourceLength; + } + }; + +NS_COM +void +ToLowerCase( nsACString& aCString ) + { + nsACString::iterator fromBegin, fromEnd; + ConvertToLowerCase converter; + copy_string(aCString.BeginWriting(fromBegin), aCString.EndWriting(fromEnd), converter); + } + +NS_COM +void +ToLowerCase( nsCSubstring& aCString ) + { + ConvertToLowerCase converter; + char* start; + converter.write(aCString.BeginWriting(start), aCString.Length()); + } + + /** + * A character sink for copying with case conversion. + */ +class CopyToLowerCase + { + public: + typedef char value_type; + + CopyToLowerCase( nsACString::iterator& aDestIter ) + : mIter(aDestIter) + { + } + + PRUint32 + write( const char* aSource, PRUint32 aSourceLength ) + { + PRUint32 len = PR_MIN(PRUint32(mIter.size_forward()), aSourceLength); + char* cp = mIter.get(); + const char* end = aSource + len; + while (aSource != end) { + char ch = *aSource; + if ((ch >= 'A') && (ch <= 'Z')) + *cp = ch + ('a' - 'A'); + else + *cp = ch; + ++aSource; + ++cp; + } + mIter.advance(len); + return len; + } + + protected: + nsACString::iterator& mIter; + }; + +NS_COM +void +ToLowerCase( const nsACString& aSource, nsACString& aDest ) + { + nsACString::const_iterator fromBegin, fromEnd; + nsACString::iterator toBegin; + aDest.SetLength(aSource.Length()); + CopyToLowerCase converter(aDest.BeginWriting(toBegin)); + copy_string(aSource.BeginReading(fromBegin), aSource.EndReading(fromEnd), converter); + } + +template +PRBool +FindInReadable_Impl( const StringT& aPattern, IteratorT& aSearchStart, IteratorT& aSearchEnd, const Comparator& compare ) + { + PRBool found_it = PR_FALSE; + + // only bother searching at all if we're given a non-empty range to search + if ( aSearchStart != aSearchEnd ) + { + IteratorT aPatternStart, aPatternEnd; + aPattern.BeginReading(aPatternStart); + aPattern.EndReading(aPatternEnd); + + // outer loop keeps searching till we find it or run out of string to search + while ( !found_it ) + { + // fast inner loop (that's what it's called, not what it is) looks for a potential match + while ( aSearchStart != aSearchEnd && + compare(*aPatternStart, *aSearchStart) ) + ++aSearchStart; + + // if we broke out of the `fast' loop because we're out of string ... we're done: no match + if ( aSearchStart == aSearchEnd ) + break; + + // otherwise, we're at a potential match, let's see if we really hit one + IteratorT testPattern(aPatternStart); + IteratorT testSearch(aSearchStart); + + // slow inner loop verifies the potential match (found by the `fast' loop) at the current position + for(;;) + { + // we already compared the first character in the outer loop, + // so we'll advance before the next comparison + ++testPattern; + ++testSearch; + + // if we verified all the way to the end of the pattern, then we found it! + if ( testPattern == aPatternEnd ) + { + found_it = PR_TRUE; + aSearchEnd = testSearch; // return the exact found range through the parameters + break; + } + + // if we got to end of the string we're searching before we hit the end of the + // pattern, we'll never find what we're looking for + if ( testSearch == aSearchEnd ) + { + aSearchStart = aSearchEnd; + break; + } + + // else if we mismatched ... it's time to advance to the next search position + // and get back into the `fast' loop + if ( compare(*testPattern, *testSearch) ) + { + ++aSearchStart; + break; + } + } + } + } + + return found_it; + } + + +NS_COM +PRBool +FindInReadable( const nsAString& aPattern, nsAString::const_iterator& aSearchStart, nsAString::const_iterator& aSearchEnd, const nsStringComparator& aComparator ) + { + return FindInReadable_Impl(aPattern, aSearchStart, aSearchEnd, aComparator); + } + +NS_COM +PRBool +FindInReadable( const nsACString& aPattern, nsACString::const_iterator& aSearchStart, nsACString::const_iterator& aSearchEnd, const nsCStringComparator& aComparator) + { + return FindInReadable_Impl(aPattern, aSearchStart, aSearchEnd, aComparator); + } + +NS_COM +PRBool +CaseInsensitiveFindInReadable( const nsACString& aPattern, nsACString::const_iterator& aSearchStart, nsACString::const_iterator& aSearchEnd ) + { + return FindInReadable_Impl(aPattern, aSearchStart, aSearchEnd, nsCaseInsensitiveCStringComparator()); + } + + /** + * This implementation is simple, but does too much work. + * It searches the entire string from left to right, and returns the last match found, if any. + * This implementation will be replaced when I get |reverse_iterator|s working. + */ +NS_COM +PRBool +RFindInReadable( const nsAString& aPattern, nsAString::const_iterator& aSearchStart, nsAString::const_iterator& aSearchEnd, const nsStringComparator& aComparator) + { + PRBool found_it = PR_FALSE; + + nsAString::const_iterator savedSearchEnd(aSearchEnd); + nsAString::const_iterator searchStart(aSearchStart), searchEnd(aSearchEnd); + + while ( searchStart != searchEnd ) + { + if ( FindInReadable(aPattern, searchStart, searchEnd, aComparator) ) + { + found_it = PR_TRUE; + + // this is the best match so far, so remember it + aSearchStart = searchStart; + aSearchEnd = searchEnd; + + // ...and get ready to search some more + // (it's tempting to set |searchStart=searchEnd| ... but that misses overlapping patterns) + ++searchStart; + searchEnd = savedSearchEnd; + } + } + + // if we never found it, return an empty range + if ( !found_it ) + aSearchStart = aSearchEnd; + + return found_it; + } + +NS_COM +PRBool +RFindInReadable( const nsACString& aPattern, nsACString::const_iterator& aSearchStart, nsACString::const_iterator& aSearchEnd, const nsCStringComparator& aComparator) + { + PRBool found_it = PR_FALSE; + + nsACString::const_iterator savedSearchEnd(aSearchEnd); + nsACString::const_iterator searchStart(aSearchStart), searchEnd(aSearchEnd); + + while ( searchStart != searchEnd ) + { + if ( FindInReadable(aPattern, searchStart, searchEnd, aComparator) ) + { + found_it = PR_TRUE; + + // this is the best match so far, so remember it + aSearchStart = searchStart; + aSearchEnd = searchEnd; + + // ...and get ready to search some more + // (it's tempting to set |searchStart=searchEnd| ... but that misses overlapping patterns) + ++searchStart; + searchEnd = savedSearchEnd; + } + } + + // if we never found it, return an empty range + if ( !found_it ) + aSearchStart = aSearchEnd; + + return found_it; + } + +NS_COM +PRBool +FindCharInReadable( PRUnichar aChar, nsAString::const_iterator& aSearchStart, const nsAString::const_iterator& aSearchEnd ) + { + PRInt32 fragmentLength = aSearchEnd.get() - aSearchStart.get(); + + const PRUnichar* charFoundAt = nsCharTraits::find(aSearchStart.get(), fragmentLength, aChar); + if ( charFoundAt ) { + aSearchStart.advance( charFoundAt - aSearchStart.get() ); + return PR_TRUE; + } + + aSearchStart.advance(fragmentLength); + return PR_FALSE; + } + +NS_COM +PRBool +FindCharInReadable( char aChar, nsACString::const_iterator& aSearchStart, const nsACString::const_iterator& aSearchEnd ) + { + PRInt32 fragmentLength = aSearchEnd.get() - aSearchStart.get(); + + const char* charFoundAt = nsCharTraits::find(aSearchStart.get(), fragmentLength, aChar); + if ( charFoundAt ) { + aSearchStart.advance( charFoundAt - aSearchStart.get() ); + return PR_TRUE; + } + + aSearchStart.advance(fragmentLength); + return PR_FALSE; + } + +NS_COM +PRUint32 +CountCharInReadable( const nsAString& aStr, + PRUnichar aChar ) +{ + PRUint32 count = 0; + nsAString::const_iterator begin, end; + + aStr.BeginReading(begin); + aStr.EndReading(end); + + while (begin != end) { + if (*begin == aChar) { + ++count; + } + ++begin; + } + + return count; +} + +NS_COM +PRUint32 +CountCharInReadable( const nsACString& aStr, + char aChar ) +{ + PRUint32 count = 0; + nsACString::const_iterator begin, end; + + aStr.BeginReading(begin); + aStr.EndReading(end); + + while (begin != end) { + if (*begin == aChar) { + ++count; + } + ++begin; + } + + return count; +} + +NS_COM PRBool +StringBeginsWith( const nsAString& aSource, const nsAString& aSubstring, + const nsStringComparator& aComparator ) + { + nsAString::size_type src_len = aSource.Length(), + sub_len = aSubstring.Length(); + if (sub_len > src_len) + return PR_FALSE; + return Substring(aSource, 0, sub_len).Equals(aSubstring, aComparator); + } + +NS_COM PRBool +StringBeginsWith( const nsACString& aSource, const nsACString& aSubstring, + const nsCStringComparator& aComparator ) + { + nsACString::size_type src_len = aSource.Length(), + sub_len = aSubstring.Length(); + if (sub_len > src_len) + return PR_FALSE; + return Substring(aSource, 0, sub_len).Equals(aSubstring, aComparator); + } + +NS_COM PRBool +StringEndsWith( const nsAString& aSource, const nsAString& aSubstring, + const nsStringComparator& aComparator ) + { + nsAString::size_type src_len = aSource.Length(), + sub_len = aSubstring.Length(); + if (sub_len > src_len) + return PR_FALSE; + return Substring(aSource, src_len - sub_len, sub_len).Equals(aSubstring, + aComparator); + } + +NS_COM PRBool +StringEndsWith( const nsACString& aSource, const nsACString& aSubstring, + const nsCStringComparator& aComparator ) + { + nsACString::size_type src_len = aSource.Length(), + sub_len = aSubstring.Length(); + if (sub_len > src_len) + return PR_FALSE; + return Substring(aSource, src_len - sub_len, sub_len).Equals(aSubstring, + aComparator); + } + + + +template +class CalculateHashCode + { + public: + typedef CharT char_type; + typedef PRUint32 hashcode_type; + typedef CharT value_type; + + CalculateHashCode() : mHashCode(0) { } + hashcode_type GetHashCode() const { return mHashCode; } + + PRUint32 write( const CharT* chars, PRUint32 N ) + { + for ( const CharT *end = chars + N; chars < end; ++chars) + mHashCode = (mHashCode>>28) ^ (mHashCode<<4) ^ PRUint32(*chars); + return N; + } + + private: + hashcode_type mHashCode; + }; + +NS_COM PRUint32 HashString( const nsAString& aStr ) + { + CalculateHashCode sink; + nsAString::const_iterator begin, end; + aStr.BeginReading(begin); + aStr.EndReading(end); + copy_string(begin, end, sink); + return sink.GetHashCode(); + } + +NS_COM PRUint32 HashString( const nsACString& aStr ) + { + CalculateHashCode sink; + nsACString::const_iterator begin, end; + aStr.BeginReading(begin); + aStr.EndReading(end); + copy_string(begin, end, sink); + return sink.GetHashCode(); + } + +static const PRUnichar empty_buffer[1] = { '\0' }; + +NS_COM const nsAFlatString& EmptyString() + { + static const nsDependentString sEmpty(empty_buffer); + + return sEmpty; + } + +NS_COM const nsAFlatCString& EmptyCString() + { + static const nsDependentCString sEmpty((const char *)empty_buffer); + + return sEmpty; + } diff --git a/src/libs/xpcom18a4/xpcom/string/src/nsString.cpp b/src/libs/xpcom18a4/xpcom/string/src/nsString.cpp new file mode 100644 index 00000000..aedf3295 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/src/nsString.cpp @@ -0,0 +1,49 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* ***** 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 IBM Corporation. + * Portions created by IBM Corporation are Copyright (C) 2003 + * IBM Corporation. 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 "nsString.h" + + // define nsString +#include "string-template-def-unichar.h" +#include "nsTString.cpp" +#include "string-template-undef.h" + + // define nsCString +#include "string-template-def-char.h" +#include "nsTString.cpp" +#include "string-template-undef.h" diff --git a/src/libs/xpcom18a4/xpcom/string/src/nsStringComparator.cpp b/src/libs/xpcom18a4/xpcom/string/src/nsStringComparator.cpp new file mode 100644 index 00000000..ced75c73 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/src/nsStringComparator.cpp @@ -0,0 +1,75 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* ***** 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 IBM Corporation. + * Portions created by IBM Corporation are Copyright (C) 2003 + * IBM Corporation. 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 +#include "nsAString.h" +#include "plstr.h" + + + // define nsStringComparator +#include "string-template-def-unichar.h" +#include "nsTStringComparator.cpp" +#include "string-template-undef.h" + + // define nsCStringComparator +#include "string-template-def-char.h" +#include "nsTStringComparator.cpp" +#include "string-template-undef.h" + + +int +nsCaseInsensitiveCStringComparator::operator()( const char_type* lhs, const char_type* rhs, PRUint32 aLength ) const + { + PRInt32 result=PRInt32(PL_strncasecmp(lhs, rhs, aLength)); + //Egads. PL_strncasecmp is returning *very* negative numbers. + //Some folks expect -1,0,1, so let's temper its enthusiasm. + if (result<0) + result=-1; + return result; + } + +int +nsCaseInsensitiveCStringComparator::operator()( char lhs, char rhs ) const + { + if (lhs == rhs) return 0; + + lhs = tolower(lhs); + rhs = tolower(rhs); + + return lhs - rhs; + } diff --git a/src/libs/xpcom18a4/xpcom/string/src/nsStringObsolete.cpp b/src/libs/xpcom18a4/xpcom/string/src/nsStringObsolete.cpp new file mode 100644 index 00000000..76106a27 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/src/nsStringObsolete.cpp @@ -0,0 +1,1327 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* ***** 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 IBM Corporation. + * Portions created by IBM Corporation are Copyright (C) 2003 + * IBM Corporation. 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 "nsString.h" + + + /** + * nsTString obsolete API support + */ + +#if MOZ_STRING_WITH_OBSOLETE_API + +#include "nsDependentString.h" +#include "nsDependentSubstring.h" +#include "nsReadableUtils.h" +#include "nsCRT.h" +#include "nsUTF8Utils.h" +#include "prdtoa.h" +#include "prprf.h" +#ifdef VBOX_USE_IPRT_IN_XPCOM +# include +#endif + +/* ***** BEGIN RICKG BLOCK ***** + * + * NOTE: This section of code was extracted from rickg's bufferRoutines.h file. + * For the most part it remains unmodified. We want to eliminate (or at + * least clean up) this code at some point. If you find the formatting + * in this section somewhat inconsistent, don't blame me! ;-) + */ + +// XXXdarin what is wrong with STDC's tolower? +inline char +ascii_tolower(char aChar) +{ + if (aChar >= 'A' && aChar <= 'Z') + return aChar + ('a' - 'A'); + return aChar; +} + +//----------------------------------------------------------------------------- +// +// This set of methods is used to search a buffer looking for a char. +// + + +/** + * This methods cans the given buffer for the given char + * + * @update gess 02/17/00 + * @param aDest is the buffer to be searched + * @param aDestLength is the size (in char-units, not bytes) of the buffer + * @param anOffset is the start pos to begin searching + * @param aChar is the target character we're looking for + * @param aCount tells us how many characters to iterate through (which may be different than aLength); -1 means use full length. + * @return index of pos if found, else -1 (kNotFound) + */ +static PRInt32 +FindChar1(const char* aDest,PRUint32 aDestLength,PRInt32 anOffset,const PRUnichar aChar,PRInt32 aCount) { + + if(anOffset < 0) + anOffset=0; + + if(aCount < 0) + aCount = (PRInt32)aDestLength; + + if((aChar < 256) && (0 < aDestLength) && ((PRUint32)anOffset < aDestLength)) { + + //We'll only search if the given aChar is within the normal ascii a range, + //(Since this string is definitely within the ascii range). + + if(0 + */ +static +#ifdef __SUNPRO_CC +inline +#endif /* __SUNPRO_CC */ +PRInt32 +Compare1To1(const char* aStr1,const char* aStr2,PRUint32 aCount,PRBool aIgnoreCase){ + PRInt32 result=0; + if(aIgnoreCase) + result=PRInt32(PL_strncasecmp(aStr1, aStr2, aCount)); + else + result=nsCharTraits::compare(aStr1,aStr2,aCount); + + // alien comparisons may return out-of-bound answers + // instead of the -1, 0, 1 expected by most clients + if ( result < -1 ) + result = -1; + else if ( result > 1 ) + result = 1; + return result; +} + +/** + * This method compares the data in one buffer with another + * @update gess 01/04/99 + * @param aStr1 is the first buffer to be compared + * @param aStr2 is the 2nd buffer to be compared + * @param aCount is the number of chars to compare + * @param aIgnoreCase tells us whether to use a case-sensitive comparison + * @return -1,0,1 depending on <,==,> + */ +static +#ifdef __SUNPRO_CC +inline +#endif /* __SUNPRO_CC */ +PRInt32 +Compare2To2(const PRUnichar* aStr1,const PRUnichar* aStr2,PRUint32 aCount){ + PRInt32 result; + + if ( aStr1 && aStr2 ) + result = nsCharTraits::compare(aStr1, aStr2, aCount); + + // The following cases are rare and survivable caller errors. + // Two null pointers are equal, but any string, even 0 length + // is greater than a null pointer. It might not really matter, + // but we pick something reasonable anyway. + else if ( !aStr1 && !aStr2 ) + result = 0; + else if ( aStr1 ) + result = 1; + else + result = -1; + + // alien comparisons may give answers outside the -1, 0, 1 expected by callers + if ( result < -1 ) + result = -1; + else if ( result > 1 ) + result = 1; + return result; +} + + +/** + * This method compares the data in one buffer with another + * @update gess 01/04/99 + * @param aStr1 is the first buffer to be compared + * @param aStr2 is the 2nd buffer to be compared + * @param aCount is the number of chars to compare + * @param aIgnoreCase tells us whether to use a case-sensitive comparison + * @return -1,0,1 depending on <,==,> + */ +static +#ifdef __SUNPRO_CC +inline +#endif /* __SUNPRO_CC */ +PRInt32 +Compare2To1(const PRUnichar* aStr1,const char* aStr2,PRUint32 aCount,PRBool aIgnoreCase){ + const PRUnichar* s1 = aStr1; + const char *s2 = aStr2; + + if (aStr1 && aStr2) { + if (aCount != 0) { + do { + + PRUnichar c1 = *s1++; + PRUnichar c2 = PRUnichar((unsigned char)*s2++); + + if (c1 != c2) { +#ifdef NS_DEBUG + // we won't warn on c1>=128 (the 2-byte value) because often + // it is just fine to compare an constant, ascii value (i.e. "body") + // against some non-ascii value (i.e. a unicode string that + // was downloaded from a web page) + if (aIgnoreCase && c2>=128) + NS_WARNING("got a non-ASCII string, but we can't do an accurate case conversion!"); +#endif + + // can't do case conversion on characters out of our range + if (aIgnoreCase && c1<128 && c2<128) { + + c1 = ascii_tolower(char(c1)); + c2 = ascii_tolower(char(c2)); + + if (c1 == c2) continue; + } + + if (c1 < c2) return -1; + return 1; + } + } while (--aCount); + } + } + return 0; +} + + +/** + * This method compares the data in one buffer with another + * @update gess 01/04/99 + * @param aStr1 is the first buffer to be compared + * @param aStr2 is the 2nd buffer to be compared + * @param aCount is the number of chars to compare + * @param aIgnoreCase tells us whether to use a case-sensitive comparison + * @return -1,0,1 depending on <,==,> + */ +inline PRInt32 +Compare1To2(const char* aStr1,const PRUnichar* aStr2,PRUint32 aCount,PRBool aIgnoreCase){ + return Compare2To1(aStr2, aStr1, aCount, aIgnoreCase) * -1; +} + + +//----------------------------------------------------------------------------- +// +// This set of methods is used compress char sequences in a buffer... +// + + +/** + * This method compresses duplicate runs of a given char from the given buffer + * + * @update rickg 03.23.2000 + * @param aString is the buffer to be manipulated + * @param aLength is the length of the buffer + * @param aSet tells us which chars to compress from given buffer + * @param aEliminateLeading tells us whether to strip chars from the start of the buffer + * @param aEliminateTrailing tells us whether to strip chars from the start of the buffer + * @return the new length of the given buffer + */ +static PRInt32 +CompressChars1(char* aString,PRUint32 aLength,const char* aSet){ + + char* from = aString; + char* end = aString + aLength; + char* to = from; + + //this code converts /n, /t, /r into normal space ' '; + //it also compresses runs of whitespace down to a single char... + if(aSet && aString && (0 < aLength)){ + PRUint32 aSetLen=strlen(aSet); + + while (from < end) { + char theChar = *from++; + + *to++=theChar; //always copy this char... + + if((kNotFound!=FindChar1(aSet,aSetLen,0,theChar,aSetLen))){ + while (from < end) { + theChar = *from++; + if(kNotFound==FindChar1(aSet,aSetLen,0,theChar,aSetLen)){ + *to++ = theChar; + break; + } + } //while + } //if + } //if + *to = 0; + } + return to - aString; +} + + + +/** + * This method compresses duplicate runs of a given char from the given buffer + * + * @update rickg 03.23.2000 + * @param aString is the buffer to be manipulated + * @param aLength is the length of the buffer + * @param aSet tells us which chars to compress from given buffer + * @param aEliminateLeading tells us whether to strip chars from the start of the buffer + * @param aEliminateTrailing tells us whether to strip chars from the start of the buffer + * @return the new length of the given buffer + */ +static PRInt32 +CompressChars2(PRUnichar* aString,PRUint32 aLength,const char* aSet){ + + PRUnichar* from = aString; + PRUnichar* end = from + aLength; + PRUnichar* to = from; + + //this code converts /n, /t, /r into normal space ' '; + //it also compresses runs of whitespace down to a single char... + if(aSet && aString && (0 < aLength)){ + PRUint32 aSetLen=strlen(aSet); + + while (from < end) { + PRUnichar theChar = *from++; + + *to++=theChar; //always copy this char... + + if((theChar<256) && (kNotFound!=FindChar1(aSet,aSetLen,0,theChar,aSetLen))){ + while (from < end) { + theChar = *from++; + if(kNotFound==FindChar1(aSet,aSetLen,0,theChar,aSetLen)){ + *to++ = theChar; + break; + } + } //while + } //if + } //if + *to = 0; + } + return to - (PRUnichar*)aString; +} + +/** + * This method strips chars in a given set from the given buffer + * + * @update gess 01/04/99 + * @param aString is the buffer to be manipulated + * @param aLength is the length of the buffer + * @param aSet tells us which chars to compress from given buffer + * @param aEliminateLeading tells us whether to strip chars from the start of the buffer + * @param aEliminateTrailing tells us whether to strip chars from the start of the buffer + * @return the new length of the given buffer + */ +static PRInt32 +StripChars1(char* aString,PRUint32 aLength,const char* aSet){ + + // XXXdarin this code should defer writing until necessary. + + char* to = aString; + char* from = aString-1; + char* end = aString + aLength; + + if(aSet && aString && (0 < aLength)){ + PRUint32 aSetLen=strlen(aSet); + while (++from < end) { + char theChar = *from; + if(kNotFound==FindChar1(aSet,aSetLen,0,theChar,aSetLen)){ + *to++ = theChar; + } + } + *to = 0; + } + return to - (char*)aString; +} + + +/** + * This method strips chars in a given set from the given buffer + * + * @update gess 01/04/99 + * @param aString is the buffer to be manipulated + * @param aLength is the length of the buffer + * @param aSet tells us which chars to compress from given buffer + * @param aEliminateLeading tells us whether to strip chars from the start of the buffer + * @param aEliminateTrailing tells us whether to strip chars from the start of the buffer + * @return the new length of the given buffer + */ +static PRInt32 +StripChars2(PRUnichar* aString,PRUint32 aLength,const char* aSet){ + + // XXXdarin this code should defer writing until necessary. + + PRUnichar* to = aString; + PRUnichar* from = aString-1; + PRUnichar* end = to + aLength; + + if(aSet && aString && (0 < aLength)){ + PRUint32 aSetLen=strlen(aSet); + while (++from < end) { + PRUnichar theChar = *from; + //Note the test for ascii range below. If you have a real unicode char, + //and you're searching for chars in the (given) ascii string, there's no + //point in doing the real search since it's out of the ascii range. + if((255 +#ifndef __SUNPRO_CC +static +#endif /* !__SUNPRO_CC */ +CharT +GetFindInSetFilter( const CharT* set) + { + CharT filter = ~CharT(0); // All bits set + while (*set) { + filter &= ~(*set); + ++set; + } + return filter; + } + +// This template class is used by our code to access rickg's buffer routines. +template struct nsBufferRoutines {}; + +NS_SPECIALIZE_TEMPLATE +struct nsBufferRoutines + { + static + PRInt32 compare( const char* a, const char* b, PRUint32 max, PRBool ic ) + { + return Compare1To1(a, b, max, ic); + } + + static + PRInt32 compare( const char* a, const PRUnichar* b, PRUint32 max, PRBool ic ) + { + return Compare1To2(a, b, max, ic); + } + + static + PRInt32 find_char( const char* s, PRUint32 max, PRInt32 offset, const PRUnichar c, PRInt32 count ) + { + return FindChar1(s, max, offset, c, count); + } + + static + PRInt32 rfind_char( const char* s, PRUint32 max, PRInt32 offset, const PRUnichar c, PRInt32 count ) + { + return RFindChar1(s, max, offset, c, count); + } + + static + char get_find_in_set_filter( const char* set ) + { + return GetFindInSetFilter(set); + } + + static + PRInt32 strip_chars( char* s, PRUint32 len, const char* set ) + { + return StripChars1(s, len, set); + } + + static + PRInt32 compress_chars( char* s, PRUint32 len, const char* set ) + { + return CompressChars1(s, len, set); + } + }; + +NS_SPECIALIZE_TEMPLATE +struct nsBufferRoutines + { + static + PRInt32 compare( const PRUnichar* a, const PRUnichar* b, PRUint32 max, PRBool ic ) + { + NS_ASSERTION(!ic, "no case-insensitive compare here"); + return Compare2To2(a, b, max); + } + + static + PRInt32 compare( const PRUnichar* a, const char* b, PRUint32 max, PRBool ic ) + { + return Compare2To1(a, b, max, ic); + } + + static + PRInt32 find_char( const PRUnichar* s, PRUint32 max, PRInt32 offset, const PRUnichar c, PRInt32 count ) + { + return FindChar2(s, max, offset, c, count); + } + + static + PRInt32 rfind_char( const PRUnichar* s, PRUint32 max, PRInt32 offset, const PRUnichar c, PRInt32 count ) + { + return RFindChar2(s, max, offset, c, count); + } + + static + PRUnichar get_find_in_set_filter( const PRUnichar* set ) + { + return GetFindInSetFilter(set); + } + + static + PRUnichar get_find_in_set_filter( const char* set ) + { + return (~PRUnichar(0)^~char(0)) | GetFindInSetFilter(set); + } + + static + PRInt32 strip_chars( PRUnichar* s, PRUint32 max, const char* set ) + { + return StripChars2(s, max, set); + } + + static + PRInt32 compress_chars( PRUnichar* s, PRUint32 len, const char* set ) + { + return CompressChars2(s, len, set); + } + }; + +//----------------------------------------------------------------------------- + +template +#ifndef __SUNPRO_CC +static +#endif /* !__SUNPRO_CC */ +PRInt32 +FindSubstring( const L* big, PRUint32 bigLen, + const R* little, PRUint32 littleLen, + PRBool ignoreCase ) + { + if (littleLen > bigLen) + return kNotFound; + + PRInt32 i, max = PRInt32(bigLen - littleLen); + for (i=0; i<=max; ++i, ++big) + { + if (nsBufferRoutines::compare(big, little, littleLen, ignoreCase) == 0) + return i; + } + + return kNotFound; + } + +template +#ifndef __SUNPRO_CC +static +#endif /* !__SUNPRO_CC */ +PRInt32 +RFindSubstring( const L* big, PRUint32 bigLen, + const R* little, PRUint32 littleLen, + PRBool ignoreCase ) + { + if (littleLen > bigLen) + return kNotFound; + + PRInt32 i, max = PRInt32(bigLen - littleLen); + + const L* iter = big + max; + for (i=max; iter >= big; --i, --iter) + { + if (nsBufferRoutines::compare(iter, little, littleLen, ignoreCase) == 0) + return i; + } + + return kNotFound; + } + +template +#ifndef __SUNPRO_CC +static +#endif /* !__SUNPRO_CC */ +PRInt32 +FindCharInSet( const CharT* data, PRUint32 dataLen, const SetCharT* set ) + { + CharT filter = nsBufferRoutines::get_find_in_set_filter(set); + + const CharT* end = data + dataLen; + for (const CharT* iter = data; iter < end; ++iter) + { + CharT currentChar = *iter; + if (currentChar & filter) + continue; // char is not in filter set; go on with next char. + + // test all chars + const SetCharT* charInSet = set; + CharT setChar = CharT(*charInSet); + while (setChar) + { + if (setChar == currentChar) + return iter - data; // found it! return index of the found char. + + setChar = CharT(*(++charInSet)); + } + } + return kNotFound; + } + +template +#ifndef __SUNPRO_CC +static +#endif /* !__SUNPRO_CC */ +PRInt32 +RFindCharInSet( const CharT* data, PRUint32 dataLen, const SetCharT* set ) + { + CharT filter = nsBufferRoutines::get_find_in_set_filter(set); + + for (const CharT* iter = data + dataLen - 1; iter >= data; --iter) + { + CharT currentChar = *iter; + if (currentChar & filter) + continue; // char is not in filter set; go on with next char. + + // test all chars + const CharT* charInSet = set; + CharT setChar = *charInSet; + while (setChar) + { + if (setChar == currentChar) + return iter - data; // found it! return index of the found char. + + setChar = *(++charInSet); + } + } + return kNotFound; + } + +/** + * This is a copy of |PR_cnvtf| with a bug fixed. (The second argument + * of PR_dtoa is 2 rather than 1.) + * + * XXXdarin if this is the right thing, then why wasn't it fixed in NSPR?!? + */ +void +Modified_cnvtf(char *buf, int bufsz, int prcsn, double fval) +{ + PRIntn decpt, sign, numdigits; + char *num, *nump; + char *bufp = buf; + char *endnum; + + /* If anything fails, we store an empty string in 'buf' */ +#ifdef VBOX_USE_IPRT_IN_XPCOM + num = (char*)RTMemAlloc(bufsz); +#else + num = (char*)malloc(bufsz); +#endif + if (num == NULL) { + buf[0] = '\0'; + return; + } + if (PR_dtoa(fval, 2, prcsn, &decpt, &sign, &endnum, num, bufsz) + == PR_FAILURE) { + buf[0] = '\0'; + goto done; + } + numdigits = endnum - num; + nump = num; + + /* + * The NSPR code had a fancy way of checking that we weren't dealing + * with -0.0 or -NaN, but I'll just use < instead. + * XXX Should we check !isnan(fval) as well? Is it portable? We + * probably don't need to bother since NAN isn't portable. + */ + if (sign && fval < 0.0f) { + *bufp++ = '-'; + } + + if (decpt == 9999) { + while ((*bufp++ = *nump++) != 0) {} /* nothing to execute */ + goto done; + } + + if (decpt > (prcsn+1) || decpt < -(prcsn-1) || decpt < -5) { + *bufp++ = *nump++; + if (numdigits != 1) { + *bufp++ = '.'; + } + + while (*nump != '\0') { + *bufp++ = *nump++; + } + *bufp++ = 'e'; + PR_snprintf(bufp, bufsz - (bufp - buf), "%+d", decpt-1); + } + else if (decpt >= 0) { + if (decpt == 0) { + *bufp++ = '0'; + } + else { + while (decpt--) { + if (*nump != '\0') { + *bufp++ = *nump++; + } + else { + *bufp++ = '0'; + } + } + } + if (*nump != '\0') { + *bufp++ = '.'; + while (*nump != '\0') { + *bufp++ = *nump++; + } + } + *bufp++ = '\0'; + } + else if (decpt < 0) { + *bufp++ = '0'; + *bufp++ = '.'; + while (decpt++) { + *bufp++ = '0'; + } + + while (*nump != '\0') { + *bufp++ = *nump++; + } + *bufp++ = '\0'; + } +done: +#ifdef VBOX_USE_IPRT_IN_XPCOM + RTMemFree(num); +#else + free(num); +#endif +} + + /** + * this method changes the meaning of |offset| and |count|: + * + * upon return, + * |offset| specifies start of search range + * |count| specifies length of search range + */ +static void +Find_ComputeSearchRange( PRUint32 bigLen, PRUint32 littleLen, PRInt32& offset, PRInt32& count ) + { + // |count| specifies how many iterations to make from |offset| + + if (offset < 0) + { + offset = 0; + } + else if (PRUint32(offset) > bigLen) + { + count = 0; + return; + } + + PRInt32 maxCount = bigLen - offset; + if (count < 0 || count > maxCount) + { + count = maxCount; + } + else + { + count += littleLen; + if (count > maxCount) + count = maxCount; + } + } + + /** + * this method changes the meaning of |offset| and |count|: + * + * upon entry, + * |offset| specifies the end point from which to search backwards + * |count| specifies the number of iterations from |offset| + * + * upon return, + * |offset| specifies start of search range + * |count| specifies length of search range + * + * + * EXAMPLE + * + * + -- littleLen=4 -- + + * : : + * |____|____|____|____|____|____|____|____|____|____|____|____| + * : : + * offset=5 bigLen=12 + * + * if count = 4, then we expect this function to return offset = 2 and + * count = 7. + * + */ +static void +RFind_ComputeSearchRange( PRUint32 bigLen, PRUint32 littleLen, PRInt32& offset, PRInt32& count ) + { + if (littleLen > bigLen) + { + offset = 0; + count = 0; + return; + } + + if (offset < 0) + offset = bigLen - littleLen; + if (count < 0) + count = offset + 1; + + PRInt32 start = offset - count + 1; + if (start < 0) + start = 0; + + count = offset + littleLen - start; + offset = start; + } + +//----------------------------------------------------------------------------- + + // define nsString obsolete methods +#include "string-template-def-unichar.h" +#include "nsTStringObsolete.cpp" +#include "string-template-undef.h" + + // define nsCString obsolete methods +#include "string-template-def-char.h" +#include "nsTStringObsolete.cpp" +#include "string-template-undef.h" + +//----------------------------------------------------------------------------- + +// specialized methods: + +PRInt32 +nsString::Find( const nsAFlatString& aString, PRInt32 aOffset, PRInt32 aCount ) const + { + // this method changes the meaning of aOffset and aCount: + Find_ComputeSearchRange(mLength, aString.Length(), aOffset, aCount); + + PRInt32 result = FindSubstring(mData + aOffset, aCount, aString.get(), aString.Length(), PR_FALSE); + if (result != kNotFound) + result += aOffset; + return result; + } + +PRInt32 +nsString::Find( const PRUnichar* aString, PRInt32 aOffset, PRInt32 aCount ) const + { + return Find(nsDependentString(aString), aOffset, aCount); + } + +PRInt32 +nsString::RFind( const nsAFlatString& aString, PRInt32 aOffset, PRInt32 aCount ) const + { + // this method changes the meaning of aOffset and aCount: + RFind_ComputeSearchRange(mLength, aString.Length(), aOffset, aCount); + + PRInt32 result = RFindSubstring(mData + aOffset, aCount, aString.get(), aString.Length(), PR_FALSE); + if (result != kNotFound) + result += aOffset; + return result; + } + +PRInt32 +nsString::RFind( const PRUnichar* aString, PRInt32 aOffset, PRInt32 aCount ) const + { + return RFind(nsDependentString(aString), aOffset, aCount); + } + +PRInt32 +nsString::FindCharInSet( const PRUnichar* aSet, PRInt32 aOffset ) const + { + if (aOffset < 0) + aOffset = 0; + else if (aOffset >= PRInt32(mLength)) + return kNotFound; + + PRInt32 result = ::FindCharInSet(mData + aOffset, mLength - aOffset, aSet); + if (result != kNotFound) + result += aOffset; + return result; + } + + + /** + * nsTString::Compare,CompareWithConversion,etc. + */ + +PRInt32 +nsCString::Compare( const char* aString, PRBool aIgnoreCase, PRInt32 aCount ) const + { + PRUint32 strLen = char_traits::length(aString); + + PRInt32 maxCount = PRInt32(NS_MIN(mLength, strLen)); + + PRInt32 compareCount; + if (aCount < 0 || aCount > maxCount) + compareCount = maxCount; + else + compareCount = aCount; + + PRInt32 result = + nsBufferRoutines::compare(mData, aString, compareCount, aIgnoreCase); + + if (result == 0 && + (aCount < 0 || strLen < PRUint32(aCount) || mLength < PRUint32(aCount))) + { + // Since the caller didn't give us a length to test, or strings shorter + // than aCount, and compareCount characters matched, we have to assume + // that the longer string is greater. + + if (mLength != strLen) + result = (mLength < strLen) ? -1 : 1; + } + return result; + } + +PRBool +nsString::EqualsIgnoreCase( const char* aString, PRInt32 aCount ) const + { + PRUint32 strLen = nsCharTraits::length(aString); + + PRInt32 maxCount = PRInt32(NS_MIN(mLength, strLen)); + + PRInt32 compareCount; + if (aCount < 0 || aCount > maxCount) + compareCount = maxCount; + else + compareCount = aCount; + + PRInt32 result = + nsBufferRoutines::compare(mData, aString, compareCount, PR_TRUE); + + if (result == 0 && + (aCount < 0 || strLen < PRUint32(aCount) || mLength < PRUint32(aCount))) + { + // Since the caller didn't give us a length to test, or strings shorter + // than aCount, and compareCount characters matched, we have to assume + // that the longer string is greater. + + if (mLength != strLen) + result = 1; // Arbitrarily using any number != 0 + } + return result == 0; + } + + /** + * ToCString, ToFloat, ToInteger + */ + +char* +nsString::ToCString( char* aBuf, PRUint32 aBufLength, PRUint32 aOffset ) const + { + // because the old implementation checked aBuf + if (!(aBuf && aBufLength > 0 && aOffset <= mLength)) + return nsnull; + + PRUint32 maxCount = NS_MIN(aBufLength-1, mLength - aOffset); + + LossyConvertEncoding converter(aBuf); + converter.write(mData + aOffset, maxCount); + converter.write_terminator(); + return aBuf; + } + +float +nsCString::ToFloat(PRInt32* aErrorCode) const + { + float res = 0.0f; + if (mLength > 0) + { + char *conv_stopped; + const char *str = mData; + // Use PR_strtod, not strtod, since we don't want locale involved. + res = (float)PR_strtod(str, &conv_stopped); + if (conv_stopped == str+mLength) + *aErrorCode = (PRInt32) NS_OK; + else // Not all the string was scanned + *aErrorCode = (PRInt32) NS_ERROR_ILLEGAL_VALUE; + } + else + { + // The string was too short (0 characters) + *aErrorCode = (PRInt32) NS_ERROR_ILLEGAL_VALUE; + } + return res; + } + +float +nsString::ToFloat(PRInt32* aErrorCode) const + { + float res = 0.0f; + char buf[100]; + if (mLength > 0 && mLength < sizeof(buf)) + { + char *conv_stopped; + const char *str = ToCString(buf, sizeof(buf)); + // Use PR_strtod, not strtod, since we don't want locale involved. + res = (float)PR_strtod(str, &conv_stopped); + if (conv_stopped == str+mLength) + *aErrorCode = (PRInt32) NS_OK; + else // Not all the string was scanned + *aErrorCode = (PRInt32) NS_ERROR_ILLEGAL_VALUE; + } + else + { + // The string was too short (0 characters) or too long (sizeof(buf)) + *aErrorCode = (PRInt32) NS_ERROR_ILLEGAL_VALUE; + } + return res; + } + + + /** + * nsTString::AssignWithConversion + */ + +void +nsCString::AssignWithConversion( const nsAString& aData ) + { + LossyCopyUTF16toASCII(aData, *this); + } + +void +nsString::AssignWithConversion( const nsACString& aData ) + { + CopyASCIItoUTF16(aData, *this); + } + + + /** + * nsTString::AppendWithConversion + */ + +void +nsCString::AppendWithConversion( const nsAString& aData ) + { + LossyAppendUTF16toASCII(aData, *this); + } + +void +nsString::AppendWithConversion( const nsACString& aData ) + { + AppendASCIItoUTF16(aData, *this); + } + + + /** + * nsTString::AppendInt + */ + +void +nsCString::AppendInt( PRInt32 aInteger, PRInt32 aRadix ) + { + char buf[20]; + const char* fmt; + switch (aRadix) { + case 8: + fmt = "%o"; + break; + case 10: + fmt = "%d"; + break; + default: + NS_ASSERTION(aRadix == 16, "Invalid radix!"); + fmt = "%x"; + } + PR_snprintf(buf, sizeof(buf), fmt, aInteger); + Append(buf); + } + +void +nsString::AppendInt( PRInt32 aInteger, PRInt32 aRadix ) + { + char buf[20]; + const char* fmt; + switch (aRadix) { + case 8: + fmt = "%o"; + break; + case 10: + fmt = "%d"; + break; + default: + NS_ASSERTION(aRadix == 16, "Invalid radix!"); + fmt = "%x"; + } + PR_snprintf(buf, sizeof(buf), fmt, aInteger); + AppendASCIItoUTF16(buf, *this); + } + +void +nsCString::AppendInt( PRInt64 aInteger, PRInt32 aRadix ) + { + char buf[30]; + const char* fmt; + switch (aRadix) { + case 8: + fmt = "%llo"; + break; + case 10: + fmt = "%lld"; + break; + default: + NS_ASSERTION(aRadix == 16, "Invalid radix!"); + fmt = "%llx"; + } + PR_snprintf(buf, sizeof(buf), fmt, aInteger); + Append(buf); + } + +void +nsString::AppendInt( PRInt64 aInteger, PRInt32 aRadix ) + { + char buf[30]; + const char* fmt; + switch (aRadix) { + case 8: + fmt = "%llo"; + break; + case 10: + fmt = "%lld"; + break; + default: + NS_ASSERTION(aRadix == 16, "Invalid radix!"); + fmt = "%llx"; + } + PR_snprintf(buf, sizeof(buf), fmt, aInteger); + AppendASCIItoUTF16(buf, *this); + } + + /** + * nsTString::AppendFloat + */ + +void +nsCString::AppendFloat( double aFloat ) + { + char buf[40]; + // Use Modified_cnvtf, which is locale-insensitive, instead of the + // locale-sensitive PR_snprintf or sprintf(3) + Modified_cnvtf(buf, sizeof(buf), 6, aFloat); + Append(buf); + } + +void +nsString::AppendFloat( double aFloat ) + { + char buf[40]; + // Use Modified_cnvtf, which is locale-insensitive, instead of the + // locale-sensitive PR_snprintf or sprintf(3) + Modified_cnvtf(buf, sizeof(buf), 6, aFloat); + AppendWithConversion(buf); + } + +#endif // !MOZ_STRING_WITH_OBSOLETE_API diff --git a/src/libs/xpcom18a4/xpcom/string/src/nsSubstring.cpp b/src/libs/xpcom18a4/xpcom/string/src/nsSubstring.cpp new file mode 100644 index 00000000..6ed0c5c8 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/src/nsSubstring.cpp @@ -0,0 +1,250 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* ***** 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 IBM Corporation. + * Portions created by IBM Corporation are Copyright (C) 2003 + * IBM Corporation. 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 ***** */ + +#ifdef DEBUG +#define ENABLE_STRING_STATS +#endif + +#ifdef ENABLE_STRING_STATS +#include +#endif + +#include +#include "nsSubstring.h" +#include "nsString.h" +#include "nsDependentString.h" +#include "nsMemory.h" +#include "pratom.h" +#ifdef VBOX_USE_IPRT_IN_XPCOM +# include +#endif + +// --------------------------------------------------------------------------- + +static const PRUnichar gNullChar = 0; + +const char* nsCharTraits ::sEmptyBuffer = (const char*) &gNullChar; +const PRUnichar* nsCharTraits::sEmptyBuffer = &gNullChar; + +// --------------------------------------------------------------------------- + +#ifdef ENABLE_STRING_STATS +class nsStringStats + { + public: + nsStringStats() + : mAllocCount(0), mReallocCount(0), mFreeCount(0), mShareCount(0) {} + + ~nsStringStats() + { + // this is a hack to suppress duplicate string stats printing + // in seamonkey as a result of the string code being linked + // into seamonkey and libxpcom! :-( + if (!mAllocCount && !mAdoptCount) + return; + +#ifndef VBOX + printf("nsStringStats\n"); + printf(" => mAllocCount: % 10d\n", mAllocCount); + printf(" => mReallocCount: % 10d\n", mReallocCount); + printf(" => mFreeCount: % 10d", mFreeCount); + if (mAllocCount > mFreeCount) + printf(" -- LEAKED %d !!!\n", mAllocCount - mFreeCount); + else + printf("\n"); + printf(" => mShareCount: % 10d\n", mShareCount); + printf(" => mAdoptCount: % 10d\n", mAdoptCount); + printf(" => mAdoptFreeCount: % 10d", mAdoptFreeCount); + if (mAdoptCount > mAdoptFreeCount) + printf(" -- LEAKED %d !!!\n", mAdoptCount - mAdoptFreeCount); + else + printf("\n"); +#endif + } + + PRInt32 mAllocCount; + PRInt32 mReallocCount; + PRInt32 mFreeCount; + PRInt32 mShareCount; + PRInt32 mAdoptCount; + PRInt32 mAdoptFreeCount; + }; +static nsStringStats gStringStats; +#define STRING_STAT_INCREMENT(_s) PR_AtomicIncrement(&gStringStats.m ## _s ## Count) +#else +#define STRING_STAT_INCREMENT(_s) +#endif + +// --------------------------------------------------------------------------- + + /** + * This structure precedes the string buffers "we" allocate. It may be the + * case that nsTSubstring::mData does not point to one of these special + * buffers. The mFlags member variable distinguishes the buffer type. + * + * When this header is in use, it enables reference counting, and capacity + * tracking. NOTE: A string buffer can be modified only if its reference + * count is 1. + */ +class nsStringHeader + { + private: + + PRInt32 mRefCount; + PRUint32 mStorageSize; + + public: + + void AddRef() + { + PR_AtomicIncrement(&mRefCount); + STRING_STAT_INCREMENT(Share); + } + + void Release() + { + if (PR_AtomicDecrement(&mRefCount) == 0) + { + STRING_STAT_INCREMENT(Free); +#ifdef VBOX_USE_IPRT_IN_XPCOM + RTMemFree(this); // we were allocated with |malloc| +#else + free(this); // we were allocated with |malloc| +#endif + } + } + + /** + * Alloc returns a pointer to a new string header with set capacity. + */ + static nsStringHeader* Alloc(size_t size) + { + STRING_STAT_INCREMENT(Alloc); + + NS_ASSERTION(size != 0, "zero capacity allocation not allowed"); + + nsStringHeader *hdr = +#ifdef VBOX_USE_IPRT_IN_XPCOM + (nsStringHeader *) RTMemAlloc(sizeof(nsStringHeader) + size); +#else + (nsStringHeader *) malloc(sizeof(nsStringHeader) + size); +#endif + if (hdr) + { + hdr->mRefCount = 1; + hdr->mStorageSize = size; + } + return hdr; + } + + static nsStringHeader* Realloc(nsStringHeader* hdr, size_t size) + { + STRING_STAT_INCREMENT(Realloc); + + NS_ASSERTION(size != 0, "zero capacity allocation not allowed"); + + // no point in trying to save ourselves if we hit this assertion + NS_ASSERTION(!hdr->IsReadonly(), "|Realloc| attempted on readonly string"); + +#ifdef VBOX_USE_IPRT_IN_XPCOM + hdr = (nsStringHeader*) RTMemRealloc(hdr, sizeof(nsStringHeader) + size); +#else + hdr = (nsStringHeader*) realloc(hdr, sizeof(nsStringHeader) + size); +#endif + if (hdr) + hdr->mStorageSize = size; + + return hdr; + } + + static nsStringHeader* FromData(void* data) + { + return (nsStringHeader*) ( ((char*) data) - sizeof(nsStringHeader) ); + } + + void* Data() const + { + return (void*) ( ((char*) this) + sizeof(nsStringHeader) ); + } + + PRUint32 StorageSize() const + { + return mStorageSize; + } + + /** + * Because nsTSubstring allows only single threaded access, if this + * method returns FALSE, then the caller can be sure that it has + * exclusive access to the nsStringHeader and associated data. + * However, if this function returns TRUE, then other strings may + * rely on the data in this buffer being constant and other threads + * may access this buffer simultaneously. + */ + PRBool IsReadonly() const + { + return mRefCount > 1; + } + }; + +// --------------------------------------------------------------------------- + +inline void +ReleaseData( void* data, PRUint32 flags ) + { + if (flags & nsSubstring::F_SHARED) + { + nsStringHeader::FromData(data)->Release(); + } + else if (flags & nsSubstring::F_OWNED) + { + nsMemory::Free(data); + STRING_STAT_INCREMENT(AdoptFree); + } + // otherwise, nothing to do. + } + + + // define nsSubstring +#include "string-template-def-unichar.h" +#include "nsTSubstring.cpp" +#include "string-template-undef.h" + + // define nsCSubstring +#include "string-template-def-char.h" +#include "nsTSubstring.cpp" +#include "string-template-undef.h" diff --git a/src/libs/xpcom18a4/xpcom/string/src/nsSubstringTuple.cpp b/src/libs/xpcom18a4/xpcom/string/src/nsSubstringTuple.cpp new file mode 100644 index 00000000..a5445d7a --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/src/nsSubstringTuple.cpp @@ -0,0 +1,64 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* ***** 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 IBM Corporation. + * Portions created by IBM Corporation are Copyright (C) 2003 + * IBM Corporation. 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 "nsSubstringTuple.h" + +#if 0 + // convert fragment to |const string_base_type&| +#define TO_SUBSTRING(_v) \ + ( (ptrdiff_t(_v) & 0x1) \ + ? NS_REINTERPRET_CAST(const abstract_string_type*, \ + ((unsigned long)_v & ~0x1))->ToSubstring() \ + : *NS_REINTERPRET_CAST(const substring_type*, (_v)) ) +#endif + + // convert fragment to |const substring_type&| +#define TO_SUBSTRING(_v) \ + ( (_v)->mVTable == obsolete_string_type::sCanonicalVTable \ + ? *(_v)->AsSubstring() \ + : (_v)->ToSubstring() ) + + // define nsSubstringTuple +#include "string-template-def-unichar.h" +#include "nsTSubstringTuple.cpp" +#include "string-template-undef.h" + + // define nsCSubstringTuple +#include "string-template-def-char.h" +#include "nsTSubstringTuple.cpp" +#include "string-template-undef.h" diff --git a/src/libs/xpcom18a4/xpcom/string/src/nsTAString.cpp b/src/libs/xpcom18a4/xpcom/string/src/nsTAString.cpp new file mode 100644 index 00000000..ffd75fe8 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/src/nsTAString.cpp @@ -0,0 +1,509 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* ***** 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 IBM Corporation. + * Portions created by IBM Corporation are Copyright (C) 2003 + * IBM Corporation. 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 ***** */ + + + /** + * Some comments on this implementation... + * + * This class is a bridge between the old string implementation and the new + * string implementation. If mVTable points to the canonical vtable for the + * new string implementation, then we can cast directly to the new string + * classes (helped by the AsSubstring() methods). However, if mVTable is not + * ours, then we need to call through the vtable to satisfy the nsTAString + * methods. + * + * In most cases we will avoid the vtable. + */ + + +nsTAString_CharT::~nsTAString_CharT() + { + if (mVTable == obsolete_string_type::sCanonicalVTable) + AsSubstring()->Finalize(); + else + AsObsoleteString()->~nsTObsoleteAString_CharT(); + } + + +nsTAString_CharT::size_type +nsTAString_CharT::Length() const + { + if (mVTable == obsolete_string_type::sCanonicalVTable) + return AsSubstring()->Length(); + + return AsObsoleteString()->Length(); + } + +PRBool +nsTAString_CharT::Equals( const self_type& readable ) const + { + if (mVTable == obsolete_string_type::sCanonicalVTable) + return AsSubstring()->Equals(readable); + + return ToSubstring().Equals(readable); + } + +PRBool +nsTAString_CharT::Equals( const self_type& readable, const comparator_type& comparator ) const + { + if (mVTable == obsolete_string_type::sCanonicalVTable) + return AsSubstring()->Equals(readable, comparator); + + return ToSubstring().Equals(readable, comparator); + } + +PRBool +nsTAString_CharT::Equals( const char_type* data ) const + { + if (mVTable == obsolete_string_type::sCanonicalVTable) + return AsSubstring()->Equals(data); + + return ToSubstring().Equals(data); + } + +PRBool +nsTAString_CharT::Equals( const char_type* data, const comparator_type& comparator ) const + { + if (mVTable == obsolete_string_type::sCanonicalVTable) + return AsSubstring()->Equals(data, comparator); + + return ToSubstring().Equals(data, comparator); + } + +PRBool +nsTAString_CharT::EqualsASCII( const char* data, size_type len ) const + { + if (mVTable == obsolete_string_type::sCanonicalVTable) + return AsSubstring()->EqualsASCII(data, len); + + return ToSubstring().EqualsASCII(data, len); + } + +PRBool +nsTAString_CharT::EqualsASCII( const char* data ) const + { + if (mVTable == obsolete_string_type::sCanonicalVTable) + return AsSubstring()->EqualsASCII(data); + + return ToSubstring().EqualsASCII(data); + } + +PRBool +nsTAString_CharT::LowerCaseEqualsASCII( const char* data, size_type len ) const + { + if (mVTable == obsolete_string_type::sCanonicalVTable) + return AsSubstring()->LowerCaseEqualsASCII(data, len); + + return ToSubstring().LowerCaseEqualsASCII(data, len); + } + +PRBool +nsTAString_CharT::LowerCaseEqualsASCII( const char* data ) const + { + if (mVTable == obsolete_string_type::sCanonicalVTable) + return AsSubstring()->LowerCaseEqualsASCII(data); + + return ToSubstring().LowerCaseEqualsASCII(data); + } + +PRBool +nsTAString_CharT::IsVoid() const + { + if (mVTable == obsolete_string_type::sCanonicalVTable) + return AsSubstring()->IsVoid(); + + return AsObsoleteString()->IsVoid(); + } + +void +nsTAString_CharT::SetIsVoid( PRBool val ) + { + if (mVTable == obsolete_string_type::sCanonicalVTable) + AsSubstring()->SetIsVoid(val); + else + AsObsoleteString()->SetIsVoid(val); + } + +PRBool +nsTAString_CharT::IsTerminated() const + { + if (mVTable == obsolete_string_type::sCanonicalVTable) + return AsSubstring()->IsTerminated(); + + return AsObsoleteString()->GetFlatBufferHandle() != nsnull; + } + +CharT +nsTAString_CharT::First() const + { + if (mVTable == obsolete_string_type::sCanonicalVTable) + return AsSubstring()->First(); + + return ToSubstring().First(); + } + +CharT +nsTAString_CharT::Last() const + { + if (mVTable == obsolete_string_type::sCanonicalVTable) + return AsSubstring()->Last(); + + return ToSubstring().Last(); + } + +nsTAString_CharT::size_type +nsTAString_CharT::CountChar( char_type c ) const + { + if (mVTable == obsolete_string_type::sCanonicalVTable) + return AsSubstring()->CountChar(c); + + return ToSubstring().CountChar(c); + } + +PRInt32 +nsTAString_CharT::FindChar( char_type c, index_type offset ) const + { + if (mVTable == obsolete_string_type::sCanonicalVTable) + return AsSubstring()->FindChar(c, offset); + + return ToSubstring().FindChar(c, offset); + } + +void +nsTAString_CharT::SetCapacity( size_type size ) + { + if (mVTable == obsolete_string_type::sCanonicalVTable) + AsSubstring()->SetCapacity(size); + else + AsObsoleteString()->SetCapacity(size); + } + +void +nsTAString_CharT::SetLength( size_type size ) + { + if (mVTable == obsolete_string_type::sCanonicalVTable) + AsSubstring()->SetLength(size); + else + AsObsoleteString()->SetLength(size); + } + +void +nsTAString_CharT::Assign( const self_type& readable ) + { + if (mVTable == obsolete_string_type::sCanonicalVTable) + AsSubstring()->Assign(readable); + else + AsObsoleteString()->do_AssignFromReadable(readable); + } + +void +nsTAString_CharT::Assign( const substring_tuple_type& tuple ) + { + if (mVTable == obsolete_string_type::sCanonicalVTable) + AsSubstring()->Assign(tuple); + else + AsObsoleteString()->do_AssignFromReadable(nsTAutoString_CharT(tuple)); + } + +void +nsTAString_CharT::Assign( const char_type* data ) + { + // null check and SetLength(0) cases needed for backwards compat + + if (mVTable == obsolete_string_type::sCanonicalVTable) + AsSubstring()->Assign(data); + else if (data) + AsObsoleteString()->do_AssignFromElementPtr(data); + else + AsObsoleteString()->SetLength(0); + } + +void +nsTAString_CharT::Assign( const char_type* data, size_type length ) + { + if (mVTable == obsolete_string_type::sCanonicalVTable) + AsSubstring()->Assign(data, length); + else + AsObsoleteString()->do_AssignFromElementPtrLength(data, length); + } + +void +nsTAString_CharT::AssignASCII( const char* data ) + { + if (mVTable == obsolete_string_type::sCanonicalVTable) + AsSubstring()->AssignASCII(data); + else + { +#ifdef CharT_is_char + AsObsoleteString()->do_AssignFromElementPtr(data); +#else + nsTAutoString_CharT temp; + temp.AssignASCII(data); + AsObsoleteString()->do_AssignFromReadable(temp); +#endif + } + } + +void +nsTAString_CharT::AssignASCII( const char* data, size_type length ) + { + if (mVTable == obsolete_string_type::sCanonicalVTable) + AsSubstring()->AssignASCII(data, length); + else + { +#ifdef CharT_is_char + AsObsoleteString()->do_AssignFromElementPtrLength(data, length); +#else + nsTAutoString_CharT temp; + temp.AssignASCII(data, length); + AsObsoleteString()->do_AssignFromReadable(temp); +#endif + } + } + +void +nsTAString_CharT::Assign( char_type c ) + { + if (mVTable == obsolete_string_type::sCanonicalVTable) + AsSubstring()->Assign(c); + else + AsObsoleteString()->do_AssignFromElement(c); + } + +void +nsTAString_CharT::Append( const self_type& readable ) + { + if (mVTable == obsolete_string_type::sCanonicalVTable) + AsSubstring()->Append(readable); + else + AsObsoleteString()->do_AppendFromReadable(readable); + } + +void +nsTAString_CharT::Append( const substring_tuple_type& tuple ) + { + if (mVTable == obsolete_string_type::sCanonicalVTable) + AsSubstring()->Append(tuple); + else + AsObsoleteString()->do_AppendFromReadable(nsTAutoString_CharT(tuple)); + } + +void +nsTAString_CharT::Append( const char_type* data ) + { + // null check case needed for backwards compat + + if (mVTable == obsolete_string_type::sCanonicalVTable) + AsSubstring()->Append(data); + else if (data) + AsObsoleteString()->do_AppendFromElementPtr(data); + } + +void +nsTAString_CharT::Append( const char_type* data, size_type length ) + { + if (mVTable == obsolete_string_type::sCanonicalVTable) + AsSubstring()->Append(data, length); + else + AsObsoleteString()->do_AppendFromElementPtrLength(data, length); + } + +void +nsTAString_CharT::AppendASCII( const char* data ) + { + if (mVTable == obsolete_string_type::sCanonicalVTable) + AsSubstring()->AppendASCII(data); + else + { +#ifdef CharT_is_char + AsObsoleteString()->do_AppendFromElementPtr(data); +#else + nsTAutoString_CharT temp; + temp.AssignASCII(data); + AsObsoleteString()->do_AppendFromReadable(temp); +#endif + } + } + +void +nsTAString_CharT::AppendASCII( const char* data, size_type length ) + { + if (mVTable == obsolete_string_type::sCanonicalVTable) + AsSubstring()->AppendASCII(data, length); + else + { +#ifdef CharT_is_char + AsObsoleteString()->do_AppendFromElementPtrLength(data, length); +#else + nsTAutoString_CharT temp; + temp.AssignASCII(data, length); + AsObsoleteString()->do_AppendFromReadable(temp); +#endif + } + } + +void +nsTAString_CharT::Append( char_type c ) + { + if (mVTable == obsolete_string_type::sCanonicalVTable) + AsSubstring()->Append(c); + else + AsObsoleteString()->do_AppendFromElement(c); + } + +void +nsTAString_CharT::Insert( const self_type& readable, index_type pos ) + { + if (mVTable == obsolete_string_type::sCanonicalVTable) + AsSubstring()->Insert(readable, pos); + else + AsObsoleteString()->do_InsertFromReadable(readable, pos); + } + +void +nsTAString_CharT::Insert( const substring_tuple_type& tuple, index_type pos ) + { + if (mVTable == obsolete_string_type::sCanonicalVTable) + AsSubstring()->Insert(tuple, pos); + else + AsObsoleteString()->do_InsertFromReadable(nsTAutoString_CharT(tuple), pos); + } + +void +nsTAString_CharT::Insert( const char_type* data, index_type pos ) + { + if (mVTable == obsolete_string_type::sCanonicalVTable) + AsSubstring()->Insert(data, pos); + else + AsObsoleteString()->do_InsertFromElementPtr(data, pos); + } + +void +nsTAString_CharT::Insert( const char_type* data, index_type pos, size_type length ) + { + if (mVTable == obsolete_string_type::sCanonicalVTable) + AsSubstring()->Insert(data, pos, length); + else + AsObsoleteString()->do_InsertFromElementPtrLength(data, pos, length); + } + +void +nsTAString_CharT::Insert( char_type c, index_type pos ) + { + if (mVTable == obsolete_string_type::sCanonicalVTable) + AsSubstring()->Insert(c, pos); + else + AsObsoleteString()->do_InsertFromElement(c, pos); + } + +void +nsTAString_CharT::Cut( index_type cutStart, size_type cutLength ) + { + if (mVTable == obsolete_string_type::sCanonicalVTable) + AsSubstring()->Cut(cutStart, cutLength); + else + AsObsoleteString()->Cut(cutStart, cutLength); + } + +void +nsTAString_CharT::Replace( index_type cutStart, size_type cutLength, const self_type& readable ) + { + if (mVTable == obsolete_string_type::sCanonicalVTable) + AsSubstring()->Replace(cutStart, cutLength, readable); + else + AsObsoleteString()->do_ReplaceFromReadable(cutStart, cutLength, readable); + } + +void +nsTAString_CharT::Replace( index_type cutStart, size_type cutLength, const substring_tuple_type& tuple ) + { + if (mVTable == obsolete_string_type::sCanonicalVTable) + AsSubstring()->Replace(cutStart, cutLength, tuple); + else + AsObsoleteString()->do_ReplaceFromReadable(cutStart, cutLength, nsTAutoString_CharT(tuple)); + } + +nsTAString_CharT::size_type +nsTAString_CharT::GetReadableBuffer( const char_type **data ) const + { + if (mVTable == obsolete_string_type::sCanonicalVTable) + { + const substring_type* str = AsSubstring(); + *data = str->mData; + return str->mLength; + } + + obsolete_string_type::const_fragment_type frag; + AsObsoleteString()->GetReadableFragment(frag, obsolete_string_type::kFirstFragment, 0); + *data = frag.mStart; + return (frag.mEnd - frag.mStart); + } + +nsTAString_CharT::size_type +nsTAString_CharT::GetWritableBuffer(char_type **data) + { + if (mVTable == obsolete_string_type::sCanonicalVTable) + { + substring_type* str = AsSubstring(); + str->BeginWriting(*data); + return str->Length(); + } + + obsolete_string_type::fragment_type frag; + AsObsoleteString()->GetWritableFragment(frag, obsolete_string_type::kFirstFragment, 0); + *data = frag.mStart; + return (frag.mEnd - frag.mStart); + } + +PRBool +nsTAString_CharT::IsDependentOn(const char_type* start, const char_type *end) const + { + // this is an optimization... + if (mVTable == obsolete_string_type::sCanonicalVTable) + return AsSubstring()->IsDependentOn(start, end); + + return ToSubstring().IsDependentOn(start, end); + } + +const nsTAString_CharT::substring_type +nsTAString_CharT::ToSubstring() const + { + const char_type* data; + size_type length = GetReadableBuffer(&data); + return substring_type(NS_CONST_CAST(char_type*, data), length, 0); + } diff --git a/src/libs/xpcom18a4/xpcom/string/src/nsTDependentSubstring.cpp b/src/libs/xpcom18a4/xpcom/string/src/nsTDependentSubstring.cpp new file mode 100644 index 00000000..8421ecc0 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/src/nsTDependentSubstring.cpp @@ -0,0 +1,65 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* ***** 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 IBM Corporation. + * Portions created by IBM Corporation are Copyright (C) 2003 + * IBM Corporation. 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 ***** */ + +void +nsTDependentSubstring_CharT::Rebind( const abstract_string_type& readable, PRUint32 startPos, PRUint32 length ) + { + size_type strLength = readable.GetReadableBuffer((const char_type**) &mData); + + if (startPos > strLength) + startPos = strLength; + + mData += startPos; + mLength = NS_MIN(length, strLength - startPos); + + SetDataFlags(F_NONE); + } + +void +nsTDependentSubstring_CharT::Rebind( const substring_type& str, PRUint32 startPos, PRUint32 length ) + { + size_type strLength = str.Length(); + + if (startPos > strLength) + startPos = strLength; + + mData = NS_CONST_CAST(char_type*, str.Data()) + startPos; + mLength = NS_MIN(length, strLength - startPos); + + SetDataFlags(F_NONE); + } diff --git a/src/libs/xpcom18a4/xpcom/string/src/nsTObsoleteAStringThunk.cpp b/src/libs/xpcom18a4/xpcom/string/src/nsTObsoleteAStringThunk.cpp new file mode 100644 index 00000000..3d1590a8 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/src/nsTObsoleteAStringThunk.cpp @@ -0,0 +1,235 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* ***** 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 IBM Corporation. + * Portions created by IBM Corporation are Copyright (C) 2003 + * IBM Corporation. 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 ***** */ + + +class nsTObsoleteAStringThunk_CharT : public nsTObsoleteAString_CharT + { + public: + typedef nsTObsoleteAStringThunk_CharT self_type; + typedef nsTSubstring_CharT substring_type; + + public: + + nsTObsoleteAStringThunk_CharT() {} + + + static const void* get_vptr() + { + const void* result; + new (&result) self_type(); + return result; + } + + + /** + * we are a nsTSubstring in disguise! + */ + + substring_type* concrete_self() { return NS_REINTERPRET_CAST( substring_type*, this); } + const substring_type* concrete_self() const { return NS_REINTERPRET_CAST(const substring_type*, this); } + + + /** + * all virtual methods need to be redirected to appropriate nsString methods + */ + + virtual ~nsTObsoleteAStringThunk_CharT() + { + concrete_self()->Finalize(); + } + + virtual PRUint32 GetImplementationFlags() const + { + return 0; + } + + virtual const buffer_handle_type* GetFlatBufferHandle() const + { + return (const buffer_handle_type*) (concrete_self()->IsTerminated() != PR_FALSE); + } + + virtual const buffer_handle_type* GetBufferHandle() const + { + return 0; + } + + virtual const shared_buffer_handle_type* GetSharedBufferHandle() const + { + return 0; + } + + virtual size_type Length() const + { + return concrete_self()->Length(); + } + + virtual PRBool IsVoid() const + { + return concrete_self()->IsVoid(); + } + + virtual void SetIsVoid(PRBool val) + { + concrete_self()->SetIsVoid(val); + } + + virtual void SetCapacity(size_type size) + { + concrete_self()->SetCapacity(size); + } + + virtual void SetLength(size_type size) + { + concrete_self()->SetLength(size); + } + + virtual void Cut(index_type cutStart, size_type cutLength) + { + concrete_self()->Cut(cutStart, cutLength); + } + + virtual void do_AssignFromReadable(const abstract_string_type &s) + { + concrete_self()->Assign(s); + } + + virtual void do_AssignFromElementPtr(const char_type *data) + { + concrete_self()->Assign(data); + } + + virtual void do_AssignFromElementPtrLength(const char_type *data, size_type length) + { + concrete_self()->Assign(data, length); + } + + virtual void do_AssignFromElement(char_type c) + { + concrete_self()->Assign(c); + } + + virtual void do_AppendFromReadable(const abstract_string_type &s) + { + concrete_self()->Append(s); + } + + virtual void do_AppendFromElementPtr(const char_type *data) + { + concrete_self()->Append(data); + } + + virtual void do_AppendFromElementPtrLength(const char_type *data, size_type length) + { + concrete_self()->Append(data, length); + } + + virtual void do_AppendFromElement(char_type c) + { + concrete_self()->Append(c); + } + + virtual void do_InsertFromReadable(const abstract_string_type &s, index_type pos) + { + concrete_self()->Insert(s, pos); + } + + virtual void do_InsertFromElementPtr(const char_type *data, index_type pos) + { + concrete_self()->Insert(data, pos); + } + + virtual void do_InsertFromElementPtrLength(const char_type *data, index_type pos, size_type length) + { + concrete_self()->Insert(data, pos, length); + } + + virtual void do_InsertFromElement(char_type c, index_type pos) + { + concrete_self()->Insert(c, pos); + } + + virtual void do_ReplaceFromReadable(index_type cutStart, size_type cutLength, const abstract_string_type &s) + { + concrete_self()->Replace(cutStart, cutLength, s); + } + + virtual const char_type *GetReadableFragment(const_fragment_type& frag, nsFragmentRequest which, PRUint32 offset) const + { + const substring_type* s = concrete_self(); + switch (which) + { + case kFirstFragment: + case kLastFragment: + case kFragmentAt: + frag.mStart = s->Data(); + frag.mEnd = frag.mStart + s->Length(); + return frag.mStart + offset; + case kPrevFragment: + case kNextFragment: + default: + return 0; + } + } + + virtual char_type *GetWritableFragment(fragment_type& frag, nsFragmentRequest which, PRUint32 offset) + { + substring_type* s = concrete_self(); + switch (which) + { + case kFirstFragment: + case kLastFragment: + case kFragmentAt: + char_type* start; + s->BeginWriting(start); + frag.mStart = start; + frag.mEnd = start + s->Length(); + return frag.mStart + offset; + case kPrevFragment: + case kNextFragment: + default: + return 0; + } + } + }; + + + /** + * initialize the pointer to the canonical vtable... + */ + +const void *nsTObsoleteAString_CharT::sCanonicalVTable = nsTObsoleteAStringThunk_CharT::get_vptr(); diff --git a/src/libs/xpcom18a4/xpcom/string/src/nsTPromiseFlatString.cpp b/src/libs/xpcom18a4/xpcom/string/src/nsTPromiseFlatString.cpp new file mode 100644 index 00000000..bf0bfc32 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/src/nsTPromiseFlatString.cpp @@ -0,0 +1,66 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* ***** 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 IBM Corporation. + * Portions created by IBM Corporation are Copyright (C) 2003 + * IBM Corporation. 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 ***** */ + +void +nsTPromiseFlatString_CharT::Init(const substring_type& str) + { + // we have to manually set this here since we are being called on an + // unitialized object. + mVTable = nsTObsoleteAString_CharT::sCanonicalVTable; + + if (str.IsTerminated()) + { + mData = NS_CONST_CAST(char_type*, str.Data()); + mLength = str.Length(); + mFlags = F_TERMINATED; // does not promote F_VOIDED + } + else + { + Assign(str); + } + } + + // this function is non-inline to minimize codesize +void +nsTPromiseFlatString_CharT::Init(const abstract_string_type& readable) + { + if (readable.mVTable == nsTObsoleteAString_CharT::sCanonicalVTable) + Init(*readable.AsSubstring()); + else + Init(readable.ToSubstring()); + } diff --git a/src/libs/xpcom18a4/xpcom/string/src/nsTString.cpp b/src/libs/xpcom18a4/xpcom/string/src/nsTString.cpp new file mode 100644 index 00000000..84911f5f --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/src/nsTString.cpp @@ -0,0 +1,63 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* ***** 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 IBM Corporation. + * Portions created by IBM Corporation are Copyright (C) 2003 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * Johnny Stenback + * + * 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 ***** */ + +NS_COM nsTAdoptingString_CharT& +nsTAdoptingString_CharT::operator=( const self_type& str ) + { + // This'll violate the constness of this argument, that's just + // the nature of this class... + self_type* mutable_str = NS_CONST_CAST(self_type*, &str); + + if (str.mFlags & F_OWNED) + { + Adopt(str.mData, str.mLength); + + // Make str forget the buffer we just took ownership of. + new (mutable_str) self_type(); + } + else + { + Assign(str); + + mutable_str->Truncate(); + } + + return *this; + } + diff --git a/src/libs/xpcom18a4/xpcom/string/src/nsTStringComparator.cpp b/src/libs/xpcom18a4/xpcom/string/src/nsTStringComparator.cpp new file mode 100644 index 00000000..6d2645a1 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/src/nsTStringComparator.cpp @@ -0,0 +1,79 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* ***** 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 IBM Corporation. + * Portions created by IBM Corporation are Copyright (C) 2003 + * IBM Corporation. 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 ***** */ + +NS_COM int +Compare( const nsTAString_CharT& lhs, const nsTAString_CharT& rhs, const nsTStringComparator_CharT& comp ) + { + typedef nsTAString_CharT::size_type size_type; + + if ( &lhs == &rhs ) + return 0; + + nsTAString_CharT::const_iterator leftIter, rightIter; + lhs.BeginReading(leftIter); + rhs.BeginReading(rightIter); + + size_type lLength = leftIter.size_forward(); + size_type rLength = rightIter.size_forward(); + size_type lengthToCompare = NS_MIN(lLength, rLength); + + int result; + if ( (result = comp(leftIter.get(), rightIter.get(), lengthToCompare)) == 0 ) + { + if ( lLength < rLength ) + result = -1; + else if ( rLength < lLength ) + result = 1; + else + result = 0; + } + + return result; + } + +int +nsTDefaultStringComparator_CharT::operator()( const char_type* lhs, const char_type* rhs, PRUint32 aLength ) const + { + return nsCharTraits::compare(lhs, rhs, aLength); + } + +int +nsTDefaultStringComparator_CharT::operator()( char_type lhs, char_type rhs) const + { + return lhs - rhs; + } diff --git a/src/libs/xpcom18a4/xpcom/string/src/nsTStringObsolete.cpp b/src/libs/xpcom18a4/xpcom/string/src/nsTStringObsolete.cpp new file mode 100644 index 00000000..5ed065ad --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/src/nsTStringObsolete.cpp @@ -0,0 +1,518 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* ***** 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 IBM Corporation. + * Portions created by IBM Corporation are Copyright (C) 2003 + * IBM Corporation. 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 ***** */ + + + + /** + * nsTString::Find + * + * aOffset specifies starting index + * aCount specifies number of string compares (iterations) + */ + +PRInt32 +nsTString_CharT::Find( const nsCString& aString, PRBool aIgnoreCase, PRInt32 aOffset, PRInt32 aCount) const + { + // this method changes the meaning of aOffset and aCount: + Find_ComputeSearchRange(mLength, aString.Length(), aOffset, aCount); + + PRInt32 result = FindSubstring(mData + aOffset, aCount, aString.get(), aString.Length(), aIgnoreCase); + if (result != kNotFound) + result += aOffset; + return result; + } + +PRInt32 +nsTString_CharT::Find( const char* aString, PRBool aIgnoreCase, PRInt32 aOffset, PRInt32 aCount) const + { + return Find(nsDependentCString(aString), aIgnoreCase, aOffset, aCount); + } + + + /** + * nsTString::RFind + * + * aOffset specifies starting index + * aCount specifies number of string compares (iterations) + */ + +PRInt32 +nsTString_CharT::RFind( const nsCString& aString, PRBool aIgnoreCase, PRInt32 aOffset, PRInt32 aCount) const + { + // this method changes the meaning of aOffset and aCount: + RFind_ComputeSearchRange(mLength, aString.Length(), aOffset, aCount); + + PRInt32 result = RFindSubstring(mData + aOffset, aCount, aString.get(), aString.Length(), aIgnoreCase); + if (result != kNotFound) + result += aOffset; + return result; + } + +PRInt32 +nsTString_CharT::RFind( const char* aString, PRBool aIgnoreCase, PRInt32 aOffset, PRInt32 aCount) const + { + return RFind(nsDependentCString(aString), aIgnoreCase, aOffset, aCount); + } + + + /** + * nsTString::RFindChar + */ + +PRInt32 +nsTString_CharT::RFindChar( PRUnichar aChar, PRInt32 aOffset, PRInt32 aCount) const + { + return nsBufferRoutines::rfind_char(mData, mLength, aOffset, aChar, aCount); + } + + + /** + * nsTString::FindCharInSet + */ + +PRInt32 +nsTString_CharT::FindCharInSet( const char* aSet, PRInt32 aOffset ) const + { + if (aOffset < 0) + aOffset = 0; + else if (aOffset >= PRInt32(mLength)) + return kNotFound; + + PRInt32 result = ::FindCharInSet(mData + aOffset, mLength - aOffset, aSet); + if (result != kNotFound) + result += aOffset; + return result; + } + + + /** + * nsTString::RFindCharInSet + */ + +PRInt32 +nsTString_CharT::RFindCharInSet( const CharT* aSet, PRInt32 aOffset ) const + { + // We want to pass a "data length" to ::RFindCharInSet + if (aOffset < 0 || aOffset > PRInt32(mLength)) + aOffset = mLength; + else + ++aOffset; + + return ::RFindCharInSet(mData, aOffset, aSet); + } + + + // it's a shame to replicate this code. it was done this way in the past + // to help performance. this function also gets to keep the rickg style + // indentation :-/ +PRInt32 +nsTString_CharT::ToInteger( PRInt32* aErrorCode, PRUint32 aRadix ) const +{ + CharT* cp=mData; + PRInt32 theRadix=10; // base 10 unless base 16 detected, or overriden (aRadix != kAutoDetect) + PRInt32 result=0; + PRBool negate=PR_FALSE; + CharT theChar=0; + + //initial value, override if we find an integer + *aErrorCode=NS_ERROR_ILLEGAL_VALUE; + + if(cp) { + + //begin by skipping over leading chars that shouldn't be part of the number... + + CharT* endcp=cp+mLength; + PRBool done=PR_FALSE; + + while((cp='A') && (theChar<='F')) { + if(10==theRadix) { + if(kAutoDetect==aRadix){ + theRadix=16; + cp=first; //backup + result=0; + haveValue = PR_FALSE; + } + else { + *aErrorCode=NS_ERROR_ILLEGAL_VALUE; + result=0; + break; + } + } + else { + result = (theRadix * result) + ((theChar-'A')+10); + haveValue = PR_TRUE; + } + } + else if((theChar>='a') && (theChar<='f')) { + if(10==theRadix) { + if(kAutoDetect==aRadix){ + theRadix=16; + cp=first; //backup + result=0; + haveValue = PR_FALSE; + } + else { + *aErrorCode=NS_ERROR_ILLEGAL_VALUE; + result=0; + break; + } + } + else { + result = (theRadix * result) + ((theChar-'a')+10); + haveValue = PR_TRUE; + } + } + else if((('X'==theChar) || ('x'==theChar)) && (!haveValue || result == 0)) { + continue; + } + else if((('#'==theChar) || ('+'==theChar)) && !haveValue) { + continue; + } + else { + //we've encountered a char that's not a legal number or sign + break; + } + } //while + if(negate) + result=-result; + } //if + } + return result; +} + + + /** + * nsTString::Mid + */ + +PRUint32 +nsTString_CharT::Mid( self_type& aResult, index_type aStartPos, size_type aLengthToCopy ) const + { + if (aStartPos == 0 && aLengthToCopy >= mLength) + aResult = *this; + else + aResult = Substring(*this, aStartPos, aLengthToCopy); + + return aResult.mLength; + } + + + /** + * nsTString::SetCharAt + */ + +PRBool +nsTString_CharT::SetCharAt( PRUnichar aChar, PRUint32 aIndex ) + { + if (aIndex >= mLength) + return PR_FALSE; + + EnsureMutable(); + + mData[aIndex] = CharT(aChar); + return PR_TRUE; + } + + + /** + * nsTString::StripChars,StripChar,StripWhitespace + */ + +void +nsTString_CharT::StripChars( const char* aSet ) + { + EnsureMutable(); + mLength = nsBufferRoutines::strip_chars(mData, mLength, aSet); + } + +void +nsTString_CharT::StripChar( char_type aChar, PRInt32 aOffset ) + { + if (mLength == 0 || aOffset >= PRInt32(mLength)) + return; + + EnsureMutable(); // XXX do this lazily? + + // XXXdarin this code should defer writing until necessary. + + char_type* to = mData + aOffset; + char_type* from = mData + aOffset; + char_type* end = mData + mLength; + + while (from < end) + { + char_type theChar = *from++; + if (aChar != theChar) + *to++ = theChar; + } + *to = char_type(0); // add the null + mLength = to - mData; + } + +void +nsTString_CharT::StripWhitespace() + { + StripChars(kWhitespace); + } + + + /** + * nsTString::ReplaceChar,ReplaceSubstring + */ + +void +nsTString_CharT::ReplaceChar( char_type aOldChar, char_type aNewChar ) + { + EnsureMutable(); // XXX do this lazily? + + for (PRUint32 i=0; i 2 && mData[0] == mData[mLength - 1] && + (mData[0] == '\'' || mData[0] == '"')) + { + ++start; + --end; + } + + PRUint32 setLen = nsCharTraits::length(aSet); + + if (aTrimLeading) + { + PRUint32 cutStart = start - mData; + PRUint32 cutLength = 0; + + // walk forward from start to end + for (; start != end; ++start, ++cutLength) + { + PRInt32 pos = FindChar1(aSet, setLen, 0, *start, setLen); + if (pos == kNotFound) + break; + } + + if (cutLength) + { + Cut(cutStart, cutLength); + + // reset iterators + start = mData + cutStart; + end = mData + mLength - cutStart; + } + } + + if (aTrimTrailing) + { + PRUint32 cutEnd = end - mData; + PRUint32 cutLength = 0; + + // walk backward from end to start + --end; + for (; end >= start; --end, ++cutLength) + { + PRInt32 pos = FindChar1(aSet, setLen, 0, *end, setLen); + if (pos == kNotFound) + break; + } + + if (cutLength) + Cut(cutEnd - cutLength, cutLength); + } + } + + + /** + * nsTString::CompressWhitespace + */ + +void +nsTString_CharT::CompressWhitespace( PRBool aTrimLeading, PRBool aTrimTrailing ) + { + const char* set = kWhitespace; + + ReplaceChar(set, ' '); + Trim(set, aTrimLeading, aTrimTrailing); + + // this one does some questionable fu... just copying the old code! + mLength = nsBufferRoutines::compress_chars(mData, mLength, set); + } + + + /** + * nsTString::AssignWithConversion + */ + +void +nsTString_CharT::AssignWithConversion( const incompatible_char_type* aData, PRInt32 aLength ) + { + // for compatibility with the old string implementation, we need to allow + // for a NULL input buffer :-( + if (!aData) + { + Truncate(); + } + else + { + if (aLength < 0) + aLength = nsCharTraits::length(aData); + + AssignWithConversion(Substring(aData, aData + aLength)); + } + } + + + /** + * nsTString::AppendWithConversion + */ + +void +nsTString_CharT::AppendWithConversion( const incompatible_char_type* aData, PRInt32 aLength ) + { + // for compatibility with the old string implementation, we need to allow + // for a NULL input buffer :-( + if (aData) + { + if (aLength < 0) + aLength = nsCharTraits::length(aData); + + AppendWithConversion(Substring(aData, aData + aLength)); + } + } diff --git a/src/libs/xpcom18a4/xpcom/string/src/nsTSubstring.cpp b/src/libs/xpcom18a4/xpcom/string/src/nsTSubstring.cpp new file mode 100644 index 00000000..e36b1863 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/src/nsTSubstring.cpp @@ -0,0 +1,656 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* ***** 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 IBM Corporation. + * Portions created by IBM Corporation are Copyright (C) 2003 + * IBM Corporation. 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 ***** */ + + + /** + * helper function for down-casting a nsTSubstring to a nsTFixedString. + */ +inline const nsTFixedString_CharT* +AsFixedString( const nsTSubstring_CharT* s ) + { + return NS_STATIC_CAST(const nsTFixedString_CharT*, s); + } + + + /** + * this function is called to prepare mData for writing. the given capacity + * indicates the required minimum storage size for mData, in sizeof(char_type) + * increments. this function returns true if the operation succeeds. it also + * returns the old data and old flags members if mData is newly allocated. + * the old data must be released by the caller. + */ +PRBool +nsTSubstring_CharT::MutatePrep( size_type capacity, char_type** oldData, PRUint32* oldFlags ) + { + // initialize to no old data + *oldData = nsnull; + *oldFlags = 0; + + size_type curCapacity = Capacity(); + + // |curCapacity == size_type(-1)| means that the buffer is immutable, so we + // need to allocate a new buffer. we cannot use the existing buffer even + // though it might be large enough. + + if (curCapacity != size_type(-1)) + { + if (capacity <= curCapacity) + return PR_TRUE; + + if (curCapacity > 0) + { + // use doubling algorithm when forced to increase available capacity, + // but always start out with exactly the requested amount. + PRUint32 temp = curCapacity; + while (temp < capacity) + temp <<= 1; + capacity = temp; + } + } + + // + // several cases: + // + // (1) we have a shared buffer (mFlags & F_SHARED) + // (2) we have an owned buffer (mFlags & F_OWNED) + // (3) we have a fixed buffer (mFlags & F_FIXED) + // (4) we have a readonly buffer + // + // requiring that we in some cases preserve the data before creating + // a new buffer complicates things just a bit ;-) + // + + size_type storageSize = (capacity + 1) * sizeof(char_type); + + // case #1 + if (mFlags & F_SHARED) + { + nsStringHeader* hdr = nsStringHeader::FromData(mData); + if (!hdr->IsReadonly()) + { + nsStringHeader *newHdr = nsStringHeader::Realloc(hdr, storageSize); + if (newHdr) + { + hdr = newHdr; + mData = (char_type*) hdr->Data(); + return PR_TRUE; + } + hdr->Release(); + // out of memory!! put us in a consistent state at least. + mData = NS_CONST_CAST(char_type*, char_traits::sEmptyBuffer); + mLength = 0; + SetDataFlags(F_TERMINATED); + return PR_FALSE; + } + } + + char_type* newData; + PRUint32 newDataFlags; + + // if we have a fixed buffer of sufficient size, then use it. this helps + // avoid heap allocations. + if ((mFlags & F_CLASS_FIXED) && (capacity < AsFixedString(this)->mFixedCapacity)) + { + newData = AsFixedString(this)->mFixedBuf; + newDataFlags = F_TERMINATED | F_FIXED; + } + else + { + // if we reach here then, we must allocate a new buffer. we cannot + // make use of our F_OWNED or F_FIXED buffers because they are not + // large enough. + + nsStringHeader* newHdr = nsStringHeader::Alloc(storageSize); + if (!newHdr) + return PR_FALSE; // we are still in a consistent state + + newData = (char_type*) newHdr->Data(); + newDataFlags = F_TERMINATED | F_SHARED; + } + + // save old data and flags + *oldData = mData; + *oldFlags = mFlags; + + mData = newData; + SetDataFlags(newDataFlags); + + // mLength does not change + + // though we are not necessarily terminated at the moment, now is probably + // still the best time to set F_TERMINATED. + + return PR_TRUE; + } + +void +nsTSubstring_CharT::Finalize() + { + ::ReleaseData(mData, mFlags); + // mData, mLength, and mFlags are purposefully left dangling + } + +void +nsTSubstring_CharT::ReplacePrep( index_type cutStart, size_type cutLen, size_type fragLen ) + { + // bound cut length + cutLen = NS_MIN(cutLen, mLength - cutStart); + + PRUint32 newLen = mLength - cutLen + fragLen; + + char_type* oldData; + PRUint32 oldFlags; + if (!MutatePrep(newLen, &oldData, &oldFlags)) + return; // XXX out-of-memory error occured! + + if (oldData) + { + // determine whether or not we need to copy part of the old string + // over to the new string. + + if (cutStart > 0) + { + // copy prefix from old string + char_traits::copy(mData, oldData, cutStart); + } + + if (cutStart + cutLen < mLength) + { + // copy suffix from old string to new offset + size_type from = cutStart + cutLen; + size_type fromLen = mLength - from; + PRUint32 to = cutStart + fragLen; + char_traits::copy(mData + to, oldData + from, fromLen); + } + + ::ReleaseData(oldData, oldFlags); + } + else + { + // original data remains intact + + // determine whether or not we need to move part of the existing string + // to make room for the requested hole. + if (fragLen != cutLen && cutStart + cutLen < mLength) + { + PRUint32 from = cutStart + cutLen; + PRUint32 fromLen = mLength - from; + PRUint32 to = cutStart + fragLen; + char_traits::move(mData + to, mData + from, fromLen); + } + } + + // add null terminator (mutable mData always has room for the null- + // terminator). + mData[newLen] = char_type(0); + mLength = newLen; + } + +nsTSubstring_CharT::size_type +nsTSubstring_CharT::Capacity() const + { + // return size_type(-1) to indicate an immutable buffer + + size_type capacity; + if (mFlags & F_SHARED) + { + // if the string is readonly, then we pretend that it has no capacity. + nsStringHeader* hdr = nsStringHeader::FromData(mData); + if (hdr->IsReadonly()) + capacity = size_type(-1); + else + capacity = (hdr->StorageSize() / sizeof(char_type)) - 1; + } + else if (mFlags & F_FIXED) + { + capacity = AsFixedString(this)->mFixedCapacity; + } + else if (mFlags & F_OWNED) + { + // we don't store the capacity of an adopted buffer because that would + // require an additional member field. the best we can do is base the + // capacity on our length. remains to be seen if this is the right + // trade-off. + capacity = mLength; + } + else + { + capacity = size_type(-1); + } + + return capacity; + } + +void +nsTSubstring_CharT::EnsureMutable() + { + if (mFlags & (F_FIXED | F_OWNED)) + return; + if ((mFlags & F_SHARED) && !nsStringHeader::FromData(mData)->IsReadonly()) + return; + + // promote to a shared string buffer + Assign(string_type(mData, mLength)); + } + +// --------------------------------------------------------------------------- + +void +nsTSubstring_CharT::Assign( const char_type* data, size_type length ) + { + // unfortunately, some callers pass null :-( + if (!data) + { + Truncate(); + return; + } + + if (length == size_type(-1)) + length = char_traits::length(data); + + if (IsDependentOn(data, data + length)) + { + // take advantage of sharing here... + Assign(string_type(data, length)); + return; + } + + ReplacePrep(0, mLength, length); + char_traits::copy(mData, data, length); + } + +void +nsTSubstring_CharT::AssignASCII( const char* data, size_type length ) + { + // A Unicode string can't depend on an ASCII string buffer, + // so this dependence check only applies to CStrings. +#ifdef CharT_is_char + if (IsDependentOn(data, data + length)) + { + // take advantage of sharing here... + Assign(string_type(data, length)); + return; + } +#endif + + ReplacePrep(0, mLength, length); + char_traits::copyASCII(mData, data, length); + } + +void +nsTSubstring_CharT::AssignASCII( const char* data ) + { + AssignASCII(data, strlen(data)); + } + +void +nsTSubstring_CharT::Assign( const self_type& str ) + { + // |str| could be sharable. we need to check its flags to know how to + // deal with it. + + if (&str == this) + return; + + if (str.mFlags & F_SHARED) + { + // nice! we can avoid a string copy :-) + + // |str| should be null-terminated + NS_ASSERTION(str.mFlags & F_TERMINATED, "shared, but not terminated"); + + ::ReleaseData(mData, mFlags); + + mData = str.mData; + mLength = str.mLength; + SetDataFlags(F_TERMINATED | F_SHARED); + + // get an owning reference to the mData + nsStringHeader::FromData(mData)->AddRef(); + } + else if (str.mFlags & F_VOIDED) + { + // inherit the F_VOIDED attribute + SetIsVoid(PR_TRUE); + } + else + { + // else, treat this like an ordinary assignment. + Assign(str.Data(), str.Length()); + } + } + +void +nsTSubstring_CharT::Assign( const substring_tuple_type& tuple ) + { + if (tuple.IsDependentOn(mData, mData + mLength)) + { + // take advantage of sharing here... + Assign(string_type(tuple)); + return; + } + + size_type length = tuple.Length(); + + ReplacePrep(0, mLength, length); + if (length) + tuple.WriteTo(mData, length); + } + + // this is non-inline to reduce codesize at the callsite +void +nsTSubstring_CharT::Assign( const abstract_string_type& readable ) + { + // promote to string if possible to take advantage of sharing + if (readable.mVTable == nsTObsoleteAString_CharT::sCanonicalVTable) + Assign(*readable.AsSubstring()); + else + Assign(readable.ToSubstring()); + } + + +void +nsTSubstring_CharT::Adopt( char_type* data, size_type length ) + { + if (data) + { + ::ReleaseData(mData, mFlags); + + if (length == size_type(-1)) + length = char_traits::length(data); + + mData = data; + mLength = length; + SetDataFlags(F_TERMINATED | F_OWNED); + + STRING_STAT_INCREMENT(Adopt); + } + else + { + SetIsVoid(PR_TRUE); + } + } + + +void +nsTSubstring_CharT::Replace( index_type cutStart, size_type cutLength, const char_type* data, size_type length ) + { + // unfortunately, some callers pass null :-( + if (!data) + { + length = 0; + } + else + { + if (length == size_type(-1)) + length = char_traits::length(data); + + if (IsDependentOn(data, data + length)) + { + nsTAutoString_CharT temp(data, length); + Replace(cutStart, cutLength, temp); + return; + } + } + + cutStart = PR_MIN(cutStart, Length()); + + ReplacePrep(cutStart, cutLength, length); + + if (length > 0) + char_traits::copy(mData + cutStart, data, length); + } + +void +nsTSubstring_CharT::ReplaceASCII( index_type cutStart, size_type cutLength, const char* data, size_type length ) + { + if (length == size_type(-1)) + length = strlen(data); + + // A Unicode string can't depend on an ASCII string buffer, + // so this dependence check only applies to CStrings. +#ifdef CharT_is_char + if (IsDependentOn(data, data + length)) + { + nsTAutoString_CharT temp(data, length); + Replace(cutStart, cutLength, temp); + return; + } +#endif + + cutStart = PR_MIN(cutStart, Length()); + + ReplacePrep(cutStart, cutLength, length); + + if (length > 0) + char_traits::copyASCII(mData + cutStart, data, length); + } + +void +nsTSubstring_CharT::Replace( index_type cutStart, size_type cutLength, const substring_tuple_type& tuple ) + { + if (tuple.IsDependentOn(mData, mData + mLength)) + { + nsTAutoString_CharT temp(tuple); + Replace(cutStart, cutLength, temp); + return; + } + + size_type length = tuple.Length(); + + cutStart = PR_MIN(cutStart, Length()); + + ReplacePrep(cutStart, cutLength, length); + + if (length > 0) + tuple.WriteTo(mData + cutStart, length); + } + +void +nsTSubstring_CharT::Replace( index_type cutStart, size_type cutLength, const abstract_string_type& readable ) + { + Replace(cutStart, cutLength, readable.ToSubstring()); + } + +void +nsTSubstring_CharT::SetCapacity( size_type capacity ) + { + // capacity does not include room for the terminating null char + + // if our capacity is reduced to zero, then free our buffer. + if (capacity == 0) + { + ::ReleaseData(mData, mFlags); + mData = NS_CONST_CAST(char_type*, char_traits::sEmptyBuffer); + mLength = 0; + SetDataFlags(F_TERMINATED); + } + else + { + char_type* oldData; + PRUint32 oldFlags; + if (!MutatePrep(capacity, &oldData, &oldFlags)) + return; // XXX out-of-memory error occured! + + // compute new string length + size_type newLen = NS_MIN(mLength, capacity); + + if (oldData) + { + // preserve old data + if (mLength > 0) + char_traits::copy(mData, oldData, newLen); + + ::ReleaseData(oldData, oldFlags); + } + + // adjust mLength if our buffer shrunk down in size + if (newLen < mLength) + mLength = newLen; + + // always null-terminate here, even if the buffer got longer. this is + // for backwards compat with the old string implementation. + mData[capacity] = char_type(0); + } + } + +void +nsTSubstring_CharT::SetLength( size_type length ) + { + SetCapacity(length); + mLength = length; + } + +void +nsTSubstring_CharT::SetIsVoid( PRBool val ) + { + if (val) + { + Truncate(); + mFlags |= F_VOIDED; + } + else + { + mFlags &= ~F_VOIDED; + } + } + +PRBool +nsTSubstring_CharT::Equals( const self_type& str ) const + { + return mLength == str.mLength && char_traits::compare(mData, str.mData, mLength) == 0; + } + +PRBool +nsTSubstring_CharT::Equals( const self_type& str, const comparator_type& comp ) const + { + return mLength == str.mLength && comp(mData, str.mData, mLength) == 0; + } + +PRBool +nsTSubstring_CharT::Equals( const abstract_string_type& readable ) const + { + const char_type* data; + size_type length = readable.GetReadableBuffer(&data); + + return mLength == length && char_traits::compare(mData, data, mLength) == 0; + } + +PRBool +nsTSubstring_CharT::Equals( const abstract_string_type& readable, const comparator_type& comp ) const + { + const char_type* data; + size_type length = readable.GetReadableBuffer(&data); + + return mLength == length && comp(mData, data, mLength) == 0; + } + +PRBool +nsTSubstring_CharT::Equals( const char_type* data ) const + { + // unfortunately, some callers pass null :-( + if (!data) + { + NS_NOTREACHED("null data pointer"); + return mLength == 0; + } + + // XXX avoid length calculation? + size_type length = char_traits::length(data); + return mLength == length && char_traits::compare(mData, data, mLength) == 0; + } + +PRBool +nsTSubstring_CharT::Equals( const char_type* data, const comparator_type& comp ) const + { + // unfortunately, some callers pass null :-( + if (!data) + { + NS_NOTREACHED("null data pointer"); + return mLength == 0; + } + + // XXX avoid length calculation? + size_type length = char_traits::length(data); + return mLength == length && comp(mData, data, mLength) == 0; + } + +PRBool +nsTSubstring_CharT::EqualsASCII( const char* data, size_type len ) const + { + return mLength == len && char_traits::compareASCII(mData, data, len) == 0; + } + +PRBool +nsTSubstring_CharT::EqualsASCII( const char* data ) const + { + return char_traits::compareASCIINullTerminated(mData, mLength, data) == 0; + } + +PRBool +nsTSubstring_CharT::LowerCaseEqualsASCII( const char* data, size_type len ) const + { + return mLength == len && char_traits::compareLowerCaseToASCII(mData, data, len) == 0; + } + +PRBool +nsTSubstring_CharT::LowerCaseEqualsASCII( const char* data ) const + { + return char_traits::compareLowerCaseToASCIINullTerminated(mData, mLength, data) == 0; + } + +nsTSubstring_CharT::size_type +nsTSubstring_CharT::CountChar( char_type c ) const + { + const char_type *start = mData; + const char_type *end = mData + mLength; + + return NS_COUNT(start, end, c); + } + +PRInt32 +nsTSubstring_CharT::FindChar( char_type c, index_type offset ) const + { + if (offset < mLength) + { + const char_type* result = char_traits::find(mData + offset, mLength - offset, c); + if (result) + return result - mData; + } + return -1; + } diff --git a/src/libs/xpcom18a4/xpcom/string/src/nsTSubstringTuple.cpp b/src/libs/xpcom18a4/xpcom/string/src/nsTSubstringTuple.cpp new file mode 100644 index 00000000..7fff5175 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/src/nsTSubstringTuple.cpp @@ -0,0 +1,127 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* ***** 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 IBM Corporation. + * Portions created by IBM Corporation are Copyright (C) 2003 + * IBM Corporation. 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 ***** */ + + + /** + * computes the aggregate string length + */ + +nsTSubstringTuple_CharT::size_type +nsTSubstringTuple_CharT::Length() const + { + PRUint32 len; + if (mHead) + len = mHead->Length(); + else + len = TO_SUBSTRING(mFragA).Length(); + + return len + TO_SUBSTRING(mFragB).Length(); + } + + + /** + * writes the aggregate string to the given buffer. bufLen is assumed + * to be equal to or greater than the value returned by the Length() + * method. the string written to |buf| is not null-terminated. + */ + +void +nsTSubstringTuple_CharT::WriteTo( char_type *buf, PRUint32 bufLen ) const + { + const substring_type& b = TO_SUBSTRING(mFragB); + + NS_ASSERTION(bufLen >= b.Length(), "buffer too small"); + PRUint32 headLen = bufLen - b.Length(); + if (mHead) + { + mHead->WriteTo(buf, headLen); + } + else + { + const substring_type& a = TO_SUBSTRING(mFragA); + + NS_ASSERTION(a.Length() == headLen, "buffer incorrectly sized"); + char_traits::copy(buf, a.Data(), a.Length()); + } + + char_traits::copy(buf + headLen, b.Data(), b.Length()); + +#if 0 + // we need to write out data into |buf|, ending at |buf+bufLen|. so our + // data needs to precede |buf+bufLen| exactly. we trust that the buffer + // was properly sized! + + const substring_type& b = TO_SUBSTRING(mFragB); + + NS_ASSERTION(bufLen >= b.Length(), "buffer is too small"); + char_traits::copy(buf + bufLen - b.Length(), b.Data(), b.Length()); + + bufLen -= b.Length(); + + if (mHead) + { + mHead->WriteTo(buf, bufLen); + } + else + { + const substring_type& a = TO_SUBSTRING(mFragA); + NS_ASSERTION(bufLen == a.Length(), "buffer is too small"); + char_traits::copy(buf, a.Data(), a.Length()); + } +#endif + } + + + /** + * returns true if this tuple is dependent on (i.e., overlapping with) + * the given char sequence. + */ + +PRBool +nsTSubstringTuple_CharT::IsDependentOn( const char_type *start, const char_type *end ) const + { + // we start with the right-most fragment since it is faster to check. + + if (TO_SUBSTRING(mFragB).IsDependentOn(start, end)) + return PR_TRUE; + + if (mHead) + return mHead->IsDependentOn(start, end); + + return TO_SUBSTRING(mFragA).IsDependentOn(start, end); + } diff --git a/src/libs/xpcom18a4/xpcom/stub/nsStringAPI.cpp b/src/libs/xpcom18a4/xpcom/stub/nsStringAPI.cpp new file mode 100644 index 00000000..ca9a76e4 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/stub/nsStringAPI.cpp @@ -0,0 +1,261 @@ +/* vim:set ts=2 sw=2 et cindent: */ +/* ***** 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 IBM Corporation. + * Portions created by IBM Corporation are Copyright (C) 2003 + * IBM Corporation. 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 "nsString.h" +#include "nsCharTraits.h" + +#define NS_STRINGAPI_IMPL +#include "nsStringAPI.h" +#include "nsNativeCharsetUtils.h" + +/* ------------------------------------------------------------------------- */ + +NS_STRINGAPI(nsresult) +NS_StringContainerInit(nsStringContainer &aContainer) +{ + NS_ASSERTION(sizeof(nsStringContainer) >= sizeof(nsString), + "nsStringContainer is not large enough"); + + // use placement new to avoid heap allocating nsString object + new (&aContainer) nsString(); + + return NS_OK; +} + +NS_STRINGAPI(void) +NS_StringContainerFinish(nsStringContainer &aContainer) +{ + // call the nsString dtor + NS_REINTERPRET_CAST(nsString *, &aContainer)->~nsString(); +} + +/* ------------------------------------------------------------------------- */ + +NS_STRINGAPI(PRUint32) +NS_StringGetData(const nsAString &aStr, const PRUnichar **aData, + PRBool *aTerminated) +{ + if (aTerminated) + *aTerminated = aStr.IsTerminated(); + + nsAString::const_iterator begin; + aStr.BeginReading(begin); + *aData = begin.get(); + return begin.size_forward(); +} + +NS_STRINGAPI(PRUnichar *) +NS_StringCloneData(const nsAString &aStr) +{ + return ToNewUnicode(aStr); +} + +NS_STRINGAPI(nsresult) +NS_StringSetData(nsAString &aStr, const PRUnichar *aData, PRUint32 aDataLength) +{ + aStr.Assign(aData, aDataLength); + return NS_OK; // XXX report errors +} + +NS_STRINGAPI(nsresult) +NS_StringSetDataRange(nsAString &aStr, + PRUint32 aCutOffset, PRUint32 aCutLength, + const PRUnichar *aData, PRUint32 aDataLength) +{ + if (aCutOffset == PR_UINT32_MAX) + { + // append case + if (aData) + aStr.Append(aData, aDataLength); + return NS_OK; // XXX report errors + } + + if (aCutLength == PR_UINT32_MAX) + aCutLength = aStr.Length() - aCutOffset; + + if (aData) + { + if (aDataLength == PR_UINT32_MAX) + aStr.Replace(aCutOffset, aCutLength, nsDependentString(aData)); + else + aStr.Replace(aCutOffset, aCutLength, Substring(aData, aData + aDataLength)); + } + else + aStr.Cut(aCutOffset, aCutLength); + + return NS_OK; // XXX report errors +} + +NS_STRINGAPI(nsresult) +NS_StringCopy(nsAString &aDest, const nsAString &aSrc) +{ + aDest.Assign(aSrc); + return NS_OK; // XXX report errors +} + +/* ------------------------------------------------------------------------- */ + +NS_STRINGAPI(nsresult) +NS_CStringContainerInit(nsCStringContainer &aContainer) +{ + NS_ASSERTION(sizeof(nsCStringContainer) >= sizeof(nsCString), + "nsCStringContainer is not large enough"); + + // use placement new to avoid heap allocating nsCString object + new (&aContainer) nsCString(); + + return NS_OK; +} + +NS_STRINGAPI(void) +NS_CStringContainerFinish(nsCStringContainer &aContainer) +{ + // call the nsCString dtor + NS_REINTERPRET_CAST(nsCString *, &aContainer)->~nsCString(); +} + +/* ------------------------------------------------------------------------- */ + +NS_STRINGAPI(PRUint32) +NS_CStringGetData(const nsACString &aStr, const char **aData, + PRBool *aTerminated) +{ + if (aTerminated) + *aTerminated = aStr.IsTerminated(); + + nsACString::const_iterator begin; + aStr.BeginReading(begin); + *aData = begin.get(); + return begin.size_forward(); +} + +NS_STRINGAPI(char *) +NS_CStringCloneData(const nsACString &aStr) +{ + return ToNewCString(aStr); +} + +NS_STRINGAPI(nsresult) +NS_CStringSetData(nsACString &aStr, const char *aData, PRUint32 aDataLength) +{ + aStr.Assign(aData, aDataLength); + return NS_OK; // XXX report errors +} + +NS_STRINGAPI(nsresult) +NS_CStringSetDataRange(nsACString &aStr, + PRUint32 aCutOffset, PRUint32 aCutLength, + const char *aData, PRUint32 aDataLength) +{ + if (aCutOffset == PR_UINT32_MAX) + { + // append case + if (aData) + aStr.Append(aData, aDataLength); + return NS_OK; // XXX report errors + } + + if (aCutLength == PR_UINT32_MAX) + aCutLength = aStr.Length() - aCutOffset; + + if (aData) + { + if (aDataLength == PR_UINT32_MAX) + aStr.Replace(aCutOffset, aCutLength, nsDependentCString(aData)); + else + aStr.Replace(aCutOffset, aCutLength, Substring(aData, aData + aDataLength)); + } + else + aStr.Cut(aCutOffset, aCutLength); + + return NS_OK; // XXX report errors +} + +NS_STRINGAPI(nsresult) +NS_CStringCopy(nsACString &aDest, const nsACString &aSrc) +{ + aDest.Assign(aSrc); + return NS_OK; // XXX report errors +} + +/* ------------------------------------------------------------------------- */ + +NS_STRINGAPI(nsresult) +NS_CStringToUTF16(const nsACString &aSrc, + nsCStringEncoding aSrcEncoding, + nsAString &aDest) +{ + switch (aSrcEncoding) + { + case NS_CSTRING_ENCODING_ASCII: + CopyASCIItoUTF16(aSrc, aDest); + break; + case NS_CSTRING_ENCODING_UTF8: + CopyUTF8toUTF16(aSrc, aDest); + break; + case NS_CSTRING_ENCODING_NATIVE_FILESYSTEM: + NS_CopyNativeToUnicode(aSrc, aDest); + break; + default: + return NS_ERROR_NOT_IMPLEMENTED; + } + + return NS_OK; // XXX report errors +} + +NS_STRINGAPI(nsresult) +NS_UTF16ToCString(const nsAString &aSrc, + nsCStringEncoding aDestEncoding, + nsACString &aDest) +{ + switch (aDestEncoding) + { + case NS_CSTRING_ENCODING_ASCII: + LossyCopyUTF16toASCII(aSrc, aDest); + break; + case NS_CSTRING_ENCODING_UTF8: + CopyUTF16toUTF8(aSrc, aDest); + break; + case NS_CSTRING_ENCODING_NATIVE_FILESYSTEM: + NS_CopyUnicodeToNative(aSrc, aDest); + break; + default: + return NS_ERROR_NOT_IMPLEMENTED; + } + + return NS_OK; // XXX report errors +} diff --git a/src/libs/xpcom18a4/xpcom/tests/.cvsignore b/src/libs/xpcom18a4/xpcom/tests/.cvsignore new file mode 100644 index 00000000..d01075e3 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/.cvsignore @@ -0,0 +1,31 @@ +CvtURL +FilesTest +Makefile +PropertiesTest +RegFactory +SizeTest01 +SizeTest02 +SizeTest03 +SizeTest04 +SizeTest05 +SizeTest06 +TestAtoms +TestAutoLock +TestBuffers +TestCOMPtr +TestCOMPtrEq +TestArray +TestCRT +TestFactory +TestID +TestObserverService +TestPermanentAtoms +TestPipes +TestThreads +TestVoidBTree +TestXPIDLString +TestServMgr +nsIFileEnumerator +nsIFileTest +TestCallTemplates +TestDeque diff --git a/src/libs/xpcom18a4/xpcom/tests/CvtURL.cpp b/src/libs/xpcom18a4/xpcom/tests/CvtURL.cpp new file mode 100644 index 00000000..4dd052ac --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/CvtURL.cpp @@ -0,0 +1,126 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 +#include "nscore.h" +#include "nsIConverterInputStream.h" +#include "nsIURL.h" +#include "nsNetUtil.h" +#include "nsCRT.h" +#include "nsString.h" +#include "prprf.h" +#include "prtime.h" + +static nsString* ConvertCharacterSetName(const char* aName) +{ + return new nsString(NS_ConvertASCIItoUCS2(aName)); +} + +int main(int argc, char** argv) +{ + if (3 != argc) { + printf("usage: CvtURL url utf8\n"); + return -1; + } + + char* characterSetName = argv[2]; + nsString* cset = ConvertCharacterSetName(characterSetName); + if (NS_PTR_TO_INT32(cset) < 0) { + printf("illegal character set name: '%s'\n", characterSetName); + return -1; + } + + // Create url object + char* urlName = argv[1]; + nsIURI* url; + nsresult rv; + rv = NS_NewURI(&url, urlName); + if (NS_OK != rv) { + printf("invalid URL: '%s'\n", urlName); + return -1; + } + + // Get an input stream from the url + nsresult ec; + nsIInputStream* in; + ec = NS_OpenURI(&in, url); + if (nsnull == in) { + printf("open of url('%s') failed: error=%x\n", urlName, ec); + return -1; + } + + // Translate the input using the argument character set id into + // unicode + nsCOMPtr uin = + do_CreateInstance("@mozilla.org/intl/converter-input-stream;1", &rv); + if (NS_SUCCEEDED(rv)) + uin->Init(in, cset->get(), nsnull, PR_TRUE); + if (NS_OK != rv) { + printf("can't create converter input stream: %d\n", rv); + return -1; + } + + // Read the input and write some output + PRTime start = PR_Now(); + PRInt32 count = 0; + for (;;) { + PRUnichar buf[1000]; + PRUint32 nb; + ec = uin->Read(buf, 0, 1000, &nb); + if (NS_FAILED(ec)) { + printf("i/o error: %d\n", ec); + break; + } + if (nb == 0) break; // EOF + count += nb; + } + PRTime end = PR_Now(); + PRTime conversion, ustoms; + LL_I2L(ustoms, 1000); + LL_SUB(conversion, end, start); + LL_DIV(conversion, conversion, ustoms); + char buf[500]; + PR_snprintf(buf, sizeof(buf), + "converting and discarding %d bytes took %lldms", + count, conversion); + puts(buf); + + // Release the objects + in->Release(); + url->Release(); + + return 0; +} diff --git a/src/libs/xpcom18a4/xpcom/tests/Makefile.in b/src/libs/xpcom18a4/xpcom/tests/Makefile.in new file mode 100644 index 00000000..2bd730e9 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/Makefile.in @@ -0,0 +1,116 @@ +# +# ***** 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.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of 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 ***** + +DEPTH = ../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = xpcom +DIRS = dynamic services +ifeq ($(OS_ARCH),WINNT) +DIRS += windows +endif + +REQUIRES = \ + string \ + $(NULL) + +CPPSRCS = \ + nsIFileEnumerator.cpp \ + nsIFileTest.cpp \ + TestArray.cpp \ + TestAtoms.cpp \ + TestAutoLock.cpp \ + TestCallTemplates.cpp \ + TestCOMPtr.cpp \ + TestCOMPtrEq.cpp \ + TestCRT.cpp \ + TestFactory.cpp \ + TestHashtables.cpp \ + TestID.cpp \ + TestObserverService.cpp \ + TestPermanentAtoms.cpp \ + TestPipes.cpp \ + TestServMgr.cpp \ + TestThreads.cpp \ + TestXPIDLString.cpp \ + TestDeque.cpp \ + TestAutoPtr.cpp \ + TestMinStringAPI.cpp \ + TestStrings.cpp \ + $(NULL) + +#CPPSRCS += TimerTest.cpp + +SIMPLE_PROGRAMS = $(CPPSRCS:.cpp=$(BIN_SUFFIX)) + +include $(topsrcdir)/config/config.mk + +LIBS += \ + $(XPCOM_LIBS) \ + $(NSPR_LIBS) \ + $(NULL) + +# Needed to resolve __yylex (?) +ifeq ($(OS_ARCH)$(OS_RELEASE),FreeBSD2) +LIBS += -lpcap +endif + +include $(topsrcdir)/config/rules.mk + +LOCAL_INCLUDES = \ + -I$(srcdir)/../ds \ + -I$(srcdir)/services \ + $(NULL) + +ifeq ($(OS_ARCH),WINNT) +ifdef GNU_CXX +CXXFLAGS += -fexceptions +else +CXXFLAGS += -GX +endif +endif + +libs:: + $(INSTALL) $(srcdir)/test.properties $(DIST)/bin/res + +install:: + $(SYSINSTALL) $(IFLAGS1) $(srcdir)/test.properties $(DESTDIR)$(mozappdir)/res + diff --git a/src/libs/xpcom18a4/xpcom/tests/RegFactory.cpp b/src/libs/xpcom18a4/xpcom/tests/RegFactory.cpp new file mode 100644 index 00000000..79e53394 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/RegFactory.cpp @@ -0,0 +1,162 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 +#include "plstr.h" +#include "prlink.h" +#include "nsIComponentRegistrar.h" +#include "nsIComponentManager.h" +#include "nsIServiceManager.h" +#include "nsILocalFile.h" +#include "nsCOMPtr.h" +#include "nsString.h" + +static PRBool gUnreg = PR_FALSE; + +void print_err(nsresult err) +{ + switch (err) { + case NS_ERROR_FACTORY_NOT_LOADED: + cerr << "Factory not loaded"; + break; + case NS_NOINTERFACE: + cerr << "No Interface"; + break; + case NS_ERROR_NULL_POINTER: + cerr << "Null pointer"; + break; + case NS_ERROR_OUT_OF_MEMORY: + cerr << "Out of memory"; + break; + default: + cerr << hex << err << dec; + } +} + +nsresult Register(nsIComponentRegistrar* registrar, const char *path) +{ + nsCOMPtr file; + nsresult rv = + NS_NewLocalFile( + NS_ConvertUTF8toUCS2(path), + PR_TRUE, + getter_AddRefs(file)); + if (NS_FAILED(rv)) return rv; + rv = registrar->AutoRegister(file); + return rv; +} + +nsresult Unregister(const char *path) +{ + /* NEEDS IMPLEMENTATION */ +#if 0 + nsresult res = nsComponentManager::AutoUnregisterComponent(path); + return res; +#else + return NS_ERROR_FAILURE; +#endif +} + +int ProcessArgs(nsIComponentRegistrar* registrar, int argc, char *argv[]) +{ + int i = 1; + nsresult res; + + while (i < argc) { + if (argv[i][0] == '-') { + int j; + for (j = 1; argv[i][j] != '\0'; j++) { + switch (argv[i][j]) { + case 'u': + gUnreg = PR_TRUE; + break; + default: + cerr << "Unknown option '" << argv[i][j] << "'\n"; + } + } + i++; + } else { + if (gUnreg == PR_TRUE) { + res = Unregister(argv[i]); + if (NS_SUCCEEDED(res)) { + cout << "Successfully unregistered: " << argv[i] << "\n"; + } else { + cerr << "Unregister failed ("; + print_err(res); + cerr << "): " << argv[i] << "\n"; + } + } else { + res = Register(registrar, argv[i]); + if (NS_SUCCEEDED(res)) { + cout << "Successfully registered: " << argv[i] << "\n"; + } else { + cerr << "Register failed ("; + print_err(res); + cerr << "): " << argv[i] << "\n"; + } + } + i++; + } + } + return 0; +} + +int main(int argc, char *argv[]) +{ + int ret = 0; + nsresult rv; + { + nsCOMPtr servMan; + rv = NS_InitXPCOM2(getter_AddRefs(servMan), nsnull, nsnull); + if (NS_FAILED(rv)) return -1; + nsCOMPtr registrar = do_QueryInterface(servMan); + NS_ASSERTION(registrar, "Null nsIComponentRegistrar"); + + /* With no arguments, RegFactory will autoregister */ + if (argc <= 1) + { + rv = registrar->AutoRegister(nsnull); + ret = (NS_FAILED(rv)) ? -1 : 0; + } + else + ret = ProcessArgs(registrar, argc, argv); + } // this scopes the nsCOMPtrs + // no nsCOMPtrs are allowed to be alive when you call NS_ShutdownXPCOM + rv = NS_ShutdownXPCOM( NULL ); + NS_ASSERTION(NS_SUCCEEDED(rv), "NS_ShutdownXPCOM failed"); + return ret; +} diff --git a/src/libs/xpcom18a4/xpcom/tests/SizeTest01.cpp b/src/libs/xpcom18a4/xpcom/tests/SizeTest01.cpp new file mode 100644 index 00000000..2d552a36 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/SizeTest01.cpp @@ -0,0 +1,107 @@ +// Test01.cpp + +#include "nsIDOMNode.h" +#include "nsCOMPtr.h" +#include "nsString.h" + +NS_DEF_PTR(nsIDOMNode); + + /* + This test file compares the generated code size of similar functions between raw + COM interface pointers (|AddRef|ing and |Release|ing by hand) and |nsCOMPtr|s. + + Function size results were determined by examining dissassembly of the generated code. + mXXX is the size of the generated code on the Macintosh. wXXX is the size on Windows. + For these tests, all reasonable optimizations were enabled and exceptions were + disabled (just as we build for release). + + The tests in this file explore only the simplest functionality: assigning a pointer + to be reference counted into a [raw, nsCOMPtr] object; ensuring that it is + |AddRef|ed and |Release|d appropriately; calling through the pointer to a function + supplied by the underlying COM interface. + + Windows: + raw_optimized 31 bytes + raw, nsCOMPtr* 34 + nsCOMPtr_optimized* 38 + nsCOMPtr_optimized 42 + nsCOMPtr 46 + + Macintosh: + raw_optimized, nsCOMPtr_optimized 112 bytes (1.0000) + nsCOMPtr 120 (1.0714) i.e., 7.14% bigger than raw_optimized et al + raw 140 (1.2500) + + The overall difference in size between Windows and Macintosh is caused by the + the PowerPC RISC architecture where every instruction is 4 bytes. + + On Macintosh, nsCOMPtr generates out-of-line destructors which are + not referenced, and which can be stripped by the linker. + */ + +void +Test01_raw( nsIDOMNode* aDOMNode, nsString* aResult ) + // m140, w34 + { + /* + This test is designed to be more like a typical large function where, + because you are working with several resources, you don't just return when + one of them is |NULL|. Similarly: |Test01_nsCOMPtr00|, and |Test01_nsIPtr00|. + */ + + nsIDOMNode* node = aDOMNode; + NS_IF_ADDREF(node); + + if ( node ) + node->GetNodeName(*aResult); + + NS_IF_RELEASE(node); + } + +void +Test01_raw_optimized( nsIDOMNode* aDOMNode, nsString* aResult ) + // m112, w31 + { + /* + This test simulates smaller functions where you _do_ just return + |NULL| at the first sign of trouble. Similarly: |Test01_nsCOMPtr01|, + and |Test01_nsIPtr01|. + */ + + /* + This test produces smaller code that |Test01_raw| because it avoids + the three tests: |NS_IF_...|, and |if ( node )|. + */ + +// -- the following code is assumed, but is commented out so we compare only +// the relevent generated code + +// if ( !aDOMNode ) +// return; + + nsIDOMNode* node = aDOMNode; + NS_ADDREF(node); + node->GetNodeName(*aResult); + NS_RELEASE(node); + } + +void +Test01_nsCOMPtr( nsIDOMNode* aDOMNode, nsString* aResult ) + // m120, w46/34 + { + nsCOMPtr node = aDOMNode; + + if ( node ) + node->GetNodeName(*aResult); + } + +void +Test01_nsCOMPtr_optimized( nsIDOMNode* aDOMNode, nsString* aResult ) + // m112, w42/38 + { +// if ( !aDOMNode ) +// return; + + nsCOMPtr node = aDOMNode; + node->GetNodeName(*aResult); + } diff --git a/src/libs/xpcom18a4/xpcom/tests/SizeTest02.cpp b/src/libs/xpcom18a4/xpcom/tests/SizeTest02.cpp new file mode 100644 index 00000000..8515fcb1 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/SizeTest02.cpp @@ -0,0 +1,93 @@ +// Test02.cpp + +#include "nsIDOMNode.h" +#include "nsCOMPtr.h" +#include "nsString.h" + +#ifdef __MWERKS__ + #pragma exceptions off +#endif + +NS_DEF_PTR(nsIDOMNode); + + /* + This test file compares the generated code size of similar functions between raw + COM interface pointers (|AddRef|ing and |Release|ing by hand) and |nsCOMPtr|s. + + Function size results were determined by examining dissassembly of the generated code. + mXXX is the size of the generated code on the Macintosh. wXXX is the size on Windows. + For these tests, all reasonable optimizations were enabled and exceptions were + disabled (just as we build for release). + + The tests in this file explore more complicated functionality: assigning a pointer + to be reference counted into a [raw, nsCOMPtr] object using |QueryInterface|; + ensuring that it is |AddRef|ed and |Release|d appropriately; calling through the pointer + to a function supplied by the underlying COM interface. The tests in this file expand + on the tests in "Test01.cpp" by adding |QueryInterface|. + + Windows: + raw01 52 + nsCOMPtr 63 + raw 66 + nsCOMPtr* 68 + + Macintosh: + nsCOMPtr 120 (1.0000) + Raw01 128 (1.1429) i.e., 14.29% bigger than nsCOMPtr + Raw00 144 (1.2000) + */ + + +void // nsresult +Test02_Raw00( nsISupports* aDOMNode, nsString* aResult ) + // m144, w66 + { +// -- the following code is assumed, but is commented out so we compare only +// the relevent generated code + +// if ( !aDOMNode ) +// return NS_ERROR_NULL_POINTER; + + nsIDOMNode* node = 0; + nsresult status = aDOMNode->QueryInterface(NS_GET_IID(nsIDOMNode), (void**)&node); + if ( NS_SUCCEEDED(status) ) + { + node->GetNodeName(*aResult); + } + + NS_IF_RELEASE(node); + +// return status; + } + +void // nsresult +Test02_Raw01( nsISupports* aDOMNode, nsString* aResult ) + // m128, w52 + { +// if ( !aDOMNode ) +// return NS_ERROR_NULL_POINTER; + + nsIDOMNode* node; + nsresult status = aDOMNode->QueryInterface(NS_GET_IID(nsIDOMNode), (void**)&node); + if ( NS_SUCCEEDED(status) ) + { + node->GetNodeName(*aResult); + NS_RELEASE(node); + } + +// return status; + } + +void // nsresult +Test02_nsCOMPtr( nsISupports* aDOMNode, nsString* aResult ) + // m120, w63/68 + { + nsresult status; + nsCOMPtr node = do_QueryInterface(aDOMNode, &status); + + if ( node ) + node->GetNodeName(*aResult); + +// return status; + } + diff --git a/src/libs/xpcom18a4/xpcom/tests/SizeTest03.cpp b/src/libs/xpcom18a4/xpcom/tests/SizeTest03.cpp new file mode 100644 index 00000000..9ca71c72 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/SizeTest03.cpp @@ -0,0 +1,101 @@ +// Test03.cpp + +#include "nsIDOMNode.h" +#include "nsCOMPtr.h" +#include "nsString.h" + +#ifdef __MWERKS__ + #pragma exceptions off +#endif + +NS_DEF_PTR(nsIDOMNode); + + /* + Windows: + nsCOMPtr_optimized* 45 + raw_optimized 48 + nsCOMPtr_optimized 50 + nsCOMPtr 54 + nsCOMPtr* 59 + raw 62 + + Macintosh: + nsCOMPtr_optimized 112 (1.0000) + raw_optimized 124 bytes (1.1071) i.e., 10.71% bigger than nsCOMPtr_optimized + nsCOMPtr 144 (1.2857) + */ + +void // nsresult +Test03_raw( nsIDOMNode* aDOMNode, nsString* aResult ) + // m140, w62 + { +// -- the following code is assumed, but is commented out so we compare only +// the relevent generated code + +// if ( !aDOMNode || !aResult ) +// return NS_ERROR_NULL_POINTER; + + nsIDOMNode* parent = 0; + nsresult status = aDOMNode->GetParentNode(&parent); + + if ( NS_SUCCEEDED(status) ) + { + parent->GetNodeName(*aResult); + } + + NS_IF_RELEASE(parent); + +// return status; + } + + +void // nsresult +Test03_raw_optimized( nsIDOMNode* aDOMNode, nsString* aResult ) + // m124, w48 + { +// if ( !aDOMNode || !aResult ) +// return NS_ERROR_NULL_POINTER; + + nsIDOMNode* parent; + nsresult status = aDOMNode->GetParentNode(&parent); + + if ( NS_SUCCEEDED(status) ) + { + parent->GetNodeName(*aResult); + NS_RELEASE(parent); + } + +// return status; + } + + +void // nsresult +Test03_nsCOMPtr( nsIDOMNode* aDOMNode, nsString* aResult ) + // m144, w54/59 + { +// if ( !aDOMNode || !aResult ) +// return NS_ERROR_NULL_POINTER; + + nsCOMPtr parent; + nsresult status = aDOMNode->GetParentNode( getter_AddRefs(parent) ); + if ( parent ) + parent->GetNodeName(*aResult); + +// return status; + } + +void // nsresult +Test03_nsCOMPtr_optimized( nsIDOMNode* aDOMNode, nsString* aResult ) + // m112, w50/45 + { +// if ( !aDOMNode || !aResult ) +// return NS_ERROR_NULL_POINTER; + + nsIDOMNode* temp; + nsresult status = aDOMNode->GetParentNode(&temp); + nsCOMPtr parent( dont_AddRef(temp) ); + if ( parent ) + parent->GetNodeName(*aResult); + +// return status; + } diff --git a/src/libs/xpcom18a4/xpcom/tests/SizeTest04.cpp b/src/libs/xpcom18a4/xpcom/tests/SizeTest04.cpp new file mode 100644 index 00000000..aad4ee68 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/SizeTest04.cpp @@ -0,0 +1,72 @@ +// Test04.cpp + +#include "nsIDOMNode.h" +#include "nsCOMPtr.h" + +#ifdef __MWERKS__ + #pragma exceptions off +#endif + +NS_DEF_PTR(nsIDOMNode); + + /* + Windows: + nsCOMPtr 13 + raw 36 + + Macintosh: + nsCOMPtr 36 bytes (1.0000) + raw 120 (3.3333) i.e., 333.33% bigger than nsCOMPtr + */ + +class Test04_Raw + { + public: + Test04_Raw(); + ~Test04_Raw(); + + void /*nsresult*/ SetNode( nsIDOMNode* newNode ); + + private: + nsIDOMNode* mNode; + }; + +Test04_Raw::Test04_Raw() + : mNode(0) + { + // nothing else to do here + } + +Test04_Raw::~Test04_Raw() + { + NS_IF_RELEASE(mNode); + } + +void // nsresult +Test04_Raw::SetNode( nsIDOMNode* newNode ) + // m120, w36 + { + NS_IF_ADDREF(newNode); + NS_IF_RELEASE(mNode); + mNode = newNode; + +// return NS_OK; + } + + + +class Test04_nsCOMPtr + { + public: + void /*nsresult*/ SetNode( nsIDOMNode* newNode ); + + private: + nsCOMPtr mNode; + }; + +void // nsresult +Test04_nsCOMPtr::SetNode( nsIDOMNode* newNode ) + // m36, w13/13 + { + mNode = newNode; + } diff --git a/src/libs/xpcom18a4/xpcom/tests/SizeTest05.cpp b/src/libs/xpcom18a4/xpcom/tests/SizeTest05.cpp new file mode 100644 index 00000000..0211610e --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/SizeTest05.cpp @@ -0,0 +1,78 @@ +// Test05.cpp + +#include "nsIDOMNode.h" +#include "nsCOMPtr.h" + +#ifdef __MWERKS__ + #pragma exceptions off +#endif + +NS_DEF_PTR(nsIDOMNode); + + /* + Windows: + raw, nsCOMPtr 21 bytes + + Macintosh: + Raw, nsCOMPtr 64 bytes + */ + +class Test05_Raw + { + public: + Test05_Raw(); + ~Test05_Raw(); + + void /*nsresult*/ GetNode( nsIDOMNode** aNode ); + + private: + nsIDOMNode* mNode; + }; + +Test05_Raw::Test05_Raw() + : mNode(0) + { + // nothing else to do here + } + +Test05_Raw::~Test05_Raw() + { + NS_IF_RELEASE(mNode); + } + +void // nsresult +Test05_Raw::GetNode( nsIDOMNode** aNode ) + // m64, w21 + { +// if ( !aNode ) +// return NS_ERROR_NULL_POINTER; + + *aNode = mNode; + NS_IF_ADDREF(*aNode); + +// return NS_OK; + } + + + +class Test05_nsCOMPtr + { + public: + void /*nsresult*/ GetNode( nsIDOMNode** aNode ); + + private: + nsCOMPtr mNode; + }; + +void // nsresult +Test05_nsCOMPtr::GetNode( nsIDOMNode** aNode ) + // m64, w21 + { +// if ( !aNode ) +// return NS_ERROR_NULL_POINTER; + + *aNode = mNode; + NS_IF_ADDREF(*aNode); + +// return NS_OK; + } diff --git a/src/libs/xpcom18a4/xpcom/tests/SizeTest06.cpp b/src/libs/xpcom18a4/xpcom/tests/SizeTest06.cpp new file mode 100644 index 00000000..2c28e7f3 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/SizeTest06.cpp @@ -0,0 +1,231 @@ +// Test06.cpp + +#include "nsIDOMWindowInternal.h" +#include "nsIScriptGlobalObject.h" +#include "nsIWebShell.h" +#include "nsIDocShell.h" +#include "nsIWebShellWindow.h" +#include "nsCOMPtr.h" + +NS_DEF_PTR(nsIScriptGlobalObject); +NS_DEF_PTR(nsIWebShell); +NS_DEF_PTR(nsIWebShellContainer); +NS_DEF_PTR(nsIWebShellWindow); + + /* + Windows: + nsCOMPtr_optimized 176 + nsCOMPtr_as_found 181 + nsCOMPtr_optimized* 182 + nsCOMPtr02* 184 + nsCOMPtr02 187 + nsCOMPtr02* 188 + nsCOMPtr03 189 + raw_optimized, nsCOMPtr00 191 + nsCOMPtr00* 199 + nsCOMPtr_as_found* 201 + raw 214 + + Macintosh: + nsCOMPtr_optimized 300 (1.0000) + nsCOMPtr02 320 (1.0667) i.e., 6.67% bigger than nsCOMPtr_optimized + nsCOMPtr00 328 (1.0933) + raw_optimized, nsCOMPtr03 332 (1.1067) + nsCOMPtr_as_found 344 (1.1467) + raw 388 (1.2933) + + */ + + +void // nsresult +Test06_raw(nsIDOMWindowInternal* aDOMWindow, nsIWebShellWindow** aWebShellWindow) + // m388, w214 +{ +// if (!aDOMWindow) +// return NS_ERROR_NULL_POINTER; + nsIScriptGlobalObject* scriptGlobalObject = 0; + nsresult status = aDOMWindow->QueryInterface(NS_GET_IID(nsIScriptGlobalObject), (void**)&scriptGlobalObject); + nsIDocShell* docShell = 0; + if (scriptGlobalObject) + scriptGlobalObject->GetDocShell(&docShell); + nsIWebShell* webShell = 0; + if (docShell) + status=docShell->QueryInterface(NS_GET_IID(nsIWebShell), (void**)&webShell); + nsIWebShell* rootWebShell = 0; + if (webShell) + //status = webShell->GetRootWebShellEvenIfChrome(rootWebShell); + {} + nsIWebShellContainer* webShellContainer = 0; + if (rootWebShell) + status = rootWebShell->GetContainer(webShellContainer); + if (webShellContainer) + status = webShellContainer->QueryInterface(NS_GET_IID(nsIWebShellWindow), (void**)aWebShellWindow); + else + (*aWebShellWindow) = 0; + NS_IF_RELEASE(webShellContainer); + NS_IF_RELEASE(rootWebShell); + NS_IF_RELEASE(webShell); + NS_IF_RELEASE(docShell); + NS_IF_RELEASE(scriptGlobalObject); +// return status; +} + +void // nsresult +Test06_raw_optimized(nsIDOMWindowInternal* aDOMWindow, nsIWebShellWindow** aWebShellWindow) + // m332, w191 +{ +// if (!aDOMWindow) +// return NS_ERROR_NULL_POINTER; + (*aWebShellWindow) = 0; + nsIScriptGlobalObject* scriptGlobalObject; + nsresult status = aDOMWindow->QueryInterface(NS_GET_IID(nsIScriptGlobalObject), (void**)&scriptGlobalObject); + if (NS_SUCCEEDED(status)) { + nsIDocShell* docShell = 0; + scriptGlobalObject->GetDocShell(&docShell); + if (docShell) { + nsIWebShell* webShell = 0; + docShell->QueryInterface(NS_GET_IID(nsIWebShell), (void**)webShell); + if (webShell) { + nsIWebShell* rootWebShell; + // status = webShell->GetRootWebShellEvenIfChrome(rootWebShell); + if (NS_SUCCEEDED(status)) { + nsIWebShellContainer* webShellContainer; + status = rootWebShell->GetContainer(webShellContainer); + if (NS_SUCCEEDED(status)) { + status = webShellContainer->QueryInterface(NS_GET_IID(nsIWebShellWindow), (void**)aWebShellWindow); + NS_RELEASE(webShellContainer); + } + NS_RELEASE(rootWebShell); + } + NS_RELEASE(webShell); + } + NS_RELEASE(docShell); + } + NS_RELEASE(scriptGlobalObject); + } +// return status; +} + +void +Test06_nsCOMPtr_as_found(nsIDOMWindowInternal* aDOMWindow, nsCOMPtr* aWebShellWindow) + // m344, w181/201 +{ +// if (!aDOMWindow) +// return; + nsCOMPtr scriptGlobalObject = do_QueryInterface(aDOMWindow); + nsCOMPtr docShell; + if (scriptGlobalObject) + scriptGlobalObject->GetDocShell(getter_AddRefs(docShell)); + nsCOMPtr webShell; + if (docShell) + webShell = do_QueryInterface(docShell); + nsCOMPtr rootWebShell; + if (webShell) + //webShell->GetRootWebShellEvenIfChrome(*getter_AddRefs(rootWebShell)); + {} + nsCOMPtr webShellContainer; + if (rootWebShell) + rootWebShell->GetContainer(*getter_AddRefs(webShellContainer)); + (*aWebShellWindow) = do_QueryInterface(webShellContainer); +} + +void // nsresult +Test06_nsCOMPtr00(nsIDOMWindowInternal* aDOMWindow, nsIWebShellWindow** aWebShellWindow) + // m328, w191/199 +{ +// if (!aDOMWindow) +// return NS_ERROR_NULL_POINTER; + nsresult status; + nsCOMPtr scriptGlobalObject = do_QueryInterface(aDOMWindow, &status); + nsIDocShell* temp0 = 0; + if (scriptGlobalObject) + scriptGlobalObject->GetDocShell(&temp0); + nsCOMPtr docShell = dont_AddRef(temp0); + nsCOMPtr webShell; + if (docShell) + webShell=do_QueryInterface(docShell, &status); + nsIWebShellContainer* temp2 = 0; + if (webShell) + status = webShell->GetContainer(temp2); + nsCOMPtr webShellContainer = dont_AddRef(temp2); + if (webShellContainer) + status = webShellContainer->QueryInterface(NS_GET_IID(nsIWebShellWindow), (void**)aWebShellWindow); + else + (*aWebShellWindow) = 0; +// return status; +} + +void // nsresult +Test06_nsCOMPtr_optimized(nsIDOMWindowInternal* aDOMWindow, nsCOMPtr* aWebShellWindow) + // m300, w176/182 +{ +// if (!aDOMWindow) +// return NS_ERROR_NULL_POINTER; + nsresult status; + nsCOMPtr scriptGlobalObject = do_QueryInterface(aDOMWindow, &status); + nsIDocShell* temp0 = 0; + if (scriptGlobalObject) + scriptGlobalObject->GetDocShell(&temp0); + nsCOMPtr webShell = do_QueryInterface(temp0, &status); + nsIWebShell* temp2 = 0; + if (webShell) + // status = webShell->GetRootWebShellEvenIfChrome(temp2); + {} + nsCOMPtr rootWebShell = dont_AddRef(temp2); + nsIWebShellContainer* temp3 = 0; + if (rootWebShell) + status = rootWebShell->GetContainer(temp3); + nsCOMPtr webShellContainer = dont_AddRef(temp3); + (*aWebShellWindow) = do_QueryInterface(webShellContainer, &status); +// return status; +} + +void // nsresult +Test06_nsCOMPtr02(nsIDOMWindowInternal* aDOMWindow, nsIWebShellWindow** aWebShellWindow) + // m320, w187/184 +{ +// if (!aDOMWindow) +// return NS_ERROR_NULL_POINTER; + (*aWebShellWindow) = 0; + nsresult status; + nsCOMPtr scriptGlobalObject = do_QueryInterface(aDOMWindow, &status); + if (scriptGlobalObject) { + nsIDocShell* temp0; + scriptGlobalObject->GetDocShell(&temp0); + nsCOMPtr webShell = do_QueryInterface(temp0); + if (webShell) { + nsIWebShellContainer* temp2; + status = webShell->GetContainer(temp2); + nsCOMPtr webShellContainer = dont_AddRef(temp2); + if (webShellContainer) + status = webShellContainer->QueryInterface(NS_GET_IID(nsIWebShellWindow), (void**)aWebShellWindow); + } + } +// return status; +} + +void // nsresult +Test06_nsCOMPtr03(nsIDOMWindowInternal* aDOMWindow, nsCOMPtr* aWebShellWindow) + // m332, w189/188 +{ +// if (!aDOMWindow) +// return NS_ERROR_NULL_POINTER; + (*aWebShellWindow) = 0; + nsresult status; + nsCOMPtr scriptGlobalObject = do_QueryInterface(aDOMWindow, &status); + if (scriptGlobalObject) { + nsIDocShell* temp0; + scriptGlobalObject->GetDocShell(&temp0); + nsCOMPtr docShell = dont_AddRef(temp0); + if (docShell) { + nsCOMPtr webShell = do_QueryInterface(docShell, &status); + if (webShell) { + nsIWebShellContainer* temp2; + status = webShell->GetContainer(temp2); + nsCOMPtr webShellContainer = dont_AddRef(temp2); + (*aWebShellWindow) = do_QueryInterface(webShellContainer, &status); + } + } + } +// return status; +} diff --git a/src/libs/xpcom18a4/xpcom/tests/StringFactoringTests/Makefile.in b/src/libs/xpcom18a4/xpcom/tests/StringFactoringTests/Makefile.in new file mode 100644 index 00000000..1ced5d3e --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/StringFactoringTests/Makefile.in @@ -0,0 +1,76 @@ +# +# ***** 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.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of 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 ***** + +DEPTH = ../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = xpcom +PROGRAM = profile_strings +#PROGRAM = test_main + +CPPSRCS = \ + $(topsrcdir)/xpcom/ds/nsString2.cpp \ + $(topsrcdir)/xpcom/ds/nsStr.cpp \ + $(topsrcdir)/xpcom/ds/nsString.cpp \ + $(topsrcdir)/xpcom/ds/nsCRT.cpp \ + $(topsrcdir)/xpcom/base/nsAllocator.cpp \ + $(topsrcdir)/xpcom/ds/nsDeque.cpp \ + profile_main.cpp \ + $(NULL) +# test_main.cpp \ + + +LIBS += \ + $(NSPR_LIBS) \ + $(NULL) + +include $(topsrcdir)/config/rules.mk + +DEFINES += -DNEW_STRING_APIS -DSTANDALONE_STRING_TESTS -UDEBUG -DNDEBUG +#DEFINES += -DSTANDALONE_STRING_TESTS -UDEBUG -DNDEBUG +INCLUDES += -I$(srcdir)/../public -I$(srcdir)/services + +libs:: + $(INSTALL) $(srcdir)/test.properties $(DIST)/bin/res + +install:: + $(SYSINSTALL) $(IFLAGS1) $(srcdir)/test.properties $(DESTDIR)$(mozappdir)/res + diff --git a/src/libs/xpcom18a4/xpcom/tests/StringFactoringTests/StringTest.Prefix b/src/libs/xpcom18a4/xpcom/tests/StringFactoringTests/StringTest.Prefix new file mode 100644 index 00000000..b9580e49 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/StringFactoringTests/StringTest.Prefix @@ -0,0 +1,4 @@ +// StringTest.Prefix + +#define STANDALONE_STRING_TESTS +#define HAVE_CPP_2BYTE_WCHAR_T diff --git a/src/libs/xpcom18a4/xpcom/tests/StringFactoringTests/StringTest.mcp b/src/libs/xpcom18a4/xpcom/tests/StringFactoringTests/StringTest.mcp new file mode 100644 index 00000000..12b125ed Binary files /dev/null and b/src/libs/xpcom18a4/xpcom/tests/StringFactoringTests/StringTest.mcp differ diff --git a/src/libs/xpcom18a4/xpcom/tests/StringFactoringTests/StringTestDebug.Prefix b/src/libs/xpcom18a4/xpcom/tests/StringFactoringTests/StringTestDebug.Prefix new file mode 100644 index 00000000..3724af94 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/StringFactoringTests/StringTestDebug.Prefix @@ -0,0 +1,4 @@ +#include "StringTest.Prefix" + +#define DEBUG 1 +#undef NDEBUG diff --git a/src/libs/xpcom18a4/xpcom/tests/StringFactoringTests/StringTestNo_wchar_t.Prefix b/src/libs/xpcom18a4/xpcom/tests/StringFactoringTests/StringTestNo_wchar_t.Prefix new file mode 100644 index 00000000..dddf8450 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/StringFactoringTests/StringTestNo_wchar_t.Prefix @@ -0,0 +1,5 @@ +// StringTestNo_wchar_t.Prefix + +#include "StringTest.Prefix" + +#undef HAVE_CPP_2BYTE_WCHAR_T diff --git a/src/libs/xpcom18a4/xpcom/tests/StringFactoringTests/StringTestProfileNew.Prefix b/src/libs/xpcom18a4/xpcom/tests/StringFactoringTests/StringTestProfileNew.Prefix new file mode 100644 index 00000000..b6ca50d3 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/StringFactoringTests/StringTestProfileNew.Prefix @@ -0,0 +1,3 @@ +// StringTestProfileNew.Prefix + +#include "StringTest.Prefix" diff --git a/src/libs/xpcom18a4/xpcom/tests/StringFactoringTests/StringTestProfileOld.Prefix b/src/libs/xpcom18a4/xpcom/tests/StringFactoringTests/StringTestProfileOld.Prefix new file mode 100644 index 00000000..d23e3ea9 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/StringFactoringTests/StringTestProfileOld.Prefix @@ -0,0 +1,6 @@ +// StringTestProfileOld.Prefix + +#include "StringTest.Prefix" + +#define OLD_STRING_APIS +#undef HAVE_CPP_2BYTE_WCHAR_T \ No newline at end of file diff --git a/src/libs/xpcom18a4/xpcom/tests/StringFactoringTests/StringTestProfileStd.Prefix b/src/libs/xpcom18a4/xpcom/tests/StringFactoringTests/StringTestProfileStd.Prefix new file mode 100644 index 00000000..eb8a7a85 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/StringFactoringTests/StringTestProfileStd.Prefix @@ -0,0 +1,7 @@ +// StringTestProfileOld.Prefix + +#include "StringTest.Prefix" + +#define OLD_STRING_APIS +#define TEST_STD_STRING +#undef HAVE_CPP_2BYTE_WCHAR_T \ No newline at end of file diff --git a/src/libs/xpcom18a4/xpcom/tests/StringFactoringTests/ToDo.doc b/src/libs/xpcom18a4/xpcom/tests/StringFactoringTests/ToDo.doc new file mode 100644 index 00000000..da114471 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/StringFactoringTests/ToDo.doc @@ -0,0 +1,41 @@ +// To Do... + + - Decide: do I really want to define |Equals| (i.e., so many extra signatures) + + . Make |ns[C]String| rename its converting operations to, e.g., |EqualsWithConversion|, + |AssignWithConversion|, |CompareWithConversion|, |AppendWithConversion|, etc. + + . Bring |Equals| and |Compare| into scope + + . Implement chunky iterators + + . Get "nsAReadableString.h" and "nsAWritableString.h" to added to the MANIFEST, etc. + + - Get "nsAReadableString.h" and "nsAWritableString.h" to compile everywhere + + - Add test for |Replace|... + + - Add tests for Find and RFind + + - Implement the Find and RFind signatures + + . Fix Truncate / SetLength confusion (make SetLength the real function in |nsString|) + + . Chop out conflicting |ns[C]String| operators + + . Figure out how if we can make PRUnichar be wchar_t, so we get the cheap constructors, + ...and ensure the cheap constructors can be made to work everywhere + + x Try the |static const unsigned long kLeftString = 1 - 1; /* because VC++ doesn't like =0 */| hack + + . Add tests for |nsShared[C]String| + + . Implement |nsShared[C]String| + + - Add tests for the shared string smart pointer + + . Implement the shared string smart pointer + + . Figure out why StdStringWrapper isn't as good as raw std::string + + - Implement a smart allocator for StdStringWrapper diff --git a/src/libs/xpcom18a4/xpcom/tests/StringFactoringTests/nsStdStringWrapper.h b/src/libs/xpcom18a4/xpcom/tests/StringFactoringTests/nsStdStringWrapper.h new file mode 100644 index 00000000..6e43b528 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/StringFactoringTests/nsStdStringWrapper.h @@ -0,0 +1,234 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Scott Collins + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +#ifndef nsStdStringWrapper_h___ +#define nsStdStringWrapper_h___ + +#include + +#ifndef nsAString_h___ +#include "nsAString.h" +#endif + + +template +class nsStringAllocator + : public std::allocator // temporarily + { + // ... + }; + + +template < class CharT, class TraitsT = nsCharTraits, class AllocatorT = nsStringAllocator > +class basic_nsStdStringWrapper + : public basic_nsAString + /* + ... + */ + { + protected: + std::basic_string mRawString; + + typedef std::basic_string basic_string_t; + + using typename basic_string_t::traits_type; + using typename basic_string_t::value_type; + using typename basic_string_t::allocator_type; + using typename basic_string_t::size_type; + using typename basic_string_t::difference_type; + using typename basic_string_t::reference; + using typename basic_string_t::const_reference; + using typename basic_string_t::pointer; + using typename basic_string_t::const_pointer; + using typename basic_string_t::iterator; + using typename basic_string_t::const_iterator; + using typename basic_string_t::reverse_iterator; + using typename basic_string_t::const_reverse_iterator; + + static const size_type npos = size_type(-1); + + protected: + virtual const void* Implementation() const; + + virtual const CharT* GetReadableFragment( nsReadableFragment&, nsFragmentRequest, PRUint32 ) const; + virtual CharT* GetWritableFragment( nsWritableFragment&, nsFragmentRequest, PRUint32 ); + + public: + basic_nsStdStringWrapper() { } + +#if 0 + explicit + basic_nsStdStringWrapper( const AllocatorT& a = AllocatorT() ) + : mRawString(a) + { + } +#endif + + explicit + basic_nsStdStringWrapper( const basic_nsAString& str ) + { + Assign(str); + } + +#if 0 + explicit + basic_nsStdStringWrapper( const basic_string_t& str, size_type pos = 0, size_type n = npos ) + : mRawString(str, pos, n) + { + } + + basic_nsStdStringWrapper( const basic_string_t& str, size_type pos, size_type n, const AllocatorT& a ) + : mRawString(str, pos, n, a) + { + } +#endif + + basic_nsStdStringWrapper( const CharT* s, size_type n, const AllocatorT& a = AllocatorT() ) + : mRawString(s, n, a) + { + } + + explicit + basic_nsStdStringWrapper( const CharT* s, const AllocatorT& a = AllocatorT() ) + : mRawString(s, a) + { + } + +#if 0 + basic_nsStdStringWrapper( size_type n, CharT c, const AllocatorT& a = AllocatorT() ) + : mRawString(n, c, a) + { + } +#endif + + virtual + PRUint32 + Length() const + { + return mRawString.length(); + } + + virtual + void + SetCapacity( PRUint32 aNewCapacity ) + { + mRawString.reserve(aNewCapacity); + } + + virtual + void + SetLength( PRUint32 aNewLength ) + { + mRawString.resize(aNewLength); + } + + protected: + virtual void do_AssignFromReadable( const basic_nsAString& ); + + // ... + }; + +NS_DEF_TEMPLATE_STRING_COMPARISON_OPERATORS(basic_nsStdStringWrapper, CharT) + + + +template +const void* +basic_nsStdStringWrapper::Implementation() const + { + static const char* implementation = "nsStdStringWrapper"; + return implementation; + } + + +template +const CharT* +basic_nsStdStringWrapper::GetReadableFragment( nsReadableFragment& aFragment, nsFragmentRequest aRequest, PRUint32 aOffset ) const + { + switch ( aRequest ) + { + case kFirstFragment: + case kLastFragment: + case kFragmentAt: + aFragment.mEnd = (aFragment.mStart = mRawString.data()) + mRawString.length(); + return aFragment.mStart + aOffset; + + case kPrevFragment: + case kNextFragment: + default: + return 0; + } + } + +template +CharT* +basic_nsStdStringWrapper::GetWritableFragment( nsWritableFragment& aFragment, nsFragmentRequest aRequest, PRUint32 aOffset ) + { + switch ( aRequest ) + { + case kFirstFragment: + case kLastFragment: + case kFragmentAt: + aFragment.mEnd = (aFragment.mStart = NS_CONST_CAST(CharT*, mRawString.data())) + mRawString.length(); + return aFragment.mStart + aOffset; + + case kPrevFragment: + case kNextFragment: + default: + return 0; + } + } + +template +void +basic_nsStdStringWrapper::do_AssignFromReadable( const basic_nsAString& rhs ) + { + typedef basic_nsStdStringWrapper this_t; + + if ( SameImplementation(*this, rhs) ) + mRawString = NS_STATIC_CAST(this_t, rhs).mRawString; + else + basic_nsAString::do_AssignFromReadable(rhs); + } + + +typedef basic_nsStdStringWrapper nsStdString; +typedef basic_nsStdStringWrapper nsStdCString; + + +#endif // !defined(nsStdStringWrapper_h___) diff --git a/src/libs/xpcom18a4/xpcom/tests/StringFactoringTests/profile_main.cpp b/src/libs/xpcom18a4/xpcom/tests/StringFactoringTests/profile_main.cpp new file mode 100644 index 00000000..d7c14621 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/StringFactoringTests/profile_main.cpp @@ -0,0 +1,497 @@ +// profile_main.cpp + +#include "nscore.h" +#include +#include +#include + +#include "nsInt64.h" + +#ifdef XP_MAC +#include +#include "Profiler.h" +#else +#include "prtime.h" +#endif + +#ifndef TEST_STD_STRING +#include "nsString.h" +#else +#include "nsStdStringWrapper.h" +typedef nsStdCString nsCString; +#endif + +static const int kTestSucceeded = 0; +static const int kTestFailed = 1; + +static const size_t N = 100000; + + +template +inline +PRUint32 +TotalLength( const T& s ) + { + return s.Length(); + } + +NS_SPECIALIZE_TEMPLATE +inline +PRUint32 +TotalLength( const string& s ) + { + return s.length(); + } + +template +inline +PRUint32 +Find( const T& text, const T& pattern ) + { + return text.Find(pattern); + } + +NS_SPECIALIZE_TEMPLATE +inline +PRUint32 +Find( const string& text, const string& pattern ) + { + return text.find(pattern); + } + +inline +nsInt64 +GetTime() + { +#ifdef XP_MAC + UnsignedWide time; + Microseconds(&time); + return nsInt64( *reinterpret_cast(&time) ); +#else + return nsInt64( PR_Now() ); +#endif + } + +class TestTimer + { + public: + TestTimer() : mStartTime(GetTime()) { } + + ~TestTimer() + { + nsInt64 stopTime = GetTime(); + nsInt64 totalTime = stopTime - mStartTime; +#ifdef HAVE_LONG_LONG + cout << setw(10) << NS_STATIC_CAST(PRInt64, totalTime) << " µs : "; +#else + cout << setw(10) << NS_STATIC_CAST(PRInt32, totalTime) << "µs : "; +#endif + } + + private: + nsInt64 mStartTime; + }; + +inline +int +foo( const nsCString& ) + { + return 1; + } + +static +int +test_construction() + { + cout << endl; + + { + nsCString someCString; + int total = 0; + TestTimer timer; + for ( int i=0; i s2 ) + ++count; + } + cout << "s1 > s2" << endl; + + { + TestTimer timer; + for ( int i=0; i +#include "nsStringIO.h" + +//#define TEST_STD_STRING + + +#include "nsString.h" +#include "nsFragmentedString.h" +#include "nsReadableUtils.h" +#include "nsSlidingString.h" + +#ifdef TEST_STD_STRING +#include "nsStdStringWrapper.h" +#else + typedef nsString nsStdString; + typedef nsCString nsStdCString; +#endif + +template +basic_nsLiteralString +literal_hello( CharT* ) + { + } + +NS_SPECIALIZE_TEMPLATE +basic_nsLiteralString +literal_hello( char* ) + { + return basic_nsLiteralString("Hello"); + } + +NS_SPECIALIZE_TEMPLATE +basic_nsLiteralString +literal_hello( PRUnichar* ) + { +#ifdef HAVE_CPP_2BYTE_WCHAR_T + return basic_nsLiteralString(L"Hello"); +#else + static PRUnichar constant_unicode[] = { 'H', 'e', 'l', 'l', 'o', PRUnichar() }; + return basic_nsLiteralString(constant_unicode); +#endif + } + +template +struct string_class_traits + { + }; + +NS_SPECIALIZE_TEMPLATE +struct string_class_traits + { + typedef PRUnichar* pointer; + typedef nsString implementation_t; + + static basic_nsLiteralString literal_hello() { return ::literal_hello(pointer()); } + }; + +NS_SPECIALIZE_TEMPLATE +struct string_class_traits + { + typedef char* pointer; + typedef nsCString implementation_t; + + static basic_nsLiteralString literal_hello() { return ::literal_hello(pointer()); } + }; + + +static +void +CallCMid( nsACString& aResult, const nsACString& aSource, PRUint32 aStartPos, PRUint32 aLengthToCopy ) + { + aSource.Mid(aResult, aStartPos, aLengthToCopy); + } + + + +template +int +test_multifragment_iterators( const basic_nsAString& aString ) + /* + ...this tests a problem that was present in |nsPromiseConcatenation| where, + because it originally stored some iteration state in the object itself, rather than + in the fragment, the iterators could get confused if used out of sequence. + + This test should be run on any multi-fragment implementation to verify that it + does not have the same bug. Make sure the first fragment is only one character long. + */ + { + typedef typename basic_nsAString::const_iterator ConstIterator; + + int tests_failed = 0; + + ConstIterator iter1 = aString.BeginReading(); + ConstIterator iter2 = aString.BeginReading(); + ++iter2; ++iter2; + + ConstIterator iter3 = aString.EndReading(); + --iter3; + ++iter1; ++iter1; + if ( iter1 != iter2 ) + { + cout << "FAILED in |test_multifragment_iterators|" << endl; + ++tests_failed; + } + + return tests_failed; + } + +template +int +test_Vidur_functions( const basic_nsAString& aString ) + { + char* char_copy = ToNewCString(aString); + PRUnichar* PRUnichar_copy = ToNewUnicode(aString); + + nsMemory::Free(PRUnichar_copy); + nsMemory::Free(char_copy); + + return 0; + } + +template +int +test_readable_hello( const basic_nsAString& aReadable ) + { + int tests_failed = 0; + + if ( aReadable.Length() != 5 ) + { + cout << "FAILED |test_readable_hello|: |Length()| --> " << aReadable.Length() << endl; + ++tests_failed; + } + + if ( aReadable.First() != CharT('H') ) + { + cout << "FAILED |test_readable_hello|: |First()| --> '" << aReadable.First() << "'" << endl; + ++tests_failed; + } + + if ( aReadable.Last() != CharT('o') ) + { + cout << "FAILED |test_readable_hello|: |Last()| --> '" << aReadable.Last() << "'" << endl; + ++tests_failed; + } + + if ( aReadable[3] != CharT('l') ) + { + cout << "FAILED |test_readable_hello|: |operator[]| --> '" << aReadable[3] << "'" << endl; + ++tests_failed; + } + + if ( aReadable.CountChar( CharT('l') ) != 2 ) + { + cout << "FAILED |test_readable_hello|: |CountChar('l')| --> " << aReadable.CountChar(CharT('l')) << endl; + ++tests_failed; + } + + basic_nsAString::const_iterator iter = aReadable.BeginReading(); + if ( *iter != CharT('H') ) + { + cout << "FAILED |test_readable_hello|: didn't start out pointing to the right thing, or else couldn't be dereferenced. --> '" << *iter << "'" << endl; + ++tests_failed; + } + + ++iter; + + if ( *iter != CharT('e') ) + { + cout << "FAILED |test_readable_hello|: iterator couldn't be incremented, or else couldn't be dereferenced. --> '" << *iter << "'" << endl; + ++tests_failed; + } + + iter = aReadable.EndReading(); + --iter; + if ( *iter != CharT('o') ) + { + cout << "FAILED |test_readable_hello|: iterator couldn't be set to |EndReading()|, or else couldn't be decremented, or else couldn't be dereferenced. --> '" << *iter << "'" << endl; + ++tests_failed; + } + + basic_nsAString::const_iterator iter1 = aReadable.BeginReading().advance(3); + if ( *iter1 != CharT('l') ) + { + cout << "FAILED |test_readable_hello|: iterator couldn't be set to |BeginReading()+=n|, or else couldn't be dereferenced. --> '" << *iter1 << "'" << endl; + ++tests_failed; + } + + basic_nsAString::const_iterator iter2 = aReadable.EndReading().advance(-2); + if ( *iter2 != CharT('l') ) + { + cout << "FAILED |test_readable_hello|: iterator couldn't be set to |EndReading()-=n|, or else couldn't be dereferenced. --> '" << *iter2 << "'" << endl; + ++tests_failed; + } + + if ( iter1 != iter2 ) + { + cout << "FAILED |test_readable_hello|: iterator comparison with !=." << endl; + ++tests_failed; + } + + if ( !(iter1 == iter2) ) + { + cout << "FAILED |test_readable_hello|: iterator comparison with ==." << endl; + ++tests_failed; + } + + typedef CharT* CharT_ptr; + if ( aReadable != literal_hello(CharT_ptr()) ) + { + cout << "FAILED |test_readable_hello|: comparison with \"Hello\"" << endl; + ++tests_failed; + } + + tests_failed += test_multifragment_iterators(aReadable); + // tests_failed += test_deprecated_GetBufferGetUnicode(aReadable); + + test_Vidur_functions(aReadable); + + return tests_failed; + } + + +template +int +test_SetLength( basic_nsAString& aWritable ) + { + int tests_failed = 0; + + string_class_traits::implementation_t oldValue(aWritable); + + + size_t oldLength = aWritable.Length(); + + if ( oldValue != Substring(aWritable, 0, oldLength) ) + { + cout << "FAILED growing a string in |test_SetLength|, saving the value didn't work." << endl; + ++tests_failed; + } + + size_t newLength = 2*(oldLength+1); + + aWritable.SetLength(newLength); + if ( aWritable.Length() != newLength ) + { + cout << "FAILED growing a string in |test_SetLength|, length is wrong." << endl; + ++tests_failed; + } + + if ( oldValue != Substring(aWritable, 0, oldLength) ) + { + cout << "FAILED growing a string in |test_SetLength|, contents damaged after growing." << endl; + ++tests_failed; + } + + aWritable.SetLength(oldLength); + if ( aWritable.Length() != oldLength ) + { + cout << "FAILED shrinking a string in |test_SetLength|." << endl; + ++tests_failed; + } + + if ( oldValue != Substring(aWritable, 0, oldLength) ) + { + cout << "FAILED growing a string in |test_SetLength|, contents damaged after shrinking." << endl; + ++tests_failed; + } + + return tests_failed; + } + + +template +int +test_insert( basic_nsAString& aWritable ) + { + int tests_failed = 0; + + string_class_traits::implementation_t oldValue(aWritable); + + if ( oldValue != aWritable ) + { + cout << "FAILED saving the old string value in |test_insert|." << endl; + ++tests_failed; + } + + string_class_traits::implementation_t insertable( string_class_traits::literal_hello() ); + + insertable.SetLength(1); + aWritable.Insert(insertable, 0); + + if ( aWritable != (insertable + oldValue) ) + { + cout << "FAILED in |test_insert|." << endl; + ++tests_failed; + } + + aWritable = oldValue; + + return tests_failed; + } + + +template +int +test_cut( basic_nsAString& aWritable ) + { + int tests_failed = 0; + + aWritable.Cut(0, aWritable.Length()+5); + + return tests_failed; + } + +template +int +test_self_assign( basic_nsAString& aWritable ) + { + int tests_failed = 0; + string_class_traits::implementation_t oldValue(aWritable); + + aWritable = aWritable; + if ( aWritable != oldValue ) + { + cout << "FAILED self assignment." << endl; + ++tests_failed; + } + + aWritable = oldValue; + return tests_failed; + } + +template +int +test_self_append( basic_nsAString& aWritable ) + { + int tests_failed = 0; + string_class_traits::implementation_t oldValue(aWritable); + + aWritable += aWritable; + if ( aWritable != oldValue + oldValue ) + { + cout << "FAILED self append." << endl; + ++tests_failed; + } + + aWritable = oldValue; + return tests_failed; + } + +template +int +test_self_insert( basic_nsAString& aWritable ) + { + int tests_failed = 0; + string_class_traits::implementation_t oldValue(aWritable); + + aWritable.Insert(aWritable, 0); + if ( aWritable != oldValue + oldValue ) + { + cout << "FAILED self insert." << endl; + ++tests_failed; + } + + aWritable = oldValue; + return tests_failed; + } + +template +int +test_self_replace( basic_nsAString& aWritable ) + { + int tests_failed = 0; + string_class_traits::implementation_t oldValue(aWritable); + + aWritable.Replace(0, 0, aWritable); + if ( aWritable != oldValue + oldValue ) + { + cout << "FAILED self insert." << endl; + ++tests_failed; + } + + aWritable = oldValue; + return tests_failed; + } + + + +template +int +test_writable( basic_nsAString& aWritable ) + { + int tests_failed = 0; + // ... + + + { + typedef CharT* CharT_ptr; + aWritable = literal_hello(CharT_ptr()); + + if ( aWritable != literal_hello(CharT_ptr()) ) + { + cout << "FAILED assignment and/or comparison in |test_writable|." << endl; + ++tests_failed; + } + + tests_failed += test_readable_hello(aWritable); + } + + tests_failed += test_SetLength(aWritable); + tests_failed += test_insert(aWritable); + tests_failed += test_cut(aWritable); + tests_failed += test_self_assign(aWritable); + tests_failed += test_self_append(aWritable); + tests_failed += test_self_insert(aWritable); + tests_failed += test_self_replace(aWritable); + + return tests_failed; + } + + + +typedef void* void_ptr; + +int +main() + { + int tests_failed = 0; + cout << "String unit tests. Compiled " __DATE__ " " __TIME__ << endl; + +#if 0 + { + nsFragmentedCString fs0; + fs0.Append("Hello"); + tests_failed += test_readable_hello(fs0); + tests_failed += test_writable(fs0); + } +#endif + + { + NS_NAMED_LITERAL_STRING(literal, "Hello"); + PRUnichar* buffer = ToNewUnicode(literal); + + nsSlidingString ss0(buffer, buffer+5, buffer+6); +// ss0.AppendBuffer(buffer, buffer+5, buffer+6); + nsReadingIterator ri0; + ss0.BeginReading(ri0); + + tests_failed += test_readable_hello(ss0); + + nsSlidingSubstring ss1(ss0); + tests_failed += test_readable_hello(ss1); + + buffer = ToNewUnicode(literal); + ss0.AppendBuffer(buffer, buffer+5, buffer+6); + + ri0.advance(5); + ss0.DiscardPrefix(ri0); + + tests_failed += test_readable_hello(ss0); + tests_failed += test_readable_hello(ss1); + + nsReadingIterator ri1; + ss0.EndReading(ri1); + + nsSlidingSubstring ss2(ss0, ri0, ri1); + tests_failed += test_readable_hello(ss2); + } + + + { + nsLiteralCString s0("Patrick Beard made me write this: \"This is just a test\"\n"); + print_string(s0); + + const char* raw_string = "He also made me write this.\n"; + nsFileCharSink output(stdout); + copy_string(raw_string, raw_string+nsCharTraits::length(raw_string), output); + + nsLiteralCString s1("This ", 5), s2("is ", 3), s3("a ", 2), s4("test\n", 5); + print_string(s1+s2+s3+s4); + + nsLiteralCString s5( "This is " "a " "test" ); + print_string(s5+NS_LITERAL_CSTRING("\n")); + + print_string(nsLiteralCString("The value of the string |x| is \"") + Substring(s0, 0, s0.Length()-1) + NS_LITERAL_CSTRING("\". Hope you liked it.")); + } + + + { + tests_failed += test_readable_hello(NS_LITERAL_STRING("Hello")); + + nsLiteralCString s1("Hello"); + tests_failed += test_readable_hello(s1); + } + + { + + nsString s3( NS_LITERAL_STRING("Hello") ); + + tests_failed += test_readable_hello(s3); + tests_failed += test_writable(s3); + + nsCString s4("Hello"); + tests_failed += test_readable_hello(s4); + tests_failed += test_writable(s4); + } + + { + nsStdString s5( NS_LITERAL_STRING("Hello") ); + + tests_failed += test_readable_hello(s5); + tests_failed += test_writable(s5); + + nsStdCString s6("Hello"); + tests_failed += test_readable_hello(s6); + tests_failed += test_writable(s6); + } + + { + nsLiteralString s7(NS_LITERAL_STRING("He")); + nsString s8(NS_LITERAL_STRING("l")); + nsStdString s9(NS_LITERAL_STRING("lo")); + + tests_failed += test_readable_hello(s7+s8+s9); + + nsString s13( s7 + s8 + s9 ); + tests_failed += test_readable_hello(s13); + + nsStdString s14( s7 + s8 + s9 ); + tests_failed += test_readable_hello(s14); + + nsCString s10("He"); + nsLiteralCString s11("l"); + nsStdCString s12("lo"); + + tests_failed += test_readable_hello(s10+s11+s12); + + + } + + { + const char *foo = "this is a really long string"; + nsCString origString; + nsCString string2; + nsCString string3; + + origString = foo; + + string2 = Substring(origString, 0, 5); + string3 = Substring(origString, 6, origString.Length() - 6); + } + + { + nsLiteralCString s13("He"); + nsCAutoString s14("l"); + nsLiteralCString s15("lo"); + + s14.Assign(s13 + s14 + s15); + + if ( int failures = test_readable_hello(s14) ) + { + tests_failed += failures; + cout << "FAILED to keep a promise." << endl; + } + } + + + { + nsLiteralCString str1("Hello"); + nsStdCString str2("Hello"); + + nsLiteralCString str3("Hello there"); + + if ( str1 != str2 ) + { + cout << "string comparison using != failed" << endl; + ++tests_failed; + } + + if ( !(str3 > str2) ) + { + cout << "string comparison using > failed" << endl; + ++tests_failed; + } + + if ( !(str2 < str3) ) + { + cout << "string comparison using < failed" << endl; + ++tests_failed; + } + + if ( str1 != "Hello" ) + { + cout << "string comparison using == failed" << endl; + ++tests_failed; + } + } + +#if 0 + nsStdCString extracted_middle("XXXXXXXXXX"); + CallCMid(extracted_middle, part1+part2a+part2b, 1, 3); + + cout << "The result of mid was \"" << extracted_middle << "\"" << endl; + + nsLiteralCString middle_answer("ell"); + if ( middle_answer != extracted_middle ) + { + cout << "mid FAILED on nsConcatString" << endl; + ++tests_failed; + } + + + + // + // |nsStdStringWrapper|, i.e., |nsStdCString| + // + + { + nsStdCString extracted_middle; + CallCMid(extracted_middle, part1+part2a+part2b, 1, 3); + + cout << "The result of mid was \"" << extracted_middle << "\"" << endl; + + nsLiteralCString middle_answer("ell"); + if ( middle_answer != extracted_middle ) + { + cout << "mid FAILED on nsStdCString" << endl; + ++tests_failed; + } + } + + + + nsStdCString leftString; + source.Left(leftString, 9); + // cout << static_cast(leftString) << endl; + + + + tests_failed += test_multifragment_iterators(part1+part2a+part2b); +#endif + + + + cout << "End of string unit tests." << endl; + if ( !tests_failed ) + cout << "OK, all tests passed." << endl; + else + cout << "FAILED one or more tests." << endl; + + return tests_failed; + } diff --git a/src/libs/xpcom18a4/xpcom/tests/TestArray.cpp b/src/libs/xpcom18a4/xpcom/tests/TestArray.cpp new file mode 100644 index 00000000..852938fe --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/TestArray.cpp @@ -0,0 +1,230 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Pierre Phaneuf + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 +#include +#include "nsISupportsArray.h" + +// {9e70a320-be02-11d1-8031-006008159b5a} +#define NS_IFOO_IID \ + {0x9e70a320, 0xbe02, 0x11d1, \ + {0x80, 0x31, 0x00, 0x60, 0x08, 0x15, 0x9b, 0x5a}} + +static const PRBool kExitOnError = PR_TRUE; + +class IFoo : public nsISupports { +public: + + NS_DEFINE_STATIC_IID_ACCESSOR(NS_IFOO_IID) + + NS_IMETHOD_(nsrefcnt) RefCnt() = 0; + NS_IMETHOD_(PRInt32) ID() = 0; +}; + +class Foo : public IFoo { +public: + + Foo(PRInt32 aID); + + // nsISupports implementation + NS_DECL_ISUPPORTS + + // IFoo implementation + NS_IMETHOD_(nsrefcnt) RefCnt() { return mRefCnt; } + NS_IMETHOD_(PRInt32) ID() { return mID; } + + static PRInt32 gCount; + + PRInt32 mID; + +private: + ~Foo(); +}; + +PRInt32 Foo::gCount; + +Foo::Foo(PRInt32 aID) +{ + mID = aID; + ++gCount; + fprintf(stdout, "init: %d (%p), %d total)\n", mID, this, gCount); +} + +Foo::~Foo() +{ + --gCount; + fprintf(stdout, "destruct: %d (%p), %d remain)\n", mID, this, gCount); +} + +NS_IMPL_ISUPPORTS1(Foo, IFoo) + +const char* AssertEqual(PRInt32 aValue1, PRInt32 aValue2) +{ + if (aValue1 == aValue2) { + return "OK"; + } + if (kExitOnError) { + exit(1); + } + return "ERROR"; +} + +void DumpArray(nsISupportsArray* aArray, PRInt32 aExpectedCount, PRInt32 aElementIDs[], PRInt32 aExpectedTotal) +{ + PRUint32 cnt = 0; + nsresult rv = aArray->Count(&cnt); + NS_ASSERTION(NS_SUCCEEDED(rv), "Count failed"); + PRInt32 count = cnt; + PRInt32 index; + + fprintf(stdout, "object count %d = %d %s\n", Foo::gCount, aExpectedTotal, + AssertEqual(Foo::gCount, aExpectedTotal)); + fprintf(stdout, "array count %d = %d %s\n", count, aExpectedCount, + AssertEqual(count, aExpectedCount)); + + for (index = 0; (index < count) && (index < aExpectedCount); index++) { + IFoo* foo = (IFoo*)(aArray->ElementAt(index)); + fprintf(stdout, "%2d: %d=%d (%p) c: %d %s\n", + index, aElementIDs[index], foo->ID(), foo, foo->RefCnt() - 1, + AssertEqual(foo->ID(), aElementIDs[index])); + foo->Release(); + } +} + +void FillArray(nsISupportsArray* aArray, PRInt32 aCount) +{ + PRInt32 index; + for (index = 0; index < aCount; index++) { + nsCOMPtr foo = new Foo(index); + aArray->AppendElement(foo); + } +} + +int main(int argc, char *argv[]) +{ + nsISupportsArray* array; + nsresult rv; + + if (NS_OK == (rv = NS_NewISupportsArray(&array))) { + FillArray(array, 10); + fprintf(stdout, "Array created:\n"); + PRInt32 fillResult[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; + DumpArray(array, 10, fillResult, 10); + + // test insert + IFoo* foo = (IFoo*)array->ElementAt(3); + foo->Release(); // pre-release to fix ref count for dumps + array->InsertElementAt(foo, 5); + fprintf(stdout, "insert 3 at 5:\n"); + PRInt32 insertResult[11] = {0, 1, 2, 3, 4, 3, 5, 6, 7, 8, 9}; + DumpArray(array, 11, insertResult, 10); + fprintf(stdout, "insert 3 at 0:\n"); + array->InsertElementAt(foo, 0); + PRInt32 insertResult2[12] = {3, 0, 1, 2, 3, 4, 3, 5, 6, 7, 8, 9}; + DumpArray(array, 12, insertResult2, 10); + fprintf(stdout, "append 3:\n"); + array->AppendElement(foo); + PRInt32 appendResult[13] = {3, 0, 1, 2, 3, 4, 3, 5, 6, 7, 8, 9, 3}; + DumpArray(array, 13, appendResult, 10); + + + // test IndexOf && LastIndexOf + PRInt32 expectedIndex[5] = {0, 4, 6, 12, -1}; + PRInt32 count = 0; + PRInt32 index = array->IndexOf(foo); + fprintf(stdout, "IndexOf(foo): %d=%d %s\n", index, expectedIndex[count], + AssertEqual(index, expectedIndex[count])); + while (-1 != index) { + count++; + index = array->IndexOfStartingAt(foo, index + 1); + if (-1 != index) + fprintf(stdout, "IndexOf(foo): %d=%d %s\n", index, expectedIndex[count], + AssertEqual(index, expectedIndex[count])); + } + index = array->LastIndexOf(foo); + count--; + fprintf(stdout, "LastIndexOf(foo): %d=%d %s\n", index, expectedIndex[count], + AssertEqual(index, expectedIndex[count])); + + // test ReplaceElementAt + fprintf(stdout, "ReplaceElementAt(8):\n"); + array->ReplaceElementAt(foo, 8); + PRInt32 replaceResult[13] = {3, 0, 1, 2, 3, 4, 3, 5, 3, 7, 8, 9, 3}; + DumpArray(array, 13, replaceResult, 9); + + // test RemoveElementAt, RemoveElement RemoveLastElement + fprintf(stdout, "RemoveElementAt(0):\n"); + array->RemoveElementAt(0); + PRInt32 removeResult[12] = {0, 1, 2, 3, 4, 3, 5, 3, 7, 8, 9, 3}; + DumpArray(array, 12, removeResult, 9); + fprintf(stdout, "RemoveElementAt(7):\n"); + array->RemoveElementAt(7); + PRInt32 removeResult2[11] = {0, 1, 2, 3, 4, 3, 5, 7, 8, 9, 3}; + DumpArray(array, 11, removeResult2, 9); + fprintf(stdout, "RemoveElement(foo):\n"); + array->RemoveElement(foo); + PRInt32 removeResult3[10] = {0, 1, 2, 4, 3, 5, 7, 8, 9, 3}; + DumpArray(array, 10, removeResult3, 9); + fprintf(stdout, "RemoveLastElement(foo):\n"); + array->RemoveLastElement(foo); + PRInt32 removeResult4[9] = {0, 1, 2, 4, 3, 5, 7, 8, 9}; + DumpArray(array, 9, removeResult4, 9); + + // test clear + fprintf(stdout, "clear array:\n"); + array->Clear(); + DumpArray(array, 0, 0, 0); + fprintf(stdout, "add 4 new:\n"); + FillArray(array, 4); + DumpArray(array, 4, fillResult, 4); + + // test compact + fprintf(stdout, "compact array:\n"); + array->Compact(); + DumpArray(array, 4, fillResult, 4); + + // test delete + fprintf(stdout, "release array:\n"); + NS_RELEASE(array); + } + else { + fprintf(stdout, "error can't create array: %x\n", rv); + } + + return 0; +} diff --git a/src/libs/xpcom18a4/xpcom/tests/TestAtoms.cpp b/src/libs/xpcom18a4/xpcom/tests/TestAtoms.cpp new file mode 100644 index 00000000..48b2f603 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/TestAtoms.cpp @@ -0,0 +1,132 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsIAtom.h" +#include "nsString.h" +#include "nsReadableUtils.h" +#include "prprf.h" +#include "prtime.h" +#include + +extern "C" int _CrtSetDbgFlag(int); + +int main(int argc, char** argv) +{ + FILE* fp = fopen("words.txt", "r"); + if (nsnull == fp) { + printf("can't open words.txt\n"); + return -1; + } + + PRInt32 count = 0; + PRUnichar** strings = new PRUnichar*[60000]; + nsIAtom** ids = new nsIAtom*[60000]; + nsAutoString s1, s2; + PRTime start = PR_Now(); + PRInt32 i; + for (i = 0; i < 30000; i++) { + char buf[1000]; + char* s = fgets(buf, sizeof(buf), fp); + if (nsnull == s) { + break; + } + nsCAutoString sb; + sb.Assign(buf); + strings[count++] = ToNewUnicode(sb); + ToUpperCase(sb); + strings[count++] = ToNewUnicode(sb); + } + PRTime end0 = PR_Now(); + + // Find and create idents + for (i = 0; i < count; i++) { + ids[i] = NS_NewAtom(strings[i]); + } + PRUnichar qqs[1]; qqs[0] = 0; + nsIAtom* qq = NS_NewAtom(qqs); + PRTime end1 = PR_Now(); + + // Now make sure we can find all the idents we just made + for (i = 0; i < count; i++) { + const char *utf8String; + ids[i]->GetUTF8String(&utf8String); + nsIAtom* id = NS_NewAtom(utf8String); + if (id != ids[i]) { + id->ToString(s1); + ids[i]->ToString(s2); + printf("find failed: id='%s' ids[%d]='%s'\n", + NS_LossyConvertUCS2toASCII(s1).get(), i, NS_LossyConvertUCS2toASCII(s2).get()); + return -1; + } + NS_RELEASE(id); + } + PRTime end2 = PR_Now(); + + // Destroy all the atoms we just made + NS_RELEASE(qq); + for (i = 0; i < count; i++) { + NS_RELEASE(ids[i]); + } + + // Print out timings + PRTime end3 = PR_Now(); + PRTime creates, finds, lookups, dtor, ustoms; + LL_I2L(ustoms, 1000); + LL_SUB(creates, end0, start); + LL_DIV(creates, creates, ustoms); + LL_SUB(finds, end1, end0); + LL_DIV(finds, finds, ustoms); + LL_SUB(lookups, end2, end1); + LL_DIV(lookups, lookups, ustoms); + LL_SUB(dtor, end3, end2); + char buf[500]; + PR_snprintf(buf, sizeof(buf), "making %d ident strings took %lldms", + count, creates); + puts(buf); + PR_snprintf(buf, sizeof(buf), "%d new idents took %lldms", + count, finds); + puts(buf); + PR_snprintf(buf, sizeof(buf), "%d ident lookups took %lldms", + count, lookups); + puts(buf); + PR_snprintf(buf, sizeof(buf), "dtor took %lldusec", dtor); + puts(buf); + + printf("%d live atoms\n", NS_GetNumberOfAtoms()); + NS_POSTCONDITION(0 == NS_GetNumberOfAtoms(), "dangling atoms"); + + return 0; +} diff --git a/src/libs/xpcom18a4/xpcom/tests/TestAutoLock.cpp b/src/libs/xpcom18a4/xpcom/tests/TestAutoLock.cpp new file mode 100644 index 00000000..4537044f --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/TestAutoLock.cpp @@ -0,0 +1,91 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* + + Some tests for nsAutoLock. + + */ + +#include "nsAutoLock.h" +#include "prthread.h" + +PRLock* gLock; +int gCount; + +static void PR_CALLBACK run(void* arg) +{ + for (int i = 0; i < 1000000; ++i) { + nsAutoLock guard(gLock); + ++gCount; + PR_ASSERT(gCount == 1); + --gCount; + } +} + + +int main(int argc, char** argv) +{ + gLock = PR_NewLock(); + gCount = 0; + + // This shouldn't compile + //nsAutoLock* l1 = new nsAutoLock(theLock); + //delete l1; + + // Create a block-scoped lock. This should compile. + { + nsAutoLock l2(gLock); + } + + // Fork a thread to access the shared variable in a tight loop + PRThread* t1 = + PR_CreateThread(PR_SYSTEM_THREAD, + run, + nsnull, + PR_PRIORITY_NORMAL, + PR_GLOBAL_THREAD, + PR_JOINABLE_THREAD, + 0); + + // ...and now do the same thing ourselves + run(nsnull); + + // Wait for the background thread to finish, if necessary. + PR_JoinThread(t1); + return 0; +} diff --git a/src/libs/xpcom18a4/xpcom/tests/TestAutoPtr.cpp b/src/libs/xpcom18a4/xpcom/tests/TestAutoPtr.cpp new file mode 100644 index 00000000..c48134a4 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/TestAutoPtr.cpp @@ -0,0 +1,566 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +// vim:cindent:ts=4:et:sw=4: +/* ***** 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 TestCOMPtrEq.cpp. + * + * The Initial Developer of the Original Code is + * L. David Baron. + * Portions created by the Initial Developer are Copyright (C) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * L. David Baron (original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsAutoPtr.h" +#include +#include "nscore.h" + +class TestObjectBaseA { + public: + // Virtual dtor for deleting through base class pointer + virtual ~TestObjectBaseA() { }; + int fooA; +}; + +class TestObjectBaseB { + public: + // Virtual dtor for deleting through base class pointer + virtual ~TestObjectBaseB() { }; + int fooB; +}; + +class TestObject : public TestObjectBaseA, public TestObjectBaseB { + public: + TestObject() + { + printf(" Creating TestObject %p.\n", + NS_STATIC_CAST(void*, this)); + } + + // Virtual dtor for deleting through base class pointer + virtual ~TestObject() + { + printf(" Destroying TestObject %p.\n", + NS_STATIC_CAST(void*, this)); + } +}; + +class TestRefObjectBaseA { + public: + int fooA; + // Must return |nsrefcnt| to keep |nsDerivedSafe| happy. + virtual nsrefcnt AddRef() = 0; + virtual nsrefcnt Release() = 0; +}; + +class TestRefObjectBaseB { + public: + int fooB; + virtual nsrefcnt AddRef() = 0; + virtual nsrefcnt Release() = 0; +}; + +class TestRefObject : public TestRefObjectBaseA, public TestRefObjectBaseB { + public: + TestRefObject() + : mRefCount(0) + { + printf(" Creating TestRefObject %p.\n", + NS_STATIC_CAST(void*, this)); + } + + ~TestRefObject() + { + printf(" Destroying TestRefObject %p.\n", + NS_STATIC_CAST(void*, this)); + } + + nsrefcnt AddRef() + { + ++mRefCount; + printf(" AddRef to %d on TestRefObject %p.\n", + mRefCount, NS_STATIC_CAST(void*, this)); + return mRefCount; + } + + nsrefcnt Release() + { + --mRefCount; + printf(" Release to %d on TestRefObject %p.\n", + mRefCount, NS_STATIC_CAST(void*, this)); + if (mRefCount == 0) { + delete NS_CONST_CAST(TestRefObject*, this); + return 0; + } + return mRefCount; + } + + protected: + PRUint32 mRefCount; + +}; + +static void CreateTestObject(TestObject **aResult) +{ + *aResult = new TestObject(); +} + +static void CreateTestRefObject(TestRefObject **aResult) +{ + (*aResult = new TestRefObject())->AddRef(); +} + +static void DoSomethingWithTestObject(TestObject *aIn) +{ + printf(" Doing something with |TestObject| %p.\n", + NS_STATIC_CAST(void*, aIn)); +} + +static void DoSomethingWithConstTestObject(const TestObject *aIn) +{ + printf(" Doing something with |const TestObject| %p.\n", + NS_STATIC_CAST(const void*, aIn)); +} + +static void DoSomethingWithTestRefObject(TestRefObject *aIn) +{ + printf(" Doing something with |TestRefObject| %p.\n", + NS_STATIC_CAST(void*, aIn)); +} + +static void DoSomethingWithConstTestRefObject(const TestRefObject *aIn) +{ + printf(" Doing something with |const TestRefObject| %p.\n", + NS_STATIC_CAST(const void*, aIn)); +} + +static void DoSomethingWithTestObjectBaseB(TestObjectBaseB *aIn) +{ + printf(" Doing something with |TestObjectBaseB| %p.\n", + NS_STATIC_CAST(void*, aIn)); +} + +static void DoSomethingWithConstTestObjectBaseB(const TestObjectBaseB *aIn) +{ + printf(" Doing something with |const TestObjectBaseB| %p.\n", + NS_STATIC_CAST(const void*, aIn)); +} + +static void DoSomethingWithTestRefObjectBaseB(TestRefObjectBaseB *aIn) +{ + printf(" Doing something with |TestRefObjectBaseB| %p.\n", + NS_STATIC_CAST(void*, aIn)); +} + +static void DoSomethingWithConstTestRefObjectBaseB(const TestRefObjectBaseB *aIn) +{ + printf(" Doing something with |const TestRefObjectBaseB| %p.\n", + NS_STATIC_CAST(const void*, aIn)); +} + +int main() +{ + { + printf("Should create one |TestObject|:\n"); + nsAutoPtr pobj( new TestObject() ); + printf("Should destroy one |TestObject|:\n"); + } + + { + printf("Should create one |TestObject|:\n"); + nsAutoPtr pobj( new TestObject() ); + printf("Should create one |TestObject| and then destroy one:\n"); + pobj = new TestObject(); + printf("Should destroy one |TestObject|:\n"); + } + + { + printf("Should create 3 |TestObject|s:\n"); + nsAutoArrayPtr pobj( new TestObject[3] ); + printf("Should create 5 |TestObject|s and then destroy 3:\n"); + pobj = new TestObject[5]; + printf("Should destroy 5 |TestObject|s:\n"); + } + + { + printf("Should create and AddRef one |TestRefObject|:\n"); + nsRefPtr pobj( new TestRefObject() ); + printf("Should Release and destroy one |TestRefObject|:\n"); + } + + { + printf("Should create and AddRef one |TestRefObject|:\n"); + nsRefPtr pobj( new TestRefObject() ); + printf("Should create and AddRef one |TestRefObject| and then Release and destroy one:\n"); + pobj = new TestRefObject(); + printf("Should Release and destroy one |TestRefObject|:\n"); + } + + { + printf("Should create and AddRef one |TestRefObject|:\n"); + nsRefPtr p1( new TestRefObject() ); + printf("Should AddRef one |TestRefObject|:\n"); + nsRefPtr p2( p1 ); + printf("Should Release twice and destroy one |TestRefObject|:\n"); + } + + printf("\nTesting equality (with all const-ness combinations):\n"); + + { + nsRefPtr p1( new TestRefObject() ); + nsRefPtr p2( p1 ); + printf("equality %s.\n", + ((p1 == p2) && !(p1 != p2)) ? "OK" : "broken"); + } + + { + const nsRefPtr p1( new TestRefObject() ); + nsRefPtr p2( p1 ); + printf("equality %s.\n", + ((p1 == p2) && !(p1 != p2)) ? "OK" : "broken"); + } + + { + nsRefPtr p1( new TestRefObject() ); + const nsRefPtr p2( p1 ); + printf("equality %s.\n", + ((p1 == p2) && !(p1 != p2)) ? "OK" : "broken"); + } + + { + const nsRefPtr p1( new TestRefObject() ); + const nsRefPtr p2( p1 ); + printf("equality %s.\n", + ((p1 == p2) && !(p1 != p2)) ? "OK" : "broken"); + } + + { + nsRefPtr p1( new TestRefObject() ); + TestRefObject * p2 = p1; + printf("equality %s.\n", + ((p1 == p2) && !(p1 != p2) && (p2 == p1) && !(p2 != p1)) ? "OK" : "broken"); + } + + { + const nsRefPtr p1( new TestRefObject() ); + TestRefObject * p2 = p1; + printf("equality %s.\n", + ((p1 == p2) && !(p1 != p2) && (p2 == p1) && !(p2 != p1)) ? "OK" : "broken"); + } + +#if 0 /* MSVC++ 6.0 can't be coaxed to accept this */ + { + nsRefPtr p1( new TestRefObject() ); + TestRefObject * const p2 = p1; + printf("equality %s.\n", + ((p1 == p2) && !(p1 != p2) && (p2 == p1) && !(p2 != p1)) ? "OK" : "broken"); + } + + { + const nsRefPtr p1( new TestRefObject() ); + TestRefObject * const p2 = p1; + printf("equality %s.\n", + ((p1 == p2) && !(p1 != p2) && (p2 == p1) && !(p2 != p1)) ? "OK" : "broken"); + } +#endif /* Things that MSVC++ 6.0 can't be coaxed to accept */ + + { + nsRefPtr p1( new TestRefObject() ); + const TestRefObject * p2 = p1; + printf("equality %s.\n", + ((p1 == p2) && !(p1 != p2) && (p2 == p1) && !(p2 != p1)) ? "OK" : "broken"); + } + + { + const nsRefPtr p1( new TestRefObject() ); + const TestRefObject * p2 = p1; + printf("equality %s.\n", + ((p1 == p2) && !(p1 != p2) && (p2 == p1) && !(p2 != p1)) ? "OK" : "broken"); + } + + { + nsRefPtr p1( new TestRefObject() ); + const TestRefObject * const p2 = p1; + printf("equality %s.\n", + ((p1 == p2) && !(p1 != p2) && (p2 == p1) && !(p2 != p1)) ? "OK" : "broken"); + } + + { + const nsRefPtr p1( new TestRefObject() ); + const TestRefObject * const p2 = p1; + printf("equality %s.\n", + ((p1 == p2) && !(p1 != p2) && (p2 == p1) && !(p2 != p1)) ? "OK" : "broken"); + } + + printf("\nTesting getter_Transfers and getter_AddRefs.\n"); + + { + nsAutoPtr ptr; + printf("Should create one |TestObject|:\n"); + CreateTestObject(getter_Transfers(ptr)); + printf("Should destroy one |TestObject|:\n"); + } + + { + nsRefPtr ptr; + printf("Should create and AddRef one |TestRefObject|:\n"); + CreateTestRefObject(getter_AddRefs(ptr)); + printf("Should Release and destroy one |TestRefObject|:\n"); + } + + printf("\nTesting casts and equality tests.\n"); + + if ((void*)(TestObject*)0x1000 == + (void*)(TestObjectBaseB*)(TestObject*)0x1000) + printf("\n\nAll these tests are meaningless!\n\n\n"); + + { + nsAutoPtr p1(new TestObject()); + TestObjectBaseB *p2 = p1; + printf("equality %s.\n", + ((NS_STATIC_CAST(void*, p1) != NS_STATIC_CAST(void*, p2)) && + (p1 == p2) && !(p1 != p2) && (p2 == p1) && !(p2 != p1)) + ? "OK" : "broken"); + } + + { + TestObject *p1 = new TestObject(); + nsAutoPtr p2(p1); + printf("equality %s.\n", + ((NS_STATIC_CAST(void*, p1) != NS_STATIC_CAST(void*, p2)) && + (p1 == p2) && !(p1 != p2) && (p2 == p1) && !(p2 != p1)) + ? "OK" : "broken"); + } + + { + nsRefPtr p1 = new TestRefObject(); + // nsCOMPtr requires a |get| for something like this as well + nsRefPtr p2 = p1.get(); + printf("equality %s.\n", + ((NS_STATIC_CAST(void*, p1) != NS_STATIC_CAST(void*, p2)) && + (p1 == p2) && !(p1 != p2) && (p2 == p1) && !(p2 != p1)) + ? "OK" : "broken"); + } + + { + nsRefPtr p1 = new TestRefObject(); + TestRefObjectBaseB *p2 = p1; + printf("equality %s.\n", + ((NS_STATIC_CAST(void*, p1) != NS_STATIC_CAST(void*, p2)) && + (p1 == p2) && !(p1 != p2) && (p2 == p1) && !(p2 != p1)) + ? "OK" : "broken"); + } + + { + TestRefObject *p1 = new TestRefObject(); + nsRefPtr p2 = p1; + printf("equality %s.\n", + ((NS_STATIC_CAST(void*, p1) != NS_STATIC_CAST(void*, p2)) && + (p1 == p2) && !(p1 != p2) && (p2 == p1) && !(p2 != p1)) + ? "OK" : "broken"); + } + + printf("\nTesting |forget()|.\n"); + + { + printf("Should create one |TestObject|:\n"); + nsAutoPtr pobj( new TestObject() ); + printf("Should do nothing:\n"); + nsAutoPtr pobj2( pobj.forget() ); + printf("Should destroy one |TestObject|:\n"); + } + + { + printf("Should create 3 |TestObject|s:\n"); + nsAutoArrayPtr pobj( new TestObject[3] ); + printf("Should do nothing:\n"); + nsAutoArrayPtr pobj2( pobj.forget() ); + printf("Should destroy 3 |TestObject|s:\n"); + } + + printf("\nTesting construction.\n"); + + { + printf("Should create one |TestObject|:\n"); + nsAutoPtr pobj(new TestObject()); + printf("Should destroy one |TestObject|:\n"); + } + + { + printf("Should create 3 |TestObject|s:\n"); + nsAutoArrayPtr pobj(new TestObject[3]); + printf("Should destroy 3 |TestObject|s:\n"); + } + + { + printf("Should create and AddRef one |TestRefObject|:\n"); + nsRefPtr pobj = new TestRefObject(); + printf("Should Release and destroy one |TestRefObject|:\n"); + } + + printf("\nTesting calling of functions (including array access and casts).\n"); + + { + printf("Should create one |TestObject|:\n"); + nsAutoPtr pobj(new TestObject()); + printf("Should do something with one |TestObject|:\n"); + DoSomethingWithTestObject(pobj); + printf("Should do something with one |TestObject|:\n"); + DoSomethingWithConstTestObject(pobj); + printf("Should destroy one |TestObject|:\n"); + } + + { + printf("Should create 3 |TestObject|s:\n"); + nsAutoArrayPtr pobj(new TestObject[3]); + printf("Should do something with one |TestObject|:\n"); + DoSomethingWithTestObject(&pobj[2]); + printf("Should do something with one |TestObject|:\n"); + DoSomethingWithConstTestObject(&pobj[1]); + printf("Should do something with one |TestObject|:\n"); + DoSomethingWithTestObject(pobj + 2); + printf("Should do something with one |TestObject|:\n"); + DoSomethingWithConstTestObject(pobj + 1); + printf("Should destroy 3 |TestObject|s:\n"); + } + + { + printf("Should create and AddRef one |TestRefObject|:\n"); + nsRefPtr pobj = new TestRefObject(); + printf("Should do something with one |TestRefObject|:\n"); + DoSomethingWithTestRefObject(pobj); + printf("Should do something with one |TestRefObject|:\n"); + DoSomethingWithConstTestRefObject(pobj); + printf("Should Release and destroy one |TestRefObject|:\n"); + } + + { + printf("Should create one |TestObject|:\n"); + nsAutoPtr pobj(new TestObject()); + printf("Should do something with one |TestObject|:\n"); + DoSomethingWithTestObjectBaseB(pobj); + printf("Should do something with one |TestObject|:\n"); + DoSomethingWithConstTestObjectBaseB(pobj); + printf("Should destroy one |TestObject|:\n"); + } + + { + printf("Should create 3 |TestObject|s:\n"); + nsAutoArrayPtr pobj(new TestObject[3]); + printf("Should do something with one |TestObject|:\n"); + DoSomethingWithTestObjectBaseB(&pobj[2]); + printf("Should do something with one |TestObject|:\n"); + DoSomethingWithConstTestObjectBaseB(&pobj[1]); + printf("Should do something with one |TestObject|:\n"); + DoSomethingWithTestObjectBaseB(pobj + 2); + printf("Should do something with one |TestObject|:\n"); + DoSomethingWithConstTestObjectBaseB(pobj + 1); + printf("Should destroy 3 |TestObject|s:\n"); + } + + { + printf("Should create and AddRef one |TestRefObject|:\n"); + nsRefPtr pobj = new TestRefObject(); + printf("Should do something with one |TestRefObject|:\n"); + DoSomethingWithTestRefObjectBaseB(pobj); + printf("Should do something with one |TestRefObject|:\n"); + DoSomethingWithConstTestRefObjectBaseB(pobj); + printf("Should Release and destroy one |TestRefObject|:\n"); + } + + { + printf("Should create one |TestObject|:\n"); + const nsAutoPtr pobj(new TestObject()); + printf("Should do something with one |TestObject|:\n"); + DoSomethingWithTestObject(pobj); + printf("Should do something with one |TestObject|:\n"); + DoSomethingWithConstTestObject(pobj); + printf("Should destroy one |TestObject|:\n"); + } + + { + printf("Should create 3 |TestObject|s:\n"); + const nsAutoArrayPtr pobj(new TestObject[3]); + printf("Should do something with one |TestObject|:\n"); + DoSomethingWithTestObject(&pobj[2]); + printf("Should do something with one |TestObject|:\n"); + DoSomethingWithConstTestObject(&pobj[1]); + printf("Should do something with one |TestObject|:\n"); + DoSomethingWithTestObject(pobj + 2); + printf("Should do something with one |TestObject|:\n"); + DoSomethingWithConstTestObject(pobj + 1); + printf("Should destroy 3 |TestObject|s:\n"); + } + + { + printf("Should create and AddRef one |TestRefObject|:\n"); + const nsRefPtr pobj = new TestRefObject(); + printf("Should do something with one |TestRefObject|:\n"); + DoSomethingWithTestRefObject(pobj); + printf("Should do something with one |TestRefObject|:\n"); + DoSomethingWithConstTestRefObject(pobj); + printf("Should Release and destroy one |TestRefObject|:\n"); + } + + { + printf("Should create one |TestObject|:\n"); + const nsAutoPtr pobj(new TestObject()); + printf("Should do something with one |TestObject|:\n"); + DoSomethingWithTestObjectBaseB(pobj); + printf("Should do something with one |TestObject|:\n"); + DoSomethingWithConstTestObjectBaseB(pobj); + printf("Should destroy one |TestObject|:\n"); + } + + { + printf("Should create 3 |TestObject|s:\n"); + const nsAutoArrayPtr pobj(new TestObject[3]); + printf("Should do something with one |TestObject|:\n"); + DoSomethingWithTestObjectBaseB(&pobj[2]); + printf("Should do something with one |TestObject|:\n"); + DoSomethingWithConstTestObjectBaseB(&pobj[1]); + printf("Should do something with one |TestObject|:\n"); + DoSomethingWithTestObjectBaseB(pobj + 2); + printf("Should do something with one |TestObject|:\n"); + DoSomethingWithConstTestObjectBaseB(pobj + 1); + printf("Should destroy 3 |TestObject|s:\n"); + } + + { + printf("Should create and AddRef one |TestRefObject|:\n"); + const nsRefPtr pobj = new TestRefObject(); + printf("Should do something with one |TestRefObject|:\n"); + DoSomethingWithTestRefObjectBaseB(pobj); + printf("Should do something with one |TestRefObject|:\n"); + DoSomethingWithConstTestRefObjectBaseB(pobj); + printf("Should Release and destroy one |TestRefObject|:\n"); + } + + return 0; +} diff --git a/src/libs/xpcom18a4/xpcom/tests/TestCOMPtr.cpp b/src/libs/xpcom18a4/xpcom/tests/TestCOMPtr.cpp new file mode 100644 index 00000000..c48219e2 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/TestCOMPtr.cpp @@ -0,0 +1,651 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Pierre Phaneuf + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 +#include +#include "nsCOMPtr.h" +#include "nsISupports.h" + +#ifdef HAVE_CPP_NEW_CASTS + #define STATIC_CAST(T,x) static_cast(x) + #define REINTERPRET_CAST(T,x) reinterpret_cast(x) +#else + #define STATIC_CAST(T,x) ((T)(x)) + #define REINTERPRET_CAST(T,x) ((T)(x)) +#endif + + +#define NS_IFOO_IID \ +{ 0x6f7652e0, 0xee43, 0x11d1, \ + { 0x9c, 0xc3, 0x00, 0x60, 0x08, 0x8c, 0xa6, 0xb3 } } + +class IFoo : public nsISupports + { + public: + NS_DEFINE_STATIC_IID_ACCESSOR(NS_IFOO_IID) + + public: + IFoo(); + // virtual dtor because IBar uses our Release() + virtual ~IFoo(); + + NS_IMETHOD_(nsrefcnt) AddRef(); + NS_IMETHOD_(nsrefcnt) Release(); + NS_IMETHOD QueryInterface( const nsIID&, void** ); + + static void print_totals(); + + private: + unsigned int refcount_; + + static unsigned int total_constructions_; + static unsigned int total_destructions_; + }; + +class IBar; + + // some types I'll need +typedef unsigned long NS_RESULT; + + // some functions I'll need (and define below) + nsresult CreateIFoo( void** ); + nsresult CreateIBar( void** result ); + void AnIFooPtrPtrContext( IFoo** ); + void AnISupportsPtrPtrContext( nsISupports** ); + void AVoidPtrPtrContext( void** ); + void set_a_IFoo( nsCOMPtr* result ); +nsCOMPtr return_a_IFoo(); + + + + +unsigned int IFoo::total_constructions_; +unsigned int IFoo::total_destructions_; + +class test_message + { + public: + test_message() + { + printf("BEGIN unit tests for |nsCOMPtr|, compiled " __DATE__ "\n"); + } + + ~test_message() + { + IFoo::print_totals(); + printf("END unit tests for |nsCOMPtr|.\n"); + } + }; + +test_message gTestMessage; + + + /* + ... + */ + +void +IFoo::print_totals() + { + printf("total constructions/destructions --> %d/%d\n", + total_constructions_, total_destructions_); + } + +IFoo::IFoo() + : refcount_(0) + { + ++total_constructions_; + printf(" new IFoo@%p [#%d]\n", + STATIC_CAST(void*, this), total_constructions_); + } + +IFoo::~IFoo() + { + ++total_destructions_; + printf("IFoo@%p::~IFoo() [#%d]\n", + STATIC_CAST(void*, this), total_destructions_); + } + +nsrefcnt +IFoo::AddRef() + { + ++refcount_; + printf("IFoo@%p::AddRef(), refcount --> %d\n", + STATIC_CAST(void*, this), refcount_); + return refcount_; + } + +nsrefcnt +IFoo::Release() + { + int wrap_message = (refcount_ == 1); + if ( wrap_message ) + printf(">>"); + + nsrefcnt const newcount = --refcount_; + printf("IFoo@%p::Release(), refcount --> %d\n", + STATIC_CAST(void*, this), newcount); + + if ( !newcount ) + { + printf(" delete IFoo@%p\n", STATIC_CAST(void*, this)); + delete this; + } + + if ( wrap_message ) + printf("<>CreateIFoo() --> "); + IFoo* foop = new IFoo; + printf("IFoo@%p\n", STATIC_CAST(void*, foop)); + + foop->AddRef(); + *result = foop; + + printf("<* result ) + { + printf(">>set_a_IFoo()\n"); + assert(result); + + nsCOMPtr foop( do_QueryInterface(new IFoo) ); + *result = foop; + printf("< +return_a_IFoo() + { + printf(">>return_a_IFoo()\n"); + nsCOMPtr foop( do_QueryInterface(new IFoo) ); + printf("<>CreateIBar() --> "); + IBar* barp = new IBar; + printf("IBar@%p\n", STATIC_CAST(void*, barp)); + + barp->AddRef(); + *result = barp; + + printf("<QueryInterface(NS_GET_IID(IFoo), REINTERPRET_CAST(void**, &fooP)) ) ) + { + try + { + fooP->print_totals(); + } + catch( ... ) + { + NS_RELEASE(fooP); + throw; + } + + NS_RELEASE(fooP); + } + } + catch( ... ) + { + NS_RELEASE(barP); + throw; + } + + NS_RELEASE(barP); + } + + return result; + } +#endif // TEST_EXCEPTIONS + +static +nsresult +TestBloat_Raw_Unsafe() + { + IBar* barP = 0; + nsresult result = CreateIBar(REINTERPRET_CAST(void**, &barP)); + + if ( barP ) + { + IFoo* fooP = 0; + if ( NS_SUCCEEDED( result = barP->QueryInterface(NS_GET_IID(IFoo), REINTERPRET_CAST(void**, &fooP)) ) ) + { + fooP->print_totals(); + NS_RELEASE(fooP); + } + + NS_RELEASE(barP); + } + + return result; + } + + +static +nsresult +TestBloat_Smart() + { + nsCOMPtr barP; + nsresult result = CreateIBar( getter_AddRefs(barP) ); + + nsCOMPtr fooP( do_QueryInterface(barP, &result) ); + + if ( fooP ) + fooP->print_totals(); + + return result; + } + + + + +nsCOMPtr gFoop; + +int +main() + { + printf(">>main()\n"); + + printf("sizeof(nsCOMPtr) --> %zd\n", sizeof(nsCOMPtr)); + +#ifdef TEST_EXCEPTIONS + TestBloat_Raw(); +#endif // TEST_EXCEPTIONS + TestBloat_Raw_Unsafe(); + TestBloat_Smart(); + + + { + printf("\n### Test 1: will a |nsCOMPtr| call |AddRef| on a pointer assigned into it?\n"); + nsCOMPtr foop( do_QueryInterface(new IFoo) ); + + printf("\n### Test 2: will a |nsCOMPtr| |Release| its old pointer when a new one is assigned in?\n"); + foop = do_QueryInterface(new IFoo); + + // [Shouldn't compile] Is it a compile time error to try to |AddRef| by hand? + //foop->AddRef(); + + // [Shouldn't compile] Is it a compile time error to try to |Release| be hand? + //foop->Release(); + + // [Shouldn't compile] Is it a compile time error to try to |delete| an |nsCOMPtr|? + //delete foop; + + printf("\n### Test 3: can you |AddRef| if you must?\n"); + STATIC_CAST(IFoo*, foop)->AddRef(); + + printf("\n### Test 4: can you |Release| if you must?\n"); + STATIC_CAST(IFoo*, foop)->Release(); + + printf("\n### Test 5: will a |nsCOMPtr| |Release| when it goes out of scope?\n"); + } + + { + printf("\n### Test 6: will a |nsCOMPtr| call the correct destructor?\n"); + nsCOMPtr foop( do_QueryInterface(new IBar) ); + } + + { + printf("\n### Test 7: can you compare one |nsCOMPtr| with another [!=]?\n"); + + nsCOMPtr foo1p( do_QueryInterface(new IFoo) ); + + // [Shouldn't compile] Is it a compile time error to omit |getter_[doesnt_]AddRef[s]|? + //AnIFooPtrPtrContext(&foo1p); + + // [Shouldn't compile] Is it a compile time error to omit |getter_[doesnt_]AddRef[s]|? + //AVoidPtrPtrContext(&foo1p); + + nsCOMPtr foo2p( do_QueryInterface(new IFoo) ); + + if ( foo1p != foo2p ) + printf("foo1p != foo2p\n"); + else + printf("foo1p == foo2p\n"); + + printf("\n### Test 7.5: can you compare a |nsCOMPtr| with NULL, 0, nsnull [!=]?\n"); + if ( foo1p != 0 ) + printf("foo1p != 0\n"); + if ( 0 != foo1p ) + printf("0 != foo1p\n"); + if ( foo1p == 0 ) + printf("foo1p == 0\n"); + if ( 0 == foo1p ) + printf("0 == foo1p\n"); + + + IFoo* raw_foo2p = foo2p.get(); + + printf("\n### Test 8: can you compare a |nsCOMPtr| with a raw interface pointer [!=]?\n"); + if ( foo1p.get() != raw_foo2p ) + printf("foo1p != raw_foo2p\n"); + else + printf("foo1p == raw_foo2p\n"); + + + printf("\n### Test 9: can you assign one |nsCOMPtr| into another?\n"); + foo1p = foo2p; + + printf("\n### Test 10: can you compare one |nsCOMPtr| with another [==]?\n"); + if ( foo1p == foo2p ) + printf("foo1p == foo2p\n"); + else + printf("foo1p != foo2p\n"); + + printf("\n### Test 11: can you compare a |nsCOMPtr| with a raw interface pointer [==]?\n"); + if ( raw_foo2p == foo2p.get() ) + printf("raw_foo2p == foo2p\n"); + else + printf("raw_foo2p != foo2p\n"); + +#if 1 + printf("\n### Test 11.5: can you compare a |nsCOMPtr| with a raw interface pointer [==]?\n"); + if ( nsCOMPtr( raw_foo2p ) == foo2p ) + printf("raw_foo2p == foo2p\n"); + else + printf("raw_foo2p != foo2p\n"); +#endif + + printf("\n### Test 12: bare pointer test?\n"); + if ( foo1p ) + printf("foo1p is not NULL\n"); + else + printf("foo1p is NULL\n"); + + printf("\n### Test 13: numeric pointer test?\n"); + if ( foo1p == 0 ) + printf("foo1p is NULL\n"); + else + printf("foo1p is not NULL\n"); + +#if 0 + if ( foo1p == 1 ) + printf("foo1p allowed compare with in\n"); +#endif + + printf("\n### Test 14: how about when two |nsCOMPtr|s referring to the same object go out of scope?\n"); + } + + { + printf("\n### Test 15,16 ...setup...\n"); + IFoo* raw_foo1p = new IFoo; + raw_foo1p->AddRef(); + + IFoo* raw_foo2p = new IFoo; + raw_foo2p->AddRef(); + + printf("\n### Test 15: what if I don't want to |AddRef| when I construct?\n"); + nsCOMPtr foo1p( dont_AddRef(raw_foo1p) ); + //nsCOMPtr foo1p = dont_AddRef(raw_foo1p); + + printf("\n### Test 16: what if I don't want to |AddRef| when I assign in?\n"); + nsCOMPtr foo2p; + foo2p = dont_AddRef(raw_foo2p); + } + + + + + + + + { + printf("\n### setup for Test 17\n"); + nsCOMPtr foop; + printf("### Test 17: basic parameter behavior?\n"); + CreateIFoo( nsGetterAddRefs(foop) ); + } + printf("### End Test 17\n"); + + + { + printf("\n### setup for Test 18\n"); + nsCOMPtr foop; + printf("### Test 18: basic parameter behavior, using the short form?\n"); + CreateIFoo( getter_AddRefs(foop) ); + } + printf("### End Test 18\n"); + + + { + printf("\n### setup for Test 19, 20\n"); + nsCOMPtr foop; + printf("### Test 19: reference parameter behavior?\n"); + set_a_IFoo(address_of(foop)); + + printf("### Test 20: return value behavior?\n"); + foop = return_a_IFoo(); + } + printf("### End Test 19, 20\n"); + + { + printf("\n### setup for Test 21\n"); + nsCOMPtr fooP; + + printf("### Test 21: is |QueryInterface| called on assigning in a raw pointer?\n"); + fooP = do_QueryInterface(new IFoo); + } + printf("### End Test 21\n"); + + { + printf("\n### setup for Test 22\n"); + nsCOMPtr fooP; + fooP = do_QueryInterface(new IFoo); + + nsCOMPtr foo2P; + + printf("### Test 22: is |QueryInterface| _not_ called when assigning in a smart-pointer of the same type?\n"); + foo2P = fooP; + } + printf("### End Test 22\n"); + + { + printf("\n### setup for Test 23\n"); + nsCOMPtr barP( do_QueryInterface(new IBar) ); + + printf("### Test 23: is |QueryInterface| called when assigning in a smart-pointer of a different type?\n"); + + nsCOMPtr fooP( do_QueryInterface(barP) ); + if ( fooP ) + printf("an IBar* is an IFoo*\n"); + } + printf("### End Test 23\n"); + + + { + nsCOMPtr fooP; + + AnIFooPtrPtrContext( getter_AddRefs(fooP) ); + AVoidPtrPtrContext( getter_AddRefs(fooP) ); + AnISupportsPtrPtrContext( getter_AddRefs(fooP) ); + } + + + { + nsCOMPtr supportsP; + + AVoidPtrPtrContext( getter_AddRefs(supportsP) ); + AnISupportsPtrPtrContext( getter_AddRefs(supportsP) ); + } + + + printf("\n### Test 24: will a static |nsCOMPtr| |Release| before program termination?\n"); + gFoop = do_QueryInterface(new IFoo); + + printf("< (original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + + /** + * This attempts to test all the possible variations of |operator==| + * used with |nsCOMPtr|s. Currently only the tests where pointers + * are to the same class are enabled. It's not clear whether we + * should be supporting other tests, and some of them won't work + * on at least some platforms. If we add separate comparisons + * for nsCOMPtr we'll need to add more tests for + * those cases. + */ + +#include "nsCOMPtr.h" + + // Don't test these now, since some of them won't work and it's + // not clear whether they should (see above). +#undef NSCAP_EQTEST_TEST_ACROSS_TYPES + +#define NS_ICOMPTREQTESTFOO_IID \ + {0x8eb5bbef, 0xd1a3, 0x4659, \ + {0x9c, 0xf6, 0xfd, 0xf3, 0xe4, 0xd2, 0x00, 0x0e}} + +class nsICOMPtrEqTestFoo : public nsISupports { + public: + NS_DEFINE_STATIC_IID_ACCESSOR(NS_ICOMPTREQTESTFOO_IID) +}; + +#ifdef NSCAP_EQTEST_TEST_ACROSS_TYPES + +#define NS_ICOMPTREQTESTFOO2_IID \ + {0x6516387b, 0x36c5, 0x4036, \ + {0x82, 0xc9, 0xa7, 0x4d, 0xd9, 0xe5, 0x92, 0x2f}} + +class nsICOMPtrEqTestFoo2 : public nsISupports { + public: + NS_DEFINE_STATIC_IID_ACCESSOR(NS_ICOMPTREQTESTFOO2_IID) +}; + +#endif + +int +main() + { + nsCOMPtr s; + nsICOMPtrEqTestFoo* r = 0; + const nsCOMPtr sc; + const nsICOMPtrEqTestFoo* rc = 0; + nsICOMPtrEqTestFoo* const rk = 0; + const nsICOMPtrEqTestFoo* const rkc = 0; + nsDerivedSafe* d = s.get(); + +#ifdef NSCAP_EQTEST_TEST_ACROSS_TYPES + nsCOMPtr s2; + nsICOMPtrEqTestFoo2* r2 = 0; + const nsCOMPtr sc2; + const nsICOMPtrEqTestFoo2* rc2 = 0; + nsICOMPtrEqTestFoo2* const rk2 = 0; + const nsICOMPtrEqTestFoo2* const rkc2 = 0; + nsDerivedSafe* d2 = s2.get(); +#endif + + return (!(PR_TRUE && + (s == s) && + (s == r) && + (s == sc) && + (s == rc) && + (s == rk) && + (s == rkc) && + (s == d) && + (r == s) && + (r == r) && + (r == sc) && + (r == rc) && + (r == rk) && + (r == rkc) && + (r == d) && + (sc == s) && + (sc == r) && + (sc == sc) && + (sc == rc) && + (sc == rk) && + (sc == rkc) && + (sc == d) && + (rc == s) && + (rc == r) && + (rc == sc) && + (rc == rc) && + (rc == rk) && + (rc == rkc) && + (rc == d) && + (rk == s) && + (rk == r) && + (rk == sc) && + (rk == rc) && + (rk == rk) && + (rk == rkc) && + (rk == d) && + (rkc == s) && + (rkc == r) && + (rkc == sc) && + (rkc == rc) && + (rkc == rk) && + (rkc == rkc) && + (rkc == d) && + (d == s) && + (d == r) && + (d == sc) && + (d == rc) && + (d == rk) && + (d == rkc) && + (d == d) && +#ifdef NSCAP_EQTEST_TEST_ACROSS_TYPES + (s == s2) && + (s == r2) && + (s == sc2) && + (s == rc2) && + (s == rk2) && + (s == rkc2) && + (s == d2) && + (r == s2) && + (r == r2) && + (r == sc2) && + (r == rc2) && + (r == rk2) && + (r == rkc2) && + (r == d2) && + (sc == s2) && + (sc == r2) && + (sc == sc2) && + (sc == rc2) && + (sc == rk2) && + (sc == rkc2) && + (sc == d2) && + (rc == s2) && + (rc == r2) && + (rc == sc2) && + (rc == rc2) && + (rc == rk2) && + (rc == rkc2) && + (rc == d2) && + (rk == s2) && + (rk == r2) && + (rk == sc2) && + (rk == rc2) && + (rk == rk2) && + (rk == rkc2) && + (rk == d2) && + (rkc == s2) && + (rkc == r2) && + (rkc == sc2) && + (rkc == rc2) && + (rkc == rk2) && + (rkc == rkc2) && + (rkc == d2) && + (d == s2) && + (d == r2) && + (d == sc2) && + (d == rc2) && + (d == rk2) && + (d == rkc2) && + (d == d2) && +#endif + PR_TRUE)); + } diff --git a/src/libs/xpcom18a4/xpcom/tests/TestCRT.cpp b/src/libs/xpcom18a4/xpcom/tests/TestCRT.cpp new file mode 100644 index 00000000..11bdd512 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/TestCRT.cpp @@ -0,0 +1,112 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsCRT.h" +#include "nsString.h" +#include "plstr.h" +#include + +// The return from strcmp etc is only defined to be postive, zero or +// negative. The magnitude of a non-zero return is irrelevant. +PRIntn sign(PRIntn val) { + if (val == 0) + return 0; + else { + if (val > 0) + return 1; + else + return -1; + } +} + + +// Verify that nsCRT versions of string comparison routines get the +// same answers as the native non-unicode versions. We only pass in +// iso-latin-1 strings, so the comparison must be valid. +static void Check(const char* s1, const char* s2, PRIntn n) +{ + PRIntn clib = PL_strcmp(s1, s2); + PRIntn clib_n = PL_strncmp(s1, s2, n); + PRIntn clib_case = PL_strcasecmp(s1, s2); + PRIntn clib_case_n = PL_strncasecmp(s1, s2, n); + + nsAutoString t1,t2; + t1.AssignWithConversion(s1); + t2.AssignWithConversion(s2); + const PRUnichar* us1 = t1.get(); + const PRUnichar* us2 = t2.get(); + + PRIntn u2 = nsCRT::strcmp(us1, us2); + PRIntn u2_n = nsCRT::strncmp(us1, us2, n); + + NS_ASSERTION(sign(clib) == sign(u2), "strcmp"); + NS_ASSERTION(sign(clib_n) == sign(u2_n), "strncmp"); +} + +struct Test { + const char* s1; + const char* s2; + PRIntn n; +}; + +static Test tests[] = { + { "foo", "foo", 3 }, + { "foo", "fo", 3 }, + + { "foo", "bar", 3 }, + { "foo", "ba", 3 }, + + { "foo", "zap", 3 }, + { "foo", "za", 3 }, + + { "bar", "foo", 3 }, + { "bar", "fo", 3 }, + + { "bar", "foo", 3 }, + { "bar", "fo", 3 }, +}; +#define NUM_TESTS int((sizeof(tests) / sizeof(tests[0]))) + +int main() +{ + Test* tp = tests; + for (int i = 0; i < NUM_TESTS; i++, tp++) { + Check(tp->s1, tp->s2, tp->n); + } + + return 0; +} diff --git a/src/libs/xpcom18a4/xpcom/tests/TestCallTemplates.cpp b/src/libs/xpcom18a4/xpcom/tests/TestCallTemplates.cpp new file mode 100644 index 00000000..3ec9c29a --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/TestCallTemplates.cpp @@ -0,0 +1,129 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim:cindent:ts=8:et:sw=4: + * + * ***** 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. + * Portions created by the Initial Developer are Copyright (C) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * L. David Baron (original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* + * This test is NOT intended to be run. It's a test to make sure + * a group of functions BUILD correctly. + */ + +#include "nsISupportsUtils.h" +#include "nsIWeakReference.h" +#include "nsIComponentManager.h" +#include "nsIServiceManager.h" +#include "nsWeakReference.h" +#include "nsIInterfaceRequestor.h" +#include "nsIInterfaceRequestorUtils.h" + +#define NS_ITESTSERVICE_IID \ + {0x127b5253, 0x37b1, 0x43c7, \ + { 0x96, 0x2b, 0xab, 0xf1, 0x2d, 0x22, 0x56, 0xae }} + +class NS_NO_VTABLE nsITestService : public nsISupports { + public: + NS_DEFINE_STATIC_IID_ACCESSOR(NS_ITESTSERVICE_IID) +}; + +class nsTestService : public nsITestService, public nsSupportsWeakReference +{ + public: + NS_DECL_ISUPPORTS +}; + +NS_IMPL_ISUPPORTS2(nsTestService, nsITestService, nsISupportsWeakReference) + +#define NS_TEST_SERVICE_CONTRACTID "@mozilla.org/test/testservice;1" +#define NS_TEST_SERVICE_CID \ + {0xa00c1406, 0x283a, 0x45c9, \ + {0xae, 0xd2, 0x1a, 0xb6, 0xdd, 0xba, 0xfe, 0x53}} +static NS_DEFINE_CID(kTestServiceCID, NS_TEST_SERVICE_CID); + +int main() +{ + /* + * NOTE: This does NOT demonstrate how these functions are + * intended to be used. They are intended for filling in out + * parameters that need to be |AddRef|ed. I'm just too lazy + * to write lots of little getter functions for a test program + * when I don't need to. + */ + + NS_NOTREACHED("This test is not intended to run, only to compile!"); + + /* Test CallQueryInterface */ + + nsISupports *mySupportsPtr = NS_REINTERPRET_CAST(nsISupports*, 0x1000); + + nsITestService *myITestService = nsnull; + CallQueryInterface(mySupportsPtr, &myITestService); + + nsTestService *myTestService = + NS_REINTERPRET_CAST(nsTestService*, mySupportsPtr); + nsISupportsWeakReference *mySupportsWeakRef; + CallQueryInterface(myTestService, &mySupportsWeakRef); + + /* Test CallQueryReferent */ + + nsIWeakReference *myWeakRef = + NS_STATIC_CAST(nsIWeakReference*, mySupportsPtr); + CallQueryReferent(myWeakRef, &myITestService); + + /* Test CallCreateInstance */ + + CallCreateInstance(kTestServiceCID, mySupportsPtr, &myITestService); + CallCreateInstance(kTestServiceCID, &myITestService); + CallCreateInstance(NS_TEST_SERVICE_CONTRACTID, mySupportsPtr, + &myITestService); + CallCreateInstance(NS_TEST_SERVICE_CONTRACTID, &myITestService); + + /* Test CallGetService */ + nsIShutdownListener *myShutdownListener = nsnull; + CallGetService(kTestServiceCID, &myITestService); + CallGetService(kTestServiceCID, myShutdownListener, &myITestService); + CallGetService(NS_TEST_SERVICE_CONTRACTID, &myITestService); + CallGetService(NS_TEST_SERVICE_CONTRACTID, myShutdownListener, + &myITestService); + + /* Test CallGetInterface */ + nsIInterfaceRequestor *myInterfaceRequestor = + NS_STATIC_CAST(nsIInterfaceRequestor*, mySupportsPtr); + CallGetInterface(myInterfaceRequestor, &myITestService); + + return 0; +} diff --git a/src/libs/xpcom18a4/xpcom/tests/TestDeque.cpp b/src/libs/xpcom18a4/xpcom/tests/TestDeque.cpp new file mode 100644 index 00000000..4b00c7fb --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/TestDeque.cpp @@ -0,0 +1,155 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsDeque.h" +#include "nsCRT.h" +#include + +/************************************************************** + Now define the token deallocator class... + **************************************************************/ +class _TestDeque { +public: + _TestDeque() { + SelfTest(); + } + int SelfTest(); + nsresult OriginalTest(); + nsresult OriginalFlaw(); + nsresult AssignFlaw(); +}; +static _TestDeque sTestDeque; + +class _Dealloc: public nsDequeFunctor { + virtual void* operator()(void* aObject) { + return 0; + } +}; + +/** + * conduct automated self test for this class + * + * @param + * @return + */ +int _TestDeque::SelfTest() { + /* the old deque should have failed a bunch of these tests */ + int results=0; + results+=OriginalTest(); + results+=OriginalFlaw(); + results+=AssignFlaw(); + return results; +} + +nsresult _TestDeque::OriginalTest() { + int ints[200]; + int count=sizeof(ints)/sizeof(int); + int i=0; + int* temp; + nsDeque theDeque(new _Dealloc); //construct a simple one... + + for (i=0;icapacity\n"); + + /* Oh, I see ... it's a circular buffer */ + printf("but the old code wasn't behaving accordingly.\n"); + + /*right*/ + printf("we shouldn't crash or anything interesting, "); + + temp=(int*)secondDeque.Peek(); + printf("peek: %d\n",*temp); + return NS_OK; +} + +nsresult _TestDeque::AssignFlaw() { + nsDeque src(new _Dealloc),dest(new _Dealloc); + return NS_OK; +} + +int main (void) { + _TestDeque test; + return 0; +} diff --git a/src/libs/xpcom18a4/xpcom/tests/TestFactory.cpp b/src/libs/xpcom18a4/xpcom/tests/TestFactory.cpp new file mode 100644 index 00000000..f0d5f777 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/TestFactory.cpp @@ -0,0 +1,160 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Pierre Phaneuf + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 +#include "TestFactory.h" +#include "nsISupports.h" +#include "nsIComponentManager.h" +#include "nsIComponentRegistrar.h" +#include "nsIServiceManager.h" + +NS_DEFINE_CID(kTestFactoryCID, NS_TESTFACTORY_CID); +NS_DEFINE_CID(kTestLoadedFactoryCID, NS_TESTLOADEDFACTORY_CID); + + +/** + * ITestClass implementation + */ + +class TestClassImpl: public ITestClass { + NS_DECL_ISUPPORTS +public: + TestClassImpl() { + } + + void Test(); +}; + +NS_IMPL_ISUPPORTS1(TestClassImpl, ITestClass) + +void TestClassImpl::Test() { + printf("hello, world!\n"); +} + +/** + * TestFactory implementation + */ + +class TestFactory: public nsIFactory { + NS_DECL_ISUPPORTS + +public: + TestFactory() { + } + + NS_IMETHOD CreateInstance(nsISupports *aDelegate, + const nsIID &aIID, + void **aResult); + + NS_IMETHOD LockFactory(PRBool aLock) { return NS_OK; } +}; + +NS_IMPL_ISUPPORTS1(TestFactory, nsIFactory) + +nsresult TestFactory::CreateInstance(nsISupports *aDelegate, + const nsIID &aIID, + void **aResult) { + if (aDelegate != NULL) { + return NS_ERROR_NO_AGGREGATION; + } + + TestClassImpl *t = new TestClassImpl(); + + if (t == NULL) { + return NS_ERROR_OUT_OF_MEMORY; + } + + nsresult res = t->QueryInterface(aIID, aResult); + + if (NS_FAILED(res)) { + *aResult = NULL; + delete t; + } + + return res; +} + + +int main(int argc, char **argv) { + nsresult rv; + + { + nsCOMPtr servMan; + rv = NS_InitXPCOM2(getter_AddRefs(servMan), nsnull, nsnull); + if (NS_FAILED(rv)) return -1; + nsCOMPtr registrar = do_QueryInterface(servMan); + NS_ASSERTION(registrar, "Null nsIComponentRegistrar"); + if (registrar) + registrar->RegisterFactory(kTestFactoryCID, + nsnull, + nsnull, + new TestFactory()); + + ITestClass *t = NULL; + nsComponentManager::CreateInstance(kTestFactoryCID, + NULL, + NS_GET_IID(ITestClass), + (void **) &t); + + if (t != NULL) { + t->Test(); + t->Release(); + } else { + printf("CreateInstance failed\n"); + } + + t = NULL; + + nsComponentManager::CreateInstance(kTestLoadedFactoryCID, + NULL, + NS_GET_IID(ITestClass), + (void **) &t); + + if (t != NULL) { + t->Test(); + t->Release(); + } else { + printf("Dynamic CreateInstance failed\n"); + } + } // 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 0; +} + diff --git a/src/libs/xpcom18a4/xpcom/tests/TestFactory.h b/src/libs/xpcom18a4/xpcom/tests/TestFactory.h new file mode 100644 index 00000000..d81cefc7 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/TestFactory.h @@ -0,0 +1,69 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Suresh Duddi + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +#ifndef __TestFactory_h +#define __TestFactory_h + +#include "nsIFactory.h" + +// {8B330F20-A24A-11d1-A961-00805F8A7AC4} +#define NS_TESTFACTORY_CID \ +{ 0x8b330f20, 0xa24a, 0x11d1, \ + { 0xa9, 0x61, 0x0, 0x80, 0x5f, 0x8a, 0x7a, 0xc4 } } + +// {8B330F21-A24A-11d1-A961-00805F8A7AC4} +#define NS_ITESTCLASS_IID \ +{ 0x8b330f21, 0xa24a, 0x11d1, \ + { 0xa9, 0x61, 0x0, 0x80, 0x5f, 0x8a, 0x7a, 0xc4 } } + +// {8B330F22-A24A-11d1-A961-00805F8A7AC4} +#define NS_TESTLOADEDFACTORY_CID \ +{ 0x8b330f22, 0xa24a, 0x11d1, \ + { 0xa9, 0x61, 0x0, 0x80, 0x5f, 0x8a, 0x7a, 0xc4 } } + +#define NS_TESTLOADEDFACTORY_CONTRACTID "@mozilla.org/xpcom/dynamic-test;1" + +class ITestClass: public nsISupports { +public: + NS_DEFINE_STATIC_IID_ACCESSOR(NS_ITESTCLASS_IID) + virtual void Test() = 0; +}; + +extern "C" void RegisterTestFactories(); + +#endif diff --git a/src/libs/xpcom18a4/xpcom/tests/TestHashtables.cpp b/src/libs/xpcom18a4/xpcom/tests/TestHashtables.cpp new file mode 100644 index 00000000..1b2d3671 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/TestHashtables.cpp @@ -0,0 +1,939 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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 C++ hashtable templates. + * + * The Initial Developer of the Original Code is + * Benjamin Smedberg. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * 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 "nsTHashtable.h" +#include "nsBaseHashtable.h" +#include "nsDataHashtable.h" +#include "nsInterfaceHashtable.h" +#include "nsClassHashtable.h" + +#include "nsCOMPtr.h" +#include "nsISupports.h" +#include "nsCRT.h" +#include "nsCOMArray.h" + +class TestUniChar // for nsClassHashtable +{ +public: + TestUniChar(PRUint32 aWord) + { + printf(" TestUniChar::TestUniChar() %u\n", aWord); + mWord = aWord; + } + + ~TestUniChar() + { + printf(" TestUniChar::~TestUniChar() %u\n", mWord); + } + + PRUint32 GetChar() const { return mWord; } + +private: + PRUint32 mWord; +}; + +struct EntityNode { + const char* mStr; // never owns buffer + PRUint32 mUnicode; +}; + +EntityNode gEntities[] = { + {"nbsp",160}, + {"iexcl",161}, + {"cent",162}, + {"pound",163}, + {"curren",164}, + {"yen",165}, + {"brvbar",166}, + {"sect",167}, + {"uml",168}, + {"copy",169}, + {"ordf",170}, + {"laquo",171}, + {"not",172}, + {"shy",173}, + {"reg",174}, + {"macr",175} +}; + +#define ENTITY_COUNT (sizeof(gEntities)/sizeof(EntityNode)) + +class EntityToUnicodeEntry : public PLDHashEntryHdr +{ +public: + typedef const char* KeyType; + typedef const char* KeyTypePointer; + + EntityToUnicodeEntry(const char* aKey) { mNode = nsnull; } + EntityToUnicodeEntry(const EntityToUnicodeEntry& aEntry) { mNode = aEntry.mNode; } + ~EntityToUnicodeEntry() { }; + + const char* GetKeyPointer() const { return mNode->mStr; } + PRBool KeyEquals(const char* aEntity) const { return !strcmp(mNode->mStr, aEntity); } + static const char* KeyToPointer(const char* aEntity) { return aEntity; } + static PLDHashNumber HashKey(const char* aEntity) { return nsCRT::HashCode(aEntity); } + enum { ALLOW_MEMMOVE = PR_TRUE }; + + const EntityNode* mNode; +}; + +PLDHashOperator +nsTEnumGo(EntityToUnicodeEntry* aEntry, void* userArg) { + printf(" enumerated \"%s\" = %u\n", + aEntry->mNode->mStr, aEntry->mNode->mUnicode); + + return PL_DHASH_NEXT; +} + +PLDHashOperator +nsTEnumStop(EntityToUnicodeEntry* aEntry, void* userArg) { + printf(" enumerated \"%s\" = %u\n", + aEntry->mNode->mStr, aEntry->mNode->mUnicode); + + return PL_DHASH_REMOVE; +} + +void +testTHashtable(nsTHashtable& hash, PRUint32 numEntries) { + printf("Filling hash with %d entries.\n", numEntries); + + PRUint32 i; + for (i = 0; i < numEntries; ++i) { + printf(" Putting entry \"%s\"...", gEntities[i].mStr); + EntityToUnicodeEntry* entry = + hash.PutEntry(gEntities[i].mStr); + + if (!entry) { + printf("FAILED\n"); + exit (2); + } + printf("OK..."); + + if (entry->mNode) { + printf("entry already exists!\n"); + exit (3); + } + printf("\n"); + + entry->mNode = &gEntities[i]; + } + + printf("Testing Get:\n"); + + for (i = 0; i < numEntries; ++i) { + printf(" Getting entry \"%s\"...", gEntities[i].mStr); + EntityToUnicodeEntry* entry = + hash.GetEntry(gEntities[i].mStr); + + if (!entry) { + printf("FAILED\n"); + exit (4); + } + + printf("Found %u\n", entry->mNode->mUnicode); + } + + printf("Testing non-existent entries..."); + + EntityToUnicodeEntry* entry = + hash.GetEntry("xxxy"); + + if (entry) { + printf("FOUND! BAD!\n"); + exit (5); + } + + printf("not found; good.\n"); + + printf("Enumerating:\n"); + PRUint32 count = hash.EnumerateEntries(nsTEnumGo, nsnull); + if (count != numEntries) { + printf(" Bad count!\n"); + exit (6); + } +} + +PLDHashOperator +nsDEnumRead(const PRUint32& aKey, const char* aData, void* userArg) { + printf(" enumerated %u = \"%s\"\n", aKey, aData); + return PL_DHASH_NEXT; +} + +PLDHashOperator +nsDEnum(const PRUint32& aKey, const char*& aData, void* userArg) { + printf(" enumerated %u = \"%s\"\n", aKey, aData); + return PL_DHASH_NEXT; +} + +PLDHashOperator +nsCEnumRead(const nsACString& aKey, TestUniChar* aData, void* userArg) { + printf(" enumerated \"%s\" = %c\n", + PromiseFlatCString(aKey).get(), aData->GetChar()); + return PL_DHASH_NEXT; +} + +PLDHashOperator +nsCEnum(const nsACString& aKey, nsAutoPtr& aData, void* userArg) { + printf(" enumerated \"%s\" = %c\n", + PromiseFlatCString(aKey).get(), aData->GetChar()); + return PL_DHASH_NEXT; +} + +// +// all this nsIFoo stuff was copied wholesale from TestCOMPTr.cpp +// + +#define NS_IFOO_IID \ +{ 0x6f7652e0, 0xee43, 0x11d1, \ + { 0x9c, 0xc3, 0x00, 0x60, 0x08, 0x8c, 0xa6, 0xb3 } } + +class IFoo : public nsISupports + { + public: + NS_DEFINE_STATIC_IID_ACCESSOR(NS_IFOO_IID) + + public: + IFoo(); + + NS_IMETHOD_(nsrefcnt) AddRef(); + NS_IMETHOD_(nsrefcnt) Release(); + NS_IMETHOD QueryInterface( const nsIID&, void** ); + + NS_IMETHOD SetString(const nsACString& /*in*/ aString); + NS_IMETHOD GetString(nsACString& /*out*/ aString); + + static void print_totals(); + + private: + ~IFoo(); + + unsigned int refcount_; + + static unsigned int total_constructions_; + static unsigned int total_destructions_; + nsCString mString; + }; + +unsigned int IFoo::total_constructions_; +unsigned int IFoo::total_destructions_; + +void +IFoo::print_totals() + { + printf("total constructions/destructions --> %d/%d\n", + total_constructions_, total_destructions_); + } + +IFoo::IFoo() + : refcount_(0) + { + ++total_constructions_; + printf(" new IFoo@%p [#%d]\n", + NS_STATIC_CAST(void*, this), total_constructions_); + } + +IFoo::~IFoo() + { + ++total_destructions_; + printf("IFoo@%p::~IFoo() [#%d]\n", + NS_STATIC_CAST(void*, this), total_destructions_); + } + +nsrefcnt +IFoo::AddRef() + { + ++refcount_; + printf("IFoo@%p::AddRef(), refcount --> %d\n", + NS_STATIC_CAST(void*, this), refcount_); + return refcount_; + } + +nsrefcnt +IFoo::Release() + { + int wrap_message = (refcount_ == 1); + if ( wrap_message ) + printf(">>"); + + nsrefcnt newrefcount = --refcount_; + printf("IFoo@%p::Release(), refcount --> %d\n", + NS_STATIC_CAST(void*, this), newrefcount); + + if ( !newrefcount ) + { + printf(" delete IFoo@%p\n", NS_STATIC_CAST(void*, this)); + delete this; + } + + if ( wrap_message ) + printf(" delete IFoo@%p\n", NS_STATIC_CAST(void*, this)); + + return newrefcount; + } + +nsresult +IFoo::QueryInterface( const nsIID& aIID, void** aResult ) + { + printf("IFoo@%p::QueryInterface()\n", NS_STATIC_CAST(void*, this)); + nsISupports* rawPtr = 0; + nsresult status = NS_OK; + + if ( aIID.Equals(GetIID()) ) + rawPtr = this; + else + { + nsID iid_of_ISupports = NS_ISUPPORTS_IID; + if ( aIID.Equals(iid_of_ISupports) ) + rawPtr = NS_STATIC_CAST(nsISupports*, this); + else + status = NS_ERROR_NO_INTERFACE; + } + + NS_IF_ADDREF(rawPtr); + *aResult = rawPtr; + + return status; + } + +nsresult +IFoo::SetString(const nsACString& aString) +{ + mString = aString; + return NS_OK; +} + +nsresult +IFoo::GetString(nsACString& aString) +{ + aString = mString; + return NS_OK; +} + +nsresult +CreateIFoo( IFoo** result ) + // a typical factory function (that calls AddRef) + { + printf(" >>CreateIFoo() --> "); + IFoo* foop = new IFoo(); + printf("IFoo@%p\n", NS_STATIC_CAST(void*, foop)); + + foop->AddRef(); + *result = foop; + + printf("<GetString(str); + + printf(" enumerated %u = \"%s\"\n", aKey, str.get()); + return PL_DHASH_NEXT; +} + +PLDHashOperator +nsIEnum(const PRUint32& aKey, nsCOMPtr& aData, void* userArg) { + nsCAutoString str; + aData->GetString(str); + + printf(" enumerated %u = \"%s\"\n", aKey, str.get()); + return PL_DHASH_NEXT; +} + +PLDHashOperator +nsIEnum2Read(nsISupports* aKey, PRUint32 aData, void* userArg) { + nsCAutoString str; + nsCOMPtr foo = do_QueryInterface(aKey); + foo->GetString(str); + + + printf(" enumerated \"%s\" = %u\n", str.get(), aData); + return PL_DHASH_NEXT; +} + +PLDHashOperator +nsIEnum2(nsISupports* aKey, PRUint32& aData, void* userArg) { + nsCAutoString str; + nsCOMPtr foo = do_QueryInterface(aKey); + foo->GetString(str); + + printf(" enumerated \"%s\" = %u\n", str.get(), aData); + return PL_DHASH_NEXT; +} + +int +main(void) { + // check an nsTHashtable + nsTHashtable EntityToUnicode; + + printf("Initializing nsTHashtable..."); + if (!EntityToUnicode.Init(ENTITY_COUNT)) { + printf("FAILED\n"); + exit (1); + } + printf("OK\n"); + + printf("Partially filling nsTHashtable:\n"); + testTHashtable(EntityToUnicode, 5); + + printf("Enumerate-removing...\n"); + PRUint32 count = EntityToUnicode.EnumerateEntries(nsTEnumStop, nsnull); + if (count != 5) { + printf("wrong count\n"); + exit (7); + } + printf("OK\n"); + + printf("Check enumeration..."); + count = EntityToUnicode.EnumerateEntries(nsTEnumGo, nsnull); + if (count) { + printf("entries remain in table!\n"); + exit (8); + } + printf("OK\n"); + + printf("Filling nsTHashtable:\n"); + testTHashtable(EntityToUnicode, ENTITY_COUNT); + + printf("Clearing..."); + EntityToUnicode.Clear(); + printf("OK\n"); + + printf("Check enumeration..."); + count = EntityToUnicode.EnumerateEntries(nsTEnumGo, nsnull); + if (count) { + printf("entries remain in table!\n"); + exit (9); + } + printf("OK\n"); + + // + // now check a data-hashtable + // + + nsDataHashtable UniToEntity; + + printf("Initializing nsDataHashtable..."); + if (!UniToEntity.Init(ENTITY_COUNT)) { + printf("FAILED\n"); + exit (10); + } + printf("OK\n"); + + printf("Filling hash with %zd entries.\n", ENTITY_COUNT); + + PRUint32 i; + for (i = 0; i < ENTITY_COUNT; ++i) { + printf(" Putting entry %u...", gEntities[i].mUnicode); + if (!UniToEntity.Put(gEntities[i].mUnicode, gEntities[i].mStr)) { + printf("FAILED\n"); + exit (11); + } + printf("OK...\n"); + } + + printf("Testing Get:\n"); + const char* str; + + for (i = 0; i < ENTITY_COUNT; ++i) { + printf(" Getting entry %u...", gEntities[i].mUnicode); + if (!UniToEntity.Get(gEntities[i].mUnicode, &str)) { + printf("FAILED\n"); + exit (12); + } + + printf("Found %s\n", str); + } + + printf("Testing non-existent entries..."); + if (UniToEntity.Get(99446, &str)) { + printf("FOUND! BAD!\n"); + exit (13); + } + + printf("not found; good.\n"); + + printf("Enumerating:\n"); + + count = UniToEntity.EnumerateRead(nsDEnumRead, nsnull); + if (count != ENTITY_COUNT) { + printf(" Bad count!\n"); + exit (14); + } + + printf("Clearing..."); + UniToEntity.Clear(); + printf("OK\n"); + + printf("Checking count..."); + count = UniToEntity.Enumerate(nsDEnum, nsnull); + if (count) { + printf(" Clear did not remove all entries.\n"); + exit (15); + } + + printf("OK\n"); + + // + // now check a thread-safe data-hashtable + // + + nsDataHashtableMT UniToEntityL; + + printf("Initializing nsDataHashtableMT..."); + if (!UniToEntityL.Init(ENTITY_COUNT)) { + printf("FAILED\n"); + exit (10); + } + printf("OK\n"); + + printf("Filling hash with %zd entries.\n", ENTITY_COUNT); + + for (i = 0; i < ENTITY_COUNT; ++i) { + printf(" Putting entry %u...", gEntities[i].mUnicode); + if (!UniToEntityL.Put(gEntities[i].mUnicode, gEntities[i].mStr)) { + printf("FAILED\n"); + exit (11); + } + printf("OK...\n"); + } + + printf("Testing Get:\n"); + + for (i = 0; i < ENTITY_COUNT; ++i) { + printf(" Getting entry %u...", gEntities[i].mUnicode); + if (!UniToEntityL.Get(gEntities[i].mUnicode, &str)) { + printf("FAILED\n"); + exit (12); + } + + printf("Found %s\n", str); + } + + printf("Testing non-existent entries..."); + if (UniToEntityL.Get(99446, &str)) { + printf("FOUND! BAD!\n"); + exit (13); + } + + printf("not found; good.\n"); + + printf("Enumerating:\n"); + + count = UniToEntityL.EnumerateRead(nsDEnumRead, nsnull); + if (count != ENTITY_COUNT) { + printf(" Bad count!\n"); + exit (14); + } + + printf("Clearing..."); + UniToEntityL.Clear(); + printf("OK\n"); + + printf("Checking count..."); + count = UniToEntityL.Enumerate(nsDEnum, nsnull); + if (count) { + printf(" Clear did not remove all entries.\n"); + exit (15); + } + + printf("OK\n"); + + // + // now check a class-hashtable + // + + nsClassHashtable EntToUniClass; + + printf("Initializing nsClassHashtable..."); + if (!EntToUniClass.Init(ENTITY_COUNT)) { + printf("FAILED\n"); + exit (16); + } + printf("OK\n"); + + printf("Filling hash with %zd entries.\n", ENTITY_COUNT); + + for (i = 0; i < ENTITY_COUNT; ++i) { + printf(" Putting entry %u...", gEntities[i].mUnicode); + TestUniChar* temp = new TestUniChar(gEntities[i].mUnicode); + + if (!EntToUniClass.Put(nsDependentCString(gEntities[i].mStr), temp)) { + printf("FAILED\n"); + delete temp; + exit (17); + } + printf("OK...\n"); + } + + printf("Testing Get:\n"); + TestUniChar* myChar; + + for (i = 0; i < ENTITY_COUNT; ++i) { + printf(" Getting entry %s...", gEntities[i].mStr); + if (!EntToUniClass.Get(nsDependentCString(gEntities[i].mStr), &myChar)) { + printf("FAILED\n"); + exit (18); + } + + printf("Found %c\n", myChar->GetChar()); + } + + printf("Testing non-existent entries..."); + if (EntToUniClass.Get(NS_LITERAL_CSTRING("xxxx"), &myChar)) { + printf("FOUND! BAD!\n"); + exit (19); + } + + printf("not found; good.\n"); + + printf("Enumerating:\n"); + + count = EntToUniClass.EnumerateRead(nsCEnumRead, nsnull); + if (count != ENTITY_COUNT) { + printf(" Bad count!\n"); + exit (20); + } + + printf("Clearing...\n"); + EntToUniClass.Clear(); + printf(" Clearing OK\n"); + + printf("Checking count..."); + count = EntToUniClass.Enumerate(nsCEnum, nsnull); + if (count) { + printf(" Clear did not remove all entries.\n"); + exit (21); + } + + printf("OK\n"); + + // + // now check a thread-safe class-hashtable + // + + nsClassHashtableMT EntToUniClassL; + + printf("Initializing nsClassHashtableMT..."); + if (!EntToUniClassL.Init(ENTITY_COUNT)) { + printf("FAILED\n"); + exit (16); + } + printf("OK\n"); + + printf("Filling hash with %zd entries.\n", ENTITY_COUNT); + + for (i = 0; i < ENTITY_COUNT; ++i) { + printf(" Putting entry %u...", gEntities[i].mUnicode); + TestUniChar* temp = new TestUniChar(gEntities[i].mUnicode); + + if (!EntToUniClassL.Put(nsDependentCString(gEntities[i].mStr), temp)) { + printf("FAILED\n"); + delete temp; + exit (17); + } + printf("OK...\n"); + } + + printf("Testing Get:\n"); + + for (i = 0; i < ENTITY_COUNT; ++i) { + printf(" Getting entry %s...", gEntities[i].mStr); + if (!EntToUniClassL.Get(nsDependentCString(gEntities[i].mStr), &myChar)) { + printf("FAILED\n"); + exit (18); + } + + printf("Found %c\n", myChar->GetChar()); + } + + printf("Testing non-existent entries..."); + if (EntToUniClassL.Get(NS_LITERAL_CSTRING("xxxx"), &myChar)) { + printf("FOUND! BAD!\n"); + exit (19); + } + + printf("not found; good.\n"); + + printf("Enumerating:\n"); + + count = EntToUniClassL.EnumerateRead(nsCEnumRead, nsnull); + if (count != ENTITY_COUNT) { + printf(" Bad count!\n"); + exit (20); + } + + printf("Clearing...\n"); + EntToUniClassL.Clear(); + printf(" Clearing OK\n"); + + printf("Checking count..."); + count = EntToUniClassL.Enumerate(nsCEnum, nsnull); + if (count) { + printf(" Clear did not remove all entries.\n"); + exit (21); + } + + printf("OK\n"); + + // + // now check a data-hashtable with an interface key + // + + nsDataHashtable EntToUniClass2; + + printf("Initializing nsDataHashtable with interface key..."); + if (!EntToUniClass2.Init(ENTITY_COUNT)) { + printf("FAILED\n"); + exit (22); + } + printf("OK\n"); + + printf("Filling hash with %zd entries.\n", ENTITY_COUNT); + + nsCOMArray fooArray; + + for (i = 0; i < ENTITY_COUNT; ++i) { + printf(" Putting entry %u...", gEntities[i].mUnicode); + nsCOMPtr foo; + CreateIFoo(getter_AddRefs(foo)); + foo->SetString(nsDependentCString(gEntities[i].mStr)); + + + fooArray.InsertObjectAt(foo, i); + + if (!EntToUniClass2.Put(foo, gEntities[i].mUnicode)) { + printf("FAILED\n"); + exit (23); + } + printf("OK...\n"); + } + + printf("Testing Get:\n"); + PRUint32 myChar2; + + for (i = 0; i < ENTITY_COUNT; ++i) { + printf(" Getting entry %s...", gEntities[i].mStr); + + if (!EntToUniClass2.Get(fooArray[i], &myChar2)) { + printf("FAILED\n"); + exit (24); + } + + printf("Found %c\n", myChar2); + } + + printf("Testing non-existent entries..."); + if (EntToUniClass2.Get((nsISupports*) 0x55443316, &myChar2)) { + printf("FOUND! BAD!\n"); + exit (25); + } + + printf("not found; good.\n"); + + printf("Enumerating:\n"); + + count = EntToUniClass2.EnumerateRead(nsIEnum2Read, nsnull); + if (count != ENTITY_COUNT) { + printf(" Bad count!\n"); + exit (26); + } + + printf("Clearing...\n"); + EntToUniClass2.Clear(); + printf(" Clearing OK\n"); + + printf("Checking count..."); + count = EntToUniClass2.Enumerate(nsIEnum2, nsnull); + if (count) { + printf(" Clear did not remove all entries.\n"); + exit (27); + } + + printf("OK\n"); + + // + // now check an interface-hashtable with an PRUint32 key + // + + nsInterfaceHashtable UniToEntClass2; + + printf("Initializing nsInterfaceHashtable..."); + if (!UniToEntClass2.Init(ENTITY_COUNT)) { + printf("FAILED\n"); + exit (28); + } + printf("OK\n"); + + printf("Filling hash with %zd entries.\n", ENTITY_COUNT); + + for (i = 0; i < ENTITY_COUNT; ++i) { + printf(" Putting entry %u...", gEntities[i].mUnicode); + nsCOMPtr foo; + CreateIFoo(getter_AddRefs(foo)); + foo->SetString(nsDependentCString(gEntities[i].mStr)); + + if (!UniToEntClass2.Put(gEntities[i].mUnicode, foo)) { + printf("FAILED\n"); + exit (29); + } + printf("OK...\n"); + } + + printf("Testing Get:\n"); + + for (i = 0; i < ENTITY_COUNT; ++i) { + printf(" Getting entry %s...", gEntities[i].mStr); + + nsCOMPtr myEnt; + if (!UniToEntClass2.Get(gEntities[i].mUnicode, getter_AddRefs(myEnt))) { + printf("FAILED\n"); + exit (30); + } + + nsCAutoString str; + myEnt->GetString(str); + printf("Found %s\n", str.get()); + } + + printf("Testing non-existent entries..."); + nsCOMPtr myEnt; + if (UniToEntClass2.Get(9462, getter_AddRefs(myEnt))) { + printf("FOUND! BAD!\n"); + exit (31); + } + + printf("not found; good.\n"); + + printf("Enumerating:\n"); + + count = UniToEntClass2.EnumerateRead(nsIEnumRead, nsnull); + if (count != ENTITY_COUNT) { + printf(" Bad count!\n"); + exit (32); + } + + printf("Clearing...\n"); + UniToEntClass2.Clear(); + printf(" Clearing OK\n"); + + printf("Checking count..."); + count = UniToEntClass2.Enumerate(nsIEnum, nsnull); + if (count) { + printf(" Clear did not remove all entries.\n"); + exit (33); + } + + printf("OK\n"); + + // + // now check a thread-safe interface hashtable + // + + nsInterfaceHashtableMT UniToEntClass2L; + + printf("Initializing nsInterfaceHashtableMT..."); + if (!UniToEntClass2L.Init(ENTITY_COUNT)) { + printf("FAILED\n"); + exit (28); + } + printf("OK\n"); + + printf("Filling hash with %zd entries.\n", ENTITY_COUNT); + + for (i = 0; i < ENTITY_COUNT; ++i) { + printf(" Putting entry %u...", gEntities[i].mUnicode); + nsCOMPtr foo; + CreateIFoo(getter_AddRefs(foo)); + foo->SetString(nsDependentCString(gEntities[i].mStr)); + + if (!UniToEntClass2L.Put(gEntities[i].mUnicode, foo)) { + printf("FAILED\n"); + exit (29); + } + printf("OK...\n"); + } + + printf("Testing Get:\n"); + + for (i = 0; i < ENTITY_COUNT; ++i) { + printf(" Getting entry %s...", gEntities[i].mStr); + + nsCOMPtr myEnt; + if (!UniToEntClass2L.Get(gEntities[i].mUnicode, getter_AddRefs(myEnt))) { + printf("FAILED\n"); + exit (30); + } + + nsCAutoString str; + myEnt->GetString(str); + printf("Found %s\n", str.get()); + } + + printf("Testing non-existent entries..."); + if (UniToEntClass2L.Get(9462, getter_AddRefs(myEnt))) { + printf("FOUND! BAD!\n"); + exit (31); + } + + printf("not found; good.\n"); + + printf("Enumerating:\n"); + + count = UniToEntClass2L.EnumerateRead(nsIEnumRead, nsnull); + if (count != ENTITY_COUNT) { + printf(" Bad count!\n"); + exit (32); + } + + printf("Clearing...\n"); + UniToEntClass2L.Clear(); + printf(" Clearing OK\n"); + + printf("Checking count..."); + count = UniToEntClass2L.Enumerate(nsIEnum, nsnull); + if (count) { + printf(" Clear did not remove all entries.\n"); + exit (33); + } + + printf("OK\n"); + + return 0; +} diff --git a/src/libs/xpcom18a4/xpcom/tests/TestID.cpp b/src/libs/xpcom18a4/xpcom/tests/TestID.cpp new file mode 100644 index 00000000..f91fda9f --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/TestID.cpp @@ -0,0 +1,77 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 +#include "plstr.h" +#include "nsID.h" +#include "prmem.h" + +static const char* const ids[] = { + "5C347B10-D55C-11D1-89B7-006008911B81", + "{5C347B10-D55C-11D1-89B7-006008911B81}", + "5c347b10-d55c-11d1-89b7-006008911b81", + "{5c347b10-d55c-11d1-89b7-006008911b81}", + + "FC347B10-D55C-F1D1-F9B7-006008911B81", + "{FC347B10-D55C-F1D1-F9B7-006008911B81}", + "fc347b10-d55c-f1d1-f9b7-006008911b81", + "{fc347b10-d55c-f1d1-f9b7-006008911b81}", +}; +#define NUM_IDS ((int) (sizeof(ids) / sizeof(ids[0]))) + +int main(int argc, char** argv) +{ + nsID id; + for (int i = 0; i < NUM_IDS; i++) { + const char* idstr = ids[i]; + if (!id.Parse(idstr)) { + fprintf(stderr, "TestID: Parse failed on test #%d\n", i); + return -1; + } + char* cp = id.ToString(); + if (NULL == cp) { + fprintf(stderr, "TestID: ToString failed on test #%d\n", i); + return -1; + } + if (0 != PL_strcmp(cp, ids[4*(i/4) + 3])) { + fprintf(stderr, "TestID: compare of ToString failed on test #%d\n", i); + return -1; + } + PR_Free(cp); + } + + return 0; +} diff --git a/src/libs/xpcom18a4/xpcom/tests/TestMinStringAPI.cpp b/src/libs/xpcom18a4/xpcom/tests/TestMinStringAPI.cpp new file mode 100644 index 00000000..811df138 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/TestMinStringAPI.cpp @@ -0,0 +1,333 @@ +/* vim:set ts=2 sw=2 et cindent: */ +/* ***** 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 IBM Corporation. + * Portions created by IBM Corporation are Copyright (C) 2003 + * IBM Corporation. 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 +#include "nsStringAPI.h" +#include "nsCRT.h" + +static const char kAsciiData[] = "hello world"; + +static const PRUnichar kUnicodeData[] = + {'h','e','l','l','o',' ','w','o','r','l','d','\0'}; + +static PRBool test_basic_1() + { + nsCStringContainer s; + NS_CStringContainerInit(s); + + const char *ptr; + PRUint32 len; + char *clone; + + NS_CStringGetData(s, &ptr); + if (ptr == nsnull || *ptr != '\0') + { + NS_ERROR("unexpected result"); + return PR_FALSE; + } + + NS_CStringSetData(s, kAsciiData, PR_UINT32_MAX); + len = NS_CStringGetData(s, &ptr); + if (ptr == nsnull || strcmp(ptr, kAsciiData) != 0) + { + NS_ERROR("unexpected result"); + return PR_FALSE; + } + if (len != sizeof(kAsciiData)-1) + { + NS_ERROR("unexpected result"); + return PR_FALSE; + } + + clone = NS_CStringCloneData(s); + if (ptr == nsnull || strcmp(ptr, kAsciiData) != 0) + { + NS_ERROR("unexpected result"); + return PR_FALSE; + } + nsMemory::Free(clone); + + nsCStringContainer temp; + NS_CStringContainerInit(temp); + NS_CStringCopy(temp, s); + + len = NS_CStringGetData(temp, &ptr); + if (ptr == nsnull || strcmp(ptr, kAsciiData) != 0) + { + NS_ERROR("unexpected result"); + return PR_FALSE; + } + if (len != sizeof(kAsciiData)-1) + { + NS_ERROR("unexpected result"); + return PR_FALSE; + } + + NS_CStringContainerFinish(temp); + + NS_CStringContainerFinish(s); + return PR_TRUE; + } + +static PRBool test_basic_2() + { + nsStringContainer s; + NS_StringContainerInit(s); + + const PRUnichar *ptr; + PRUint32 len; + PRUnichar *clone; + + NS_StringGetData(s, &ptr); + if (ptr == nsnull || *ptr != '\0') + { + NS_ERROR("unexpected result"); + return PR_FALSE; + } + + NS_StringSetData(s, kUnicodeData, PR_UINT32_MAX); + len = NS_StringGetData(s, &ptr); + if (ptr == nsnull || nsCRT::strcmp(ptr, kUnicodeData) != 0) + { + NS_ERROR("unexpected result"); + return PR_FALSE; + } + if (len != sizeof(kUnicodeData)/2 - 1) + { + NS_ERROR("unexpected result"); + return PR_FALSE; + } + + clone = NS_StringCloneData(s); + if (ptr == nsnull || nsCRT::strcmp(ptr, kUnicodeData) != 0) + { + NS_ERROR("unexpected result"); + return PR_FALSE; + } + nsMemory::Free(clone); + + nsStringContainer temp; + NS_StringContainerInit(temp); + NS_StringCopy(temp, s); + + len = NS_StringGetData(temp, &ptr); + if (ptr == nsnull || nsCRT::strcmp(ptr, kUnicodeData) != 0) + { + NS_ERROR("unexpected result"); + return PR_FALSE; + } + if (len != sizeof(kUnicodeData)/2 - 1) + { + NS_ERROR("unexpected result"); + return PR_FALSE; + } + + NS_StringContainerFinish(temp); + + NS_StringContainerFinish(s); + + return PR_TRUE; + } + +static PRBool test_convert() + { + nsStringContainer s; + NS_StringContainerInit(s); + NS_StringSetData(s, kUnicodeData, sizeof(kUnicodeData)/2 - 1); + + nsCStringContainer temp; + NS_CStringContainerInit(temp); + + const char *data; + + NS_UTF16ToCString(s, NS_CSTRING_ENCODING_ASCII, temp); + NS_CStringGetData(temp, &data); + if (strcmp(data, kAsciiData) != 0) + return PR_FALSE; + + NS_UTF16ToCString(s, NS_CSTRING_ENCODING_UTF8, temp); + NS_CStringGetData(temp, &data); + if (strcmp(data, kAsciiData) != 0) + return PR_FALSE; + + NS_CStringContainerFinish(temp); + + NS_StringContainerFinish(s); + return PR_TRUE; + } + +static PRBool test_append() + { + nsCStringContainer s; + NS_CStringContainerInit(s); + + NS_CStringSetData(s, "foo"); + NS_CStringAppendData(s, "bar"); + + NS_CStringContainerFinish(s); + return PR_TRUE; + } + +// Replace all occurances of |matchVal| with |newVal| +static void ReplaceSubstring( nsACString& str, + const nsACString& matchVal, + const nsACString& newVal ) + { + const char* sp, *mp, *np; + PRUint32 sl, ml, nl; + + sl = NS_CStringGetData(str, &sp); + ml = NS_CStringGetData(matchVal, &mp); + nl = NS_CStringGetData(newVal, &np); + + for (const char* iter = sp; iter <= sp + sl - ml; ++iter) + { + if (memcmp(iter, mp, ml) == 0) + { + PRUint32 offset = iter - sp; + + NS_CStringSetDataRange(str, offset, ml, np, nl); + + sl = NS_CStringGetData(str, &sp); + + iter = sp + offset + nl - 1; + } + } + } + +static PRBool test_replace_driver(const char *strVal, + const char *matchVal, + const char *newVal, + const char *finalVal) + { + nsCStringContainer a; + NS_CStringContainerInit(a); + NS_CStringSetData(a, strVal); + + nsCStringContainer b; + NS_CStringContainerInit(b); + NS_CStringSetData(b, matchVal); + + nsCStringContainer c; + NS_CStringContainerInit(c); + NS_CStringSetData(c, newVal); + + ReplaceSubstring(a, b, c); + + const char *data; + NS_CStringGetData(a, &data); + if (strcmp(data, finalVal) != 0) + return PR_FALSE; + + NS_CStringContainerFinish(c); + NS_CStringContainerFinish(b); + NS_CStringContainerFinish(a); + return PR_TRUE; + } + +static PRBool test_replace() + { + PRBool rv; + + rv = test_replace_driver("hello world, hello again!", + "hello", + "goodbye", + "goodbye world, goodbye again!"); + if (!rv) + return rv; + + rv = test_replace_driver("foofoofoofoo!", + "foo", + "bar", + "barbarbarbar!"); + if (!rv) + return rv; + + rv = test_replace_driver("foo bar systems", + "xyz", + "crazy", + "foo bar systems"); + if (!rv) + return rv; + + rv = test_replace_driver("oh", + "xyz", + "crazy", + "oh"); + if (!rv) + return rv; + + return PR_TRUE; + } + +//---- + +typedef PRBool (*TestFunc)(); + +static const struct Test + { + const char* name; + TestFunc func; + } +tests[] = + { + { "test_basic_1", test_basic_1 }, + { "test_basic_2", test_basic_2 }, + { "test_convert", test_convert }, + { "test_append", test_append }, + { "test_replace", test_replace }, + { nsnull, nsnull } + }; + +//---- + +int main(int argc, char **argv) + { + int count = 1; + if (argc > 1) + count = atoi(argv[1]); + + while (count--) + { + for (const Test* t = tests; t->name != nsnull; ++t) + { + printf("%25s : %s\n", t->name, t->func() ? "SUCCESS" : "FAILURE"); + } + } + + return 0; + } diff --git a/src/libs/xpcom18a4/xpcom/tests/TestObserverService.cpp b/src/libs/xpcom18a4/xpcom/tests/TestObserverService.cpp new file mode 100644 index 00000000..148400e2 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/TestObserverService.cpp @@ -0,0 +1,250 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Pierre Phaneuf + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsISupports.h" +#include "nsIComponentManager.h" +#include "nsIObserverService.h" +#include "nsIObserver.h" +#include "nsIEnumerator.h" +#include "nsString.h" +#include "nsReadableUtils.h" +#include "prprf.h" +#include "nsWeakReference.h" + +static nsIObserverService *anObserverService = NULL; + +#ifdef VBOX +static bool testResult( nsresult rv ) { + if ( NS_SUCCEEDED( rv ) ) { + printf("...ok\n"); + return true; + } + printf("...failed, rv=0x%x\n", (int)rv); + return false; +} +#else +static void testResult( nsresult rv ) { + if ( NS_SUCCEEDED( rv ) ) { + printf("...ok\n"); + } else { + printf("...failed, rv=0x%x\n", (int)rv); + } + return; +} +#endif + +void printString(nsString &str) { +#ifdef VBOX /* asan complains about mixing different allocators */ + char *cstr = ToNewCString(str); + printf("%s", cstr); + nsMemory::Free(cstr); +#else + const char *cstr = ToNewCString(str); + printf("%s", cstr); + delete [] (char*)cstr; +#endif +} + +class TestObserver : public nsIObserver, public nsSupportsWeakReference { +public: + TestObserver( const nsAString &name ) + : mName( name ) { + } + NS_DECL_ISUPPORTS + NS_DECL_NSIOBSERVER + + nsString mName; + +private: + ~TestObserver() {} +}; + +NS_IMPL_ISUPPORTS2( TestObserver, nsIObserver, nsISupportsWeakReference ) + +NS_IMETHODIMP +TestObserver::Observe( nsISupports *aSubject, + const char *aTopic, + const PRUnichar *someData ) { + nsCString topic( aTopic ); + nsString data( someData ); + /* + The annoying double-cast below is to work around an annoying bug in + the compiler currently used on wensleydale. This is a test. + */ + printString(mName); + printf(" has observed something: subject@%p", (void*)aSubject); + printf(" name="); + printString(NS_REINTERPRET_CAST(TestObserver*, NS_REINTERPRET_CAST(void*, aSubject))->mName); + printf(" aTopic=%s", topic.get()); + printf(" someData="); + printString(data); + printf("\n"); + return NS_OK; +} + +int main(int argc, char *argv[]) +{ + nsCString topicA; topicA.Assign( "topic-A" ); + nsCString topicB; topicB.Assign( "topic-B" ); + nsresult rv; + + nsresult res = nsComponentManager::CreateInstance("@mozilla.org/observer-service;1", + NULL, + NS_GET_IID(nsIObserverService), + (void **) &anObserverService); +#ifdef VBOX + bool fSuccess = res == NS_OK; +#endif + + if (res == NS_OK) { + + nsIObserver *aObserver = new TestObserver(NS_LITERAL_STRING("Observer-A")); + aObserver->AddRef(); + nsIObserver *bObserver = new TestObserver(NS_LITERAL_STRING("Observer-B")); + bObserver->AddRef(); + + printf("Adding Observer-A as observer of topic-A...\n"); + rv = anObserverService->AddObserver(aObserver, topicA.get(), PR_FALSE); +#ifdef VBOX + fSuccess = fSuccess && +#endif + testResult(rv); + + printf("Adding Observer-B as observer of topic-A...\n"); + rv = anObserverService->AddObserver(bObserver, topicA.get(), PR_FALSE); +#ifdef VBOX + fSuccess = fSuccess && +#endif + testResult(rv); + + printf("Adding Observer-B as observer of topic-B...\n"); + rv = anObserverService->AddObserver(bObserver, topicB.get(), PR_FALSE); +#ifdef VBOX + fSuccess = fSuccess && +#endif + testResult(rv); + + printf("Testing Notify(observer-A, topic-A)...\n"); + rv = anObserverService->NotifyObservers( aObserver, + topicA.get(), + NS_LITERAL_STRING("Testing Notify(observer-A, topic-A)").get() ); +#ifdef VBOX + fSuccess = fSuccess && +#endif + testResult(rv); + + printf("Testing Notify(observer-B, topic-B)...\n"); + rv = anObserverService->NotifyObservers( bObserver, + topicB.get(), + NS_LITERAL_STRING("Testing Notify(observer-B, topic-B)").get() ); +#ifdef VBOX + fSuccess = fSuccess && +#endif + testResult(rv); + + printf("Testing EnumerateObserverList (for topic-A)...\n"); + nsCOMPtr e; + rv = anObserverService->EnumerateObservers(topicA.get(), getter_AddRefs(e)); + +#ifdef VBOX + fSuccess = fSuccess && +#endif + testResult(rv); + + printf("Enumerating observers of topic-A...\n"); + if ( e ) { + nsCOMPtr observer; + PRBool loop = PR_TRUE; + while( NS_SUCCEEDED(e->HasMoreElements(&loop)) && loop) + { + e->GetNext(getter_AddRefs(observer)); + printf("Calling observe on enumerated observer "); + printString(NS_REINTERPRET_CAST(TestObserver*, + NS_REINTERPRET_CAST(void*, observer.get()))->mName); + printf("...\n"); + rv = observer->Observe( observer, + topicA.get(), + NS_LITERAL_STRING("during enumeration").get() ); +#ifdef VBOX + fSuccess = fSuccess && +#endif + testResult(rv); + } + } + printf("...done enumerating observers of topic-A\n"); + + printf("Removing Observer-A...\n"); + rv = anObserverService->RemoveObserver(aObserver, topicA.get()); +#ifdef VBOX + fSuccess = fSuccess && +#endif + testResult(rv); + + + printf("Removing Observer-B (topic-A)...\n"); + rv = anObserverService->RemoveObserver(bObserver, topicB.get()); +#ifdef VBOX + fSuccess = fSuccess && +#endif + testResult(rv); + printf("Removing Observer-B (topic-B)...\n"); + rv = anObserverService->RemoveObserver(bObserver, topicA.get()); +#ifdef VBOX + fSuccess = fSuccess && +#endif + testResult(rv); + +#ifdef VBOX + /* Cleanup: */ + nsrefcnt refs = bObserver->Release(); + fSuccess = fSuccess && refs == 0; + if (refs != 0) + printf("bObserver->Release() -> %d, expected 0\n", (int)refs); + + refs = aObserver->Release(); + fSuccess = fSuccess && refs == 0; + if (refs != 0) + printf("aObserver->Release() -> %d, expected 0\n", (int)refs); +#endif + } +#ifdef VBOX + return fSuccess ? 0 : 1; +#else + return NS_OK; +#endif +} diff --git a/src/libs/xpcom18a4/xpcom/tests/TestPermanentAtoms.cpp b/src/libs/xpcom18a4/xpcom/tests/TestPermanentAtoms.cpp new file mode 100644 index 00000000..09b0b2e9 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/TestPermanentAtoms.cpp @@ -0,0 +1,88 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +// vim:cindent:ts=8:et:sw=4: +/* ***** 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 TestPermanentAtoms.cpp. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * L. David Baron (original author) + * + * 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 "nsIAtom.h" +#include "nsAtomTable.h" +#include "nsCOMPtr.h" +#include +#include "nsString.h" +#include "nsReadableUtils.h" + +static void Assert(PRBool aCondition, const char* aStatement) +{ + printf("%s: %s\n", aCondition?"PASS":"FAIL", aStatement); +} + +static void AssertString(nsIAtom *aAtom, const nsACString& aString) +{ + const char *str; + NS_STATIC_CAST(AtomImpl*,aAtom)->GetUTF8String(&str); + Assert(nsDependentCString(str) == aString, "string is correct"); +} + +static void AssertPermanence(nsIAtom *aAtom, PRBool aPermanence) +{ + Assert(NS_STATIC_CAST(AtomImpl*,aAtom)->IsPermanent() == aPermanence, + aPermanence ? "atom is permanent" : "atom is not permanent"); +} + +int main() +{ + nsCOMPtr foo = do_GetAtom("foo"); + AssertString(foo, NS_LITERAL_CSTRING("foo")); + AssertPermanence(foo, PR_FALSE); + + nsCOMPtr foop = do_GetPermanentAtom("foo"); + AssertString(foop, NS_LITERAL_CSTRING("foo")); + AssertPermanence(foop, PR_TRUE); + + Assert(foo == foop, "atoms are equal"); + + nsCOMPtr barp = do_GetPermanentAtom("bar"); + AssertString(barp, NS_LITERAL_CSTRING("bar")); + AssertPermanence(barp, PR_TRUE); + + nsCOMPtr bar = do_GetAtom("bar"); + AssertString(bar, NS_LITERAL_CSTRING("bar")); + AssertPermanence(bar, PR_TRUE); + + Assert(bar == barp, "atoms are equal"); + + return 0; +} diff --git a/src/libs/xpcom18a4/xpcom/tests/TestPipes.cpp b/src/libs/xpcom18a4/xpcom/tests/TestPipes.cpp new file mode 100644 index 00000000..2d798a5b --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/TestPipes.cpp @@ -0,0 +1,655 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Pierre Phaneuf + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsIThread.h" +#include "nsIRunnable.h" +#include "nsIInputStream.h" +#include "nsIOutputStream.h" +#include "nsIServiceManager.h" +#include "prprf.h" +#include "prinrval.h" +#include "plstr.h" +#include "nsCRT.h" +#include "nsCOMPtr.h" +#include +#include "nsIPipe.h" // new implementation +#include "nsAutoLock.h" +#include // for rand + +#define KEY 0xa7 +#define ITERATIONS 33333 +char kTestPattern[] = "My hovercraft is full of eels.\n"; + +PRBool gTrace = PR_FALSE; + +static nsresult +WriteAll(nsIOutputStream *os, const char *buf, PRUint32 bufLen, PRUint32 *lenWritten) +{ + const char *p = buf; + *lenWritten = 0; + while (bufLen) { + PRUint32 n; + nsresult rv = os->Write(p, bufLen, &n); + if (NS_FAILED(rv)) return rv; + p += n; + bufLen -= n; + *lenWritten += n; + } + return NS_OK; +} + +class nsReceiver : public nsIRunnable { +public: + NS_DECL_ISUPPORTS + + NS_IMETHOD Run() { + nsresult rv; + char buf[101]; + PRUint32 count; + PRIntervalTime start = PR_IntervalNow(); + while (PR_TRUE) { + rv = mIn->Read(buf, 100, &count); + if (NS_FAILED(rv)) { + printf("read failed\n"); + break; + } + if (count == 0) { +// printf("EOF count = %d\n", mCount); + break; + } + + if (gTrace) { + printf("read: "); + buf[count] = '\0'; + printf(buf); + printf("\n"); + } + mCount += count; + } + PRIntervalTime end = PR_IntervalNow(); + printf("read %d bytes, time = %dms\n", mCount, + PR_IntervalToMilliseconds(end - start)); + return rv; + } + + nsReceiver(nsIInputStream* in) : mIn(in), mCount(0) { + NS_ADDREF(in); + } + + PRUint32 GetBytesRead() { return mCount; } + +private: + ~nsReceiver() { + NS_RELEASE(mIn); + } + +protected: + nsIInputStream* mIn; + PRUint32 mCount; +}; + +NS_IMPL_THREADSAFE_ISUPPORTS1(nsReceiver, nsIRunnable) + +nsresult +TestPipe(nsIInputStream* in, nsIOutputStream* out) +{ + nsresult rv; + nsIThread* thread; + nsReceiver* receiver = new nsReceiver(in); + if (receiver == nsnull) return NS_ERROR_OUT_OF_MEMORY; + NS_ADDREF(receiver); + + rv = NS_NewThread(&thread, receiver, 0, PR_JOINABLE_THREAD); + if (NS_FAILED(rv)) return rv; + + PRUint32 total = 0; + PRIntervalTime start = PR_IntervalNow(); + for (PRUint32 i = 0; i < ITERATIONS; i++) { + PRUint32 writeCount; + char *buf = PR_smprintf("%d %s", i, kTestPattern); + PRUint32 len = strlen(buf); + rv = WriteAll(out, buf, len, &writeCount); + if (gTrace) { + printf("wrote: "); + for (PRUint32 j = 0; j < writeCount; j++) { + putc(buf[j], stdout); + } + printf("\n"); + } + PR_smprintf_free(buf); + if (NS_FAILED(rv)) return rv; + total += writeCount; + } + rv = out->Close(); + if (NS_FAILED(rv)) return rv; + + PRIntervalTime end = PR_IntervalNow(); + + thread->Join(); + + printf("wrote %d bytes, time = %dms\n", total, + PR_IntervalToMilliseconds(end - start)); + NS_ASSERTION(receiver->GetBytesRead() == total, "didn't read everything"); + + NS_RELEASE(thread); + NS_RELEASE(receiver); + + return NS_OK; +} + +//////////////////////////////////////////////////////////////////////////////// + +class nsShortReader : public nsIRunnable { +public: + NS_DECL_ISUPPORTS + + NS_IMETHOD Run() { + nsresult rv; + char buf[101]; + PRUint32 count; + PRUint32 total = 0; + while (PR_TRUE) { + //if (gTrace) + // printf("calling Read\n"); + rv = mIn->Read(buf, 100, &count); + if (NS_FAILED(rv)) { + printf("read failed\n"); + break; + } + if (count == 0) { + break; + } + buf[count] = '\0'; + if (gTrace) + printf("read %d bytes: %s\n", count, buf); + Received(count); + total += count; + } + printf("read %d bytes\n", total); + return rv; + } + + nsShortReader(nsIInputStream* in) : mIn(in), mReceived(0) { + NS_ADDREF(in); + } + + void Received(PRUint32 count) { + nsAutoCMonitor mon(this); + mReceived += count; + mon.Notify(); + } + + PRUint32 WaitForReceipt() { + nsAutoCMonitor mon(this); + PRUint32 result = mReceived; + while (result == 0) { + mon.Wait(); + NS_ASSERTION(mReceived >= 0, "failed to receive"); + result = mReceived; + } + mReceived = 0; + return result; + } + +private: + ~nsShortReader() { + NS_RELEASE(mIn); + } + +protected: + nsIInputStream* mIn; + PRUint32 mReceived; +}; + +NS_IMPL_THREADSAFE_ISUPPORTS1(nsShortReader, nsIRunnable) + +nsresult +TestShortWrites(nsIInputStream* in, nsIOutputStream* out) +{ + nsresult rv; + nsIThread* thread; + nsShortReader* receiver = new nsShortReader(in); + if (receiver == nsnull) return NS_ERROR_OUT_OF_MEMORY; + NS_ADDREF(receiver); + + rv = NS_NewThread(&thread, receiver, 0, PR_JOINABLE_THREAD); + if (NS_FAILED(rv)) return rv; + + PRUint32 total = 0; + for (PRUint32 i = 0; i < ITERATIONS; i++) { + PRUint32 writeCount; + char* buf = PR_smprintf("%d %s", i, kTestPattern); + PRUint32 len = strlen(buf); + len = len * rand() / RAND_MAX; + len = PR_MAX(1, len); + rv = WriteAll(out, buf, len, &writeCount); + if (NS_FAILED(rv)) return rv; + NS_ASSERTION(writeCount == len, "didn't write enough"); + total += writeCount; + + if (gTrace) + printf("wrote %d bytes: %s\n", writeCount, buf); + PR_smprintf_free(buf); + //printf("calling Flush\n"); + out->Flush(); + //printf("calling WaitForReceipt\n"); + PRUint32 received = receiver->WaitForReceipt(); + NS_ASSERTION(received == writeCount, "received wrong amount"); + } + rv = out->Close(); + if (NS_FAILED(rv)) return rv; + + thread->Join(); + printf("wrote %d bytes\n", total); + + NS_RELEASE(thread); + NS_RELEASE(receiver); + + return NS_OK; +} + +//////////////////////////////////////////////////////////////////////////////// + +#if 0 + +class nsPipeObserver : public nsIInputStreamObserver, + public nsIOutputStreamObserver +{ +public: + NS_DECL_ISUPPORTS + + NS_IMETHOD OnFull(nsIOutputStream *outStr) { + printf("OnFull outStr=%p\n", outStr); + return NS_OK; + } + + NS_IMETHOD OnWrite(nsIOutputStream *outStr, PRUint32 amount) { + printf("OnWrite outStr=%p amount=%d\n", outStr, amount); + return NS_OK; + } + + NS_IMETHOD OnEmpty(nsIInputStream* inStr) { + printf("OnEmpty inStr=%p\n", inStr); + return NS_OK; + } + + NS_IMETHOD OnClose(nsIInputStream* inStr) { + printf("OnClose inStr=%p\n", inStr); + return NS_OK; + } + + nsPipeObserver() { } + +private: + ~nsPipeObserver() {} +}; + +NS_IMPL_ISUPPORTS2(nsPipeObserver, nsIInputStreamObserver, nsIOutputStreamObserver) + +nsresult +TestPipeObserver() +{ + nsresult rv; + nsPipeObserver* obs = new nsPipeObserver(); + if (obs == nsnull) return NS_ERROR_OUT_OF_MEMORY; + NS_ADDREF(obs); + + printf("TestPipeObserver: OnWrite and OnFull should be called once, OnEmpty should be called twice.\n"); + nsIInputStream* in; + nsIOutputStream* out; + rv = NS_NewPipe(&in, &out, 18, 36, PR_TRUE, PR_TRUE); + if (NS_FAILED(rv)) return rv; + + nsCOMPtr observableIn(do_QueryInterface(in, &rv)); + if (NS_FAILED(rv)) return rv; + nsCOMPtr observableOut(do_QueryInterface(out, &rv)); + if (NS_FAILED(rv)) return rv; + + rv = observableIn->SetObserver(obs); + if (NS_FAILED(rv)) return rv; + rv = observableOut->SetObserver(obs); + if (NS_FAILED(rv)) return rv; + + char buf[] = "puirt a beul: a style of Gaelic vocal music intended for dancing."; + PRUint32 cnt; + printf("> should see OnWrite message:\n"); + rv = out->Write(buf, 20, &cnt); + if (NS_FAILED(rv)) return rv; + NS_ASSERTION(cnt == 20, "Write failed"); + + printf("> should see OnWrite message followed by OnFull message:\n"); + rv = out->Write(buf + 20, 20, &cnt); + if (NS_FAILED(rv)) return rv; + NS_ASSERTION(cnt == 16, "Write failed"); + + rv = in->Available(&cnt); + if (NS_FAILED(rv)) return rv; + printf("available = %u\n", cnt); + NS_ASSERTION(cnt == 36, "Available failed"); + + char buf2[40]; + printf("> should see OnEmpty message:\n"); + rv = in->Read(buf2, 40, &cnt); + if (NS_FAILED(rv)) return rv; + printf("cnt = %u\n", cnt); + NS_ASSERTION(cnt == 36, "Read failed"); + NS_ASSERTION(nsCRT::strncmp(buf, buf2, 36) == 0, "Read wrong stuff"); + + rv = in->Available(&cnt); + if (NS_FAILED(rv)) return rv; + printf("available = %u\n", cnt); + NS_ASSERTION(cnt == 0, "Available failed"); + + printf("> should see OnEmpty message:\n"); + rv = in->Read(buf2, 2, &cnt); + if (NS_FAILED(rv) && rv != NS_BASE_STREAM_WOULD_BLOCK) return rv; + NS_ASSERTION(cnt == 0 && rv == NS_BASE_STREAM_WOULD_BLOCK, "Read failed"); + + printf("> should see OnWrite message:\n"); + rv = out->Write(buf, 20, &cnt); + if (NS_FAILED(rv)) return rv; + NS_ASSERTION(cnt == 20, "Write failed"); + + rv = in->Available(&cnt); + if (NS_FAILED(rv)) return rv; + printf("available = %u\n", cnt); + NS_ASSERTION(cnt == 20, "Available failed"); + + printf("> should see OnEmpty message:\n"); + rv = in->Read(buf2, 20, &cnt); + if (NS_FAILED(rv)) return rv; + NS_ASSERTION(cnt == 20, "Read failed"); + + printf("> should see OnClose message:\n"); + NS_RELEASE(obs); + NS_RELEASE(in); + NS_RELEASE(out); + return NS_OK; +} +#endif + +//////////////////////////////////////////////////////////////////////////////// + +class nsPump : public nsIRunnable +{ +public: + NS_DECL_ISUPPORTS + + NS_IMETHOD Run() { + nsresult rv; + PRUint32 count; + while (PR_TRUE) { + nsAutoCMonitor mon(this); + rv = mOut->WriteFrom(mIn, ~0U, &count); + if (NS_FAILED(rv)) { + printf("Write failed\n"); + break; + } + if (count == 0) { + printf("EOF count = %d\n", mCount); + break; + } + + if (gTrace) { + printf("Wrote: %d\n", count); + } + mCount += count; + } + mOut->Close(); + return rv; + } + + nsPump(nsIInputStream* in, + nsIOutputStream* out) + : mIn(in), mOut(out), mCount(0) { + } + +private: + ~nsPump() {} + +protected: + nsCOMPtr mIn; + nsCOMPtr mOut; + PRUint32 mCount; +}; + +NS_IMPL_THREADSAFE_ISUPPORTS1(nsPump, + nsIRunnable) + +nsresult +TestChainedPipes() +{ + nsresult rv; + printf("TestChainedPipes\n"); + + nsIInputStream* in1; + nsIOutputStream* out1; + rv = NS_NewPipe(&in1, &out1, 20, 1999); + if (NS_FAILED(rv)) return rv; + + nsIInputStream* in2; + nsIOutputStream* out2; + rv = NS_NewPipe(&in2, &out2, 200, 401); + if (NS_FAILED(rv)) return rv; + + nsIThread* thread; + nsPump* pump = new nsPump(in1, out2); + if (pump == nsnull) return NS_ERROR_OUT_OF_MEMORY; + NS_ADDREF(pump); + + rv = NS_NewThread(&thread, pump, 0, PR_JOINABLE_THREAD); + if (NS_FAILED(rv)) return rv; + + nsIThread* receiverThread; + nsReceiver* receiver = new nsReceiver(in2); + if (receiver == nsnull) return NS_ERROR_OUT_OF_MEMORY; + NS_ADDREF(receiver); + + rv = NS_NewThread(&receiverThread, receiver, 0, PR_JOINABLE_THREAD); + if (NS_FAILED(rv)) return rv; + + PRUint32 total = 0; + for (PRUint32 i = 0; i < ITERATIONS; i++) { + PRUint32 writeCount; + char* buf = PR_smprintf("%d %s", i, kTestPattern); + PRUint32 len = strlen(buf); + len = len * rand() / RAND_MAX; + len = PR_MAX(1, len); + rv = WriteAll(out1, buf, len, &writeCount); + if (NS_FAILED(rv)) return rv; + NS_ASSERTION(writeCount == len, "didn't write enough"); + total += writeCount; + + if (gTrace) + printf("wrote %d bytes: %s\n", writeCount, buf); + + PR_smprintf_free(buf); + } + printf("wrote total of %d bytes\n", total); + rv = out1->Close(); + if (NS_FAILED(rv)) return rv; + + thread->Join(); + receiverThread->Join(); + + NS_RELEASE(thread); + NS_RELEASE(pump); + NS_RELEASE(receiverThread); + NS_RELEASE(receiver); + NS_RELEASE(out2); + NS_RELEASE(in2); + NS_RELEASE(in1); + NS_RELEASE(out1); + return NS_OK; +} + +//////////////////////////////////////////////////////////////////////////////// + +void +RunTests(PRUint32 segSize, PRUint32 segCount) +{ + nsresult rv; + nsIInputStream* in = 0; /* bird: initialize to quiet gcc. */ + nsIOutputStream* out = 0; /* ditto */ + PRUint32 bufSize; + + bufSize = segSize * segCount; + printf("Testing New Pipes: segment size %d buffer size %d\n", segSize, bufSize); + + printf("Testing long writes...\n"); + rv = NS_NewPipe(&in, &out, segSize, bufSize); + NS_ASSERTION(NS_SUCCEEDED(rv), "NS_NewPipe failed"); + rv = TestPipe(in, out); + NS_RELEASE(in); + NS_RELEASE(out); + NS_ASSERTION(NS_SUCCEEDED(rv), "TestPipe failed"); + + printf("Testing short writes...\n"); + rv = NS_NewPipe(&in, &out, segSize, bufSize); + NS_ASSERTION(NS_SUCCEEDED(rv), "NS_NewPipe failed"); + rv = TestShortWrites(in, out); + NS_RELEASE(in); + NS_RELEASE(out); + NS_ASSERTION(NS_SUCCEEDED(rv), "TestPipe failed"); +} + +//////////////////////////////////////////////////////////////////////////////// +#if 0 +void +TestSearch(const char* delim, PRUint32 segSize) +{ + nsresult rv; + // need at least 2 segments to test boundary conditions: + PRUint32 bufDataSize = segSize * 2; + PRUint32 bufSize = segSize * 2; + nsIInputStream* in; + nsIOutputStream* out; + rv = NS_NewPipe(&in, &out, segSize, bufSize); + NS_ASSERTION(NS_SUCCEEDED(rv), "NS_NewPipe failed"); + out->SetNonBlocking(PR_TRUE); + + PRUint32 i, j, amt; + PRUint32 delimLen = nsCRT::strlen(delim); + for (i = 0; i < bufDataSize; i++) { + // first fill the buffer + for (j = 0; j < i; j++) { + rv = out->Write("-", 1, &amt); + NS_ASSERTION(NS_SUCCEEDED(rv) && amt == 1, "Write failed"); + } + rv = out->Write(delim, delimLen, &amt); + NS_ASSERTION(NS_SUCCEEDED(rv), "Write failed"); + if (i + amt < bufDataSize) { + for (j = i + amt; j < bufDataSize; j++) { + rv = out->Write("+", 1, &amt); + NS_ASSERTION(NS_SUCCEEDED(rv) && amt == 1, "Write failed"); + } + } + + // now search for the delimiter + PRBool found; + PRUint32 offset; + rv = in->Search(delim, PR_FALSE, &found, &offset); + NS_ASSERTION(NS_SUCCEEDED(rv), "Search failed"); + + // print the results + char* bufferContents = new char[bufDataSize + 1]; + rv = in->Read(bufferContents, bufDataSize, &amt); + NS_ASSERTION(NS_SUCCEEDED(rv) && amt == bufDataSize, "Read failed"); + bufferContents[bufDataSize] = '\0'; + printf("Buffer: %s\nDelim: %s %s offset: %d\n", bufferContents, + delim, (found ? "found" : "not found"), offset); + } + NS_RELEASE(in); + NS_RELEASE(out); +} +#endif +//////////////////////////////////////////////////////////////////////////////// + +#ifdef DEBUG +extern NS_COM void +TestSegmentedBuffer(); +#endif + +int +main(int argc, char* argv[]) +{ + nsresult rv; + nsIServiceManager* servMgr; + + rv = NS_InitXPCOM2(&servMgr, NULL, NULL); + if (NS_FAILED(rv)) return rv; + + if (argc > 1 && nsCRT::strcmp(argv[1], "-trace") == 0) + gTrace = PR_TRUE; + +#ifdef DEBUG + TestSegmentedBuffer(); +#endif + +#if 0 // obsolete old implementation + rv = NS_NewPipe(&in, &out, 4096 * 4); + if (NS_FAILED(rv)) { + printf("NewPipe failed\n"); + return -1; + } + + rv = TestPipe(in, out); + NS_RELEASE(in); + NS_RELEASE(out); + if (NS_FAILED(rv)) { + printf("TestPipe failed\n"); + return -1; + } +#endif +#if 0 + TestSearch("foo", 8); + TestSearch("bar", 6); + TestSearch("baz", 2); +#endif + + rv = TestChainedPipes(); + NS_ASSERTION(NS_SUCCEEDED(rv), "TestChainedPipes failed"); + RunTests(16, 1); + RunTests(4096, 16); + NS_RELEASE(servMgr); + rv = NS_ShutdownXPCOM( NULL ); + NS_ASSERTION(NS_SUCCEEDED(rv), "NS_ShutdownXPCOM failed"); + return 0; +} + +//////////////////////////////////////////////////////////////////////////////// diff --git a/src/libs/xpcom18a4/xpcom/tests/TestServMgr.cpp b/src/libs/xpcom18a4/xpcom/tests/TestServMgr.cpp new file mode 100644 index 00000000..8eaaaa77 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/TestServMgr.cpp @@ -0,0 +1,173 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Pierre Phaneuf + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "MyService.h" +#include "nsXPCOM.h" +#include "nsIServiceManager.h" +#include "nsIComponentManager.h" +#include + +static NS_DEFINE_CID(kIMyServiceCID, NS_IMYSERVICE_CID); + +//////////////////////////////////////////////////////////////////////////////// + +IMyService* myServ = NULL; + +nsresult +BeginTest(int testNumber) +{ + nsresult err; + NS_ASSERTION(myServ == NULL, "myServ not reset"); + err = nsServiceManager::GetService(kIMyServiceCID, NS_GET_IID(IMyService), + (nsISupports**)&myServ); + return err; +} + +nsresult +EndTest(int testNumber) +{ + nsresult err = NS_OK; + + if (myServ) { + err = myServ->Doit(); + if (err != NS_OK) return err; + + err = nsServiceManager::ReleaseService(kIMyServiceCID, myServ); + if (err != NS_OK) return err; + myServ = NULL; + } + + printf("test %d succeeded\n", testNumber); + return NS_OK; +} + +nsresult +SimpleTest(int testNumber) +{ + // This test just gets a service, uses it and releases it. + + nsresult err; + err = BeginTest(testNumber); + if (err != NS_OK) return err; + err = EndTest(testNumber); + return err; +} + +//////////////////////////////////////////////////////////////////////////////// + +nsresult +AsyncShutdown(int testNumber) +{ + nsresult err; + + // If the AsyncShutdown was truly asynchronous and happened on another + // thread, we'd have to protect all accesses to myServ throughout this + // code with a monitor. + + err = nsServiceManager::UnregisterService(kIMyServiceCID); + if (err == NS_ERROR_SERVICE_NOT_AVAILABLE) { + printf("async shutdown -- service not found\n"); + return NS_OK; + } + return err; +} + +nsresult +AsyncNoShutdownTest(int testNumber) +{ + // This test gets a service, and also gets an async request for shutdown, + // but the service doesn't get shut down because some other client (who's + // not participating in the async shutdown game as he should) is + // continuing to hang onto the service. This causes myServ variable to + // get set to NULL, but the service doesn't get unloaded right away as + // it should. + + nsresult err; + + err = BeginTest(testNumber); + if (err != NS_OK) return err; + + // Create some other user of kIMyServiceCID, preventing it from + // really going away: + IMyService* otherClient; + err = nsServiceManager::GetService(kIMyServiceCID, NS_GET_IID(IMyService), + (nsISupports**)&otherClient); + if (err != NS_OK) return err; + + err = AsyncShutdown(testNumber); + if (err != NS_OK) return err; + err = EndTest(testNumber); + + // Finally, release the other client. + err = nsServiceManager::ReleaseService(kIMyServiceCID, otherClient); + + return err; +} + +//////////////////////////////////////////////////////////////////////////////// +int +main(void) +{ + nsresult err; + int testNumber = 0; + + err = NS_InitXPCOM2(nsnull, nsnull, nsnull); + if (NS_FAILED(err)) { + printf("NS_InitXPCOM2 failed\n"); + return -1; + } + + err = SimpleTest(++testNumber); + if (err != NS_OK) + goto error; + + err = AsyncNoShutdownTest(++testNumber); + if (err != NS_OK) + goto error; + + AsyncShutdown(++testNumber); + + printf("there was great success\n"); + return 0; + + error: + printf("test %d failed\n", testNumber); + return -1; +} + +//////////////////////////////////////////////////////////////////////////////// diff --git a/src/libs/xpcom18a4/xpcom/tests/TestShutdown.cpp b/src/libs/xpcom18a4/xpcom/tests/TestShutdown.cpp new file mode 100644 index 00000000..259a7b31 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/TestShutdown.cpp @@ -0,0 +1,78 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Pierre Phaneuf + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsIServiceManager.h" + +// Gee this seems simple! It's for testing for memory leaks with Purify. + +void main(int argc, char* argv[]) +{ + nsresult rv; + nsIServiceManager* servMgr; + rv = NS_InitXPCOM2(&servMgr, NULL, NULL); + NS_ASSERTION(NS_SUCCEEDED(rv), "NS_InitXPCOM failed"); + + // try loading a component and releasing it to see if it leaks + if (argc > 1 && argv[1] != nsnull) { + char* cidStr = argv[1]; + nsISupports* obj = nsnull; + if (cidStr[0] == '{') { + nsCID cid; + cid.Parse(cidStr); + rv = nsComponentManager::CreateInstance(cid, nsnull, + NS_GET_IID(nsISupports), + (void**)&obj); + } + else { + // contractID case: + rv = nsComponentManager::CreateInstance(cidStr, nsnull, + NS_GET_IID(nsISupports), + (void**)&obj); + } + if (NS_SUCCEEDED(rv)) { + printf("Successfully created %s\n", cidStr); + NS_RELEASE(obj); + } + else { + printf("Failed to create %s (%x)\n", cidStr, rv); + } + } + + rv = NS_ShutdownXPCOM(servMgr); + NS_ASSERTION(NS_SUCCEEDED(rv), "NS_ShutdownXPCOM failed"); +} diff --git a/src/libs/xpcom18a4/xpcom/tests/TestStackCrawl.cpp b/src/libs/xpcom18a4/xpcom/tests/TestStackCrawl.cpp new file mode 100644 index 00000000..76187edd --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/TestStackCrawl.cpp @@ -0,0 +1,11 @@ +#include + +#include "nsISupportsUtils.h" +#include "nsTraceRefCntImpl.h" + +int main(int argc, char* argv[]) +{ + nsTraceRefcntImpl::WalkTheStack(stdout); + return 0; +} + diff --git a/src/libs/xpcom18a4/xpcom/tests/TestStrings.cpp b/src/libs/xpcom18a4/xpcom/tests/TestStrings.cpp new file mode 100644 index 00000000..b1b725a4 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/TestStrings.cpp @@ -0,0 +1,643 @@ +/* vim:set ts=2 sw=2 et cindent: */ +/* ***** 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 IBM Corporation. + * Portions created by IBM Corporation are Copyright (C) 2003 + * IBM Corporation. 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 +#include "nsString.h" +#include "nsReadableUtils.h" +#include "nsCRT.h" + +void test_assign_helper(const nsACString& in, nsACString &_retval) + { + _retval = in; + } + +PRBool test_assign() + { + nsCString result; + test_assign_helper(NS_LITERAL_CSTRING("a") + NS_LITERAL_CSTRING("b"), result); + PRBool r = strcmp(result.get(), "ab") == 0; + if (!r) + printf("[result=%s]\n", result.get()); + return r; + } + +PRBool test_assign_c() + { + nsCString c; c.Assign('c'); + PRBool r = strcmp(c.get(), "c") == 0; + if (!r) + printf("[result=%s]\n", c.get()); + return r; + } + +PRBool test1() + { + NS_NAMED_LITERAL_STRING(empty, ""); + const nsAString& aStr = empty; + + nsAutoString buf(aStr); + + PRInt32 n = buf.FindChar(','); + + n = buf.Length(); + + buf.Cut(0, n + 1); + n = buf.FindChar(','); + + if (n != kNotFound) + printf("n=%d\n", n); + + return n == kNotFound; + } + +PRBool test2() + { + nsCString data("hello world"); + const nsACString& aStr = data; + + nsCString temp(aStr); + temp.Cut(0, 6); + + PRBool r = strcmp(temp.get(), "world") == 0; + if (!r) + printf("[temp=%s]\n", temp.get()); + return r; + } + +PRBool test_find() + { + nsCString src(""); + + PRInt32 i = src.Find("DOCTYPE", PR_TRUE, 2, 1); + if (i == 2) + return PR_TRUE; + + printf("i=%d\n", i); + return PR_FALSE; + } + +PRBool test_rfind() + { + const char text[] = ""; + const char term[] = "bLaH"; + nsCString src(text); + PRInt32 i; + + i = src.RFind(term, PR_TRUE, 3, -1); + if (i != kNotFound) + { + printf("unexpected result searching from offset=3, i=%d\n", i); + return PR_FALSE; + } + + i = src.RFind(term, PR_TRUE, -1, -1); + if (i != 20) + { + printf("unexpected result searching from offset=-1, i=%d\n", i); + return PR_FALSE; + } + + i = src.RFind(term, PR_TRUE, 13, -1); + if (i != 10) + { + printf("unexpected result searching from offset=13, i=%d\n", i); + return PR_FALSE; + } + + i = src.RFind(term, PR_TRUE, 22, 3); + if (i != 20) + { + printf("unexpected result searching from offset=22, i=%d\n", i); + return PR_FALSE; + } + + return PR_TRUE; + } + +PRBool test_rfind_2() + { + const char text[] = ""; + nsCString src(text); + PRInt32 i = src.RFind("TYPE", PR_FALSE, 5, -1); + if (i == 5) + return PR_TRUE; + + printf("i=%d\n", i); + return PR_FALSE; + } + +PRBool test_rfind_3() + { + const char text[] = "urn:mozilla:locale:en-US:necko"; + nsCAutoString value(text); + PRInt32 i = value.RFind(":"); + if (i == 24) + return PR_TRUE; + + printf("i=%d\n", i); + return PR_FALSE; + } + +PRBool test_rfind_4() + { + nsCString value("a.msf"); + PRInt32 i = value.RFind(".msf"); + if (i != 1) + { + printf("i=%d\n", i); + return PR_FALSE; + } + + return PR_TRUE; + } + +PRBool test_distance() + { + const char text[] = "abc-xyz"; + nsCString s(text); + nsCString::const_iterator begin, end; + s.BeginReading(begin); + s.EndReading(end); + size_t d = Distance(begin, end); + PRBool r = (d == sizeof(text)-1); + if (!r) + printf("d=%zu\n", d); + return r; + } + +PRBool test_length() + { + const char text[] = "abc-xyz"; + nsCString s(text); + size_t d = s.Length(); + PRBool r = (d == sizeof(text)-1); + if (!r) + printf("d=%zu\n", d); + return r; + } + +PRBool test_trim() + { + const char text[] = " a\t $ "; + const char set[] = " \t$"; + + nsCString s(text); + s.Trim(set); + PRBool r = strcmp(s.get(), "a") == 0; + if (!r) + printf("[s=%s]\n", s.get()); + return r; + } + +PRBool test_replace_substr() + { + const char text[] = "abc-ppp-qqq-ppp-xyz"; + nsCString s(text); + s.ReplaceSubstring("ppp", "www"); + PRBool r = strcmp(s.get(), "abc-www-qqq-www-xyz") == 0; + if (!r) + { + printf("[s=%s]\n", s.get()); + return PR_FALSE; + } + + s.Assign("foobar"); + s.ReplaceSubstring("foo", "bar"); + s.ReplaceSubstring("bar", ""); + r = strcmp(s.get(), "") == 0; + if (!r) + { + printf("[s=%s]\n", s.get()); + return PR_FALSE; + } + + s.Assign("foofoofoo"); + s.ReplaceSubstring("foo", "foo"); + r = strcmp(s.get(), "foofoofoo") == 0; + if (!r) + { + printf("[s=%s]\n", s.get()); + return PR_FALSE; + } + + s.Assign("foofoofoo"); + s.ReplaceSubstring("of", "fo"); + r = strcmp(s.get(), "fofoofooo") == 0; + if (!r) + { + printf("[s=%s]\n", s.get()); + return PR_FALSE; + } + + return PR_TRUE; + } + +PRBool test_replace_substr_2() + { + const char *oldName = nsnull; + const char *newName = "user"; + nsString acctName; acctName.AssignLiteral("forums.foo.com"); + nsAutoString newAcctName, oldVal, newVal; + oldVal.AssignWithConversion(oldName); + newVal.AssignWithConversion(newName); + newAcctName.Assign(acctName); + + // here, oldVal is empty. we are testing that this function + // does not hang. see bug 235355. + newAcctName.ReplaceSubstring(oldVal, newVal); + + // we expect that newAcctName will be unchanged. + if (!newAcctName.Equals(acctName)) + return PR_FALSE; + + return PR_TRUE; + } + +PRBool test_strip_ws() + { + const char text[] = " a $ "; + nsCString s(text); + s.StripWhitespace(); + PRBool r = strcmp(s.get(), "a$") == 0; + if (!r) + printf("[s=%s]\n", s.get()); + return r; + } + +PRBool test_equals_ic() + { + nsCString s; + PRBool r = s.LowerCaseEqualsLiteral("view-source"); + if (r) + printf("[r=%d]\n", r); + return !r; + } + +PRBool test_fixed_string() + { + char buf[256] = "hello world"; + + nsFixedCString s(buf, sizeof(buf)); + + if (s.Length() != strlen(buf)) + return PR_FALSE; + + if (strcmp(s.get(), buf) != 0) + return PR_FALSE; + + s.Assign("foopy doopy doo"); + if (s.get() != buf) + return PR_FALSE; + + return PR_TRUE; + } + +PRBool test_concat() + { + nsCString bar("bar"); + const nsACString& barRef = bar; + + const nsPromiseFlatCString& result = + PromiseFlatCString(NS_LITERAL_CSTRING("foo") + + NS_LITERAL_CSTRING(",") + + barRef); + if (strcmp(result.get(), "foo,bar") == 0) + return PR_TRUE; + + printf("[result=%s]\n", result.get()); + return PR_FALSE; + } + +PRBool test_concat_2() + { + nsCString fieldTextStr("xyz"); + nsCString text("text"); + const nsACString& aText = text; + + nsCAutoString result( fieldTextStr + aText ); + + if (strcmp(result.get(), "xyztext") == 0) + return PR_TRUE; + + printf("[result=%s]\n", result.get()); + return PR_FALSE; + } + +#if 0 +PRBool test_concat_3() + { + nsCString a("a"), b("b"); + + // THIS DOES NOT COMPILE + const nsACString& r = a + b; + + return PR_TRUE; + } +#endif + +PRBool test_xpidl_string() + { + nsXPIDLCString a, b; + a = b; + if (a != b) + return PR_FALSE; + + a.Adopt(0); + if (a != b) + return PR_FALSE; + + a.Append("foopy"); + a.Assign(b); + if (a != b) + return PR_FALSE; + + a.Insert("", 0); + a.Assign(b); + if (a != b) + return PR_FALSE; + + const char text[] = "hello world"; + *getter_Copies(a) = nsCRT::strdup(text); + if (strcmp(a, text) != 0) + return PR_FALSE; + + b = a; + if (strcmp(a, b) != 0) + return PR_FALSE; + + a.Adopt(0); + nsACString::const_iterator begin, end; + a.BeginReading(begin); + a.EndReading(end); + char *r = ToNewCString(Substring(begin, end)); + if (strcmp(r, "") != 0) + return PR_FALSE; + nsMemory::Free(r); + + a.Adopt(0); + if (a != (const char*) 0) + return PR_FALSE; + + /* + PRInt32 index = a.FindCharInSet("xyz"); + if (index != kNotFound) + return PR_FALSE; + */ + + return PR_TRUE; + } + +PRBool test_empty_assign() + { + nsCString a; + a.AssignLiteral(""); + + a.AppendLiteral(""); + + nsCString b; + b.SetCapacity(0); + return PR_TRUE; + } + +PRBool test_set_length() + { + const char kText[] = "Default Plugin"; + nsCString buf; + buf.SetCapacity(sizeof(kText)-1); + buf.Assign(kText); + buf.SetLength(sizeof(kText)-1); + if (strcmp(buf.get(), kText) != 0) + return PR_FALSE; + return PR_TRUE; + } + +PRBool test_substring() + { + nsCString super("hello world"), sub("hello"); + + // this tests that |super| starts with |sub|, + + PRBool r = sub.Equals(StringHead(super, sub.Length())); + if (!r) + return PR_FALSE; + + // and verifies that |sub| does not start with |super|. + + r = super.Equals(StringHead(sub, super.Length())); + if (r) + return PR_FALSE; + + return PR_TRUE; + } + +PRBool test_appendint64() + { + nsCString str; + + PRInt64 max = LL_MaxInt(); + static const char max_expected[] = "9223372036854775807"; + PRInt64 min = LL_MinInt(); + static const char min_expected[] = "-9223372036854775808"; + static const char min_expected_oct[] = "1000000000000000000000"; + PRInt64 maxint_plus1 = LL_INIT(1, 0); + static const char maxint_plus1_expected[] = "4294967296"; + static const char maxint_plus1_expected_x[] = "100000000"; + + str.AppendInt(max); + + if (!str.Equals(max_expected)) { + fprintf(stderr, "Error appending LL_MaxInt(): Got %s\n", str.get()); + return PR_FALSE; + } + + str.Truncate(); + str.AppendInt(min); + if (!str.Equals(min_expected)) { + fprintf(stderr, "Error appending LL_MinInt(): Got %s\n", str.get()); + return PR_FALSE; + } + str.Truncate(); + str.AppendInt(min, 8); + if (!str.Equals(min_expected_oct)) { + fprintf(stderr, "Error appending LL_MinInt() (oct): Got %s\n", str.get()); + return PR_FALSE; + } + + + str.Truncate(); + str.AppendInt(maxint_plus1); + if (!str.Equals(maxint_plus1_expected)) { + fprintf(stderr, "Error appending PR_UINT32_MAX + 1: Got %s\n", str.get()); + return PR_FALSE; + } + str.Truncate(); + str.AppendInt(maxint_plus1, 16); + if (!str.Equals(maxint_plus1_expected_x)) { + fprintf(stderr, "Error appending PR_UINT32_MAX + 1 (hex): Got %s\n", str.get()); + return PR_FALSE; + } + + + return PR_TRUE; + } + +PRBool test_findcharinset() + { + nsCString buf("hello, how are you?"); + + PRInt32 index = buf.FindCharInSet(",?", 5); + if (index != 5) + return PR_FALSE; + + index = buf.FindCharInSet("helo", 0); + if (index != 0) + return PR_FALSE; + + index = buf.FindCharInSet("z?", 6); + if (index != (PRInt32) buf.Length()-1) + return PR_FALSE; + + return PR_TRUE; + } + +PRBool test_rfindcharinset() + { + nsCString buf("hello, how are you?"); + + PRInt32 index = buf.RFindCharInSet(",?", 5); + if (index != 5) + return PR_FALSE; + + index = buf.RFindCharInSet("helo", 0); + if (index != 0) + return PR_FALSE; + + index = buf.RFindCharInSet("z?", 6); + if (index != kNotFound) + return PR_FALSE; + + index = buf.RFindCharInSet("l", 5); + if (index != 3) + return PR_FALSE; + + buf.Assign("abcdefghijkabc"); + + index = buf.RFindCharInSet("ab"); + if (index != 12) + return PR_FALSE; + + index = buf.RFindCharInSet("ab", 11); + if (index != 11) + return PR_FALSE; + + index = buf.RFindCharInSet("ab", 10); + if (index != 1) + return PR_FALSE; + + index = buf.RFindCharInSet("ab", 0); + if (index != 0) + return PR_FALSE; + + index = buf.RFindCharInSet("cd", 1); + if (index != kNotFound) + return PR_FALSE; + + index = buf.RFindCharInSet("h"); + if (index != 7) + return PR_FALSE; + + return PR_TRUE; + } + +//---- + +typedef PRBool (*TestFunc)(); + +static const struct Test + { + const char* name; + TestFunc func; + } +tests[] = + { + { "test_assign", test_assign }, + { "test_assign_c", test_assign_c }, + { "test1", test1 }, + { "test2", test2 }, + { "test_find", test_find }, + { "test_rfind", test_rfind }, + { "test_rfind_2", test_rfind_2 }, + { "test_rfind_3", test_rfind_3 }, + { "test_rfind_4", test_rfind_4 }, + { "test_distance", test_distance }, + { "test_length", test_length }, + { "test_trim", test_trim }, + { "test_replace_substr", test_replace_substr }, + { "test_replace_substr_2", test_replace_substr_2 }, + { "test_strip_ws", test_strip_ws }, + { "test_equals_ic", test_equals_ic }, + { "test_fixed_string", test_fixed_string }, + { "test_concat", test_concat }, + { "test_concat_2", test_concat_2 }, + { "test_xpidl_string", test_xpidl_string }, + { "test_empty_assign", test_empty_assign }, + { "test_set_length", test_set_length }, + { "test_substring", test_substring }, + { "test_appendint64", test_appendint64 }, + { "test_findcharinset", test_findcharinset }, + { "test_rfindcharinset", test_rfindcharinset }, + { nsnull, nsnull } + }; + +//---- + +int main(int argc, char **argv) + { + int count = 1; + if (argc > 1) + count = atoi(argv[1]); + + while (count--) + { + for (const Test* t = tests; t->name != nsnull; ++t) + { + printf("%25s : %s\n", t->name, t->func() ? "SUCCESS" : "FAILURE <--"); + } + } + + return 0; + } diff --git a/src/libs/xpcom18a4/xpcom/tests/TestThreads.cpp b/src/libs/xpcom18a4/xpcom/tests/TestThreads.cpp new file mode 100644 index 00000000..10025a05 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/TestThreads.cpp @@ -0,0 +1,280 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Pierre Phaneuf + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsIThread.h" +#include "nsIRunnable.h" +#include +#include +#include "nspr.h" +#include "nsCOMPtr.h" +#include "nsIServiceManager.h" + +class nsRunner : public nsIRunnable { +public: + NS_DECL_ISUPPORTS + + NS_IMETHOD Run() { + nsCOMPtr thread; + nsresult rv = nsIThread::GetCurrent(getter_AddRefs(thread)); + if (NS_FAILED(rv)) { + printf("failed to get current thread\n"); + return rv; + } + printf("running %d on thread %p\n", mNum, (void *)thread.get()); + + // if we don't do something slow, we'll never see the other + // worker threads run + PR_Sleep(PR_MillisecondsToInterval(100)); + + return rv; + } + + nsRunner(int num) : mNum(num) { + } + +protected: + int mNum; +}; + +NS_IMPL_THREADSAFE_ISUPPORTS1(nsRunner, nsIRunnable) + +nsresult +TestThreads() +{ + nsresult rv; + + nsCOMPtr runner; + rv = NS_NewThread(getter_AddRefs(runner), new nsRunner(0), 0, PR_JOINABLE_THREAD); + if (NS_FAILED(rv)) { + printf("failed to create thread\n"); + return rv; + } + + nsCOMPtr thread; + rv = nsIThread::GetCurrent(getter_AddRefs(thread)); + if (NS_FAILED(rv)) { + printf("failed to get current thread\n"); + return rv; + } + + PRThreadScope scope; + rv = runner->GetScope(&scope); + if (NS_FAILED(rv)) { + printf("runner already exited\n"); + } + + rv = runner->Join(); // wait for the runner to die before quitting + if (NS_FAILED(rv)) { + printf("join failed\n"); + } + + rv = runner->GetScope(&scope); // this should fail after Join + if (NS_SUCCEEDED(rv)) { + printf("get scope failed\n"); + } + + rv = runner->Interrupt(); // this should fail after Join + if (NS_SUCCEEDED(rv)) { + printf("interrupt failed\n"); + } + + //////////////////////////////////////////////////////////////////////////// + // try an unjoinable thread + rv = NS_NewThread(getter_AddRefs(runner), new nsRunner(1)); + if (NS_FAILED(rv)) { + printf("failed to create thread\n"); + return rv; + } + + rv = runner->Join(); // wait for the runner to die before quitting + if (NS_SUCCEEDED(rv)) { + printf("shouldn't have been able to join an unjoinable thread\n"); + } + + PR_Sleep(PR_MillisecondsToInterval(100)); // hopefully the runner will quit here + + return NS_OK; +} + +class nsStressRunner : public nsIRunnable { +public: + NS_DECL_ISUPPORTS + + NS_IMETHOD Run() { + NS_ASSERTION(!mWasRun, "run twice!"); + mWasRun = PR_TRUE; + PR_Sleep(1); + if (!PR_AtomicDecrement(&gNum)) { + printf(" last thread was %d\n", mNum); + } + return NS_OK; + } + + nsStressRunner(int num) : mNum(num), mWasRun(PR_FALSE) { + PR_AtomicIncrement(&gNum); + } + + static PRInt32 GetGlobalCount() {return gNum;} + +private: + ~nsStressRunner() { + NS_ASSERTION(mWasRun, "never run!"); + } + +protected: + static PRInt32 gNum; + PRInt32 mNum; + PRBool mWasRun; +}; + +PRInt32 nsStressRunner::gNum = 0; + +NS_IMPL_THREADSAFE_ISUPPORTS1(nsStressRunner, nsIRunnable) + +static int Stress(int loops, int threads) +{ + + for (int i = 0; i < loops; i++) { + printf("Loop %d of %d\n", i+1, loops); + + int k; + nsIThread** array = new nsIThread*[threads]; + NS_ASSERTION(array, "out of memory"); + + NS_ASSERTION(!nsStressRunner::GetGlobalCount(), "bad count of runnables"); + + for (k = 0; k < threads; k++) { + nsCOMPtr t; + nsresult rv = NS_NewThread(getter_AddRefs(t), + new nsStressRunner(k), + 0, PR_JOINABLE_THREAD); + NS_ASSERTION(NS_SUCCEEDED(rv), "can't create thread"); + NS_ADDREF(array[k] = t); + } + + for (k = threads-1; k >= 0; k--) { + array[k]->Join(); + NS_RELEASE(array[k]); + } + delete [] array; + } + return 0; +} + +PR_STATIC_CALLBACK(void) threadProc(void *arg) +{ + // printf(" running thread %d\n", (int) arg); + PR_Sleep(1); + PR_ASSERT(PR_JOINABLE_THREAD == PR_GetThreadState(PR_GetCurrentThread())); +} + +static int StressNSPR(int loops, int threads) +{ + + for (int i = 0; i < loops; i++) { + printf("Loop %d of %d\n", i+1, loops); + + int k; + PRThread** array = new PRThread*[threads]; + PR_ASSERT(array); + + for (k = 0; k < threads; k++) { + array[k] = PR_CreateThread(PR_USER_THREAD, + threadProc, (void*)(uintptr_t)k, + PR_PRIORITY_NORMAL, + PR_GLOBAL_THREAD, + PR_JOINABLE_THREAD, + 0); + PR_ASSERT(array[k]); + } + + for (k = 0; k < threads; k++) { + PR_ASSERT(PR_JOINABLE_THREAD == PR_GetThreadState(array[k])); + } + + for (k = threads-1; k >= 0; k--) { + PR_JoinThread(array[k]); + } + delete [] array; + } + return 0; +} + + +int +main(int argc, char** argv) +{ + int retval = 0; + nsresult rv; + + rv = NS_InitXPCOM2(nsnull, nsnull, nsnull); + if (NS_FAILED(rv)) return -1; + + if (argc > 1 && !strcmp(argv[1], "-stress")) { + int loops; + int threads; + if (argc != 4 || *argv[2] != '-' || *argv[3] != '-' || + !(loops = atoi(argv[2]+1)) || !(threads = atoi(argv[3]+1))) { + printf("To use -stress you must pass loop count and thread count...\n" + " TestThreads -stress -1000 -50\n"); + } else { + printf("Running stress test with %d loops of %d threads each\n", + loops, threads); + retval = Stress(loops, threads); + } + } else if (argc > 1 && !strcmp(argv[1], "-stress-nspr")) { + int loops; + int threads; + if (argc != 4 || *argv[2] != '-' || *argv[3] != '-' || + !(loops = atoi(argv[2]+1)) || !(threads = atoi(argv[3]+1))) { + printf("To use -stress-nspr you must pass loop count and thread count...\n" + " TestThreads -stress -1000 -50\n"); + } else { + printf("Running stress test with %d loops of %d threads each\n", + loops, threads); + retval = StressNSPR(loops, threads); + } + } else { + rv = TestThreads(); + if (NS_FAILED(rv)) return -1; + } + + rv = NS_ShutdownXPCOM(nsnull); + if (NS_FAILED(rv)) return -1; + return retval; +} diff --git a/src/libs/xpcom18a4/xpcom/tests/TestVoidBTree.cpp b/src/libs/xpcom18a4/xpcom/tests/TestVoidBTree.cpp new file mode 100644 index 00000000..956f179f --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/TestVoidBTree.cpp @@ -0,0 +1,302 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org Code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 +#include +#include "nsVoidBTree.h" +#include "nsVoidArray.h" + +#define COUNT 1024 +#define POINTER(i) NS_REINTERPRET_CAST(void*, 4 + 4 * (i)) + +static PRBool +Equal(const nsVoidArray& aControl, const nsVoidBTree& aTest) +{ + if (aControl.Count() != aTest.Count()) { + printf("counts not equal; "); + return PR_FALSE; + } + + for (PRInt32 i = aControl.Count() - 1; i >= 0; --i) { + if (aControl[i] != aTest[i]) { + printf("element %d differs; ", i); + return PR_FALSE; + } + } + + return PR_TRUE; +} + + +static void +CheckForwardEnumeration(const nsVoidArray& aControl, const nsVoidBTree& aTest) +{ + PRInt32 index = 0; + + nsVoidBTree::ConstIterator last = aTest.Last(); + for (nsVoidBTree::ConstIterator element = aTest.First(); element != last; ++element, ++index) { + if (*element != aControl[index]) { + printf("failed forward enumeration\n"); + exit(-1); + } + } + + if (index != aControl.Count()) { + printf("erratic termination during forward enumeration\n"); + exit(-1); + } +} + +static void +CheckBackwardEnumeration(const nsVoidArray& aControl, const nsVoidBTree& aTest) +{ + PRInt32 index = aControl.Count(); + nsVoidBTree::ConstIterator first = aTest.First(); + nsVoidBTree::ConstIterator element = aTest.Last(); + + if (first != element) { + do { + if (*--element != aControl[--index]) { + printf("failed backward enumeration\n"); + exit(-1); + } + } while (element != first); + } + + if (index != 0) { + printf("erratic termination during backward enumeration\n"); + exit(-1); + } +} + +int main(int argc, char* argv[]) +{ + nsVoidBTree btree; + + PRInt32 i; + + //---------------------------------------- + // Tail fill + for (i = 0; i < COUNT; ++i) + btree.InsertElementAt(NS_REINTERPRET_CAST(void*, POINTER(i)), i); + + for (i = 0; i < COUNT; ++i) { + if (btree[i] != POINTER(i)) { + printf("tail fill failed\n"); + return -1; + } + } + + printf("tail fill succeeded\n"); + + //---------------------------------------- + // Tail empty + for (i = COUNT - 1; i >= 0; --i) + btree.RemoveElementAt(i); + + if (btree.Count() != 0) { + printf("tail empty failed\n"); + return -1; + } + + printf("tail empty succeeded\n"); + + // N.B. no intervening Clear() to verify that we handle the re-use + // case. + + //---------------------------------------- + // Front fill + for (i = 0; i < COUNT; ++i) + btree.InsertElementAt(POINTER(i), 0); + + for (i = 0; i < COUNT; ++i) { + if (btree[COUNT - (i + 1)] != POINTER(i)) { + printf("simple front fill failed\n"); + return -1; + } + } + + printf("front fill succeeded\n"); + + //---------------------------------------- + // Front empty + for (i = COUNT - 1; i >= 0; --i) + btree.RemoveElementAt(0); + + if (btree.Count() != 0) { + printf("front empty failed\n"); + return -1; + } + + printf("front empty succeeded\n"); + fflush(stdout); + + //---------------------------------------- + // Test boundary conditions with small btree + + { + printf("small btree boundary conditions "); + fflush(stdout); + + nsVoidArray control; + btree.Clear(); + + CheckBackwardEnumeration(control, btree); + CheckForwardEnumeration(control, btree); + + btree.AppendElement(POINTER(0)); + control.AppendElement(POINTER(0)); + + CheckBackwardEnumeration(control, btree); + CheckForwardEnumeration(control, btree); + + btree.AppendElement(POINTER(1)); + control.AppendElement(POINTER(1)); + + CheckBackwardEnumeration(control, btree); + CheckForwardEnumeration(control, btree); + + btree.RemoveElementAt(0); + btree.RemoveElementAt(0); + control.RemoveElementAt(0); + control.RemoveElementAt(0); + + CheckBackwardEnumeration(control, btree); + CheckForwardEnumeration(control, btree); + + printf("succeeded\n"); + } + + //---------------------------------------- + // Iterator + { + nsVoidArray control; + btree.Clear(); + + // Fill + for (i = 0; i < COUNT; ++i) { + PRInt32 slot = i ? rand() % i : 0; + + btree.InsertElementAt(POINTER(i), slot); + control.InsertElementAt(POINTER(i), slot); + + if (! Equal(control, btree)) { + printf("failed\n"); + return -1; + } + } + + for (nsVoidBTree::Iterator m = btree.First(); m != btree.Last(); ++m) { + nsVoidBTree::Iterator n; + for (n = m, ++n; n != btree.Last(); ++n) { + if (*m > *n) { + void* tmp = *m; + *m = *n; + *n = tmp; + } + } + } + + nsVoidBTree::Iterator el; + for (el = btree.First(), i = 0; el != btree.Last(); ++el, ++i) { + if (*el != POINTER(i)) { + printf("bubble sort failed\n"); + return -1; + } + } + + printf("iteration succeeded\n"); + } + + //---------------------------------------- + // Random hammering + + printf("random fill/empty: "); + + for (PRInt32 iter = 10; iter >= 1; --iter) { + printf("%d ", iter); + fflush(stdout); + + nsVoidArray control; + btree.Clear(); + + // Fill + for (i = 0; i < COUNT; ++i) { + PRInt32 slot = i ? rand() % i : 0; + + btree.InsertElementAt(POINTER(i), slot); + control.InsertElementAt(POINTER(i), slot); + + if (! Equal(control, btree)) { + printf("failed\n"); + return -1; + } + } + + // IndexOf + for (i = 0; i < COUNT; ++i) { + void* element = control[i]; + if (btree.IndexOf(element) != i) { + printf("failed IndexOf at %d\n", i); + return -1; + } + } + + // Backward enumeration + CheckBackwardEnumeration(control, btree); + + // Forward enumeration + CheckForwardEnumeration(control, btree); + + // Empty + for (i = COUNT - 1; i >= 0; --i) { + PRInt32 slot = i ? rand() % i : 0; + + btree.RemoveElementAt(slot); + control.RemoveElementAt(slot); + + if (! Equal(control, btree)) { + printf("failed\n"); + return -1; + } + } + } + + printf("succeeded\n"); + + return 0; +} diff --git a/src/libs/xpcom18a4/xpcom/tests/TestXPIDLString.cpp b/src/libs/xpcom18a4/xpcom/tests/TestXPIDLString.cpp new file mode 100644 index 00000000..f2802e1f --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/TestXPIDLString.cpp @@ -0,0 +1,18 @@ +#include "nsString.h" +#include "nsReadableUtils.h" +#include "nsXPIDLString.h" + +static void +nsXPIDLStringTest_Value(PRUnichar** aResult) +{ + *aResult = ToNewUnicode(NS_LITERAL_STRING("Hello, World")); +} + +int +main(int argc, char* argv[]) +{ + nsXPIDLString s1; + nsXPIDLStringTest_Value(getter_Copies(s1)); + return 0; +} + diff --git a/src/libs/xpcom18a4/xpcom/tests/dynamic/.cvsignore b/src/libs/xpcom18a4/xpcom/tests/dynamic/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/dynamic/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/xpcom/tests/dynamic/Makefile.in b/src/libs/xpcom18a4/xpcom/tests/dynamic/Makefile.in new file mode 100644 index 00000000..c17318c0 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/dynamic/Makefile.in @@ -0,0 +1,61 @@ +# +# ***** 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.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of 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 ***** + +DEPTH = ../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +IS_COMPONENT = 1 +MODULE_NAME = nsTestDynamicModule +MODULE = xpcom +LIBRARY_NAME = testdynamic +SHORT_LIBNAME = tdynamic + +CPPSRCS = TestDynamic.cpp + +include $(topsrcdir)/config/config.mk + +LOCAL_INCLUDES = -I$(srcdir)/.. -I$(srcdir)/../../public + +include $(topsrcdir)/config/rules.mk + +EXTRA_DSO_LDOPTS += $(MOZ_COMPONENT_LIBS) + + diff --git a/src/libs/xpcom18a4/xpcom/tests/dynamic/TestDynamic.cpp b/src/libs/xpcom18a4/xpcom/tests/dynamic/TestDynamic.cpp new file mode 100644 index 00000000..a27d8ea9 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/dynamic/TestDynamic.cpp @@ -0,0 +1,76 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Suresh Duddi + * Christopher Blizzard + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 +#include "TestFactory.h" +#include "nsIGenericFactory.h" + +/** + * ITestClass implementation + */ + +class TestDynamicClassImpl: public ITestClass { + NS_DECL_ISUPPORTS + + TestDynamicClassImpl() { + } + void Test(); +}; + +NS_IMPL_ISUPPORTS1(TestDynamicClassImpl, ITestClass) + +void TestDynamicClassImpl::Test() { + printf("hello, dynamic world!\n"); +} + +/** + * Generic Module + */ + +NS_GENERIC_FACTORY_CONSTRUCTOR(TestDynamicClassImpl) + +static const nsModuleComponentInfo components[] = +{ + { "Test Dynamic", NS_TESTLOADEDFACTORY_CID, NS_TESTLOADEDFACTORY_CONTRACTID, + TestDynamicClassImplConstructor + } +}; + +NS_IMPL_NSGETMODULE(nsTestDynamicModule, components) + diff --git a/src/libs/xpcom18a4/xpcom/tests/dynamic/win32.order b/src/libs/xpcom18a4/xpcom/tests/dynamic/win32.order new file mode 100644 index 00000000..bf181a81 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/dynamic/win32.order @@ -0,0 +1 @@ +_NSGetModule ; 1 diff --git a/src/libs/xpcom18a4/xpcom/tests/nsIFileEnumerator.cpp b/src/libs/xpcom18a4/xpcom/tests/nsIFileEnumerator.cpp new file mode 100644 index 00000000..a5f3551d --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/nsIFileEnumerator.cpp @@ -0,0 +1,95 @@ +#include "nsILocalFile.h" +#include "nsDependentString.h" +#include "nsString.h" + +#include +#include "nsIComponentRegistrar.h" +#include "nsIComponentManager.h" +#include "nsIServiceManager.h" +#include "nsMemory.h" +#include "nsXPIDLString.h" +#include "nsISimpleEnumerator.h" + + +PRBool LoopInDir(nsILocalFile* file) +{ + nsresult rv; + nsCOMPtr entries; + rv = file->GetDirectoryEntries(getter_AddRefs(entries)); + if(NS_FAILED(rv) || !entries) + return PR_FALSE; + + PRBool hasMore; + while(NS_SUCCEEDED(entries->HasMoreElements(&hasMore)) && hasMore) + { + nsCOMPtr sup; + entries->GetNext(getter_AddRefs(sup)); + if(!sup) + return PR_FALSE; + + nsCOMPtr file = do_QueryInterface(sup); + if(!file) + return PR_FALSE; + + nsCAutoString name; + if(NS_FAILED(file->GetNativeLeafName(name))) + return PR_FALSE; + + PRBool isDir; + printf("%s\n", name.get()); + rv = file->IsDirectory(&isDir); + if (NS_FAILED(rv)) + { + printf("IsDirectory Failed!!!\n"); + return PR_FALSE; + } + + if (isDir == PR_TRUE) + { + nsCOMPtr lfile = do_QueryInterface(file); + LoopInDir(lfile); + } + } + return PR_TRUE; +} + + +int +main(int argc, char* argv[]) +{ + nsresult rv; + { + nsCOMPtr topDir; + + nsCOMPtr servMan; + rv = NS_InitXPCOM2(getter_AddRefs(servMan), nsnull, nsnull); + if (NS_FAILED(rv)) return -1; + nsCOMPtr registrar = do_QueryInterface(servMan); + NS_ASSERTION(registrar, "Null nsIComponentRegistrar"); + if (registrar) + registrar->AutoRegister(nsnull); + + if (argc > 1 && argv[1] != nsnull) + { + char* pathStr = argv[1]; + NS_NewNativeLocalFile(nsDependentCString(pathStr), PR_FALSE, getter_AddRefs(topDir)); + } + + if (!topDir) + { + printf("No Top Dir\n"); + return -1; + } + PRInt32 startTime = PR_IntervalNow(); + + LoopInDir(topDir); + + PRInt32 endTime = PR_IntervalNow(); + + printf("\nTime: %d\n", PR_IntervalToMilliseconds(endTime - startTime)); + } // 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 0; +} diff --git a/src/libs/xpcom18a4/xpcom/tests/nsIFileTest.cpp b/src/libs/xpcom18a4/xpcom/tests/nsIFileTest.cpp new file mode 100644 index 00000000..1dd2cd54 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/nsIFileTest.cpp @@ -0,0 +1,475 @@ +#include "nsILocalFile.h" +#if 0 /* too new */ +#include "nsStringGlue.h" +#else +#include "nsString.h" +#endif + +#include +#include "nsXPCOM.h" +#include "nsIComponentManager.h" +#include "nsIComponentRegistrar.h" +#include "nsIServiceManager.h" +#include "nsIMemory.h" + +#include "nsComponentManagerUtils.h" +#include "nsCOMPtr.h" + +void Passed(); +void Failed(const char* explanation = nsnull); +void Inspect(); +void Banner(const char* bannerString); + +void VerifyResult(nsresult rv) +{ + if (NS_FAILED(rv)) + { + Failed("rv failed"); + printf("rv = %d\n", rv); + } +} +//---------------------------------------------------------------------------- +void Banner(const char* bannerString) +//---------------------------------------------------------------------------- +{ + printf("---------------------------\n"); + printf("%s\n", bannerString); + printf("---------------------------\n"); +} + +//---------------------------------------------------------------------------- +void Passed() +//---------------------------------------------------------------------------- +{ + printf("Test passed."); +} + +//---------------------------------------------------------------------------- +void Failed(const char* explanation) +//---------------------------------------------------------------------------- +{ + printf("ERROR : Test failed.\n"); + printf("REASON: %s.\n", explanation); +} + +//---------------------------------------------------------------------------- +void Inspect() +//---------------------------------------------------------------------------- +{ + printf("^^^^^^^^^^ PLEASE INSPECT OUTPUT FOR ERRORS\n"); +} + +void GetPaths(nsILocalFile* file) +{ + nsresult rv; + nsCAutoString pathName; + + printf("Getting Path\n"); + + rv = file->GetNativePath(pathName); + VerifyResult(rv); + + printf("filepath: %s\n", pathName.get()); +} + +void InitTest(const char* creationPath, const char* appendPath) +{ + nsILocalFile* file = nsnull; + nsresult rv = CallCreateInstance(NS_LOCAL_FILE_CONTRACTID, &file); + + + if (NS_FAILED(rv) || (!file)) + { + printf("create nsILocalFile failed\n"); + return; + } + + nsCAutoString leafName; + + Banner("InitWithPath"); + printf("creationPath == %s\nappendPath == %s\n", creationPath, appendPath); + + rv = file->InitWithNativePath(nsDependentCString(creationPath)); + VerifyResult(rv); + + printf("Getting Filename\n"); + rv = file->GetNativeLeafName(leafName); + printf(" %s\n", leafName.get()); + VerifyResult(rv); + + printf("Appending %s \n", appendPath); + rv = file->AppendNative(nsDependentCString(appendPath)); + VerifyResult(rv); + + printf("Getting Filename\n"); + rv = file->GetNativeLeafName(leafName); + printf(" %s\n", leafName.get()); + VerifyResult(rv); + + GetPaths(file); + + + printf("Check For Existence\n"); + + PRBool exists; + file->Exists(&exists); + + NS_RELEASE(file); + + if (exists) + printf("Yup!\n"); + else + printf("no.\n"); +} + + +void CreationTest(const char* creationPath, const char* appendPath, + PRInt32 whatToCreate, PRInt32 perm) +{ + nsresult rv; + nsCOMPtr file = + do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv); + + if (NS_FAILED(rv) || (!file)) + { + printf("create nsILocalFile failed\n"); + return; + } + + Banner("Creation Test"); + printf("creationPath == %s\nappendPath == %s\n", creationPath, appendPath); + + rv = file->InitWithNativePath(nsDependentCString(creationPath)); + VerifyResult(rv); + + printf("Appending %s\n", appendPath); + rv = file->AppendRelativeNativePath(nsDependentCString(appendPath)); + VerifyResult(rv); + + printf("Check For Existence\n"); + + PRBool exists; + file->Exists(&exists); + + if (exists) + printf("Yup!\n"); + else + printf("no.\n"); + + + rv = file->Create(whatToCreate, perm); + VerifyResult(rv); + + rv = file->Exists(&exists); + VerifyResult(rv); + + + if (!exists) + { + Failed("Did not create file system object!"); + return; + } + +} + +void CreateUniqueTest(const char* creationPath, const char* appendPath, + PRInt32 whatToCreate, PRInt32 perm) +{ + nsresult rv; + nsCOMPtr file = + do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv); + + if (NS_FAILED(rv) || (!file)) + { + printf("create nsILocalFile failed\n"); + return; + } + + Banner("Creation Test"); + printf("creationPath == %s\nappendPath == %s\n", creationPath, appendPath); + + rv = file->InitWithNativePath(nsDependentCString(creationPath)); + VerifyResult(rv); + + printf("Appending %s\n", appendPath); + rv = file->AppendNative(nsDependentCString(appendPath)); + VerifyResult(rv); + + printf("Check For Existence\n"); + + PRBool exists; + file->Exists(&exists); + + if (exists) + printf("Yup!\n"); + else + printf("no.\n"); + + + rv = file->CreateUnique(whatToCreate, perm); + VerifyResult(rv); + + rv = file->Exists(&exists); + VerifyResult(rv); + + + if (!exists) + { + Failed("Did not create file system object!"); + return; + } + +} + + +void +CopyTest(const char *testFile, const char *targetDir) +{ + printf("start copy test\n"); + + nsresult rv; + nsCOMPtr file = + do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv); + + if (NS_FAILED(rv) || (!file)) + { + printf("create nsILocalFile failed\n"); + return; + } + + rv = file->InitWithNativePath(nsDependentCString(testFile)); + VerifyResult(rv); + + nsCOMPtr dir = + do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv); + + if (NS_FAILED(rv) || (!dir)) + { + printf("create nsILocalFile failed\n"); + return; + } + + rv = dir->InitWithNativePath(nsDependentCString(targetDir)); + VerifyResult(rv); + + rv = file->CopyTo(dir, EmptyString()); + VerifyResult(rv); + + printf("end copy test\n"); +} + +void +DeletionTest(const char* creationPath, const char* appendPath, PRBool recursive) +{ + nsresult rv; + nsCOMPtr file = + do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv); + + if (NS_FAILED(rv) || (!file)) + { + printf("create nsILocalFile failed\n"); + return; + } + + Banner("Deletion Test"); + printf("creationPath == %s\nappendPath == %s\n", creationPath, appendPath); + + rv = file->InitWithNativePath(nsDependentCString(creationPath)); + VerifyResult(rv); + + printf("Appending %s\n", appendPath); + rv = file->AppendNative(nsDependentCString(appendPath)); + VerifyResult(rv); + + printf("Check For Existance\n"); + + PRBool exists; + file->Exists(&exists); + + if (exists) + printf("Yup!\n"); + else + printf("no.\n"); + + rv = file->Remove(recursive); + VerifyResult(rv); + + rv = file->Exists(&exists); + VerifyResult(rv); + + if (exists) + { + Failed("Did not create delete system object!"); + return; + } + +} + +void +MoveTest(const char *testFile, const char *targetDir) +{ + Banner("Move Test"); + + printf("start move test\n"); + + nsresult rv; + nsCOMPtr file(do_CreateInstance(NS_LOCAL_FILE_CONTRACTID)); + + if (!file) + { + printf("create nsILocalFile failed\n"); + return; + } + + rv = file->InitWithNativePath(nsDependentCString(testFile)); + VerifyResult(rv); + + nsCOMPtr dir(do_CreateInstance(NS_LOCAL_FILE_CONTRACTID)); + + if (!dir) + { + printf("create nsILocalFile failed\n"); + return; + } + + rv = dir->InitWithNativePath(nsDependentCString(targetDir)); + VerifyResult(rv); + + rv = file->MoveToNative(dir, NS_LITERAL_CSTRING("newtemp")); + VerifyResult(rv); + if (NS_FAILED(rv)) + { + printf("MoveToNative() test Failed.\n"); + } + printf("end move test\n"); +} + +// move up the number of directories in moveUpCount, then append "foo/bar" +void +NormalizeTest(const char *testPath, int moveUpCount, + const char *expected) +{ + Banner("Normalize Test"); + + nsresult rv; + nsCOMPtr file(do_CreateInstance(NS_LOCAL_FILE_CONTRACTID)); + + if (!file) + { + printf("create nsILocalFile failed\n"); + return; + } + + rv = file->InitWithNativePath(nsDependentCString(testPath)); + VerifyResult(rv); + + nsCOMPtr parent; + nsAutoString path; + for (int i=0; i < moveUpCount; i++) + { + rv = file->GetParent(getter_AddRefs(parent)); + VerifyResult(rv); + rv = parent->GetPath(path); + VerifyResult(rv); + rv = file->InitWithPath(path); + VerifyResult(rv); + } + + if (!parent) { + printf("Getting parent failed!\n"); + return; + } + + rv = parent->Append(NS_LITERAL_STRING("foo")); + VerifyResult(rv); + rv = parent->Append(NS_LITERAL_STRING("bar")); + VerifyResult(rv); + + rv = parent->Normalize(); + VerifyResult(rv); + + nsCAutoString newPath; + rv = parent->GetNativePath(newPath); + VerifyResult(rv); + + nsCOMPtr + expectedFile(do_CreateInstance(NS_LOCAL_FILE_CONTRACTID)); + + if (!expectedFile) + { + printf("create nsILocalFile failed\n"); + return; + } + rv = expectedFile->InitWithNativePath(nsDependentCString(expected)); + VerifyResult(rv); + + rv = expectedFile->Normalize(); + VerifyResult(rv); + + nsCAutoString expectedPath; + rv = expectedFile->GetNativePath(expectedPath); + VerifyResult(rv); + + if (!newPath.Equals(expectedPath)) { + printf("ERROR: Normalize() test Failed!\n"); + printf(" Got: %s\n", newPath.get()); + printf("Expected: %s\n", expectedPath.get()); + } + + printf("end normalize test.\n"); +} + +int main(void) +{ + nsCOMPtr servMan; + NS_InitXPCOM2(getter_AddRefs(servMan), nsnull, nsnull); + nsCOMPtr registrar = do_QueryInterface(servMan); + NS_ASSERTION(registrar, "Null nsIComponentRegistrar"); + registrar->AutoRegister(nsnull); + +#if defined(XP_WIN) || defined(XP_OS2) + InitTest("c:\\temp\\", "sub1/sub2/"); // expect failure + InitTest("d:\\temp\\", "sub1\\sub2\\"); // expect failure + + CreationTest("c:\\temp\\", "file.txt", nsIFile::NORMAL_FILE_TYPE, 0644); + DeletionTest("c:\\temp\\", "file.txt", PR_FALSE); + + MoveTest("c:\\newtemp\\", "d:"); + + CreationTest("c:\\temp\\", "mumble\\a\\b\\c\\d\\e\\f\\g\\h\\i\\j\\k\\", nsIFile::DIRECTORY_TYPE, 0644); + DeletionTest("c:\\temp\\", "mumble", PR_TRUE); + + CreateUniqueTest("c:\\temp\\", "foo", nsIFile::NORMAL_FILE_TYPE, 0644); + CreateUniqueTest("c:\\temp\\", "foo", nsIFile::NORMAL_FILE_TYPE, 0644); + CreateUniqueTest("c:\\temp\\", "bar.xx", nsIFile::DIRECTORY_TYPE, 0644); + CreateUniqueTest("c:\\temp\\", "bar.xx", nsIFile::DIRECTORY_TYPE, 0644); + DeletionTest("c:\\temp\\", "foo", PR_TRUE); + DeletionTest("c:\\temp\\", "foo-1", PR_TRUE); + DeletionTest("c:\\temp\\", "bar.xx", PR_TRUE); + DeletionTest("c:\\temp\\", "bar-1.xx", PR_TRUE); + +#else +#ifdef XP_UNIX + InitTest("/tmp/", "sub1/sub2/"); // expect failure + + CreationTest("/tmp", "file.txt", nsIFile::NORMAL_FILE_TYPE, 0644); + DeletionTest("/tmp/", "file.txt", PR_FALSE); + + CreationTest("/tmp", "mumble/a/b/c/d/e/f/g/h/i/j/k/", nsIFile::DIRECTORY_TYPE, 0644); + DeletionTest("/tmp", "mumble", PR_TRUE); + + CreationTest("/tmp", "file", nsIFile::NORMAL_FILE_TYPE, 0644); + CopyTest("/tmp/file", "/tmp/newDir"); + MoveTest("/tmp/file", "/tmp/newDir/anotherNewDir"); + DeletionTest("/tmp", "newDir", PR_TRUE); + + CreationTest("/tmp", "qux/quux", nsIFile::NORMAL_FILE_TYPE, 0644); + CreationTest("/tmp", "foo/bar", nsIFile::NORMAL_FILE_TYPE, 0644); + NormalizeTest("/tmp/qux/quux/..", 1, "/tmp/foo/bar"); + DeletionTest("/tmp", "qux", PR_TRUE); + DeletionTest("/tmp", "foo", PR_TRUE); + +#endif /* XP_UNIX */ +#endif /* XP_WIN || XP_OS2 */ + return 0; +} diff --git a/src/libs/xpcom18a4/xpcom/tests/resources.h b/src/libs/xpcom18a4/xpcom/tests/resources.h new file mode 100644 index 00000000..b82df25e --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/resources.h @@ -0,0 +1,52 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Chris Waterson + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ +#ifndef resources_h___ +#define resources_h___ + +#define TIMER_1SECOND 40000 +#define TIMER_5SECOND 40001 +#define TIMER_10SECOND 40002 + +#define TIMER_1REPEAT 40003 +#define TIMER_5REPEAT 40004 +#define TIMER_10REPEAT 40005 + +#define TIMER_CANCEL 40006 +#define TIMER_EXIT 40010 + +#endif /* resources_h___ */ diff --git a/src/libs/xpcom18a4/xpcom/tests/services/.cvsignore b/src/libs/xpcom18a4/xpcom/tests/services/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/services/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/xpcom/tests/services/Makefile.in b/src/libs/xpcom18a4/xpcom/tests/services/Makefile.in new file mode 100644 index 00000000..84cd3c84 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/services/Makefile.in @@ -0,0 +1,58 @@ +# +# ***** 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.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of 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 ***** + +DEPTH = ../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = xpcom +IS_COMPONENT = 1 +MODULE_NAME = MyService +LIBRARY_NAME = MyService +SHORT_LIBNAME = MyServce + +CPPSRCS = MyService.cpp + +LOCAL_INCLUDES = -I$(srcdir)/.. + +EXTRA_DSO_LDOPTS += $(MOZ_COMPONENT_LIBS) + +include $(topsrcdir)/config/rules.mk + diff --git a/src/libs/xpcom18a4/xpcom/tests/services/MyService.cpp b/src/libs/xpcom18a4/xpcom/tests/services/MyService.cpp new file mode 100644 index 00000000..aec78449 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/services/MyService.cpp @@ -0,0 +1,93 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Pierre Phaneuf + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "MyService.h" +#include "nsIServiceManager.h" +#include "nsIGenericFactory.h" +#include + +//////////////////////////////////////////////////////////////////////////////// + +class MyService : public IMyService { +public: + + NS_IMETHOD + Doit(void); + + MyService(); + NS_DECL_ISUPPORTS + +private: + ~MyService(); +}; + +//////////////////////////////////////////////////////////////////////////////// +// MyService Implementation + +NS_IMPL_ISUPPORTS1(MyService, IMyService) + +MyService::MyService() +{ + printf(" creating my service\n"); +} + +MyService::~MyService() +{ + printf(" destroying my service\n"); +} + +nsresult +MyService::Doit(void) +{ + printf(" invoking my service\n"); + return NS_OK; +} + +//////////////////////////////////////////////////////////////////////////////// +// MyServiceFactory Implementation + +NS_GENERIC_FACTORY_CONSTRUCTOR(MyService) + +static const nsModuleComponentInfo myService_components[] = { + { "MyService", NS_IMYSERVICE_CID, nsnull, MyServiceConstructor }, +}; + +NS_IMPL_NSGETMODULE(MyService, myService_components) + + + diff --git a/src/libs/xpcom18a4/xpcom/tests/services/MyService.h b/src/libs/xpcom18a4/xpcom/tests/services/MyService.h new file mode 100644 index 00000000..30b0e30a --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/services/MyService.h @@ -0,0 +1,69 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Pierre Phaneuf + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +#ifndef MyService_h__ +#define MyService_h__ + +#include "nsISupports.h" + +#define NS_IMYSERVICE_IID \ +{ /* fedc3380-3648-11d2-8163-006008119d7a */ \ + 0xfedc3380, \ + 0x3648, \ + 0x11d2, \ + {0x81, 0x63, 0x00, 0x60, 0x08, 0x11, 0x9d, 0x7a} \ +} + +class IMyService : public nsISupports { +public: + NS_DEFINE_STATIC_IID_ACCESSOR(NS_IMYSERVICE_IID) + + NS_IMETHOD + Doit(void) = 0; + +}; + +#define NS_IMYSERVICE_CID \ +{ /* 34876550-364b-11d2-8163-006008119d7a */ \ + 0x34876550, \ + 0x364b, \ + 0x11d2, \ + {0x81, 0x63, 0x00, 0x60, 0x08, 0x11, 0x9d, 0x7a} \ +} + +#endif // MyService_h__ diff --git a/src/libs/xpcom18a4/xpcom/tests/services/win32.order b/src/libs/xpcom18a4/xpcom/tests/services/win32.order new file mode 100644 index 00000000..132a4357 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/services/win32.order @@ -0,0 +1 @@ +_NSCanUnload ; 1 diff --git a/src/libs/xpcom18a4/xpcom/tests/test.properties b/src/libs/xpcom18a4/xpcom/tests/test.properties new file mode 100644 index 00000000..4ed37783 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/test.properties @@ -0,0 +1,46 @@ +# ***** 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.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of 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 ***** +1=1 + 2=2 +3 =3 + 4 =4 +5=5 +6= 6 +7=7 +8= 8 +# this is a comment +9=this is the first part of a continued line \ + and here is the 2nd part diff --git a/src/libs/xpcom18a4/xpcom/tests/utils/WhatError.cpp b/src/libs/xpcom18a4/xpcom/tests/utils/WhatError.cpp new file mode 100644 index 00000000..13942f3b --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/utils/WhatError.cpp @@ -0,0 +1,61 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsError.h" +#include +#include + +int +main(int argc, char **argv) +{ + int errorCode = 0; + char buffer[100]; + + if (argc != 2) + return -1; + + sscanf( argv[1], "0x%x", &errorCode); + sprintf(buffer, "%d", errorCode); + sscanf( buffer, "%d", &errorCode); + + printf( "Code: %d, Module: %d, Severity: %d\n", + NS_ERROR_GET_CODE(errorCode), + NS_ERROR_GET_MODULE(errorCode), + NS_ERROR_GET_SEVERITY(errorCode)); + + return 0; +} diff --git a/src/libs/xpcom18a4/xpcom/tests/utils/cp.js b/src/libs/xpcom18a4/xpcom/tests/utils/cp.js new file mode 100644 index 00000000..a38c120b --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/utils/cp.js @@ -0,0 +1,111 @@ +const nsILocalFile = Components.interfaces.nsILocalFile; +var prefix = ""; + +function rename(source, newName) +{ + try { + var sourceFile = Components.classes["@mozilla.org/file/local;1"]. + createInstance(nsILocalFile); + sourceFile.initWithPath(source); + + } + catch (e) { + dump("Could not create nsILocalFile\n"); + } + + + try { + sourceFile.copyTo(null, newName); + } + catch (e) { + dump("error coping" + e + "\n"); + } +} + + +function cp(source, dest, followLinks, newName) +{ + try { + var sourceFile = Components.classes["@mozilla.org/file/local;1"]. + createInstance(nsILocalFile); + sourceFile.initWithPath(source); + + var destFile = Components.classes["@mozilla.org/file/local;1"]. + createInstance(nsILocalFile); + destFile.initWithPath(dest); + + } + catch (e) { + dump("Could not create nsILocalFile\n"); + } + + try { + + if (! destFile.isDirectory()) + { + dump("destination not a directory!\n"); + return; + } + } + catch (e) { + dump("error accessing dest"); + } + + try { + if (followLinks) + { + sourceFile.copyToFollowingLinks(destFile, newName); + } + else + { + sourceFile.copyTo(destFile, newName); + } + } + catch (e) { + dump("error coping" + e + "\n"); + } +} + + +function mv(source, dest, followLinks, newName) +{ + try { + var sourceFile = Components.classes["@mozilla.org/file/local;1"]. + createInstance(nsILocalFile); + sourceFile.initWithPath(source); + + var destFile = Components.classes["@mozilla.org/file/local;1"]. + createInstance(nsILocalFile); + destFile.initWithPath(dest); + + } + catch (e) { + dump("Could not create nsILocalFile\n"); + } + + try { + + if (! destFile.isDirectory()) + { + dump("destination not a directory!\n"); + return; + } + } + catch (e) { + dump("error accessing dest"); + } + + try { + if (followLinks) + { + sourceFile.moveToFollowingLinks(destFile, newName); + } + else + { + sourceFile.moveTo(destFile, newName); + } + } + catch (e) { + dump("error coping" + e + "\n"); + } +} diff --git a/src/libs/xpcom18a4/xpcom/tests/utils/dirs.js b/src/libs/xpcom18a4/xpcom/tests/utils/dirs.js new file mode 100644 index 00000000..c3fc2479 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/utils/dirs.js @@ -0,0 +1,155 @@ +function dumpPathOfProperty(prop) +{ + dump(prop +' = '); + + try + { + var file = dsprops.get(prop, Components.interfaces.nsIFile); + dump(file.path + '\n'); + } + catch (ar) + { + dump('undefined or error \n'); + } +} + +var dscontractid = "@mozilla.org/file/directory_service;1"; // XXX old-style +var ds = Components.classes[dscontractid].getService(); +var dsprops = ds.QueryInterface(Components.interfaces.nsIProperties); + +dump("xpcom locations::\n"); +// XPCOM Locations: + dumpPathOfProperty ("xpcom.currentProcess"); + dumpPathOfProperty ("xpcom.currentProcess.componentRegistry"); + dumpPathOfProperty ("xpcom.currentProcess.componentDirectory"); + dumpPathOfProperty ("system.OS_DriveDirectory"); + dumpPathOfProperty ("system.OS_TemporaryDirectory"); + dumpPathOfProperty ("system.OS_CurrentProcessDirectory"); + dumpPathOfProperty ("system.OS_CurrentWorkingDirectory"); + +dump("Mac locations::\n"); +// Mac + dumpPathOfProperty ("system.SystemDirectory"); + dumpPathOfProperty ("system.DesktopDirectory"); + dumpPathOfProperty ("system.TrashDirectory"); + dumpPathOfProperty ("system.StartupDirectory"); + dumpPathOfProperty ("system.ShutdownDirectory"); + dumpPathOfProperty ("system.AppleMenuDirectory"); + dumpPathOfProperty ("system.ControlPanelDirectory"); + dumpPathOfProperty ("system.ExtensionDirectory"); + dumpPathOfProperty ("system.FontsDirectory"); + dumpPathOfProperty ("system.PreferencesDirectory"); + dumpPathOfProperty ("system.DocumentsDirectory"); + dumpPathOfProperty ("system.InternetSearchDirectory"); + +dump("PC locations::\n"); +// PC + dumpPathOfProperty ("system.SystemDirectory"); + dumpPathOfProperty ("system.WindowsDirectory"); + dumpPathOfProperty ("system.HomeDirectory"); + dumpPathOfProperty ("system.Desktop"); + dumpPathOfProperty ("system.Programs"); + dumpPathOfProperty ("system.Controls"); + dumpPathOfProperty ("system.Printers"); + dumpPathOfProperty ("system.Personal"); + dumpPathOfProperty ("system.Favorites"); + dumpPathOfProperty ("system.Startup"); + dumpPathOfProperty ("system.Recent"); + dumpPathOfProperty ("system.Sendto"); + dumpPathOfProperty ("system.Bitbucket"); + dumpPathOfProperty ("system.Startmenu"); + dumpPathOfProperty ("system.Desktopdirectory"); + dumpPathOfProperty ("system.Drives"); + dumpPathOfProperty ("system.Network"); + dumpPathOfProperty ("system.Nethood"); + dumpPathOfProperty ("system.Fonts"); + dumpPathOfProperty ("system.Templates"); + dumpPathOfProperty ("system.Common_Startmenu"); + dumpPathOfProperty ("system.Common_Programs"); + dumpPathOfProperty ("system.Common_Startup"); + dumpPathOfProperty ("system.Common_Desktopdirectory"); + dumpPathOfProperty ("system.Appdata"); + dumpPathOfProperty ("system.Printhood"); + +dump("Unix locations::\n"); +// Unix + + dumpPathOfProperty ("system.LocalDirectory"); + dumpPathOfProperty ("system.LibDirectory"); + dumpPathOfProperty ("system.HomeDirectory"); + +dump("Beos locations::\n"); +// Beos + + dumpPathOfProperty ("system.SettingsDirectory"); + dumpPathOfProperty ("system.HomeDirectory"); + dumpPathOfProperty ("system.DesktopDirectory"); + dumpPathOfProperty ("system.SystemDirectory"); + +dump("OS2 locations::\n"); +// OS2 + dumpPathOfProperty ("system.SystemDirectory"); + dumpPathOfProperty ("system.OS2Directory"); + dumpPathOfProperty ("system.DesktopDirectory"); + + +// XPFE locations: + + +// application Directories: + dumpPathOfProperty ("app.res.directory"); + dumpPathOfProperty ("app.defaults.directory"); + dumpPathOfProperty ("app.chrome.directory"); + dumpPathOfProperty ("app.chrome.user.directory"); + dumpPathOfProperty ("app.plugins.directory"); + +// application Files: + + dumpPathOfProperty ("app.registry.file.4"); + dumpPathOfProperty ("app.registry.file.5"); + dumpPathOfProperty ("app.local.store.file.5"); + dumpPathOfProperty ("app.history.file.5"); + dumpPathOfProperty ("app.user.panels.5"); + +// Preferences: + +// dumpPathOfProperty ("app.prefs.directory.3"); +// dumpPathOfProperty ("app.prefs.directory.4"); + dumpPathOfProperty ("app.prefs.directory.5"); + dumpPathOfProperty ("app.pref.default.directory.5"); + +// dumpPathOfProperty ("app.prefs.file.3"); +// dumpPathOfProperty ("app.prefs.file.4"); + dumpPathOfProperty ("app.prefs.file.5"); + +// Profile: + +// dumpPathOfProperty ("app.profile.user.directory.3"); +// dumpPathOfProperty ("app.profile.user.directory.4"); + dumpPathOfProperty ("app.profile.user.directory.5"); +// dumpPathOfProperty ("app.profile.default.user.directory.3"); +// dumpPathOfProperty ("app.profile.default.user.directory.4"); + dumpPathOfProperty ("app.profile.default.user.directory.5"); +// dumpPathOfProperty ("app.profile.defaults.directory.3"); +// dumpPathOfProperty ("app.profile.defaults.directory.4"); + dumpPathOfProperty ("app.profile.defaults.directory.5"); + + + +// Bookmarks: + +// dumpPathOfProperty ("app.bookmark.file.3"); +// dumpPathOfProperty ("app.bookmark.file.4"); + dumpPathOfProperty ("app.bookmark.file.5"); + +// Search + dumpPathOfProperty ("app.search.file.5"); + dumpPathOfProperty ("app.search.directory.5"); + + +// MailNews: + + dumpPathOfProperty ("app.mail.directory.5"); + dumpPathOfProperty ("app.mail.imap.directory.5"); + dumpPathOfProperty ("app.mail.news.directory.5"); + dumpPathOfProperty ("app.mail.messenger.cache.directory.5"); diff --git a/src/libs/xpcom18a4/xpcom/tests/utils/ls.js b/src/libs/xpcom18a4/xpcom/tests/utils/ls.js new file mode 100644 index 00000000..8ae62f06 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/utils/ls.js @@ -0,0 +1,64 @@ +const nsILocalFile = Components.interfaces.nsILocalFile; +var prefix = ""; + +function ls(path, recur) +{ + var file = Components.classes["@mozilla.org/file/local;1"]. + createInstance(nsILocalFile); + try { + file.initWithPath( path ); + + if (file.isDirectory() && arguments.length == 1) + ls_dir(file, recur); + else + ls_file(file, recur); + } + catch (e) { + dump("Error Returned " + e + "\n"); + } +} +function ls_file(file, recur) +{ + dump(prefix); + + try { + if (file.isDirectory()) { + dump("directory " + file.leafName + "\n"); + if(recur) + ls_dir(file, true); + return; + } + + dump(file.leafName + " " + file.fileSize); + if (file.isSymlink()) + dump(" -> " + file.target); + dump("\n"); + } + + catch (e) { + dump(file.leafName + " (error accessing)\n"); + } +} + +function ls_dir(file, recur) +{ + var leafName = file.leafName; + + var old = prefix; + prefix = prefix + " "; + + iter = file.directoryEntries; + dump(iter + "\n"); + + foreach_iter(iter, + function (file) { ls_file(file, recur); }); + prefix = old; +} + +function foreach_iter(iter, fun) +{ + while (iter.hasMoreElements()) { + var item = iter.getNext().QueryInterface(nsILocalFile); + fun(item); + } +} diff --git a/src/libs/xpcom18a4/xpcom/tests/windows/.cvsignore b/src/libs/xpcom18a4/xpcom/tests/windows/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/windows/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/xpcom/tests/windows/Makefile.in b/src/libs/xpcom18a4/xpcom/tests/windows/Makefile.in new file mode 100644 index 00000000..8bd782c8 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/windows/Makefile.in @@ -0,0 +1,60 @@ +# +# ***** 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.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 2001 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of 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 ***** + +DEPTH = ../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = xpcom + +REQUIRES = string + +CPPSRCS = TestCOM.cpp +#TestHelloXPLoop.cpp nsStringTest.cpp + +SIMPLE_PROGRAMS = $(CPPSRCS:.cpp=$(BIN_SUFFIX)) + +include $(topsrcdir)/config/config.mk + +include $(topsrcdir)/config/rules.mk + +OS_LIBS = $(call EXPAND_LIBNAME,rpcrt4 uuid) + +LIBS = $(XPCOM_LIBS) $(NSPR_LIBS) diff --git a/src/libs/xpcom18a4/xpcom/tests/windows/TestCOM.cpp b/src/libs/xpcom18a4/xpcom/tests/windows/TestCOM.cpp new file mode 100644 index 00000000..b76eccb4 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/windows/TestCOM.cpp @@ -0,0 +1,181 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Pierre Phaneuf + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 +#include +#include +#include "nsISupports.h" +#include "nsIFactory.h" + +// unknwn.h is needed to build with WIN32_LEAN_AND_MEAN +#include + +// {5846BA30-B856-11d1-A98A-00805F8A7AC4} +#define NS_ITEST_COM_IID \ +{ 0x5846ba30, 0xb856, 0x11d1, \ + { 0xa9, 0x8a, 0x0, 0x80, 0x5f, 0x8a, 0x7a, 0xc4 } } + +class nsITestCom: public nsISupports +{ +public: + NS_DEFINE_STATIC_IID_ACCESSOR(NS_ITEST_COM_IID) + NS_IMETHOD Test() = 0; +}; + +/* + * nsTestCom + */ + +class nsTestCom: public nsITestCom { + NS_DECL_ISUPPORTS + +public: + nsTestCom() { + } + + NS_IMETHOD Test() { + printf("Accessed nsITestCom::Test() from COM\n"); + return NS_OK; + } + +private: + ~nsTestCom() { + printf("nsTestCom instance successfully deleted\n"); + } +}; + +NS_IMPL_QUERY_INTERFACE1(nsTestCom, nsITestCom) + +nsrefcnt nsTestCom::AddRef() +{ + nsrefcnt res = ++mRefCnt; + NS_LOG_ADDREF(this, mRefCnt, "nsTestCom", sizeof(*this)); + printf("nsTestCom: Adding ref = %d\n", res); + return res; +} + +nsrefcnt nsTestCom::Release() +{ + nsrefcnt res = --mRefCnt; + NS_LOG_RELEASE(this, mRefCnt, "nsTestCom"); + printf("nsTestCom: Releasing = %d\n", res); + if (res == 0) { + delete this; + } + return res; +} + +class nsTestComFactory: public nsIFactory { + NS_DECL_ISUPPORTS +public: + nsTestComFactory() { + } + + NS_IMETHOD CreateInstance(nsISupports *aOuter, + const nsIID &aIID, + void **aResult); + + NS_IMETHOD LockFactory(PRBool aLock) { + printf("nsTestComFactory: "); + printf("%s", (aLock == PR_TRUE ? "Locking server" : "Unlocking server")); + printf("\n"); + return S_OK; + } +}; + +NS_IMPL_ISUPPORTS1(nsTestComFactory, nsIFactory) + +nsresult nsTestComFactory::CreateInstance(nsISupports *aOuter, + const nsIID &aIID, + void **aResult) +{ + if (aOuter != NULL) { + return NS_ERROR_NO_AGGREGATION; + } + + nsTestCom *t = new nsTestCom(); + + if (t == NULL) { + return NS_ERROR_OUT_OF_MEMORY; + } + + NS_ADDREF(t); + nsresult res = t->QueryInterface(aIID, aResult); + NS_RELEASE(t); + + if (NS_SUCCEEDED(res)) { + printf("nsTestComFactory: successfully created nsTestCom instance\n"); + } + + return res; +} + +/* + * main + */ + +int main(int argc, char *argv[]) +{ + nsTestComFactory *inst = new nsTestComFactory(); + IClassFactory *iFactory; + inst->QueryInterface(NS_GET_IID(nsIFactory), (void **) &iFactory); + + IUnknown *iUnknown; + nsITestCom *iTestCom; + + nsresult res; + iFactory->LockServer(TRUE); + res = iFactory->CreateInstance(NULL, + IID_IUnknown, + (void **) &iUnknown); + iFactory->LockServer(FALSE); + + GUID testGUID = NS_ITEST_COM_IID; + HRESULT hres; + hres= iUnknown->QueryInterface(testGUID, + (void **) &iTestCom); + + iTestCom->Test(); + + iUnknown->Release(); + iTestCom->Release(); + iFactory->Release(); + + return 0; +} + diff --git a/src/libs/xpcom18a4/xpcom/tests/windows/TestHelloXPLoop.cpp b/src/libs/xpcom18a4/xpcom/tests/windows/TestHelloXPLoop.cpp new file mode 100644 index 00000000..fdfa1218 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/windows/TestHelloXPLoop.cpp @@ -0,0 +1,177 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * ***** 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 the Mozilla browser. + * + * The Initial Developer of the Original Code is + * Netscape Communications, Inc. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Travis Bogard + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsIServiceManager.h" +#include "nsCOMPtr.h" +#include "nsCNativeApp.h" +#include "nsIEventLoop.h" +#include + +static NS_DEFINE_CID(kNativeAppCID, NS_NATIVE_APP_CID); + +LRESULT CALLBACK WndProc(HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam); + +void ErrorBox(LPSTR text) +{ + MessageBox(NULL, text, "XP Event Loop", MB_OK | MB_ICONSTOP); +} + +void InfoBox(LPSTR text) +{ + MessageBox(NULL, text, "XP Event Loop", MB_OK | MB_ICONINFORMATION); +} + +int WINAPI WinMain(HINSTANCE inst, + HINSTANCE prevInstance, + LPSTR lpszCmdLine, + int nShowCmd) +{ + char* lpszAppName = "HelloWorld"; + HWND wnd; + WNDCLASSEX wndclass; + int retCode; + + { // Needed to scope all nsCOMPtr within XPCOM Init and Shutdown + nsresult rv; + nsCOMPtr servMan; + rv = NS_InitXPCOM2(getter_AddRefs(servMan), nsnull, nsnull); + if(NS_FAILED(rv)) + { + ErrorBox("Failed to initalize xpcom."); + return -1; + } + + nsCOMPtr registrar = do_QueryInterface(servMan); + NS_ASSERTION(registrar, "Null nsIComponentRegistrar"); + registrar->AutoRegister(nsnull); + + nsCOMPtr nativeAppService(do_GetService(kNativeAppCID, &rv)); + + if(NS_FAILED(rv)) + { + ErrorBox("Failed to get nativeAppService"); + return -1; + } + wndclass.cbSize = sizeof(wndclass); + wndclass.style = CS_HREDRAW | CS_VREDRAW; + wndclass.lpfnWndProc = WndProc; + wndclass.cbClsExtra = 0; + wndclass.cbWndExtra = 0; + wndclass.hInstance = inst; + wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION); + wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); + wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); + wndclass.lpszMenuName = NULL; + wndclass.lpszClassName = lpszAppName; + wndclass.hIconSm = LoadIcon(NULL, IDI_APPLICATION); + + RegisterClassEx(&wndclass) ; + + wnd = CreateWindow(lpszAppName, "The Hello World", + WS_OVERLAPPEDWINDOW, + CW_USEDEFAULT, CW_USEDEFAULT, + CW_USEDEFAULT, CW_USEDEFAULT, + NULL, NULL, inst, NULL); + + ShowWindow(wnd, nShowCmd); + UpdateWindow(wnd); + + nsCOMPtr eventLoop; + + if(NS_FAILED(nativeAppService->CreateEventLoop(L"_MainLoop", + nsEventLoopTypes::MainAppLoop, getter_AddRefs(eventLoop)))) + { + ErrorBox("Failed to create event Loop"); + return 0; + } + + eventLoop->Run(nsnull, nsnull, nsnull, &retCode); + eventLoop = nsnull; // Clear out before Shutting down XPCOM + + InfoBox("Hello World app is out of loop"); + } + NS_ShutdownXPCOM(nsnull); + InfoBox("Hello World app is exiting"); + return retCode; +} + +LRESULT CALLBACK WndProc(HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + HDC hdc; + PAINTSTRUCT ps; + RECT rect; + + switch(msg) + { + case WM_PAINT: + hdc = BeginPaint(wnd, &ps); + + GetClientRect(wnd, &rect); + + DrawText(hdc, "Hello, XP Event Loop!", -1, &rect, + DT_SINGLELINE | DT_CENTER | DT_VCENTER); + + EndPaint(wnd, &ps); + return 0; + + case WM_DESTROY: + { + nsresult rv; + nsCOMPtr nativeAppService = + do_GetService(kNativeAppCID, &rv); + if(NS_FAILED(rv)) + { + ErrorBox("Could not get NativeAppService"); + return 0; + } + nsCOMPtr eventLoop; + + if(NS_FAILED(nativeAppService->FindEventLoop(L"_MainLoop", + getter_AddRefs(eventLoop)))) + { + ErrorBox("Failed to find event Loop"); + return 0; + } + eventLoop->Exit(0); + } + return 0; + } + + return DefWindowProc(wnd, msg, wParam, lParam); +} diff --git a/src/libs/xpcom18a4/xpcom/tests/windows/nsStringTest.cpp b/src/libs/xpcom18a4/xpcom/tests/windows/nsStringTest.cpp new file mode 100644 index 00000000..6719ed38 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/windows/nsStringTest.cpp @@ -0,0 +1,33 @@ + +#include +#include "nsStr.h" +#include "nsStringTest2.h" +#include "nsString.h" +#include "nsReadableUtils.h" + +int main(){ + + nsString temp("\t\t\n\r\n\r25,* \t \n\n \t"); + temp.CompressWhitespace(); + + nsString temp1("\t\t\n\r\n\r25,* \t \n\n \t"); + temp1.CompressSet("\t\n\r ",' ',false,false); + + nsString temp3(""); + char* s = ToNewCString(temp3); + delete s; + + char* f = ToNewCString(nsAutoString("")); + char* f1 = ToNewCString(nsCAutoString("")); + delete f; + delete f1; + + + CStringTester gStringTester; + + gStringTester.TestI18nString(); + + return 0; +} + + diff --git a/src/libs/xpcom18a4/xpcom/tests/windows/nsStringTest.h b/src/libs/xpcom18a4/xpcom/tests/windows/nsStringTest.h new file mode 100644 index 00000000..8244a5a1 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/windows/nsStringTest.h @@ -0,0 +1,2277 @@ +/******************************************************************************************** + * + * MODULES NOTES: + * + * This file is designed to help test the new nsString classes. + * + * Contributor(s): + * Rick Gessner + * + * History: + * + * 02.29.2000: Original files (rickg) + * 03.02.2000: Flesh out the interface to be compatible with old library (rickg) + * + ********************************************************************************************/ + +#ifndef _STRINGTEST +#define _STRINGTEST + + +#include "nsString.h" +#include "nsReadableUtils.h" +#include + +#define USE_STL + +#ifdef USE_STL +#include +using namespace std; +#endif + +#define USE_WIDE 1 +#ifdef USE_WIDE + #define stringtype nsString + #define astringtype nsAutoString + #define chartype PRUnichar +#else + #define stringtype nsCString + #define astringtype nsCAutoString + #define chartype char +#endif + + +#include + + + +static const char* kConstructorError = "constructor error"; +static const char* kComparisonError = "Comparision error!"; +static const char* kEqualsError = "Equals error!"; + +static char* kNumbers[]={"0123456789","0\01\02\03\04\05\06\07\08\09\0\0\0"}; +static char* kLetters[]={"abcdefghij","a\0b\0c\0d\0e\0f\0g\0h\0i\0j\0\0\0"}; +static char* kAAA[]={"AAA","A\0A\0A\0\0\0"}; +static char* kBBB[]={"BBB","B\0B\0B\0\0\0"}; +static char* kHello[]={"hello","h\0e\0l\0l\0o\0\0\0"}; +static char* kWSHello[]={" hello "," \0 \0h\0e\0l\0l\0o\0 \0 \0\0\0"}; + + + +/******************************************************** + + This class's only purpose in life is to test the + netscape string library. We exercise the string + API's here, and do a bit of performance testing + against the standard c++ library string (from STL). + + ********************************************************/ +class CStringTester { +public: + CStringTester() { + TestConstructors(); + TestAutoStrings(); + TestAppend(); + TestAssignAndAdd(); + TestInsert(); + TestDelete(); + TestTruncate(); + TestLogical(); + TestLexomorphic(); + TestCreators(); + TestNumerics(); + TestExtractors(); + TestSearching(); + TestSubsumables(); + TestRandomOps(); + TestReplace(); + TestRegressions(); + TestStringPerformance(); + TestWideStringPerformance(); + } +protected: + int TestConstructors(); + int TestLogical(); + int TestAutoStrings(); + int TestAppend(); + int TestAssignAndAdd(); + int TestInsert(); + int TestDelete(); + int TestTruncate(); + int TestLexomorphic(); + int TestCreators(); + int TestNumerics(); + int TestExtractors(); + int TestSearching(); + int TestSubsumables(); + int TestRandomOps(); + int TestReplace(); + int TestStringPerformance(); + int TestWideStringPerformance(); + int TestRegressions(); +}; + + +class Stopwatch { +public: + Stopwatch() { + start=clock(); + } + + void Stop() { + stop=clock(); + } + + double Elapsed() { + return (double)(stop - start) / CLOCKS_PER_SEC; + } + + void Print(const char* msg= "") { + printf("%s %f\n",msg,Elapsed()); + } + + clock_t start,stop; +}; + +/** + * + * @update gess10/30/98 + * @param + * @return + */ +int CStringTester::TestSearching(){ + int result=0; + + + + PRUnichar pbuf[10]={'e','f','g',0}; + PRUnichar pbuf2[10]={'a','b','c',0}; + + + //Since there is so much ground to cover with searching, we use a typedef to + //allow you to vary the string type being searched... + + + stringtype theDest("abcdefghijkabc"); + nsString s1("ijk"); + nsCString c1("ijk"); + + PRInt32 pos=theDest.Find(pbuf); + NS_ASSERTION(pos==4,"Error: Find routine"); + + pos=theDest.Find(pbuf2,PR_FALSE,-1); + NS_ASSERTION(pos==0,"Error: Find routine"); + + pos=theDest.Find(pbuf2,PR_FALSE,pos+1); + NS_ASSERTION(pos==11,"Error: Find routine"); + + pos=theDest.FindChar('a'); + NS_ASSERTION(pos==0,"Error: Find routine"); + + pos=theDest.FindChar('a',PR_FALSE,pos+1); + NS_ASSERTION(pos==11,"Error: Find routine"); + + pos=theDest.Find("efg"); + NS_ASSERTION(pos==4,"Error: Find routine"); + + pos=theDest.Find("EFG",PR_TRUE); + NS_ASSERTION(pos==4,"Error: Find routine"); + + pos=theDest.FindChar('d'); + NS_ASSERTION(pos==3,"Error: Find char routine"); + + pos=theDest.Find(s1); + NS_ASSERTION(pos==8,"Error: Find char routine"); + + pos=theDest.FindCharInSet("12k"); + NS_ASSERTION(pos==10,"Error: Findcharinset routine"); + + pos=theDest.FindCharInSet(pbuf); + NS_ASSERTION(pos==4,"Error: Findcharinset routine"); + + pos=theDest.FindCharInSet(s1); + NS_ASSERTION(pos==8,"Error: Findcharinset routine"); + + pos=theDest.Find("efg",PR_FALSE,2); + NS_ASSERTION(pos==4,"Error: Find routine"); + + pos=theDest.RFindCharInSet("12k"); + NS_ASSERTION(pos==10,"Error: RFindcharinset routine"); + + pos=theDest.RFindCharInSet("xyz"); + NS_ASSERTION(pos==-1,"Error: RFindcharinset routine"); + + pos=theDest.RFindCharInSet(pbuf); + NS_ASSERTION(pos==6,"Error: RFindcharinset routine"); + + pos=theDest.RFindCharInSet(s1); + NS_ASSERTION(pos==10,"Error: RFindcharinset routine"); + + pos=theDest.RFind("efg"); + NS_ASSERTION(pos==4,"Error: RFind routine"); + + pos=theDest.RFind("xxx"); + NS_ASSERTION(pos==-1,"Error: RFind routine"); //this should fail + + pos=theDest.RFind(""); + NS_ASSERTION(pos==-1,"Error: RFind routine"); //this too should fail. + + pos=theDest.RFindChar('a',PR_FALSE,4); + NS_ASSERTION(pos==-1,"Error: RFind routine"); + + + //now try searching with FindChar using offset and count... + { + stringtype s1("hello there rick"); + + PRInt32 pos=s1.FindChar('r'); //this will search from the beginning, and for the length of the string. + NS_ASSERTION(pos==9,"Error: FindChar() with offset and count"); + + pos=s1.FindChar('r',PR_FALSE,0,5); //this will search from the front using count. THIS WILL FAIL! + NS_ASSERTION(pos==-1,"Error: FindChar() with offset and count"); + + pos=s1.FindChar('r',PR_FALSE,0,10); //this will search from the front using count. THIS WILL SUCCEED! + NS_ASSERTION(pos==9,"Error: FindChar() with offset and count"); + + pos=s1.FindChar('i',PR_FALSE,5,5); //this will search from the middle using count. THIS WILL FAIL! + NS_ASSERTION(pos==-1,"Error: FindChar() with offset and count"); + + pos=s1.FindChar('i',PR_FALSE,5,10); //this will search from the middle using count. THIS WILL SUCCEED! + NS_ASSERTION(pos==13,"Error: FindChar() with offset and count"); + + pos=s1.FindChar('k',PR_FALSE,10,2); //this will search from near the end using count. THIS WILL FAIL! + NS_ASSERTION(pos==-1,"Error: FindChar() with offset and count"); + + pos=s1.FindChar('k',PR_FALSE,10,7); //this will search from near the end using count. THIS WILL SUCCEED! + NS_ASSERTION(pos==15,"Error: FindChar() with offset and count"); + + //now let's try a few with bad data... + + pos=s1.FindChar('k',PR_FALSE,100,2); //this will search from a bad offset. THIS WILL FAIL! + NS_ASSERTION(pos==-1,"Error: FindChar() with offset and count"); + + pos=s1.FindChar('k',PR_FALSE,10,0); //this will search for a bad count. THIS WILL FAIL! + NS_ASSERTION(pos==-1,"Error: FindChar() with offset and count"); + + pos=s1.FindChar('k',PR_FALSE,10,20); //this will search for a bad count. THIS WILL SUCCEED! + NS_ASSERTION(pos==15,"Error: FindChar() with offset and count"); + + pos=s1.FindChar('k',PR_FALSE,10,4); //this will search for a bad count. THIS WILL FAIL! + NS_ASSERTION(pos==-1,"Error: FindChar() with offset and count"); + + pos=10; + } + + //now try searching with RFindChar using offset and count... + { + stringtype s1("hello there rick"); + + PRInt32 pos=s1.RFindChar('o'); //this will search from the end, and for the length of the string. + NS_ASSERTION(pos==4,"Error: RFindChar() with offset and count"); + + pos=s1.RFindChar('i'); //this will search from the end, and for the length of the string. + NS_ASSERTION(pos==13,"Error: RFindChar() with offset and count"); + + pos=s1.RFindChar(' ',PR_FALSE,-1,4); //this will search from the end, and for the length of the string. + NS_ASSERTION(pos==-1,"Error: RFindChar() with offset and count"); //THIS WILL FAIL + + pos=s1.RFindChar(' ',PR_FALSE,12,1); //this will search from the middle, and for the length of 1. + NS_ASSERTION(pos==-1,"Error: RFindChar() with offset and count"); //THIS WILL FAIL + + pos=s1.RFindChar(' ',PR_FALSE,12,2); //this will search from the middle, and for the length of 2. + NS_ASSERTION(pos==11,"Error: RFindChar() with offset and count"); //THIS WILL SUCCEED + + pos=s1.RFindChar('o',PR_FALSE,-1,5); //this will search from the end using count. THIS WILL FAIL! + NS_ASSERTION(pos==-1,"Error: RFindChar() with offset and count"); + + pos=s1.RFindChar('o',PR_FALSE,-1,12); //this will search from the front using count. THIS WILL SUCCEED! + NS_ASSERTION(pos==4,"Error: RFindChar() with offset and count"); + + pos=s1.RFindChar('l',PR_FALSE,8,2); //this will search from the middle using count. THIS WILL FAIL! + NS_ASSERTION(pos==-1,"Error: RFindChar() with offset and count"); + + pos=s1.RFindChar('l',PR_FALSE,8,7); //this will search from the middle using count. THIS WILL SUCCEED! + NS_ASSERTION(pos==3,"Error: RFindChar() with offset and count"); + +//*** + + pos=s1.RFindChar('h',PR_FALSE,3,2); //this will search from near the end using count. THIS WILL FAIL! + NS_ASSERTION(pos==-1,"Error: RFindChar() with offset and count"); + + pos=s1.RFindChar('h',PR_FALSE,3,7); //this will search from near the end using count. THIS WILL SUCCEED! + NS_ASSERTION(pos==0,"Error: RFindChar() with offset and count"); + + //now let's try a few with bad data... + + pos=s1.RFindChar('k',PR_FALSE,100,2); //this will search from a bad offset. THIS WILL FAIL! + NS_ASSERTION(pos==-1,"Error: RFindChar() with offset and count"); + + pos=s1.RFindChar('k',PR_FALSE,10,0); //this will search for a bad count. THIS WILL FAIL! + NS_ASSERTION(pos==-1,"Error: RFindChar() with offset and count"); + + pos=10; + } + + //now try searching with Find() using offset and count... + { + stringtype s1("hello there rick"); + + PRInt32 pos= s1.Find("there",PR_FALSE,0,4); //first search from front using offset + NS_ASSERTION(pos==-1,"Error: Find() with offset and count"); //THIS WILL FAIL + + pos= s1.Find("there",PR_FALSE,0,8); //first search from front using count + NS_ASSERTION(pos==6,"Error: Find) with offset and count"); //THIS WILL SUCCEED + + pos= s1.Find("there",PR_FALSE,4,1); //first search from front using count + NS_ASSERTION(pos==-1,"Error: Find() with offset and count"); //THIS WILL FAIL + + pos= s1.Find("there",PR_FALSE,5,2); //first search from front using count + NS_ASSERTION(pos==6,"Error: Find() with offset and count"); //THIS WILL SUCCEED + + pos= s1.Find("there",PR_FALSE,6,1); //first search from front using count + NS_ASSERTION(pos==6,"Error: Find() with offset and count"); //THIS WILL SUCCEED + + pos= s1.Find("there",PR_FALSE,6,0); //first search from front using a bogus count + NS_ASSERTION(pos==-1,"Error: Find() with offset and count"); //THIS WILL FAIL + + pos= s1.Find("k",PR_FALSE,15,1); //first search from end using a count + NS_ASSERTION(pos==15,"Error: Find() with offset and count"); //THIS WILL SUCCEED + + pos= s1.Find("k",PR_FALSE,15,10); //first search from end using a LARGE count + NS_ASSERTION(pos==15,"Error: Find() with offset and count"); //THIS WILL SUCCEED + + pos= s1.Find("k",PR_FALSE,25,10); //first search from bogus offset using a LARGE count + NS_ASSERTION(pos==-1,"Error: Find() with offset and count"); //THIS WILL FAIL + + pos=10; + } + + //now try substringsearching with RFind() using offset and count... + { + nsString s1("abcdefghijklmnopqrstuvwxyz"); + + PRInt32 pos= s1.RFind("ghi"); //first search from end using count + NS_ASSERTION(pos==6,"Error: RFind() with offset and count"); //THIS WILL SUCCEED! + + pos= s1.RFind("nop",PR_FALSE,-1,4); //first search from end using count + NS_ASSERTION(pos==-1,"Error: RFind() with offset and count"); //THIS WILL FAIL + + pos= s1.RFind("nop",PR_FALSE,-1,15); //first search from end using count + NS_ASSERTION(pos==13,"Error: RFind() with offset and count"); //THIS WILL SUCCEED + + pos= s1.RFind("nop",PR_FALSE,16,3); //first search from middle using count + NS_ASSERTION(pos==-1,"Error: RFind() with offset and count"); //THIS WILL FAIL + + pos= s1.RFind("nop",PR_FALSE,16,7); //first search from middle using count + NS_ASSERTION(pos==13,"Error: RFind() with offset and count"); //THIS WILL SUCCEED + + pos= s1.RFind("nop",PR_FALSE,0,1); //first search from front using count + NS_ASSERTION(pos==-1,"Error: RFind() with offset and count"); //THIS WILL FAIL + + pos= s1.RFind("abc",PR_FALSE,0,1); //first search from middle using count + NS_ASSERTION(pos==0,"Error: RFind() with offset and count"); //THIS WILL SUCCEED + + pos= s1.RFind("foo",PR_FALSE,10,100); //first search from front using bogus count + NS_ASSERTION(pos==-1,"Error: RFind() with offset and count"); //THIS WILL FAIL + + pos= s1.RFind("ghi",PR_FALSE,30,1); //first search from middle using bogus offset + NS_ASSERTION(pos==-1,"Error: RFind() with offset and count"); //THIS WILL FAIL + + pos=10; + } + + //Various UNICODE tests... + { + //do some searching against chinese unicode chars... + + PRUnichar chinese[] = {0x4e41,0x4e42, 0x4e43, 0x0000}; // 3 chinese unicode + + nsString T2(chinese); + nsString T2copy(chinese); + + pos = T2.FindCharInSet("A"); + NS_ASSERTION(kNotFound==pos,"Error in FindCharInSet"); + + pos=T2.RFindCharInSet("A",2); + NS_ASSERTION(kNotFound==pos,"Error in RFindCharInSet"); + + pos=T2.Find("A", PR_FALSE, 0, 1); + NS_ASSERTION(kNotFound==pos,"Error in Find"); + + pos=T2.RFind("A", PR_FALSE, 2, 1); + NS_ASSERTION(kNotFound==pos,"Error in RFind"); + + T2.ReplaceChar("A",' '); + NS_ASSERTION(T2==T2copy,"Error in ReplaceChar"); + + //Here's the 3rd FTang unicode test... + + static char test4[]="ABCDEF"; + static char test4b[]=" BCDEF"; + + PRUnichar test5[]={0x4e41, 0x0000}; + PRUnichar test6[]={0x0041, 0x0000}; + + nsCString T4(test4); + nsCString T4copy(test4); + nsCString T4copyb(test4b); + nsCString T5(test5); + nsCString T6(test6); + + pos = T4.FindCharInSet(T5.get()); + NS_ASSERTION(0==pos,"Error in FindcharInSet"); //This should succeed. + + pos = T4.FindCharInSet(T6.get()); + NS_ASSERTION(kNotFoundtemp8.Compare(bbbb),kComparisonError); + NS_ASSERTION(0>temp8.Compare(temp9),kComparisonError); + NS_ASSERTION(0=temp8)),kComparisonError); + + NS_ASSERTION(((temp9>temp8) && (temp8<=temp9)),kComparisonError); + NS_ASSERTION(temp9>aaaa,kComparisonError); + + NS_ASSERTION(temp8<=temp8,kComparisonError); + NS_ASSERTION(temp8<=temp9,kComparisonError); + NS_ASSERTION(temp8<=bbbb,kComparisonError); + + NS_ASSERTION(((temp9>=temp8) && (temp8=temp8,kComparisonError); + NS_ASSERTION(temp9>=aaaa,kComparisonError); + + NS_ASSERTION(temp8.Equals(temp8),kEqualsError); + NS_ASSERTION(temp8.Equals(aaaa),kEqualsError); + + stringtype temp10(temp8); + ToUpperCase(temp10); + NS_ASSERTION(temp8.Equals(temp10,PR_TRUE),kEqualsError); + NS_ASSERTION(temp8.Equals("AAAA",PR_TRUE),kEqualsError); + + + //now test the new string Equals APIs.. + { + nsCString s1("hello there"); + NS_ASSERTION(s1.Equals("hello there"),kEqualsError); + NS_ASSERTION(s1.Equals("hello rick",PR_FALSE,5),kEqualsError); + NS_ASSERTION(!s1.Equals("hello rick",PR_FALSE-1),kEqualsError); + + nsCString s2(""); + NS_ASSERTION(s2.Equals(""),kEqualsError); + + nsCString s3("view-source:"); + NS_ASSERTION(s3.Equals("VIEW-SOURCE:",PR_TRUE,12),kEqualsError); + } + + //now test the count argument... + { + nsString s1("rickgessner"); + nsString s2("rickricardo"); + PRInt32 result=s1.Compare(s2); //assume no case conversion, and full-length comparison... + result=s1.Compare(s2,PR_FALSE,4); + result=s1.Compare(s2,PR_FALSE,5); + + PRBool b=s1.Equals(s2); + b=s1.Equals("rick",PR_FALSE,4); + b=s1.Equals("rickz",PR_FALSE,5); + + result=10; + + nsString s3("view"); + +#define kString "view-source" + + b=s3.Equals(kString); + result=10; + } + + return result; +} + +/** + * + * @update gess10/30/98 + * @param + * @return + */ +int CStringTester::TestAssignAndAdd(){ + int result=0; + + static const char* s1="hello"; + static const char* s2="world"; + static const PRUnichar pbuf[] = {' ','w','o','r','l','d',0}; + + nsString ns1("I'm an nsString"); + nsCString nc1("I'm an nsCString"); + + nsAutoString as1("nsAutoString source"); + nsCAutoString ac1("nsCAutoString source"); + + + { + //**** Test assignments to nsCString... + + nsCString theDest; + theDest.Assign(theDest); //assign nsString to itself + theDest.Assign(ns1); //assign an nsString to an nsString + NS_ASSERTION(theDest==ns1,"Assignment error"); + + theDest.Assign(nc1); //assign an nsCString to an nsString + NS_ASSERTION(theDest==nc1,"Assignment error"); + + theDest.Assign(as1); //assign an nsAutoString to an nsString +// NS_ASSERTION(theDest==as1,"Assignment error"); + + theDest.Assign(ac1); //assign an nsCAutoString to an nsString +// NS_ASSERTION(theDest==ac1,"Assignment error"); + + theDest.Assign("simple char*"); //assign a char* to an nsString + NS_ASSERTION(theDest=="simple char*","Assignment error"); + + theDest.Assign(pbuf); //assign a PRUnichar* to an nsString + NS_ASSERTION(theDest==pbuf,"Assignment error"); + + theDest.Assign('!'); //assign a char to an nsString + NS_ASSERTION(theDest=="!","Assignment error"); + + theDest.Assign(PRUnichar('$')); //assign a char to an nsString + NS_ASSERTION(theDest=="$","Assignment error"); + + theDest=ns1; + NS_ASSERTION(theDest==ns1,"Assignment error"); + + theDest=nc1; + NS_ASSERTION(theDest==nc1,"Assignment error"); + + theDest='a'; + NS_ASSERTION(theDest=="a","Assignment error"); + + theDest=PRUnichar('a'); + NS_ASSERTION(theDest=="a","Assignment error"); + + theDest=s1; + NS_ASSERTION(theDest==s1,"Assignment error"); + + theDest=pbuf; + NS_ASSERTION(theDest==pbuf,"Assignment error"); + + } + + //test operator+()... + { + + /* NOT WORKING YET... + nsString s1("hello"); + nsString s2(" world"); + nsCString c1(" world"); + + stringtype theDest; + + theDest=s1+s2; + NS_ASSERTION(theDest=="hello world","Assignment error"); + + theDest=s1+c1; + NS_ASSERTION(theDest=="hello world","Assignment error"); + + theDest=s1+" world"; + NS_ASSERTION(theDest=="hello world","Assignment error"); + + theDest=s1+pbuf; + NS_ASSERTION(theDest=="hello world","Assignment error"); + + theDest=s1+'!'; + NS_ASSERTION(theDest=="hello!","Assignment error"); + + theDest=s1+PRUnichar('!'); + NS_ASSERTION(theDest=="hello!","Assignment error"); +*/ + + } + + return result; +} + + +/** + * + * @update gess10/30/98 + * @param + * @return + */ +int CStringTester::TestAppend(){ + int result=0; + + + static const char* s1="hello"; + static const char* s2="world"; + static const PRUnichar pbuf[] = {' ','w','o','r','l','d',0}; + static const PRUnichar pbuf1[] = {'a','b','c','d','l','d'}; + + + stringtype theDest; + theDest.Append((float)100.100); + NS_ASSERTION(theDest=="100.1","Append(float) error"); + + theDest.Truncate(); + theDest.Append(12345); + NS_ASSERTION(theDest=="12345","Append(int) error"); + + theDest.Truncate(); + theDest.Append(pbuf1,1); + NS_ASSERTION(theDest=="a","Append(PRUnichar*,count) error"); + + theDest.Truncate(); + theDest.Append('a'); + NS_ASSERTION(theDest=="a","Append(char) error"); + + + static const PRUnichar pbuf2[] = {'w','h','a','t','s',' ','u','p',' ','d','o','c','?',0}; + + theDest.Truncate(); + theDest.Append(pbuf,20); //try appending more chars than actual length of pbuf + NS_ASSERTION(theDest!=pbuf,"Append(PRUnichar*) error"); + //(NOTE: if you tell me to append X chars, I'll assume you really have X chars, and the length + // get's set accordingly. This test really is correct; it just seems odd. + + theDest.Truncate(0); + theDest.Append(pbuf,5); //try appending fewer chars than actual length of pbuf + NS_ASSERTION(theDest==" worl","Append(PRUnichar*) error"); + + theDest.Truncate(0); + theDest.Append(pbuf); //try appending all of pbuf + NS_ASSERTION(theDest==pbuf,"Append(PRUnichar*) error"); + + char* ss=0; + theDest.Truncate(); + theDest.Append(ss); //try appending NULL + NS_ASSERTION(theDest=="","Append(nullstr) error"); + + theDest.Append(pbuf,0); //try appending nothing + NS_ASSERTION(theDest=="","Append(nullstr) error"); + + + { + //test improvement to unichar appends... + stringtype s1("hello"); + char c='!'; + s1+=c; + NS_ASSERTION(s1=="hello!","operator+=() error"); + + c=(char)0xfa; + s1+=c; + s1.Append(c); + + PRUnichar theChar='f'; + s1+=theChar; + + char theChar2='g'; + s1+=theChar2; + +// long theLong= 1234; +// s1+=theLong; + + } + + { + //this just proves we can append nulls in our buffers... + stringtype c("hello"); + stringtype s(" there"); + c.Append(s); + char buf[]={'a','b',0,'d','e'}; + s.Append(buf,5); + } + + + stringtype temp2("there"); + + theDest.Append(temp2); + theDest.Append(" xxx "); + theDest.Append(pbuf); + theDest.Append('4'); + theDest.Append(PRUnichar('Z')); + + stringtype a(s1); + stringtype b(s2); + + theDest.Truncate(); + temp2.Truncate(); + +/* NOT WORKING YET... + theDest=a+b; + temp2=a+"world!"; + temp2=a+pbuf; + stringtype temp3; + temp3=temp2+'!'; +*/ + return result; +} + + +/** + * + * @update gess10/30/98 + * @param + * @return + */ +int CStringTester::TestExtractors(){ + int result=0; + + //first test the 2 byte version... + + + { + nsString temp1("hello there rick"); + nsString temp2; + + temp1.Left(temp2,10); + NS_ASSERTION(temp2=="hello ther","Left() error"); + + temp1.Mid(temp2,6,5); + NS_ASSERTION(temp2=="there","Mid() error"); + + temp1.Right(temp2,4); + NS_ASSERTION(temp2=="rick","Right() error"); + + //Now test the character accessor methods... + nsString theString("hello"); + PRUint32 len=theString.Length(); + PRUnichar theChar; + for(PRUint32 i=0;i2) { + pos=theString.Length()/2; + theSTLString.insert(pos,str[index],4); + theString.Insert(str[index],pos); + } + break; + + case 6: + case 7: + case 8: + case 9: + theOp=eDelete; + if(theString.Length()>10) { + len=theString.Length()/2; + pos=theString.Length()/4; + theSTLString.erase(pos,len); + theString.Cut(pos,len); + } + break; + + default: + theOp=eNOP; + + } //for + + if(eNOP300) { + theString.Truncate(); + theSTLString.erase(); + } +#endif + thePrevString=theString; + } + } +#endif + return result; +} + + +/** + * + * @update gess10/30/98 + * @param + * @return + */ +int CStringTester::TestReplace(){ + int result=0; + + const char* find=".."; + const char* rep= "+"; + + const char* s1="hello..there..rick..gessner."; + const char* s2="hello+there+rick+gessner."; + + nsCString s(s1); + s.ReplaceSubstring(find,rep); + NS_ASSERTION(s==s2,"ReplaceSubstring error"); + + s.ReplaceSubstring(rep,find); + NS_ASSERTION(s==s1,"ReplaceSubstring error"); + + return result; +} + + +/** + * This method tests the performance of various methods. + * + * + * @return + */ +int CStringTester::TestWideStringPerformance() { + + printf("Widestring performance tests...\n"); + + char* libname[] = {"STL","nsString",0}; + + + //************************************************** + //Test Construction against STL::wstring... + //************************************************** + { + nsString theConst; + for(int z=0;z<10;z++){ + theConst.Append("0123456789"); + } + + Stopwatch watch1; + int i; + for(i=0;i<1000000;i++){ + nsString s(theConst); + } + watch1.Stop(); + + wchar_t wbuf[] = {'a','b','c','d','e','f','g','h','i','j',0}; + wstring theConst2; + for(int w=0;w<10;w++){ + theConst2.append(wbuf); + } + + Stopwatch watch2; +#ifdef USE_STL + for(i=0;i<1000000;i++){ + wstring s(theConst2); + } +#endif + watch2.Stop(); + + printf("Construct(abcde) NSString: %f STL: %f\n",watch1.Elapsed(),watch2.Elapsed()); + } + + + //************************************************** + //Test append("abcde") against STL::wstring... + //************************************************** + { + + PRUnichar pbuf[10]={'a','b','c','d','e',0}; + + Stopwatch watch1; + int i; + for(i=0;i<1000;i++){ + nsString s; + for(int j=0;j<200;j++){ + s.Append("abcde"); + } + } + watch1.Stop(); + + wchar_t wbuf[10] = {'a','b','c','d','e',0}; + + Stopwatch watch2; +#ifdef USE_STL + for(i=0;i<1000;i++){ + wstring s; + for(int j=0;j<200;j++){ + s.append(wbuf); + } + } +#endif + watch2.Stop(); + + printf("Append(abcde) NSString: %f STL: %f\n",watch1.Elapsed(),watch2.Elapsed()); + } + + //************************************************** + //Test append(char) against STL::wstring + //************************************************** + { + + Stopwatch watch1; + int i; + for(i=0;i<500;i++){ + nsString s; + for(int j=0;j<200;j++){ + s.Append('a'); + } + } + watch1.Stop(); + + + Stopwatch watch2; +#ifdef USE_STL + for(i=0;i<500;i++){ + wstring s; + wchar_t theChar('a'); + for(int j=0;j<200;j++){ + s.append('a',1); + } + } +#endif + watch2.Stop(); + + printf("Append('a') NSString: %f STL: %f\n",watch1.Elapsed(),watch2.Elapsed()); + int x=0; + } + + //************************************************** + //Test insert("123") against STL::wstring + //************************************************** + { + + PRUnichar pbuf1[10]={'a','b','c','d','e','f',0}; + PRUnichar pbuf2[10]={'1','2','3',0}; + + Stopwatch watch1; + int i; + for(i=0;i<1000;i++){ + nsString s("abcdef"); + int inspos=3; + for(int j=0;j<100;j++){ + s.Insert(pbuf2,inspos); + inspos+=3; + } + } + watch1.Stop(); + + + wchar_t wbuf1[10] = {'a','b','c','d','e','f',0}; + wchar_t wbuf2[10] = {'1','2','3',0}; + + Stopwatch watch2; +#ifdef USE_STL + for(i=0;i<1000;i++){ + wstring s(wbuf1); + int inspos=3; + for(int j=0;j<100;j++){ + s.insert(inspos,wbuf2); + inspos+=3; + } + } +#endif + watch2.Stop(); + + printf("Insert(123) NSString: %f STL: %f\n",watch1.Elapsed(),watch2.Elapsed()); + int x=0; + } + + //************************************************** + //Let's test substring searching performance... + //************************************************** + { + PRUnichar pbuf1[] = {'a','a','a','a','a','a','a','a','a','a','b',0}; + PRUnichar pbuf2[] = {'a','a','b',0}; + + nsString s(pbuf1); + nsString target(pbuf2); + + Stopwatch watch1; + int i; + for(i=-1;i<200000;i++) { + PRInt32 result=s.Find(target,PR_FALSE); + } + watch1.Stop(); + + Stopwatch watch2; +#ifdef USE_STL + wchar_t wbuf1[] = {'a','a','a','a','a','a','a','a','a','a','b',0}; + wchar_t wbuf2[] = {'a','a','b',0}; + wstring ws(wbuf1); + wstring wtarget(wbuf2); + + for(i=-1;i<200000;i++) { + PRInt32 result=ws.find(wtarget); + } +#endif + watch2.Stop(); + + printf("Find(aab) NSString: %f STL: %f\n",watch1.Elapsed(),watch2.Elapsed()); + } + + //************************************************** + //Now let's test comparisons... + //************************************************** + { + nsString s("aaaaaaaaaaaaaaaaaaab"); + PRUnichar target[]={'a','a','a','a','a','a','a','a','a','a','a','a','a','b',0}; + size_t theLen=(sizeof(target)-1)/2; + + Stopwatch watch1; + int result=0; + int i; + for(i=-1;i<1000000;i++) { + result=s.Compare(target,PR_FALSE,theLen); + result++; + } + watch1.Stop(); + + Stopwatch watch2; +#ifdef USE_STL + wchar_t buf[]={'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','b',0}; + wstring ws(buf); + wchar_t wtarget[]={'a','a','a','a','a','a','a','a','a','a','a','a','a','b',0}; + + for(i=-1;i<1000000;i++) { + result=ws.compare(0,theLen,wtarget); + result++; + } +#endif + watch2.Stop(); + + printf("Compare(aaaaaaaab) NSString: %f STL: %f\n",watch1.Elapsed(),watch2.Elapsed()); + + } + + //************************************************** + //Now lets test string deletions... + //************************************************** + { + + int strcount=6000; + int outerIter=100; + int innerIter=100; + + PRUnichar pbuf[] = {'1','2','3','4','5','6','7','8','9','0',0}; + nsString source1; //build up our target string... + int i; + for(i=0;i"); + PRInt32 result=s.Find("",PR_TRUE); + + //this was a known bug... + { + nsString s0(""); + PRInt32 pos=s0.RFind("-->"); + nsString s1("debug"); + pos=s1.RFind("b"); + pos=s1.RFind("de",PR_FALSE,1); + pos=10; + } + + //this was a known bug... + { + nsString s0("RDF:RDF"); + PRInt32 pos=s0.Find(":"); + pos=10; + } + + return result; +} + +#endif + diff --git a/src/libs/xpcom18a4/xpcom/tests/windows/nsStringTest2.h b/src/libs/xpcom18a4/xpcom/tests/windows/nsStringTest2.h new file mode 100644 index 00000000..16ffc11a --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/windows/nsStringTest2.h @@ -0,0 +1,444 @@ +/******************************************************************************************** + * + * MODULES NOTES: + * + * This file is designed to help test the new nsString classes. + * + * Contributor(s): + * Rick Gessner + * + * History: + * + * 02.29.2000: Original files (rickg) + * 03.02.2000: Flesh out the interface to be compatible with old library (rickg) + * + ********************************************************************************************/ + +#ifndef _STRINGTEST2 +#define _STRINGTEST2 + + +#include "nsString.h" +#include + +#define USE_STL + +#ifdef USE_STL +#include +using namespace std; +#endif + +#define USE_WIDE 1 +#ifdef USE_WIDE + #define stringtype nsString + #define astringtype nsAutoString + #define chartype PRUnichar +#else + #define stringtype nsCString + #define astringtype nsCAutoString + #define chartype char +#endif + +#include +const double gTicks = 1.0e-7; + + + + + +/******************************************************** + + This class's only purpose in life is to test the + netscape string library. We exercise the string + API's here, and do a bit of performance testing + against the standard c++ library string (from STL). + + ********************************************************/ +class CStringTester { + +public: + + int TestI18nString(); + +}; + + + + +//test 1: unicode char is stripped correctly using StripChars() +void nsStringTest1(){ + PRUnichar test[]={0x0041,0x0051,0x0052,0x0000}; + nsString T(test); + PRUnichar result[]={0x0051,0x0052,0x0000}; + nsString R(result); + T.StripChars("ABC"); + NS_ASSERTION(T.Equals(R), "Test 1: Unicode comparison error"); +} +//test 2: unicode char is not matched and stripped when high-order byte is not 0x00 +void nsStringTest2(){ + PRUnichar test[]={0x4e41,0x4e51,0x4e52,0x4e53,0x0000}; + nsAutoString T(test); + PRUnichar result[]={0x4e41,0x4e51,0x4e52,0x4e53,0x0000}; + nsAutoString R(result); + T.StripChars("ABC"); + NS_ASSERTION(T.Equals(R), "Unicode comparison error"); +} + //test 3: unicode char is not matched and stripped when high-order byte is 0xFF +void nsStringTest3(){ + + PRUnichar test[] = {0xFF41,0x4e51,0x4e52,0x4e53,0x0000}; + nsAutoString T(test); + PRUnichar result[] = {0xFF41,0x4e51,0x4e52,0x4e53,0x0000}; + nsAutoString R(test); + T.StripChars("ABC"); + NS_ASSERTION(T.Equals(R), "Unicode comparison error"); +} +void nsStringTest4(){ + //test 4: unicode char is matched and stripped correctly using StripChar() + PRUnichar test[] = {0x0041,0x0051,0x0052,0x0000}; + nsAutoString T(test); + PRUnichar result[] = {0x0051,0x0052,0x0000}; + nsAutoString R(result); + T.StripChar('A'); + NS_ASSERTION(T.Equals(R), "Unicode comparison error"); +} +void nsStringTest5(){ + //test 5: unicode char is not matched and stripped when high-order byte is not 0x00 + + PRUnichar test[]={0x4e41,0x4e51,0x4e52,0x4e53,0x0000}; + nsAutoString T(test); + PRUnichar result[]={0x4e41,0x4e51,0x4e52,0x4e53,0x0000}; + nsAutoString R(result); + T.StripChar('A'); + NS_ASSERTION(T.Equals(R), "Unicode comparison error"); +} +void nsStringTest6(){ + //test 6: unicode char is not matched and stripped when high-order byte is 0xFF + + PRUnichar test[] = {0xFF41,0x4e51,0x4e52,0x4e53,0x0000}; + nsAutoString T(test); + PRUnichar result[] = {0xFF41,0x4e51,0x4e52,0x4e53,0x0000}; + nsAutoString R(result); + T.StripChar('A'); + NS_ASSERTION(T.Equals(R), "Unicode comparison error"); +} +void nsStringTest7(){ + //test 7: unicode char is matched and replaced correctly using ReplaceChar() + + PRUnichar test[] = {0x0041,0x0051,0x0052,0x0000}; + nsAutoString T(test); + PRUnichar result[] = {0x0050,0x0051,0x0052,0x0000}; + nsAutoString R(result); + T.ReplaceChar('A',0x50); + NS_ASSERTION(T.Equals(R), "Unicode comparison error"); +} +void nsStringTest8(){ + //test 8: unicode char is not matched or replaced when high-order byte != 0x00 + + PRUnichar test[] = {0x4e41,0x4e51,0x4e52,0x4e53,0x0000}; + nsAutoString T(test); + PRUnichar result[] = {0x4e41,0x4e51,0x4e52,0x4e53,0x0000}; + nsAutoString R(result); + T.ReplaceChar('A',0x50); + NS_ASSERTION(T.Equals(R), "Unicode comparison error"); +} +void nsStringTest9(){ + //test 9: unicode char is not matched or replaced when high-order byte matches search char + + PRUnichar test[] = {0x4150,0x4e51,0x4e52,0x4e53,0x0000}; + nsAutoString T(test); + PRUnichar result[] = {0x4150,0x4e51,0x4e52,0x4e53,0x0000}; + nsAutoString R(result); + T.ReplaceChar('A',0x50); + NS_ASSERTION(T.Equals(R), "Unicode comparison error"); +} +void nsStringTest10(){ + //test 10: unicode char is not matched or replaced when high-order byte == 0xFF + + PRUnichar test[] = {0xFFc1,0x4e51,0x4e52,0x4e53,0x0000}; + nsAutoString T(test); + PRUnichar result[] = {0xFFc1,0x4e51,0x4e52,0x4e53,0x0000}; + nsAutoString R(result); + T.ReplaceChar('A',0x50); + NS_ASSERTION(T.Equals(R), "Unicode comparison error"); +} + +void nsStringTest11(){ + //test 11: unicode char is correctly replaced when parameter 1 is a string + + PRUnichar test[] = {0x0041,0x0051,0x0052,0x0000}; + nsAutoString T(test); + PRUnichar result[] = {0x0050,0x0051,0x0052,0x0000}; + nsAutoString R(result); + T.ReplaceChar("ABC",0x50); + NS_ASSERTION(T.Equals(R), "Unicode comparison error"); +} +void nsStringTest12(){ + //test 12: unicode char is not replaced when high-order byte != 0x00 + + PRUnichar test[] = {0x4e41,0x0051,0x0052,0x0000}; + nsAutoString T(test); + PRUnichar result[] = {0x4e41,0x0051,0x0052,0x0000}; + nsAutoString R(result); + T.ReplaceChar("ABC",0x50); + NS_ASSERTION(T.Equals(R), "Unicode comparison error"); + +} +void nsStringTest13(){ + //test 13: unicode char is not replaced when high-order byte matches char in search string + PRUnichar test[] = {0x4150,0x4e51,0x4e52,0x4e53,0x0000}; + nsAutoString T(test); + PRUnichar result[] = {0x4150,0x4e51,0x4e52,0x4e53,0x0000}; + nsAutoString R(result); + T.ReplaceChar("ABC",'T'); + NS_ASSERTION(T.Equals(R), "Unicode comparison error"); + +} +void nsStringTest14(){ + PRUnichar test[] = {0xFFc2,0x4e51,0x4e52,0x4e53,0x0000}; + nsAutoString T(test); + PRUnichar result[] = {0xFFc2,0x4e51,0x4e52,0x4e53,0x0000}; + nsAutoString R(result); + T.ReplaceChar("ABC",'T'); + NS_ASSERTION(T.Equals(R), "Unicode comparison error"); +} +void nsStringTest15(){ + PRUnichar test[] = {0xFFc2,0x4e51,0x4e52,0x4e53,0x0000}; + nsAutoString T(test); + PRUnichar result[] = {0xFFc2,0x4e51,0x4e52,0x4e53,0x0000}; + nsAutoString R(result); + PRUnichar s = 0xc2; //compiler error on this line + T.ReplaceChar(s,'T'); + NS_ASSERTION(T.Equals(R), "Unicode comparison error"); +} + +void nsStringTest16(){ + /* TESTS for ReplaceSubstring()*/ + + PRUnichar test[] = {0x0041,0x0042,0x0043,0x0044,0x0045,0x0000}; + nsAutoString T(test); + PRUnichar result[] = {0x0044,0x0045,0x0046,0x0044,0x0045}; + nsAutoString R(result); + T.ReplaceSubstring("ABC","DEF"); + NS_ASSERTION(T.Equals(R), "Unicode comparison error"); + +} +void nsStringTest17(){ + + PRUnichar test[] = {0x0041,0x4e42,0x0043,0x0044,0x0045,0x0000}; + nsAutoString T(test); + PRUnichar result[] = {0x0041,0x4e42,0x0043,0x0044,0x0045,0x0000}; + nsAutoString R(result); + T.ReplaceSubstring("ABC","DEF"); + NS_ASSERTION(T.Equals(R), "Unicode comparison error"); +} +void nsStringTest18(){ + /*TESTS for Trim()*/ + + PRUnichar test[] = {0x0041,0x4e51,0x4e52,0x4e53,0x0000}; + nsAutoString T(test); + PRUnichar result[] = {0x4e51,0x4e52,0x4e53,0x0000}; + nsAutoString R (result); + T.Trim("ABC"); + NS_ASSERTION(T.Equals(R), "Unicode comparison error"); +} +void nsStringTest19(){ + PRUnichar test[] = {0x4e41,0x4e51,0x4e52,0x4e53,0x0000}; + nsAutoString T(test); + PRUnichar result[] = {0x4e41,0x4e51,0x4e52,0x4e53,0x0000}; + nsAutoString R(result); + T.Trim("ABC"); + NS_ASSERTION(T.Equals(R), "Unicode comparison error"); +} +void nsStringTest22(){ + PRUnichar test[] = {0x4e51,0x4e52,0x4e53,0x4e41,0x0000}; + nsAutoString T(test); + PRUnichar result[] = {0x4e51,0x4e52,0x4e53,0x4e41,0x0000}; + nsAutoString R(result); + T.Trim("ABC"); + NS_ASSERTION(T.Equals(R), "Unicode comparison error"); + +} +//void nsStringTest23(){ +// PRUnichar test[] = {0x4e51,0x4e52,0x4e53,0x4e22,0x0000}; +// nsAutoString T(test); +// PRUnichar s(0x4e22); +// PRUnichar result[] = {0x4e51,0x4e52,0x4e53,0x0000}; +// nsAutoString R(result); +// T.Trim(s,PR_TRUE,PR_TRUE,PR_FALSE); +// NS_ASSERTION(T.Equals(R), "Unicode comparison error"); +//} +void nsStringTest24(){ + /*TESTS for Find()*/ + PRUnichar test[] = {0x0041,0x0042,0x0043,0x0051,0x0052,0x0000}; + nsAutoString T(test); + NS_ASSERTION(T.Find("ABC") == 0, "Unicode comparison error"); + +} +void nsStringTest25(){ + PRUnichar test[] = {0x4e41,0x4e42,0x4e43,0x4e53,0x0000}; + nsAutoString T(test); + NS_ASSERTION(T.Find("ABC") == -1, "Unicode comparison error"); + +} +void nsStringTest26(){ + PRUnichar test[] = {0xFFc1,0x0051,0x0052,0x0053,0x0000}; + nsAutoString T(test); + PRUnichar str[] = {0xc1,0x51,0x52}; + nsAutoString S(str); + NS_ASSERTION(T.Find(S) == -1, "Unicode comparison error"); +} +void nsStringTest27(){ + /*TESTS for FindChar()*/ + + PRUnichar test[] = {0x0041,0x0051,0x0052,0x0000}; + nsAutoString T(test); + NS_ASSERTION(T.FindChar('A') == 0, "Unicode comparison error"); +} +void nsStringTest28(){ + PRUnichar test[] = {0x4e41,0x4e42,0x4e43,0x4e53,0x0000}; + nsAutoString T(test); + NS_ASSERTION(T.FindChar('A') == -1, "Unicode comparison error"); +} +void nsStringTest29(){ + PRUnichar test[] = {0xFFc1,0x4e51,0x4e52,0x4e53,0x0000}; + nsAutoString T(test); + NS_ASSERTION(T.FindChar(0xc1) == -1, "Unicode comparison error"); + +} +void nsStringTest30(){ + PRUnichar test[] = {0x4132,0x0051,0x0052,0x0000}; + nsAutoString T(test); + NS_ASSERTION(T.FindChar('A1') == -1, "Unicode comparison error"); +} + /*TESTS for FindCharInSet()*/ +void nsStringTest31(){ + PRUnichar test[] = {0x0041,0x0051,0x0052,0x0000}; + nsAutoString T(test); + NS_ASSERTION(T.FindCharInSet("ABC") == 0, "Unicode comparison error"); +} +void nsStringTest32(){ + PRUnichar test[] = {0x4e41,0x4e42,0x4e43,0x4e53,0x0000}; + nsAutoString T(test); + NS_ASSERTION(T.FindCharInSet("ABC") == -1, "Unicode comparison error"); + +} +void nsStringTest33(){ + PRUnichar test[] = {0xFFc1,0x4e51,0x4e52,0x4e53,0x0000}; + nsAutoString T(test); + PRUnichar str[] = {0xc1,0x51,0x52}; + nsAutoString s(str); + NS_ASSERTION(T.FindCharInSet(s) == -1, "Unicode comparison error"); +} +void nsStringTest34(){ + PRUnichar test[] = {0x4132,0x5132,0x5232,0x0000}; + nsAutoString T(test); + NS_ASSERTION(T.FindCharInSet("ABC") == -1, "Unicode comparison error"); +} + /*TESTS for RFind()*/ +void nsStringTest35(){ + + PRUnichar test[] = {0x0051,0x0052,0x0041,0x0042,0x0043,0x0000}; + nsAutoString T(test); + NS_ASSERTION(T.RFind("ABC") == 2, "Unicode comparison error"); +} +void nsStringTest36(){ + PRUnichar test[] = {0x4e41,0x4e42,0x4e43,0x4e53,0x0000}; + nsAutoString T(test); + NS_ASSERTION(T.RFind("ABC") == -1, "Unicode comparison error"); +} +void nsStringTest37(){ + PRUnichar test[] = {0xFFc1,0xFFc2,0xFFc3,0x4e53,0x0000}; + nsAutoString T(test); + PRUnichar str[] = {0xc1,0xc2,0xc3}; + nsAutoString s(str); + NS_ASSERTION(T.RFind(s) == -1, "Unicode comparison error"); +} + /*TESTS for RFindCharInSet*/ +void nsStringTest38(){ + + PRUnichar test[] = {0x0041,0x0042,0x0043,0x0000}; + nsAutoString T(test); + int res = T.RFindCharInSet("ABC"); + NS_ASSERTION(res==0, "Unicode comparison error"); +} +void nsStringTest39(){ + PRUnichar test[] = {0x4e41,0x4e42,0x4e43,0x4e53,0x0000}; + nsAutoString T(test); + NS_ASSERTION(T.RFindCharInSet("ABC") == -1, "Unicode comparison error"); +} +void nsStringTest40(){ + PRUnichar test[] = {0xFFc1,0x4e51,0x4e52,0x4e53,0x0000}; + nsAutoString T(test); + PRUnichar str[] = {0xc1,0xc2,0xc3}; + nsAutoString s(str); + NS_ASSERTION(T.RFindCharInSet(s) == -1, "Unicode comparison error"); +} +void nsStringTest41(){ + PRUnichar test[] = {0x4132,0x0051,0x0052,0x0000}; + nsAutoString T(test); + NS_ASSERTION(T.RFindCharInSet("ABC") == -1, "Unicode comparison error"); +} + /* TESTS for Compare() */ +void nsStringTest42(){ + PRUnichar test[] = {0x0041,0x0042,0x0043,0x0000}; + nsAutoString T(test); + NS_ASSERTION(T.Compare("ABC") == 0, "Unicode comparison error"); +} +void nsStringTest43(){ + PRUnichar test[] = {0xc341,0xc342,0xc343}; + nsAutoString T(test); + NS_ASSERTION(T.Compare("ABC") == 1, "Unicode comparison error"); +} + + +int CStringTester::TestI18nString(){ + nsStringTest1(); + nsStringTest2(); + nsStringTest3(); + nsStringTest4(); + nsStringTest5(); + nsStringTest6(); + nsStringTest7(); + nsStringTest8(); + nsStringTest9(); + nsStringTest10(); + nsStringTest11(); + nsStringTest12(); + nsStringTest13(); + nsStringTest14(); + nsStringTest15(); + nsStringTest16(); + nsStringTest17(); + nsStringTest18(); + nsStringTest19(); + //nsStringTest20(); + //nsStringTest21(); + nsStringTest22(); + //nsStringTest23(); + nsStringTest24(); + nsStringTest25(); + nsStringTest26(); + nsStringTest27(); + nsStringTest28(); + nsStringTest29(); + nsStringTest30(); + nsStringTest31(); + nsStringTest32(); + nsStringTest33(); + nsStringTest34(); + nsStringTest35(); + nsStringTest36(); + nsStringTest37(); + nsStringTest38(); + nsStringTest39(); + nsStringTest40(); + nsStringTest41(); + nsStringTest42(); + nsStringTest43(); + + return 0; +} + +#endif + diff --git a/src/libs/xpcom18a4/xpcom/threads/.cvsignore b/src/libs/xpcom18a4/xpcom/threads/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/threads/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/xpcom/threads/Makefile.in b/src/libs/xpcom18a4/xpcom/threads/Makefile.in new file mode 100644 index 00000000..83433706 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/threads/Makefile.in @@ -0,0 +1,105 @@ +# +# ***** 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.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of 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 ***** + +DEPTH = ../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = xpcom +ifeq ($(OS_ARCH),WINNT) +XPIDL_MODULE = xpcom_thread +else +XPIDL_MODULE = xpcom_threads +endif +LIBRARY_NAME = xpcomthreads_s +GRE_MODULE = 1 +REQUIRES = string \ + $(NULL) + + +CSRCS = \ + plevent.c \ + $(NULL) + +CPPSRCS = \ + nsAutoLock.cpp \ + nsEnvironment.cpp \ + nsEventQueue.cpp \ + nsEventQueueService.cpp \ + nsThread.cpp \ + nsTimerImpl.cpp \ + nsProcessCommon.cpp \ + TimerThread.cpp \ + $(NULL) + +EXPORTS = \ + nsAutoLock.h \ + plevent.h \ + nsProcess.h \ + nsEventQueueUtils.h \ + $(NULL) + +XPIDLSRCS = \ + nsIThread.idl \ + nsITimer.idl \ + nsITimerInternal.idl \ + nsITimerManager.idl \ + nsIRunnable.idl \ + nsIEventTarget.idl \ + nsIEventQueue.idl \ + nsIEventQueueService.idl \ + nsIEnvironment.idl \ + nsIProcess.idl \ + $(NULL) + +EXPORTS := $(addprefix $(srcdir)/, $(EXPORTS)) + +LOCAL_INCLUDES = -I$(srcdir)/../components + +# we don't want the shared lib, but we want to force the creation of a static lib. +FORCE_STATIC_LIB = 1 + +# Force use of PIC +FORCE_USE_PIC = 1 + +include $(topsrcdir)/config/rules.mk + +DEFINES += -D_IMPL_NS_COM + diff --git a/src/libs/xpcom18a4/xpcom/threads/TimerThread.cpp b/src/libs/xpcom18a4/xpcom/threads/TimerThread.cpp new file mode 100644 index 00000000..94076892 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/threads/TimerThread.cpp @@ -0,0 +1,462 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Stuart Parmenter + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsTimerImpl.h" +#include "TimerThread.h" + +#include "nsAutoLock.h" +#include "pratom.h" + +#include "nsIObserverService.h" +#include "nsIServiceManager.h" + +NS_IMPL_THREADSAFE_ISUPPORTS3(TimerThread, nsIRunnable, nsISupportsWeakReference, nsIObserver) + +TimerThread::TimerThread() : + mInitInProgress(0), + mInitialized(PR_FALSE), + mLock(nsnull), + mCondVar(nsnull), + mShutdown(PR_FALSE), + mWaiting(PR_FALSE), + mSleeping(PR_FALSE), + mDelayLineCounter(0), + mMinTimerPeriod(0), + mTimeoutAdjustment(0) +{ +} + +TimerThread::~TimerThread() +{ + if (mCondVar) + PR_DestroyCondVar(mCondVar); + if (mLock) + PR_DestroyLock(mLock); + + mThread = nsnull; + + PRInt32 n = mTimers.Count(); + while (--n >= 0) { + nsTimerImpl *timer = NS_STATIC_CAST(nsTimerImpl *, mTimers[n]); + NS_RELEASE(timer); + } + + nsCOMPtr observerService = do_GetService("@mozilla.org/observer-service;1"); + if (observerService) { + observerService->RemoveObserver(this, "sleep_notification"); + observerService->RemoveObserver(this, "wake_notification"); + } + +} + +nsresult +TimerThread::InitLocks() +{ + NS_ASSERTION(!mLock, "InitLocks called twice?"); + mLock = PR_NewLock(); + if (!mLock) + return NS_ERROR_OUT_OF_MEMORY; + + mCondVar = PR_NewCondVar(mLock); + if (!mCondVar) + return NS_ERROR_OUT_OF_MEMORY; + + return NS_OK; +} + +nsresult TimerThread::Init() +{ + if (mInitialized) { + if (!mThread) + return NS_ERROR_FAILURE; + + return NS_OK; + } + + if (PR_AtomicSet(&mInitInProgress, 1) == 0) { + nsresult rv; + + mEventQueueService = do_GetService("@mozilla.org/event-queue-service;1", &rv); + if (NS_SUCCEEDED(rv)) { + nsCOMPtr observerService + (do_GetService("@mozilla.org/observer-service;1", &rv)); + + if (NS_SUCCEEDED(rv)) { + // We hold on to mThread to keep the thread alive. + rv = NS_NewThread(getter_AddRefs(mThread), + NS_STATIC_CAST(nsIRunnable*, this), + 0, + PR_JOINABLE_THREAD, + PR_PRIORITY_NORMAL, + PR_GLOBAL_THREAD); + + if (NS_FAILED(rv)) { + mThread = nsnull; + } + else { + observerService->AddObserver(this, "sleep_notification", PR_TRUE); + observerService->AddObserver(this, "wake_notification", PR_TRUE); + } + } + } + + PR_Lock(mLock); + mInitialized = PR_TRUE; + PR_NotifyAllCondVar(mCondVar); + PR_Unlock(mLock); + } + else { + PR_Lock(mLock); + while (!mInitialized) { + PR_WaitCondVar(mCondVar, PR_INTERVAL_NO_TIMEOUT); + } + PR_Unlock(mLock); + } + + if (!mThread) + return NS_ERROR_FAILURE; + + return NS_OK; +} + +nsresult TimerThread::Shutdown() +{ + if (!mThread) + return NS_ERROR_NOT_INITIALIZED; + + { // lock scope + nsAutoLock lock(mLock); + + mShutdown = PR_TRUE; + + // notify the cond var so that Run() can return + if (mCondVar && mWaiting) + PR_NotifyCondVar(mCondVar); + + nsTimerImpl *timer; + for (PRInt32 i = mTimers.Count() - 1; i >= 0; i--) { + timer = NS_STATIC_CAST(nsTimerImpl*, mTimers[i]); + RemoveTimerInternal(timer); + } + } + + mThread->Join(); // wait for the thread to die + return NS_OK; +} + +// Keep track of how early (positive slack) or late (negative slack) timers +// are running, and use the filtered slack number to adaptively estimate how +// early timers should fire to be "on time". +void TimerThread::UpdateFilter(PRUint32 aDelay, PRIntervalTime aTimeout, + PRIntervalTime aNow) +{ + PRInt32 slack = (PRInt32) (aTimeout - aNow); + double smoothSlack = 0; + PRUint32 i, filterLength; + static PRIntervalTime kFilterFeedbackMaxTicks = + PR_MillisecondsToInterval(FILTER_FEEDBACK_MAX); + + if (slack > 0) { + if (slack > (PRInt32)kFilterFeedbackMaxTicks) + slack = kFilterFeedbackMaxTicks; + } else { + if (slack < -(PRInt32)kFilterFeedbackMaxTicks) + slack = -(PRInt32)kFilterFeedbackMaxTicks; + } + mDelayLine[mDelayLineCounter & DELAY_LINE_LENGTH_MASK] = slack; + if (++mDelayLineCounter < DELAY_LINE_LENGTH) { + // Startup mode: accumulate a full delay line before filtering. + PR_ASSERT(mTimeoutAdjustment == 0); + filterLength = 0; + } else { + // Past startup: compute number of filter taps based on mMinTimerPeriod. + if (mMinTimerPeriod == 0) { + mMinTimerPeriod = (aDelay != 0) ? aDelay : 1; + } else if (aDelay != 0 && aDelay < mMinTimerPeriod) { + mMinTimerPeriod = aDelay; + } + + filterLength = (PRUint32) (FILTER_DURATION / mMinTimerPeriod); + if (filterLength > DELAY_LINE_LENGTH) + filterLength = DELAY_LINE_LENGTH; + else if (filterLength < 4) + filterLength = 4; + + for (i = 1; i <= filterLength; i++) + smoothSlack += mDelayLine[(mDelayLineCounter-i) & DELAY_LINE_LENGTH_MASK]; + smoothSlack /= filterLength; + + // XXXbe do we need amplification? hacking a fudge factor, need testing... + mTimeoutAdjustment = (PRInt32) (smoothSlack * 1.5); + } + +#ifdef DEBUG_TIMERS + if (PR_LOG_TEST(gTimerLog, PR_LOG_DEBUG)) { + PR_LOG(gTimerLog, PR_LOG_DEBUG, + ("UpdateFilter: smoothSlack = %g, filterLength = %u\n", + smoothSlack, filterLength)); + } +#endif +} + +/* void Run(); */ +NS_IMETHODIMP TimerThread::Run() +{ + nsAutoLock lock(mLock); + + while (!mShutdown) { + PRIntervalTime waitFor; + + if (mSleeping) { + // Sleep for 0.1 seconds while not firing timers. + waitFor = PR_MillisecondsToInterval(100); + } else { + waitFor = PR_INTERVAL_NO_TIMEOUT; + PRIntervalTime now = PR_IntervalNow(); + nsTimerImpl *timer = nsnull; + + if (mTimers.Count() > 0) { + timer = NS_STATIC_CAST(nsTimerImpl*, mTimers[0]); + + if (!TIMER_LESS_THAN(now, timer->mTimeout + mTimeoutAdjustment)) { + next: + // NB: AddRef before the Release under RemoveTimerInternal to avoid + // mRefCnt passing through zero, in case all other refs than the one + // from mTimers have gone away (the last non-mTimers[i]-ref's Release + // must be racing with us, blocked in gThread->RemoveTimer waiting + // for TimerThread::mLock, under nsTimerImpl::Release. + + NS_ADDREF(timer); + RemoveTimerInternal(timer); + + // We release mLock around the Fire call to avoid deadlock. + lock.unlock(); + +#ifdef DEBUG_TIMERS + if (PR_LOG_TEST(gTimerLog, PR_LOG_DEBUG)) { + PR_LOG(gTimerLog, PR_LOG_DEBUG, + ("Timer thread woke up %dms from when it was supposed to\n", + (now >= timer->mTimeout) + ? PR_IntervalToMilliseconds(now - timer->mTimeout) + : -(PRInt32)PR_IntervalToMilliseconds(timer->mTimeout-now)) + ); + } +#endif + + // We are going to let the call to PostTimerEvent here handle the + // release of the timer so that we don't end up releasing the timer + // on the TimerThread instead of on the thread it targets. + timer->PostTimerEvent(); + timer = nsnull; + + lock.lock(); + if (mShutdown) + break; + + // Update now, as PostTimerEvent plus the locking may have taken a + // tick or two, and we may goto next below. + now = PR_IntervalNow(); + } + } + + if (mTimers.Count() > 0) { + timer = NS_STATIC_CAST(nsTimerImpl *, mTimers[0]); + + PRIntervalTime timeout = timer->mTimeout + mTimeoutAdjustment; + + // Don't wait at all (even for PR_INTERVAL_NO_WAIT) if the next timer + // is due now or overdue. + if (!TIMER_LESS_THAN(now, timeout)) + goto next; + waitFor = timeout - now; + } + +#ifdef DEBUG_TIMERS + if (PR_LOG_TEST(gTimerLog, PR_LOG_DEBUG)) { + if (waitFor == PR_INTERVAL_NO_TIMEOUT) + PR_LOG(gTimerLog, PR_LOG_DEBUG, + ("waiting for PR_INTERVAL_NO_TIMEOUT\n")); + else + PR_LOG(gTimerLog, PR_LOG_DEBUG, + ("waiting for %u\n", PR_IntervalToMilliseconds(waitFor))); + } +#endif + } + + mWaiting = PR_TRUE; + PR_WaitCondVar(mCondVar, waitFor); + mWaiting = PR_FALSE; + } + + return NS_OK; +} + +nsresult TimerThread::AddTimer(nsTimerImpl *aTimer) +{ + nsAutoLock lock(mLock); + + // Add the timer to our list. + PRInt32 i = AddTimerInternal(aTimer); + if (i < 0) + return NS_ERROR_OUT_OF_MEMORY; + + // Awaken the timer thread. + if (mCondVar && mWaiting && i == 0) + PR_NotifyCondVar(mCondVar); + + return NS_OK; +} + +nsresult TimerThread::TimerDelayChanged(nsTimerImpl *aTimer) +{ + nsAutoLock lock(mLock); + + // Our caller has a strong ref to aTimer, so it can't go away here under + // ReleaseTimerInternal. + RemoveTimerInternal(aTimer); + + PRInt32 i = AddTimerInternal(aTimer); + if (i < 0) + return NS_ERROR_OUT_OF_MEMORY; + + // Awaken the timer thread. + if (mCondVar && mWaiting && i == 0) + PR_NotifyCondVar(mCondVar); + + return NS_OK; +} + +nsresult TimerThread::RemoveTimer(nsTimerImpl *aTimer) +{ + nsAutoLock lock(mLock); + + // Remove the timer from our array. Tell callers that aTimer was not found + // by returning NS_ERROR_NOT_AVAILABLE. Unlike the TimerDelayChanged case + // immediately above, our caller may be passing a (now-)weak ref in via the + // aTimer param, specifically when nsTimerImpl::Release loses a race with + // TimerThread::Run, must wait for the mLock auto-lock here, and during the + // wait Run drops the only remaining ref to aTimer via RemoveTimerInternal. + + if (!RemoveTimerInternal(aTimer)) + return NS_ERROR_NOT_AVAILABLE; + + // Awaken the timer thread. + if (mCondVar && mWaiting) + PR_NotifyCondVar(mCondVar); + + return NS_OK; +} + +// This function must be called from within a lock +PRInt32 TimerThread::AddTimerInternal(nsTimerImpl *aTimer) +{ + PRIntervalTime now = PR_IntervalNow(); + PRInt32 count = mTimers.Count(); + PRInt32 i = 0; + for (; i < count; i++) { + nsTimerImpl *timer = NS_STATIC_CAST(nsTimerImpl *, mTimers[i]); + + // Don't break till we have skipped any overdue timers. Do not include + // mTimeoutAdjustment here, because we are really trying to avoid calling + // TIMER_LESS_THAN(t, u), where the t is now + DELAY_INTERVAL_MAX, u is + // now - overdue, and DELAY_INTERVAL_MAX + overdue > DELAY_INTERVAL_LIMIT. + // In other words, we want to use now-based time, now adjusted time, even + // though "overdue" ultimately depends on adjusted time. + + // XXX does this hold for TYPE_REPEATING_PRECISE? /be + + if (TIMER_LESS_THAN(now, timer->mTimeout) && + TIMER_LESS_THAN(aTimer->mTimeout, timer->mTimeout)) { + break; + } + } + + if (!mTimers.InsertElementAt(aTimer, i)) + return -1; + + aTimer->mArmed = PR_TRUE; + NS_ADDREF(aTimer); + return i; +} + +PRBool TimerThread::RemoveTimerInternal(nsTimerImpl *aTimer) +{ + if (!mTimers.RemoveElement(aTimer)) + return PR_FALSE; + + // Order is crucial here -- see nsTimerImpl::Release. + aTimer->mArmed = PR_FALSE; + NS_RELEASE(aTimer); + return PR_TRUE; +} + +void TimerThread::DoBeforeSleep() +{ + mSleeping = PR_TRUE; +} + +void TimerThread::DoAfterSleep() +{ + for (PRInt32 i = 0; i < mTimers.Count(); i ++) { + nsTimerImpl *timer = NS_STATIC_CAST(nsTimerImpl*, mTimers[i]); + // get and set the delay to cause its timeout to be recomputed + PRUint32 delay; + timer->GetDelay(&delay); + timer->SetDelay(delay); + } + + // nuke the stored adjustments, so they get recalibrated + mTimeoutAdjustment = 0; + mDelayLineCounter = 0; + mSleeping = PR_FALSE; +} + + +/* void observe (in nsISupports aSubject, in string aTopic, in wstring aData); */ +NS_IMETHODIMP +TimerThread::Observe(nsISupports* /* aSubject */, const char *aTopic, const PRUnichar* /* aData */) +{ + if (strcmp(aTopic, "sleep_notification") == 0) + DoBeforeSleep(); + else if (strcmp(aTopic, "wake_notification") == 0) + DoAfterSleep(); + + return NS_OK; +} diff --git a/src/libs/xpcom18a4/xpcom/threads/TimerThread.h b/src/libs/xpcom18a4/xpcom/threads/TimerThread.h new file mode 100644 index 00000000..fa23cfc9 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/threads/TimerThread.h @@ -0,0 +1,122 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Stuart Parmenter + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +#ifndef TimerThread_h___ +#define TimerThread_h___ + +#include "nsWeakReference.h" + +#include "nsIEventQueueService.h" +#include "nsIObserver.h" +#include "nsIRunnable.h" +#include "nsIThread.h" + +#include "nsTimerImpl.h" + +#include "nsVoidArray.h" + +#include "prcvar.h" +#include "prinrval.h" +#include "prlock.h" + +class TimerThread : public nsSupportsWeakReference, + public nsIRunnable, + public nsIObserver +{ +public: + TimerThread(); + NS_HIDDEN_(nsresult) InitLocks(); + + NS_DECL_ISUPPORTS + NS_DECL_NSIRUNNABLE + NS_DECL_NSIOBSERVER + + NS_HIDDEN_(nsresult) Init(); + NS_HIDDEN_(nsresult) Shutdown(); + + nsresult AddTimer(nsTimerImpl *aTimer); + nsresult TimerDelayChanged(nsTimerImpl *aTimer); + nsresult RemoveTimer(nsTimerImpl *aTimer); + +#define FILTER_DURATION 1e3 /* one second */ +#define FILTER_FEEDBACK_MAX 100 /* 1/10th of a second */ + + void UpdateFilter(PRUint32 aDelay, PRIntervalTime aTimeout, + PRIntervalTime aNow); + + // For use by nsTimerImpl::Fire() + nsCOMPtr mEventQueueService; + + void DoBeforeSleep(); + void DoAfterSleep(); + +private: + ~TimerThread(); + + PRInt32 mInitInProgress; + PRBool mInitialized; + + // These two internal helper methods must be called while mLock is held. + // AddTimerInternal returns the position where the timer was added in the + // list, or -1 if it failed. + PRInt32 AddTimerInternal(nsTimerImpl *aTimer); + PRBool RemoveTimerInternal(nsTimerImpl *aTimer); + + nsCOMPtr mThread; + PRLock *mLock; + PRCondVar *mCondVar; + + PRPackedBool mShutdown; + PRPackedBool mWaiting; + PRPackedBool mSleeping; + + nsVoidArray mTimers; + +#define DELAY_LINE_LENGTH_LOG2 5 +#define DELAY_LINE_LENGTH_MASK PR_BITMASK(DELAY_LINE_LENGTH_LOG2) +#define DELAY_LINE_LENGTH PR_BIT(DELAY_LINE_LENGTH_LOG2) + + PRInt32 mDelayLine[DELAY_LINE_LENGTH]; + PRUint32 mDelayLineCounter; + PRUint32 mMinTimerPeriod; // milliseconds + PRInt32 mTimeoutAdjustment; +}; + +#endif /* TimerThread_h___ */ diff --git a/src/libs/xpcom18a4/xpcom/threads/nsAutoLock.cpp b/src/libs/xpcom18a4/xpcom/threads/nsAutoLock.cpp new file mode 100644 index 00000000..df89408c --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/threads/nsAutoLock.cpp @@ -0,0 +1,435 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsAutoLock.h" + +#ifdef DEBUG + +#include "plhash.h" +#include "prprf.h" +#include "prlock.h" +#include "prthread.h" +#include "nsDebug.h" +#include "nsVoidArray.h" + +#ifdef NS_TRACE_MALLOC_XXX +# include +# include "nsTraceMalloc.h" +#endif + +static PRUintn LockStackTPI = (PRUintn)-1; +static PLHashTable* OrderTable = 0; +static PRLock* OrderTableLock = 0; + +static const char* const LockTypeNames[] = {"Lock", "Monitor", "CMonitor"}; + +struct nsNamedVector : public nsVoidArray { + const char* mName; + +#ifdef NS_TRACE_MALLOC_XXX + // Callsites for the inner locks/monitors stored in our base nsVoidArray. + // This array parallels our base nsVoidArray. + nsVoidArray mInnerSites; +#endif + + nsNamedVector(const char* name = 0, PRUint32 initialSize = 0) + : nsVoidArray(initialSize), + mName(name) + { + } +}; + +static void * PR_CALLBACK +_hash_alloc_table(void *pool, PRSize size) +{ + return operator new(size); +} + +static void PR_CALLBACK +_hash_free_table(void *pool, void *item) +{ + operator delete(item); +} + +static PLHashEntry * PR_CALLBACK +_hash_alloc_entry(void *pool, const void *key) +{ + return new PLHashEntry; +} + +/* + * Because monitors and locks may be associated with an nsAutoLockBase, + * without having had their associated nsNamedVector created explicitly in + * nsAutoMonitor::NewMonitor/DeleteMonitor, we need to provide a freeEntry + * PLHashTable hook, to avoid leaking nsNamedVectors which are replaced by + * nsAutoMonitor::NewMonitor. + * + * There is still a problem with the OrderTable containing orphaned + * nsNamedVector entries, for manually created locks wrapped by nsAutoLocks. + * (there should be no manually created monitors wrapped by nsAutoMonitors: + * you should use nsAutoMonitor::NewMonitor and nsAutoMonitor::DestroyMonitor + * instead of PR_NewMonitor and PR_DestroyMonitor). These lock vectors don't + * strictly leak, as they are killed on shutdown, but there are unnecessary + * named vectors in the hash table that outlive their associated locks. + * + * XXX so we should have nsLock, nsMonitor, etc. and strongly type their + * XXX nsAutoXXX counterparts to take only the non-auto types as inputs + */ +static void PR_CALLBACK +_hash_free_entry(void *pool, PLHashEntry *entry, PRUintn flag) +{ + nsNamedVector* vec = (nsNamedVector*) entry->value; + if (vec) { + entry->value = 0; + delete vec; + } + if (flag == HT_FREE_ENTRY) + delete entry; +} + +static const PLHashAllocOps _hash_alloc_ops = { + _hash_alloc_table, _hash_free_table, + _hash_alloc_entry, _hash_free_entry +}; + +PR_STATIC_CALLBACK(PRIntn) +_purge_one(PLHashEntry* he, PRIntn cnt, void* arg) +{ + nsNamedVector* vec = (nsNamedVector*) he->value; + + if (he->key == arg) + return HT_ENUMERATE_REMOVE; + vec->RemoveElement(arg); + return HT_ENUMERATE_NEXT; +} + +PR_STATIC_CALLBACK(void) +OnMonitorRecycle(void* addr) +{ + PR_Lock(OrderTableLock); + PL_HashTableEnumerateEntries(OrderTable, _purge_one, addr); + PR_Unlock(OrderTableLock); +} + +PR_STATIC_CALLBACK(PLHashNumber) +_hash_pointer(const void* key) +{ + return PLHashNumber(NS_PTR_TO_INT32(key)) >> 2; +} + +// Must be single-threaded here, early in primordial thread. +static void InitAutoLockStatics() +{ + (void) PR_NewThreadPrivateIndex(&LockStackTPI, 0); + OrderTable = PL_NewHashTable(64, _hash_pointer, + PL_CompareValues, PL_CompareValues, + &_hash_alloc_ops, 0); + if (OrderTable && !(OrderTableLock = PR_NewLock())) { + PL_HashTableDestroy(OrderTable); + OrderTable = 0; + } + PR_CSetOnMonitorRecycle(OnMonitorRecycle); +} + +void _FreeAutoLockStatics() +{ + PLHashTable* table = OrderTable; + if (!table) return; + + // Called at shutdown, so we don't need to lock. + PR_CSetOnMonitorRecycle(0); + PR_DestroyLock(OrderTableLock); + OrderTableLock = 0; + PL_HashTableDestroy(table); + OrderTable = 0; +} + +static nsNamedVector* GetVector(PLHashTable* table, const void* key) +{ + PLHashNumber hash = _hash_pointer(key); + PLHashEntry** hep = PL_HashTableRawLookup(table, hash, key); + PLHashEntry* he = *hep; + if (he) + return (nsNamedVector*) he->value; + nsNamedVector* vec = new nsNamedVector(); + if (vec) + PL_HashTableRawAdd(table, hep, hash, key, vec); + return vec; +} + +// We maintain an acyclic graph in OrderTable, so recursion can't diverge. +static PRBool Reachable(PLHashTable* table, const void* goal, const void* start) +{ + PR_ASSERT(goal); + PR_ASSERT(start); + nsNamedVector* vec = GetVector(table, start); + for (PRUint32 i = 0, n = vec->Count(); i < n; i++) { + void* addr = vec->ElementAt(i); + if (addr == goal || Reachable(table, goal, addr)) + return PR_TRUE; + } + return PR_FALSE; +} + +static PRBool WellOrdered(const void* addr1, const void* addr2, + const void *callsite2, PRUint32* index2p, + nsNamedVector** vec1p, nsNamedVector** vec2p) +{ + PRBool rv = PR_TRUE; + PLHashTable* table = OrderTable; + if (!table) return rv; + PR_Lock(OrderTableLock); + + // Check whether we've already asserted (addr1 < addr2). + nsNamedVector* vec1 = GetVector(table, addr1); + if (vec1) { + PRUint32 i, n; + + for (i = 0, n = vec1->Count(); i < n; i++) + if (vec1->ElementAt(i) == addr2) + break; + + if (i == n) { + // Now check for (addr2 < addr1) and return false if so. + nsNamedVector* vec2 = GetVector(table, addr2); + if (vec2) { + for (i = 0, n = vec2->Count(); i < n; i++) { + void* addri = vec2->ElementAt(i); + PR_ASSERT(addri); + if (addri == addr1 || Reachable(table, addr1, addri)) { + *index2p = i; + *vec1p = vec1; + *vec2p = vec2; + rv = PR_FALSE; + break; + } + } + + if (rv) { + // Assert (addr1 < addr2) into the order table. + // XXX fix plvector/nsVector to use const void* + vec1->AppendElement((void*) addr2); +#ifdef NS_TRACE_MALLOC_XXX + vec1->mInnerSites.AppendElement((void*) callsite2); +#endif + } + } + } + } + + PR_Unlock(OrderTableLock); + return rv; +} + +nsAutoLockBase::nsAutoLockBase(void* addr, nsAutoLockType type) +{ + if (LockStackTPI == PRUintn(-1)) + InitAutoLockStatics(); + + nsAutoLockBase* stackTop = + (nsAutoLockBase*) PR_GetThreadPrivate(LockStackTPI); + if (stackTop) { + if (stackTop->mAddr == addr) { + // Ignore reentry: it's legal for monitors, and NSPR will assert + // if you reenter a PRLock. + } else if (!addr) { + // Ignore null addresses: the caller promises not to use the + // lock at all, and NSPR will assert if you enter it. + } else { + const void* node = +#ifdef NS_TRACE_MALLOC_XXX + NS_GetStackTrace(1) +#else + nsnull +#endif + ; + nsNamedVector* vec1; + nsNamedVector* vec2; + PRUint32 i2; + + if (!WellOrdered(stackTop->mAddr, addr, node, &i2, &vec1, &vec2)) { + char buf[128]; + PR_snprintf(buf, sizeof buf, + "Potential deadlock between %s%s@%p and %s%s@%p", + vec1->mName ? vec1->mName : "", + LockTypeNames[stackTop->mType], + stackTop->mAddr, + vec2->mName ? vec2->mName : "", + LockTypeNames[type], + addr); +#ifdef NS_TRACE_MALLOC_XXX + fprintf(stderr, "\n*** %s\n\nCurrent stack:\n", buf); + NS_DumpStackTrace(node, stderr); + + fputs("\nPrevious stack:\n", stderr); + NS_DumpStackTrace(vec2->mInnerSites.ElementAt(i2), stderr); + putc('\n', stderr); +#endif + NS_ERROR(buf); + } + } + } + + mAddr = addr; + mDown = stackTop; + mType = type; + if (mAddr) + (void) PR_SetThreadPrivate(LockStackTPI, this); +} + +nsAutoLockBase::~nsAutoLockBase() +{ + if (mAddr) + (void) PR_SetThreadPrivate(LockStackTPI, mDown); +} + +void nsAutoLockBase::Show() +{ + if (!mAddr) + return; + nsAutoLockBase* curr = (nsAutoLockBase*) PR_GetThreadPrivate(LockStackTPI); + nsAutoLockBase* prev = nsnull; + while (curr != mDown) { + prev = curr; + curr = prev->mDown; + } + if (!prev) + PR_SetThreadPrivate(LockStackTPI, this); + else + prev->mDown = this; +} + +void nsAutoLockBase::Hide() +{ + if (!mAddr) + return; + nsAutoLockBase* curr = (nsAutoLockBase*) PR_GetThreadPrivate(LockStackTPI); + nsAutoLockBase* prev = nsnull; + while (curr != this) { + prev = curr; + curr = prev->mDown; + } + if (!prev) + PR_SetThreadPrivate(LockStackTPI, mDown); + else + prev->mDown = mDown; +} + +#endif /* DEBUG */ + +PRMonitor* nsAutoMonitor::NewMonitor(const char* name) +{ + PRMonitor* mon = PR_NewMonitor(); +#ifdef DEBUG + if (mon && OrderTable) { + nsNamedVector* value = new nsNamedVector(name); + if (value) { + PR_Lock(OrderTableLock); + PL_HashTableAdd(OrderTable, mon, value); + PR_Unlock(OrderTableLock); + } + } +#endif + return mon; +} + +void nsAutoMonitor::DestroyMonitor(PRMonitor* mon) +{ +#ifdef DEBUG + if (OrderTable) + OnMonitorRecycle(mon); +#endif + PR_DestroyMonitor(mon); +} + +void nsAutoMonitor::Enter() +{ +#ifdef DEBUG + if (!mAddr) { + NS_ERROR("It is not legal to enter a null monitor"); + return; + } + nsAutoLockBase* stackTop = + (nsAutoLockBase*) PR_GetThreadPrivate(LockStackTPI); + NS_ASSERTION(stackTop == mDown, "non-LIFO nsAutoMonitor::Enter"); + mDown = stackTop; + (void) PR_SetThreadPrivate(LockStackTPI, this); +#endif + PR_EnterMonitor(mMonitor); + mLockCount += 1; +} + +void nsAutoMonitor::Exit() +{ +#ifdef DEBUG + if (!mAddr) { + NS_ERROR("It is not legal to exit a null monitor"); + return; + } + (void) PR_SetThreadPrivate(LockStackTPI, mDown); +#endif + PRStatus status = PR_ExitMonitor(mMonitor); + NS_ASSERTION(status == PR_SUCCESS, "PR_ExitMonitor failed"); + mLockCount -= 1; +} + +// XXX we don't worry about cached monitors being destroyed behind our back. +// XXX current NSPR (mozilla/nsprpub/pr/src/threads/prcmon.c) never destroys +// XXX a cached monitor! potential resource pig in conjunction with necko... + +void nsAutoCMonitor::Enter() +{ +#ifdef DEBUG + nsAutoLockBase* stackTop = + (nsAutoLockBase*) PR_GetThreadPrivate(LockStackTPI); + NS_ASSERTION(stackTop == mDown, "non-LIFO nsAutoCMonitor::Enter"); + mDown = stackTop; + (void) PR_SetThreadPrivate(LockStackTPI, this); +#endif + PR_CEnterMonitor(mLockObject); + mLockCount += 1; +} + +void nsAutoCMonitor::Exit() +{ +#ifdef DEBUG + (void) PR_SetThreadPrivate(LockStackTPI, mDown); +#endif + PRStatus status = PR_CExitMonitor(mLockObject); + NS_ASSERTION(status == PR_SUCCESS, "PR_CExitMonitor failed"); + mLockCount -= 1; +} diff --git a/src/libs/xpcom18a4/xpcom/threads/nsAutoLock.h b/src/libs/xpcom18a4/xpcom/threads/nsAutoLock.h new file mode 100644 index 00000000..a82d6ffc --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/threads/nsAutoLock.h @@ -0,0 +1,383 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + + +/* + A stack-based lock object that makes using PRLock a bit more + convenient. It acquires the monitor when constructed, and releases + it when it goes out of scope. + + For example, + + class Foo { + private: + PRLock* mLock; + + public: + Foo(void) { + mLock = PR_NewLock(); + } + + ~Foo(void) { + PR_DestroyLock(mLock); + } + + void ThreadSafeMethod(void) { + // we're don't hold the lock yet... + + nsAutoLock lock(mLock); + // ...but now we do. + + // we even can do wacky stuff like return from arbitrary places w/o + // worrying about forgetting to release the lock + if (some_weird_condition) + return; + + // otherwise do some other stuff + } + + void ThreadSafeBlockScope(void) { + // we're not in the lock here... + + { + nsAutoLock lock(mLock); + // but we are now, at least until the block scope closes + } + + // ...now we're not in the lock anymore + } + }; + + A similar stack-based locking object is available for PRMonitor. The + major difference is that the PRMonitor must be created and destroyed + via the static methods on nsAutoMonitor. + + For example: + Foo::Foo() { + mMon = nsAutoMonitor::NewMonitor("FooMonitor"); + } + nsresult Foo::MyMethod(...) { + nsAutoMonitor mon(mMon); + ... + // go ahead and do deeply nested returns... + return NS_ERROR_FAILURE; + ... + // or call Wait or Notify... + mon.Wait(); + ... + // cleanup is automatic + } + */ + +#ifndef nsAutoLock_h__ +#define nsAutoLock_h__ + +#include "nscore.h" +#include "prlock.h" +#include "prlog.h" + +/** + * nsAutoLockBase + * This is the base class for the stack-based locking objects. + * Clients of derived classes need not play with this superclass. + **/ +class NS_COM nsAutoLockBase { +protected: + nsAutoLockBase() {} + enum nsAutoLockType {eAutoLock, eAutoMonitor, eAutoCMonitor}; + +#ifdef DEBUG + nsAutoLockBase(void* addr, nsAutoLockType type); + ~nsAutoLockBase(); + + void Show(); + void Hide(); + + void* mAddr; + nsAutoLockBase* mDown; + nsAutoLockType mType; +#else + nsAutoLockBase(void* addr, nsAutoLockType type) {} + ~nsAutoLockBase() {} + + void Show() {} + void Hide() {} +#endif +}; + +/** + * nsAutoLock + * Stack-based locking object for PRLock. + **/ +class NS_COM nsAutoLock : public nsAutoLockBase { +private: + PRLock* mLock; + PRBool mLocked; + + // Not meant to be implemented. This makes it a compiler error to + // construct or assign an nsAutoLock object incorrectly. + nsAutoLock(void); + nsAutoLock(const nsAutoLock& /*aLock*/); + nsAutoLock& operator =(const nsAutoLock& /*aLock*/); + + // Not meant to be implemented. This makes it a compiler error to + // attempt to create an nsAutoLock object on the heap. + static void* operator new(size_t /*size*/) CPP_THROW_NEW; + static void operator delete(void* /*memory*/); + +public: + /** + * Constructor + * The constructor aquires the given lock. The destructor + * releases the lock. + * + * @param aLock A valid PRLock* returned from the NSPR's + * PR_NewLock() function. + **/ + nsAutoLock(PRLock* aLock) + : nsAutoLockBase(aLock, eAutoLock), + mLock(aLock), + mLocked(PR_TRUE) { + PR_ASSERT(mLock); + + // This will assert deep in the bowels of NSPR if you attempt + // to re-enter the lock. + PR_Lock(mLock); + } + + ~nsAutoLock(void) { + if (mLocked) + PR_Unlock(mLock); + } + + /** + * lock + * Client may call this to reaquire the given lock. Take special + * note that attempting to aquire a locked lock will hang or crash. + **/ + void lock() { + Show(); + PR_ASSERT(!mLocked); + PR_Lock(mLock); + mLocked = PR_TRUE; + } + + + /** + * unlock + * Client may call this to release the given lock. Take special + * note unlocking an unlocked lock has undefined results. + **/ + void unlock() { + PR_ASSERT(mLocked); + PR_Unlock(mLock); + mLocked = PR_FALSE; + Hide(); + } +}; + +#include "prcmon.h" +#include "nsError.h" +#include "nsDebug.h" + +class NS_COM nsAutoMonitor : public nsAutoLockBase { +public: + + /** + * NewMonitor + * Allocates a new PRMonitor for use with nsAutoMonitor. + * @param name A (unique /be?) name which can reference this monitor + * @returns nsnull if failure + * A valid PRMonitor* is successful while must be destroyed + * by nsAutoMonitor::DestroyMonitor() + **/ + static PRMonitor* NewMonitor(const char* name); + static void DestroyMonitor(PRMonitor* mon); + + + /** + * Constructor + * The constructor locks the given monitor. During destruction + * the monitor will be unlocked. + * + * @param mon A valid PRMonitor* returned from + * nsAutoMonitor::NewMonitor(). + **/ + nsAutoMonitor(PRMonitor* mon) + : nsAutoLockBase((void*)mon, eAutoMonitor), + mMonitor(mon), mLockCount(0) + { + NS_ASSERTION(mMonitor, "null monitor"); + if (mMonitor) { + PR_EnterMonitor(mMonitor); + mLockCount = 1; + } + } + + ~nsAutoMonitor() { + NS_ASSERTION(mMonitor, "null monitor"); + if (mMonitor && mLockCount) { +#ifdef DEBUG + PRStatus status = +#endif + PR_ExitMonitor(mMonitor); + NS_ASSERTION(status == PR_SUCCESS, "PR_ExitMonitor failed"); + } + } + + /** + * Enter + * Client may call this to reenter the given monitor. + * @see prmon.h + **/ + void Enter(); + + /** + * Exit + * Client may call this to exit the given monitor. + * @see prmon.h + **/ + void Exit(); + + /** + * Wait + * @see prmon.h + **/ + nsresult Wait(PRIntervalTime interval = PR_INTERVAL_NO_TIMEOUT) { + return PR_Wait(mMonitor, interval) == PR_SUCCESS + ? NS_OK : NS_ERROR_FAILURE; + } + + /** + * Notify + * @see prmon.h + **/ + nsresult Notify() { + return PR_Notify(mMonitor) == PR_SUCCESS + ? NS_OK : NS_ERROR_FAILURE; + } + + /** + * NotifyAll + * @see prmon.h + **/ + nsresult NotifyAll() { + return PR_NotifyAll(mMonitor) == PR_SUCCESS + ? NS_OK : NS_ERROR_FAILURE; + } + +private: + PRMonitor* mMonitor; + PRInt32 mLockCount; + + // Not meant to be implemented. This makes it a compiler error to + // construct or assign an nsAutoLock object incorrectly. + nsAutoMonitor(void); + nsAutoMonitor(const nsAutoMonitor& /*aMon*/); + nsAutoMonitor& operator =(const nsAutoMonitor& /*aMon*/); + + // Not meant to be implemented. This makes it a compiler error to + // attempt to create an nsAutoLock object on the heap. + static void* operator new(size_t /*size*/) CPP_THROW_NEW; + static void operator delete(void* /*memory*/); +}; + +//////////////////////////////////////////////////////////////////////////////// +// Once again, this time with a cache... +// (Using this avoids the need to allocate a PRMonitor, which may be useful when +// a large number of objects of the same class need associated monitors.) + +#include "prcmon.h" +#include "nsError.h" + +class NS_COM nsAutoCMonitor : public nsAutoLockBase { +public: + nsAutoCMonitor(void* lockObject) + : nsAutoLockBase(lockObject, eAutoCMonitor), + mLockObject(lockObject), mLockCount(0) + { + NS_ASSERTION(lockObject, "null lock object"); + PR_CEnterMonitor(mLockObject); + mLockCount = 1; + } + + ~nsAutoCMonitor() { + if (mLockCount) { +#ifdef DEBUG + PRStatus status = +#endif + PR_CExitMonitor(mLockObject); + NS_ASSERTION(status == PR_SUCCESS, "PR_CExitMonitor failed"); + } + } + + void Enter(); + void Exit(); + + nsresult Wait(PRIntervalTime interval = PR_INTERVAL_NO_TIMEOUT) { + return PR_CWait(mLockObject, interval) == PR_SUCCESS + ? NS_OK : NS_ERROR_FAILURE; + } + + nsresult Notify() { + return PR_CNotify(mLockObject) == PR_SUCCESS + ? NS_OK : NS_ERROR_FAILURE; + } + + nsresult NotifyAll() { + return PR_CNotifyAll(mLockObject) == PR_SUCCESS + ? NS_OK : NS_ERROR_FAILURE; + } + +private: + void* mLockObject; + PRInt32 mLockCount; + + // Not meant to be implemented. This makes it a compiler error to + // construct or assign an nsAutoLock object incorrectly. + nsAutoCMonitor(void); + nsAutoCMonitor(const nsAutoCMonitor& /*aMon*/); + nsAutoCMonitor& operator =(const nsAutoCMonitor& /*aMon*/); + + // Not meant to be implemented. This makes it a compiler error to + // attempt to create an nsAutoLock object on the heap. + static void* operator new(size_t /*size*/) CPP_THROW_NEW; + static void operator delete(void* /*memory*/); +}; + +#endif // nsAutoLock_h__ + diff --git a/src/libs/xpcom18a4/xpcom/threads/nsEnvironment.cpp b/src/libs/xpcom18a4/xpcom/threads/nsEnvironment.cpp new file mode 100644 index 00000000..139b24a6 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/threads/nsEnvironment.cpp @@ -0,0 +1,202 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 embedding code. + * + * The Initial Developers of the Original Code are + * Benjamin Smedberg and + * Roland Mainz . + * + * Portions created by the Initial Developer are Copyright (C) 2003/2004 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * 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 "nsEnvironment.h" +#include "prenv.h" +#include "prprf.h" +#include "nsAutoLock.h" +#include "nsBaseHashtable.h" +#include "nsHashKeys.h" +#include "nsPromiseFlatString.h" +#include "nsDependentString.h" +#include "nsNativeCharsetUtils.h" + +NS_IMPL_THREADSAFE_ISUPPORTS1(nsEnvironment, nsIEnvironment) + +NS_METHOD +nsEnvironment::Create(nsISupports *aOuter, REFNSIID aIID, + void **aResult) +{ + nsresult rv; + *aResult = nsnull; + + if (aOuter != nsnull) { + return NS_ERROR_NO_AGGREGATION; + } + + nsEnvironment* obj = new nsEnvironment(); + if (!obj) { + return NS_ERROR_OUT_OF_MEMORY; + } + + obj->mLock = PR_NewLock(); + if (!obj->mLock) { + delete obj; + return NS_ERROR_OUT_OF_MEMORY; + } + + rv = obj->QueryInterface(aIID, aResult); + if (NS_FAILED(rv)) { + delete obj; + } + return rv; +} + +nsEnvironment::~nsEnvironment() +{ + if (mLock) + PR_DestroyLock(mLock); +} + +NS_IMETHODIMP +nsEnvironment::Exists(const nsAString& aName, PRBool *aOutValue) +{ + nsCAutoString nativeName; + nsresult rv = NS_CopyUnicodeToNative(aName, nativeName); + NS_ENSURE_SUCCESS(rv, rv); + + nsCAutoString nativeVal; +#if defined(XP_UNIX) + /* For Unix/Linux platforms we follow the Unix definition: + * An environment variable exists when |getenv()| returns a non-NULL value. + * An environment variable does not exist when |getenv()| returns NULL. + */ + const char *value = PR_GetEnv(nativeName.get()); + + *aOutValue = (value)?(PR_TRUE):(PR_FALSE); +#else + /* For non-Unix/Linux platforms we have to fall back to a + * "portable" definition (which is incorrect for Unix/Linux!!!!) + * which simply checks whether the string returned by |Get()| is empty + * or not. + */ + nsAutoString value; + Get(aName, value); + *aOutValue = (value.IsEmpty())?(PR_FALSE):(PR_TRUE); +#endif /* XP_UNIX */ + + return NS_OK; +} + +NS_IMETHODIMP +nsEnvironment::Get(const nsAString& aName, nsAString& aOutValue) +{ + nsCAutoString nativeName; + nsresult rv = NS_CopyUnicodeToNative(aName, nativeName); + NS_ENSURE_SUCCESS(rv, rv); + + nsCAutoString nativeVal; + const char *value = PR_GetEnv(nativeName.get()); + if (value) { + rv = NS_CopyNativeToUnicode(nsDependentCString(value), aOutValue); + } else { + aOutValue.Truncate(); + rv = NS_OK; + } + + return rv; +} + +/* Environment strings must have static duration; We're gonna leak all of this + * at shutdown: this is by design, caused how Unix/Linux implement environment + * vars. + */ + +typedef nsBaseHashtableET EnvEntryType; +typedef nsTHashtable EnvHashType; + +static EnvHashType *gEnvHash = nsnull; + +static PRBool +EnsureEnvHash() +{ + if (gEnvHash) + return PR_TRUE; + + gEnvHash = new EnvHashType; + if (!gEnvHash) + return PR_FALSE; + + if(gEnvHash->Init()) + return PR_TRUE; + + delete gEnvHash; + gEnvHash = nsnull; + return PR_FALSE; +} + +NS_IMETHODIMP +nsEnvironment::Set(const nsAString& aName, const nsAString& aValue) +{ + nsCAutoString nativeName; + nsCAutoString nativeVal; + + nsresult rv = NS_CopyUnicodeToNative(aName, nativeName); + NS_ENSURE_SUCCESS(rv, rv); + + rv = NS_CopyUnicodeToNative(aValue, nativeVal); + NS_ENSURE_SUCCESS(rv, rv); + + nsAutoLock lock(mLock); // autolock unlocks automagically + + if (!EnsureEnvHash()){ + return NS_ERROR_UNEXPECTED; + } + + EnvEntryType* entry = gEnvHash->PutEntry(nativeName); + if (!entry) { + return NS_ERROR_OUT_OF_MEMORY; + } + + char* newData = PR_smprintf("%s=%s", + nativeName.get(), + nativeVal.get()); + if (!newData) { + return NS_ERROR_OUT_OF_MEMORY; + } + + PR_SetEnv(newData); + if (entry->mData) { + PR_smprintf_free(entry->mData); + } + entry->mData = newData; + return NS_OK; +} + + diff --git a/src/libs/xpcom18a4/xpcom/threads/nsEnvironment.h b/src/libs/xpcom18a4/xpcom/threads/nsEnvironment.h new file mode 100644 index 00000000..46e8d66a --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/threads/nsEnvironment.h @@ -0,0 +1,67 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 embedding code. + * + * The Initial Developers of the Original Code are + * Benjamin Smedberg and + * Roland Mainz . + * + * Portions created by the Initial Developer are Copyright (C) 2003/2004 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * 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 ***** */ + +#ifndef nsEnvironment_h__ +#define nsEnvironment_h__ + +#include "nsIEnvironment.h" +#include "prlock.h" + +#define NS_ENVIRONMENT_CID \ + { 0X3D68F92UL, 0X9513, 0X4E25, \ + { 0X9B, 0XE9, 0X7C, 0XB2, 0X39, 0X87, 0X41, 0X72 } } +#define NS_ENVIRONMENT_CONTRACTID "@mozilla.org/process/environment;1" + +class nsEnvironment : public nsIEnvironment +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIENVIRONMENT + + static NS_METHOD Create(nsISupports *aOuter, REFNSIID aIID, + void **aResult); + +private: + nsEnvironment() { } + ~nsEnvironment(); + + PRLock *mLock; +}; + +#endif /* !nsEnvironment_h__ */ diff --git a/src/libs/xpcom18a4/xpcom/threads/nsEventQueue.cpp b/src/libs/xpcom18a4/xpcom/threads/nsEventQueue.cpp new file mode 100644 index 00000000..7dc8f089 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/threads/nsEventQueue.cpp @@ -0,0 +1,632 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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 Communicator client code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsCOMPtr.h" +#include "nsEventQueue.h" +#include "nsIEventQueueService.h" +#include "nsIThread.h" + +#include "nsIServiceManager.h" +#include "nsIObserverService.h" + +#include "nsString.h" + +#include "prlog.h" + +#ifdef NS_DEBUG +#include "prprf.h" +#endif + +#if defined(PR_LOGGING) && defined(DEBUG_danm) +/* found these logs useful in conjunction with netlibStreamEvent logging + from netwerk. */ +PRLogModuleInfo* gEventQueueLog = 0; +PRUint32 gEventQueueLogCount = 0; +PRUint32 gEventQueueLogPPCount = 0; +static int gEventQueueLogPPLevel = 0; +static PLEventQueue *gEventQueueLogQueue = 0; +static PRThread *gEventQueueLogThread = 0; +#endif + +// in a real system, these would be members in a header class... +static const char gActivatedNotification[] = "nsIEventQueueActivated"; +static const char gDestroyedNotification[] = "nsIEventQueueDestroyed"; + +nsEventQueueImpl::nsEventQueueImpl() +{ + NS_ADDREF_THIS(); + /* The slightly weird ownership model for eventqueues goes like this: + + General: + There's an addref from the factory generally held by whoever asked for + the queue. The queue addrefs itself (right here) and releases itself + after someone calls StopAcceptingEvents() on the queue and when it is + dark and empty (in CheckForDeactivation()). + + Chained queues: + + Eldest queue: + The eldest queue in a chain is held on to by the EventQueueService + in a hash table, so it is possible that the eldest queue may not be + released until the EventQueueService is shutdown. + You may not call StopAcceptingEvents() on this queue until you have + done so on all younger queues. + + General: + Each queue holds a reference to their immediate elder link and a weak + reference to their immediate younger link. Because you must shut down + queues from youngest to eldest, all the references will be removed. + + It happens something like: + queue->StopAcceptingEvents() + { + CheckForDeactivation() + { + -- hopefully we are able to shutdown now -- + Unlink() + { + -- remove the reference we hold to our elder queue -- + -- NULL out our elder queues weak reference to us -- + } + RELEASE ourself (to balance the ADDREF here in the constructor) + -- and we should go away. -- + } + } + + + Notes: + A dark queue no longer accepts events. An empty queue simply has no events. + */ + +#if defined(PR_LOGGING) && defined(DEBUG_danm) + PR_LOG(gEventQueueLog, PR_LOG_DEBUG, + ("EventQueue: Created [queue=%lx]",(long)mEventQueue)); + ++gEventQueueLogCount; +#endif + + mYoungerQueue = nsnull; + mEventQueue = nsnull; + mAcceptingEvents = PR_TRUE; + mCouldHaveEvents = PR_TRUE; +} + +nsEventQueueImpl::~nsEventQueueImpl() +{ + Unlink(); + +#if defined(PR_LOGGING) && defined(DEBUG_danm) + PR_LOG(gEventQueueLog, PR_LOG_DEBUG, + ("EventQueue: Destroyed [queue=%lx]",(long)mEventQueue)); + ++gEventQueueLogCount; +#endif + + if (mEventQueue) { + NotifyObservers(gDestroyedNotification); + PL_DestroyEventQueue(mEventQueue); + } +} + +NS_IMETHODIMP +nsEventQueueImpl::Init(PRBool aNative) +{ + PRThread *thread = PR_GetCurrentThread(); + if (aNative) + mEventQueue = PL_CreateNativeEventQueue("Thread event queue...", thread); + else + mEventQueue = PL_CreateMonitoredEventQueue("Thread event queue...", thread); + NotifyObservers(gActivatedNotification); + return NS_OK; +} + +NS_IMETHODIMP +nsEventQueueImpl::InitFromPRThread(PRThread* thread, PRBool aNative) +{ + if (thread == NS_CURRENT_THREAD) + { + thread = PR_GetCurrentThread(); + } + else if (thread == NS_UI_THREAD) + { + nsCOMPtr mainIThread; + nsresult rv; + + // Get the primordial thread + rv = nsIThread::GetMainThread(getter_AddRefs(mainIThread)); + if (NS_FAILED(rv)) return rv; + + rv = mainIThread->GetPRThread(&thread); + if (NS_FAILED(rv)) return rv; + } + + if (aNative) + mEventQueue = PL_CreateNativeEventQueue("Thread event queue...", thread); + else + mEventQueue = PL_CreateMonitoredEventQueue("Thread event queue...", thread); + NotifyObservers(gActivatedNotification); + return NS_OK; +} + +NS_IMETHODIMP +nsEventQueueImpl::InitFromPLQueue(PLEventQueue* aQueue) +{ + mEventQueue = aQueue; + NotifyObservers(gActivatedNotification); + return NS_OK; +} + +/* nsISupports interface implementation... */ +NS_IMPL_THREADSAFE_ISUPPORTS3(nsEventQueueImpl, + nsIEventQueue, + nsIEventTarget, + nsPIEventQueueChain) + +/* nsIEventQueue interface implementation... */ + +NS_IMETHODIMP +nsEventQueueImpl::StopAcceptingEvents() +{ + // this assertion is bogus. I should be able to shut down the eldest queue, + // as long as there are no younger children + + + NS_ASSERTION(mElderQueue || !mYoungerQueue, "attempted to disable eldest queue in chain"); + mAcceptingEvents = PR_FALSE; + CheckForDeactivation(); +#if defined(PR_LOGGING) && defined(DEBUG_danm) + PR_LOG(gEventQueueLog, PR_LOG_DEBUG, + ("EventQueue: StopAccepting [queue=%lx, accept=%d, could=%d]", + (long)mEventQueue,(int)mAcceptingEvents,(int)mCouldHaveEvents)); + ++gEventQueueLogCount; +#endif + return NS_OK; +} + +// utility funtion to send observers a notification +void +nsEventQueueImpl::NotifyObservers(const char *aTopic) +{ + nsresult rv; + + nsCOMPtr os = do_GetService("@mozilla.org/observer-service;1", &rv); + if (NS_SUCCEEDED(rv)) { + nsCOMPtr kungFuDeathGrip(this); + nsCOMPtr us(do_QueryInterface(kungFuDeathGrip)); + os->NotifyObservers(us, aTopic, NULL); + } +} + + +NS_IMETHODIMP +nsEventQueueImpl::InitEvent(PLEvent* aEvent, + void* owner, + PLHandleEventProc handler, + PLDestroyEventProc destructor) +{ + PL_InitEvent(aEvent, owner, handler, destructor); + return NS_OK; +} + + +NS_IMETHODIMP +nsEventQueueImpl::PostEvent(PLEvent* aEvent) +{ + if (!mAcceptingEvents) { +#if defined(PR_LOGGING) && defined(DEBUG_danm) + PR_LOG(gEventQueueLog, PR_LOG_DEBUG, + ("EventQueue: Punt posted event [queue=%lx, accept=%d, could=%d]", + (long)mEventQueue,(int)mAcceptingEvents,(int)mCouldHaveEvents)); + ++gEventQueueLogCount; +#endif + nsresult rv = NS_ERROR_FAILURE; + NS_ASSERTION(mElderQueue, "event dropped because event chain is dead"); + if (mElderQueue) { + nsCOMPtr elder(do_QueryInterface(mElderQueue)); + if (elder) + rv = elder->PostEvent(aEvent); + } + return rv; + } +#if defined(PR_LOGGING) && defined(DEBUG_danm) + PR_LOG(gEventQueueLog, PR_LOG_DEBUG, + ("EventQueue: Posting event [queue=%lx]", (long)mEventQueue)); + ++gEventQueueLogCount; +#endif + return PL_PostEvent(mEventQueue, aEvent) == PR_SUCCESS ? NS_OK : NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +nsEventQueueImpl::PostSynchronousEvent(PLEvent* aEvent, void** aResult) +{ + if (!mAcceptingEvents) { +#if defined(PR_LOGGING) && defined(DEBUG_danm) + PR_LOG(gEventQueueLog, PR_LOG_DEBUG, + ("EventQueue: Punt posted synchronous event [queue=%lx, accept=%d, could=%d]", + (long)mEventQueue,(int)mAcceptingEvents,(int)mCouldHaveEvents)); + ++gEventQueueLogCount; +#endif + nsresult rv = NS_ERROR_NO_INTERFACE; + NS_ASSERTION(mElderQueue, "event dropped because event chain is dead"); + if (mElderQueue) { + nsCOMPtr elder(do_QueryInterface(mElderQueue)); + if (elder) + rv = elder->PostSynchronousEvent(aEvent, aResult); + return rv; + } + return NS_ERROR_ABORT; + } + +#if defined(PR_LOGGING) && defined(DEBUG_danm) + PR_LOG(gEventQueueLog, PR_LOG_DEBUG, + ("EventQueue: Posting synchronous event [queue=%lx]", (long)mEventQueue)); + ++gEventQueueLogCount; +#endif + void* result = PL_PostSynchronousEvent(mEventQueue, aEvent); + if (aResult) + *aResult = result; + + return NS_OK; +} + +NS_IMETHODIMP +nsEventQueueImpl::EnterMonitor() +{ + PL_ENTER_EVENT_QUEUE_MONITOR(mEventQueue); + return NS_OK; +} + +NS_IMETHODIMP +nsEventQueueImpl::ExitMonitor() +{ + PL_EXIT_EVENT_QUEUE_MONITOR(mEventQueue); + return NS_OK; +} + + +NS_IMETHODIMP +nsEventQueueImpl::RevokeEvents(void* owner) +{ + PL_RevokeEvents(mEventQueue, owner); + if (mElderQueue) { + nsCOMPtr elder(do_QueryInterface(mElderQueue)); + if (elder) + elder->RevokeEvents(owner); + } + return NS_OK; +} + + +NS_IMETHODIMP +nsEventQueueImpl::GetPLEventQueue(PLEventQueue** aEventQueue) +{ + if (!mEventQueue) + return NS_ERROR_NULL_POINTER; + + *aEventQueue = mEventQueue; + return NS_OK; +} + +NS_IMETHODIMP +nsEventQueueImpl::IsOnCurrentThread(PRBool *aResult) +{ + *aResult = PL_IsQueueOnCurrentThread( mEventQueue ); + return NS_OK; +} + + +NS_IMETHODIMP +nsEventQueueImpl::IsQueueNative(PRBool *aResult) +{ + *aResult = PL_IsQueueNative(mEventQueue); + return NS_OK; +} + +NS_IMETHODIMP +nsEventQueueImpl::PendingEvents(PRBool *aResult) +{ + *aResult = PL_EventAvailable(mEventQueue); + if (!*aResult && mElderQueue) { + nsCOMPtr elder(do_QueryInterface(mElderQueue)); + if (elder) + return elder->EventAvailable(*aResult); + } + return NS_OK; +} + + +NS_IMETHODIMP +nsEventQueueImpl::ProcessPendingEvents() +{ + PRBool correctThread = PL_IsQueueOnCurrentThread(mEventQueue); + + NS_ASSERTION(correctThread, "attemping to process events on the wrong thread"); + + if (!correctThread) + return NS_ERROR_FAILURE; +#if defined(PR_LOGGING) && defined(DEBUG_danm) + ++gEventQueueLogPPLevel; + if ((gEventQueueLogQueue != mEventQueue || gEventQueueLogThread != PR_GetCurrentThread() || + gEventQueueLogCount != gEventQueueLogPPCount) && gEventQueueLogPPLevel == 1) { + PR_LOG(gEventQueueLog, PR_LOG_DEBUG, + ("EventQueue: Process pending [queue=%lx, accept=%d, could=%d]", + (long)mEventQueue,(int)mAcceptingEvents,(int)mCouldHaveEvents)); + gEventQueueLogPPCount = ++gEventQueueLogCount; + gEventQueueLogQueue = mEventQueue; + gEventQueueLogThread = PR_GetCurrentThread(); + } +#endif + PL_ProcessPendingEvents(mEventQueue); + + // if we're no longer accepting events and there are still events in the + // queue, then process remaining events. + if (!mAcceptingEvents && PL_EventAvailable(mEventQueue)) + PL_ProcessPendingEvents(mEventQueue); + + CheckForDeactivation(); + + if (mElderQueue) { + nsCOMPtr elder(do_QueryInterface(mElderQueue)); + if (elder) + elder->ProcessPendingEvents(); + } +#if defined(PR_LOGGING) && defined(DEBUG_danm) + --gEventQueueLogPPLevel; +#endif + return NS_OK; +} + +NS_IMETHODIMP +nsEventQueueImpl::EventLoop() +{ + PRBool correctThread = PL_IsQueueOnCurrentThread(mEventQueue); + + NS_ASSERTION(correctThread, "attemping to process events on the wrong thread"); + + if (!correctThread) + return NS_ERROR_FAILURE; + + PL_EventLoop(mEventQueue); + return NS_OK; +} + +NS_IMETHODIMP +nsEventQueueImpl::EventAvailable(PRBool& aResult) +{ + aResult = PL_EventAvailable(mEventQueue); + return NS_OK; +} + +NS_IMETHODIMP +nsEventQueueImpl::GetEvent(PLEvent** aResult) +{ + *aResult = PL_GetEvent(mEventQueue); + CheckForDeactivation(); + return NS_OK; +} + +NS_IMETHODIMP +nsEventQueueImpl::HandleEvent(PLEvent* aEvent) +{ + PRBool correctThread = PL_IsQueueOnCurrentThread(mEventQueue); + NS_ASSERTION(correctThread, "attemping to process events on the wrong thread"); + if (!correctThread) + return NS_ERROR_FAILURE; + +#if defined(PR_LOGGING) && defined(DEBUG_danm) + PR_LOG(gEventQueueLog, PR_LOG_DEBUG, + ("EventQueue: handle event [queue=%lx, accept=%d, could=%d]", + (long)mEventQueue,(int)mAcceptingEvents,(int)mCouldHaveEvents)); + ++gEventQueueLogCount; +#endif + PL_HandleEvent(aEvent); + return NS_OK; +} + +NS_IMETHODIMP +nsEventQueueImpl::WaitForEvent(PLEvent** aResult) +{ + PRBool correctThread = PL_IsQueueOnCurrentThread(mEventQueue); + NS_ASSERTION(correctThread, "attemping to process events on the wrong thread"); + if (!correctThread) + return NS_ERROR_FAILURE; + +#if defined(PR_LOGGING) && defined(DEBUG_danm) + PR_LOG(gEventQueueLog, PR_LOG_DEBUG, + ("EventQueue: wait for event [queue=%lx, accept=%d, could=%d]", + (long)mEventQueue,(int)mAcceptingEvents,(int)mCouldHaveEvents)); + ++gEventQueueLogCount; +#endif + *aResult = PL_WaitForEvent(mEventQueue); + CheckForDeactivation(); + return NS_OK; +} + +NS_IMETHODIMP_(PRInt32) +nsEventQueueImpl::GetEventQueueSelectFD() +{ + return PL_GetEventQueueSelectFD(mEventQueue); +} + +NS_METHOD +nsEventQueueImpl::Create(nsISupports *aOuter, + REFNSIID aIID, + void **aResult) +{ + nsEventQueueImpl* evt = new nsEventQueueImpl(); + if (evt == NULL) + return NS_ERROR_OUT_OF_MEMORY; + nsresult rv = evt->QueryInterface(aIID, aResult); + if (NS_FAILED(rv)) { + delete evt; + } + return rv; +} + +// ---------------- nsPIEventQueueChain ----------------- + +NS_IMETHODIMP +nsEventQueueImpl::AppendQueue(nsIEventQueue *aQueue) +{ + nsresult rv; + nsCOMPtr end; + nsCOMPtr queueChain(do_QueryInterface(aQueue)); + + if (!aQueue) + return NS_ERROR_NO_INTERFACE; + +/* this would be nice + NS_ASSERTION(aQueue->mYoungerQueue == NULL && aQueue->mElderQueue == NULL, + "event queue repeatedly appended to queue chain"); +*/ + rv = NS_ERROR_NO_INTERFACE; + +#ifdef NS_DEBUG + int depth = 0; + nsEventQueueImpl *next = this; + while (next && depth < 100) { + next = NS_STATIC_CAST(nsEventQueueImpl *, next->mYoungerQueue); + ++depth; + } + if (depth > 5) { + char warning[80]; + PR_snprintf(warning, sizeof(warning), + "event queue chain length is %d. this is almost certainly a leak.", depth); + NS_WARNING(warning); + } +#endif + + // (be careful doing this outside nsEventQueueService's mEventQMonitor) + + GetYoungest(getter_AddRefs(end)); + nsCOMPtr endChain(do_QueryInterface(end)); + if (endChain) { + endChain->SetYounger(queueChain); + queueChain->SetElder(endChain); + rv = NS_OK; + } + return rv; +} + +NS_IMETHODIMP +nsEventQueueImpl::Unlink() +{ + nsCOMPtr young = mYoungerQueue, + old = mElderQueue; + +#if defined(PR_LOGGING) && defined(DEBUG_danm) + PR_LOG(gEventQueueLog, PR_LOG_DEBUG, + ("EventQueue: unlink [queue=%lx, younger=%lx, elder=%lx]", + (long)mEventQueue,(long)mYoungerQueue, (long)mElderQueue.get())); + ++gEventQueueLogCount; +#endif + + // this is probably OK, but shouldn't happen by design, so tell me if it does + NS_ASSERTION(!mYoungerQueue, "event queue chain broken in middle"); + + // break links early in case the Release cascades back onto us + mYoungerQueue = nsnull; + mElderQueue = nsnull; + + if (young) + young->SetElder(old); + if (old) { + old->SetYounger(young); + } + return NS_OK; +} + +NS_IMETHODIMP +nsEventQueueImpl::GetYoungest(nsIEventQueue **aQueue) +{ + if (mYoungerQueue) + return mYoungerQueue->GetYoungest(aQueue); + + nsIEventQueue *answer = NS_STATIC_CAST(nsIEventQueue *, this); + NS_ADDREF(answer); + *aQueue = answer; + return NS_OK; +} + +NS_IMETHODIMP +nsEventQueueImpl::GetYoungestActive(nsIEventQueue **aQueue) +{ + nsCOMPtr answer; + + if (mYoungerQueue) + mYoungerQueue->GetYoungestActive(getter_AddRefs(answer)); + if (!answer) { + if (mAcceptingEvents && mCouldHaveEvents) + answer = NS_STATIC_CAST(nsIEventQueue *, this); + } + *aQueue = answer; + NS_IF_ADDREF(*aQueue); + return NS_OK; +} + +NS_IMETHODIMP +nsEventQueueImpl::SetYounger(nsPIEventQueueChain *aQueue) +{ + mYoungerQueue = aQueue; + return NS_OK; +} + +NS_IMETHODIMP +nsEventQueueImpl::SetElder(nsPIEventQueueChain *aQueue) +{ + mElderQueue = aQueue; + return NS_OK; +} + +NS_IMETHODIMP +nsEventQueueImpl::GetYounger(nsIEventQueue **aQueue) +{ + if (!mYoungerQueue) { + *aQueue = nsnull; + return NS_OK; + } + return mYoungerQueue->QueryInterface(NS_GET_IID(nsIEventQueue), (void**)&aQueue); +} + +NS_IMETHODIMP +nsEventQueueImpl::GetElder(nsIEventQueue **aQueue) +{ + if (!mElderQueue) { + *aQueue = nsnull; + return NS_OK; + } + return mElderQueue->QueryInterface(NS_GET_IID(nsIEventQueue), (void**)&aQueue); +} + diff --git a/src/libs/xpcom18a4/xpcom/threads/nsEventQueue.h b/src/libs/xpcom18a4/xpcom/threads/nsEventQueue.h new file mode 100644 index 00000000..51f33e47 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/threads/nsEventQueue.h @@ -0,0 +1,89 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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 Communicator client code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Pierre Phaneuf + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "prmon.h" +#include "nsIEventQueue.h" +#include "nsPIEventQueueChain.h" + +class nsEventQueueImpl : public nsIEventQueue, + public nsPIEventQueueChain +{ +public: + nsEventQueueImpl(); + + NS_DECL_ISUPPORTS + NS_DECL_NSIEVENTTARGET + NS_DECL_NSIEVENTQUEUE + + // Helpers + static NS_METHOD Create(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr); + + static const nsCID& CID() { static nsCID cid = NS_EVENTQUEUE_CID; return cid; } + + // nsPIEventQueueChain interface + NS_IMETHOD AppendQueue(nsIEventQueue *aQueue); + NS_IMETHOD Unlink(); + NS_IMETHOD GetYoungest(nsIEventQueue **aQueue); + NS_IMETHOD GetYoungestActive(nsIEventQueue **aQueue); + NS_IMETHOD SetYounger(nsPIEventQueueChain *aQueue); + NS_IMETHOD GetYounger(nsIEventQueue **aQueue); + NS_IMETHOD SetElder(nsPIEventQueueChain *aQueue); + NS_IMETHOD GetElder(nsIEventQueue **aQueue); + +private: + ~nsEventQueueImpl(); + + PLEventQueue *mEventQueue; + PRBool mAcceptingEvents, // accept new events or pass them on? + mCouldHaveEvents; // accepting new ones, or still have old ones? + nsCOMPtr mElderQueue; // younger can hold on to elder + nsPIEventQueueChain *mYoungerQueue; // but elder can't hold on to younger + + void NotifyObservers(const char *aTopic); + + void CheckForDeactivation() { + if (mCouldHaveEvents && !mAcceptingEvents && !PL_EventAvailable(mEventQueue)) { + if (PL_IsQueueOnCurrentThread(mEventQueue)) { + mCouldHaveEvents = PR_FALSE; + NS_RELEASE_THIS(); // balance ADDREF from the constructor + } else + NS_ERROR("CheckForDeactivation called from wrong thread!"); + } + } +}; + diff --git a/src/libs/xpcom18a4/xpcom/threads/nsEventQueueService.cpp b/src/libs/xpcom18a4/xpcom/threads/nsEventQueueService.cpp new file mode 100644 index 00000000..4fbb65aa --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/threads/nsEventQueueService.cpp @@ -0,0 +1,450 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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 Communicator client code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Rick Potts + * Ramiro Estrugo + * Warren Harris + * Leaf Nunes + * David Matiskella + * David Hyatt + * Seth Spitzer + * Suresh Duddi + * Bruce Mitchener + * Scott Collins + * Daniel Matejka + * Doug Turner + * Stuart Parmenter + * Mike Kaply + * Dan Mosedale + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsEventQueueService.h" +#include "prmon.h" +#include "nsIComponentManager.h" +#include "nsIThread.h" +#include "nsPIEventQueueChain.h" + +#include "prlog.h" + +#if defined(PR_LOGGING) || defined(DEBUG_danm) +extern PRLogModuleInfo* gEventQueueLog; +extern PRUint32 gEventQueueLogCount; +#endif + +static NS_DEFINE_CID(kEventQueueCID, NS_EVENTQUEUE_CID); + +nsEventQueueServiceImpl::nsEventQueueServiceImpl() +{ + mEventQMonitor = PR_NewMonitor(); +#if defined(PR_LOGGING) && defined(DEBUG_danm) + if (!gEventQueueLog) + gEventQueueLog = PR_NewLogModule("nseventqueue"); +#endif +} + +PR_STATIC_CALLBACK(PLDHashOperator) +hash_enum_remove_queues(const void *aThread_ptr, + nsCOMPtr& aEldestQueue, + void* closure) +{ + // 'aQueue' should be the eldest queue. + nsCOMPtr pie(do_QueryInterface(aEldestQueue)); + nsCOMPtr q; + + // stop accepting events for youngest to oldest + pie->GetYoungest(getter_AddRefs(q)); + while (q) { + q->StopAcceptingEvents(); + + nsCOMPtr pq(do_QueryInterface(q)); + pq->GetElder(getter_AddRefs(q)); + } + + return PL_DHASH_REMOVE; +} + +nsEventQueueServiceImpl::~nsEventQueueServiceImpl() +{ + // XXX make it so we only enum over this once + mEventQTable.Enumerate(hash_enum_remove_queues, nsnull); // call StopAcceptingEvents on everything and clear out the hashtable + + PR_DestroyMonitor(mEventQMonitor); +} + +nsresult +nsEventQueueServiceImpl::Init() +{ + NS_ENSURE_TRUE(mEventQMonitor, NS_ERROR_OUT_OF_MEMORY); + + // This will only be called once on the main thread, so it's safe to + // not enter the monitor here. + if (!mEventQTable.Init()) { + return NS_ERROR_OUT_OF_MEMORY; + } + + // ensure that a main thread event queue exists! + nsresult rv; + nsCOMPtr mainThread; + rv = nsIThread::GetMainThread(getter_AddRefs(mainThread)); + if (NS_SUCCEEDED(rv)) { + PRThread *thr; + rv = mainThread->GetPRThread(&thr); + if (NS_SUCCEEDED(rv)) + rv = CreateEventQueue(thr, PR_TRUE); + } + return rv; +} + +/* nsISupports interface implementation... */ +NS_IMPL_THREADSAFE_ISUPPORTS1(nsEventQueueServiceImpl, nsIEventQueueService) + +/* nsIEventQueueService interface implementation... */ + +NS_IMETHODIMP +nsEventQueueServiceImpl::CreateThreadEventQueue() +{ + return CreateEventQueue(PR_GetCurrentThread(), PR_TRUE); +} + +NS_IMETHODIMP +nsEventQueueServiceImpl::CreateMonitoredThreadEventQueue() +{ + return CreateEventQueue(PR_GetCurrentThread(), PR_FALSE); +} + +NS_IMETHODIMP +nsEventQueueServiceImpl::CreateFromIThread(nsIThread *aThread, PRBool aNative, + nsIEventQueue **aResult) +{ + nsresult rv; + PRThread *prThread; + + rv = aThread->GetPRThread(&prThread); + if (NS_SUCCEEDED(rv)) { + rv = CreateEventQueue(prThread, aNative); // addrefs + if (NS_SUCCEEDED(rv)) + rv = GetThreadEventQueue(prThread, aResult); // addrefs + } + return rv; +} + +// private method +NS_IMETHODIMP +nsEventQueueServiceImpl::MakeNewQueue(PRThread* thread, + PRBool aNative, + nsIEventQueue **aQueue) +{ + nsresult rv; + nsCOMPtr queue = do_CreateInstance(kEventQueueCID, &rv); + + if (NS_SUCCEEDED(rv)) { + rv = queue->InitFromPRThread(thread, aNative); + } + *aQueue = queue; + NS_IF_ADDREF(*aQueue); + return rv; +} + +// private method +NS_IMETHODIMP +nsEventQueueServiceImpl::CreateEventQueue(PRThread *aThread, PRBool aNative) +{ + nsresult rv = NS_OK; + /* Enter the lock that protects the EventQ hashtable... */ + PR_EnterMonitor(mEventQMonitor); + + /* create only one event queue chain per thread... */ + if (!mEventQTable.GetWeak(aThread)) { + nsCOMPtr queue; + + // we don't have one in the table + rv = MakeNewQueue(aThread, aNative, getter_AddRefs(queue)); // create new queue + mEventQTable.Put(aThread, queue); // add to the table (initial addref) + } + + // Release the EventQ lock... + PR_ExitMonitor(mEventQMonitor); + return rv; +} + + +NS_IMETHODIMP +nsEventQueueServiceImpl::DestroyThreadEventQueue(void) +{ + nsresult rv = NS_OK; + + /* Enter the lock that protects the EventQ hashtable... */ + PR_EnterMonitor(mEventQMonitor); + + PRThread* currentThread = PR_GetCurrentThread(); + nsIEventQueue* queue = mEventQTable.GetWeak(currentThread); + if (queue) { + queue->StopAcceptingEvents(); // tell the queue to stop accepting events + queue = nsnull; // Queue may die on the next line + mEventQTable.Remove(currentThread); // remove nsIEventQueue from hash table (releases) + } + + // Release the EventQ lock... + PR_ExitMonitor(mEventQMonitor); + return rv; +} + +NS_IMETHODIMP +nsEventQueueServiceImpl::CreateFromPLEventQueue(PLEventQueue* aPLEventQueue, nsIEventQueue** aResult) +{ + // Create our thread queue using the component manager + nsresult rv; + nsCOMPtr queue = do_CreateInstance(kEventQueueCID, &rv); + if (NS_FAILED(rv)) return rv; + + rv = queue->InitFromPLQueue(aPLEventQueue); + if (NS_FAILED(rv)) return rv; + + *aResult = queue; + NS_IF_ADDREF(*aResult); + return NS_OK; +} + + +// Return the active event queue on our chain +/* inline */ +nsresult nsEventQueueServiceImpl::GetYoungestEventQueue(nsIEventQueue *queue, nsIEventQueue **aResult) +{ + nsCOMPtr answer; + + if (queue) { + nsCOMPtr ourChain(do_QueryInterface(queue)); + if (ourChain) + ourChain->GetYoungestActive(getter_AddRefs(answer)); + else + answer = queue; + } + + *aResult = answer; + NS_IF_ADDREF(*aResult); + return NS_OK; +} + + +// create new event queue, append it to the current thread's chain of event queues. +// return it, addrefed. +NS_IMETHODIMP +nsEventQueueServiceImpl::PushThreadEventQueue(nsIEventQueue **aNewQueue) +{ + nsresult rv = NS_OK; + PRThread* currentThread = PR_GetCurrentThread(); + PRBool native = PR_TRUE; // native by default as per old comment + + + NS_ASSERTION(aNewQueue, "PushThreadEventQueue called with null param"); + + /* Enter the lock that protects the EventQ hashtable... */ + PR_EnterMonitor(mEventQMonitor); + + nsIEventQueue* queue = mEventQTable.GetWeak(currentThread); + + NS_ASSERTION(queue, "pushed event queue on top of nothing"); + + if (queue) { // find out what kind of queue our relatives are + nsCOMPtr youngQueue; + GetYoungestEventQueue(queue, getter_AddRefs(youngQueue)); + if (youngQueue) { + youngQueue->IsQueueNative(&native); + } + } + + nsIEventQueue* newQueue = nsnull; + MakeNewQueue(currentThread, native, &newQueue); // create new queue; addrefs + + if (!queue) { + // shouldn't happen. as a fallback, we guess you wanted a native queue + mEventQTable.Put(currentThread, newQueue); + } + + // append to the event queue chain + nsCOMPtr ourChain(do_QueryInterface(queue)); // QI the queue in the hash table + if (ourChain) + ourChain->AppendQueue(newQueue); // append new queue to it + + *aNewQueue = newQueue; + +#if defined(PR_LOGGING) && defined(DEBUG_danm) + PLEventQueue *equeue; + (*aNewQueue)->GetPLEventQueue(&equeue); + PR_LOG(gEventQueueLog, PR_LOG_DEBUG, + ("EventQueue: Service push queue [queue=%lx]",(long)equeue)); + ++gEventQueueLogCount; +#endif + + // Release the EventQ lock... + PR_ExitMonitor(mEventQMonitor); + return rv; +} + +// disable and release the given queue (though the last one won't be released) +NS_IMETHODIMP +nsEventQueueServiceImpl::PopThreadEventQueue(nsIEventQueue *aQueue) +{ + PRThread* currentThread = PR_GetCurrentThread(); + + /* Enter the lock that protects the EventQ hashtable... */ + PR_EnterMonitor(mEventQMonitor); + + nsCOMPtr eldestQueue; + mEventQTable.Get(currentThread, getter_AddRefs(eldestQueue)); + + // If we are popping the eldest queue, remove its mEventQTable entry. + if (aQueue == eldestQueue) + mEventQTable.Remove(currentThread); + + // Exit the monitor before processing pending events to avoid deadlock. + // Our reference from the eldestQueue nsCOMPtr will keep that object alive. + // Since it is thread-private, no one else can race with us here. + PR_ExitMonitor(mEventQMonitor); + if (!eldestQueue) + return NS_ERROR_FAILURE; + +#if defined(PR_LOGGING) && defined(DEBUG_danm) + PLEventQueue *equeue; + aQueue->GetPLEventQueue(&equeue); + PR_LOG(gEventQueueLog, PR_LOG_DEBUG, + ("EventQueue: Service pop queue [queue=%lx]",(long)equeue)); + ++gEventQueueLogCount; +#endif + aQueue->StopAcceptingEvents(); + aQueue->ProcessPendingEvents(); // make sure we don't orphan any events + + return NS_OK; +} + +NS_IMETHODIMP +nsEventQueueServiceImpl::GetThreadEventQueue(PRThread* aThread, nsIEventQueue** aResult) +{ + /* Parameter validation... */ + if (NULL == aResult) return NS_ERROR_NULL_POINTER; + + PRThread* keyThread = aThread; + + if (keyThread == NS_CURRENT_THREAD) + { + keyThread = PR_GetCurrentThread(); + } + else if (keyThread == NS_UI_THREAD) + { + nsCOMPtr mainIThread; + + // Get the primordial thread + nsresult rv = nsIThread::GetMainThread(getter_AddRefs(mainIThread)); + if (NS_FAILED(rv)) return rv; + + rv = mainIThread->GetPRThread(&keyThread); + if (NS_FAILED(rv)) return rv; + } + + /* Enter the lock that protects the EventQ hashtable... */ + PR_EnterMonitor(mEventQMonitor); + + nsCOMPtr queue; + mEventQTable.Get(keyThread, getter_AddRefs(queue)); + + PR_ExitMonitor(mEventQMonitor); + + if (queue) { + GetYoungestEventQueue(queue, aResult); // get the youngest active queue + } else { + *aResult = nsnull; + } + // XXX: Need error code for requesting an event queue when none exists... + if (!*aResult) { + return NS_ERROR_NOT_AVAILABLE; + } + return NS_OK; +} + + +NS_IMETHODIMP +nsEventQueueServiceImpl::ResolveEventQueue(nsIEventQueue* queueOrConstant, nsIEventQueue* *resultQueue) +{ + if (queueOrConstant == NS_CURRENT_EVENTQ) { + return GetThreadEventQueue(NS_CURRENT_THREAD, resultQueue); + } + else if (queueOrConstant == NS_UI_THREAD_EVENTQ) { + return GetThreadEventQueue(NS_UI_THREAD, resultQueue); + } + + *resultQueue = queueOrConstant; + NS_ADDREF(*resultQueue); + return NS_OK; +} + +NS_IMETHODIMP +nsEventQueueServiceImpl::GetSpecialEventQueue(PRInt32 aQueue, + nsIEventQueue* *_retval) +{ + nsresult rv; + + // barf if someone gave us a zero pointer + // + if (!_retval) { + return NS_ERROR_NULL_POINTER; + } + + // try and get the requested event queue, returning NS_ERROR_FAILURE if there + // is a problem. GetThreadEventQueue() does the AddRef() for us. + // + switch (aQueue) { + case CURRENT_THREAD_EVENT_QUEUE: + rv = GetThreadEventQueue(NS_CURRENT_THREAD, _retval); + if (NS_FAILED(rv)) { + return NS_ERROR_FAILURE; + } + break; + + case UI_THREAD_EVENT_QUEUE: + rv = GetThreadEventQueue(NS_UI_THREAD, _retval); + if (NS_FAILED(rv)) { + return NS_ERROR_FAILURE; + } + break; + + // somebody handed us a bogus constant + // + default: + return NS_ERROR_ILLEGAL_VALUE; + } + + return NS_OK; +} + diff --git a/src/libs/xpcom18a4/xpcom/threads/nsEventQueueService.h b/src/libs/xpcom18a4/xpcom/threads/nsEventQueueService.h new file mode 100644 index 00000000..6fddb941 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/threads/nsEventQueueService.h @@ -0,0 +1,77 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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 Communicator client code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +#ifndef nsEventQueueService_h__ +#define nsEventQueueService_h__ + +#include "nsIEventQueueService.h" +#include "nsInterfaceHashtable.h" +#include "nsHashKeys.h" +#include "nsIEventQueue.h" + +//////////////////////////////////////////////////////////////////////////////// + +class nsEventQueueServiceImpl : public nsIEventQueueService +{ +public: + nsEventQueueServiceImpl(); + + nsresult Init(); + + // nsISupports interface... + NS_DECL_ISUPPORTS + + // nsIEventQueueService interface... + NS_DECL_NSIEVENTQUEUESERVICE + +private: + ~nsEventQueueServiceImpl(); + + /* Create a queue for the given thread if one does not exist. + Addref the descriptor in any case. parameter aNative is + ignored if the queue already exists. */ + NS_IMETHOD CreateEventQueue(PRThread *aThread, PRBool aNative); + NS_IMETHOD MakeNewQueue(PRThread* thread, PRBool aNative, nsIEventQueue **aQueue); + inline nsresult GetYoungestEventQueue(nsIEventQueue *queue, nsIEventQueue **aResult); + + nsInterfaceHashtable mEventQTable; + PRMonitor *mEventQMonitor; +}; + +//////////////////////////////////////////////////////////////////////////////// + +#endif // nsEventQueueService_h__ diff --git a/src/libs/xpcom18a4/xpcom/threads/nsEventQueueUtils.h b/src/libs/xpcom18a4/xpcom/threads/nsEventQueueUtils.h new file mode 100644 index 00000000..5df2e406 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/threads/nsEventQueueUtils.h @@ -0,0 +1,78 @@ +/* ***** 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 ***** */ + +#ifndef nsEventQueueUtils_h__ +#define nsEventQueueUtils_h__ + +#include "nsIEventQueueService.h" +#include "nsIServiceManager.h" +#include "nsCOMPtr.h" + +inline nsresult +NS_GetEventQueueService(nsIEventQueueService **result) +{ + static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID); + return CallGetService(kEventQueueServiceCID, result); +} + +inline nsresult +NS_GetCurrentEventQ(nsIEventQueue **result, + nsIEventQueueService *serv = nsnull) +{ + nsCOMPtr eqs; + if (!serv) { + nsresult rv = NS_GetEventQueueService(getter_AddRefs(eqs)); + if (NS_FAILED(rv)) return rv; + serv = eqs; + } + return serv->GetThreadEventQueue(NS_CURRENT_THREAD, result); +} + +inline nsresult +NS_GetMainEventQ(nsIEventQueue **result, + nsIEventQueueService *serv = nsnull) +{ + nsCOMPtr eqs; + if (!serv) { + nsresult rv = NS_GetEventQueueService(getter_AddRefs(eqs)); + if (NS_FAILED(rv)) return rv; + serv = eqs; + } + return serv->GetThreadEventQueue(NS_UI_THREAD, result); +} + +#endif // !nsEventQueueUtils_h__ diff --git a/src/libs/xpcom18a4/xpcom/threads/nsIEnvironment.idl b/src/libs/xpcom18a4/xpcom/threads/nsIEnvironment.idl new file mode 100644 index 00000000..95351346 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/threads/nsIEnvironment.idl @@ -0,0 +1,89 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 embedding code. + * + * The Initial Developers of the Original Code are + * Benjamin Smedberg and + * Roland Mainz . + * + * Portions created by the Initial Developer are Copyright (C) 2003/2004 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * 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 "nsISupports.idl" + +/** + * Scriptable access to the current process environment. + * + */ +[scriptable, uuid(101d5941-d820-4e85-a266-9a3469940807)] +interface nsIEnvironment : nsISupports +{ + /** + * Set the value of an environment variable. + * + * @param aName the variable name to set. + * @param aValue the value to set. + */ + void set(in AString aName, in AString aValue); + + /** + * Get the value of an environment variable. + * + * @param aName the variable name to retrieve. + * @return returns the value of the env variable. An empty string + * will be returned when the env variable does not exist or + * when the value itself is an empty string - please use + * |exists()| to probe whether the env variable exists + * or not. + */ + AString get(in AString aName); + + /** + * Check the existence of an environment variable. + * This method checks whether an environment variable is present in + * the environment or not. + * + * - For Unix/Linux platforms we follow the Unix definition: + * An environment variable exists when |getenv()| returns a non-NULL value. + * An environment variable does not exist when |getenv()| returns NULL. + * - For non-Unix/Linux platforms we have to fall back to a + * "portable" definition (which is incorrect for Unix/Linux!!!!) + * which simply checks whether the string returned by |Get()| is empty + * or not. + * + * @param aName the variable name to probe. + * @return if the variable has been set, the value returned is + * PR_TRUE. If the variable was not defined in the + * environment PR_FALSE will be returned. + */ + boolean exists(in AString aName); +}; + diff --git a/src/libs/xpcom18a4/xpcom/threads/nsIEventQueue.idl b/src/libs/xpcom18a4/xpcom/threads/nsIEventQueue.idl new file mode 100644 index 00000000..416c80a1 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/threads/nsIEventQueue.idl @@ -0,0 +1,107 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 Communicator client code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * David Hyatt + * Suresh Duddi + * Doug Turner + * Judson Valeski + * Dan Matejka + * Ray Whitmer + * Dan Mosedale + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsIEventTarget.idl" + +%{C++ +#include "prthread.h" + +// {13D86C61-00A9-11d3-9F2A-00400553EEF0} +#define NS_EVENTQUEUE_CID \ +{ 0x13d86c61, 0xa9, 0x11d3, { 0x9f, 0x2a, 0x0, 0x40, 0x5, 0x53, 0xee, 0xf0 } } + +#define NS_EVENTQUEUE_CONTRACTID "@mozilla.org/event-queue;1" +#define NS_EVENTQUEUE_CLASSNAME "Event Queue" + +%} + +// some forward decls +// +[ptr] native PLEventQueuePtr(PLEventQueue); +[ptr] native PRThreadPtr(PRThread); +native PRStatus(PRStatus); +[ref] native PRBoolRef(PRBool); +native PLHandleEventProc(PLHandleEventProc); +native PLDestroyEventProc(PLDestroyEventProc); + +[scriptable, uuid(176AFB41-00A4-11d3-9F2A-00400553EEF0)] +interface nsIEventQueue : nsIEventTarget +{ + [noscript] void initEvent(in PLEventPtr aEvent, + in voidPtr owner, + in PLHandleEventProc handler, + in PLDestroyEventProc destructor); + + [noscript] void postSynchronousEvent(in PLEventPtr aEvent, + out voidPtr aResult); + + boolean pendingEvents(); + void processPendingEvents(); + void eventLoop(); + + [noscript] void eventAvailable(in PRBoolRef aResult); + [noscript] PLEventPtr getEvent(); + [noscript] void handleEvent(in PLEventPtr aEvent); + [noscript] PLEventPtr waitForEvent(); + + [notxpcom] PRInt32 getEventQueueSelectFD(); + + void init(in boolean aNative); + [noscript] void initFromPRThread(in PRThreadPtr thread, + in boolean aNative); + [noscript] void initFromPLQueue(in PLEventQueuePtr aQueue); + + void enterMonitor(); + void exitMonitor(); + + [noscript] void revokeEvents(in voidPtr owner); + [noscript] PLEventQueuePtr getPLEventQueue(); + + boolean isQueueNative(); + + // effectively kill the queue. warning: the queue is allowed to delete + // itself any time after this. + void stopAcceptingEvents(); +}; + diff --git a/src/libs/xpcom18a4/xpcom/threads/nsIEventQueueService.idl b/src/libs/xpcom18a4/xpcom/threads/nsIEventQueueService.idl new file mode 100644 index 00000000..e9c93e86 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/threads/nsIEventQueueService.idl @@ -0,0 +1,151 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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 Communicator client code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Rick Potts + * David Matiskella + * David Hyatt + * Suresh Duddi + * Scott Collins + * Dan Matejka + * Doug Turner + * Ray Whitmer + * Dan Mosedale + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsISupports.idl" +#include "nsIEventQueue.idl" + +%{C++ +#include "prthread.h" +#include "plevent.h" + +/* be761f00-a3b0-11d2-996c-0080c7cb1080 */ +#define NS_EVENTQUEUESERVICE_CID \ +{ 0xbe761f00, 0xa3b0, 0x11d2, \ + {0x99, 0x6c, 0x00, 0x80, 0xc7, 0xcb, 0x10, 0x80} } + +#define NS_EVENTQUEUESERVICE_CONTRACTID "@mozilla.org/event-queue-service;1" +#define NS_EVENTQUEUESERVICE_CLASSNAME "Event Queue Service" + +#define NS_CURRENT_THREAD ((PRThread*)0) +#define NS_CURRENT_EVENTQ ((nsIEventQueue*)0) + +#define NS_UI_THREAD ((PRThread*)1) +#define NS_UI_THREAD_EVENTQ ((nsIEventQueue*)1) + +%} + +/* a forward decl */ +interface nsIThread; + +[scriptable, uuid(a6cf90dc-15b3-11d2-932e-00805f8add32)] +interface nsIEventQueueService : nsISupports +{ + /** + * Creates and holds a native event queue for the current thread. + * "Native" queues have an associated callback mechanism which is + * automatically triggered when an event is posted. See plevent.c for + * details. + * @return NS_OK on success, or a host of failure indications + */ + void createThreadEventQueue(); + + /** + * Creates and hold a monitored event queue for the current thread. + * "Monitored" queues have no callback processing mechanism. + * @return NS_OK on success, or a host of failure indications + */ + void createMonitoredThreadEventQueue(); + + /** + * Somewhat misnamed, this method releases the service's hold on the event + * queue(s) for this thread. Subsequent attempts to access this thread's + * queue (GetThreadEventQueue, for example) may fail, though the queue itself + * will be destroyed only after all references to it are released and the + * queue itself is no longer actively processing events. + * @return nonsense. + */ + void destroyThreadEventQueue(); + + nsIEventQueue createFromIThread(in nsIThread aThread, + in boolean aNative); + + [noscript] nsIEventQueue createFromPLEventQueue(in PLEventQueuePtr + aPLEventQueue); + + // Add a new event queue for the current thread, making it the "current" + // queue. Return that queue, addrefed. + nsIEventQueue pushThreadEventQueue(); + + // release and disable the queue + void popThreadEventQueue(in nsIEventQueue aQueue); + + [noscript] nsIEventQueue getThreadEventQueue(in PRThreadPtr aThread); + + /** + * @deprecated in favor of getSpecialEventQueue, since that's + * scriptable and this isn't. + * + * Check for any "magic" event queue constants (NS_CURRENT_EVENTQ, + * NS_UI_THREAD_EVENTQ) and return the real event queue that they + * represent, AddRef()ed. Otherwise, return the event queue passed + * in, AddRef()ed. This is not scriptable because the arguments in + * question may be magic constants rather than real nsIEventQueues. + * + * @arg queueOrConstant either a real event queue or a magic + * constant to be resolved + * + * @return a real event queue, AddRef()ed + */ + [noscript] nsIEventQueue resolveEventQueue(in nsIEventQueue queueOrConstant); + + /** + * Returns the appropriate special event queue, AddRef()ed. Really + * just a scriptable version of ResolveEventQueue. + * + * @arg aQueue Either CURRENT_THREAD_EVENT_QUEUE or + * UI_THREAD_EVENT_QUEUE + * @return The requested nsIEventQueue, AddRef()ed + * @exception NS_ERROR_NULL_POINTER Zero pointer passed in for return value + * @exception NS_ERROR_ILLEGAL_VALUE Bogus constant passed in aQueue + * @exception NS_ERROR_FAILURE Error while calling + * GetThreadEventQueue() + */ + nsIEventQueue getSpecialEventQueue(in long aQueue); + + const long CURRENT_THREAD_EVENT_QUEUE = 0; + const long UI_THREAD_EVENT_QUEUE = 1; + +}; diff --git a/src/libs/xpcom18a4/xpcom/threads/nsIEventTarget.idl b/src/libs/xpcom18a4/xpcom/threads/nsIEventTarget.idl new file mode 100644 index 00000000..3b19d9ca --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/threads/nsIEventTarget.idl @@ -0,0 +1,67 @@ +/* ***** 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 IBM Corporation. + * Portions created by IBM Corporation are Copyright (C) 2003 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * IBM Corp. + * + * 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 "nsISupports.idl" + +%{C++ +#include "plevent.h" +%} + +[ptr] native PLEventPtr(PLEvent); + +/** + * nsIEventTarget + * + * This interface is used to dispatch events to a particular thread. In many + * cases the event target also supports nsIEventQueue. + */ +[scriptable, uuid(ea99ad5b-cc67-4efb-97c9-2ef620a59f2a)] +interface nsIEventTarget : nsISupports +{ + /** + * Method for posting an asynchronous event to the event target. If this + * method succeeds, then the event will be dispatched on the target thread. + * + * @param aEvent + * The event to dispatched. + */ + [noscript] void postEvent(in PLEventPtr aEvent); + + /** + * This method returns true if the event target is the current thread. + */ + boolean isOnCurrentThread(); +}; diff --git a/src/libs/xpcom18a4/xpcom/threads/nsIProcess.idl b/src/libs/xpcom18a4/xpcom/threads/nsIProcess.idl new file mode 100644 index 00000000..07769cb7 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/threads/nsIProcess.idl @@ -0,0 +1,32 @@ +#include "nsIFile.idl" +#include "nsISupports.idl" + +[scriptable, uuid(9da0b650-d07e-4617-a18a-250035572ac8)] + +interface nsIProcess : nsISupports +{ + void init(in nsIFile executable); + void initWithPid(in unsigned long pid); + + void kill(); + + /** XXX what charset? **/ + /** Executes the file this object was initialized with + * @param blocking Whether to wait until the process terminates before returning or not + * @param args An array of arguments to pass to the process + * @param count The length of the args array + * @return the PID of the newly spawned process */ + unsigned long run(in boolean blocking, [array, size_is(count)] in string args, in unsigned long count); + + readonly attribute nsIFile location; + readonly attribute unsigned long pid; + readonly attribute string processName; + readonly attribute unsigned long processSignature; + readonly attribute long exitValue; +}; + +%{C++ + +#define NS_PROCESS_CONTRACTID "@mozilla.org/process/util;1" +#define NS_PROCESS_CLASSNAME "Process Specification" +%} diff --git a/src/libs/xpcom18a4/xpcom/threads/nsIRunnable.idl b/src/libs/xpcom18a4/xpcom/threads/nsIRunnable.idl new file mode 100644 index 00000000..1cedda38 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/threads/nsIRunnable.idl @@ -0,0 +1,44 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsISupports.idl" + +[scriptable, uuid(4a2abaf0-6886-11d3-9382-00104ba0fd40)] +interface nsIRunnable : nsISupports +{ + void run(); +}; diff --git a/src/libs/xpcom18a4/xpcom/threads/nsIThread.idl b/src/libs/xpcom18a4/xpcom/threads/nsIThread.idl new file mode 100644 index 00000000..f28d6ec9 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/threads/nsIThread.idl @@ -0,0 +1,144 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsISupports.idl" + +%{C++ +#include "prthread.h" + +#define NS_THREAD_CID \ +{ /* 85CE5510-7808-11d3-A181-0050041CAF44 */ \ + 0x85ce5510, \ + 0x7808, \ + 0x11d3, \ + {0xa1, 0x81, 0x00, 0x50, 0x04, 0x1c, 0xaf, 0x44} \ +} + +#define NS_THREAD_CONTRACTID "@mozilla.org/thread;1" +#define NS_THREAD_CLASSNAME "Thread" +#if 0 +%} + +typedef PRUint32 PRThreadPriority; +typedef PRUint32 PRThreadScope; +typedef PRUint32 PRThreadState; + +%{C++ +#endif +%} + +interface nsIRunnable; + +[ptr] native PRThread(PRThread); + +[scriptable, uuid(6be5e380-6886-11d3-9382-00104ba0fd40)] +interface nsIThread : nsISupports +{ + // These must all match the values used in prthread.h + const PRUint32 PRIORITY_LOW = 0; + const PRUint32 PRIORITY_NORMAL = 1; + const PRUint32 PRIORITY_HIGH = 2; + const PRUint32 PRIORITY_URGENT = 3; + + const PRUint32 SCOPE_LOCAL = 0; + const PRUint32 SCOPE_GLOBAL = 1; + const PRUint32 SCOPE_BOUND = 2; + + const PRUint32 STATE_JOINABLE = 0; + const PRUint32 STATE_UNJOINABLE = 1; + + void join(); + void interrupt(); + + attribute PRThreadPriority priority; + readonly attribute PRThreadScope scope; + readonly attribute PRThreadState state; + + [noscript] PRThread GetPRThread(); + + void init(in nsIRunnable aRunnable, + in PRUint32 aStackSize, + in PRThreadPriority aPriority, + in PRThreadScope aScope, + in PRThreadState aState); + + /* + * Get the currently running thread (really a static method sort of thing). + */ + readonly attribute nsIThread currentThread; + + /* + * Sleep to at least this many milliseconds (only works on currrent thread). + */ + void sleep(in PRUint32 msec); + +%{C++ + // returns the nsIThread for the current thread: + static NS_COM nsresult GetCurrent(nsIThread* *result); + + // returns the nsIThread for an arbitrary PRThread: + static NS_COM nsresult GetIThread(PRThread* prthread, nsIThread* *result); + + // initializes the "main" thread (really, just saves the current thread + // at time of calling. meant to be called once at app startup, in lieu + // of proper static initializers, to save the primordial thread + // for later recall.) + static NS_COM nsresult SetMainThread(); + + // return the "main" thread + static NS_COM nsresult GetMainThread(nsIThread **result); + + static NS_COM PRBool IsMainThread(); +%} +}; + +%{C++ +extern NS_COM nsresult +NS_NewThread(nsIThread* *result, + nsIRunnable* runnable, + PRUint32 stackSize = 0, + PRThreadState state = PR_UNJOINABLE_THREAD, + PRThreadPriority priority = PR_PRIORITY_NORMAL, + PRThreadScope scope = PR_GLOBAL_THREAD); + +extern NS_COM nsresult +NS_NewThread(nsIThread* *result, + PRUint32 stackSize = 0, + PRThreadState state = PR_UNJOINABLE_THREAD, + PRThreadPriority priority = PR_PRIORITY_NORMAL, + PRThreadScope scope = PR_GLOBAL_THREAD); +%} diff --git a/src/libs/xpcom18a4/xpcom/threads/nsITimer.idl b/src/libs/xpcom18a4/xpcom/threads/nsITimer.idl new file mode 100644 index 00000000..855d538d --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/threads/nsITimer.idl @@ -0,0 +1,191 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * ***** 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.org code. + * + * 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): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsISupports.idl" + +interface nsIObserver; + +%{C++ +/** + * The signature of the timer callback function passed to initWithCallback. This + * is the function that will get called when the timer expires if the timer is + * initialized via initWithCallback. + * + * @param aTimer the timer which has expired + * @param aClosure opaque parameter passed to initWithCallback + * + * Implementers should return the following: + * + * @return NS_OK + * + */ +class nsITimer; +typedef void (*nsTimerCallbackFunc) (nsITimer *aTimer, void *aClosure); +%} + +native nsTimerCallbackFunc(nsTimerCallbackFunc); + +/** + * The callback interface for timers. + */ +interface nsITimer; + +[scriptable, uuid(a796816d-7d47-4348-9ab8-c7aeb3216a7d)] +interface nsITimerCallback : nsISupports +{ + /** + * @param aTimer the timer which has expired + */ + void notify(in nsITimer timer); +}; + + +/** + * nsITimer instances must be initialized by calling one of the "init" methods + * documented below. You may also re-initialize an existing instance with new + * delay to avoid the overhead of destroying and creating a timer. It is not + * necessary to cancel the timer in that case. + */ +[scriptable, uuid(29ee628e-a3ea-471f-965d-dc9f11d1c183)] +interface nsITimer : nsISupports +{ + /* Timer types */ + + /** + * Type of a timer that fires once only. + */ + const short TYPE_ONE_SHOT = 0; + + /** + * After firing, a TYPE_REPEATING_SLACK timer is stopped and not restarted + * until its callback completes. Specified timer period will be at least + * the time between when processing for last firing the callback completes + * and when the next firing occurs. + * + * This is the preferable repeating type for most situations. + */ + const short TYPE_REPEATING_SLACK = 1; + + /** + * An TYPE_REPEATING_PRECISE repeating timer aims to have constant period + * between firings. The processing time for each timer callback should not + * influence the timer period. However, if the processing for the last + * timer firing could not be completed until just before the next firing + * occurs, then you could have two timer notification routines being + * executed in quick succession. + */ + const short TYPE_REPEATING_PRECISE = 2; + + /** + * Initialize a timer that will fire after the said delay. + * A user must keep a reference to this timer till it is + * is no longer needed or has been cancelled. + * + * @param aObserver the callback object that observes the + * ``timer-callback'' topic with the subject being + * the timer itself when the timer fires: + * + * observe(nsISupports aSubject, => nsITimer + * string aTopic, => ``timer-callback'' + * wstring data => null + * + * @param aDelay delay in milliseconds for timer to fire + * @param aType timer type per TYPE* consts defined above + */ + void init(in nsIObserver aObserver, in unsigned long aDelay, + in unsigned long aType); + + + /** + * Initialize a timer to fire after the given millisecond interval. + * This version takes a function to call and a closure to pass to + * that function. + * + * @param aFunc The function to invoke + * @param aClosure An opaque pointer to pass to that function + * @param aDelay The millisecond interval + * @param aType Timer type per TYPE* consts defined above + */ + [noscript] void initWithFuncCallback(in nsTimerCallbackFunc aCallback, + in voidPtr aClosure, + in unsigned long aDelay, + in unsigned long aType); + + /** + * Initialize a timer to fire after the given millisecond interval. + * This version takes a function to call and a closure to pass to + * that function. + * + * @param aFunc nsITimerCallback interface to call when timer expires + * @param aDelay The millisecond interval + * @param aType Timer type per TYPE* consts defined above + */ + void initWithCallback(in nsITimerCallback aCallback, + in unsigned long aDelay, + in unsigned long aType); + + /** + * Cancel the timer. This method works on all types, not just on repeating + * timers -- you might want to cancel a TYPE_ONE_SHOT timer, and even reuse + * it by re-initializing it (to avoid object destruction and creation costs + * by conserving one timer instance). + */ + void cancel(); + + /** + * The millisecond delay of the timeout + */ + attribute unsigned long delay; + + /** + * The timer type : one shot or repeating + */ + attribute unsigned long type; + + /** + * The opaque pointer pass to initWithCallback. + */ + [noscript] readonly attribute voidPtr closure; +}; + +%{C++ +#define NS_TIMER_CONTRACTID "@mozilla.org/timer;1" +#define NS_TIMER_CALLBACK_TOPIC "timer-callback" +%} + diff --git a/src/libs/xpcom18a4/xpcom/threads/nsITimerInternal.idl b/src/libs/xpcom18a4/xpcom/threads/nsITimerInternal.idl new file mode 100644 index 00000000..c334ae19 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/threads/nsITimerInternal.idl @@ -0,0 +1,48 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * ***** 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.org code. + * + * 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): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsISupports.idl" + + +[scriptable, uuid(6dd8f185-ceb8-4878-8e38-2d13edc2d079)] +interface nsITimerInternal : nsISupports +{ + attribute boolean idle; +}; + diff --git a/src/libs/xpcom18a4/xpcom/threads/nsITimerManager.idl b/src/libs/xpcom18a4/xpcom/threads/nsITimerManager.idl new file mode 100644 index 00000000..f391d313 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/threads/nsITimerManager.idl @@ -0,0 +1,61 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * ***** 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.org code. + * + * 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): + * Stuart Parmenter + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsISupports.idl" + +[scriptable, uuid(8fce8c6a-1dd2-11b2-8352-8cdd2b965efc)] +interface nsITimerManager : nsISupports +{ + /** + * A flag that turns on the use of idle timers on the main thread. + * this should only be called once. + * + * By default, idle timers are off. + * + * One this is set to TRUE, you are expected to call hasIdleTimers/fireNextIdleTimer + * when you have time in your main loop. + */ + attribute boolean useIdleTimers; + + boolean hasIdleTimers(); + + // Fire next idle timers waiting on the current thread + void fireNextIdleTimer(); +}; diff --git a/src/libs/xpcom18a4/xpcom/threads/nsPIEventQueueChain.h b/src/libs/xpcom18a4/xpcom/threads/nsPIEventQueueChain.h new file mode 100644 index 00000000..8d3c0933 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/threads/nsPIEventQueueChain.h @@ -0,0 +1,93 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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 Communicator client code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +#ifndef nsPIEventQueueChain_h__ +#define nsPIEventQueueChain_h__ + +#include "nsISupports.h" + +// {8f310040-82a7-11d3-95bc-0060083a0bcf} +#define NS_IEVENTQUEUECHAIN_IID \ +{ 0x8f310040, 0x82a7, 0x11d3, { 0x95, 0xbc, 0x0, 0x60, 0x8, 0x3a, 0xb, 0xcf } } + +class nsIEventQueue; + +class nsPIEventQueueChain : public nsISupports +{ +public: + NS_DEFINE_STATIC_IID_ACCESSOR(NS_IEVENTQUEUECHAIN_IID); + + /** + * Add the given queue as the new youngest member of our chain. + * It will not be addrefed. + * @param aQueue the queue. must not be null. + * @return error indication + */ + NS_IMETHOD AppendQueue(nsIEventQueue *aQueue) = 0; + + /** + * Remove this element from the chain. + * @return NS_OK + */ + NS_IMETHOD Unlink() = 0; + + /** + * Fetch (and addref) the youngest member of the chain. + * @param *aQueue the youngest queue. aQueue must not be null. + * @return error indication + */ + NS_IMETHOD GetYoungest(nsIEventQueue **aQueue) = 0; + + /** + * Fetch (and addref) the youngest member of the chain which is + * still accepting events, or at least still contains events in need + * of processing. + * @param *aQueue the youngest such queue. aQueue must not be null. + * *aQueue will be returned null, if no such queue is found. + * @return error indication -- can be NS_OK even if *aQueue is 0 + */ + NS_IMETHOD GetYoungestActive(nsIEventQueue **aQueue) = 0; + + NS_IMETHOD SetYounger(nsPIEventQueueChain *aQueue) = 0; + NS_IMETHOD GetYounger(nsIEventQueue **aQueue) = 0; + + NS_IMETHOD SetElder(nsPIEventQueueChain *aQueue) = 0; + NS_IMETHOD GetElder(nsIEventQueue **aQueue) = 0; +}; + +#endif /* nsPIEventQueueChain_h___ */ + diff --git a/src/libs/xpcom18a4/xpcom/threads/nsProcess.h b/src/libs/xpcom18a4/xpcom/threads/nsProcess.h new file mode 100644 index 00000000..f061fe1c --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/threads/nsProcess.h @@ -0,0 +1,71 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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 Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Don Bragg + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +#ifndef _nsPROCESSWIN_H_ +#define _nsPROCESSWIN_H_ + +#include "nsIProcess.h" +#include "nsIFile.h" +#include "nsString.h" +#include "prproces.h" + +#define NS_PROCESS_CID \ +{0x7b4eeb20, 0xd781, 0x11d4, \ + {0x8A, 0x83, 0x00, 0x10, 0xa4, 0xe0, 0xc9, 0xca}} + +class nsProcess : public nsIProcess +{ +public: + + NS_DECL_ISUPPORTS + NS_DECL_NSIPROCESS + + nsProcess(); + +private: + ~nsProcess() {} + + nsCOMPtr mExecutable; + PRInt32 mExitValue; + nsCString mTargetPath; + PRProcess *mProcess; + +}; + +#endif diff --git a/src/libs/xpcom18a4/xpcom/threads/nsProcessCommon.cpp b/src/libs/xpcom18a4/xpcom/threads/nsProcessCommon.cpp new file mode 100644 index 00000000..07087c2f --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/threads/nsProcessCommon.cpp @@ -0,0 +1,363 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Don Bragg + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/***************************************************************************** + * + * nsProcess is used to execute new processes and specify if you want to + * wait (blocking) or continue (non-blocking). + * + ***************************************************************************** + */ + +#include "nsCOMPtr.h" +#include "nsMemory.h" +#include "nsProcess.h" +#include "prtypes.h" +#include "prio.h" +#include "prenv.h" +#include "nsCRT.h" + +#include + +#if defined( XP_WIN ) +#include "prmem.h" +#include "nsString.h" +#include "nsLiteralString.h" +#include "nsReadableUtils.h" +#include +#endif + +//-------------------------------------------------------------------// +// nsIProcess implementation +//-------------------------------------------------------------------// +NS_IMPL_ISUPPORTS1(nsProcess, nsIProcess) + +//Constructor +nsProcess::nsProcess():mExitValue(-1), + mProcess(nsnull) +{ +} + +NS_IMETHODIMP +nsProcess::Init(nsIFile* executable) +{ + PRBool isFile; + + //First make sure the file exists + nsresult rv = executable->IsFile(&isFile); + if (NS_FAILED(rv)) return rv; + if (!isFile) + return NS_ERROR_FAILURE; + + //Store the nsIFile in mExecutable + mExecutable = executable; + //Get the path because it is needed by the NSPR process creation +#ifdef XP_WIN + rv = mExecutable->GetNativeTarget(mTargetPath); + if (NS_FAILED(rv) || mTargetPath.IsEmpty() ) +#endif + rv = mExecutable->GetNativePath(mTargetPath); + + return rv; +} + + +#if defined( XP_WIN ) +static int assembleCmdLine(char *const *argv, char **cmdLine) +{ + char *const *arg; + char *p, *q; + int cmdLineSize; + int numBackslashes; + int i; + int argNeedQuotes; + + /* + * Find out how large the command line buffer should be. + */ + cmdLineSize = 0; + for (arg = argv; *arg; arg++) { + /* + * \ and " need to be escaped by a \. In the worst case, + * every character is a \ or ", so the string of length + * may double. If we quote an argument, that needs two ". + * Finally, we need a space between arguments, and + * a null byte at the end of command line. + */ + cmdLineSize += 2 * strlen(*arg) /* \ and " need to be escaped */ + + 2 /* we quote every argument */ + + 1; /* space in between, or final null */ + } + p = *cmdLine = (char *) PR_MALLOC(cmdLineSize); + if (p == NULL) { + return -1; + } + + for (arg = argv; *arg; arg++) { + /* Add a space to separates the arguments */ + if (arg != argv) { + *p++ = ' '; + } + q = *arg; + numBackslashes = 0; + argNeedQuotes = 0; + + /* If the argument contains white space, it needs to be quoted. */ + if (strpbrk(*arg, " \f\n\r\t\v")) { + argNeedQuotes = 1; + } + + if (argNeedQuotes) { + *p++ = '"'; + } + while (*q) { + if (*q == '\\') { + numBackslashes++; + q++; + } else if (*q == '"') { + if (numBackslashes) { + /* + * Double the backslashes since they are followed + * by a quote + */ + for (i = 0; i < 2 * numBackslashes; i++) { + *p++ = '\\'; + } + numBackslashes = 0; + } + /* To escape the quote */ + *p++ = '\\'; + *p++ = *q++; + } else { + if (numBackslashes) { + /* + * Backslashes are not followed by a quote, so + * don't need to double the backslashes. + */ + for (i = 0; i < numBackslashes; i++) { + *p++ = '\\'; + } + numBackslashes = 0; + } + *p++ = *q++; + } + } + + /* Now we are at the end of this argument */ + if (numBackslashes) { + /* + * Double the backslashes if we have a quote string + * delimiter at the end. + */ + if (argNeedQuotes) { + numBackslashes *= 2; + } + for (i = 0; i < numBackslashes; i++) { + *p++ = '\\'; + } + } + if (argNeedQuotes) { + *p++ = '"'; + } + } + + *p = '\0'; + return 0; +} +#endif + +// XXXldb |args| has the wrong const-ness +NS_IMETHODIMP +nsProcess::Run(PRBool blocking, const char **args, PRUint32 count, PRUint32 *pid) +{ + nsresult rv = NS_OK; + + // make sure that when we allocate we have 1 greater than the + // count since we need to null terminate the list for the argv to + // pass into PR_CreateProcess + char **my_argv = NULL; +#ifdef VBOX + my_argv = (char **)nsMemory::Alloc(sizeof(char *) * (count + 2) ); +#else + my_argv = (char **)malloc(sizeof(char *) * (count + 2) ); +#endif + if (!my_argv) { + return NS_ERROR_OUT_OF_MEMORY; + } + + // copy the args + PRUint32 i; + for (i=0; i < count; i++) { + my_argv[i+1] = NS_CONST_CAST(char*, args[i]); + } + // we need to set argv[0] to the program name. + my_argv[0] = mTargetPath.BeginWriting(); + // null terminate the array + my_argv[count+1] = NULL; + + #if defined(XP_WIN) + STARTUPINFO startupInfo; + PROCESS_INFORMATION procInfo; + BOOL retVal; + char *cmdLine; + + if (assembleCmdLine(my_argv, &cmdLine) == -1) { + nsMemory::Free(my_argv); + return NS_ERROR_FILE_EXECUTION_FAILED; + } + + ZeroMemory(&startupInfo, sizeof(startupInfo)); + startupInfo.cb = sizeof(startupInfo); + + retVal = CreateProcess(NULL, + // NS_CONST_CAST(char*, mTargetPath.get()), + cmdLine, + NULL, /* security attributes for the new + * process */ + NULL, /* security attributes for the primary + * thread in the new process */ + FALSE, /* inherit handles */ + 0, /* creation flags */ + NULL, /* env */ + NULL, /* current drive and directory */ + &startupInfo, + &procInfo + ); + PR_FREEIF( cmdLine ); + if (blocking) { + + // if success, wait for process termination. the early returns and such + // are a bit ugly but preserving the logic of the nspr code I copied to + // minimize our risk abit. + + if ( retVal == TRUE ) { + DWORD dwRetVal; + unsigned long exitCode; + + dwRetVal = WaitForSingleObject(procInfo.hProcess, INFINITE); + if (dwRetVal == WAIT_FAILED) { + nsMemory::Free(my_argv); + return PR_FAILURE; + } + if (GetExitCodeProcess(procInfo.hProcess, &exitCode) == FALSE) { + mExitValue = exitCode; + nsMemory::Free(my_argv); + return PR_FAILURE; + } + mExitValue = exitCode; + CloseHandle(procInfo.hProcess); + } + else + rv = PR_FAILURE; + } + else { + + // map return value into success code + + if ( retVal == TRUE ) + rv = PR_SUCCESS; + else + rv = PR_FAILURE; + } + +#else + if ( blocking ) { + mProcess = PR_CreateProcess(mTargetPath.get(), my_argv, NULL, NULL); + if (mProcess) + rv = PR_WaitProcess(mProcess, &mExitValue); + } + else { + rv = PR_CreateProcessDetached(mTargetPath.get(), my_argv, NULL, NULL); + } +#endif + + // free up our argv + nsMemory::Free(my_argv); + + if (rv != PR_SUCCESS) + return NS_ERROR_FILE_EXECUTION_FAILED; + return NS_OK; +} + +NS_IMETHODIMP nsProcess::InitWithPid(PRUint32 pid) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsProcess::GetLocation(nsIFile** aLocation) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsProcess::GetPid(PRUint32 *aPid) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsProcess::GetProcessName(char** aProcessName) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsProcess::GetProcessSignature(PRUint32 *aProcessSignature) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsProcess::Kill() +{ + nsresult rv = NS_OK; + if (mProcess) + rv = PR_KillProcess(mProcess); + + return rv; +} + +NS_IMETHODIMP +nsProcess::GetExitValue(PRInt32 *aExitValue) +{ + *aExitValue = mExitValue; + + return NS_OK; +} diff --git a/src/libs/xpcom18a4/xpcom/threads/nsProcessMac.cpp b/src/libs/xpcom18a4/xpcom/threads/nsProcessMac.cpp new file mode 100644 index 00000000..d6411f47 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/threads/nsProcessMac.cpp @@ -0,0 +1,188 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Don Bragg + * Samir Gehani + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/***************************************************************************** + * + * nsProcess is used to execute new processes and specify if you want to + * wait (blocking) or continue (non-blocking). + * + ***************************************************************************** + */ + +#include "nsCOMPtr.h" +#include "nsMemory.h" + +#include "nsProcess.h" + +#include "prtypes.h" +#include "prio.h" +#include "prenv.h" +#include "nsCRT.h" +#include "prthread.h" + +#include +#include + +#include "nsILocalFileMac.h" + +//-------------------------------------------------------------------// +// nsIProcess implementation +//-------------------------------------------------------------------// +NS_IMPL_ISUPPORTS1(nsProcess, nsIProcess) + +//Constructor +nsProcess::nsProcess() +:mExitValue(-1), + mProcess(nsnull) +{ +} + +NS_IMETHODIMP +nsProcess::Init(nsIFile* executable) +{ + PRBool isFile; + + //First make sure the file exists + nsresult rv = executable->IsFile(&isFile); + if (NS_FAILED(rv)) return rv; + + if (!isFile) + return NS_ERROR_FAILURE; + + mExecutable = executable; + + return NS_OK; +} + + +NS_IMETHODIMP +nsProcess::Run(PRBool blocking, const char **args, PRUint32 count, PRUint32 *pid) +{ + OSErr err = noErr; + LaunchParamBlockRec launchPB; + FSSpec resolvedSpec; + Boolean bDone = false; + ProcessInfoRec info; + + nsCOMPtr macExecutable = do_QueryInterface(mExecutable); + macExecutable->GetFSSpec(&resolvedSpec); + + launchPB.launchAppSpec = &resolvedSpec; + launchPB.launchAppParameters = NULL; + launchPB.launchBlockID = extendedBlock; + launchPB.launchEPBLength = extendedBlockLen; + launchPB.launchFileFlags = NULL; + launchPB.launchControlFlags = launchContinue + launchNoFileFlags + launchUseMinimum; + if (!blocking) + launchPB.launchControlFlags += launchDontSwitch; + + err = LaunchApplication(&launchPB); + if (err != noErr) + return NS_ERROR_FAILURE; + + // NOTE: blocking mode assumes you are running on a thread + // other than the UI thread that has teh main event loop + if (blocking) + { + do + { + info.processInfoLength = sizeof(ProcessInfoRec); + info.processName = nil; + info.processAppSpec = nil; + err = GetProcessInformation(&launchPB.launchProcessSN, &info); + + if (err == noErr) + { + // still running so sleep some more (200 msecs) + PR_Sleep(200); + } + else + { + // no longer in process manager's internal list: so assume done + bDone = true; + } + } + while (!bDone); + } + + return NS_OK; +} + +NS_IMETHODIMP nsProcess::InitWithPid(PRUint32 pid) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsProcess::GetLocation(nsIFile** aLocation) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsProcess::GetPid(PRUint32 *aPid) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsProcess::GetProcessName(char** aProcessName) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsProcess::GetProcessSignature(PRUint32 *aProcessSignature) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsProcess::Kill() +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsProcess::GetExitValue(PRInt32 *aExitValue) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + diff --git a/src/libs/xpcom18a4/xpcom/threads/nsThread.cpp b/src/libs/xpcom18a4/xpcom/threads/nsThread.cpp new file mode 100644 index 00000000..b4cc15f4 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/threads/nsThread.cpp @@ -0,0 +1,457 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsThread.h" +#include "prmem.h" +#include "prlog.h" +#include "nsAutoLock.h" + +PRUintn nsThread::kIThreadSelfIndex = 0; +static nsIThread *gMainThread = 0; + +#if defined(PR_LOGGING) +// +// Log module for nsIThread logging... +// +// To enable logging (see prlog.h for full details): +// +// set NSPR_LOG_MODULES=nsIThread:5 +// set NSPR_LOG_FILE=nspr.log +// +// this enables PR_LOG_DEBUG level information and places all output in +// the file nspr.log +// +// gSocketLog is defined in nsSocketTransport.cpp +// +PRLogModuleInfo* nsIThreadLog = nsnull; + +#endif /* PR_LOGGING */ + +//////////////////////////////////////////////////////////////////////////////// + +nsThread::nsThread() + : mThread(nsnull), mDead(PR_FALSE), mStartLock(nsnull) +{ +#if defined(PR_LOGGING) + // + // Initialize the global PRLogModule for nsIThread logging + // if necessary... + // + if (nsIThreadLog == nsnull) { + nsIThreadLog = PR_NewLogModule("nsIThread"); + } +#endif /* PR_LOGGING */ + + // enforce matching of constants to enums in prthread.h + NS_ASSERTION(int(nsIThread::PRIORITY_LOW) == int(PR_PRIORITY_LOW) && + int(nsIThread::PRIORITY_NORMAL) == int(PRIORITY_NORMAL) && + int(nsIThread::PRIORITY_HIGH) == int(PRIORITY_HIGH) && + int(nsIThread::PRIORITY_URGENT) == int(PRIORITY_URGENT) && + int(nsIThread::SCOPE_LOCAL) == int(PR_LOCAL_THREAD) && + int(nsIThread::SCOPE_GLOBAL) == int(PR_GLOBAL_THREAD) && + int(nsIThread::STATE_JOINABLE) == int(PR_JOINABLE_THREAD) && + int(nsIThread::STATE_UNJOINABLE) == int(PR_UNJOINABLE_THREAD), + "Bad constant in nsIThread!"); +} + +nsThread::~nsThread() +{ + if (mStartLock) + PR_DestroyLock(mStartLock); + + PR_LOG(nsIThreadLog, PR_LOG_DEBUG, + ("nsIThread %p destroyed\n", this)); + + // This code used to free the nsIThreadLog loginfo stuff + // Don't do that; loginfo structures are owned by nspr + // and would be freed if we ever called PR_Cleanup() + // see bug 142072 +} + +void +nsThread::Main(void* arg) +{ + nsThread* self = (nsThread*)arg; + + self->WaitUntilReadyToStartMain(); + + nsresult rv = NS_OK; + rv = self->RegisterThreadSelf(); + NS_ASSERTION(rv == NS_OK, "failed to set thread self"); + + PR_LOG(nsIThreadLog, PR_LOG_DEBUG, + ("nsIThread %p start run %p\n", self, self->mRunnable.get())); + rv = self->mRunnable->Run(); + NS_ASSERTION(NS_SUCCEEDED(rv), "runnable failed"); + +#ifdef DEBUG + // Because a thread can die after gMainThread dies and takes nsIThreadLog with it, + // we need to check for it being null so that we don't crash on shutdown. + if (nsIThreadLog) { + PRThreadState state; + rv = self->GetState(&state); + PR_LOG(nsIThreadLog, PR_LOG_DEBUG, + ("nsIThread %p end run %p\n", self, self->mRunnable.get())); + } +#endif + + // explicitly drop the runnable now in case there are circular references + // between it and the thread object + self->mRunnable = nsnull; +} + +void +nsThread::Exit(void* arg) +{ + nsThread* self = (nsThread*)arg; + + if (self->mDead) { + NS_ERROR("attempt to Exit() thread twice"); + return; + } + + self->mDead = PR_TRUE; + +#if defined(PR_LOGGING) + if (nsIThreadLog) { + PR_LOG(nsIThreadLog, PR_LOG_DEBUG, + ("nsIThread %p exited\n", self)); + } +#endif + NS_RELEASE(self); +} + +NS_METHOD +nsThread::Create(nsISupports *aOuter, REFNSIID aIID, void **aResult) +{ + nsThread* thread = new nsThread(); + if (!thread) return NS_ERROR_OUT_OF_MEMORY; + nsresult rv = thread->QueryInterface(aIID, aResult); + if (NS_FAILED(rv)) delete thread; + return rv; +} + +NS_IMPL_THREADSAFE_ISUPPORTS1(nsThread, nsIThread) + +NS_IMETHODIMP +nsThread::Join() +{ + // don't check for mDead here because nspr calls Exit (cleaning up + // thread-local storage) before they let us join with the thread + + PR_LOG(nsIThreadLog, PR_LOG_DEBUG, + ("nsIThread %p start join\n", this)); + if (!mThread) + return NS_ERROR_NOT_INITIALIZED; + PRStatus status = PR_JoinThread(mThread); + // XXX can't use NS_RELEASE here because the macro wants to set + // this to null (bad c++) + PR_LOG(nsIThreadLog, PR_LOG_DEBUG, + ("nsIThread %p end join\n", this)); + if (status == PR_SUCCESS) { + NS_RELEASE_THIS(); // most likely the final release of this thread + return NS_OK; + } + else + return NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +nsThread::GetPriority(PRThreadPriority *result) +{ + if (mDead) + return NS_ERROR_FAILURE; + if (!mThread) + return NS_ERROR_NOT_INITIALIZED; + *result = PR_GetThreadPriority(mThread); + return NS_OK; +} + +NS_IMETHODIMP +nsThread::SetPriority(PRThreadPriority value) +{ + if (mDead) + return NS_ERROR_FAILURE; + if (!mThread) + return NS_ERROR_NOT_INITIALIZED; + PR_SetThreadPriority(mThread, value); + return NS_OK; +} + +NS_IMETHODIMP +nsThread::Interrupt() +{ + if (mDead) + return NS_ERROR_FAILURE; + if (!mThread) + return NS_ERROR_NOT_INITIALIZED; + PRStatus status = PR_Interrupt(mThread); + return status == PR_SUCCESS ? NS_OK : NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +nsThread::GetScope(PRThreadScope *result) +{ + if (mDead) + return NS_ERROR_FAILURE; + if (!mThread) + return NS_ERROR_NOT_INITIALIZED; + *result = PR_GetThreadScope(mThread); + return NS_OK; +} + +NS_IMETHODIMP +nsThread::GetState(PRThreadState *result) +{ + if (mDead) + return NS_ERROR_FAILURE; + if (!mThread) + return NS_ERROR_NOT_INITIALIZED; + *result = PR_GetThreadState(mThread); + return NS_OK; +} + +NS_IMETHODIMP +nsThread::GetPRThread(PRThread* *result) +{ + if (mDead) { + *result = nsnull; + return NS_ERROR_FAILURE; + } + *result = mThread; + return NS_OK; +} + +NS_IMETHODIMP +nsThread::Init(nsIRunnable* runnable, + PRUint32 stackSize, + PRThreadPriority priority, + PRThreadScope scope, + PRThreadState state) +{ + NS_ENSURE_ARG_POINTER(runnable); + mRunnable = runnable; + + NS_ADDREF_THIS(); // released in nsThread::Exit + if (state == PR_JOINABLE_THREAD) + NS_ADDREF_THIS(); // released in nsThread::Join + mStartLock = PR_NewLock(); + if (mStartLock == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + PR_Lock(mStartLock); + mThread = PR_CreateThread(PR_USER_THREAD, Main, this, + priority, scope, state, stackSize); + PR_Unlock(mStartLock); + PR_LOG(nsIThreadLog, PR_LOG_DEBUG, + ("nsIThread %p created\n", this)); + + if (mThread == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + return NS_OK; +} + +/* readonly attribute nsIThread currentThread; */ +NS_IMETHODIMP +nsThread::GetCurrentThread(nsIThread * *aCurrentThread) +{ + return GetIThread(PR_GetCurrentThread(), aCurrentThread); +} + +/* void sleep (in PRUint32 msec); */ +NS_IMETHODIMP +nsThread::Sleep(PRUint32 msec) +{ + if (PR_GetCurrentThread() != mThread) + return NS_ERROR_FAILURE; + + if (PR_Sleep(PR_MillisecondsToInterval(msec)) != PR_SUCCESS) + return NS_ERROR_FAILURE; + + return NS_OK; +} + +NS_COM nsresult +NS_NewThread(nsIThread* *result, + nsIRunnable* runnable, + PRUint32 stackSize, + PRThreadState state, + PRThreadPriority priority, + PRThreadScope scope) +{ + nsresult rv; + nsThread* thread = new nsThread(); + if (thread == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + NS_ADDREF(thread); + + rv = thread->Init(runnable, stackSize, priority, scope, state); + if (NS_FAILED(rv)) { + NS_RELEASE(thread); + return rv; + } + + *result = thread; + return NS_OK; +} + +NS_COM nsresult +NS_NewThread(nsIThread* *result, + PRUint32 stackSize, + PRThreadState state, + PRThreadPriority priority, + PRThreadScope scope) +{ + nsThread* thread = new nsThread(); + if (thread == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + NS_ADDREF(thread); + *result = thread; + return NS_OK; +} + +//////////////////////////////////////////////////////////////////////////////// + +nsresult +nsThread::RegisterThreadSelf() +{ + PRStatus status; + + if (kIThreadSelfIndex == 0) { + status = PR_NewThreadPrivateIndex(&kIThreadSelfIndex, Exit); + if (status != PR_SUCCESS) return NS_ERROR_FAILURE; + } + + status = PR_SetThreadPrivate(kIThreadSelfIndex, this); + if (status != PR_SUCCESS) return NS_ERROR_FAILURE; + + return NS_OK; +} + +void +nsThread::WaitUntilReadyToStartMain() +{ + PR_Lock(mStartLock); + PR_Unlock(mStartLock); + PR_DestroyLock(mStartLock); + mStartLock = nsnull; +} + +NS_COM nsresult +nsIThread::GetCurrent(nsIThread* *result) +{ + return GetIThread(PR_GetCurrentThread(), result); +} + +NS_COM nsresult +nsIThread::GetIThread(PRThread* prthread, nsIThread* *result) +{ + PRStatus status; + nsThread* thread; + + if (nsThread::kIThreadSelfIndex == 0) { + status = PR_NewThreadPrivateIndex(&nsThread::kIThreadSelfIndex, nsThread::Exit); + if (status != PR_SUCCESS) return NS_ERROR_FAILURE; + } + + thread = (nsThread*)PR_GetThreadPrivate(nsThread::kIThreadSelfIndex); + if (thread == nsnull) { + // if the current thread doesn't have an nsIThread associated + // with it, make one + thread = new nsThread(); + if (thread == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + NS_ADDREF(thread); // released by Exit + thread->SetPRThread(prthread); + nsresult rv = thread->RegisterThreadSelf(); + if (NS_FAILED(rv)) return rv; + } + NS_ADDREF(thread); + *result = thread; + return NS_OK; +} + +NS_COM nsresult +nsIThread::SetMainThread() +{ + // strictly speaking, it could be set twice. but practically speaking, + // it's almost certainly an error if it is + if (gMainThread != 0) { + NS_ERROR("Setting main thread twice?"); + return NS_ERROR_FAILURE; + } + return GetCurrent(&gMainThread); +} + +NS_COM nsresult +nsIThread::GetMainThread(nsIThread **result) +{ + NS_ASSERTION(result, "bad result pointer"); + if (gMainThread == 0) + return NS_ERROR_FAILURE; + *result = gMainThread; + NS_ADDREF(gMainThread); + return NS_OK; +} + +NS_COM PRBool +nsIThread::IsMainThread() +{ + if (gMainThread == 0) + return PR_TRUE; + + PRThread *theMainThread; + gMainThread->GetPRThread(&theMainThread); + return theMainThread == PR_GetCurrentThread(); +} + +void +nsThread::Shutdown() +{ + if (gMainThread) { + // XXX nspr doesn't seem to be calling the main thread's destructor + // callback, so let's help it out: + nsThread::Exit(NS_STATIC_CAST(nsThread*, gMainThread)); + nsrefcnt cnt; + NS_RELEASE2(gMainThread, cnt); + NS_WARN_IF_FALSE(cnt == 0, "Main thread being held past XPCOM shutdown."); + gMainThread = nsnull; + + kIThreadSelfIndex = 0; + } +} + +//////////////////////////////////////////////////////////////////////////////// diff --git a/src/libs/xpcom18a4/xpcom/threads/nsThread.h b/src/libs/xpcom18a4/xpcom/threads/nsThread.h new file mode 100644 index 00000000..e75086a7 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/threads/nsThread.h @@ -0,0 +1,92 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** + * This Original Code has been modified by IBM Corporation. + * Modifications made by IBM described herein are + * Copyright (c) International Business Machines + * Corporation, 2000 + * + * Modifications to Mozilla code or documentation + * identified per MPL Section 3.3 + * + * Date Modified by Description of modification + * 04/20/2000 IBM Corp. Added PR_CALLBACK for Optlink use in OS2 + */ + +#ifndef nsThread_h__ +#define nsThread_h__ + +#include "nsIRunnable.h" +#include "nsIThread.h" +#include "nsCOMPtr.h" + +class nsThread : public nsIThread +{ +public: + NS_DECL_ISUPPORTS + + // nsIThread methods: + NS_DECL_NSITHREAD + + // nsThread methods: + nsThread(); + + nsresult RegisterThreadSelf(); + void SetPRThread(PRThread* thread) { mThread = thread; } + void WaitUntilReadyToStartMain(); + + static void PR_CALLBACK Main(void* arg); + static void PR_CALLBACK Exit(void* arg); + static void PR_CALLBACK Shutdown(); + + static PRUintn kIThreadSelfIndex; + + static NS_METHOD + Create(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr); + +private: + ~nsThread(); + +protected: + PRThread* mThread; + nsCOMPtr mRunnable; + PRBool mDead; + PRLock* mStartLock; +}; + +//////////////////////////////////////////////////////////////////////////////// + +#endif // nsThread_h__ diff --git a/src/libs/xpcom18a4/xpcom/threads/nsTimerImpl.cpp b/src/libs/xpcom18a4/xpcom/threads/nsTimerImpl.cpp new file mode 100644 index 00000000..dc19452f --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/threads/nsTimerImpl.cpp @@ -0,0 +1,642 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Stuart Parmenter + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsTimerImpl.h" +#include "TimerThread.h" +#include "nsAutoLock.h" + +#include "nsVoidArray.h" + +#include "nsIEventQueue.h" + +#include "prmem.h" + +static PRInt32 gGenerator = 0; +static TimerThread* gThread = nsnull; +static PRBool gFireOnIdle = PR_FALSE; +static nsTimerManager* gManager = nsnull; + +#ifdef DEBUG_TIMERS +#include + +double nsTimerImpl::sDeltaSumSquared = 0; +double nsTimerImpl::sDeltaSum = 0; +double nsTimerImpl::sDeltaNum = 0; + +static void +myNS_MeanAndStdDev(double n, double sumOfValues, double sumOfSquaredValues, + double *meanResult, double *stdDevResult) +{ + double mean = 0.0, var = 0.0, stdDev = 0.0; + if (n > 0.0 && sumOfValues >= 0) { + mean = sumOfValues / n; + double temp = (n * sumOfSquaredValues) - (sumOfValues * sumOfValues); + if (temp < 0.0 || n <= 1) + var = 0.0; + else + var = temp / (n * (n - 1)); + // for some reason, Windows says sqrt(0.0) is "-1.#J" (?!) so do this: + stdDev = var != 0.0 ? sqrt(var) : 0.0; + } + *meanResult = mean; + *stdDevResult = stdDev; +} +#endif + +NS_IMPL_THREADSAFE_QUERY_INTERFACE2(nsTimerImpl, nsITimer, nsITimerInternal) +NS_IMPL_THREADSAFE_ADDREF(nsTimerImpl) + +NS_IMETHODIMP_(nsrefcnt) nsTimerImpl::Release(void) +{ + nsrefcnt count; + + NS_PRECONDITION(0 != mRefCnt, "dup release"); + count = PR_AtomicDecrement((PRInt32 *)&mRefCnt); + NS_LOG_RELEASE(this, count, "nsTimerImpl"); + if (count == 0) { + mRefCnt = 1; /* stabilize */ + + /* enable this to find non-threadsafe destructors: */ + /* NS_ASSERT_OWNINGTHREAD(nsTimerImpl); */ + NS_DELETEXPCOM(this); + return 0; + } + + // If only one reference remains, and mArmed is set, then the ref must be + // from the TimerThread::mTimers array, so we Cancel this timer to remove + // the mTimers element, and return 0 if Cancel in fact disarmed the timer. + // + // We use an inlined version of nsTimerImpl::Cancel here to check for the + // NS_ERROR_NOT_AVAILABLE code returned by gThread->RemoveTimer when this + // timer is not found in the mTimers array -- i.e., when the timer was not + // in fact armed once we acquired TimerThread::mLock, in spite of mArmed + // being true here. That can happen if the armed timer is being fired by + // TimerThread::Run as we race and test mArmed just before it is cleared by + // the timer thread. If the RemoveTimer call below doesn't find this timer + // in the mTimers array, then the last ref to this timer is held manually + // and temporarily by the TimerThread, so we should fall through to the + // final return and return 1, not 0. + // + // The original version of this thread-based timer code kept weak refs from + // TimerThread::mTimers, removing this timer's weak ref in the destructor, + // but that leads to double-destructions in the race described above, and + // adding mArmed doesn't help, because destructors can't be deferred, once + // begun. But by combining reference-counting and a specialized Release + // method with "is this timer still in the mTimers array once we acquire + // the TimerThread's lock" testing, we defer destruction until we're sure + // that only one thread has its hot little hands on this timer. + // + // Note that both approaches preclude a timer creator, and everyone else + // except the TimerThread who might have a strong ref, from dropping all + // their strong refs without implicitly canceling the timer. Timers need + // non-mTimers-element strong refs to stay alive. + + if (count == 1 && mArmed) { + mCanceled = PR_TRUE; + + if (NS_SUCCEEDED(gThread->RemoveTimer(this))) + return 0; + } + + return count; +} + +nsTimerImpl::nsTimerImpl() : + mClosure(nsnull), + mCallbackType(CALLBACK_TYPE_UNKNOWN), + mIdle(PR_TRUE), + mFiring(PR_FALSE), + mArmed(PR_FALSE), + mCanceled(PR_FALSE), + mGeneration(0), + mDelay(0), + mTimeout(0) +{ + // XXXbsmedberg: shouldn't this be in Init()? + nsIThread::GetCurrent(getter_AddRefs(mCallingThread)); + + mCallback.c = nsnull; + +#ifdef DEBUG_TIMERS + mStart = 0; + mStart2 = 0; +#endif +} + +nsTimerImpl::~nsTimerImpl() +{ + ReleaseCallback(); +} + +//static +nsresult +nsTimerImpl::Startup() +{ + nsresult rv; + + gThread = new TimerThread(); + if (!gThread) return NS_ERROR_OUT_OF_MEMORY; + + NS_ADDREF(gThread); + rv = gThread->InitLocks(); + + if (NS_FAILED(rv)) { + NS_RELEASE(gThread); + } + + return rv; +} + +void nsTimerImpl::Shutdown() +{ +#ifdef DEBUG_TIMERS + if (PR_LOG_TEST(gTimerLog, PR_LOG_DEBUG)) { + double mean = 0, stddev = 0; + myNS_MeanAndStdDev(sDeltaNum, sDeltaSum, sDeltaSumSquared, &mean, &stddev); + + PR_LOG(gTimerLog, PR_LOG_DEBUG, ("sDeltaNum = %f, sDeltaSum = %f, sDeltaSumSquared = %f\n", sDeltaNum, sDeltaSum, sDeltaSumSquared)); + PR_LOG(gTimerLog, PR_LOG_DEBUG, ("mean: %fms, stddev: %fms\n", mean, stddev)); + } +#endif + + if (!gThread) + return; + + gThread->Shutdown(); + NS_RELEASE(gThread); + + gFireOnIdle = PR_FALSE; +} + + +nsresult nsTimerImpl::InitCommon(PRUint32 aType, PRUint32 aDelay) +{ + nsresult rv; + + NS_ENSURE_TRUE(gThread, NS_ERROR_NOT_INITIALIZED); + + rv = gThread->Init(); + NS_ENSURE_SUCCESS(rv, rv); + + /** + * In case of re-Init, both with and without a preceding Cancel, clear the + * mCanceled flag and assign a new mGeneration. But first, remove any armed + * timer from the timer thread's list. + * + * If we are racing with the timer thread to remove this timer and we lose, + * the RemoveTimer call made here will fail to find this timer in the timer + * thread's list, and will return false harmlessly. We test mArmed here to + * avoid the small overhead in RemoveTimer of locking the timer thread and + * checking its list for this timer. It's safe to test mArmed even though + * it might be cleared on another thread in the next cycle (or even already + * be cleared by another CPU whose store hasn't reached our CPU's cache), + * because RemoveTimer is idempotent. + */ + if (mArmed) + gThread->RemoveTimer(this); + mCanceled = PR_FALSE; + mGeneration = PR_AtomicIncrement(&gGenerator); + + mType = (PRUint8)aType; + SetDelayInternal(aDelay); + + return gThread->AddTimer(this); +} + +NS_IMETHODIMP nsTimerImpl::InitWithFuncCallback(nsTimerCallbackFunc aFunc, + void *aClosure, + PRUint32 aDelay, + PRUint32 aType) +{ + ReleaseCallback(); + mCallbackType = CALLBACK_TYPE_FUNC; + mCallback.c = aFunc; + mClosure = aClosure; + + return InitCommon(aType, aDelay); +} + +NS_IMETHODIMP nsTimerImpl::InitWithCallback(nsITimerCallback *aCallback, + PRUint32 aDelay, + PRUint32 aType) +{ + ReleaseCallback(); + mCallbackType = CALLBACK_TYPE_INTERFACE; + mCallback.i = aCallback; + NS_ADDREF(mCallback.i); + + return InitCommon(aType, aDelay); +} + +NS_IMETHODIMP nsTimerImpl::Init(nsIObserver *aObserver, + PRUint32 aDelay, + PRUint32 aType) +{ + ReleaseCallback(); + mCallbackType = CALLBACK_TYPE_OBSERVER; + mCallback.o = aObserver; + NS_ADDREF(mCallback.o); + + return InitCommon(aType, aDelay); +} + +NS_IMETHODIMP nsTimerImpl::Cancel() +{ + mCanceled = PR_TRUE; + + if (gThread) + gThread->RemoveTimer(this); + + return NS_OK; +} + +NS_IMETHODIMP nsTimerImpl::SetDelay(PRUint32 aDelay) +{ + // If we're already repeating precisely, update mTimeout now so that the + // new delay takes effect in the future. + if (mTimeout != 0 && mType == TYPE_REPEATING_PRECISE) + mTimeout = PR_IntervalNow(); + + SetDelayInternal(aDelay); + + if (!mFiring && gThread) + gThread->TimerDelayChanged(this); + + return NS_OK; +} + +NS_IMETHODIMP nsTimerImpl::GetDelay(PRUint32* aDelay) +{ + *aDelay = mDelay; + return NS_OK; +} + +NS_IMETHODIMP nsTimerImpl::SetType(PRUint32 aType) +{ + mType = (PRUint8)aType; + // XXX if this is called, we should change the actual type.. this could effect + // repeating timers. we need to ensure in Fire() that if mType has changed + // during the callback that we don't end up with the timer in the queue twice. + return NS_OK; +} + +NS_IMETHODIMP nsTimerImpl::GetType(PRUint32* aType) +{ + *aType = mType; + return NS_OK; +} + + +NS_IMETHODIMP nsTimerImpl::GetClosure(void** aClosure) +{ + *aClosure = mClosure; + return NS_OK; +} + + +NS_IMETHODIMP nsTimerImpl::GetIdle(PRBool *aIdle) +{ + *aIdle = mIdle; + return NS_OK; +} + +NS_IMETHODIMP nsTimerImpl::SetIdle(PRBool aIdle) +{ + mIdle = aIdle; + return NS_OK; +} + +void nsTimerImpl::Fire() +{ + if (mCanceled) + return; + + PRIntervalTime now = PR_IntervalNow(); +#ifdef DEBUG_TIMERS + if (PR_LOG_TEST(gTimerLog, PR_LOG_DEBUG)) { + PRIntervalTime a = now - mStart; // actual delay in intervals + PRUint32 b = PR_MillisecondsToInterval(mDelay); // expected delay in intervals + PRUint32 d = PR_IntervalToMilliseconds((a > b) ? a - b : b - a); // delta in ms + sDeltaSum += d; + sDeltaSumSquared += double(d) * double(d); + sDeltaNum++; + + PR_LOG(gTimerLog, PR_LOG_DEBUG, ("[this=%p] expected delay time %4dms\n", this, mDelay)); + PR_LOG(gTimerLog, PR_LOG_DEBUG, ("[this=%p] actual delay time %4dms\n", this, PR_IntervalToMilliseconds(a))); + PR_LOG(gTimerLog, PR_LOG_DEBUG, ("[this=%p] (mType is %d) -------\n", this, mType)); + PR_LOG(gTimerLog, PR_LOG_DEBUG, ("[this=%p] delta %4dms\n", this, (a > b) ? (PRInt32)d : -(PRInt32)d)); + + mStart = mStart2; + mStart2 = 0; + } +#endif + + PRIntervalTime timeout = mTimeout; + if (mType == TYPE_REPEATING_PRECISE) { + // Precise repeating timers advance mTimeout by mDelay without fail before + // calling Fire(). + timeout -= PR_MillisecondsToInterval(mDelay); + } + gThread->UpdateFilter(mDelay, timeout, now); + + mFiring = PR_TRUE; + + switch (mCallbackType) { + case CALLBACK_TYPE_FUNC: + mCallback.c(this, mClosure); + break; + case CALLBACK_TYPE_INTERFACE: + mCallback.i->Notify(this); + break; + case CALLBACK_TYPE_OBSERVER: + mCallback.o->Observe(NS_STATIC_CAST(nsITimer*,this), + NS_TIMER_CALLBACK_TOPIC, + nsnull); + break; + default:; + } + + mFiring = PR_FALSE; + +#ifdef DEBUG_TIMERS + if (PR_LOG_TEST(gTimerLog, PR_LOG_DEBUG)) { + PR_LOG(gTimerLog, PR_LOG_DEBUG, + ("[this=%p] Took %dms to fire timer callback\n", + this, PR_IntervalToMilliseconds(PR_IntervalNow() - now))); + } +#endif + + if (mType == TYPE_REPEATING_SLACK) { + SetDelayInternal(mDelay); // force mTimeout to be recomputed. + if (gThread) + gThread->AddTimer(this); + } +} + + +struct TimerEventType : public PLEvent { + PRInt32 mGeneration; +#ifdef DEBUG_TIMERS + PRIntervalTime mInitTime; +#endif +}; + + +void* handleTimerEvent(TimerEventType* event) +{ + nsTimerImpl* timer = NS_STATIC_CAST(nsTimerImpl*, event->owner); + if (event->mGeneration != timer->GetGeneration()) + return nsnull; + +#ifdef DEBUG_TIMERS + if (PR_LOG_TEST(gTimerLog, PR_LOG_DEBUG)) { + PRIntervalTime now = PR_IntervalNow(); + PR_LOG(gTimerLog, PR_LOG_DEBUG, + ("[this=%p] time between PostTimerEvent() and Fire(): %dms\n", + event->owner, PR_IntervalToMilliseconds(now - event->mInitTime))); + } +#endif + + if (gFireOnIdle) { + PRBool idle = PR_FALSE; + timer->GetIdle(&idle); + if (idle) { + NS_ASSERTION(gManager, "Global Thread Manager is null!"); + if (gManager) + gManager->AddIdleTimer(timer); + return nsnull; + } + } + + timer->Fire(); + + return nsnull; +} + +void destroyTimerEvent(TimerEventType* event) +{ + nsTimerImpl *timer = NS_STATIC_CAST(nsTimerImpl*, event->owner); + NS_RELEASE(timer); + PR_DELETE(event); +} + + +void nsTimerImpl::PostTimerEvent() +{ + // XXX we may want to reuse the PLEvent in the case of repeating timers. + TimerEventType* event; + + // construct + event = PR_NEW(TimerEventType); + if (!event) + return; + + // initialize + PL_InitEvent((PLEvent*)event, this, + (PLHandleEventProc)handleTimerEvent, + (PLDestroyEventProc)destroyTimerEvent); + + // Since TimerThread addref'd 'this' for us, we don't need to addref here. + // We will release in destroyMyEvent. We do need to copy the generation + // number from this timer into the event, so we can avoid firing a timer + // that was re-initialized after being canceled. + event->mGeneration = mGeneration; + +#ifdef DEBUG_TIMERS + if (PR_LOG_TEST(gTimerLog, PR_LOG_DEBUG)) { + event->mInitTime = PR_IntervalNow(); + } +#endif + + // If this is a repeating precise timer, we need to calculate the time for + // the next timer to fire before we make the callback. + if (mType == TYPE_REPEATING_PRECISE) { + SetDelayInternal(mDelay); + if (gThread) + gThread->AddTimer(this); + } + + PRThread *thread; + nsresult rv = mCallingThread->GetPRThread(&thread); + if (NS_FAILED(rv)) { + NS_WARNING("Dropping timer event because thread is dead"); + return; + } + + nsCOMPtr queue; + if (gThread) + gThread->mEventQueueService->GetThreadEventQueue(thread, getter_AddRefs(queue)); + if (queue) + queue->PostEvent(event); +} + +void nsTimerImpl::SetDelayInternal(PRUint32 aDelay) +{ + PRIntervalTime delayInterval = PR_MillisecondsToInterval(aDelay); + if (delayInterval > DELAY_INTERVAL_MAX) { + delayInterval = DELAY_INTERVAL_MAX; + aDelay = PR_IntervalToMilliseconds(delayInterval); + } + + mDelay = aDelay; + + PRIntervalTime now = PR_IntervalNow(); + if (mTimeout == 0 || mType != TYPE_REPEATING_PRECISE) + mTimeout = now; + + mTimeout += delayInterval; + +#ifdef DEBUG_TIMERS + if (PR_LOG_TEST(gTimerLog, PR_LOG_DEBUG)) { + if (mStart == 0) + mStart = now; + else + mStart2 = now; + } +#endif +} + +/** + * Timer Manager code + */ + +NS_IMPL_THREADSAFE_ISUPPORTS1(nsTimerManager, nsITimerManager) + +nsTimerManager::nsTimerManager() +{ + mLock = PR_NewLock(); + gManager = this; +} + +nsTimerManager::~nsTimerManager() +{ + gManager = nsnull; + PR_DestroyLock(mLock); + + nsTimerImpl *theTimer; + PRInt32 count = mIdleTimers.Count(); + + for (PRInt32 i = 0; i < count; i++) { + theTimer = NS_STATIC_CAST(nsTimerImpl*, mIdleTimers[i]); + NS_IF_RELEASE(theTimer); + } +} + +NS_IMETHODIMP nsTimerManager::SetUseIdleTimers(PRBool aUseIdleTimers) +{ + if (aUseIdleTimers == PR_FALSE && gFireOnIdle == PR_TRUE) + return NS_ERROR_FAILURE; + + gFireOnIdle = aUseIdleTimers; + + return NS_OK; +} + +NS_IMETHODIMP nsTimerManager::GetUseIdleTimers(PRBool *aUseIdleTimers) +{ + *aUseIdleTimers = gFireOnIdle; + return NS_OK; +} + +NS_IMETHODIMP nsTimerManager::HasIdleTimers(PRBool *aHasTimers) +{ + nsAutoLock lock (mLock); + PRUint32 count = mIdleTimers.Count(); + *aHasTimers = (count != 0); + return NS_OK; +} + +nsresult nsTimerManager::AddIdleTimer(nsITimer* timer) +{ + if (!timer) + return NS_ERROR_FAILURE; + nsAutoLock lock(mLock); + mIdleTimers.AppendElement(timer); + NS_ADDREF(timer); + return NS_OK; +} + +NS_IMETHODIMP nsTimerManager::FireNextIdleTimer() +{ + if (!gFireOnIdle || !nsIThread::IsMainThread()) { + return NS_OK; + } + + nsTimerImpl *theTimer = nsnull; + + { + nsAutoLock lock (mLock); + PRUint32 count = mIdleTimers.Count(); + + if (count == 0) + return NS_OK; + + theTimer = NS_STATIC_CAST(nsTimerImpl*, mIdleTimers[0]); + mIdleTimers.RemoveElement(theTimer); + } + + theTimer->Fire(); + + NS_RELEASE(theTimer); + + return NS_OK; +} + + +// NOT FOR PUBLIC CONSUMPTION! +nsresult +NS_NewTimer(nsITimer* *aResult, nsTimerCallbackFunc aCallback, void *aClosure, + PRUint32 aDelay, PRUint32 aType) +{ + nsTimerImpl* timer = new nsTimerImpl(); + if (timer == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + NS_ADDREF(timer); + + nsresult rv = timer->InitWithFuncCallback(aCallback, aClosure, + aDelay, aType); + if (NS_FAILED(rv)) { + NS_RELEASE(timer); + return rv; + } + + *aResult = timer; + return NS_OK; +} diff --git a/src/libs/xpcom18a4/xpcom/threads/nsTimerImpl.h b/src/libs/xpcom18a4/xpcom/threads/nsTimerImpl.h new file mode 100644 index 00000000..98596f4e --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/threads/nsTimerImpl.h @@ -0,0 +1,195 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Stuart Parmenter + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +#ifndef nsTimerImpl_h___ +#define nsTimerImpl_h___ + +//#define FORCE_PR_LOG /* Allow logging in the release build */ + +#include "nsITimer.h" +#include "nsVoidArray.h" +#include "nsIThread.h" +#include "nsITimerInternal.h" +#include "nsIObserver.h" + +#include "nsCOMPtr.h" + +#include "prlog.h" + +#if defined(PR_LOGGING) +static PRLogModuleInfo *gTimerLog = PR_NewLogModule("nsTimerImpl"); +#define DEBUG_TIMERS 1 +#else +#undef DEBUG_TIMERS +#endif + +#define NS_TIMER_CLASSNAME "Timer" +#define NS_TIMER_CID \ +{ /* 5ff24248-1dd2-11b2-8427-fbab44f29bc8 */ \ + 0x5ff24248, \ + 0x1dd2, \ + 0x11b2, \ + {0x84, 0x27, 0xfb, 0xab, 0x44, 0xf2, 0x9b, 0xc8} \ +} + +enum { + CALLBACK_TYPE_UNKNOWN = 0, + CALLBACK_TYPE_INTERFACE = 1, + CALLBACK_TYPE_FUNC = 2, + CALLBACK_TYPE_OBSERVER = 3 +}; + +// Two timer deadlines must differ by less than half the PRIntervalTime domain. +#define DELAY_INTERVAL_LIMIT PR_BIT(8 * sizeof(PRIntervalTime) - 1) + +// Maximum possible delay (XXX rework to use ms rather than interval ticks). +#define DELAY_INTERVAL_MAX (DELAY_INTERVAL_LIMIT - 1) + +// Is interval-time t less than u, even if t has wrapped PRIntervalTime? +#define TIMER_LESS_THAN(t, u) ((t) - (u) > DELAY_INTERVAL_LIMIT) + +class nsTimerImpl : public nsITimer, public nsITimerInternal +{ +public: + + nsTimerImpl(); + + static NS_HIDDEN_(nsresult) Startup(); + static NS_HIDDEN_(void) Shutdown(); + + friend class TimerThread; + + void Fire(); + void PostTimerEvent(); + void SetDelayInternal(PRUint32 aDelay); + + NS_DECL_ISUPPORTS + NS_DECL_NSITIMER + NS_DECL_NSITIMERINTERNAL + + PRInt32 GetGeneration() { return mGeneration; } + +private: + ~nsTimerImpl(); + + nsresult InitCommon(PRUint32 aType, PRUint32 aDelay); + + void ReleaseCallback() + { + if (mCallbackType == CALLBACK_TYPE_INTERFACE) + NS_RELEASE(mCallback.i); + else if (mCallbackType == CALLBACK_TYPE_OBSERVER) + NS_RELEASE(mCallback.o); + } + + nsCOMPtr mCallingThread; + + void * mClosure; + + union { + nsTimerCallbackFunc c; + nsITimerCallback * i; + nsIObserver * o; + } mCallback; + + // These members are set by Init (called from NS_NewTimer) and never reset. + PRUint8 mCallbackType; + PRPackedBool mIdle; + + // These members are set by the initiating thread, when the timer's type is + // changed and during the period where it fires on that thread. + PRUint8 mType; + PRPackedBool mFiring; + + + // Use a PRBool (int) here to isolate loads and stores of these two members + // done on various threads under the protection of TimerThread::mLock, from + // loads and stores done on the initiating/type-changing/timer-firing thread + // to the above PRUint8/PRPackedBool members. + PRBool mArmed; + PRBool mCanceled; + + // The generation number of this timer, re-generated each time the timer is + // initialized so one-shot timers can be canceled and re-initialized by the + // arming thread without any bad race conditions. + PRInt32 mGeneration; + + PRUint32 mDelay; + PRIntervalTime mTimeout; + +#ifdef DEBUG_TIMERS + PRIntervalTime mStart, mStart2; + static double sDeltaSum; + static double sDeltaSumSquared; + static double sDeltaNum; +#endif + +}; + +#define NS_TIMERMANAGER_CONTRACTID "@mozilla.org/timer/manager;1" +#define NS_TIMERMANAGER_CLASSNAME "Timer Manager" +#define NS_TIMERMANAGER_CID \ +{ /* 4fe206fa-1dd2-11b2-8a0a-88bacbecc7d2 */ \ + 0x4fe206fa, \ + 0x1dd2, \ + 0x11b2, \ + {0x8a, 0x0a, 0x88, 0xba, 0xcb, 0xec, 0xc7, 0xd2} \ +} + +#include "nsITimerManager.h" + +class nsTimerManager : nsITimerManager +{ +public: + nsTimerManager(); + + NS_DECL_ISUPPORTS + NS_DECL_NSITIMERMANAGER + + nsresult AddIdleTimer(nsITimer* timer); +private: + ~nsTimerManager(); + + PRLock *mLock; + nsVoidArray mIdleTimers; +}; + + +#endif /* nsTimerImpl_h___ */ diff --git a/src/libs/xpcom18a4/xpcom/threads/plevent.c b/src/libs/xpcom18a4/xpcom/threads/plevent.c new file mode 100644 index 00000000..c5e9040f --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/threads/plevent.c @@ -0,0 +1,1774 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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.org Code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +#if defined(_WIN32) +#include +#endif + +#if defined(XP_OS2) +#define INCL_DOS +#define INCL_DOSERRORS +#define INCL_WIN +#include +#define DefWindowProc WinDefWindowProc +#endif /* XP_OS2 */ + +#include "nspr.h" +#include "plevent.h" + +#if !defined(WIN32) +#include +#include +#if !defined(XP_OS2) +#include +#endif /* !XP_OS2 */ +#endif /* !Win32 */ + +#if defined(XP_UNIX) +/* for fcntl */ +#include +#include +#endif + +#if defined(XP_BEOS) +#include +#endif + +#if defined(XP_MACOSX) +#if defined(MOZ_WIDGET_COCOA) +#include +#define MAC_USE_CFRUNLOOPSOURCE +#elif defined(TARGET_CARBON) +/* #include */ +/* #define MAC_USE_CARBON_EVENT */ +#include +#define MAC_USE_CFRUNLOOPSOURCE +#endif +#endif + +#include "private/pprthred.h" + +#if defined(VMS) +/* +** On OpenVMS, XtAppAddInput doesn't want a regular fd, instead it +** wants an event flag. So, we don't create and use a pipe for +** notification of when an event queue has something ready, instead +** we use an event flag. Shouldn't be a problem if we only have +** a few event queues. +*/ +#include +#include +#include +#endif /* VMS */ + +#if defined(_WIN32) +/* Comment out the following USE_TIMER define to prevent + * WIN32 from using a WIN32 native timer for PLEvent notification. + * With USE_TIMER defined we will use a timer when pending input + * or paint events are starved, otherwise it will use a posted + * WM_APP msg for PLEvent notification. + */ +#define USE_TIMER + +/* Threshold defined in milliseconds for determining when the input + * and paint events have been held in the WIN32 msg queue too long + */ +#define INPUT_STARVATION_LIMIT 50 +/* The paint starvation limit is set to the smallest value which + * does not cause performance degradation while running page load tests + */ +#define PAINT_STARVATION_LIMIT 750 +/* The WIN9X paint starvation limit is larger because it was + * determined that the following value was required to prevent performance + * degradation on page load tests for WIN98/95 only. + */ +#define WIN9X_PAINT_STARVATION_LIMIT 3000 + +#define TIMER_ID 0 +/* If _md_PerformanceSetting <=0 then no event starvation otherwise events will be starved */ +static PRInt32 _md_PerformanceSetting = 0; +static PRUint32 _md_StarvationDelay = 0; +static PRUint32 _md_SwitchTime = 0; +#endif + +static PRLogModuleInfo *event_lm = NULL; + +/******************************************************************************* + * Private Stuff + ******************************************************************************/ + +/* +** EventQueueType -- Defines notification type for an event queue +** +*/ +typedef enum { + EventQueueIsNative = 1, + EventQueueIsMonitored = 2 +} EventQueueType; + + +struct PLEventQueue { + const char* name; + PRCList queue; + PRMonitor* monitor; + PRThread* handlerThread; + EventQueueType type; + PRPackedBool processingEvents; + PRPackedBool notified; +#if defined(_WIN32) + PRPackedBool timerSet; +#endif + +#if defined(XP_UNIX) && !defined(XP_MACOSX) +#if defined(VMS) + int efn; +#else + PRInt32 eventPipe[2]; +#endif + PLGetEventIDFunc idFunc; + void* idFuncClosure; +#elif defined(_WIN32) || defined(XP_OS2) + HWND eventReceiverWindow; + PRBool removeMsg; +#elif defined(XP_BEOS) + port_id eventport; +#elif defined(XP_MACOSX) +#if defined(MAC_USE_CFRUNLOOPSOURCE) + CFRunLoopSourceRef mRunLoopSource; + CFRunLoopRef mMainRunLoop; + CFStringRef mRunLoopModeStr; /* vbox */ +#elif defined(MAC_USE_CARBON_EVENT) + EventHandlerUPP eventHandlerUPP; + EventHandlerRef eventHandlerRef; +#endif +#endif +}; + +#define PR_EVENT_PTR(_qp) \ + ((PLEvent*) ((char*) (_qp) - offsetof(PLEvent, link))) + +static PRStatus _pl_SetupNativeNotifier(PLEventQueue* self); +static void _pl_CleanupNativeNotifier(PLEventQueue* self); +static PRStatus _pl_NativeNotify(PLEventQueue* self); +static PRStatus _pl_AcknowledgeNativeNotify(PLEventQueue* self); +static void _md_CreateEventQueue( PLEventQueue *eventQueue ); +static PRInt32 _pl_GetEventCount(PLEventQueue* self); + + +#if defined(_WIN32) || defined(XP_OS2) +#if defined(XP_OS2) +ULONG _pr_PostEventMsgId; +#else +UINT _pr_PostEventMsgId; +#endif /* OS2 */ +static char *_pr_eventWindowClass = "XPCOM:EventWindow"; +#endif /* Win32, OS2 */ + +#if defined(_WIN32) + +static LPCTSTR _md_GetEventQueuePropName() { + static ATOM atom = 0; + if (!atom) { + atom = GlobalAddAtom("XPCOM_EventQueue"); + } + return MAKEINTATOM(atom); +} +#endif + +#if defined(MAC_USE_CARBON_EVENT) +enum { + kEventClassPL = FOUR_CHAR_CODE('PLEC'), + + kEventProcessPLEvents = 1, + + kEventParamPLEventQueue = FOUR_CHAR_CODE('OWNQ') +}; + +static pascal Boolean _md_CarbonEventComparator(EventRef inEvent, void *inCompareData); +#endif + +/******************************************************************************* + * Event Queue Operations + ******************************************************************************/ + +/* +** _pl_CreateEventQueue() -- Create the event queue +** +** +*/ +static PLEventQueue * _pl_CreateEventQueue(const char *name, + PRThread *handlerThread, + EventQueueType qtype) +{ + PRStatus err; + PLEventQueue* self = NULL; + PRMonitor* mon = NULL; + + if (event_lm == NULL) + event_lm = PR_NewLogModule("event"); + + self = PR_NEWZAP(PLEventQueue); + if (self == NULL) return NULL; + + mon = PR_NewNamedMonitor(name); + if (mon == NULL) goto error; + + self->name = name; + self->monitor = mon; + self->handlerThread = handlerThread; + self->processingEvents = PR_FALSE; + self->type = qtype; +#if defined(_WIN32) + self->timerSet = PR_FALSE; +#endif +#if defined(_WIN32) || defined(XP_OS2) + self->removeMsg = PR_TRUE; +#endif + + self->notified = PR_FALSE; + + PR_INIT_CLIST(&self->queue); + if ( qtype == EventQueueIsNative ) { + err = _pl_SetupNativeNotifier(self); + if (err) goto error; + _md_CreateEventQueue( self ); + } + return self; + + error: + if (mon != NULL) + PR_DestroyMonitor(mon); + PR_DELETE(self); + return NULL; +} + +PR_IMPLEMENT(PLEventQueue*) +PL_CreateEventQueue(const char* name, PRThread* handlerThread) +{ + return( _pl_CreateEventQueue( name, handlerThread, EventQueueIsNative )); +} + +PR_EXTERN(PLEventQueue *) +PL_CreateNativeEventQueue(const char *name, PRThread *handlerThread) +{ + return( _pl_CreateEventQueue( name, handlerThread, EventQueueIsNative )); +} + +PR_EXTERN(PLEventQueue *) +PL_CreateMonitoredEventQueue(const char *name, PRThread *handlerThread) +{ + return( _pl_CreateEventQueue( name, handlerThread, EventQueueIsMonitored )); +} + +PR_IMPLEMENT(PRMonitor*) +PL_GetEventQueueMonitor(PLEventQueue* self) +{ + return self->monitor; +} + +static void PR_CALLBACK +_pl_destroyEvent(PLEvent* event, void* data, PLEventQueue* queue) +{ + PL_DequeueEvent(event, queue); + PL_DestroyEvent(event); +} + +PR_IMPLEMENT(void) +PL_DestroyEventQueue(PLEventQueue* self) +{ + PR_EnterMonitor(self->monitor); + + /* destroy undelivered events */ + PL_MapEvents(self, _pl_destroyEvent, NULL); + + if ( self->type == EventQueueIsNative ) + _pl_CleanupNativeNotifier(self); + + /* destroying the monitor also destroys the name */ + PR_ExitMonitor(self->monitor); + PR_DestroyMonitor(self->monitor); + PR_DELETE(self); + +} + +PR_IMPLEMENT(PRStatus) +PL_PostEvent(PLEventQueue* self, PLEvent* event) +{ + PRStatus err = PR_SUCCESS; + PRMonitor* mon; + + if (self == NULL) + return PR_FAILURE; + + mon = self->monitor; + PR_EnterMonitor(mon); + +#if defined(XP_UNIX) && !defined(XP_MACOSX) + if (self->idFunc && event) + event->id = self->idFunc(self->idFuncClosure); +#endif + + /* insert event into thread's event queue: */ + if (event != NULL) { + PR_APPEND_LINK(&event->link, &self->queue); + } + + if (self->type == EventQueueIsNative && !self->notified) { + err = _pl_NativeNotify(self); + + if (err != PR_SUCCESS) + goto error; + + self->notified = PR_TRUE; + } + + /* + * This may fall on deaf ears if we're really notifying the native + * thread, and no one has called PL_WaitForEvent (or PL_EventLoop): + */ + err = PR_Notify(mon); + +error: + PR_ExitMonitor(mon); + return err; +} + +PR_IMPLEMENT(void*) +PL_PostSynchronousEvent(PLEventQueue* self, PLEvent* event) +{ + void* result; + + if (self == NULL) + return NULL; + + PR_ASSERT(event != NULL); + + if (PR_GetCurrentThread() == self->handlerThread) { + /* Handle the case where the thread requesting the event handling + * is also the thread that's supposed to do the handling. */ + result = event->handler(event); + } + else { + int i, entryCount; + + event->lock = PR_NewLock(); + if (!event->lock) { + return NULL; + } + event->condVar = PR_NewCondVar(event->lock); + if(!event->condVar) { + PR_DestroyLock(event->lock); + event->lock = NULL; + return NULL; + } + + PR_Lock(event->lock); + + entryCount = PR_GetMonitorEntryCount(self->monitor); + + event->synchronousResult = (void*)PR_TRUE; + + PL_PostEvent(self, event); + + /* We need temporarily to give up our event queue monitor if + we're holding it, otherwise, the thread we're going to wait + for notification from won't be able to enter it to process + the event. */ + if (entryCount) { + for (i = 0; i < entryCount; i++) + PR_ExitMonitor(self->monitor); + } + + event->handled = PR_FALSE; + + while (!event->handled) { + /* wait for event to be handled or destroyed */ + PR_WaitCondVar(event->condVar, PR_INTERVAL_NO_TIMEOUT); + } + + if (entryCount) { + for (i = 0; i < entryCount; i++) + PR_EnterMonitor(self->monitor); + } + + result = event->synchronousResult; + event->synchronousResult = NULL; + PR_Unlock(event->lock); + } + + /* For synchronous events, they're destroyed here on the caller's + thread before the result is returned. See PL_HandleEvent. */ + PL_DestroyEvent(event); + + return result; +} + +PR_IMPLEMENT(PLEvent*) +PL_GetEvent(PLEventQueue* self) +{ + PLEvent* event = NULL; + PRStatus err = PR_SUCCESS; + + if (self == NULL) + return NULL; + + PR_EnterMonitor(self->monitor); + + if (!PR_CLIST_IS_EMPTY(&self->queue)) { + if ( self->type == EventQueueIsNative && + self->notified && + !self->processingEvents && + 0 == _pl_GetEventCount(self) ) + { + err = _pl_AcknowledgeNativeNotify(self); + self->notified = PR_FALSE; + } + if (err) + goto done; + + /* then grab the event and return it: */ + event = PR_EVENT_PTR(self->queue.next); + PR_REMOVE_AND_INIT_LINK(&event->link); + } + + done: + PR_ExitMonitor(self->monitor); + return event; +} + +PR_IMPLEMENT(PRBool) +PL_EventAvailable(PLEventQueue* self) +{ + PRBool result = PR_FALSE; + + if (self == NULL) + return PR_FALSE; + + PR_EnterMonitor(self->monitor); + + if (!PR_CLIST_IS_EMPTY(&self->queue)) + result = PR_TRUE; + + PR_ExitMonitor(self->monitor); + return result; +} + +PR_IMPLEMENT(void) +PL_MapEvents(PLEventQueue* self, PLEventFunProc fun, void* data) +{ + PRCList* qp; + + if (self == NULL) + return; + + PR_EnterMonitor(self->monitor); + qp = self->queue.next; + while (qp != &self->queue) { + PLEvent* event = PR_EVENT_PTR(qp); + qp = qp->next; + (*fun)(event, data, self); + } + PR_ExitMonitor(self->monitor); +} + +static void PR_CALLBACK +_pl_DestroyEventForOwner(PLEvent* event, void* owner, PLEventQueue* queue) +{ + PR_ASSERT(PR_GetMonitorEntryCount(queue->monitor) > 0); + if (event->owner == owner) { + PR_LOG(event_lm, PR_LOG_DEBUG, + ("$$$ \tdestroying event %0x for owner %0x", event, owner)); + PL_DequeueEvent(event, queue); + + if (event->synchronousResult == (void*)PR_TRUE) { + PR_Lock(event->lock); + event->synchronousResult = NULL; + event->handled = PR_TRUE; + PR_NotifyCondVar(event->condVar); + PR_Unlock(event->lock); + } + else { + PL_DestroyEvent(event); + } + } + else { + PR_LOG(event_lm, PR_LOG_DEBUG, + ("$$$ \tskipping event %0x for owner %0x", event, owner)); + } +} + +PR_IMPLEMENT(void) +PL_RevokeEvents(PLEventQueue* self, void* owner) +{ + if (self == NULL) + return; + + PR_LOG(event_lm, PR_LOG_DEBUG, + ("$$$ revoking events for owner %0x", owner)); + + /* + ** First we enter the monitor so that no one else can post any events + ** to the queue: + */ + PR_EnterMonitor(self->monitor); + PR_LOG(event_lm, PR_LOG_DEBUG, ("$$$ owner %0x, entered monitor", owner)); + + /* + ** Discard any pending events for this owner: + */ + PL_MapEvents(self, _pl_DestroyEventForOwner, owner); + +#ifdef DEBUG + { + PRCList* qp = self->queue.next; + while (qp != &self->queue) { + PLEvent* event = PR_EVENT_PTR(qp); + qp = qp->next; + PR_ASSERT(event->owner != owner); + } + } +#endif /* DEBUG */ + + PR_ExitMonitor(self->monitor); + + PR_LOG(event_lm, PR_LOG_DEBUG, + ("$$$ revoking events for owner %0x", owner)); +} + +static PRInt32 +_pl_GetEventCount(PLEventQueue* self) +{ + PRCList* node; + PRInt32 count = 0; + + PR_EnterMonitor(self->monitor); + node = PR_LIST_HEAD(&self->queue); + while (node != &self->queue) { + count++; + node = PR_NEXT_LINK(node); + } + PR_ExitMonitor(self->monitor); + + return count; +} + +PR_IMPLEMENT(void) +PL_ProcessPendingEvents(PLEventQueue* self) +{ + PRInt32 count; + + if (self == NULL) + return; + + + PR_EnterMonitor(self->monitor); + + if (self->processingEvents) { + _pl_AcknowledgeNativeNotify(self); + self->notified = PR_FALSE; + PR_ExitMonitor(self->monitor); + return; + } + self->processingEvents = PR_TRUE; + + /* Only process the events that are already in the queue, and + * not any new events that get added. Do this by counting the + * number of events currently in the queue + */ + count = _pl_GetEventCount(self); + PR_ExitMonitor(self->monitor); + + while (count-- > 0) { + PLEvent* event = PL_GetEvent(self); + if (event == NULL) + break; + + PR_LOG(event_lm, PR_LOG_DEBUG, ("$$$ processing event")); + PL_HandleEvent(event); + PR_LOG(event_lm, PR_LOG_DEBUG, ("$$$ done processing event")); + } + + PR_EnterMonitor(self->monitor); + + if (self->type == EventQueueIsNative) { + count = _pl_GetEventCount(self); + + if (count <= 0) { + _pl_AcknowledgeNativeNotify(self); + self->notified = PR_FALSE; + } + else { + _pl_NativeNotify(self); + self->notified = PR_TRUE; + } + + } + self->processingEvents = PR_FALSE; + + PR_ExitMonitor(self->monitor); +} + +/******************************************************************************* + * Event Operations + ******************************************************************************/ + +PR_IMPLEMENT(void) +PL_InitEvent(PLEvent* self, void* owner, + PLHandleEventProc handler, + PLDestroyEventProc destructor) +{ +#ifdef PL_POST_TIMINGS + self->postTime = PR_IntervalNow(); +#endif + PR_INIT_CLIST(&self->link); + self->handler = handler; + self->destructor = destructor; + self->owner = owner; + self->synchronousResult = NULL; + self->handled = PR_FALSE; + self->lock = NULL; + self->condVar = NULL; +#if defined(XP_UNIX) && !defined(XP_MACOSX) + self->id = 0; +#endif +} + +PR_IMPLEMENT(void*) +PL_GetEventOwner(PLEvent* self) +{ + return self->owner; +} + +PR_IMPLEMENT(void) +PL_HandleEvent(PLEvent* self) +{ + void* result; + if (self == NULL) + return; + + /* This event better not be on an event queue anymore. */ + PR_ASSERT(PR_CLIST_IS_EMPTY(&self->link)); + + result = self->handler(self); + if (NULL != self->synchronousResult) { + PR_Lock(self->lock); + self->synchronousResult = result; + self->handled = PR_TRUE; + PR_NotifyCondVar(self->condVar); + PR_Unlock(self->lock); + } + else { + /* For asynchronous events, they're destroyed by the event-handler + thread. See PR_PostSynchronousEvent. */ + PL_DestroyEvent(self); + } +} +#ifdef PL_POST_TIMINGS +static long s_eventCount = 0; +static long s_totalTime = 0; +#endif + +PR_IMPLEMENT(void) +PL_DestroyEvent(PLEvent* self) +{ + if (self == NULL) + return; + + /* This event better not be on an event queue anymore. */ + PR_ASSERT(PR_CLIST_IS_EMPTY(&self->link)); + + if(self->condVar) + PR_DestroyCondVar(self->condVar); + if(self->lock) + PR_DestroyLock(self->lock); + +#ifdef PL_POST_TIMINGS + s_totalTime += PR_IntervalNow() - self->postTime; + s_eventCount++; + printf("$$$ running avg (%d) \n", PR_IntervalToMilliseconds(s_totalTime/s_eventCount)); +#endif + + self->destructor(self); +} + +PR_IMPLEMENT(void) +PL_DequeueEvent(PLEvent* self, PLEventQueue* queue) +{ + if (self == NULL) + return; + + /* Only the owner is allowed to dequeue events because once the + client has put it in the queue, they have no idea whether it's + been processed and destroyed or not. */ + + PR_ASSERT(queue->handlerThread == PR_GetCurrentThread()); + + PR_EnterMonitor(queue->monitor); + + PR_ASSERT(!PR_CLIST_IS_EMPTY(&self->link)); + +#if 0 + /* I do not think that we need to do this anymore. + if we do not acknowledge and this is the only + only event in the queue, any calls to process + the eventQ will be effective noop. + */ + if (queue->type == EventQueueIsNative) + _pl_AcknowledgeNativeNotify(queue); +#endif + + PR_REMOVE_AND_INIT_LINK(&self->link); + + PR_ExitMonitor(queue->monitor); +} + +PR_IMPLEMENT(void) +PL_FavorPerformanceHint(PRBool favorPerformanceOverEventStarvation, + PRUint32 starvationDelay) +{ +#if defined(_WIN32) + + _md_StarvationDelay = starvationDelay; + + if (favorPerformanceOverEventStarvation) { + _md_PerformanceSetting++; + return; + } + + _md_PerformanceSetting--; + + if (_md_PerformanceSetting == 0) { + /* Switched from allowing event starvation to no event starvation so grab + the current time to determine when to actually switch to using timers + instead of posted WM_APP messages. */ + _md_SwitchTime = PR_IntervalToMilliseconds(PR_IntervalNow()); + } + +#endif +} + +/******************************************************************************* + * Pure Event Queues + * + * For when you're only processing PLEvents and there is no native + * select, thread messages, or AppleEvents. + ******************************************************************************/ + +PR_IMPLEMENT(PLEvent*) +PL_WaitForEvent(PLEventQueue* self) +{ + PLEvent* event; + PRMonitor* mon; + + if (self == NULL) + return NULL; + + mon = self->monitor; + PR_EnterMonitor(mon); + + while ((event = PL_GetEvent(self)) == NULL) { + PRStatus err; + PR_LOG(event_lm, PR_LOG_DEBUG, ("$$$ waiting for event")); + err = PR_Wait(mon, PR_INTERVAL_NO_TIMEOUT); + if ((err == PR_FAILURE) + && (PR_PENDING_INTERRUPT_ERROR == PR_GetError())) break; + } + + PR_ExitMonitor(mon); + return event; +} + +PR_IMPLEMENT(void) +PL_EventLoop(PLEventQueue* self) +{ + if (self == NULL) + return; + + while (PR_TRUE) { + PLEvent* event = PL_WaitForEvent(self); + if (event == NULL) { + /* This can only happen if the current thread is interrupted */ + return; + } + + PR_LOG(event_lm, PR_LOG_DEBUG, ("$$$ processing event")); + PL_HandleEvent(event); + PR_LOG(event_lm, PR_LOG_DEBUG, ("$$$ done processing event")); + } +} + +/******************************************************************************* + * Native Event Queues + * + * For when you need to call select, or WaitNextEvent, and yet also want + * to handle PLEvents. + ******************************************************************************/ + +static PRStatus +_pl_SetupNativeNotifier(PLEventQueue* self) +{ +#if defined(VMS) + unsigned int status; + self->idFunc = 0; + self->idFuncClosure = 0; + status = LIB$GET_EF(&self->efn); + if (!$VMS_STATUS_SUCCESS(status)) + return PR_FAILURE; + PR_LOG(event_lm, PR_LOG_DEBUG, + ("$$$ Allocated event flag %d", self->efn)); + return PR_SUCCESS; +#elif defined(XP_UNIX) && !defined(XP_MACOSX) + int err; + int flags; + + self->idFunc = 0; + self->idFuncClosure = 0; + + err = pipe(self->eventPipe); + if (err != 0) { + return PR_FAILURE; + } +#ifdef VBOX + fcntl(self->eventPipe[0], F_SETFD, FD_CLOEXEC); + fcntl(self->eventPipe[1], F_SETFD, FD_CLOEXEC); +#endif + + /* make the pipe nonblocking */ + flags = fcntl(self->eventPipe[0], F_GETFL, 0); + if (flags == -1) { + goto failed; + } + err = fcntl(self->eventPipe[0], F_SETFL, flags | O_NONBLOCK); + if (err == -1) { + goto failed; + } + flags = fcntl(self->eventPipe[1], F_GETFL, 0); + if (flags == -1) { + goto failed; + } + err = fcntl(self->eventPipe[1], F_SETFL, flags | O_NONBLOCK); + if (err == -1) { + goto failed; + } + return PR_SUCCESS; + +failed: + close(self->eventPipe[0]); + close(self->eventPipe[1]); + return PR_FAILURE; +#elif defined(XP_BEOS) + /* hook up to the nsToolkit queue, however the appshell + * isn't necessairly started, so we might have to create + * the queue ourselves + */ + char portname[64]; + char semname[64]; + PR_snprintf(portname, sizeof(portname), "event%lx", + (long unsigned) self->handlerThread); + PR_snprintf(semname, sizeof(semname), "sync%lx", + (long unsigned) self->handlerThread); + + if((self->eventport = find_port(portname)) < 0) + { + /* create port + */ + self->eventport = create_port(500, portname); + + /* We don't use the sem, but it has to be there + */ + create_sem(0, semname); + } + + return PR_SUCCESS; +#else + return PR_SUCCESS; +#endif +} + +static void +_pl_CleanupNativeNotifier(PLEventQueue* self) +{ +#if defined(VMS) + { + unsigned int status; + PR_LOG(event_lm, PR_LOG_DEBUG, + ("$$$ Freeing event flag %d", self->efn)); + status = LIB$FREE_EF(&self->efn); + } +#elif defined(XP_UNIX) && !defined(XP_MACOSX) + close(self->eventPipe[0]); + close(self->eventPipe[1]); +#elif defined(_WIN32) + if (self->timerSet) { + KillTimer(self->eventReceiverWindow, TIMER_ID); + self->timerSet = PR_FALSE; + } + RemoveProp(self->eventReceiverWindow, _md_GetEventQueuePropName()); + + /* DestroyWindow doesn't do anything when called from a non ui thread. Since + * self->eventReceiverWindow was created on the ui thread, it must be destroyed + * on the ui thread. + */ + SendMessage(self->eventReceiverWindow, WM_CLOSE, 0, 0); + +#elif defined(XP_OS2) + WinDestroyWindow(self->eventReceiverWindow); +#elif defined(MAC_USE_CFRUNLOOPSOURCE) + + CFRunLoopRemoveSource(self->mMainRunLoop, self->mRunLoopSource, kCFRunLoopCommonModes); + CFRunLoopRemoveSource(self->mMainRunLoop, self->mRunLoopSource, self->mRunLoopModeStr); /* vbox */ + CFRelease(self->mRunLoopSource); + CFRelease(self->mMainRunLoop); + CFRelease(self->mRunLoopModeStr); /* vbox */ + +#elif defined(MAC_USE_CARBON_EVENT) + EventComparatorUPP comparator = NewEventComparatorUPP(_md_CarbonEventComparator); + PR_ASSERT(comparator != NULL); + if (comparator) { + FlushSpecificEventsFromQueue(GetMainEventQueue(), comparator, self); + DisposeEventComparatorUPP(comparator); + } + DisposeEventHandlerUPP(self->eventHandlerUPP); + RemoveEventHandler(self->eventHandlerRef); +#endif +} + +#if defined(_WIN32) + +static PRBool _md_WasInputPending = PR_FALSE; +static PRUint32 _md_InputTime = 0; +static PRBool _md_WasPaintPending = PR_FALSE; +static PRUint32 _md_PaintTime = 0; +/* last mouse location */ +static POINT _md_LastMousePos; + +/******************************************************************************* + * Timer callback function. Timers are used on WIN32 instead of APP events + * when there are pending UI events because APP events can cause the GUI to lockup + * because posted messages are processed before other messages. + ******************************************************************************/ + +static void CALLBACK _md_TimerProc( HWND hwnd, UINT uMsg, UINT idEvent, DWORD dwTime ) +{ + PREventQueue* queue = (PREventQueue *) GetProp(hwnd, _md_GetEventQueuePropName()); + PR_ASSERT(queue != NULL); + + KillTimer(hwnd, TIMER_ID); + queue->timerSet = PR_FALSE; + queue->removeMsg = PR_FALSE; + PL_ProcessPendingEvents( queue ); + queue->removeMsg = PR_TRUE; +} + +static PRBool _md_IsWIN9X = PR_FALSE; +static PRBool _md_IsOSSet = PR_FALSE; + +static void _md_DetermineOSType() +{ + OSVERSIONINFO os; + os.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + GetVersionEx(&os); + if (VER_PLATFORM_WIN32_WINDOWS == os.dwPlatformId) { + _md_IsWIN9X = PR_TRUE; + } +} + +static PRUint32 _md_GetPaintStarvationLimit() +{ + if (! _md_IsOSSet) { + _md_DetermineOSType(); + _md_IsOSSet = PR_TRUE; + } + + if (_md_IsWIN9X) { + return WIN9X_PAINT_STARVATION_LIMIT; + } + + return PAINT_STARVATION_LIMIT; +} + + +/* + * Determine if an event is being starved (i.e the starvation limit has + * been exceeded. + * Note: this function uses the current setting and updates the contents + * of the wasPending and lastTime arguments + * + * ispending: PR_TRUE if the event is currently pending + * starvationLimit: Threshold defined in milliseconds for determining when + * the event has been held in the queue too long + * wasPending: PR_TRUE if the last time _md_EventIsStarved was called + * the event was pending. This value is updated within + * this function. + * lastTime: Holds the last time the event was in the queue. + * This value is updated within this function + * returns: PR_TRUE if the event is starved, PR_FALSE otherwise + */ + +static PRBool _md_EventIsStarved(PRBool isPending, PRUint32 starvationLimit, + PRBool *wasPending, PRUint32 *lastTime, + PRUint32 currentTime) +{ + if (*wasPending && isPending) { + /* + * It was pending previously and the event is still + * pending so check to see if the elapsed time is + * over the limit which indicates the event was starved + */ + if ((currentTime - *lastTime) > starvationLimit) { + return PR_TRUE; /* pending and over the limit */ + } + + return PR_FALSE; /* pending but within the limit */ + } + + if (isPending) { + /* + * was_pending must be false so record the current time + * so the elapsed time can be computed the next time this + * function is called + */ + *lastTime = currentTime; + *wasPending = PR_TRUE; + return PR_FALSE; + } + + /* Event is no longer pending */ + *wasPending = PR_FALSE; + return PR_FALSE; +} + +/* Determines if the there is a pending Mouse or input event */ + +static PRBool _md_IsInputPending(WORD qstatus) +{ + /* Return immediately there aren't any pending input or paints. */ + if (qstatus == 0) { + return PR_FALSE; + } + + /* Is there anything other than a QS_MOUSEMOVE pending? */ + if ((qstatus & QS_MOUSEBUTTON) || + (qstatus & QS_KEY) || + (qstatus & QS_HOTKEY)) { + return PR_TRUE; + } + + /* + * Mouse moves need extra processing to determine if the mouse + * pointer actually changed location because Windows automatically + * generates WM_MOVEMOVE events when a new window is created which + * we need to filter out. + */ + if (qstatus & QS_MOUSEMOVE) { + POINT cursorPos; + GetCursorPos(&cursorPos); + if ((_md_LastMousePos.x == cursorPos.x) && + (_md_LastMousePos.y == cursorPos.y)) { + return PR_FALSE; /* This is a fake mouse move */ + } + + /* Real mouse move */ + _md_LastMousePos.x = cursorPos.x; + _md_LastMousePos.y = cursorPos.y; + return PR_TRUE; + } + + return PR_FALSE; +} + +static PRStatus +_pl_NativeNotify(PLEventQueue* self) +{ +#ifdef USE_TIMER + WORD qstatus; + + PRUint32 now = PR_IntervalToMilliseconds(PR_IntervalNow()); + + /* Since calls to set the _md_PerformanceSetting can be nested + * only performance setting values <= 0 will potentially trigger + * the use of a timer. + */ + if ((_md_PerformanceSetting <= 0) && + ((now - _md_SwitchTime) > _md_StarvationDelay)) { + SetTimer(self->eventReceiverWindow, TIMER_ID, 0 ,_md_TimerProc); + self->timerSet = PR_TRUE; + _md_WasInputPending = PR_FALSE; + _md_WasPaintPending = PR_FALSE; + return PR_SUCCESS; + } + + qstatus = HIWORD(GetQueueStatus(QS_INPUT | QS_PAINT)); + + /* Check for starved input */ + if (_md_EventIsStarved( _md_IsInputPending(qstatus), + INPUT_STARVATION_LIMIT, + &_md_WasInputPending, + &_md_InputTime, + now )) { + /* + * Use a timer for notification. Timers have the lowest priority. + * They are not processed until all other events have been processed. + * This allows any starved paints and input to be processed. + */ + SetTimer(self->eventReceiverWindow, TIMER_ID, 0 ,_md_TimerProc); + self->timerSet = PR_TRUE; + + /* + * Clear any pending paint. _md_WasInputPending was cleared in + * _md_EventIsStarved. + */ + _md_WasPaintPending = PR_FALSE; + return PR_SUCCESS; + } + + if (_md_EventIsStarved( (qstatus & QS_PAINT), + _md_GetPaintStarvationLimit(), + &_md_WasPaintPending, + &_md_PaintTime, + now) ) { + /* + * Use a timer for notification. Timers have the lowest priority. + * They are not processed until all other events have been processed. + * This allows any starved paints and input to be processed + */ + SetTimer(self->eventReceiverWindow, TIMER_ID, 0 ,_md_TimerProc); + self->timerSet = PR_TRUE; + + /* + * Clear any pending input. _md_WasPaintPending was cleared in + * _md_EventIsStarved. + */ + _md_WasInputPending = PR_FALSE; + return PR_SUCCESS; + } + + /* + * Nothing is being starved so post a message instead of using a timer. + * Posted messages are processed before other messages so they have the + * highest priority. + */ +#endif + PostMessage( self->eventReceiverWindow, _pr_PostEventMsgId, + (WPARAM)0, (LPARAM)self ); + + return PR_SUCCESS; +}/* --- end _pl_NativeNotify() --- */ +#endif + + +#if defined(XP_OS2) +static PRStatus +_pl_NativeNotify(PLEventQueue* self) +{ + BOOL rc = WinPostMsg( self->eventReceiverWindow, _pr_PostEventMsgId, + 0, MPFROMP(self)); + return (rc == TRUE) ? PR_SUCCESS : PR_FAILURE; +}/* --- end _pl_NativeNotify() --- */ +#endif /* XP_OS2 */ + +#if defined(VMS) +/* Just set the event flag */ +static PRStatus +_pl_NativeNotify(PLEventQueue* self) +{ + unsigned int status; + PR_LOG(event_lm, PR_LOG_DEBUG, + ("_pl_NativeNotify: self=%p efn=%d", + self, self->efn)); + status = SYS$SETEF(self->efn); + return ($VMS_STATUS_SUCCESS(status)) ? PR_SUCCESS : PR_FAILURE; +}/* --- end _pl_NativeNotify() --- */ +#elif defined(XP_UNIX) && !defined(XP_MACOSX) + +static PRStatus +_pl_NativeNotify(PLEventQueue* self) +{ +#define NOTIFY_TOKEN 0xFA + PRInt32 count; + unsigned char buf[] = { NOTIFY_TOKEN }; + +# ifdef VBOX + /* Don't write two chars, because we'll only acknowledge one and that'll + cause trouble for anyone selecting/polling on the read descriptor. */ + if (self->notified) + return PR_SUCCESS; +# endif + + PR_LOG(event_lm, PR_LOG_DEBUG, + ("_pl_NativeNotify: self=%p", + self)); + count = write(self->eventPipe[1], buf, 1); + if (count == 1) + return PR_SUCCESS; + if (count == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) + return PR_SUCCESS; + return PR_FAILURE; +}/* --- end _pl_NativeNotify() --- */ +#endif /* defined(XP_UNIX) && !defined(XP_MACOSX) */ + +#if defined(XP_BEOS) +struct ThreadInterfaceData +{ + void *data; + int32 sync; +}; + +static PRStatus +_pl_NativeNotify(PLEventQueue* self) +{ + struct ThreadInterfaceData id; + id.data = self; + id.sync = false; + write_port(self->eventport, 'natv', &id, sizeof(id)); + + return PR_SUCCESS; /* Is this correct? */ +} +#endif /* XP_BEOS */ + +#if defined(XP_MACOSX) +static PRStatus +_pl_NativeNotify(PLEventQueue* self) +{ +#if defined(MAC_USE_CFRUNLOOPSOURCE) + CFRunLoopSourceSignal(self->mRunLoopSource); + CFRunLoopWakeUp(self->mMainRunLoop); +#elif defined(MAC_USE_CARBON_EVENT) + OSErr err; + EventRef newEvent; + if (CreateEvent(NULL, kEventClassPL, kEventProcessPLEvents, + 0, kEventAttributeNone, &newEvent) != noErr) + return PR_FAILURE; + err = SetEventParameter(newEvent, kEventParamPLEventQueue, + typeUInt32, sizeof(PREventQueue*), &self); + if (err == noErr) { + err = PostEventToQueue(GetMainEventQueue(), newEvent, kEventPriorityLow); + ReleaseEvent(newEvent); + } + if (err != noErr) + return PR_FAILURE; +#endif + return PR_SUCCESS; +} +#endif /* defined(XP_MACOSX) */ + +static PRStatus +_pl_AcknowledgeNativeNotify(PLEventQueue* self) +{ +#if defined(_WIN32) || defined(XP_OS2) +#ifdef XP_OS2 + QMSG aMsg; +#else + MSG aMsg; +#endif + /* + * only remove msg when we've been called directly by + * PL_ProcessPendingEvents, not when we've been called by + * the window proc because the window proc will remove the + * msg for us. + */ + if (self->removeMsg) { + PR_LOG(event_lm, PR_LOG_DEBUG, + ("_pl_AcknowledgeNativeNotify: self=%p", self)); +#ifdef XP_OS2 + WinPeekMsg((HAB)0, &aMsg, self->eventReceiverWindow, + _pr_PostEventMsgId, _pr_PostEventMsgId, PM_REMOVE); +#else + PeekMessage(&aMsg, self->eventReceiverWindow, + _pr_PostEventMsgId, _pr_PostEventMsgId, PM_REMOVE); + if (self->timerSet) { + KillTimer(self->eventReceiverWindow, TIMER_ID); + self->timerSet = PR_FALSE; + } +#endif + } + return PR_SUCCESS; +#elif defined(VMS) + PR_LOG(event_lm, PR_LOG_DEBUG, + ("_pl_AcknowledgeNativeNotify: self=%p efn=%d", + self, self->efn)); + /* + ** If this is the last entry, then clear the event flag. Also make sure + ** the flag is cleared on any spurious wakeups. + */ + sys$clref(self->efn); + return PR_SUCCESS; +#elif defined(XP_UNIX) && !defined(XP_MACOSX) + + PRInt32 count; + unsigned char c; + PR_LOG(event_lm, PR_LOG_DEBUG, + ("_pl_AcknowledgeNativeNotify: self=%p", + self)); + /* consume the byte NativeNotify put in our pipe: */ + count = read(self->eventPipe[0], &c, 1); + if ((count == 1) && (c == NOTIFY_TOKEN)) + return PR_SUCCESS; + if ((count == -1) && ((errno == EAGAIN) || (errno == EWOULDBLOCK))) + return PR_SUCCESS; + return PR_FAILURE; +#elif defined(MAC_USE_CFRUNLOOPSOURCE) /* vbox */ + /* vbox */ + CFRunLoopRunInMode(self->mRunLoopModeStr, 0.0, 1); /* vbox */ + return PR_SUCCESS; /* vbox */ +#else + + /* nothing to do on the other platforms */ + return PR_SUCCESS; +#endif +} + +PR_IMPLEMENT(PRInt32) +PL_GetEventQueueSelectFD(PLEventQueue* self) +{ + if (self == NULL) + return -1; + +#if defined(VMS) + return -(self->efn); +#elif defined(XP_UNIX) && !defined(XP_MACOSX) + return self->eventPipe[0]; +#else + return -1; /* other platforms don't handle this (yet) */ +#endif +} + +PR_IMPLEMENT(PRBool) +PL_IsQueueOnCurrentThread( PLEventQueue *queue ) +{ + PRThread *me = PR_GetCurrentThread(); + return me == queue->handlerThread; +} + +PR_EXTERN(PRBool) +PL_IsQueueNative(PLEventQueue *queue) +{ + return queue->type == EventQueueIsNative ? PR_TRUE : PR_FALSE; +} + +#if defined(_WIN32) +/* +** Global Instance handle... +** In Win32 this is the module handle of the DLL. +** +*/ +static HINSTANCE _pr_hInstance; +#endif + + +#if defined(_WIN32) + +/* +** Initialization routine for the DLL... +*/ + +BOOL WINAPI DllMain (HINSTANCE hDLL, DWORD dwReason, LPVOID lpReserved) +{ + switch (dwReason) + { + case DLL_PROCESS_ATTACH: + _pr_hInstance = hDLL; + break; + + case DLL_THREAD_ATTACH: + break; + + case DLL_THREAD_DETACH: + break; + + case DLL_PROCESS_DETACH: + _pr_hInstance = NULL; + break; + } + + return TRUE; +} +#endif + + +#if defined(_WIN32) || defined(XP_OS2) +#ifdef XP_OS2 +MRESULT EXPENTRY +_md_EventReceiverProc(HWND hwnd, ULONG uMsg, MPARAM wParam, MPARAM lParam) +#else +LRESULT CALLBACK +_md_EventReceiverProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +#endif +{ + if (_pr_PostEventMsgId == uMsg ) + { + PREventQueue *queue = (PREventQueue *)lParam; + queue->removeMsg = PR_FALSE; + PL_ProcessPendingEvents(queue); + queue->removeMsg = PR_TRUE; +#ifdef XP_OS2 + return MRFROMLONG(TRUE); +#else + return TRUE; +#endif + } + return DefWindowProc(hwnd, uMsg, wParam, lParam); +} + +static PRBool isInitialized; +static PRCallOnceType once; +static PRLock *initLock; + +/* +** InitWinEventLib() -- Create the Windows initialization lock +** +*/ +static PRStatus InitEventLib( void ) +{ + PR_ASSERT( initLock == NULL ); + + initLock = PR_NewLock(); + return initLock ? PR_SUCCESS : PR_FAILURE; +} + +#endif /* Win32, OS2 */ + +#if defined(_WIN32) + +/* +** _md_CreateEventQueue() -- ModelDependent initializer +*/ +static void _md_CreateEventQueue( PLEventQueue *eventQueue ) +{ + WNDCLASS wc; + + /* + ** If this is the first call to PL_InitializeEventsLib(), + ** make the call to InitWinEventLib() to create the initLock. + ** + ** Then lock the initializer lock to insure that + ** we have exclusive control over the initialization sequence. + ** + */ + + + /* Register the windows message for XPCOM Event notification */ + _pr_PostEventMsgId = RegisterWindowMessage("XPCOM_PostEvent"); + + /* Register the class for the event receiver window */ + if (!GetClassInfo(_pr_hInstance, _pr_eventWindowClass, &wc)) { + wc.style = 0; + wc.lpfnWndProc = _md_EventReceiverProc; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hInstance = _pr_hInstance; + wc.hIcon = NULL; + wc.hCursor = NULL; + wc.hbrBackground = (HBRUSH) NULL; + wc.lpszMenuName = (LPCSTR) NULL; + wc.lpszClassName = _pr_eventWindowClass; + RegisterClass(&wc); + } + + /* Create the event receiver window */ + eventQueue->eventReceiverWindow = CreateWindow(_pr_eventWindowClass, + "XPCOM:EventReceiver", + 0, 0, 0, 10, 10, + NULL, NULL, _pr_hInstance, + NULL); + PR_ASSERT(eventQueue->eventReceiverWindow); + /* Set a property which can be used to retrieve the event queue + * within the _md_TimerProc callback + */ + SetProp(eventQueue->eventReceiverWindow, + _md_GetEventQueuePropName(), (HANDLE)eventQueue); + + return; +} /* end _md_CreateEventQueue() */ +#endif /* Winxx */ + +#if defined(XP_OS2) +/* +** _md_CreateEventQueue() -- ModelDependent initializer +*/ +static void _md_CreateEventQueue( PLEventQueue *eventQueue ) +{ + /* Must have HMQ for this & can't assume we already have appshell */ + if( FALSE == WinQueryQueueInfo( HMQ_CURRENT, NULL, 0)) + { + PPIB ppib; + PTIB ptib; + HAB hab; + HMQ hmq; + + /* Set our app to be a PM app before attempting Win calls */ + DosGetInfoBlocks(&ptib, &ppib); + ppib->pib_ultype = 3; + + hab = WinInitialize(0); + hmq = WinCreateMsgQueue(hab, 0); + PR_ASSERT(hmq); + } + + if( !_pr_PostEventMsgId) + { + WinRegisterClass( 0 /* hab_current */, + _pr_eventWindowClass, + _md_EventReceiverProc, + 0, 0); + + _pr_PostEventMsgId = WinAddAtom( WinQuerySystemAtomTable(), + "XPCOM_PostEvent"); + } + + eventQueue->eventReceiverWindow = WinCreateWindow( HWND_DESKTOP, + _pr_eventWindowClass, + "", 0, + 0, 0, 0, 0, + HWND_DESKTOP, + HWND_TOP, + 0, + NULL, + NULL); + PR_ASSERT(eventQueue->eventReceiverWindow); + + return; +} /* end _md_CreateEventQueue() */ +#endif /* XP_OS2 */ + +#if (defined(XP_UNIX) && !defined(XP_MACOSX)) || defined(XP_BEOS) +/* +** _md_CreateEventQueue() -- ModelDependent initializer +*/ +static void _md_CreateEventQueue( PLEventQueue *eventQueue ) +{ + /* there's really nothing special to do here, + ** the guts of the unix stuff is in the setupnativenotify + ** and related functions. + */ + return; +} /* end _md_CreateEventQueue() */ +#endif /* (defined(XP_UNIX) && !defined(XP_MACOSX)) || defined(XP_BEOS) */ + +#if defined(MAC_USE_CFRUNLOOPSOURCE) +static void _md_EventReceiverProc(void *info) +{ + PLEventQueue *queue = (PLEventQueue*)info; + PL_ProcessPendingEvents(queue); +} + +#elif defined(MAC_USE_CARBON_EVENT) +/* +** _md_CreateEventQueue() -- ModelDependent initializer +*/ + +static pascal OSStatus _md_EventReceiverProc(EventHandlerCallRef nextHandler, + EventRef inEvent, + void* userData) +{ + if (GetEventClass(inEvent) == kEventClassPL && + GetEventKind(inEvent) == kEventProcessPLEvents) + { + PREventQueue *queue; + if (GetEventParameter(inEvent, kEventParamPLEventQueue, + typeUInt32, NULL, sizeof(PREventQueue*), NULL, + &queue) == noErr) + { + PL_ProcessPendingEvents(queue); + return noErr; + } + } + return eventNotHandledErr; +} + +static pascal Boolean _md_CarbonEventComparator(EventRef inEvent, + void *inCompareData) +{ + Boolean match = false; + + if (GetEventClass(inEvent) == kEventClassPL && + GetEventKind(inEvent) == kEventProcessPLEvents) + { + PREventQueue *queue; + match = ((GetEventParameter(inEvent, kEventParamPLEventQueue, + typeUInt32, NULL, sizeof(PREventQueue*), NULL, + &queue) == noErr) && (queue == inCompareData)); + } + return match; +} + +#endif /* defined(MAC_USE_CARBON_EVENT) */ + +#if defined(XP_MACOSX) +static void _md_CreateEventQueue( PLEventQueue *eventQueue ) +{ +#if defined(MAC_USE_CFRUNLOOPSOURCE) + CFRunLoopSourceContext sourceContext = { 0 }; + sourceContext.version = 0; + sourceContext.info = (void*)eventQueue; + sourceContext.perform = _md_EventReceiverProc; + + /* make a run loop source */ + eventQueue->mRunLoopSource = CFRunLoopSourceCreate(kCFAllocatorDefault, 0 /* order */, &sourceContext); + PR_ASSERT(eventQueue->mRunLoopSource); + + eventQueue->mMainRunLoop = CFRunLoopGetCurrent(); + CFRetain(eventQueue->mMainRunLoop); + + /* and add it to the run loop */ + CFRunLoopAddSource(eventQueue->mMainRunLoop, eventQueue->mRunLoopSource, kCFRunLoopCommonModes); + + /* Add it again but with a unique mode name so we can acknowledge it + without processing any other message sources. */ + { /* vbox */ + char szModeName[80]; /* vbox */ + snprintf(szModeName, sizeof(szModeName), "VBoxXPCOMQueueMode-%p", eventQueue); /* vbox */ + eventQueue->mRunLoopModeStr = CFStringCreateWithCString(kCFAllocatorDefault, /* vbox */ + szModeName, kCFStringEncodingASCII); /* vbox */ + CFRunLoopAddSource(eventQueue->mMainRunLoop, /* vbox */ + eventQueue->mRunLoopSource, eventQueue->mRunLoopModeStr); /* vbox */ + } /* vbox */ + +#elif defined(MAC_USE_CARBON_EVENT) + eventQueue->eventHandlerUPP = NewEventHandlerUPP(_md_EventReceiverProc); + PR_ASSERT(eventQueue->eventHandlerUPP); + if (eventQueue->eventHandlerUPP) + { + EventTypeSpec eventType; + + eventType.eventClass = kEventClassPL; + eventType.eventKind = kEventProcessPLEvents; + + InstallApplicationEventHandler(eventQueue->eventHandlerUPP, 1, &eventType, + eventQueue, &eventQueue->eventHandlerRef); + PR_ASSERT(eventQueue->eventHandlerRef); + } +#endif +} /* end _md_CreateEventQueue() */ +#endif /* defined(XP_MACOSX) */ + +/* extra functions for unix */ + +#if defined(XP_UNIX) && !defined(XP_MACOSX) + +PR_IMPLEMENT(PRInt32) +PL_ProcessEventsBeforeID(PLEventQueue *aSelf, unsigned long aID) +{ + PRInt32 count = 0; + PRInt32 fullCount; + + if (aSelf == NULL) + return -1; + + PR_EnterMonitor(aSelf->monitor); + + if (aSelf->processingEvents) { + PR_ExitMonitor(aSelf->monitor); + return 0; + } + + aSelf->processingEvents = PR_TRUE; + + /* Only process the events that are already in the queue, and + * not any new events that get added. Do this by counting the + * number of events currently in the queue + */ + fullCount = _pl_GetEventCount(aSelf); + PR_LOG(event_lm, PR_LOG_DEBUG, + ("$$$ fullCount is %d id is %ld\n", fullCount, aID)); + + if (fullCount == 0) { + aSelf->processingEvents = PR_FALSE; + PR_ExitMonitor(aSelf->monitor); + return 0; + } + + PR_ExitMonitor(aSelf->monitor); + + while (fullCount-- > 0) { + /* peek at the next event */ + PLEvent *event; + event = PR_EVENT_PTR(aSelf->queue.next); + if (event == NULL) + break; + PR_LOG(event_lm, PR_LOG_DEBUG, ("$$$ processing event %ld\n", + event->id)); + if (event->id >= aID) { + PR_LOG(event_lm, PR_LOG_DEBUG, ("$$$ skipping event and breaking")); + break; + } + + event = PL_GetEvent(aSelf); + PL_HandleEvent(event); + PR_LOG(event_lm, PR_LOG_DEBUG, ("$$$ done processing event")); + count++; + } + + PR_EnterMonitor(aSelf->monitor); + + /* if full count still had items left then there's still items left + in the queue. Let the native notify token stay. */ + + if (aSelf->type == EventQueueIsNative) { + fullCount = _pl_GetEventCount(aSelf); + + if (fullCount <= 0) { + _pl_AcknowledgeNativeNotify(aSelf); + aSelf->notified = PR_FALSE; + } + } + + aSelf->processingEvents = PR_FALSE; + + PR_ExitMonitor(aSelf->monitor); + + return count; +} + +PR_IMPLEMENT(void) +PL_RegisterEventIDFunc(PLEventQueue *aSelf, PLGetEventIDFunc aFunc, + void *aClosure) +{ + aSelf->idFunc = aFunc; + aSelf->idFuncClosure = aClosure; +} + +PR_IMPLEMENT(void) +PL_UnregisterEventIDFunc(PLEventQueue *aSelf) +{ + aSelf->idFunc = 0; + aSelf->idFuncClosure = 0; +} + +#endif /* defined(XP_UNIX) && !defined(XP_MACOSX) */ + +/* --- end plevent.c --- */ diff --git a/src/libs/xpcom18a4/xpcom/threads/plevent.h b/src/libs/xpcom18a4/xpcom/threads/plevent.h new file mode 100644 index 00000000..5bc9c89f --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/threads/plevent.h @@ -0,0 +1,690 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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.org Code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/********************************************************************** +NSPL Events + +Defining Events +--------------- + +Events are essentially structures that represent argument lists for a +function that will run on another thread. All event structures you +define must include a PLEvent struct as their first field: + + typedef struct MyEventType { + PLEvent e; + // arguments follow... + int x; + char* y; + } MyEventType; + +It is also essential that you establish a model of ownership for each +argument passed in an event record, i.e. whether particular arguments +will be deleted by the event destruction callback, or whether they +only loaned to the event handler callback, and guaranteed to persist +until the time at which the handler is called. + +Sending Events +-------------- + +Events are initialized by PL_InitEvent and can be sent via +PL_PostEvent or PL_PostSynchronousEvent. Events can also have an +owner. The owner of an event can revoke all the events in a given +event-queue by calling PL_RevokeEvents. An owner might want +to do this if, for instance, it is being destroyed, and handling the +events after the owner's destruction would cause an error (e.g. an +MWContext). + +Since the act of initializing and posting an event must be coordinated +with it's possible revocation, it is essential that the event-queue's +monitor be entered surrounding the code that constructs, initializes +and posts the event: + + void postMyEvent(MyOwner* owner, int x, char* y) + { + MyEventType* event; + + PL_ENTER_EVENT_QUEUE_MONITOR(myQueue); + + // construct + event = PR_NEW(MyEventType); + if (event == NULL) goto done; + + // initialize + PL_InitEvent(event, owner, + (PLHandleEventProc)handleMyEvent, + (PLDestroyEventProc)destroyMyEvent); + event->x = x; + event->y = strdup(y); + + // post + PL_PostEvent(myQueue, &event->e); + + done: + PL_EXIT_EVENT_QUEUE_MONITOR(myQueue); + } + +If you don't call PL_InitEvent and PL_PostEvent within the +event-queue's monitor, you'll get a big red assert. + +Handling Events +--------------- + +To handle an event you must write a callback that is passed the event +record you defined containing the event's arguments: + + void* handleMyEvent(MyEventType* event) + { + doit(event->x, event->y); + return NULL; // you could return a value for a sync event + } + +Similarly for the destruction callback: + + void destroyMyEvent(MyEventType* event) + { + free(event->y); // created by strdup + free(event); + } + +Processing Events in Your Event Loop +------------------------------------ + +If your main loop only processes events delivered to the event queue, +things are rather simple. You just get the next event (which may +block), and then handle it: + + while (1) { + event = PL_GetEvent(myQueue); + PL_HandleEvent(event); + } + +However, if other things must be waited on, you'll need to obtain a +file-descriptor that represents your event queue, and hand it to select: + + fd = PL_GetEventQueueSelectFD(myQueue); + ...add fd to select set... + while (select(...)) { + if (...fd...) { + PL_ProcessPendingEvents(myQueue); + } + ... + } + +Of course, with Motif and Windows it's more complicated than that, and +on Mac it's completely different, but you get the picture. + +Revoking Events +--------------- +If at any time an owner of events is about to be destroyed, you must +take steps to ensure that no one tries to use the event queue after +the owner is gone (or a crash may result). You can do this by either +processing all the events in the queue before destroying the owner: + + { + ... + PL_ENTER_EVENT_QUEUE_MONITOR(myQueue); + PL_ProcessPendingEvents(myQueue); + DestroyMyOwner(owner); + PL_EXIT_EVENT_QUEUE_MONITOR(myQueue); + ... + } + +or by revoking the events that are in the queue for that owner. This +removes them from the queue and calls their destruction callback: + + { + ... + PL_ENTER_EVENT_QUEUE_MONITOR(myQueue); + PL_RevokeEvents(myQueue, owner); + DestroyMyOwner(owner); + PL_EXIT_EVENT_QUEUE_MONITOR(myQueue); + ... + } + +In either case it is essential that you be in the event-queue's monitor +to ensure that all events are removed from the queue for that owner, +and to ensure that no more events will be delivered for that owner. +**********************************************************************/ + +#ifndef plevent_h___ +#define plevent_h___ + +#include "prtypes.h" +#include "prclist.h" +#include "prthread.h" +#include "prlock.h" +#include "prcvar.h" +#include "prmon.h" + +/* For HWND */ +#if defined(XP_WIN32) +#include +#elif defined(XP_OS2) +#define INCL_DOSMISC +#define INCL_DOSPROCESS +#define INCL_DOSERRORS +#include +#endif + +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +#define PL_DestroyEvent VBoxNsplPL_DestroyEvent +#define PL_HandleEvent VBoxNsplPL_HandleEvent +#define PL_InitEvent VBoxNsplPL_InitEvent +#define PL_CreateEventQueue VBoxNsplPL_CreateEventQueue +#define PL_CreateMonitoredEventQueue VBoxNsplPL_CreateMonitoredEventQueue +#define PL_CreateNativeEventQueue VBoxNsplPL_CreateNativeEventQueue +#define PL_DequeueEvent VBoxNsplPL_DequeueEvent +#define PL_DestroyEventQueue VBoxNsplPL_DestroyEventQueue +#define PL_EventAvailable VBoxNsplPL_EventAvailable +#define PL_EventLoop VBoxNsplPL_EventLoop +#define PL_GetEvent VBoxNsplPL_GetEvent +#define PL_GetEventOwner VBoxNsplPL_GetEventOwner +#define PL_GetEventQueueMonitor VBoxNsplPL_GetEventQueueMonitor +#define PL_GetEventQueueSelectFD VBoxNsplPL_GetEventQueueSelectFD +#define PL_MapEvents VBoxNsplPL_MapEvents +#define PL_PostEvent VBoxNsplPL_PostEvent +#define PL_PostSynchronousEvent VBoxNsplPL_PostSynchronousEvent +#define PL_ProcessEventsBeforeID VBoxNsplPL_ProcessEventsBeforeID +#define PL_ProcessPendingEvents VBoxNsplPL_ProcessPendingEvents +#define PL_RegisterEventIDFunc VBoxNsplPL_RegisterEventIDFunc +#define PL_RevokeEvents VBoxNsplPL_RevokeEvents +#define PL_UnregisterEventIDFunc VBoxNsplPL_UnregisterEventIDFunc +#define PL_WaitForEvent VBoxNsplPL_WaitForEvent +#define PL_IsQueueNative VBoxNsplPL_IsQueueNative +#define PL_IsQueueOnCurrentThread VBoxNsplPL_IsQueueOnCurrentThread +#define PL_FavorPerformanceHint VBoxNsplPL_FavorPerformanceHint +#endif /* VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + +PR_BEGIN_EXTERN_C + +/* Typedefs */ + +typedef struct PLEvent PLEvent; +typedef struct PLEventQueue PLEventQueue; + +/******************************************************************************* + * Event Queue Operations + ******************************************************************************/ + +/* +** Creates a new event queue. Returns NULL on failure. +*/ +PR_EXTERN(PLEventQueue*) +PL_CreateEventQueue(const char* name, PRThread* handlerThread); + + +/* ----------------------------------------------------------------------- +** FUNCTION: PL_CreateNativeEventQueue() +** +** DESCRIPTION: +** PL_CreateNativeEventQueue() creates an event queue that +** uses platform specific notify mechanisms. +** +** For Unix, the platform specific notify mechanism provides +** an FD that may be extracted using the function +** PL_GetEventQueueSelectFD(). The FD returned may be used in +** a select() function call. +** +** For Windows, the platform specific notify mechanism +** provides an event receiver window that is called by +** Windows to process the event using the windows message +** pump engine. +** +** INPUTS: +** name: A name, as a diagnostic aid. +** +** handlerThread: A pointer to the PRThread structure for +** the thread that will "handle" events posted to this event +** queue. +** +** RETURNS: +** A pointer to a PLEventQueue structure or NULL. +** +*/ +PR_EXTERN(PLEventQueue *) + PL_CreateNativeEventQueue( + const char *name, + PRThread *handlerThread + ); + +/* ----------------------------------------------------------------------- +** FUNCTION: PL_CreateMonitoredEventQueue() +** +** DESCRIPTION: +** PL_CreateMonitoredEventQueue() creates an event queue. No +** platform specific notify mechanism is created with the +** event queue. +** +** Users of this type of event queue must explicitly poll the +** event queue to retreive and process events. +** +** +** INPUTS: +** name: A name, as a diagnostic aid. +** +** handlerThread: A pointer to the PRThread structure for +** the thread that will "handle" events posted to this event +** queue. +** +** RETURNS: +** A pointer to a PLEventQueue structure or NULL. +** +*/ +PR_EXTERN(PLEventQueue *) + PL_CreateMonitoredEventQueue( + const char *name, + PRThread *handlerThread + ); + +/* +** Destroys an event queue. +*/ +PR_EXTERN(void) +PL_DestroyEventQueue(PLEventQueue* self); + +/* +** Returns the monitor associated with an event queue. This monitor is +** selectable. The monitor should be entered to protect against anyone +** calling PL_RevokeEvents while the event is trying to be constructed +** and delivered. +*/ +PR_EXTERN(PRMonitor*) +PL_GetEventQueueMonitor(PLEventQueue* self); + +#define PL_ENTER_EVENT_QUEUE_MONITOR(queue) \ + PR_EnterMonitor(PL_GetEventQueueMonitor(queue)) + +#define PL_EXIT_EVENT_QUEUE_MONITOR(queue) \ + PR_ExitMonitor(PL_GetEventQueueMonitor(queue)) + +/* +** Posts an event to an event queue, waking up any threads waiting for an +** event. If event is NULL, notification still occurs, but no event will +** be available. +** +** Any events delivered by this routine will be destroyed by PL_HandleEvent +** when it is called (by the event-handling thread). +*/ +PR_EXTERN(PRStatus) +PL_PostEvent(PLEventQueue* self, PLEvent* event); + +/* +** Like PL_PostEvent, this routine posts an event to the event handling +** thread, but does so synchronously, waiting for the result. The result +** which is the value of the handler routine is returned. +** +** Any events delivered by this routine will be not be destroyed by +** PL_HandleEvent, but instead will be destroyed just before the result is +** returned (by the current thread). +*/ +PR_EXTERN(void*) +PL_PostSynchronousEvent(PLEventQueue* self, PLEvent* event); + +/* +** Gets an event from an event queue. Returns NULL if no event is +** available. +*/ +PR_EXTERN(PLEvent*) +PL_GetEvent(PLEventQueue* self); + +/* +** Returns true if there is an event available for PL_GetEvent. +*/ +PR_EXTERN(PRBool) +PL_EventAvailable(PLEventQueue* self); + +/* +** This is the type of the function that must be passed to PL_MapEvents +** (see description below). +*/ +typedef void +(PR_CALLBACK *PLEventFunProc)(PLEvent* event, void* data, PLEventQueue* queue); + +/* +** Applies a function to every event in the event queue. This can be used +** to selectively handle, filter, or remove events. The data pointer is +** passed to each invocation of the function fun. +*/ +PR_EXTERN(void) +PL_MapEvents(PLEventQueue* self, PLEventFunProc fun, void* data); + +/* +** This routine walks an event queue and destroys any event whose owner is +** the owner specified. The == operation is used to compare owners. +*/ +PR_EXTERN(void) +PL_RevokeEvents(PLEventQueue* self, void* owner); + +/* +** This routine processes all pending events in the event queue. It can be +** called from the thread's main event-processing loop whenever the event +** queue's selectFD is ready (returned by PL_GetEventQueueSelectFD). +*/ +PR_EXTERN(void) +PL_ProcessPendingEvents(PLEventQueue* self); + +/******************************************************************************* + * Pure Event Queues + * + * For when you're only processing PLEvents and there is no native + * select, thread messages, or AppleEvents. + ******************************************************************************/ + +/* +** Blocks until an event can be returned from the event queue. This routine +** may return NULL if the current thread is interrupted. +*/ +PR_EXTERN(PLEvent*) +PL_WaitForEvent(PLEventQueue* self); + +/* +** One stop shopping if all you're going to do is process PLEvents. Just +** call this and it loops forever processing events as they arrive. It will +** terminate when your thread is interrupted or dies. +*/ +PR_EXTERN(void) +PL_EventLoop(PLEventQueue* self); + +/******************************************************************************* + * Native Event Queues + * + * For when you need to call select, or WaitNextEvent, and yet also want + * to handle PLEvents. + ******************************************************************************/ + +/* +** This routine allows you to grab the file descriptor associated with an +** event queue and use it in the readFD set of select. Useful for platforms +** that support select, and must wait on other things besides just PLEvents. +*/ +PR_EXTERN(PRInt32) +PL_GetEventQueueSelectFD(PLEventQueue* self); + +/* +** This routine will allow you to check to see if the given eventQueue in +** on the current thread. It will return PR_TRUE if so, else it will return +** PR_FALSE +*/ +PR_EXTERN(PRBool) + PL_IsQueueOnCurrentThread( PLEventQueue *queue ); + +/* +** Returns whether the queue is native (true) or monitored (false) +*/ +PR_EXTERN(PRBool) +PL_IsQueueNative(PLEventQueue *queue); + +/******************************************************************************* + * Event Operations + ******************************************************************************/ + +/* +** The type of an event handler function. This function is passed as an +** initialization argument to PL_InitEvent, and called by +** PL_HandleEvent. If the event is called synchronously, a void* result +** may be returned (otherwise any result will be ignored). +*/ +typedef void* +(PR_CALLBACK *PLHandleEventProc)(PLEvent* self); + +/* +** The type of an event destructor function. This function is passed as +** an initialization argument to PL_InitEvent, and called by +** PL_DestroyEvent. +*/ +typedef void +(PR_CALLBACK *PLDestroyEventProc)(PLEvent* self); + +/* +** Initializes an event. Usually events are embedded in a larger event +** structure which holds event-specific data, so this is an initializer +** for that embedded part of the structure. +*/ +PR_EXTERN(void) +PL_InitEvent(PLEvent* self, void* owner, + PLHandleEventProc handler, + PLDestroyEventProc destructor); + +/* +** Returns the owner of an event. +*/ +PR_EXTERN(void*) +PL_GetEventOwner(PLEvent* self); + +/* +** Handles an event, calling the event's handler routine. +*/ +PR_EXTERN(void) +PL_HandleEvent(PLEvent* self); + +/* +** Destroys an event, calling the event's destructor. +*/ +PR_EXTERN(void) +PL_DestroyEvent(PLEvent* self); + +/* +** Removes an event from an event queue. +*/ +PR_EXTERN(void) +PL_DequeueEvent(PLEvent* self, PLEventQueue* queue); + + +/* + * Give hint to native PL_Event notification mechanism. If the native + * platform needs to tradeoff performance vs. native event starvation + * this hint tells the native dispatch code which to favor. + * The default is to prevent event starvation. + * + * Calls to this function may be nested. When the number of calls that + * pass PR_TRUE is subtracted from the number of calls that pass PR_FALSE + * is greater than 0, performance is given precedence over preventing + * event starvation. + * + * The starvationDelay arg is only used when + * favorPerformanceOverEventStarvation is PR_FALSE. It is the + * amount of time in milliseconds to wait before the PR_FALSE actually + * takes effect. + */ +PR_EXTERN(void) +PL_FavorPerformanceHint(PRBool favorPerformanceOverEventStarvation, PRUint32 starvationDelay); + + +/******************************************************************************* + * Private Stuff + ******************************************************************************/ + +struct PLEvent { + PRCList link; + PLHandleEventProc handler; + PLDestroyEventProc destructor; + void* owner; + void* synchronousResult; + PRLock* lock; + PRCondVar* condVar; + PRBool handled; +#ifdef PL_POST_TIMINGS + PRIntervalTime postTime; +#endif +#ifdef XP_UNIX + unsigned long id; +#endif /* XP_UNIX */ + /* other fields follow... */ +}; + +/******************************************************************************/ + +/* +** Returns the event queue associated with the main thread. +** +*/ +#if defined(XP_WIN) || defined(XP_OS2) +/* ----------------------------------------------------------------------- +** FUNCTION: PL_GetNativeEventReceiverWindow() +** +** DESCRIPTION: +** PL_GetNativeEventReceiverWindow() returns the windows +** handle of the event receiver window associated with the +** referenced PLEventQueue argument. +** +** INPUTS: +** PLEventQueue pointer +** +** RETURNS: +** event receiver window handle. +** +** RESTRICTIONS: MS-Windows ONLY. +** +*/ +PR_EXTERN(HWND) + PL_GetNativeEventReceiverWindow( + PLEventQueue *eqp + ); +#endif /* XP_WIN || XP_OS2 */ + +#ifdef XP_UNIX +/* ----------------------------------------------------------------------- +** FUNCTION: PL_ProcessEventsBeforeID() +** +** DESCRIPTION: +** +** PL_ProcessEventsBeforeID() will process events in a native event +** queue that have an id that is older than the ID passed in. +** +** INPUTS: +** PLEventQueue *aSelf +** unsigned long aID +** +** RETURNS: +** PRInt32 number of requests processed, -1 on error. +** +** RESTRICTIONS: Unix only (well, X based unix only) +*/ +PR_EXTERN(PRInt32) +PL_ProcessEventsBeforeID(PLEventQueue *aSelf, unsigned long aID); + +/* This prototype is a function that can be called when an event is + posted to stick an ID on it. */ + +typedef unsigned long +(PR_CALLBACK *PLGetEventIDFunc)(void *aClosure); + + +/* ----------------------------------------------------------------------- +** FUNCTION: PL_RegisterEventIDFunc() +** +** DESCRIPTION: +** +** This function registers a function for getting the ID on unix for +** this event queue. +** +** INPUTS: +** PLEventQueue *aSelf +** PLGetEventIDFunc func +** void *aClosure +** +** RETURNS: +** void +** +** RESTRICTIONS: Unix only (well, X based unix only) */ +PR_EXTERN(void) +PL_RegisterEventIDFunc(PLEventQueue *aSelf, PLGetEventIDFunc aFunc, + void *aClosure); + +/* ----------------------------------------------------------------------- +** FUNCTION: PL_RegisterEventIDFunc() +** +** DESCRIPTION: +** +** This function unregisters a function for getting the ID on unix for +** this event queue. +** +** INPUTS: +** PLEventQueue *aSelf +** +** RETURNS: +** void +** +** RESTRICTIONS: Unix only (well, X based unix only) */ +PR_EXTERN(void) +PL_UnregisterEventIDFunc(PLEventQueue *aSelf); + +#endif /* XP_UNIX */ + + +/* ----------------------------------------------------------------------- */ + +#if defined(NO_NSPR_10_SUPPORT) +#else +/********* ???????????????? FIX ME ??????????????????????????? *****/ +/********************** Some old definitions *****************************/ + +/* Re: prevent.h->plevent.h */ +#define PREvent PLEvent +#define PREventQueue PLEventQueue +#define PR_CreateEventQueue PL_CreateEventQueue +#define PR_DestroyEventQueue PL_DestroyEventQueue +#define PR_GetEventQueueMonitor PL_GetEventQueueMonitor +#define PR_ENTER_EVENT_QUEUE_MONITOR PL_ENTER_EVENT_QUEUE_MONITOR +#define PR_EXIT_EVENT_QUEUE_MONITOR PL_EXIT_EVENT_QUEUE_MONITOR +#define PR_PostEvent PL_PostEvent +#define PR_PostSynchronousEvent PL_PostSynchronousEvent +#define PR_GetEvent PL_GetEvent +#define PR_EventAvailable PL_EventAvailable +#define PREventFunProc PLEventFunProc +#define PR_MapEvents PL_MapEvents +#define PR_RevokeEvents PL_RevokeEvents +#define PR_ProcessPendingEvents PL_ProcessPendingEvents +#define PR_WaitForEvent PL_WaitForEvent +#define PR_EventLoop PL_EventLoop +#define PR_GetEventQueueSelectFD PL_GetEventQueueSelectFD +#define PRHandleEventProc PLHandleEventProc +#define PRDestroyEventProc PLDestroyEventProc +#define PR_InitEvent PL_InitEvent +#define PR_GetEventOwner PL_GetEventOwner +#define PR_HandleEvent PL_HandleEvent +#define PR_DestroyEvent PL_DestroyEvent +#define PR_DequeueEvent PL_DequeueEvent +#define PR_GetMainEventQueue PL_GetMainEventQueue + +/********* ????????????? End Fix me ?????????????????????????????? *****/ +#endif /* NO_NSPR_10_SUPPORT */ + +PR_END_EXTERN_C + +#endif /* plevent_h___ */ diff --git a/src/libs/xpcom18a4/xpcom/tools/.cvsignore b/src/libs/xpcom18a4/xpcom/tools/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tools/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/xpcom/tools/Makefile.in b/src/libs/xpcom18a4/xpcom/tools/Makefile.in new file mode 100644 index 00000000..be87de04 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tools/Makefile.in @@ -0,0 +1,53 @@ +# +# ***** 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.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of 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 ***** + +DEPTH = ../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = xpcom +DIRS = registry + +ifeq ($(OS_ARCH),WINNT) +DIRS += windows +endif + +include $(topsrcdir)/config/rules.mk + diff --git a/src/libs/xpcom18a4/xpcom/tools/analyze-xpcom-log.pl b/src/libs/xpcom18a4/xpcom/tools/analyze-xpcom-log.pl new file mode 100755 index 00000000..81ccb212 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tools/analyze-xpcom-log.pl @@ -0,0 +1,177 @@ +#!/usr/local/bin/perl -w + +# Perl script to analyze the xpcom output file +# +# To create xpcom output file : +# +# setenv NSPR_LOG_MODULES nsComponentManager:5 +# setenv NSPR_LOG_FILE xpcom.out +# ./mozilla +# +# Also to try to convert CID -> contractID this program looks for +# a file reg.out in the current directory. To generate this file +# +# $ regExport > reg.out +# +# Usage: analyze-xpcom-log.pl < xpcom.out +# [does better if ./reg.out is available] +# +# Suresh Duddi + + +use strict; + +# forward declarations +sub getContractID($); +sub sum($); + +# Configuration parameters +# Print all ? +my $all = 0; + +# hash of cid -> contractid +my %contractid; +my %contractid_n; +my %failedContractid_n; + +# count of instances of objects created +my (%objs, %objs_contractid, %failedObjs) = (); + +# dlls loaded +my @dlls; + +# temporaries +my ($cid, $n, $str); + +while (<>) { + chomp; + + # dlls loaded + if (/loading \"(.*)\"/) { + push @dlls, $1; + next; + } + + # FAILED ContractIDToClassID + if (/ContractIDToClassID\((.*)\).*\[FAILED\]/) { + $failedContractid_n{$1}++; + next; + } + + # ContractIDToClassID + if (/ContractIDToClassID\((.*)\).*\{(.*)\}/) { + $contractid{$2} = $1; + $contractid_n{$2}++; + next; + } + + # CreateInstance() + if (/CreateInstance\(\{(.*)\}\) succeeded/) { + $objs{$1}++; + next; + } + + # CreateInstanceByContractID() + if (/CreateInstanceByContractID\((.*)\) succeeded/) { + $objs_contractid{$1}++; + next; + } + + # FAILED CreateInstance() + if (/CreateInstance\(\{(.*)\}\) FAILED/) { + $failedObjs{$1}++; + next; + } +} + +# if there is a file named reg.out in the current dir +# then use that to fill in the ContractIDToClassID mapping. +my $REG; +open REG, ") { + chomp; + if (/contractID - (.*)$/) { + my $id = $1; + $cid = ; + chomp($cid); + $cid =~ s/^.*\{(.*)\}.*$/$1/; + $contractid{$cid} = $id; + } +} + +# print results +# ---------------------------------------------------------------------- + +# dlls loaded +print "dlls loaded [", scalar @dlls, "]\n"; +print "----------------------------------------------------------------------\n"; +for ($n = 0; $n < scalar @dlls; $n++) { + printf "%2d. %s\n", $n+1, $dlls[$n]; +} +print "\n"; + +# Objects created +print "Object creations from CID [", sum(\%objs), "]\n"; +print "----------------------------------------------------------------------\n"; +foreach $cid (sort {$objs{$b} <=> $objs{$a} } keys %objs) { + last if (!$all && $objs{$cid} < 50); + printf "%5d. %s - %s\n", $objs{$cid}, $cid, getContractID($cid); +} +print "\n"; + +print "Object creations from ContractID [", sum(\%objs_contractid), "]\n"; +print "----------------------------------------------------------------------\n"; +foreach $cid (sort {$objs_contractid{$b} <=> $objs_contractid{$a} } keys %objs_contractid) { + last if (!$all && $objs_contractid{$cid} < 50); + printf "%5d. %s - %s\n", $objs_contractid{$cid}, $cid, getContractID($cid); +} +print "\n"; + +# FAILED Objects created +print "FAILED Objects creations [", sum(\%failedObjs), "]\n"; +print "----------------------------------------------------------------------\n"; +foreach $cid (sort {$failedObjs{$b} <=> $failedObjs{$a} } keys %failedObjs) { + last if (!$all && $failedObjs{$cid} < 50); + printf "%5d. %s - %s", $failedObjs{$cid}, $cid, getContractID($cid); +} +print "\n"; + +# ContractIDToClassID calls +print "ContractIDToClassID() calls [", sum(\%contractid_n),"]\n"; +print "----------------------------------------------------------------------\n"; +foreach $cid (sort {$contractid_n{$b} <=> $contractid_n{$a} } keys %contractid_n) { + last if (!$all && $contractid_n{$cid} < 50); + printf "%5d. %s - %s\n", $contractid_n{$cid}, $cid, getContractID($cid); +} +print "\n"; + + +# FAILED ContractIDToClassID calls +print "FAILED ContractIDToClassID() calls [", sum(\%failedContractid_n), "]\n"; +print "----------------------------------------------------------------------\n"; +foreach $cid (sort {$failedContractid_n{$b} <=> $failedContractid_n{$a} } keys %failedContractid_n) { + last if (!$all && $failedContractid_n{$cid} < 50); + printf "%5d. %s\n", $failedContractid_n{$cid}, $cid; +} +print "\n"; + + +# Subroutines + +sub getContractID($) { + my $cid = shift; + my $ret = ""; + $ret = $contractid{$cid} if (exists $contractid{$cid}); + return $ret; +} + +sub sum($) { + my $hash_ref = shift; + my %hash = %$hash_ref; + my $total = 0; + my $key; + foreach $key (keys %hash) { + $total += $hash{$key}; + } + return $total; +} diff --git a/src/libs/xpcom18a4/xpcom/tools/registry/.cvsignore b/src/libs/xpcom18a4/xpcom/tools/registry/.cvsignore new file mode 100644 index 00000000..91acd38b --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tools/registry/.cvsignore @@ -0,0 +1,3 @@ +Makefile +regExport +regxpcom diff --git a/src/libs/xpcom18a4/xpcom/tools/registry/Makefile.in b/src/libs/xpcom18a4/xpcom/tools/registry/Makefile.in new file mode 100644 index 00000000..5c19d014 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tools/registry/Makefile.in @@ -0,0 +1,77 @@ +# +# ***** 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.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of 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 ***** + +DEPTH = ../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = xpcom +CPPSRCS = regxpcom.cpp + +DEFINES += -DXPCOM_GLUE + +REQUIRES = \ + string \ + $(NULL) + +LOCAL_INCLUDES = \ + -I$(srcdir)/../../build \ + $(NULL) + +SIMPLE_PROGRAMS = $(CPPSRCS:.cpp=$(BIN_SUFFIX)) + +LIBS = \ + $(DIST)/lib/$(LIB_PREFIX)xpcomglue.$(LIB_SUFFIX) \ + $(NSPR_LIBS) \ + $(NULL) + +# Need to link with CoreFoundation on Mac +ifneq (,$(filter mac cocoa,$(MOZ_WIDGET_TOOLKIT))) +LIBS += \ + $(TK_LIBS) \ + $(NULL) +endif + +SDK_BINARY = \ + $(SIMPLE_PROGRAMS) \ + $(NULL) + +include $(topsrcdir)/config/rules.mk + diff --git a/src/libs/xpcom18a4/xpcom/tools/registry/regxpcom.cpp b/src/libs/xpcom18a4/xpcom/tools/registry/regxpcom.cpp new file mode 100644 index 00000000..b8822b8f --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tools/registry/regxpcom.cpp @@ -0,0 +1,404 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Pierre Phaneuf + * Mike Shaver + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "stdlib.h" +#include "prenv.h" +#include "nspr.h" + +#include "nsXPCOMPrivate.h" // for XPCOM_DLL defines. + +#include "nsXPCOMGlue.h" +#include "nsIComponentManager.h" +#include "nsIComponentRegistrar.h" +#include "nsIServiceManager.h" +#include "nsCOMPtr.h" +#include "nsILocalFile.h" +#include "nsEmbedString.h" +#include "nsIDirectoryService.h" +#include "nsDirectoryServiceDefs.h" + + +static PRBool gUnreg = PR_FALSE, gQuiet = PR_FALSE; + +static const char* gXPCOMLocation = nsnull; +static const char* gCompRegLocation = nsnull; +static const char* gXPTIDatLocation = nsnull; +static char* gPathEnvString = nsnull; + +class DirectoryServiceProvider : public nsIDirectoryServiceProvider +{ + public: + DirectoryServiceProvider() {} + + NS_DECL_ISUPPORTS + NS_DECL_NSIDIRECTORYSERVICEPROVIDER + + private: + ~DirectoryServiceProvider() {} +}; + +NS_IMPL_ISUPPORTS1(DirectoryServiceProvider, nsIDirectoryServiceProvider) + +NS_IMETHODIMP +DirectoryServiceProvider::GetFile(const char *prop, PRBool *persistant, nsIFile **_retval) +{ + nsCOMPtr localFile; + nsresult rv = NS_ERROR_FAILURE; + + *_retval = nsnull; + *persistant = PR_TRUE; + + const char* fileLocation = nsnull; + + if(strcmp(prop, NS_XPCOM_CURRENT_PROCESS_DIR) == 0 && gXPCOMLocation) + { + fileLocation = gXPCOMLocation; + } + else if(strcmp(prop, NS_XPCOM_COMPONENT_REGISTRY_FILE) == 0 && gCompRegLocation) + { + fileLocation = gCompRegLocation; + } + else if(strcmp(prop, NS_XPCOM_XPTI_REGISTRY_FILE) == 0 && gXPTIDatLocation) + { + fileLocation = gXPTIDatLocation; + } + else + return NS_ERROR_FAILURE; + + rv = NS_NewNativeLocalFile(nsEmbedCString(fileLocation), PR_TRUE, getter_AddRefs(localFile)); + if (NS_FAILED(rv)) return rv; + + return localFile->QueryInterface(NS_GET_IID(nsIFile), (void**)_retval); +} + +int startup_xpcom() +{ + nsresult rv; + + if (gXPCOMLocation) { + int len = strlen(gXPCOMLocation); + char* xpcomPath = (char*) malloc(len + sizeof(XPCOM_DLL) + sizeof(XPCOM_FILE_PATH_SEPARATOR) + 1); + sprintf(xpcomPath, "%s" XPCOM_FILE_PATH_SEPARATOR XPCOM_DLL, gXPCOMLocation); + + rv = XPCOMGlueStartup(xpcomPath); + + free(xpcomPath); + + const char* path = PR_GetEnv(XPCOM_SEARCH_KEY); + if (!path) { + path = ""; + } + + if (gPathEnvString) + PR_smprintf_free(gPathEnvString); + + gPathEnvString = PR_smprintf("%s=%s;%s", + XPCOM_SEARCH_KEY, + gXPCOMLocation, + path); + + if (gXPCOMLocation) + PR_SetEnv(gPathEnvString); + } + else + { + rv = XPCOMGlueStartup(nsnull); + } + + if (NS_FAILED(rv)) + { + printf("Can not initialize XPCOM Glue\n"); + return -1; + } + + DirectoryServiceProvider *provider = new DirectoryServiceProvider(); + if ( !provider ) + { + NS_WARNING("GRE_Startup failed"); + XPCOMGlueShutdown(); + return -1; + } + + nsCOMPtr file; + if (gXPCOMLocation) + { + rv = NS_NewNativeLocalFile(nsEmbedCString(gXPCOMLocation), + PR_TRUE, + getter_AddRefs(file)); + } + + NS_ADDREF(provider); + rv = NS_InitXPCOM2(nsnull, file, provider); + NS_RELEASE(provider); + + if (NS_FAILED(rv)) { + printf("Can not initialize XPCOM\n"); + XPCOMGlueShutdown(); + return -1; + } + + return 0; +} + +void shutdown_xpcom() +{ + nsresult rv; + + rv = NS_ShutdownXPCOM(nsnull); + + if (NS_FAILED(rv)) { + printf("Can not shutdown XPCOM cleanly\n"); + } + + rv = XPCOMGlueShutdown(); + + if (NS_FAILED(rv)) { + printf("Can not shutdown XPCOM Glue cleanly\n"); + } + if (gPathEnvString) + PR_smprintf_free(gPathEnvString); +} + + +nsresult Register(const char *path) +{ + startup_xpcom(); + + nsresult rv; + nsCOMPtr spec; + + if (path) { + rv = NS_NewNativeLocalFile(nsEmbedCString(path), + PR_TRUE, + getter_AddRefs(spec)); + } + + nsCOMPtr registrar; + rv = NS_GetComponentRegistrar(getter_AddRefs(registrar)); + if (NS_FAILED(rv)) { + printf("Can not aquire component registrar\n"); + return rv; + } + + if (gUnreg) + rv = registrar->AutoUnregister(spec); + else + rv = registrar->AutoRegister(spec); + + spec = 0; + registrar = 0; + + shutdown_xpcom(); + return rv; +} + + +void ReportSuccess(const char *file) +{ + if (gQuiet) + return; + + if (gUnreg) + printf("Unregistration successful for %s\n", file); + else + printf("Registration successful for %s\n", file); +} + +void ReportError(nsresult err, const char *file) +{ + if (gUnreg) + printf("Unregistration failed: ("); + else + printf("Registration failed: ("); + + switch (err) + { + case NS_ERROR_FACTORY_NOT_LOADED: + printf("Factory not loaded"); + break; + case NS_NOINTERFACE: + printf("No Interface"); + break; + case NS_ERROR_NULL_POINTER: + printf("Null pointer"); + break; + case NS_ERROR_OUT_OF_MEMORY: + printf("Out of memory"); + break; + default: + printf("%x", (unsigned)err); + } + + printf(") %s\n", file); +} + +void printHelp() +{ + printf( +"Mozilla regxpcom - a registration tool for xpcom components \n" +" \n" +"Usage: regxpcom [options] [file-or-directory] \n" +" \n" +"Options: \n" +" -x path Specifies the location of a directory containing the \n" +" xpcom library which will be used when registering new \n" +" component libraries. This path will also be added to \n" +" the \"load library\" path. If not specified, the \n" +" current working directory will be used. \n" +" -c path Specifies the location of the compreg.dat file. If \n" +" not specifed, the compreg.dat file will be in its \n" +" default location. \n" +" -d path Specifies the location of the xpti.dat file. If not \n" +" specifed, the xpti.dat file will be in its default \n" +" location. \n" +" -a Option to register all files in the default component \n" +" directories. This is the default behavior if regxpcom \n" +" is called without any arguments. \n" +" -h Displays this help screen. Must be the only option \n" +" specified. \n" +" -u Option to uninstall the files-or-directory instead of \n" +" registering them. \n" +" -q Quiets some of the output of regxpcom. \n\n"); +} + +int ProcessArgs(int argc, char *argv[]) +{ + int i = 1, result = 0; + nsresult res; + + while (i < argc) + { + if (argv[i][0] == '-') + { + int j; + for (j = 1; argv[i][j] != '\0'; j++) + { + switch (argv[i][j]) + { + case 'h': + printHelp(); + return 0; // we are all done! + + case 'u': + gUnreg = PR_TRUE; + break; + + case 'q': + gQuiet = PR_TRUE; + break; + + case 'a': + { + res = Register(nsnull); + if (NS_FAILED(res)) + { + ReportError(res, "component directory"); + result = -1; + } + else + { + ReportSuccess("component directory"); + } + } + break; + + case 'x': + gXPCOMLocation = argv[++i]; + j = strlen(gXPCOMLocation) - 1; + break; + + case 'c': + gCompRegLocation = argv[++i]; + j = strlen(gCompRegLocation) - 1; + break; + + case 'd': + gXPTIDatLocation = argv[++i]; + j = strlen(gXPTIDatLocation) - 1; + break; + + default: + printf("Unknown option '%c'\n", argv[i][j]); + } + } + } + else + { + res = Register(argv[i]); + + if (NS_FAILED(res)) + { + ReportError(res, argv[i]); + result = -1; + } + else + { + ReportSuccess(argv[i]); + } + } + i++; + } + return result; +} + + +int main(int argc, char *argv[]) +{ + int ret; + nsresult rv; + + /* With no arguments, regxpcom will autoregister */ + if (argc <= 1) + { + startup_xpcom(); + nsCOMPtr registrar; + rv = NS_GetComponentRegistrar(getter_AddRefs(registrar)); + if (NS_FAILED(rv)) { + printf("Can not aquire component registrar\n"); + return -1; + } + rv = registrar->AutoRegister(nsnull); + ret = (NS_FAILED(rv)) ? -1 : 0; + registrar = 0; + shutdown_xpcom(); + } else + ret = ProcessArgs(argc, argv); + + return ret; +} diff --git a/src/libs/xpcom18a4/xpcom/tools/windows/.cvsignore b/src/libs/xpcom18a4/xpcom/tools/windows/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tools/windows/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/xpcom/tools/windows/Makefile.in b/src/libs/xpcom18a4/xpcom/tools/windows/Makefile.in new file mode 100644 index 00000000..f6ba7e69 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tools/windows/Makefile.in @@ -0,0 +1,52 @@ +# +# ***** 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.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of 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 ***** + +DEPTH = ../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +SIMPLE_PROGRAMS = rebasedlls$(BIN_SUFFIX) + +CPPSRCS = rebasedlls.cpp + +OS_LIBS += $(call EXPAND_LIBNAME,imagehlp) + +include $(topsrcdir)/config/rules.mk + diff --git a/src/libs/xpcom18a4/xpcom/tools/windows/rebasedlls.cpp b/src/libs/xpcom18a4/xpcom/tools/windows/rebasedlls.cpp new file mode 100644 index 00000000..321160e7 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tools/windows/rebasedlls.cpp @@ -0,0 +1,104 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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 Communicator client code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 +#include +#include +#include + +static char* gSymbolPath = NULL; +static DWORD gBaseAddr = (DWORD) 0x60000000; +static time_t now; + +static void +ReBase(char* aDLLName) +{ + DWORD oldsize, oldbase, newsize; + DWORD newbase = gBaseAddr; + BOOL b = ReBaseImage(aDLLName, gSymbolPath, TRUE, FALSE, FALSE, + 0, &oldsize, &oldbase, &newsize, &newbase, + now); + DWORD lastError = ::GetLastError(); + printf("%-20s %08x %08x %08x %08x", + aDLLName, oldbase, oldsize, newbase, newsize); + if (!b) { + printf(" (failed: error=%d/0x%x)", lastError, lastError); + } + fputs("\n", stdout); + + // advance base; round size up to nearest 64k + newsize = ((newsize + 65535) >> 16) << 16; + gBaseAddr = newbase + newsize; +} + +static void +Usage() +{ + printf("Usage: ReBase [-libs library-path] dlls...\n"); +} + +int +main(int argc, char** argv) +{ + now = time(0); + int i; + for (i = 1; i < argc; i++) { + if (argv[i][0] == '-') { + if (strcmp(argv[i], "-libs") == 0) { + if (i == argc - 1) { + Usage(); + return -1; + } + gSymbolPath = argv[++i]; + } + else { + Usage(); + return -1; + } + } + else + break; + } + + if (i < argc) { + printf("Library OldBase OldSize NewBase NewSize\n"); + printf("------- ------- ------- ------- -------\n"); + } + for (; i < argc; i++) { + ReBase(argv[i]); + } + return 0; +} diff --git a/src/libs/xpcom18a4/xpcom/typelib/.cvsignore b/src/libs/xpcom18a4/xpcom/typelib/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/typelib/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/xpcom/typelib/Makefile.in b/src/libs/xpcom18a4/xpcom/typelib/Makefile.in new file mode 100644 index 00000000..43d92023 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/typelib/Makefile.in @@ -0,0 +1,49 @@ +# +# ***** 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.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of 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 ***** + +DEPTH = ../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = xpcom +DIRS = xpt xpidl + +include $(topsrcdir)/config/rules.mk + diff --git a/src/libs/xpcom18a4/xpcom/typelib/xpidl/.cvsignore b/src/libs/xpcom18a4/xpcom/typelib/xpidl/.cvsignore new file mode 100644 index 00000000..8e5eac0d --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/typelib/xpidl/.cvsignore @@ -0,0 +1,2 @@ +xpidl +Makefile diff --git a/src/libs/xpcom18a4/xpcom/typelib/xpidl/Makefile.in b/src/libs/xpcom18a4/xpcom/typelib/xpidl/Makefile.in new file mode 100644 index 00000000..ae228ef0 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/typelib/xpidl/Makefile.in @@ -0,0 +1,88 @@ +# +# The contents of this file are subject to the Netscape 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/NPL/ +# +# 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.org code. +# +# The Initial Developer of the Original Code is Netscape +# Communications Corporation. Portions created by Netscape are +# Copyright (C) 1998 Netscape Communications Corporation. All +# Rights Reserved. +# +# Contributor(s): +# + +DEPTH = ../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = xpcom +PROGRAM = xpidl$(BIN_SUFFIX) +INTERNAL_TOOLS = 1 + +# glib and libIDL link against the non-debug msvcrt +MOZ_NO_DEBUG_RTL=1 + +CSRCS = \ + xpidl.c \ + xpidl_idl.c \ + xpidl_util.c \ + xpidl_header.c \ + xpidl_typelib.c \ + xpidl_doc.c \ + xpidl_java.c \ + $(NULL) + +SDK_BINARY = \ + $(PROGRAM) \ + $(NULL) + +ifdef CROSS_COMPILE +HOST_PROGRAM = host_xpidl$(HOST_BIN_SUFFIX) +HOST_CSRCS = $(CSRCS) +endif + +include $(topsrcdir)/config/rules.mk + +CFLAGS += $(LIBIDL_CFLAGS) + +# Compile directly against the static lib, so we can use xpidl during the build +# without the shared library path being set. +ifeq (WINNT,$(OS_ARCH)) +DEFINES += -DEXPORT_XPT_API +ifndef GNU_CC +LDFLAGS += -SUBSYSTEM:CONSOLE -NODEFAULTLIB:MSVCRTD +endif +endif + +# Tell the $(PROGRAM) target that we need to be recompiled when libxpt changes. +LIBS = $(DIST)/lib/$(LIB_PREFIX)xpt.$(LIB_SUFFIX) $(LIBIDL_LIBS) +EXTRA_DEPS = $(wildcard $(DIST)/lib/$(LIB_PREFIX)xpt.*) + +ifdef CROSS_COMPILE +HOST_CFLAGS += $(HOST_LIBIDL_CFLAGS) +HOST_LIBS = $(DIST)/host/lib/libhostxpt.$(LIB_SUFFIX) $(HOST_LIBIDL_LIBS) +HOST_EXTRA_DEPS = $(wildcard $(DIST)/host/lib/libhostxpt.*) + +ifdef HOST_NSPR_MDCPUCFG +HOST_CFLAGS += -DMDCPUCFG=$(HOST_NSPR_MDCPUCFG) +endif +endif + +ifdef MACOS_SDK_DIR +NEXT_ROOT= +OS_LIBS := $(patsubst -L$(MACOS_SDK_DIR)/usr/lib%,,$(OS_LIBS)) +endif + +export:: + @$(MAKE) libs diff --git a/src/libs/xpcom18a4/xpcom/typelib/xpidl/README b/src/libs/xpcom18a4/xpcom/typelib/xpidl/README new file mode 100644 index 00000000..b7a400e0 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/typelib/xpidl/README @@ -0,0 +1,16 @@ +Wed Dec 2 14:35:41 EST 1998 + +xpidl depends on Andrew Veliath and Elliot Lee's libIDL, a part of the +GNOME ORBit C ORB. We currently require libIDL >= 0.6.3, which in turn +requires glib >= 1.2.0. + +libIDL builds for Linux and Win32 can be found, along with source +tarballs, at http://www.rpi.edu/~veliaa/libIDL/, and Win32 users will +need glib 1.2 and glib 1.2-dev from +http://user.sgic.fi/~tml/gimp/win32/. Source and Linux RPMs are also +available from ftp://ftp.mozilla.org/pub/mozilla/libraries, and Win32 +binaries are included in the wintools.zip file at +ftp://ftp.mozilla.org/pub/mozilla/source/wintools.zip. A Mac project +is in progress, and should be appearing shortly. + +glib tarballs and RPMs for Linux can be found through http://www.gtk.org. diff --git a/src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/compiler.rsrc b/src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/compiler.rsrc new file mode 100644 index 00000000..fb06f6a3 Binary files /dev/null and b/src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/compiler.rsrc differ diff --git a/src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/linker.rsrc b/src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/linker.rsrc new file mode 100644 index 00000000..bec7c043 Binary files /dev/null and b/src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/linker.rsrc differ diff --git a/src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/mac_console.c b/src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/mac_console.c new file mode 100644 index 00000000..ecda11e0 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/mac_console.c @@ -0,0 +1,139 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: NPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Netscape 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/NPL/ + * + * 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * 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 NPL, 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 NPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "mac_console.h" + +#ifndef __CONSOLE__ +#include +#endif + +extern CWPluginContext gPluginContext; + +UInt32 mac_console_count = 0; +CWMemHandle mac_console_handle = NULL; + +/* + * The following four functions provide the UI for the console package. + * Users wishing to replace SIOUX with their own console package need + * only provide the four functions below in a library. + */ + +/* + * extern short InstallConsole(short fd); + * + * Installs the Console package, this function will be called right + * before any read or write to one of the standard streams. + * + * short fd: The stream which we are reading/writing to/from. + * returns short: 0 no error occurred, anything else error. + */ + +short InstallConsole(short fd) +{ +#pragma unused (fd) + mac_console_count = 0; + CWAllocMemHandle(gPluginContext, 8192, false, &mac_console_handle); + return 0; +} + +/* + * extern void RemoveConsole(void); + * + * Removes the console package. It is called after all other streams + * are closed and exit functions (installed by either atexit or _atexit) + * have been called. Since there is no way to recover from an error, + * this function doesn't need to return any. + */ + +void RemoveConsole(void) +{ + if (mac_console_handle != NULL) { + CWFreeMemHandle(gPluginContext, mac_console_handle); + mac_console_handle = NULL; + } +} + +/* + * extern long WriteCharsToConsole(char *buffer, long n); + * + * Writes a stream of output to the Console window. This function is + * called by write. + * + * char *buffer: Pointer to the buffer to be written. + * long n: The length of the buffer to be written. + * returns short: Actual number of characters written to the stream, + * -1 if an error occurred. + */ + +long WriteCharsToConsole(char *buffer, long n) +{ + long size = 0; + void* ptr = NULL; + + if (CWGetMemHandleSize(gPluginContext, mac_console_handle, &size) == noErr) { + if (mac_console_count + n >= size) { + size += 8192; + if (CWResizeMemHandle(gPluginContext, mac_console_handle, size) != noErr) + return -1; + } + } + + if (CWLockMemHandle(gPluginContext, mac_console_handle, false, &ptr) == noErr) { + BlockMoveData(buffer, (char *)ptr + mac_console_count, n); + mac_console_count += n; + CWUnlockMemHandle(gPluginContext, mac_console_handle); + } + + return 0; +} + +/* + * extern long ReadCharsFromConsole(char *buffer, long n); + * + * Reads from the Console into a buffer. This function is called by + * read. + * + * char *buffer: Pointer to the buffer which will recieve the input. + * long n: The maximum amount of characters to be read (size of + * buffer). + * returns short: Actual number of characters read from the stream, + * -1 if an error occurred. + */ + +long ReadCharsFromConsole(char *buffer, long n) +{ + return 0; +} diff --git a/src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/mac_console.h b/src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/mac_console.h new file mode 100644 index 00000000..88809f85 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/mac_console.h @@ -0,0 +1,49 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: NPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Netscape 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/NPL/ + * + * 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * 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 NPL, 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 NPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + mac_console.h + */ + +#pragma once + +#include +#include + +#include "CWPlugins.h" + +extern UInt32 mac_console_count; +extern CWMemHandle mac_console_handle; diff --git a/src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/mac_memory.cpp b/src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/mac_memory.cpp new file mode 100644 index 00000000..41d03d88 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/mac_memory.cpp @@ -0,0 +1,146 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: NPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Netscape 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/NPL/ + * + * 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * 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 NPL, 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 NPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + mac_memory.cpp + */ + +#include +#include + +#include +#include + +#include "DropInCompilerLinker.h" +#include "CompilerMapping.h" +#include "CWPluginErrors.h" + +extern CWPluginContext gPluginContext; + +/** + * Note: memory allocated by these operators will automatically be freed after the + * current call into xpidl_compiler completes. This should be fine in most cases, + * as we are also having the compiler be reloaded for every request to reinitialize + * global data. Just be careful out there! + */ + +const Boolean kTemporaryAllocation = false; + +void* operator new(size_t size) +{ + void* ptr = NULL; + if (CWAllocateMemory(gPluginContext, size, kTemporaryAllocation, &ptr) == cwNoErr) + return ptr; + return NULL; +} + +void operator delete(void* ptr) +{ + if (ptr != NULL) + CWFreeMemory(gPluginContext, ptr, kTemporaryAllocation); +} + +void* operator new[] (size_t size) +{ + void* ptr = NULL; + if (CWAllocateMemory(gPluginContext, size, kTemporaryAllocation, &ptr) == cwNoErr) + return ptr; + return NULL; +} + +void operator delete[](void* ptr) +{ + if (ptr != NULL) + CWFreeMemory(gPluginContext, ptr, kTemporaryAllocation); +} + +namespace std { + +#define TRACK_ALLOCATION +#define kTrackedCookie 'TRKD' + +void* malloc(size_t size) +{ +#if defined(TRACK_ALLOCATION) + OSType* ptr = (OSType*) new char[sizeof(OSType) + size]; + if (ptr != NULL) + *ptr++ = kTrackedCookie; + return ptr; +#else + return new char[size]; +#endif +} + +void free(void *ptr) +{ +#if defined(TRACK_ALLOCATION) + OSType* type = (OSType*)ptr; + if (*--type == kTrackedCookie) + delete[] (char*) type; + else + DebugStr("\pillegal block passed to free."); +#else + delete[] (char*) ptr; +#endif +} + +void* calloc(size_t nmemb, size_t size) +{ + size *= nmemb; + void* ptr = malloc(size); + if (ptr != NULL) { + BlockZero(ptr, size); + } + return ptr; +} + +void* realloc(void * ptr, size_t size) +{ + void* newptr = NULL; + + if (size > 0) + newptr = malloc(size); + + if (ptr != NULL && newptr != NULL) + BlockMoveData(ptr, newptr, size); + + if (ptr != NULL) + free(ptr); + + return newptr; +} + +} diff --git a/src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/mac_stdlib.cpp b/src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/mac_stdlib.cpp new file mode 100644 index 00000000..881dcb0b --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/mac_stdlib.cpp @@ -0,0 +1,58 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: NPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Netscape 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/NPL/ + * + * 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * 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 NPL, 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 NPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + mac_stdlib.cpp + + replacement functions for the CodeWarrior plugin. + + by Patrick C. Beard. + */ + +#include +#include +#include + +// simply throw us out of here! + +jmp_buf exit_jump; +int exit_status = 0; + +void std::exit(int status) +{ + exit_status = status; + longjmp(exit_jump, -1); +} diff --git a/src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/mac_strings.cpp b/src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/mac_strings.cpp new file mode 100644 index 00000000..37e389e5 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/mac_strings.cpp @@ -0,0 +1,38 @@ +/* + mac_strings.cpp + */ + +#include "mac_strings.h" + +#include +#include +#include + +StringPtr c2p_strcpy(StringPtr pstr, const char* cstr) +{ + size_t len = ::strlen(cstr); + if (len > 255) len = 255; + BlockMoveData(cstr, pstr + 1, len); + pstr[0] = len; + return pstr; +} + +char* p2c_strcpy(char* cstr, const StringPtr pstr) +{ + size_t len = pstr[0]; + BlockMoveData(pstr + 1, cstr, len); + cstr[len] = '\0'; + return cstr; +} + +char* p2c_strdup(StringPtr pstr) +{ + size_t len = pstr[0]; + char* cstr = new char[1 + len]; + if (cstr != NULL) { + BlockMoveData(pstr + 1, cstr, len); + cstr[len] = '\0'; + } + return cstr; +} + diff --git a/src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/mac_strings.h b/src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/mac_strings.h new file mode 100644 index 00000000..44f39312 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/mac_strings.h @@ -0,0 +1,47 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: NPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Netscape 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/NPL/ + * + * 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * 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 NPL, 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 NPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + mac_strings.h + */ + +#pragma once + +#include + +StringPtr c2p_strcpy(StringPtr pstr, const char* cstr); +char* p2c_strcpy(char* cstr, const StringPtr pstr); +char* p2c_strdup(StringPtr pstr); diff --git a/src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/mac_xpidl.cpp b/src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/mac_xpidl.cpp new file mode 100644 index 00000000..49f061d9 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/mac_xpidl.cpp @@ -0,0 +1,417 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: NPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Netscape 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/NPL/ + * + * 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * 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 NPL, 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 NPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + mac_xpidl.cpp + + Metrowerks Codewarrior IDL plugin. + + by Patrick C. Beard. + */ + +/* standard headers */ +#include +#include +#include +#include +#include +#include + +/* system headers */ +#include +#include +#include + +#include "FullPath.h" +#include "MoreFilesExtras.h" + +/* compiler headers */ +#include "DropInCompilerLinker.h" +#include "CompilerMapping.h" +#include "CWPluginErrors.h" + +/* local headers. */ +#include "mac_xpidl.h" +#include "mac_console.h" +#include "mac_strings.h" +#include "mac_xpidl_panel.h" + +/* prototypes of local functions */ +static CWResult Compile(CWPluginContext context); +static CWResult Disassemble(CWPluginContext context); +static CWResult LocateFile(CWPluginContext context, const char* filename, FSSpec& file); + +/* external variables */ +extern jmp_buf exit_jump; +extern int exit_status; + +/* global variables */ +CWPluginContext gPluginContext; + +/* local variables */ +static CWFileSpec gSourceFile; +static char* gSourcePath = NULL; +static CWFileSpec gOutputFile; + +extern "C" { +pascal short xpidl_compiler(CWPluginContext context); +int xpidl_main(int argc, char* argv[]); +int xptdump_main(int argc, char* argv[]); + +FILE * FSp_fopen(ConstFSSpecPtr spec, const char * open_mode); +} + +pascal short xpidl_compiler(CWPluginContext context) +{ + long request; + if (CWGetPluginRequest(context, &request) != cwNoErr) + return cwErrRequestFailed; + + gPluginContext = context; + short result = cwNoErr; + + /* dispatch on compiler request */ + switch (request) { + case reqInitCompiler: + /* compiler has just been loaded into memory */ + break; + + case reqTermCompiler: + /* compiler is about to be unloaded from memory */ + break; + + case reqCompile: + /* compile a source file */ + result = Compile(context); + break; + + case reqCompDisassemble: + /* disassemble a source file */ + result = Disassemble(context); + break; + + default: + result = cwErrRequestFailed; + break; + } + + /* is this necessary? */ + CWDonePluginRequest(context, result); + + /* return result code */ + return (result); +} + +static char* full_path_to(const FSSpec& file) +{ + short len = 0; + Handle fullPath = NULL; + if (FSpGetFullPath(&file, &len, &fullPath) == noErr && fullPath != NULL) { + char* path = new char[1 + len]; + if (path != NULL) { + BlockMoveData(*fullPath, path, len); + path[len] = '\0'; + } + DisposeHandle(fullPath); + return path; + } + return NULL; +} + +static CWResult GetSettings(CWPluginContext context, XPIDLSettings& settings) +{ + CWMemHandle settingsHand; + CWResult err = CWGetNamedPreferences(context, kXPIDLPanelName, &settingsHand); + if (!CWSUCCESS(err)) + return (err); + + XPIDLSettings* settingsPtr = NULL; + err = CWLockMemHandle(context, settingsHand, false, (void**)&settingsPtr); + if (!CWSUCCESS(err)) + return (err); + + settings = *settingsPtr; + + err = CWUnlockMemHandle(context, settingsHand); + if (!CWSUCCESS(err)) + return (err); + + return noErr; +} + +static CWResult Compile(CWPluginContext context) +{ + CWResult err = CWGetMainFileSpec(context, &gSourceFile); + if (!CWSUCCESS(err)) + return (err); + + long fileNum; + err = CWGetMainFileNumber(context, &fileNum); + if (!CWSUCCESS(err)) + return (err); + + // get the name of the source file to compile. + gSourcePath = p2c_strdup(gSourceFile.name); + if (gSourcePath == NULL) + return cwErrOutOfMemory; + + // build an argument list and call the compiler. + XPIDLSettings settings = { kXPIDLSettingsVersion, kXPIDLModeHeader, false, false }; + GetSettings(context, settings); + +#if 0 + // if generating .xpt files, let the IDE tell us where to put the output file. + // otherwise, put them in the project's output directory. + if (settings.mode == kXPIDLModeTypelib) + err = CWGetSuggestedObjectFileSpec(context, fileNum, &gOutputFile); + else + err = CWGetOutputFileDirectory(gPluginContext, &gOutputFile); +#else + // always generate the output file into the project target's data directory. + err = CWGetSuggestedObjectFileSpec(context, fileNum, &gOutputFile); +#endif + if (!CWSUCCESS(err)) + return (err); + + int argc = 3; + char* modes[] = { "header", "java", "typelib", "doc" }; + char* argv[] = { "xpidl", "-m", modes[settings.mode - 1], NULL, NULL, NULL, NULL, }; + if (settings.warnings) argv[argc++] = "-w"; + if (settings.verbose) argv[argc++] = "-v"; + argv[argc++] = gSourcePath; + + if (setjmp(exit_jump) == 0) { + if (xpidl_main(argc, argv) != 0) + err = cwErrRequestFailed; + } else { + // evidently the good old exit function got called. + if (exit_status != 0) + err = cwErrRequestFailed; + } + + // if the compilation succeeded, tell CodeWarrior about the output file. + // this ensures several things: 1. if the output file is deleted by the user, + // then the IDE will know to recompile it, which is good for dirty builds, + // where the output files may be hand deleted; 2. if the user elects to remove + // objects, the output files are deleted. Thanks to robv@metrowerks.com for + // pointing this new CWPro4 API out. + if (err == cwNoErr) { + CWObjectData objectData; + BlockZero(&objectData, sizeof(objectData)); + + // for fun, show how large the output file is in the data area. + long dataSize, rsrcSize; + if (FSpGetFileSize(&gOutputFile, &dataSize, &rsrcSize) == noErr) + objectData.idatasize = dataSize; + + // tell the IDE that this file was generated by the compiler. + objectData.objectfile = &gOutputFile; + + err = CWStoreObjectData(context, fileNum, &objectData); + } else { + // an error occured, delete the output file, which might be a partial file. + if (gOutputFile.name[0] != 0) { + ::FSpDelete(&gOutputFile); + } + } + + delete[] gSourcePath; + gSourcePath = NULL; + + return (err); +} + +static CWResult Disassemble(CWPluginContext context) +{ + // the disassembly code has moved to the linker. + return noErr; +} + +static CWResult LocateFile(CWPluginContext context, const char* filename, FSSpec& file) +{ + /* prefill the CWFileInfo struct */ + CWFileInfo fileinfo; + BlockZero(&fileinfo, sizeof(fileinfo)); + // memset(&fileinfo, 0, sizeof(fileinfo)); + fileinfo.fullsearch = true; + fileinfo.suppressload = true; + fileinfo.dependencyType = cwNormalDependency; + fileinfo.isdependentoffile = kCurrentCompiledFile; + + /* locate the file name using the project's access paths */ + CWResult err = CWFindAndLoadFile(context, filename, &fileinfo); + if (err == cwNoErr) { + file = fileinfo.filespec; + } else if (err == cwErrFileNotFound) { + char errmsg[200]; + sprintf(errmsg, "Can't locate file \"%s\".", filename); + CWResult callbackResult = CWReportMessage(context, 0, errmsg, 0, messagetypeError, 0); + } + + return (err); +} + +/** + * Substitute for standard fopen, treats certain filenames specially, + * and also considers the mode argument. If a file is being opened + * for reading, the file is assumed to be locateable using CodeWarrior's + * standard access paths. If it's for writing, the file is opened in + * the current project's output directory. + */ +FILE* std::fopen(const char* filename, const char *mode) +{ + FSSpec filespec; + CWResult err = noErr; + do { + if (filename == gSourcePath || strcmp(filename, gSourcePath) == 0) { + // opening the main source file. + filespec = gSourceFile; + } else if (mode[0] == 'w') { + // if an output file, open it in the current compilation's output directory. + c2p_strcpy(filespec.name, filename); + filespec.vRefNum = gOutputFile.vRefNum; + filespec.parID = gOutputFile.parID; + c2p_strcpy(gOutputFile.name, filename); + } else { + // an input file, use CodeWarrior's search paths to find the named source file. + err = LocateFile(gPluginContext, filename, filespec); + } + } while (0); + // if all went well, we have a file to open. + return (err == noErr ? FSp_fopen(&filespec, mode) : NULL); +} + +/** + * Returns the length of a file, assuming it is always located in the + * project's output directory. + */ +size_t mac_get_file_length(const char* filename) +{ + long dataSize= 0, rsrcSize = 0; + FSSpec filespec; + if (CWGetOutputFileDirectory(gPluginContext, &filespec) != noErr) + return 0; + c2p_strcpy(filespec.name, filename); + if (FSpGetFileSize(&filespec, &dataSize, &rsrcSize) != noErr) + return 0; + return dataSize; +} + +void mac_warning(const char* warning_message) +{ + CWReportMessage(gPluginContext, 0, warning_message, 0, messagetypeWarning, 0); +} + +void mac_error(const char* error_message) +{ + CWReportMessage(gPluginContext, 0, error_message, 0, messagetypeError, 0); +} + +// plugin compiler exports. + +#if CW_USE_PRAGMA_EXPORT +#pragma export on +#endif + +CWPLUGIN_ENTRY(CWPlugin_GetDropInFlags)(const DropInFlags** flags, long* flagsSize) +{ + static const DropInFlags sFlags = { + kCurrentDropInFlagsVersion, + CWDROPINCOMPILERTYPE, + DROPINCOMPILERLINKERAPIVERSION, + (kGeneratescode | /* kCandisassemble | */ kCompMultiTargAware | kCompAlwaysReload), + Lang_MISC, + DROPINCOMPILERLINKERAPIVERSION + }; + + *flags = &sFlags; + *flagsSize = sizeof(sFlags); + + return cwNoErr; +} + +CWPLUGIN_ENTRY(CWPlugin_GetDropInName)(const char** dropinName) +{ + static const char* sDropInName = "xpidl"; + + *dropinName = sDropInName; + + return cwNoErr; +} + +CWPLUGIN_ENTRY(CWPlugin_GetDisplayName)(const char** displayName) +{ + static const char* sDisplayName = "xpidl"; + + *displayName = sDisplayName; + + return cwNoErr; +} + +CWPLUGIN_ENTRY(CWPlugin_GetPanelList)(const CWPanelList** panelList) +{ + static const char* sPanelName = kXPIDLPanelName; + static CWPanelList sPanelList = { kCurrentCWPanelListVersion, 1, &sPanelName }; + + *panelList = &sPanelList; + + return cwNoErr; +} + +CWPLUGIN_ENTRY(CWPlugin_GetTargetList)(const CWTargetList** targetList) +{ + static CWDataType sCPU = '****'; + static CWDataType sOS = '****'; + static CWTargetList sTargetList = { kCurrentCWTargetListVersion, 1, &sCPU, 1, &sOS }; + + *targetList = &sTargetList; + + return cwNoErr; +} + +CWPLUGIN_ENTRY(CWPlugin_GetDefaultMappingList)(const CWExtMapList** defaultMappingList) +{ + static CWExtensionMapping sExtension = { 'TEXT', ".idl", 0 }; + static CWExtMapList sExtensionMapList = { kCurrentCWExtMapListVersion, 1, &sExtension }; + + *defaultMappingList = &sExtensionMapList; + + return cwNoErr; +} + +#if CW_USE_PRAGMA_EXPORT +#pragma export off +#endif diff --git a/src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/mac_xpidl.h b/src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/mac_xpidl.h new file mode 100644 index 00000000..bb1c5048 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/mac_xpidl.h @@ -0,0 +1,25 @@ +/* + mac_xpidl.h + + prototypes for the Mac CodeWarrior plugin version of xpidl. + + by Patrick C. Beard. + */ + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _STDIO_H +#include +#endif + +size_t mac_get_file_length(const char* filename); +void mac_warning(const char* warning_message); +void mac_error(const char* error_message); + +#ifdef __cplusplus +} +#endif diff --git a/src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/mac_xpidl_panel.cpp b/src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/mac_xpidl_panel.cpp new file mode 100644 index 00000000..b046071d --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/mac_xpidl_panel.cpp @@ -0,0 +1,695 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: NPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Netscape 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/NPL/ + * + * 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * 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 NPL, 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 NPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + mac_xpidl_panel.cpp + */ + +#define CW_STRICT_DIALOGS 1 + +/* standard headers */ +#include +#include +#include + +/* system headers */ +#include +#include +#include +#include +#include +#include +#include + +/* compiler headers */ +#include + +/* project headers */ +#include "mac_xpidl_panel.h" + +enum { + kFactoryPrefsID = 128, + kCW7ItemListID = 128, + kCW8ItemListID = 129, + + kXPIDLModeItem = 1, + kXPIDLWarningsItem, + kXPIDLVerboseItem, + + kXPTLinkerOutputItem = 4 +}; + + +/* local variables */ +static RgnHandle sDragRgn; +static Boolean sHighlightOn; + + +/* prototypes of local functions */ +static short InitDialog(PanelParameterBlock *pb); +static void TermDialog(PanelParameterBlock *pb); +static void PutData(PanelParameterBlock *pb, Handle options); +static short GetData(PanelParameterBlock *pb, Handle options, Boolean noisy); +static void ByteSwapData(XPIDLSettingsHandle options); +static short Filter(PanelParameterBlock *pb, EventRecord *event, short *itemHit); +static void ItemHit(PanelParameterBlock *pb); +static void Validate(Handle original, Handle current, Boolean *recompile, Boolean *relink, Boolean *reset); +static short GetPref(AEKeyword keyword, AEDesc *prefsDesc, Handle settings); +static short SetPref(AEKeyword keyword, const AEDesc *prefsDesc, Handle settings); +static short GetFactory(Handle settings); +static short UpdatePref(Handle settings); +static Boolean ComparePrefs(Handle prefsHand1, Handle prefsHand2); +static Boolean ComparePrefs(XPIDLSettings& prefs1, XPIDLSettings& prefs2); +static void OutlineRect(const Rect* focusRect, Boolean outlineOn); +static OSErr DragEnter(PanelParameterBlock *pb); +static void DragWithin(PanelParameterBlock *pb); +static void DragExit(PanelParameterBlock *pb); +static void DragDrop(PanelParameterBlock *pb); + +extern "C" { + +pascal short xpidl_panel(PanelParameterBlock *pb); + +} + +/* + * main - entry-point for Drop-In Preferences Panel + * + */ + +pascal short xpidl_panel(PanelParameterBlock *pb) +{ + short result; + + result = noErr; + + switch (pb->request) + { + case reqInitPanel: + /* panel has just been loaded into memory */ + break; + + case reqTermPanel: + /* panel is about to be unloaded from memory */ + break; + + case reqFirstLoad: + /* first time panel was loaded. */ + break; + + case reqInitDialog: + /* hook our dialog item list into the preferences dialog */ + result = InitDialog(pb); + break; + + case reqTermDialog: + /* unhook our dialog item list from the preferences dialog */ + TermDialog(pb); + break; + + case reqPutData: + /* put the data in the given handle into our dialog items */ + PutData(pb, pb->currentPrefs); + break; + + case reqGetData: + /* fill in the given handle with our dialog items */ + result = GetData(pb, pb->currentPrefs, true); + break; + + case reqByteSwapData: + /* byte swap the data in the handle */ + ByteSwapData((XPIDLSettingsHandle)pb->currentPrefs); + break; + + case reqFilter: + /* filter an event in the dialog */ + result = Filter(pb, pb->event, &pb->itemHit); + break; + + case reqItemHit: + /* handle a hit on one of our dialog items */ + ItemHit(pb); + break; + + case reqDrawCustomItem: + /* handle a request to draw one of our user items (CW/8 and later) */ + break; + + case reqActivateItem: + break; + + case reqDeactivateItem: + break; + + case reqHandleKey: + break; + + case reqHandleClick: + break; + + case reqFindStatus: + break; + + case reqObeyCommand: + break; + + case reqAEGetPref: + /* return one item in the given handle as an Apple Event descriptor */ + result = GetPref(pb->prefsKeyword, &pb->prefsDesc, pb->currentPrefs); + break; + + case reqAESetPref: + /* change one item in the given handle according to the given Apple Event descriptor */ + result = SetPref(pb->prefsKeyword, &pb->prefsDesc, pb->currentPrefs); + break; + + case reqValidate: + /* determine if we need to reset paths, recompile, or relink */ + Validate(pb->originalPrefs, pb->currentPrefs, &pb->recompile, &pb->relink, &pb->reset); + break; + + case reqGetFactory: + /* return our factory settings */ + result = GetFactory(pb->factoryPrefs); + break; + + case reqUpdatePref: + /* update the given handle to use the current format for our prefs data */ + result = UpdatePref(pb->currentPrefs); + break; + + case reqDragEnter: + /* determine if we can accept the drag and, if so, start tracking */ + result = DragEnter(pb); + break; + + case reqDragWithin: + /* continue tracking */ + DragWithin(pb); + break; + + case reqDragExit: + /* stop tracking */ + DragExit(pb); + break; + + case reqDragDrop: + /* the user has dropped in our panel */ + DragDrop(pb); + break; + + default: + result = paramErr; + break; + } + + return (result); +} + +/* + * InitDialog - initialize Dialog Box items for this panel + * + */ + +static short InitDialog(PanelParameterBlock *pb) +{ + OSErr err; + + // The library function will call the IDE to append the dialog items + // if possible; else it will call AppendDITL itself. This way, you + // don't have to worry about it. + + err = CWPanlAppendItems(pb, kCW8ItemListID); + if (err != noErr) + return (err); + + sDragRgn = NewRgn(); + + return (err); +} + +/* + * TermDialog - destroy Dialog Box items for this panel + * + */ + +static void TermDialog(PanelParameterBlock *pb) +{ + DisposeRgn(sDragRgn); +} + +inline Boolean hasLinkerOutput(short mode) +{ + return (mode == kXPIDLModeHeader || mode == kXPIDLModeTypelib); +} + +/* + * PutData - copy the options data from the handle to the screen + * + */ + +static void PutData(PanelParameterBlock *pb, Handle options) +{ + // make sure the options are the right size. + UpdatePref(options); + + XPIDLSettings prefsData = **(XPIDLSettingsHandle) options; + + CWPanlSetItemValue(pb, kXPIDLModeItem, prefsData.mode); + CWPanlSetItemValue(pb, kXPIDLWarningsItem, prefsData.warnings); + CWPanlSetItemValue(pb, kXPIDLVerboseItem, prefsData.verbose); + + CWPanlEnableItem(pb, kXPTLinkerOutputItem, hasLinkerOutput(prefsData.mode)); + CWPanlSetItemText(pb, kXPTLinkerOutputItem, prefsData.output); +} + +/* + * GetData - copy the options data from screen to the handle + * + */ + +static short GetData(PanelParameterBlock *pb, Handle options, Boolean noisy) +{ + XPIDLSettings prefsData = **(XPIDLSettingsHandle) options; + long mode, warnings, verbose; + + CWPanlGetItemValue(pb, kXPIDLModeItem, &mode); + CWPanlGetItemValue(pb, kXPIDLWarningsItem, &warnings); + CWPanlGetItemValue(pb, kXPIDLVerboseItem, &verbose); + + prefsData.mode = (short) mode; + prefsData.warnings = (Boolean) warnings; + prefsData.verbose = (Boolean) verbose; + + CWPanlGetItemText(pb, kXPTLinkerOutputItem, prefsData.output, sizeof(Str32)); + + ** (XPIDLSettingsHandle) options = prefsData; + + return (noErr); +} + +static void ByteSwapShort(short* x) +{ + union { + short s; + char c[2]; + } from,to; + + from.s=*x; + to.c[0]=from.c[1]; + to.c[1]=from.c[0]; + *x = to.s; +} + +/* + * ByteSwapData - byte-swap the options data + * + */ + +static void ByteSwapData(XPIDLSettingsHandle options) +{ + ByteSwapShort(&(**options).version); + ByteSwapShort(&(**options).mode); +} + +/* + * Filter - filter an event for the Preferences panel + * + */ +static short Filter(PanelParameterBlock *pb, EventRecord *event, short *itemHit) +{ +#pragma unused(pb, event, itemHit) + + return (noErr); +} + +/* + * ItemHit - handle an itemHit in a Preferences panel + * + */ + +static void ItemHit(PanelParameterBlock *pb) +{ + short theItem = pb->itemHit - pb->baseItems; + long oldValue; + + switch (theItem) { + case kXPIDLModeItem: + CWPanlGetItemValue(pb, theItem, &oldValue); + CWPanlEnableItem(pb, kXPTLinkerOutputItem, hasLinkerOutput(oldValue)); + break; + + case kXPIDLWarningsItem: + case kXPIDLVerboseItem: + CWPanlGetItemValue(pb, theItem, &oldValue); + break; + } + + GetData(pb, pb->currentPrefs, false); + + pb->canRevert = !ComparePrefs(pb->originalPrefs, pb->currentPrefs); + pb->canFactory = !ComparePrefs(pb->factoryPrefs, pb->currentPrefs); +} + +/* + * Validate - check if panel's changes require a recompile or relink + * + */ + +static void Validate(Handle original, Handle current, Boolean *recompile, Boolean *relink, Boolean *reset) +{ +#pragma unused(original, current) + XPIDLSettings& origSettings = **(XPIDLSettingsHandle) original; + XPIDLSettings& currentSettings = **(XPIDLSettingsHandle) current; + + *recompile = currentSettings.mode != origSettings.mode; + *relink = *recompile && hasLinkerOutput(currentSettings.mode); + *reset = false; +} + +/* + * GetPref - get a specified Preference setting for an AppleEvent request + * + */ +static short GetPref(AEKeyword keyword, AEDesc *prefsDesc, Handle settings) +{ +#if 0 + XPIDLSettings prefsData = ** (XPIDLSettingsHandle) settings; + DescType anEnum; + OSErr err; + + switch (keyword) { + case prefsLN_GenerateSymFile: + err = AECreateDesc(typeBoolean, &prefsData.linksym, sizeof(Boolean), prefsDesc); + break; + + case prefsPR_ProjectType: + switch (prefsData.projtype) + { + case kProjTypeApplication: anEnum = enum_Project_Application; break; + case kProjTypeLibrary: anEnum = enum_Project_Library; break; + case kProjTypeSharedLib: anEnum = enum_Project_SharedLibrary; break; + case kProjTypeCodeResource: anEnum = enum_Project_CodeResource; break; + case kProjTypeMPWTool: anEnum = enum_Project_MPWTool; break; + default: return (paramErr); + } + err = AECreateDesc(typeEnumeration, &anEnum, sizeof(anEnum), prefsDesc); + break; + + case prefsPR_FileName: + err = AECreateDesc(typeChar, prefsData.outfile+1, StrLength(prefsData.outfile), prefsDesc); + break; + + default: + err = errAECantHandleClass; + break; + } + + return (err); +#else + return (errAECantHandleClass); +#endif +} + +/* + * SetPref - set a specified Preference setting from an AppleEvent request + * + */ + +static short SetPref(AEKeyword keyword, const AEDesc *prefsDesc, Handle settings) +{ +#if 0 + XPIDLSettings prefsData = ** (XPIDLSettingsHandle) settings; + AEDesc toDesc = { typeNull, NULL }; + OSErr err = noErr; + Handle dataHand; + Size textLength; + DescType anEnum; + + switch (keyword) + { + case prefsLN_GenerateSymFile: + if (prefsDesc->descriptorType == typeBoolean) + { + dataHand = prefsDesc->dataHandle; + } + else + { + err = AECoerceDesc(prefsDesc, typeBoolean, &toDesc); + if (err == noErr) + dataHand = toDesc.dataHandle; + } + if (err == noErr) + { + prefsData.linksym = ** (Boolean **) dataHand; + } + break; + + case prefsPR_ProjectType: + if (prefsDesc->descriptorType != typeEnumeration) + { + err = errAETypeError; + break; + } + + anEnum = ** (DescType **) prefsDesc->dataHandle; + + switch (anEnum) + { + case enum_Project_Application: prefsData.projtype = kProjTypeApplication; break; + case enum_Project_Library: prefsData.projtype = kProjTypeLibrary; break; + case enum_Project_SharedLibrary: prefsData.projtype = kProjTypeSharedLib; break; + case enum_Project_CodeResource: prefsData.projtype = kProjTypeCodeResource; break; + case enum_Project_MPWTool: prefsData.projtype = kProjTypeMPWTool; break; + default: return (errAECoercionFail); + } + break; + + case prefsPR_FileName: + if (prefsDesc->descriptorType == typeChar) + { + dataHand = prefsDesc->dataHandle; + } + else + { + err = AECoerceDesc(prefsDesc, typeChar, &toDesc); + if (err == noErr) + dataHand = toDesc.dataHandle; + } + if (err == noErr) + { + textLength = GetHandleSize(dataHand); + if (textLength > sizeof(prefsData.outfile) - 1) + textLength = sizeof(prefsData.outfile) - 1; + BlockMoveData(*dataHand, prefsData.outfile+1, textLength); + prefsData.outfile[0] = textLength; + } + break; + + default: + err = errAECantHandleClass; + break; + } + + if (err == noErr) + { + ** (XPIDLSettingsHandle) settings = prefsData; + } + + AEDisposeDesc(&toDesc); + + return (err); +#else + return (errAECantHandleClass); +#endif +} + +/* + * GetFactory - retrieve factory settings + * + */ + +static short GetFactory(Handle settings) +{ + Handle factory; + Size size; + OSErr err; + + factory = Get1Resource('pref', kFactoryPrefsID); + if (factory == NULL) { + err = ResError(); + if (err == noErr) + err = resNotFound; + return (err); + } + + size = GetHandleSize(factory); + SetHandleSize(settings, size); + err = MemError(); + + if (err == noErr) { + BlockMoveData(*factory, *settings, size); + } + + return (err); +} + +/* + * UpdatePref - "upgrade" a pref to the current version + */ +static short UpdatePref(Handle settings) +{ + if (GetHandleSize(settings) != sizeof(XPIDLSettings)) + GetFactory(settings); + + return (noErr); +} + +/* + * ComparePrefs + * + */ +static Boolean ComparePrefs(Handle prefsHand1, Handle prefsHand2) +{ + XPIDLSettings& prefs1 = **(XPIDLSettingsHandle) prefsHand1; + XPIDLSettings& prefs2 = **(XPIDLSettingsHandle) prefsHand2; + + return ((prefs1.mode == prefs2.mode) && + (prefs1.warnings == prefs2.warnings) && + (prefs1.verbose == prefs2.verbose) && + (EqualString(prefs1.output, prefs2.output, true, true))); +} + +static Boolean ComparePrefs(XPIDLSettings& prefs1, XPIDLSettings& prefs2) +{ + return ((prefs1.mode == prefs2.mode) && + (prefs1.warnings == prefs2.warnings) && + (prefs1.verbose == prefs2.verbose) && + (EqualString(prefs1.output, prefs2.output, true, true))); +} + +/* + * OutlineRect + * + */ +static void OutlineRect(const Rect* focusRect, Boolean outlineOn) +{ + ColorSpec savedForeColor, backColor; + PenState savedPen; + + GetPenState(&savedPen); + PenNormal(); + + if (!outlineOn) + { + SaveFore(&savedForeColor); + SaveBack(&backColor); + RestoreFore(&backColor); + } + + PenSize(2, 2); + FrameRect(focusRect); + + SetPenState(&savedPen); + + if (!outlineOn) + { + RestoreFore(&savedForeColor); + } +} + +/* + * DragEnter + * + */ +static OSErr DragEnter(PanelParameterBlock *pb) +{ +#if 0 + short theItem = pb->itemHit - pb->baseItems; + unsigned short itemCount; + Rect itemRect; + OSErr err; +#endif + + /* Return paramErr if the user is on a item that can't be dropped on */ + return (paramErr); +} + +/* + * DragWithin + * + */ +static void DragWithin(PanelParameterBlock *pb) +{ +#pragma unused(pb) + + /* there's nothing to do */ + +/// SysBreakStr("\preqDragWithin"); +} + +/* + * DragExit + * + */ +static void DragExit(PanelParameterBlock *pb) +{ + OSErr err; + +/// SysBreakStr("\preqDragExit"); + + if (sHighlightOn) { + err = HideDragHilite(pb->dragref); + if (err == noErr) + sHighlightOn = false; + } +} + +/* + * DragDrop + * + */ +static void DragDrop(PanelParameterBlock *pb) +{ +#if 0 + Rect itemRect; +#endif + +/// SysBreakStr("\preqDragDrop"); + + DragExit(pb); +} diff --git a/src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/mac_xpidl_panel.h b/src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/mac_xpidl_panel.h new file mode 100644 index 00000000..582b1055 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/mac_xpidl_panel.h @@ -0,0 +1,106 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: NPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Netscape 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/NPL/ + * + * 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * 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 NPL, 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 NPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + mac_xpidl_panel.h + */ + +#pragma once + +#ifndef __MAC_XPIDL_PANEL__ +#define __MAC_XPIDL_PANEL__ + +#ifndef __TYPES__ +#include +#endif + +#pragma options align=mac68k + +/* this is the name of the panel, as shown in the Finder */ +#define kXPIDLPanelName "xpidl Settings" + +/* + * AppleScript dictionary info. As a rule of thumb, dropin panels should use the + * same terminology and numeric code in their 'aete' that the IDE uses if there + * is already a similar item in the IDE's 'aete'. That is the case here, so we + * merely duplicate applicable 68K Project and 68K Linker user terms below. + */ + +enum { +/* Symbolic Name Code AETE Terminology */ + class_XPIDL = 'XIDL', + + prefsPR_ProjectType = 'PR01', /* Project Type */ + prefsPR_FileName = 'PR02', /* File Name */ + prefsLN_GenerateSymFile = 'LN02', /* Generate SYM File */ + + /* enumeration for project type */ + enumeration_ProjectType = 'PRPT', + enum_Project_Application = 'PRPA', /* application */ + enum_Project_Library = 'PRPL', /* library */ + enum_Project_SharedLibrary = 'PRPS', /* shared library */ + enum_Project_CodeResource = 'PRPC', /* code resource */ + enum_Project_MPWTool = 'PRPM' /* MPW tool */ +}; + +enum { + kXPIDLModeHeader = 1, + kXPIDLModeJava, + kXPIDLModeTypelib, + kXPIDLModeDoc +}; + +/* This is the structure that is manipulated by the panel. The sample + * compiler & linker both "know" about this structure. + */ + +enum { + kXPIDLSettingsVersion = 0x0100 +}; + +struct XPIDLSettings { + short version; /* version # of settings data */ + short mode; /* one of kXPIDLModeHeader, ... */ + Boolean warnings; /* generate warnings. */ + Boolean verbose; /* verbose mode */ + Str32Field output; /* name of the output file */ +}; + +typedef struct XPIDLSettings XPIDLSettings, **XPIDLSettingsHandle; + +#pragma options align=reset + +#endif /* __MAC_XPIDL_PANEL__ */ diff --git a/src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/mac_xpt_linker.cpp b/src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/mac_xpt_linker.cpp new file mode 100644 index 00000000..fe137959 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/mac_xpt_linker.cpp @@ -0,0 +1,546 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: NPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Netscape 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/NPL/ + * + * 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * 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 NPL, 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 NPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + mac_xpt_linker.cpp + + CodeWarrior plugin linker, links together multiple .xpt files. + + by Patrick C. Beard. + */ + +/* standard headers */ +#include +#include +#include + +/* system headers */ +#include +#include +#include +#include + +/* compiler headers */ +#include "DropInCompilerLinker.h" +#include "CompilerMapping.h" +#include "CWPluginErrors.h" + +/* project headers */ +#include "mac_xpidl_panel.h" +#include "mac_console.h" +#include "mac_strings.h" +#include "FullPath.h" +#include "MoreFilesExtras.h" + +/* use standard CodeWarrior debugger */ +#define kDebuggerCreator 'MWDB' + +/* prototypes of local functions */ +static CWResult Link(CWPluginContext context); +static CWResult Disassemble(CWPluginContext context); +static CWResult GetTargetInfo(CWPluginContext context); + +extern "C" { +pascal short xpt_linker(CWPluginContext context); +int xptlink_main(int argc, char* argv[]); +int xptdump_main(int argc, char* argv[]); + +FILE * FSp_fopen(ConstFSSpecPtr spec, const char * open_mode); +size_t mac_get_file_length(const char* filename); +} + +/* external variables */ +extern jmp_buf exit_jump; +extern int exit_status; + +/* global variables */ +CWPluginContext gPluginContext; + +/* local variables */ +static CWFileSpec gOutputDirectory; +static CWFileSpec gObjectCodeDirectory; + +/* + * xpt_linker - main entry-point for linker plugin + * + */ +pascal short xpt_linker(CWPluginContext context) +{ + long request; + if (CWGetPluginRequest(context, &request) != cwNoErr) + return cwErrRequestFailed; + + gPluginContext = context; + short result = cwNoErr; + + /* dispatch on linker request */ + switch (request) { + case reqInitLinker: + /* linker has just been loaded into memory */ + break; + + case reqTermLinker: + /* linker is about to be unloaded from memory */ + break; + + case reqLink: + /* build the final executable */ + result = Link(context); + break; + + case reqDisassemble: + /* disassemble object code for a given project file */ + result = Disassemble(context); + break; + + case reqTargetInfo: + /* return info describing target characteristics */ + result = GetTargetInfo(context); + break; + + default: + result = cwErrRequestFailed; + break; + } + + result = CWDonePluginRequest(context, result); + + /* return result code */ + return result; +} + +static char* full_path_to(const FSSpec& file) +{ + short len = 0; + Handle fullPath = NULL; + if (FSpGetFullPath(&file, &len, &fullPath) == noErr && fullPath != NULL) { + char* path = new char[1 + len]; + if (path != NULL) { + BlockMoveData(*fullPath, path, len); + path[len] = '\0'; + } + DisposeHandle(fullPath); + return path; + } + return NULL; +} + +/** + * Provides the full path name to a given directory. + */ +static char* full_path_to(short vRefNum, long dirID) +{ + long parID; + if (GetParentID(vRefNum, dirID, NULL, &parID) == noErr) { + FSSpec dirSpec = { vRefNum, parID }; + if (GetDirName(vRefNum, dirID, dirSpec.name) == noErr) { + return full_path_to(dirSpec); + } + } + return NULL; +} + +/** + * Returns the length of a file, assuming it is always located in the + * project's object code directory. + */ +size_t mac_get_file_length(const char* filename) +{ + FSSpec fileSpec = { gObjectCodeDirectory.vRefNum, gObjectCodeDirectory.parID }; + c2p_strcpy(fileSpec.name, filename); + long dataSize, rsrcSize; + if (FSpGetFileSize(&fileSpec, &dataSize, &rsrcSize) != noErr) + dataSize = 0; + return dataSize; +} + +/** + * replaces standard fopen -- opens files for writing in the project's output directory, + * and files for reading in the object code directory. + */ +FILE* std::fopen(const char* filename, const char *mode) +{ + CWFileSpec& fileDir = (mode[0] == 'r' ? gObjectCodeDirectory : gOutputDirectory); + FSSpec fileSpec = { fileDir.vRefNum, fileDir.parID }; + c2p_strcpy(fileSpec.name, filename); + return FSp_fopen(&fileSpec, mode); +} + +static CWResult GetSettings(CWPluginContext context, XPIDLSettings& settings) +{ + CWMemHandle settingsHand; + CWResult err = CWGetNamedPreferences(context, kXPIDLPanelName, &settingsHand); + if (!CWSUCCESS(err)) + return err; + + XPIDLSettings* settingsPtr = NULL; + err = CWLockMemHandle(context, settingsHand, false, (void**)&settingsPtr); + if (!CWSUCCESS(err)) + return err; + + settings = *settingsPtr; + + err = CWUnlockMemHandle(context, settingsHand); + if (!CWSUCCESS(err)) + return err; + + return cwNoErr; +} + +static CWResult LinkHeaders(CWPluginContext context, XPIDLSettings& settings) +{ + // find out how many files there are to link. + long fileCount = 0; + CWResult err = CWGetProjectFileCount(context, &fileCount); + if (err != cwNoErr || fileCount == 0) + return err; + + // get the output directory. + FSSpec outputDir; + err = CWGetOutputFileDirectory(context, &outputDir); + if (!CWSUCCESS(err)) + return err; + + // enumerate all of the output header files, and make aliases to them in + // the output directory. + for (long index = 0; (err == cwNoErr) && (index < fileCount); index++) { + // get the name of each output file. + CWFileSpec outputFile; + err = CWGetStoredObjectFileSpec(context, index, &outputFile); + if (err == cwNoErr) { + FInfo info; + err = FSpGetFInfo(&outputFile, &info); + + FSSpec aliasFile = { outputDir.vRefNum, outputDir.parID }; + BlockMoveData(outputFile.name, aliasFile.name, 1 + outputFile.name[0]); + + AliasHandle alias = NULL; + if (NewAliasMinimal(&outputFile, &alias) == noErr) { + // recreate the alias file from scratch. + FSpDelete(&aliasFile); + FSpCreateResFile(&aliasFile, info.fdCreator, info.fdType, smRoman); + short refNum = FSpOpenResFile(&aliasFile, fsRdWrPerm); + if (refNum != -1) { + UseResFile(refNum); + AddResource(Handle(alias), rAliasType, 0, aliasFile.name); + ReleaseResource(Handle(alias)); + UpdateResFile(refNum); + CloseResFile(refNum); + } + // finally, mark the newly created file as an alias file. + FSpGetFInfo(&aliasFile, &info); + info.fdFlags |= kIsAlias; + FSpSetFInfo(&aliasFile, &info); + } + } + } + + // create the target file in the output directory. + BlockMoveData(settings.output, outputDir.name, 1 + settings.output[0]); + FILE* outputFile = FSp_fopen(&outputDir, "w"); + if (outputFile != NULL) fclose(outputFile); + + return err; +} + +static CWResult LinkTypeLib(CWPluginContext context, XPIDLSettings& settings) +{ + // find out how many files there are to link. + long fileCount = 0; + CWResult err = CWGetProjectFileCount(context, &fileCount); + if (err != cwNoErr || fileCount == 0) + return err; + + // assemble the argument list. + // { "xpt_link", outputFile, inputFile1, ..., inputFileN, NULL } + char** argv = new char*[2 + fileCount + 1]; + int argc = 0; + argv[argc++] = "xpt_link"; + + // get the output directory. + err = CWGetOutputFileDirectory(context, &gOutputDirectory); + if (!CWSUCCESS(err)) + return err; + + // get the object code directory. + err = CWGetStoredObjectFileSpec(context, 0, &gObjectCodeDirectory); + if (!CWSUCCESS(err)) + return err; + + // push the output file name. + if ((argv[argc++] = p2c_strdup(settings.output)) == NULL) + return cwErrOutOfMemory; + + for (long index = 0; (err == cwNoErr) && (index < fileCount); index++) { + // get the name of each output file. + CWFileSpec outputFile; + err = CWGetStoredObjectFileSpec(context, index, &outputFile); + if (err == cwNoErr) { + if ((argv[argc++] = p2c_strdup(outputFile.name)) == NULL) { + err = cwErrOutOfMemory; + break; + } + } + } + + if (err != cwNoErr) + return err; + + // trap calls to exit, which longjmp back to here. + if (setjmp(exit_jump) == 0) { + if (xptlink_main(argc, argv) != 0) + err = cwErrRequestFailed; + } else { + // evidently the good old exit function got called. + if (exit_status != 0) + err = cwErrRequestFailed; + } + + return err; +} + +static CWResult Link(CWPluginContext context) +{ + // load the relevant prefs. + XPIDLSettings settings = { kXPIDLSettingsVersion, kXPIDLModeTypelib, false, false }; + CWResult err = GetSettings(context, settings); + if (err != cwNoErr) + return err; + + switch (settings.mode) { + case kXPIDLModeHeader: + return LinkHeaders(context, settings); + case kXPIDLModeTypelib: + return LinkTypeLib(context, settings); + default: + return cwNoErr; + } +} + +static CWResult Disassemble(CWPluginContext context) +{ + CWResult err = noErr; + + // cache the project's output directory. + err = CWGetOutputFileDirectory(gPluginContext, &gOutputDirectory); + if (!CWSUCCESS(err)) + return err; + + long fileNum; + err = CWGetMainFileNumber(context, &fileNum); + if (!CWSUCCESS(err)) + return err; + + // get the output file's location from the stored object data. + err = CWGetStoredObjectFileSpec(context, fileNum, &gObjectCodeDirectory); + if (!CWSUCCESS(err)) + return err; + + char* outputName = p2c_strdup(gObjectCodeDirectory.name); + if (outputName == NULL) + return cwErrOutOfMemory; + + XPIDLSettings settings = { kXPIDLSettingsVersion, kXPIDLModeTypelib, false, false }; + GetSettings(context, settings); + + // build an argument list and call xpt_dump. + int argc = 1; + char* argv[] = { "xpt_dump", NULL, NULL, NULL }; + if (settings.verbose) argv[argc++] = "-v"; + argv[argc++] = outputName; + + // trap calls to exit, which longjmp back to here. + if (setjmp(exit_jump) == 0) { + if (xptdump_main(argc, argv) != 0) + err = cwErrRequestFailed; + } else { + // evidently the good old exit function got called. + if (exit_status != 0) + err = cwErrRequestFailed; + } + + delete[] outputName; + + if (err == noErr) { + // display the disassembly in its own fresh text window. + CWNewTextDocumentInfo info = { + NULL, + mac_console_handle, + false + }; + CWResizeMemHandle(context, mac_console_handle, mac_console_count); + err = CWCreateNewTextDocument(context, &info); + } + + return err; +} + +static CWResult GetTargetInfo(CWPluginContext context) +{ + CWTargetInfo targ; + memset(&targ, 0, sizeof(targ)); + + CWResult err = CWGetOutputFileDirectory(context, &targ.outfile); + targ.outputType = linkOutputFile; + targ.symfile = targ.outfile; /* location of SYM file */ + targ.linkType = exelinkageFlat; + targ.targetCPU = '****'; + targ.targetOS = '****'; + + // load the relevant settings. + XPIDLSettings settings = { kXPIDLSettingsVersion, kXPIDLModeTypelib, false, false }; + err = GetSettings(context, settings); + if (err != cwNoErr) + return err; + +#if CWPLUGIN_HOST == CWPLUGIN_HOST_MACOS + // tell the IDE about the output file. + targ.outfileCreator = 'MMCH'; + targ.outfileType = 'CWIE'; + targ.debuggerCreator = kDebuggerCreator; /* so IDE can locate our debugger */ + + BlockMoveData(settings.output, targ.outfile.name, 1 + settings.output[0]); + targ.symfile.name[0] = 0; +#endif + +#if CWPLUGIN_HOST == CWPLUGIN_HOST_WIN32 + targ.debugHelperIsRegKey = true; + *(long*)targ.debugHelperName = kDebuggerCreator; + targ.debugHelperName[4] = 0; + strcat(targ.outfile.path, "\\"); + strcat(targ.outfile.path, prefsData.outfile); + strcpy(targ.symfile.path, targ.outfile.path); + strcat(targ.symfile.path, ".SYM"); +#endif + + targ.runfile = targ.outfile; + targ.linkAgainstFile = targ.outfile; + + /* we can only run applications */ + // targ.canRun = (prefsData.projtype == kProjTypeApplication); + + /* we can only debug if we have a SYM file */ + // targ.canDebug = prefsData.linksym; + + err = CWSetTargetInfo(context, &targ); + + return err; +} + +#if 0 + +#if CW_USE_PRAGMA_EXPORT +#pragma export on +#endif + +CWPLUGIN_ENTRY(CWPlugin_GetDropInFlags)(const DropInFlags** flags, long* flagsSize) +{ + static const DropInFlags sFlags = { + kCurrentDropInFlagsVersion, + CWDROPINLINKERTYPE, + DROPINCOMPILERLINKERAPIVERSION_7, + (linkMultiTargAware | linkAlwaysReload), + 0, + DROPINCOMPILERLINKERAPIVERSION + }; + + *flags = &sFlags; + *flagsSize = sizeof(sFlags); + + return cwNoErr; +} + +CWPLUGIN_ENTRY(CWPlugin_GetDropInName)(const char** dropinName) +{ + static const char* sDropInName = "xpt Linker"; + *dropinName = sDropInName; + return cwNoErr; +} + +CWPLUGIN_ENTRY(CWPlugin_GetDisplayName)(const char** displayName) +{ + static const char* sDisplayName = "xpt Linker"; + *displayName = sDisplayName; + return cwNoErr; +} + +CWPLUGIN_ENTRY(CWPlugin_GetPanelList)(const CWPanelList** panelList) +{ + // +++Turn this on when the sample panel has been converted! + static const char* sPanelName = kXPIDLPanelName; + static CWPanelList sPanelList = { kCurrentCWPanelListVersion, 1, &sPanelName }; + + *panelList = &sPanelList; + + return cwNoErr; +} + +CWPLUGIN_ENTRY(CWPlugin_GetTargetList)(const CWTargetList** targetList) +{ + static CWDataType sCPU = '****'; + static CWDataType sOS = '****'; + static CWTargetList sTargetList = { kCurrentCWTargetListVersion, 1, &sCPU, 1, &sOS }; + + *targetList = &sTargetList; + + return cwNoErr; +} + +CWPLUGIN_ENTRY(CWPlugin_GetDefaultMappingList)(const CWExtMapList** defaultMappingList) +{ + static CWExtensionMapping sExtension = { 'MMCH', ".xpt", 0 }; + static CWExtMapList sExtensionMapList = { kCurrentCWExtMapListVersion, 1, &sExtension }; + + *defaultMappingList = &sExtensionMapList; + + return cwNoErr; +} + +CWPLUGIN_ENTRY (CWPlugin_GetFamilyList)(const CWFamilyList** familyList) +{ + static CWFamily sFamily = { 'XIDL', "xpidl Settings" }; + static CWFamilyList sFamilyList = { kCurrentCWFamilyListVersion, 0, &sFamily }; + + *familyList = &sFamilyList; + + return cwNoErr; +} + +#if CW_USE_PRAGMA_EXPORT +#pragma export off +#endif + +#endif diff --git a/src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/panel.rsrc b/src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/panel.rsrc new file mode 100644 index 00000000..c5777088 Binary files /dev/null and b/src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/panel.rsrc differ diff --git a/src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/version.rsrc b/src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/version.rsrc new file mode 100644 index 00000000..6737d356 Binary files /dev/null and b/src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/version.rsrc differ diff --git a/src/libs/xpcom18a4/xpcom/typelib/xpidl/xpidl.c b/src/libs/xpcom18a4/xpcom/typelib/xpidl/xpidl.c new file mode 100644 index 00000000..e1a7c58d --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/typelib/xpidl/xpidl.c @@ -0,0 +1,275 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: NPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Netscape 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/NPL/ + * + * 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * 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 NPL, 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 NPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * Main xpidl program entry point. + */ + +#include "xpidl.h" + +static ModeData modes[] = { + {"header", "Generate C++ header", "h", xpidl_header_dispatch}, + {"typelib", "Generate XPConnect typelib", "xpt", xpidl_typelib_dispatch}, + {"doc", "Generate HTML documentation", "html", xpidl_doc_dispatch}, + {"java", "Generate Java interface", "java", xpidl_java_dispatch}, + {0, 0, 0, 0} +}; + +static ModeData * +FindMode(char *mode) +{ + int i; + for (i = 0; modes[i].mode; i++) { + if (!strcmp(modes[i].mode, mode)) + return &modes[i]; + } + return NULL; +} + +gboolean enable_debug = FALSE; +gboolean enable_warnings = FALSE; +gboolean verbose_mode = FALSE; +gboolean emit_typelib_annotations = FALSE; +gboolean explicit_output_filename = FALSE; + +/* The following globals are explained in xpt_struct.h */ +PRUint8 major_version = XPT_MAJOR_VERSION; +PRUint8 minor_version = XPT_MINOR_VERSION; + +static char xpidl_usage_str[] = +"Usage: %s -m mode [-w] [-v] [-t version number]\n" +" [-I path] [-o basename | -e filename.ext] filename.idl\n" +" -a emit annotations to typelib\n" +" -w turn on warnings (recommended)\n" +" -v verbose mode (NYI)\n" +" -t create a typelib of a specific version number\n" +" -I add entry to start of include path for ``#include \"nsIThing.idl\"''\n" +" -o use basename (e.g. ``/tmp/nsIThing'') for output\n" +" -e use explicit output filename\n" +" -m specify output mode:\n"; + +static void +xpidl_usage(int argc, char *argv[]) +{ + int i; + fprintf(stderr, xpidl_usage_str, argv[0]); + for (i = 0; modes[i].mode; i++) { + fprintf(stderr, " %-12s %-30s (.%s)\n", modes[i].mode, + modes[i].modeInfo, modes[i].suffix); + } +} + +#if defined(XP_MAC) && defined(XPIDL_PLUGIN) +#define main xpidl_main +int xpidl_main(int argc, char *argv[]); +#endif + +int main(int argc, char *argv[]) +{ + int i; + IncludePathEntry *inc, *inc_head, **inc_tail; + char *file_basename = NULL; + ModeData *mode = NULL; + gboolean create_old_typelib = FALSE; + + /* turn this on for extra checking of our code */ +/* IDL_check_cast_enable(TRUE); */ + + inc_head = xpidl_malloc(sizeof *inc); +#ifndef XP_MAC + inc_head->directory = "."; +#else + inc_head->directory = ""; +#endif + inc_head->next = NULL; + inc_tail = &inc_head->next; + + for (i = 1; i < argc; i++) { + if (argv[i][0] != '-') + break; + switch (argv[i][1]) { + case '-': + argc++; /* pretend we didn't see this */ + /* fall through */ + case 0: /* - is a legal input filename (stdin) */ + goto done_options; + case 'a': + emit_typelib_annotations = TRUE; + break; + case 'w': + enable_warnings = TRUE; + break; + case 'v': + verbose_mode = TRUE; + break; + case 't': + { + /* Parse for "-t version number" and store it into global boolean + * and string variables. + */ + const gchar* typelib_version_string = NULL; + + /* + * If -t is the last argument on the command line, we have a problem + */ + + if (i + 1 == argc) { + fprintf(stderr, "ERROR: missing version number after -t\n"); + xpidl_usage(argc, argv); + return 1; + } + + /* Do not allow more than one "-t" definition */ + if (create_old_typelib) { + fprintf(stderr, + "ERROR: -t argument used twice. " + "Cannot specify more than one version\n"); + xpidl_usage(argc, argv); + return 1; + } + + /* + * Assume that the argument after "-t" is the version number string + * and search for it in our internal list of acceptable version + * numbers. + */ + switch (XPT_ParseVersionString(argv[++i], &major_version, + &minor_version)) { + case XPT_VERSION_CURRENT: + break; + case XPT_VERSION_OLD: + create_old_typelib = TRUE; + break; + case XPT_VERSION_UNSUPPORTED: + fprintf(stderr, "ERROR: version \"%s\" not supported.\n", + argv[i]); + xpidl_usage(argc, argv); + return 1; + case XPT_VERSION_UNKNOWN: + default: + fprintf(stderr, "ERROR: version \"%s\" not recognised.\n", + argv[i]); + xpidl_usage(argc, argv); + return 1; + } + break; + } + case 'I': + if (argv[i][2] == '\0' && i == argc) { + fputs("ERROR: missing path after -I\n", stderr); + xpidl_usage(argc, argv); + return 1; + } + inc = xpidl_malloc(sizeof *inc); + if (argv[i][2] == '\0') { + /* is it the -I foo form? */ + inc->directory = argv[++i]; + } else { + /* must be the -Ifoo form. Don't preincrement i. */ + inc->directory = argv[i] + 2; + } +#ifdef DEBUG_shaver_includes + fprintf(stderr, "adding %s to include path\n", inc->directory); +#endif + inc->next = NULL; + *inc_tail = inc; + inc_tail = &inc->next; + break; + case 'o': + if (i == argc) { + fprintf(stderr, "ERROR: missing basename after -o\n"); + xpidl_usage(argc, argv); + return 1; + } + file_basename = argv[++i]; + explicit_output_filename = FALSE; + break; + case 'e': + if (i == argc) { + fprintf(stderr, "ERROR: missing basename after -e\n"); + xpidl_usage(argc, argv); + return 1; + } + file_basename = argv[++i]; + explicit_output_filename = TRUE; + break; + case 'm': + if (i + 1 == argc) { + fprintf(stderr, "ERROR: missing modename after -m\n"); + xpidl_usage(argc, argv); + return 1; + } + if (mode) { + fprintf(stderr, + "ERROR: must specify exactly one mode " + "(first \"%s\", now \"%s\")\n", mode->mode, + argv[i + 1]); + xpidl_usage(argc, argv); + return 1; + } + mode = FindMode(argv[++i]); + if (!mode) { + fprintf(stderr, "ERROR: unknown mode \"%s\"\n", argv[i]); + xpidl_usage(argc, argv); + return 1; + } + break; + default: + fprintf(stderr, "unknown option %s\n", argv[i]); + xpidl_usage(argc, argv); + return 1; + } + } + done_options: + if (!mode) { + fprintf(stderr, "ERROR: must specify output mode\n"); + xpidl_usage(argc, argv); + return 1; + } + if (argc != i + 1) { + fprintf(stderr, "ERROR: extra arguments after input file\n"); + } + + /* + * Don't try to process multiple files, given that we don't handle -o + * multiply. + */ + if (xpidl_process_idl(argv[i], inc_head, file_basename, mode)) + return 0; + + return 1; +} diff --git a/src/libs/xpcom18a4/xpcom/typelib/xpidl/xpidl.h b/src/libs/xpcom18a4/xpcom/typelib/xpidl/xpidl.h new file mode 100644 index 00000000..857bfdf8 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/typelib/xpidl/xpidl.h @@ -0,0 +1,278 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: NPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Netscape 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/NPL/ + * + * 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * 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 NPL, 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 NPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * Intramodule declarations. + */ + +#ifndef __xpidl_h +#define __xpidl_h + +#include +#include +#include +#include +#include +#include /* After glib.h to avoid warnings about shadowing 'index'. */ + +#ifndef XP_MAC +#include +#else +#include +#endif + +#include + +/* + * IDL_tree_warning bombs on libIDL version 6.5, and I don't want to not write + * warnings... so I define a versioned one here. Thanks to Mike Shaver for the + * this solution, which allows us to pass through varargs calls. + */ +#if !(LIBIDL_MAJOR_VERSION == 0 && LIBIDL_MINOR_VERSION == 6 && \ + LIBIDL_MICRO_VERSION == 5) && !defined(DEBUG_shaver) +/* + * This turns a varargs call to XPIDL_WARNING directly into a varargs + * call to IDL_tree_warning or xpidl_tree_warning as appropriate. The + * only tricky bit is that you must call XPIDL_WARNING with extra + * parens, e.g. XPIDL_WARNING((foo, bar, "sil")) + * + * Probably best removed when we leave 6.5. */ +#define XPIDL_WARNING(x) IDL_tree_warning x +#else +extern void xpidl_tree_warning(IDL_tree p, int level, const char *fmt, ...); +#define XPIDL_WARNING(x) xpidl_tree_warning x +#endif + +/* + * Internal operation flags. + */ +extern gboolean enable_debug; +extern gboolean enable_warnings; +extern gboolean verbose_mode; +extern gboolean emit_typelib_annotations; +extern gboolean explicit_output_filename; + +extern PRUint8 major_version; +extern PRUint8 minor_version; + +typedef struct TreeState TreeState; + +/* + * A function to handle an IDL_tree type. + */ +typedef gboolean (*nodeHandler)(TreeState *); + +/* + * Struct containing functions to define the behavior of a given output mode. + */ +typedef struct backend { + nodeHandler *dispatch_table; /* nodeHandlers table, indexed by node type. */ + nodeHandler emit_prolog; /* called at beginning of output generation. */ + nodeHandler emit_epilog; /* called at end. */ +} backend; + +/* Function that produces a struct of output-generation functions */ +typedef backend *(*backendFactory)(); + +extern backend *xpidl_header_dispatch(void); +extern backend *xpidl_typelib_dispatch(void); +extern backend *xpidl_doc_dispatch(void); +extern backend *xpidl_java_dispatch(void); + +typedef struct ModeData { + char *mode; + char *modeInfo; + char *suffix; + backendFactory factory; +} ModeData; + +typedef struct IncludePathEntry { + char *directory; + struct IncludePathEntry *next; +} IncludePathEntry; + +struct TreeState { + FILE *file; + /* Maybe supplied by -o. Not related to (g_)basename from string.h or glib */ + char *basename; + IDL_ns ns; + IDL_tree tree; + GSList *base_includes; + nodeHandler *dispatch; + void *priv; /* mode-private data */ +#ifdef VBOX_XPIDL_EMULATE_GENJIFACES + char *real_outname; +#endif + +}; + +/* + * Process an IDL file, generating InterfaceInfo, documentation and headers as + * appropriate. + */ +int +xpidl_process_idl(char *filename, IncludePathEntry *include_path, + char *file_basename, ModeData *mode); + +/* + * Iterate over an IDLN_LIST -- why is this not part of libIDL? + */ +void +xpidl_list_foreach(IDL_tree p, IDL_tree_func foreach, gpointer user_data); + +/* + * Wrapper whines to stderr then exits after null return from malloc or strdup. + */ +void * +xpidl_malloc(size_t nbytes); + +char * +xpidl_strdup(const char *s); + +/* + * Return a newly allocated string to the start of the base filename of path. + * Free with g_free(). + */ +char * +xpidl_basename(const char * path); + +/* + * Process an XPIDL node and its kids, if any. + */ +gboolean +xpidl_process_node(TreeState *state); + +/* + * Write a newline folllowed by an indented, one-line comment containing IDL + * source decompiled from state->tree. + */ +void +xpidl_write_comment(TreeState *state, int indent); + + + +/* + * Functions for parsing and printing UUIDs. + */ + +/* + * How large should the buffer supplied to xpidl_sprint_IID be? + */ +#define UUID_LENGTH 37 + +/* + * Print an iid to into a supplied buffer; the buffer should be at least + * UUID_LENGTH bytes. + */ +gboolean +xpidl_sprint_iid(nsID *iid, char iidbuf[]); + +/* + * Parse a uuid string into an nsID struct. We cannot link against libxpcom, + * so we re-implement nsID::Parse here. + */ +gboolean +xpidl_parse_iid(nsID *id, const char *str); + + +/* Try to common a little node-handling stuff. */ + +/* is this node from an aggregate type (interface)? */ +#define UP_IS_AGGREGATE(node) \ + (IDL_NODE_UP(node) && \ + (IDL_NODE_TYPE(IDL_NODE_UP(node)) == IDLN_INTERFACE || \ + IDL_NODE_TYPE(IDL_NODE_UP(node)) == IDLN_FORWARD_DCL)) + +#define UP_IS_NATIVE(node) \ + (IDL_NODE_UP(node) && \ + IDL_NODE_TYPE(IDL_NODE_UP(node)) == IDLN_NATIVE) + +/* is this type output in the form " *"? */ +#define STARRED_TYPE(node) (IDL_NODE_TYPE(node) == IDLN_TYPE_STRING || \ + IDL_NODE_TYPE(node) == IDLN_TYPE_WIDE_STRING || \ + (IDL_NODE_TYPE(node) == IDLN_IDENT && \ + UP_IS_AGGREGATE(node))) + +#define DIPPER_TYPE(node) \ + (NULL != IDL_tree_property_get(node, "domstring") || \ + NULL != IDL_tree_property_get(node, "utf8string") || \ + NULL != IDL_tree_property_get(node, "cstring") || \ + NULL != IDL_tree_property_get(node, "astring")) + +/* + * Find the underlying type of an identifier typedef. Returns NULL + * (and doesn't complain) on failure. + */ +IDL_tree /* IDL_TYPE_DCL */ +find_underlying_type(IDL_tree typedef_ident); + +/* + * Check that const declarations match their stated sign and are of the + * appropriate types. + */ +gboolean +verify_const_declaration(IDL_tree const_tree); + +/* + * Check that scriptable attributes in scriptable interfaces actually are. + */ +gboolean +verify_attribute_declaration(IDL_tree method_tree); + +/* + * Perform various validation checks on methods. + */ +gboolean +verify_method_declaration(IDL_tree method_tree); + +/* + * Verifies the interface declaration + */ +gboolean +verify_interface_declaration(IDL_tree method_tree); + +/* + * Verify that a native declaration has an associated C++ expression, i.e. that + * it's of the form native () + */ +gboolean +check_native(TreeState *state); + +void +printlist(FILE *outfile, GSList *slist); + +#endif /* __xpidl_h */ diff --git a/src/libs/xpcom18a4/xpcom/typelib/xpidl/xpidl_doc.c b/src/libs/xpcom18a4/xpcom/typelib/xpidl/xpidl_doc.c new file mode 100644 index 00000000..d560e407 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/typelib/xpidl/xpidl_doc.c @@ -0,0 +1,312 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: NPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Netscape 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/NPL/ + * + * 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * 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 NPL, 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 NPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "xpidl.h" + +/* + * Generates documentation from javadoc-style comments in XPIDL files. + */ + +static gboolean +doc_prolog(TreeState *state) +{ + fprintf(state->file, "\n"); + fprintf(state->file, "\n"); + + fprintf(state->file, + "\n", + state->basename); + fprintf(state->file, "documentation for %s.idl interfaces\n", + state->basename); + fprintf(state->file, "\n\n"); + fprintf(state->file, "\n"); + + return TRUE; +} + +static gboolean +doc_epilog(TreeState *state) +{ + fprintf(state->file, "\n"); + fprintf(state->file, "\n"); + + return TRUE; +} + + +static gboolean +doc_list(TreeState *state) +{ + IDL_tree iter; + for (iter = state->tree; iter; iter = IDL_LIST(iter).next) { + state->tree = IDL_LIST(iter).data; + if (!xpidl_process_node(state)) + return FALSE; + } + return TRUE; +} + +static gboolean +print_list(FILE *outfile, IDL_tree list) +{ + if (list == NULL) + return TRUE; + + fprintf(outfile, "
    \n"); + while (list != NULL) { + fprintf(outfile, "
  • %s\n", + IDL_IDENT(IDL_LIST(list).data).str); + list = IDL_LIST(list).next; + } + fprintf(outfile, "
\n"); + return TRUE; +} + +static gboolean +doc_interface(TreeState *state) +{ + IDL_tree iface = state->tree; + IDL_tree iter; + IDL_tree orig; + char *classname = IDL_IDENT(IDL_INTERFACE(iface).ident).str; + GSList *doc_comments = IDL_IDENT(IDL_INTERFACE(iface).ident).comments; + + fprintf(state->file, "interface %s
\n", classname); + + /* Much more could happen at this step. */ + /* + * If parsing doc comments, you might need to take some care with line + * endings, as the xpidl frontend will return comments containing of /r, + * /n, /r/n depending on the platform. It's best to leave out platform + * #defines and just treat them all as equivalent. + */ + if (doc_comments != NULL) { + fprintf(state->file, "doc comments:
\n"); + fprintf(state->file, "
\n");
+        printlist(state->file, doc_comments);
+        fprintf(state->file, "
\n"); + fprintf(state->file, "
\n"); + } + + /* inherits from */ + /* + * Note that we accept multiple inheritance here (for e.g. gnome idl) + * even though the header backend (specific to mozilla idl) rejects it. + */ + if ((iter = IDL_INTERFACE(iface).inheritance_spec)) { + fprintf(state->file, "%s inherits from:
\n", classname); + print_list(state->file, iter); + fprintf(state->file, "
\n"); + } + + /* + * Call xpidl_process_node to recur through list of declarations in + * interface body; another option would be to explicitly iterate through + * the list. xpidl_process_node currently requires twiddling the state to + * get the right node; I'll fix that soon to just take the node. Makes it + * easier to follow what's going on, I think... + */ + orig = state->tree; + state->tree = IDL_INTERFACE(iface).body; + if (state->tree && !xpidl_process_node(state)) + return FALSE; + state->tree = orig; + + return TRUE; +} + +/* + * Copied from xpidl_header.c. You'll probably want to change it; if you can + * use it verbatim or abstract it, we could move it to xpidl_util.c and share + * it from there. + */ +static gboolean +write_type(IDL_tree type_tree, FILE *outfile) +{ + if (!type_tree) { + fputs("void", outfile); + return TRUE; + } + + switch (IDL_NODE_TYPE(type_tree)) { + case IDLN_TYPE_INTEGER: { + gboolean sign = IDL_TYPE_INTEGER(type_tree).f_signed; + switch (IDL_TYPE_INTEGER(type_tree).f_type) { + case IDL_INTEGER_TYPE_SHORT: + fputs(sign ? "PRInt16" : "PRUint16", outfile); + break; + case IDL_INTEGER_TYPE_LONG: + fputs(sign ? "PRInt32" : "PRUint32", outfile); + break; + case IDL_INTEGER_TYPE_LONGLONG: + fputs(sign ? "PRInt64" : "PRUint64", outfile); + break; + default: + g_error("Unknown integer type %d\n", + IDL_TYPE_INTEGER(type_tree).f_type); + return FALSE; + } + break; + } + case IDLN_TYPE_CHAR: + fputs("char", outfile); + break; + case IDLN_TYPE_WIDE_CHAR: + fputs("PRUnichar", outfile); /* wchar_t? */ + break; + case IDLN_TYPE_WIDE_STRING: + fputs("PRUnichar *", outfile); + break; + case IDLN_TYPE_STRING: + fputs("char *", outfile); + break; + case IDLN_TYPE_BOOLEAN: + fputs("PRBool", outfile); + break; + case IDLN_TYPE_OCTET: + fputs("PRUint8", outfile); + break; + case IDLN_TYPE_FLOAT: + switch (IDL_TYPE_FLOAT(type_tree).f_type) { + case IDL_FLOAT_TYPE_FLOAT: + fputs("float", outfile); + break; + case IDL_FLOAT_TYPE_DOUBLE: + fputs("double", outfile); + break; + /* XXX 'long double' just ignored, or what? */ + default: + fprintf(outfile, "unknown_type_%d", IDL_NODE_TYPE(type_tree)); + break; + } + break; + case IDLN_IDENT: + if (UP_IS_NATIVE(type_tree)) { + fputs(IDL_NATIVE(IDL_NODE_UP(type_tree)).user_type, outfile); + if (IDL_tree_property_get(type_tree, "ptr")) { + fputs(" *", outfile); + } else if (IDL_tree_property_get(type_tree, "ref")) { + fputs(" &", outfile); + } + } else { + fputs(IDL_IDENT(type_tree).str, outfile); + } + if (UP_IS_AGGREGATE(type_tree)) + fputs(" *", outfile); + break; + default: + fprintf(outfile, "unknown_type_%d", IDL_NODE_TYPE(type_tree)); + break; + } + return TRUE; +} + +/* handle ATTR_DCL (attribute declaration) nodes */ +static gboolean +doc_attribute_declaration(TreeState *state) +{ + IDL_tree attr = state->tree; + + if (!verify_attribute_declaration(attr)) + return FALSE; + /* + * Attribute idents can also take doc comments. They're ignored here; + * should they be? + */ + + if (IDL_ATTR_DCL(attr).f_readonly) + fprintf(state->file, "readonly "); + + fprintf(state->file, "attribute "); + + if (!write_type(IDL_ATTR_DCL(attr).param_type_spec, state->file)) + return FALSE; + + fprintf(state->file, "\n"); + print_list(state->file, IDL_ATTR_DCL(attr).simple_declarations); + fprintf(state->file, "
\n"); + + return TRUE; +} + +/* handle OP_DCL (method declaration) nodes */ +static gboolean +doc_method_declaration(TreeState *state) +{ + /* + * Doc comment for attributes also applies here. + */ + + /* + * Look at 'write_method_signature' in xpidl_header.c for an example of how + * to navigate parse trees for methods. For here, I just print the method + * name. + */ + + fprintf(state->file, + "method %s
\n", + IDL_IDENT(IDL_OP_DCL(state->tree).ident).str); + + return TRUE; +} + +backend * +xpidl_doc_dispatch(void) +{ + static backend result; + static nodeHandler table[IDLN_LAST]; + static gboolean initialized = FALSE; + + result.emit_prolog = doc_prolog; + result.emit_epilog = doc_epilog; + + if (!initialized) { + /* Initialize non-NULL elements */ + + /* I just handle a few... many still to be filled in! */ + + table[IDLN_LIST] = doc_list; + table[IDLN_INTERFACE] = doc_interface; + table[IDLN_ATTR_DCL] = doc_attribute_declaration; + table[IDLN_OP_DCL] = doc_method_declaration; + + initialized = TRUE; + } + + result.dispatch_table = table; + return &result; +} diff --git a/src/libs/xpcom18a4/xpcom/typelib/xpidl/xpidl_header.c b/src/libs/xpcom18a4/xpcom/typelib/xpidl/xpidl_header.c new file mode 100644 index 00000000..f4fe9d5b --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/typelib/xpidl/xpidl_header.c @@ -0,0 +1,1196 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: NPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Netscape 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/NPL/ + * + * 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * 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 NPL, 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 NPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * Generate XPCOM headers from XPIDL. + */ + +#include "xpidl.h" +#include + +#define AS_DECL 0 +#define AS_CALL 1 +#define AS_IMPL 2 + +static gboolean write_method_signature(IDL_tree method_tree, FILE *outfile, + int mode, const char *className); +static gboolean write_attr_accessor(IDL_tree attr_tree, FILE * outfile, + gboolean getter, + int mode, const char *className); + +static void +write_indent(FILE *outfile) { + fputs(" ", outfile); +} + +static gboolean +header_prolog(TreeState *state) +{ + char *define = xpidl_basename(state->basename); + fprintf(state->file, "/*\n * DO NOT EDIT. THIS FILE IS GENERATED FROM" + " %s.idl\n */\n", state->basename); + fprintf(state->file, + "\n#ifndef __gen_%s_h__\n" + "#define __gen_%s_h__\n", + define, define); + g_free(define); + if (state->base_includes != NULL) { + guint len = g_slist_length(state->base_includes); + guint i; + + fputc('\n', state->file); + for (i = 0; i < len; i++) { + char *ident, *dot; + + ident = (char *)g_slist_nth_data(state->base_includes, i); + + /* suppress any trailing .extension */ + + /* XXX use g_basename instead ? ? */ + + dot = strrchr(ident, '.'); + if (dot != NULL) + *dot = '\0'; + + + /* begin include guard */ + fprintf(state->file, + "\n#ifndef __gen_%s_h__\n", + ident); + + fprintf(state->file, "#include \"%s.h\"\n", + (char *)g_slist_nth_data(state->base_includes, i)); + + fprintf(state->file, "#endif\n"); + + } + if (i > 0) + fputc('\n', state->file); + } + /* + * Support IDL files that don't include a root IDL file that defines + * NS_NO_VTABLE. + */ + fprintf(state->file, + "/* For IDL files that don't want to include root IDL files. */\n" + "#ifndef NS_NO_VTABLE\n" + "#define NS_NO_VTABLE\n" + "#endif\n"); + + return TRUE; +} + +static gboolean +header_epilog(TreeState *state) +{ + char *define = xpidl_basename(state->basename); + fprintf(state->file, "\n#endif /* __gen_%s_h__ */\n", define); + g_free(define); + return TRUE; +} + +static void +write_classname_iid_define(FILE *file, const char *className) +{ + const char *iidName; + if (className[0] == 'n' && className[1] == 's') { + /* backcompat naming styles */ + fputs("NS_", file); + iidName = className + 2; + } else { + iidName = className; + } + while (*iidName) + fputc(toupper(*iidName++), file); + fputs("_IID", file); +} + +static gboolean +interface(TreeState *state) +{ + IDL_tree iface = state->tree, iter, orig; + char *className = IDL_IDENT(IDL_INTERFACE(iface).ident).str; + char *classNameUpper = NULL; + char *classNameImpl = NULL; + char *cp; + gboolean ok = TRUE; + gboolean keepvtable; + const char *iid; + const char *name_space; + struct nsID id; + char iid_parsed[UUID_LENGTH]; + GSList *doc_comments = IDL_IDENT(IDL_INTERFACE(iface).ident).comments; + + if (!verify_interface_declaration(iface)) + return FALSE; + +#define FAIL do {ok = FALSE; goto out;} while(0) + + fprintf(state->file, "\n/* starting interface: %s */\n", + className); + + name_space = IDL_tree_property_get(IDL_INTERFACE(iface).ident, "namespace"); + if (name_space) { + fprintf(state->file, "/* namespace: %s */\n", + name_space); + fprintf(state->file, "/* fully qualified name: %s.%s */\n", + name_space,className); + } + + iid = IDL_tree_property_get(IDL_INTERFACE(iface).ident, "uuid"); + if (iid) { + /* Redundant, but a better error than 'cannot parse.' */ + if (strlen(iid) != 36) { + IDL_tree_error(state->tree, "IID %s is the wrong length\n", iid); + FAIL; + } + + /* + * Parse uuid and then output resulting nsID to string, to validate + * uuid and normalize resulting .h files. + */ + if (!xpidl_parse_iid(&id, iid)) { + IDL_tree_error(state->tree, "cannot parse IID %s\n", iid); + FAIL; + } + if (!xpidl_sprint_iid(&id, iid_parsed)) { + IDL_tree_error(state->tree, "error formatting IID %s\n", iid); + FAIL; + } + + /* #define NS_ISUPPORTS_IID_STR "00000000-0000-0000-c000-000000000046" */ + fputs("#define ", state->file); + write_classname_iid_define(state->file, className); + fprintf(state->file, "_STR \"%s\"\n", iid_parsed); + fputc('\n', state->file); + + /* #define NS_ISUPPORTS_IID { {0x00000000 .... 0x46 }} */ + fprintf(state->file, "#define "); + write_classname_iid_define(state->file, className); + fprintf(state->file, " \\\n" + " {0x%.8x, 0x%.4x, 0x%.4x, \\\n" + " { 0x%.2x, 0x%.2x, 0x%.2x, 0x%.2x, " + "0x%.2x, 0x%.2x, 0x%.2x, 0x%.2x }}\n", + id.m0, id.m1, id.m2, + id.m3[0], id.m3[1], id.m3[2], id.m3[3], + id.m3[4], id.m3[5], id.m3[6], id.m3[7]); + fputc('\n', state->file); + } else { + IDL_tree_error(state->tree, "interface %s lacks a uuid attribute\n", + className); + FAIL; + } + + if (doc_comments != NULL) + printlist(state->file, doc_comments); + + /* + * NS_NO_VTABLE is defined in nsISupportsUtils.h, and defined on windows + * to __declspec(novtable) on windows. This optimization is safe + * whenever the constructor calls no virtual methods. Writing in IDL + * almost guarantees this, except for the case when a %{C++ block occurs in + * the interface. We detect that case, and emit a macro call that disables + * the optimization. + */ + keepvtable = FALSE; + for (iter = IDL_INTERFACE(state->tree).body; + iter != NULL; + iter = IDL_LIST(iter).next) + { + IDL_tree data = IDL_LIST(iter).data; + if (IDL_NODE_TYPE(data) == IDLN_CODEFRAG) + keepvtable = TRUE; + } + + /* The interface declaration itself. */ + fprintf(state->file, + "class %s%s", + (keepvtable ? "" : "NS_NO_VTABLE "), className); + + if ((iter = IDL_INTERFACE(iface).inheritance_spec)) { + fputs(" : ", state->file); + if (IDL_LIST(iter).next != NULL) { + IDL_tree_error(iter, + "multiple inheritance is not supported by xpidl"); + FAIL; + } + fprintf(state->file, "public %s", IDL_IDENT(IDL_LIST(iter).data).str); + } + fputs(" {\n" + " public: \n\n", state->file); + if (iid) { + fputs(" NS_DEFINE_STATIC_IID_ACCESSOR(", state->file); + write_classname_iid_define(state->file, className); + fputs(")\n\n", state->file); + } + + orig = state->tree; /* It would be nice to remove this state-twiddling. */ + + state->tree = IDL_INTERFACE(iface).body; + + if (state->tree && !xpidl_process_node(state)) + FAIL; + + fputs("};\n", state->file); + fputc('\n', state->file); + + /* + * #define NS_DECL_NSIFOO - create method prototypes that can be used in + * class definitions that support this interface. + * + * Walk the tree explicitly to prototype a reworking of xpidl to get rid of + * the callback mechanism. + */ + state->tree = orig; + fputs("/* Use this macro when declaring classes that implement this " + "interface. */\n", state->file); + fputs("#define NS_DECL_", state->file); + classNameUpper = xpidl_strdup(className); + for (cp = classNameUpper; *cp != '\0'; cp++) + *cp = toupper(*cp); + fprintf(state->file, "%s \\\n", classNameUpper); + if (IDL_INTERFACE(state->tree).body == NULL) { + write_indent(state->file); + fputs("/* no methods! */\n", state->file); + } + + for (iter = IDL_INTERFACE(state->tree).body; + iter != NULL; + iter = IDL_LIST(iter).next) + { + IDL_tree data = IDL_LIST(iter).data; + + switch(IDL_NODE_TYPE(data)) { + case IDLN_OP_DCL: + write_indent(state->file); + write_method_signature(data, state->file, AS_DECL, NULL); + break; + + case IDLN_ATTR_DCL: + write_indent(state->file); + if (!write_attr_accessor(data, state->file, TRUE, AS_DECL, NULL)) + FAIL; + if (!IDL_ATTR_DCL(data).f_readonly) { + fputs("; \\\n", state->file); /* Terminate the previous one. */ + write_indent(state->file); + if (!write_attr_accessor(data, state->file, + FALSE, AS_DECL, NULL)) + FAIL; + /* '; \n' at end will clean up. */ + } + break; + + case IDLN_CONST_DCL: + /* ignore it here; it doesn't contribute to the macro. */ + continue; + + case IDLN_CODEFRAG: + XPIDL_WARNING((iter, IDL_WARNING1, + "%%{ .. %%} code fragment within interface " + "ignored when generating NS_DECL_%s macro; " + "if the code fragment contains method " + "declarations, the macro probably isn't " + "complete.", classNameUpper)); + continue; + + default: + IDL_tree_error(iter, + "unexpected node type %d! " + "Please file a bug against the xpidl component.", + IDL_NODE_TYPE(data)); + FAIL; + } + + if (IDL_LIST(iter).next != NULL) { + fprintf(state->file, "; \\\n"); + } else { + fprintf(state->file, "; \n"); + } + } + fputc('\n', state->file); + + /* XXX abstract above and below into one function? */ + /* + * #define NS_FORWARD_NSIFOO - create forwarding methods that can delegate + * behavior from in implementation to another object. As generated by + * idlc. + */ + fprintf(state->file, + "/* Use this macro to declare functions that forward the " + "behavior of this interface to another object. */\n" + "#define NS_FORWARD_%s(_to) \\\n", + classNameUpper); + if (IDL_INTERFACE(state->tree).body == NULL) { + write_indent(state->file); + fputs("/* no methods! */\n", state->file); + } + + for (iter = IDL_INTERFACE(state->tree).body; + iter != NULL; + iter = IDL_LIST(iter).next) + { + IDL_tree data = IDL_LIST(iter).data; + + switch(IDL_NODE_TYPE(data)) { + case IDLN_OP_DCL: + write_indent(state->file); + write_method_signature(data, state->file, AS_DECL, NULL); + fputs(" { return _to ", state->file); + write_method_signature(data, state->file, AS_CALL, NULL); + break; + + case IDLN_ATTR_DCL: + write_indent(state->file); + if (!write_attr_accessor(data, state->file, TRUE, AS_DECL, NULL)) + FAIL; + fputs(" { return _to ", state->file); + if (!write_attr_accessor(data, state->file, TRUE, AS_CALL, NULL)) + FAIL; + if (!IDL_ATTR_DCL(data).f_readonly) { + fputs("; } \\\n", state->file); /* Terminate the previous one. */ + write_indent(state->file); + if (!write_attr_accessor(data, state->file, + FALSE, AS_DECL, NULL)) + FAIL; + fputs(" { return _to ", state->file); + if (!write_attr_accessor(data, state->file, + FALSE, AS_CALL, NULL)) + FAIL; + /* '; } \n' at end will clean up. */ + } + break; + + case IDLN_CONST_DCL: + case IDLN_CODEFRAG: + continue; + + default: + FAIL; + } + + if (IDL_LIST(iter).next != NULL) { + fprintf(state->file, "; } \\\n"); + } else { + fprintf(state->file, "; } \n"); + } + } + fputc('\n', state->file); + + + /* XXX abstract above and below into one function? */ + /* + * #define NS_FORWARD_SAFE_NSIFOO - create forwarding methods that can delegate + * behavior from in implementation to another object. As generated by + * idlc. + */ + fprintf(state->file, + "/* Use this macro to declare functions that forward the " + "behavior of this interface to another object in a safe way. */\n" + "#define NS_FORWARD_SAFE_%s(_to) \\\n", + classNameUpper); + if (IDL_INTERFACE(state->tree).body == NULL) { + write_indent(state->file); + fputs("/* no methods! */\n", state->file); + } + + for (iter = IDL_INTERFACE(state->tree).body; + iter != NULL; + iter = IDL_LIST(iter).next) + { + IDL_tree data = IDL_LIST(iter).data; + + switch(IDL_NODE_TYPE(data)) { + case IDLN_OP_DCL: + write_indent(state->file); + write_method_signature(data, state->file, AS_DECL, NULL); + fputs(" { return !_to ? NS_ERROR_NULL_POINTER : _to->", state->file); + write_method_signature(data, state->file, AS_CALL, NULL); + break; + + case IDLN_ATTR_DCL: + write_indent(state->file); + if (!write_attr_accessor(data, state->file, TRUE, AS_DECL, NULL)) + FAIL; + fputs(" { return !_to ? NS_ERROR_NULL_POINTER : _to->", state->file); + if (!write_attr_accessor(data, state->file, TRUE, AS_CALL, NULL)) + FAIL; + if (!IDL_ATTR_DCL(data).f_readonly) { + fputs("; } \\\n", state->file); /* Terminate the previous one. */ + write_indent(state->file); + if (!write_attr_accessor(data, state->file, + FALSE, AS_DECL, NULL)) + FAIL; + fputs(" { return !_to ? NS_ERROR_NULL_POINTER : _to->", state->file); + if (!write_attr_accessor(data, state->file, + FALSE, AS_CALL, NULL)) + FAIL; + /* '; } \n' at end will clean up. */ + } + break; + + case IDLN_CONST_DCL: + case IDLN_CODEFRAG: + continue; + + default: + FAIL; + } + + if (IDL_LIST(iter).next != NULL) { + fprintf(state->file, "; } \\\n"); + } else { + fprintf(state->file, "; } \n"); + } + } + fputc('\n', state->file); + + /* + * Build a sample implementation template. + */ + if (strlen(className) >= 3 && className[2] == 'I') { + classNameImpl = xpidl_strdup(className); + if (!classNameImpl) + FAIL; + memmove(&classNameImpl[2], &classNameImpl[3], strlen(classNameImpl) - 2); + } else { + classNameImpl = xpidl_strdup("_MYCLASS_"); + if (!classNameImpl) + FAIL; + } + + fputs("#if 0\n" + "/* Use the code below as a template for the " + "implementation class for this interface. */\n" + "\n" + "/* Header file */" + "\n", + state->file); + fprintf(state->file, "class %s : public %s\n", classNameImpl, className); + fputs("{\n" + "public:\n", state->file); + write_indent(state->file); + fputs("NS_DECL_ISUPPORTS\n", state->file); + write_indent(state->file); + fprintf(state->file, "NS_DECL_%s\n", classNameUpper); + fputs("\n", state->file); + write_indent(state->file); + fprintf(state->file, "%s();\n", classNameImpl); + fputs("\n" + "private:\n", state->file); + write_indent(state->file); + fprintf(state->file, "~%s();\n", classNameImpl); + fputs("\n" + "protected:\n", state->file); + write_indent(state->file); + fputs("/* additional members */\n", state->file); + fputs("};\n\n", state->file); + + fputs("/* Implementation file */\n", state->file); + + fprintf(state->file, + "NS_IMPL_ISUPPORTS1(%s, %s)\n", classNameImpl, className); + fputs("\n", state->file); + + fprintf(state->file, "%s::%s()\n", classNameImpl, classNameImpl); + fputs("{\n", state->file); + write_indent(state->file); + fputs("/* member initializers and constructor code */\n", state->file); + fputs("}\n\n", state->file); + + fprintf(state->file, "%s::~%s()\n", classNameImpl, classNameImpl); + fputs("{\n", state->file); + write_indent(state->file); + fputs("/* destructor code */\n", state->file); + fputs("}\n\n", state->file); + + for (iter = IDL_INTERFACE(state->tree).body; + iter != NULL; + iter = IDL_LIST(iter).next) + { + IDL_tree data = IDL_LIST(iter).data; + + switch(IDL_NODE_TYPE(data)) { + case IDLN_OP_DCL: + /* It would be nice to remove this state-twiddling. */ + orig = state->tree; + state->tree = data; + xpidl_write_comment(state, 0); + state->tree = orig; + + write_method_signature(data, state->file, AS_IMPL, classNameImpl); + fputs("\n{\n", state->file); + write_indent(state->file); + write_indent(state->file); + fputs("return NS_ERROR_NOT_IMPLEMENTED;\n" + "}\n" + "\n", state->file); + break; + + case IDLN_ATTR_DCL: + /* It would be nice to remove this state-twiddling. */ + orig = state->tree; + state->tree = data; + xpidl_write_comment(state, 0); + state->tree = orig; + + if (!write_attr_accessor(data, state->file, TRUE, + AS_IMPL, classNameImpl)) + FAIL; + fputs("\n{\n", state->file); + write_indent(state->file); + write_indent(state->file); + fputs("return NS_ERROR_NOT_IMPLEMENTED;\n" + "}\n", state->file); + + if (!IDL_ATTR_DCL(data).f_readonly) { + if (!write_attr_accessor(data, state->file, FALSE, + AS_IMPL, classNameImpl)) + FAIL; + fputs("\n{\n", state->file); + write_indent(state->file); + write_indent(state->file); + fputs("return NS_ERROR_NOT_IMPLEMENTED;\n" + "}\n", state->file); + } + fputs("\n", state->file); + break; + + case IDLN_CONST_DCL: + case IDLN_CODEFRAG: + continue; + + default: + FAIL; + } + } + + fputs("/* End of implementation class template. */\n" + "#endif\n" + "\n", state->file); + +#undef FAIL + +out: + if (classNameUpper) + free(classNameUpper); + if (classNameImpl) + free(classNameImpl); + return ok; +} + +static gboolean +list(TreeState *state) +{ + IDL_tree iter; + for (iter = state->tree; iter; iter = IDL_LIST(iter).next) { + state->tree = IDL_LIST(iter).data; + if (!xpidl_process_node(state)) + return FALSE; + } + return TRUE; +} + +static gboolean +write_type(IDL_tree type_tree, gboolean is_out, FILE *outfile) +{ + if (!type_tree) { + fputs("void", outfile); + return TRUE; + } + + switch (IDL_NODE_TYPE(type_tree)) { + case IDLN_TYPE_INTEGER: { + gboolean sign = IDL_TYPE_INTEGER(type_tree).f_signed; + switch (IDL_TYPE_INTEGER(type_tree).f_type) { + case IDL_INTEGER_TYPE_SHORT: + fputs(sign ? "PRInt16" : "PRUint16", outfile); + break; + case IDL_INTEGER_TYPE_LONG: + fputs(sign ? "PRInt32" : "PRUint32", outfile); + break; + case IDL_INTEGER_TYPE_LONGLONG: + fputs(sign ? "PRInt64" : "PRUint64", outfile); + break; + default: + g_error("Unknown integer type %d\n", + IDL_TYPE_INTEGER(type_tree).f_type); + return FALSE; + } + break; + } + case IDLN_TYPE_CHAR: + fputs("char", outfile); + break; + case IDLN_TYPE_WIDE_CHAR: + fputs("PRUnichar", outfile); /* wchar_t? */ + break; + case IDLN_TYPE_WIDE_STRING: + fputs("PRUnichar *", outfile); + break; + case IDLN_TYPE_STRING: + fputs("char *", outfile); + break; + case IDLN_TYPE_BOOLEAN: + fputs("PRBool", outfile); + break; + case IDLN_TYPE_OCTET: + fputs("PRUint8", outfile); + break; + case IDLN_TYPE_FLOAT: + switch (IDL_TYPE_FLOAT(type_tree).f_type) { + case IDL_FLOAT_TYPE_FLOAT: + fputs("float", outfile); + break; + case IDL_FLOAT_TYPE_DOUBLE: + fputs("double", outfile); + break; + /* XXX 'long double' just ignored, or what? */ + default: + fprintf(outfile, "unknown_type_%d", IDL_NODE_TYPE(type_tree)); + break; + } + break; + case IDLN_IDENT: + if (UP_IS_NATIVE(type_tree)) { + if (IDL_tree_property_get(type_tree, "domstring") || + IDL_tree_property_get(type_tree, "astring")) { + fputs("nsAString", outfile); + } else if (IDL_tree_property_get(type_tree, "utf8string")) { + fputs("nsACString", outfile); + } else if (IDL_tree_property_get(type_tree, "cstring")) { + fputs("nsACString", outfile); + } else { + fputs(IDL_NATIVE(IDL_NODE_UP(type_tree)).user_type, outfile); + } + if (IDL_tree_property_get(type_tree, "ptr")) { + fputs(" *", outfile); + } else if (IDL_tree_property_get(type_tree, "ref")) { + fputs(" &", outfile); + } + } else { + fputs(IDL_IDENT(type_tree).str, outfile); + } + if (UP_IS_AGGREGATE(type_tree)) + fputs(" *", outfile); + break; + default: + fprintf(outfile, "unknown_type_%d", IDL_NODE_TYPE(type_tree)); + break; + } + return TRUE; +} + +/* + * An attribute declaration looks like: + * + * [ IDL_ATTR_DCL] + * - param_type_spec [IDL_TYPE_* or NULL for void] + * - simple_declarations [IDL_LIST] + * - data [IDL_IDENT] + * - next [IDL_LIST or NULL if no more idents] + * - data [IDL_IDENT] + */ + +#define ATTR_IDENT(tree) (IDL_IDENT(IDL_LIST(IDL_ATTR_DCL(tree).simple_declarations).data)) +#define ATTR_TYPE_DECL(tree) (IDL_ATTR_DCL(tree).param_type_spec) +#define ATTR_TYPE(tree) (IDL_NODE_TYPE(ATTR_TYPE_DECL(tree))) + +/* + * AS_DECL writes 'NS_IMETHOD foo(string bar, long sil)' + * AS_IMPL writes 'NS_IMETHODIMP className::foo(string bar, long sil)' + * AS_CALL writes 'foo(bar, sil)' + */ +static gboolean +write_attr_accessor(IDL_tree attr_tree, FILE * outfile, + gboolean getter, int mode, const char *className) +{ + char *attrname = ATTR_IDENT(attr_tree).str; + + if (mode == AS_DECL) { + fputs("NS_IMETHOD ", outfile); + } else if (mode == AS_IMPL) { + fprintf(outfile, "NS_IMETHODIMP %s::", className); + } + fprintf(outfile, "%cet%c%s(", + getter ? 'G' : 'S', + toupper(*attrname), attrname + 1); + if (mode == AS_DECL || mode == AS_IMPL) { + /* Setters for string, wstring, nsid, domstring, utf8string, + * cstring and astring get const. + */ + if (!getter && + (IDL_NODE_TYPE(ATTR_TYPE_DECL(attr_tree)) == IDLN_TYPE_STRING || + IDL_NODE_TYPE(ATTR_TYPE_DECL(attr_tree)) == IDLN_TYPE_WIDE_STRING || + IDL_tree_property_get(ATTR_TYPE_DECL(attr_tree), "nsid") || + IDL_tree_property_get(ATTR_TYPE_DECL(attr_tree), "domstring") || + IDL_tree_property_get(ATTR_TYPE_DECL(attr_tree), "utf8string") || + IDL_tree_property_get(ATTR_TYPE_DECL(attr_tree), "cstring") || + IDL_tree_property_get(ATTR_TYPE_DECL(attr_tree), "astring"))) + { + fputs("const ", outfile); + } + + if (!write_type(ATTR_TYPE_DECL(attr_tree), getter, outfile)) + return FALSE; + fprintf(outfile, "%s%s", + (STARRED_TYPE(attr_tree) ? "" : " "), + (getter && !DIPPER_TYPE(ATTR_TYPE_DECL(attr_tree)))? "*" : ""); + } + fprintf(outfile, "a%c%s)", toupper(attrname[0]), attrname + 1); + return TRUE; +} + +static gboolean +attr_dcl(TreeState *state) +{ + GSList *doc_comments; + + if (!verify_attribute_declaration(state->tree)) + return FALSE; + + doc_comments = + IDL_IDENT(IDL_LIST(IDL_ATTR_DCL + (state->tree).simple_declarations).data).comments; + + if (doc_comments != NULL) { + write_indent(state->file); + printlist(state->file, doc_comments); + } + + /* + * XXX lists of attributes with the same type, e.g. + * attribute string foo, bar sil; + * are legal IDL... but we don't do anything with 'em. + */ + if (IDL_LIST(IDL_ATTR_DCL(state->tree).simple_declarations).next != NULL) { + XPIDL_WARNING((state->tree, IDL_WARNING1, + "multiple attributes in a single declaration aren't " + "currently supported by xpidl")); + } + + xpidl_write_comment(state, 2); + + write_indent(state->file); + if (!write_attr_accessor(state->tree, state->file, TRUE, AS_DECL, NULL)) + return FALSE; + fputs(" = 0;\n", state->file); + + if (!IDL_ATTR_DCL(state->tree).f_readonly) { + write_indent(state->file); + if (!write_attr_accessor(state->tree, state->file, FALSE, AS_DECL, NULL)) + return FALSE; + fputs(" = 0;\n", state->file); + } + fputc('\n', state->file); + + return TRUE; +} + +static gboolean +do_enum(TreeState *state) +{ + IDL_tree_error(state->tree, "enums not supported, " + "see http://bugzilla.mozilla.org/show_bug.cgi?id=8781"); + return FALSE; +} + +static gboolean +do_const_dcl(TreeState *state) +{ + struct _IDL_CONST_DCL *dcl = &IDL_CONST_DCL(state->tree); + const char *name = IDL_IDENT(dcl->ident).str; + gboolean is_signed; + GSList *doc_comments = IDL_IDENT(dcl->ident).comments; + IDL_tree real_type; + const char *const_format; + + if (!verify_const_declaration(state->tree)) + return FALSE; + + if (doc_comments != NULL) { + write_indent(state->file); + printlist(state->file, doc_comments); + } + + /* Could be a typedef; try to map it to the real type. */ + real_type = find_underlying_type(dcl->const_type); + real_type = real_type ? real_type : dcl->const_type; + is_signed = IDL_TYPE_INTEGER(real_type).f_signed; + + const_format = is_signed ? "%" IDL_LL "d" : "%" IDL_LL "uU"; + write_indent(state->file); + fprintf(state->file, "enum { %s = ", name); + fprintf(state->file, const_format, IDL_INTEGER(dcl->const_exp).value); + fprintf(state->file, " };\n\n"); + + return TRUE; +} + +static gboolean +do_typedef(TreeState *state) +{ + IDL_tree type = IDL_TYPE_DCL(state->tree).type_spec; + IDL_tree dcls = IDL_TYPE_DCL(state->tree).dcls; + IDL_tree complex; + GSList *doc_comments; + + if (IDL_NODE_TYPE(type) == IDLN_TYPE_SEQUENCE) { + XPIDL_WARNING((state->tree, IDL_WARNING1, + "sequences not supported, ignored")); + } else { + if (IDL_NODE_TYPE(complex = IDL_LIST(dcls).data) == IDLN_TYPE_ARRAY) { + IDL_tree dim = IDL_TYPE_ARRAY(complex).size_list; + doc_comments = IDL_IDENT(IDL_TYPE_ARRAY(complex).ident).comments; + + if (doc_comments != NULL) + printlist(state->file, doc_comments); + + fputs("typedef ", state->file); + if (!write_type(type, FALSE, state->file)) + return FALSE; + fputs(" ", state->file); + + fprintf(state->file, "%s", + IDL_IDENT(IDL_TYPE_ARRAY(complex).ident).str); + do { + fputc('[', state->file); + if (IDL_LIST(dim).data) { + fprintf(state->file, "%ld", + (long)IDL_INTEGER(IDL_LIST(dim).data).value); + } + fputc(']', state->file); + } while ((dim = IDL_LIST(dim).next) != NULL); + } else { + doc_comments = IDL_IDENT(IDL_LIST(dcls).data).comments; + + if (doc_comments != NULL) + printlist(state->file, doc_comments); + + fputs("typedef ", state->file); + if (!write_type(type, FALSE, state->file)) + return FALSE; + fputs(" ", state->file); + fputs(IDL_IDENT(IDL_LIST(dcls).data).str, state->file); + } + fputs(";\n\n", state->file); + } + return TRUE; +} + +/* + * param generation: + * in string foo --> nsString *foo + * out string foo --> nsString **foo; + * inout string foo --> nsString **foo; + */ + +/* If notype is true, just write the param name. */ +static gboolean +write_param(IDL_tree param_tree, FILE *outfile) +{ + IDL_tree param_type_spec = IDL_PARAM_DCL(param_tree).param_type_spec; + gboolean is_in = IDL_PARAM_DCL(param_tree).attr == IDL_PARAM_IN; + /* in string, wstring, nsid, domstring, utf8string, cstring and + * astring any explicitly marked [const] are const + */ + + if (is_in && + (IDL_NODE_TYPE(param_type_spec) == IDLN_TYPE_STRING || + IDL_NODE_TYPE(param_type_spec) == IDLN_TYPE_WIDE_STRING || + IDL_tree_property_get(IDL_PARAM_DCL(param_tree).simple_declarator, + "const") || + IDL_tree_property_get(param_type_spec, "nsid") || + IDL_tree_property_get(param_type_spec, "domstring") || + IDL_tree_property_get(param_type_spec, "utf8string") || + IDL_tree_property_get(param_type_spec, "cstring") || + IDL_tree_property_get(param_type_spec, "astring"))) { + fputs("const ", outfile); + } + else if (IDL_PARAM_DCL(param_tree).attr == IDL_PARAM_OUT && + IDL_tree_property_get(IDL_PARAM_DCL(param_tree).simple_declarator, + "shared")) { + fputs("const ", outfile); + } + + if (!write_type(param_type_spec, !is_in, outfile)) + return FALSE; + + /* unless the type ended in a *, add a space */ + if (!STARRED_TYPE(param_type_spec)) + fputc(' ', outfile); + + /* out and inout params get a bonus '*' (unless this is type that has a + * 'dipper' class that is passed in to receive 'out' data) + */ + if (IDL_PARAM_DCL(param_tree).attr != IDL_PARAM_IN && + !DIPPER_TYPE(param_type_spec)) { + fputc('*', outfile); + } + /* arrays get a bonus * too */ + /* XXX Should this be a leading '*' or a trailing "[]" ?*/ + if (IDL_tree_property_get(IDL_PARAM_DCL(param_tree).simple_declarator, + "array")) + fputc('*', outfile); + + fputs(IDL_IDENT(IDL_PARAM_DCL(param_tree).simple_declarator).str, outfile); + + return TRUE; +} + +/* + * A forward declaration, usually an interface. + */ +static gboolean +forward_dcl(TreeState *state) +{ + IDL_tree iface = state->tree; + const char *className = IDL_IDENT(IDL_FORWARD_DCL(iface).ident).str; + + if (!className) + return FALSE; + + fprintf(state->file, "class %s; /* forward declaration */\n\n", className); + return TRUE; +} + +/* + * Shared between the interface class declaration and the NS_DECL_IFOO macro + * provided to aid declaration of implementation classes. + * mode... + * AS_DECL writes 'NS_IMETHOD foo(string bar, long sil)' + * AS_IMPL writes 'NS_IMETHODIMP className::foo(string bar, long sil)' + * AS_CALL writes 'foo(bar, sil)' + */ +static gboolean +write_method_signature(IDL_tree method_tree, FILE *outfile, int mode, + const char *className) +{ + struct _IDL_OP_DCL *op = &IDL_OP_DCL(method_tree); + gboolean no_generated_args = TRUE; + gboolean op_notxpcom = + (IDL_tree_property_get(op->ident, "notxpcom") != NULL); + const char *name; + IDL_tree iter; + + if (mode == AS_DECL) { + if (op_notxpcom) { + fputs("NS_IMETHOD_(", outfile); + if (!write_type(op->op_type_spec, FALSE, outfile)) + return FALSE; + fputc(')', outfile); + } else { + fputs("NS_IMETHOD", outfile); + } + fputc(' ', outfile); + } + else if (mode == AS_IMPL) { + if (op_notxpcom) { + fputs("NS_IMETHODIMP_(", outfile); + if (!write_type(op->op_type_spec, FALSE, outfile)) + return FALSE; + fputc(')', outfile); + } else { + fputs("NS_IMETHODIMP", outfile); + } + fputc(' ', outfile); + } + name = IDL_IDENT(op->ident).str; + if (mode == AS_IMPL) { + fprintf(outfile, "%s::%c%s(", className, toupper(*name), name + 1); + } else { + fprintf(outfile, "%c%s(", toupper(*name), name + 1); + } + for (iter = op->parameter_dcls; iter; iter = IDL_LIST(iter).next) { + if (mode == AS_DECL || mode == AS_IMPL) { + if (!write_param(IDL_LIST(iter).data, outfile)) + return FALSE; + } else { + fputs(IDL_IDENT(IDL_PARAM_DCL(IDL_LIST(iter).data) + .simple_declarator).str, + outfile); + } + if ((IDL_LIST(iter).next || + (!op_notxpcom && op->op_type_spec) || op->f_varargs)) + fputs(", ", outfile); + no_generated_args = FALSE; + } + + /* make IDL return value into trailing out argument */ + if (op->op_type_spec && !op_notxpcom) { + IDL_tree fake_param = IDL_param_dcl_new(IDL_PARAM_OUT, + op->op_type_spec, + IDL_ident_new("_retval")); + if (!fake_param) + return FALSE; + if (mode == AS_DECL || mode == AS_IMPL) { + if (!write_param(fake_param, outfile)) + return FALSE; + } else { + fputs("_retval", outfile); + } + if (op->f_varargs) + fputs(", ", outfile); + no_generated_args = FALSE; + } + + /* varargs go last */ + if (op->f_varargs) { + if (mode == AS_DECL || mode == AS_IMPL) { + fputs("nsVarArgs *", outfile); + } + fputs("_varargs", outfile); + no_generated_args = FALSE; + } + + /* + * If generated method has no arguments, output 'void' to avoid C legacy + * behavior of disabling type checking. + */ + if (no_generated_args && mode == AS_DECL) { + fputs("void", outfile); + } + + fputc(')', outfile); + + return TRUE; +} + +/* + * A method is an `operation', therefore a method decl is an `op dcl'. + * I blame Elliot. + */ +static gboolean +op_dcl(TreeState *state) +{ + GSList *doc_comments = IDL_IDENT(IDL_OP_DCL(state->tree).ident).comments; + + /* + * Verify that e.g. non-scriptable methods in [scriptable] interfaces + * are declared so. Do this in a separate verification pass? + */ + if (!verify_method_declaration(state->tree)) + return FALSE; + + if (doc_comments != NULL) { + write_indent(state->file); + printlist(state->file, doc_comments); + } + xpidl_write_comment(state, 2); + + write_indent(state->file); + if (!write_method_signature(state->tree, state->file, AS_DECL, NULL)) + return FALSE; + fputs(" = 0;\n\n", state->file); + + return TRUE; +} + +static void +write_codefrag_line(gpointer data, gpointer user_data) +{ + TreeState *state = (TreeState *)user_data; + const char *line = (const char *)data; + fputs(line, state->file); + fputc('\n', state->file); +} + +static gboolean +codefrag(TreeState *state) +{ + const char *desc = IDL_CODEFRAG(state->tree).desc; + GSList *lines = IDL_CODEFRAG(state->tree).lines; + guint fragment_length; + + if (strcmp(desc, "C++") && /* libIDL bug? */ strcmp(desc, "C++\r")) { + XPIDL_WARNING((state->tree, IDL_WARNING1, + "ignoring '%%{%s' escape. " + "(Use '%%{C++' to escape verbatim C++ code.)", desc)); + + return TRUE; + } + + /* + * Emit #file directive to point debuggers back to the original .idl file + * for the duration of the code fragment. We look at internal IDL node + * properties _file, _line to do this; hopefully they won't change. + * + * _line seems to refer to the line immediately after the closing %}, so + * we backtrack to get the proper line for the beginning of the block. + */ + /* + * Looks like getting this right means maintaining an accurate line + * count of everything generated, so we can set the file back to the + * correct line in the generated file afterwards. Skipping for now... + */ + + fragment_length = g_slist_length(lines); +/* fprintf(state->file, "#line %d \"%s\"\n", */ +/* state->tree->_line - fragment_length - 1, */ +/* state->tree->_file); */ + + g_slist_foreach(lines, write_codefrag_line, (gpointer)state); + + return TRUE; +} + +backend * +xpidl_header_dispatch(void) +{ + static backend result; + static nodeHandler table[IDLN_LAST]; + static gboolean initialized = FALSE; + + result.emit_prolog = header_prolog; + result.emit_epilog = header_epilog; + + if (!initialized) { + table[IDLN_LIST] = list; + table[IDLN_ATTR_DCL] = attr_dcl; + table[IDLN_OP_DCL] = op_dcl; + table[IDLN_FORWARD_DCL] = forward_dcl; + table[IDLN_TYPE_ENUM] = do_enum; + table[IDLN_INTERFACE] = interface; + table[IDLN_CODEFRAG] = codefrag; + table[IDLN_TYPE_DCL] = do_typedef; + table[IDLN_CONST_DCL] = do_const_dcl; + table[IDLN_NATIVE] = check_native; + initialized = TRUE; + } + + result.dispatch_table = table; + return &result; +} diff --git a/src/libs/xpcom18a4/xpcom/typelib/xpidl/xpidl_idl.c b/src/libs/xpcom18a4/xpcom/typelib/xpidl/xpidl_idl.c new file mode 100644 index 00000000..175f379a --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/typelib/xpidl/xpidl_idl.c @@ -0,0 +1,836 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: NPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Netscape 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/NPL/ + * + * 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Michael Ang + * + * 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 NPL, 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 NPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * Common IDL-processing code. + */ + +#include "xpidl.h" + +#ifdef XP_MAC +#include +#endif + +static gboolean parsed_empty_file; + +/* + * The bulk of the generation happens here. + */ +gboolean +xpidl_process_node(TreeState *state) +{ + gint type; + nodeHandler *dispatch, handler; + + XPT_ASSERT(state->tree); + type = IDL_NODE_TYPE(state->tree); + + if ((dispatch = state->dispatch) && (handler = dispatch[type])) + return handler(state); + return TRUE; +} + +#if defined(XP_MAC) && defined(XPIDL_PLUGIN) +extern void mac_warning(const char* warning_message); +#endif + +static int +msg_callback(int level, int num, int line, const char *file, + const char *message) +{ + char *warning_message; + + /* + * Egregious hack to permit empty files. + * XXX libIDL needs an API to detect this case robustly. + */ + if (0 == strcmp(message, "File empty after optimization")) { + parsed_empty_file = TRUE; + return 1; + } + + if (!file) + file = ""; + warning_message = g_strdup_printf("%s:%d: %s\n", file, line, message); + +#if defined(XP_MAC) && defined(XPIDL_PLUGIN) + mac_warning(warning_message); +#else + fputs(warning_message, stderr); +#endif + + g_free(warning_message); + return 1; +} + +/* + * To keep track of the state associated with a given input file. The 'next' + * field lets us maintain a stack of input files. + */ +typedef struct input_data { + char *filename; /* where did I come from? */ + unsigned int lineno; /* last lineno processed */ + char *buf; /* contents of file */ + char *point; /* next char to feed to libIDL */ + char *max; /* 1 past last char in buf */ + struct input_data *next; /* file from which we were included */ +} input_data; + +/* + * Passed to us by libIDL. Holds global information and the current stack of + * include files. + */ +typedef struct input_callback_state { + struct input_data *input_stack; /* linked list of input_data */ + GHashTable *already_included; /* to prevent redundant includes */ + IncludePathEntry *include_path; /* search path for included files */ + GSList *base_includes; /* to accumulate #includes from *first* file; + * for passing thru TreeState to + * xpidl_header backend. */ +} input_callback_state; + +static FILE * +fopen_from_includes(const char *filename, const char *mode, + IncludePathEntry *include_path) +{ + IncludePathEntry *current_path = include_path; + char *pathname; + FILE *inputfile; + if (!strcmp(filename, "-")) + return stdin; + + if (filename[0] != '/') { + while (current_path) { + pathname = g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s", + current_path->directory, filename); + if (!pathname) + return NULL; + inputfile = fopen(pathname, mode); + g_free(pathname); + if (inputfile) + return inputfile; + current_path = current_path->next; + } + } else { + inputfile = fopen(filename, mode); + if (inputfile) + return inputfile; + } + return NULL; +} + +#if defined(XP_MAC) && defined(XPIDL_PLUGIN) +extern FILE* mac_fopen(const char* filename, const char *mode); +#endif + +static input_data * +new_input_data(const char *filename, IncludePathEntry *include_path) +{ + input_data *new_data; + FILE *inputfile; + char *buffer = NULL; + size_t offset = 0; + size_t buffer_size; +#ifdef XP_MAC + size_t i; +#endif + +#if defined(XP_MAC) && defined(XPIDL_PLUGIN) + /* on Mac, fopen knows how to find files. */ + inputfile = fopen(filename, "r"); +#elif defined(XP_OS2) || defined(XP_WIN32) + /* + * if filename is fully qualified (starts with driver letter), then + * just call fopen(); else, go with fopen_from_includes() + */ + if( filename[1] == ':' ) + inputfile = fopen(filename, "r"); + else + inputfile = fopen_from_includes(filename, "r", include_path); +#else + inputfile = fopen_from_includes(filename, "r", include_path); +#endif + + if (!inputfile) + return NULL; + +#ifdef XP_MAC + { + struct stat input_stat; + if (fstat(fileno(inputfile), &input_stat)) + return NULL; + buffer = malloc(input_stat.st_size + 1); + if (!buffer) + return NULL; + offset = fread(buffer, 1, input_stat.st_size, inputfile); + if (ferror(inputfile)) + return NULL; + } +#else + /* + * Rather than try to keep track of many different varieties of state + * around the boundaries of a circular buffer, we just read in the entire + * file. + * + * We iteratively grow the buffer here; an alternative would be to use + * stat to find the exact buffer size we need, as xpt_dump does. + */ + for (buffer_size = 8191; ; buffer_size *= 2) { + size_t just_read; + buffer = realloc(buffer, buffer_size + 1); /* +1 for trailing nul */ + just_read = fread(buffer + offset, 1, buffer_size - offset, inputfile); + if (ferror(inputfile)) + return NULL; + + if (just_read < buffer_size - offset || just_read == 0) { + /* Done reading. */ + offset += just_read; + break; + } + offset += just_read; + } +#endif + + fclose(inputfile); + +#ifdef XP_MAC + /* + * libIDL doesn't speak '\r' properly - always make sure lines end with + * '\n'. + */ + for (i = 0; i < offset; i++) { + if (buffer[i] == '\r') + buffer[i] = '\n'; + } +#endif + + new_data = xpidl_malloc(sizeof (struct input_data)); + new_data->point = new_data->buf = buffer; + new_data->max = buffer + offset; + *new_data->max = '\0'; + new_data->filename = xpidl_strdup(filename); + /* libIDL expects the line number to be that of the *next* line */ + new_data->lineno = 2; + new_data->next = NULL; + + return new_data; +} + +/* process pending raw section */ +static int +NextIsRaw(input_data *data, char **startp, int *lenp) +{ + char *end, *start; + + /* + * XXXmccabe still needed: an in_raw flag to handle the case where we're in + * a raw block, but haven't managed to copy it all to xpidl. This will + * happen when we have a raw block larger than + * IDL_input_data->fill.max_size (currently 8192.) + */ + if (!(data->point[0] == '%' && data->point[1] == '{')) + return 0; + + start = *startp = data->point; + + end = NULL; + while (start < data->max && (end = strstr(start, "%}"))) { + if (end[-1] == '\r' || + end[-1] == '\n') + break; + start = end + 1; + } + + if (end && start < data->max) { + *lenp = end - data->point + 2; + return 1; + } else { + const char *filename; + int lineno; + + IDL_file_get(&filename, &lineno); + msg_callback(IDL_ERROR, 0, lineno, filename, + "unterminated %{ block"); + return -1; + } +} + +/* process pending comment */ +static int +NextIsComment(input_data *data, char **startp, int *lenp) +{ + char *end; + + if (!(data->point[0] == '/' && data->point[1] == '*')) + return 0; + + end = strstr(data->point, "*/"); + *lenp = 0; + if (end) { + int skippedLines = 0; + char *tempPoint; + + /* get current lineno */ + IDL_file_get(NULL,(int *)&data->lineno); + + /* get line count */ + for (tempPoint = data->point; tempPoint < end; tempPoint++) { + if (*tempPoint == '\n') + skippedLines++; + } + + data->lineno += skippedLines; + IDL_file_set(data->filename, (int)data->lineno); + + *startp = end + 2; + + /* If it's a ** comment, tell libIDL about it. */ + if (data->point[2] == '*') { + /* hack termination. +2 to get past '*' '/' */ + char t = *(end + 2); + *(end + 2) = '\0'; + IDL_queue_new_ident_comment(data->point); + *(end + 2) = t; + } + + data->point = *startp; /* XXXmccabe move this out of function? */ + return 1; + } else { + const char *filename; + int lineno; + + IDL_file_get(&filename, &lineno); + msg_callback(IDL_ERROR, 0, lineno, filename, + "unterminated comment"); + return -1; + } +} + +static int +NextIsInclude(input_callback_state *callback_state, char **startp, + int *lenp) +{ + input_data *data = callback_state->input_stack; + input_data *new_data; + char *filename, *end; + const char *scratch; + + /* process the #include that we're in now */ + if (strncmp(data->point, "#include \"", 10)) { + return 0; + } + + filename = data->point + 10; /* skip #include " */ + XPT_ASSERT(filename < data->max); + end = filename; + while (end < data->max) { + if (*end == '\"' || *end == '\n' || *end == '\r') + break; + end++; + } + + if (*end != '\"') { + /* + * Didn't find end of include file. Scan 'til next whitespace to find + * some reasonable approximation of the filename, and use it to report + * an error. + */ + + end = filename; + while (end < data->max) { + if (*end == ' ' || *end == '\n' || *end == '\r' || *end == '\t') + break; + end++; + } + *end = '\0'; + + /* make sure we have accurate line info */ + IDL_file_get(&scratch, (int *)&data->lineno); + fprintf(stderr, + "%s:%u: didn't find end of quoted include name \"%s\n", + scratch, data->lineno, filename); + return -1; + } + + *end = '\0'; + *startp = end + 1; + + if (data->next == NULL) { + /* + * If we're in the initial file, add this filename to the list + * of filenames to be turned into #include "filename.h" + * directives in xpidl_header.c. We do it here rather than in the + * block below so it still gets added to the list even if it's + * already been recursively included from some other file. + */ + char *filename_cp = xpidl_strdup(filename); + + /* note that g_slist_append accepts and likes null as list-start. */ + callback_state->base_includes = + g_slist_append(callback_state->base_includes, filename_cp); + } + + /* store offset for when we pop, or if we skip this one */ + data->point = *startp; + + if (!g_hash_table_lookup(callback_state->already_included, filename)) { + filename = xpidl_strdup(filename); + g_hash_table_insert(callback_state->already_included, + filename, (void *)TRUE); + new_data = new_input_data(filename, callback_state->include_path); + if (!new_data) { + char *error_message; + IDL_file_get(&scratch, (int *)&data->lineno); + error_message = + g_strdup_printf("can't open included file %s for reading\n", + filename); + msg_callback(IDL_ERROR, 0, + data->lineno, scratch, error_message); + g_free(error_message); + return -1; + } + + new_data->next = data; + /* tell libIDL to exclude this IDL from the toplevel tree */ + IDL_inhibit_push(); + IDL_file_get(&scratch, (int *)&data->lineno); + callback_state->input_stack = new_data; + IDL_file_set(new_data->filename, (int)new_data->lineno); + } + + *lenp = 0; /* this is magic, see the comment below */ + return 1; +} + +static void +FindSpecial(input_data *data, char **startp, int *lenp) +{ + char *point = data->point; + + /* magic sequences are: + * "%{" raw block + * "/\*" comment + * "#include \"" include + * The first and last want a newline [\r\n] before, or the start of the + * file. + */ + +#define LINE_START(data, point) (point == data->buf || \ + (point > data->point && \ + (point[-1] == '\r' || point[-1] == '\n'))) + + while (point < data->max) { + if (point[0] == '/' && point[1] == '*') + break; + if (LINE_START(data, point)) { + if (point[0] == '%' && point[1] == '{') + break; + if (point[0] == '#' && !strncmp(point + 1, "include \"", 9)) + break; + } + point++; + } + +#undef LINE_START + + *startp = data->point; + *lenp = point - data->point; +} + +/* set this with a debugger to see exactly what libIDL sees */ +static FILE *tracefile; + +static int +input_callback(IDL_input_reason reason, union IDL_input_data *cb_data, + gpointer user_data) +{ + input_callback_state *callback_state = user_data; + input_data *data = callback_state->input_stack; + input_data *new_data = NULL; + unsigned int len, copy; + int rv; + char *start; + + switch(reason) { + case IDL_INPUT_REASON_INIT: + if (data == NULL || data->next == NULL) { + /* + * This is the first file being processed. As it's the target + * file, we only look for it in the first entry in the include + * path, which we assume to be the current directory. + */ + + /* XXXmccabe proper assumption? Do we handle files in other + directories? */ + + IncludePathEntry first_entry; + + first_entry.directory = callback_state->include_path->directory; + first_entry.next = NULL; + + new_data = new_input_data(cb_data->init.filename, + &first_entry); + } else { + new_data = new_input_data(cb_data->init.filename, + callback_state->include_path); + } + + if (!new_data) + return -1; + + IDL_file_set(new_data->filename, (int)new_data->lineno); + callback_state->input_stack = new_data; + return 0; + + case IDL_INPUT_REASON_FILL: + start = NULL; + len = 0; + + while (data->point >= data->max) { + if (!data->next) + return 0; + + /* Current file is done; revert to including file */ + callback_state->input_stack = data->next; + free(data->filename); + free(data->buf); + free(data); + data = callback_state->input_stack; + + IDL_file_set(data->filename, (int)data->lineno); + IDL_inhibit_pop(); + } + + /* + * Now we scan for sequences which require special attention: + * \n#include begins an include statement + * \n%{ begins a raw-source block + * /\* begins a comment + * + * We used to be fancier here, so make sure that we sent the most + * data possible at any given time. To that end, we skipped over + * \n%{ raw \n%} blocks and then _continued_ the search for special + * sequences like \n#include or /\* comments . + * + * It was really ugly, though -- liberal use of goto! lots of implicit + * state! what fun! -- so now we just do this: + * + * if (special at start) { + * process that special - + * - raw: send it to libIDL, and don't look inside for specials + * - comments: adjust point and start over + * - includes: push new input_data struct for included file, and + * start over + * } else { + * scan for next special + * send data up to that special to libIDL + * } + * + * If len is set to zero, it is a sentinel value indicating we a comment + * or include was found, and parsing should start over. + * + * XXX const string foo = "/\*" will just screw us horribly. + * Hm but. We could treat strings as we treat raw blocks, eh? + */ + + /* + * Order is important, so that you can have /\* comments and + * #includes within raw sections, and so that you can comment out + * #includes. + */ + rv = NextIsRaw(data, &start, (int *)&len); + if (rv == -1) return -1; + if (!rv) { + /* + * When NextIsComment succeeds, it returns a 0 len (requesting a + * restart) and adjusts data->point to pick up after the comment. + */ + rv = NextIsComment(data, &start, (int *)&len); + if (rv == -1) return -1; + if (!rv) { + /* + * NextIsInclude might push a new input_data struct; if so, it + * will return a 0 len, letting the callback pick up the new + * file the next time around. + */ + rv = NextIsInclude(callback_state, &start, (int *)&len); + if (rv == -1) return -1; + if (!rv) + FindSpecial(data, &start, (int *)&len); + } + } + + if (len == 0) { + /* + * len == 0 is a sentinel value that means we found a comment or + * include. If we found a comment, point has been adjusted to + * point past the comment. If we found an include, a new input_data + * has been pushed. In both cases, calling the input_callback again + * will pick up the new state. + */ + return input_callback(reason, cb_data, user_data); + } + + copy = MIN(len, (unsigned int) cb_data->fill.max_size); + memcpy(cb_data->fill.buffer, start, copy); + data->point = start + copy; + + if (tracefile) + fwrite(cb_data->fill.buffer, copy, 1, tracefile); + + return copy; + + case IDL_INPUT_REASON_ABORT: + case IDL_INPUT_REASON_FINISH: + while (data != NULL) { + input_data *next; + + next = data->next; + free(data->filename); + free(data->buf); + free(data); + data = next; + } + return 0; + + default: + g_error("unknown input reason %d!", reason); + return -1; + } +} + +static void +free_ghash_key(gpointer key, gpointer value, gpointer user_data) +{ + /* We're only storing TRUE in the value... */ + free(key); +} + +static void +free_gslist_data(gpointer data, gpointer user_data) +{ + free(data); +} + +/* Pick up unlink. */ +#ifdef XP_UNIX +#include +#elif XP_WIN +/* We get it from stdio.h. */ +#endif + +int +xpidl_process_idl(char *filename, IncludePathEntry *include_path, + char *file_basename, ModeData *mode) +{ + char *tmp, *outname, *real_outname = NULL; + IDL_tree top; + TreeState state; + int rv; + input_callback_state callback_state; + gboolean ok = TRUE; + backend *emitter; + + callback_state.input_stack = NULL; + callback_state.base_includes = NULL; + callback_state.include_path = include_path; + callback_state.already_included = g_hash_table_new(g_str_hash, g_str_equal); + + if (!callback_state.already_included) { + fprintf(stderr, "failed to create hashtable. out of memory?\n"); + return 0; + } + + state.basename = xpidl_strdup(filename); + + /* if basename has an .extension, truncate it. */ + tmp = strrchr(state.basename, '.'); + if (tmp) + *tmp = '\0'; + + if (!file_basename) + outname = xpidl_strdup(state.basename); + else + outname = xpidl_strdup(file_basename); + + /* so we don't include it again! */ + g_hash_table_insert(callback_state.already_included, + xpidl_strdup(filename), (void *)TRUE); + + parsed_empty_file = FALSE; + + rv = IDL_parse_filename_with_input(filename, input_callback, &callback_state, + msg_callback, &top, + &state.ns, + IDLF_IGNORE_FORWARDS | + IDLF_XPIDL, + enable_warnings ? IDL_WARNING1 : + IDL_ERROR); + if (parsed_empty_file) { + /* + * If we've detected (via hack in msg_callback) that libIDL returned + * failure because it found a file with no IDL, set the parse tree to + * null and proceed. Allowing this is useful to permit .idl files that + * collect #includes. + */ + top = NULL; + state.ns = NULL; + } else if (rv != IDL_SUCCESS) { + if (rv == -1) { + g_warning("Parse of %s failed: %s", filename, g_strerror(errno)); + } else { + g_warning("Parse of %s failed", filename); + } + return 0; + } + + state.basename = xpidl_strdup(filename); + tmp = strrchr(state.basename, '.'); + if (tmp) + *tmp = '\0'; + + /* so xpidl_header.c can use it to generate a list of #include directives */ + state.base_includes = callback_state.base_includes; + + emitter = mode->factory(); + state.dispatch = emitter->dispatch_table; + + if (strcmp(outname, "-")) { + const char *fopen_mode; + char *out_basename; + + /* explicit_output_filename can't be true without a filename */ + if (explicit_output_filename) { + real_outname = g_strdup(outname); + } else { +/* + *This combination seems a little strange, what about OS/2? + * Assume it's some build issue + */ +#if defined(XP_UNIX) || defined(XP_WIN) + if (!file_basename) { + out_basename = xpidl_basename(outname); + } else { + out_basename = outname; + } +#else + out_basename = outname; +#endif + real_outname = g_strdup_printf("%s.%s", out_basename, mode->suffix); + if (out_basename != outname) + g_free(out_basename); + } + + /* Use binary write for typelib mode */ + fopen_mode = (strcmp(mode->mode, "typelib")) ? "w" : "wb"; + state.file = fopen(real_outname, fopen_mode); + if (!state.file) { + perror("error opening output file"); + return 0; + } + } else { + state.file = stdout; + } + state.tree = top; +#ifdef VBOX_XPIDL_EMULATE_GENJIFACES + state.real_outname = real_outname; +#endif + + if (emitter->emit_prolog) + emitter->emit_prolog(&state); + if (state.tree) /* Only if we have a tree to process. */ + ok = xpidl_process_node(&state); + if (emitter->emit_epilog) + emitter->emit_epilog(&state); + + if (state.file != stdout) + fclose(state.file); + free(state.basename); + free(outname); + g_hash_table_foreach(callback_state.already_included, free_ghash_key, NULL); + g_hash_table_destroy(callback_state.already_included); + g_slist_foreach(callback_state.base_includes, free_gslist_data, NULL); + + if (state.ns) + IDL_ns_free(state.ns); + if (top) + IDL_tree_free(top); + + if (real_outname != NULL) { + /* + * Delete partial output file on failure. (Mac does this in the plugin + * driver code, if the compiler returns failure.) + */ +#if defined(XP_UNIX) || defined(XP_WIN) + if (!ok) + unlink(real_outname); +#endif + g_free(real_outname); + } + + return ok; +} + +/* + * Our own version of IDL_tree_warning, which we use when IDL_tree_warning + * would crash on us. + */ +void +xpidl_tree_warning(IDL_tree p, int level, const char *fmt, ...) +{ + va_list ap; + char *msg, *file; + int lineno; + + /* XXX need to check against __IDL_max_msg_level, no accessor */ + va_start(ap, fmt); + msg = g_strdup_vprintf(fmt, ap); + + if (p) { + file = p->_file; + lineno = p->_line; + } else { + file = NULL; + lineno = 0; + } + + /* call our message callback, like IDL_tree_warning would */ + msg_callback(level, 0, lineno, file, msg); + g_free(msg); + va_end(ap); +} diff --git a/src/libs/xpcom18a4/xpcom/typelib/xpidl/xpidl_java.c b/src/libs/xpcom18a4/xpcom/typelib/xpidl/xpidl_java.c new file mode 100644 index 00000000..4f708027 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/typelib/xpidl/xpidl_java.c @@ -0,0 +1,1053 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * 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.org code. + * + * The Initial Developer of the Original Code is Sun Microsystems, + * Inc. Portions created by Sun are + * Copyright (C) 1999 Sun Microsystems, Inc. All + * Rights Reserved. + * + * Contributor(s): + * Michael Allen (michael.allen@sun.com) + * Frank Mitchell (frank.mitchell@sun.com) + */ + +/* + * Generate Java interfaces from XPIDL. + */ + +#include "xpidl.h" +#include +#include + + +struct java_priv_data { + GHashTable *typedefTable; +}; + +#define TYPEDEFS(state) (((struct java_priv_data *)state->priv)->typedefTable) + +static gboolean +write_classname_iid_define(FILE *file, const char *className) +{ + const char *iidName; + if (className[0] == 'n' && className[1] == 's') { + /* backcompat naming styles */ + fputs("NS_", file); + iidName = className + 2; + } else { + iidName = className; + } + + while (*iidName) { + fputc(toupper(*iidName++), file); + } + + fputs("_IID", file); + return TRUE; +} + +static gboolean +java_prolog(TreeState *state) +{ +#ifdef VBOX_XPIDL_EMULATE_GENJIFACES_DIFF + const char *basename; + const char *ext; +#endif + + state->priv = calloc(1, sizeof(struct java_priv_data)); + if (!state->priv) + return FALSE; + TYPEDEFS(state) = 0; + TYPEDEFS(state) = g_hash_table_new(g_str_hash, g_str_equal); + if (!TYPEDEFS(state)) { + /* XXX report error */ + free(state->priv); + return FALSE; + } + + /* + * First pass + */ + +#ifdef VBOX_XPIDL_EMULATE_GENJIFACES_DIFF + basename = xpidl_basename(state->real_outname ? state->real_outname : state->basename); + ext = strrchr(basename, '.'); + if (!ext) + ext = strchr(basename, '\0'); + fprintf(state->file, + "/**\n" + " * NOTE: THIS IS A GENERATED FILE. PLEASE CONSULT THE ORIGINAL IDL FILE\n" + " * FOR THE FULL DOCUMENTATION AND LICENSE.\n" + " *\n" + " * @see \n" + " **/\n" + "\n" + "package org.mozilla.interfaces;\n\n" + "import java.math.BigInteger;\n\n" + "\n" + , ext - basename >= 19 ? 19 : (int)(ext - basename), basename); + g_free(basename); +#else + fputs("/*\n * ************* DO NOT EDIT THIS FILE ***********\n", + state->file); + + fprintf(state->file, + " *\n * This file was automatically generated from %s.idl.\n", + state->basename); + + fputs(" */\n\n", state->file); +#endif + + return TRUE; +} + +static gboolean +java_epilog(TreeState *state) +{ + /* points to other elements of the tree, so just destroy the table */ + g_hash_table_destroy(TYPEDEFS(state)); + free(state->priv); + state->priv = NULL; + +#ifndef VBOX_XPIDL_EMULATE_GENJIFACES_DIFF + /* + * Last pass + */ + + fprintf(state->file, "\n/*\n * end\n */\n"); +#endif + + return TRUE; +} + +static gboolean +forward_declaration(TreeState *state) +{ + /* + * Java doesn't need forward declarations unless the declared + * class resides in a different package. + */ +#if 0 + IDL_tree iface = state->tree; + const char *className = IDL_IDENT(IDL_FORWARD_DCL(iface).ident).str; + const char *pkgName = "org.mozilla.xpcom"; + if (!className) + return FALSE; + /* XXX: Get package name and compare */ + fprintf(state->file, "import %s.%s;\n", pkgName, className); +#endif + return TRUE; +} + + +static gboolean +interface_declaration(TreeState *state) +{ + IDL_tree interface = state->tree; + IDL_tree iterator = NULL; + char *interface_name = IDL_IDENT(IDL_INTERFACE(interface).ident).str; + const char *iid = NULL; + + if (!verify_interface_declaration(interface)) + return FALSE; +#ifndef VBOX_XPIDL_EMULATE_GENJIFACES_DIFF + /* + * Write out JavaDoc comment + */ + + fprintf(state->file, "\n/**\n * Interface %s\n", interface_name); +#endif + +#ifndef LIBIDL_MAJOR_VERSION + iid = IDL_tree_property_get(interface, "uuid"); +#else + iid = IDL_tree_property_get(IDL_INTERFACE(interface).ident, "uuid"); +#endif + +#ifndef VBOX_XPIDL_EMULATE_GENJIFACES_DIFF + if (iid != NULL) { + fprintf(state->file, " *\n * IID: 0x%s\n */\n\n", iid); + } else { + fputs(" */\n\n", state->file); + } +#endif + + /* + * Write "public interface " + */ + + fprintf(state->file, "public interface %s ", interface_name); + + /* + * Check for inheritence, and iterator over the inherited names, + * if any. + */ + + if ((iterator = IDL_INTERFACE(interface).inheritance_spec)) { + fputs("extends ", state->file); + + do { + + fprintf(state->file, "%s", + IDL_IDENT(IDL_LIST(iterator).data).str); + + if (IDL_LIST(iterator).next) { + fputs(", ", state->file); + } + } while ((iterator = IDL_LIST(iterator).next)); + + } + + fputs("\n{\n", state->file); + + if (iid) { + /* + * Write interface constants for IID + */ + +#ifdef VBOX_XPIDL_EMULATE_GENJIFACES_DIFF + fputs(" public static final String ", state->file); +#else + fputs(" public static final String ", state->file); +#endif + + /* XXX s.b just "IID" ? */ + if (!write_classname_iid_define(state->file, interface_name)) { + return FALSE; + } + +#ifdef VBOX_XPIDL_EMULATE_GENJIFACES + fputs(" =\n \"{", state->file); + while (*iid) { + fputc(tolower(*iid++), state->file); + } + fputs("}\";\n", state->file); + +#else + fprintf(state->file, "_STRING =\n \"%s\";\n\n", iid); + + fputs(" public static final nsID ", state->file); + + /* XXX s.b just "IID" ? */ + if (!write_classname_iid_define(state->file, interface_name)) { + return FALSE; + } + + fprintf(state->file, " =\n new nsID(\"%s\");\n\n", iid); +#endif + } + + /* + * Advance the state of the tree, go on to process more + */ + + state->tree = IDL_INTERFACE(interface).body; + + if (state->tree && !xpidl_process_node(state)) { + return FALSE; + } + + + fputs("\n}\n", state->file); + + return TRUE; +} + +static gboolean +process_list(TreeState *state) +{ +#ifdef VBOX_XPIDL_EMULATE_GENJIFACES_DIFF + /* To make the diffing simple, group the constants, methods and attributes. */ + IDL_tree list = state->tree; + IDL_tree iter; + for (iter = list; iter; iter = IDL_LIST(iter).next) { + if (IDL_NODE_TYPE(IDL_LIST(iter).data) == IDLN_CONST_DCL) { + state->tree = IDL_LIST(iter).data; + if (!xpidl_process_node(state)) + return FALSE; + } + } + for (iter = list; iter; iter = IDL_LIST(iter).next) { + if (IDL_NODE_TYPE(IDL_LIST(iter).data) == IDLN_ATTR_DCL) { + state->tree = IDL_LIST(iter).data; + if (!xpidl_process_node(state)) + return FALSE; + } + } + for (iter = list; iter; iter = IDL_LIST(iter).next) { + if (IDL_NODE_TYPE(IDL_LIST(iter).data) == IDLN_OP_DCL) { + state->tree = IDL_LIST(iter).data; + if (!xpidl_process_node(state)) + return FALSE; + } + } + for (iter = list; iter; iter = IDL_LIST(iter).next) { + if ( IDL_NODE_TYPE(IDL_LIST(iter).data) != IDLN_CONST_DCL + && IDL_NODE_TYPE(IDL_LIST(iter).data) != IDLN_OP_DCL + && IDL_NODE_TYPE(IDL_LIST(iter).data) != IDLN_ATTR_DCL ) { + state->tree = IDL_LIST(iter).data; + if (!xpidl_process_node(state)) + return FALSE; + } + } + +#else + IDL_tree iter; + for (iter = state->tree; iter; iter = IDL_LIST(iter).next) { + state->tree = IDL_LIST(iter).data; + if (!xpidl_process_node(state)) + return FALSE; + } +#endif + return TRUE; +} + +#ifdef VBOX_XPIDL_EMULATE_GENJIFACES +static gboolean +interface_declaration_wrapper(TreeState *state) +{ + IDL_tree interface = state->tree; + char *interface_name = IDL_IDENT(IDL_INTERFACE(interface).ident).str; + FILE *org_file = state->file; + char *org_name = state->real_outname; + void *org_priv = state->priv; + gboolean rc; + + /* + * Skip non-scriptable interfaces. + */ + if ( !IDL_tree_property_get(IDL_INTERFACE(interface).ident, "scriptable") + && strcmp(interface_name, "nsIAppShell") ) + return TRUE; + + /* + * GROSS HACK: If the interface isn't the same as the file name, + * temporarily switch output file. + */ + if (state->real_outname) { + const char *basename = xpidl_basename(state->real_outname); + const char *ext = strrchr(basename, '.'); + if ( ext + && !strcmp(ext, ".java") + && ( strncmp(interface_name, basename, ext - basename) + || interface_name[ext - basename] != '.') ) { + size_t needed = strlen(state->real_outname) + strlen(interface_name) + strlen(".java") + 4; + char *tmp = malloc(needed); + if (basename != state->real_outname) + sprintf(tmp,"%.*s/%s.java", (int)(basename - state->real_outname - 1), state->real_outname, interface_name); + else + sprintf(tmp,"%s.java", interface_name); + state->file = fopen(tmp, "w"); + if (!state->file) { + perror("error opening output file"); + state->file = org_file; + free(tmp); + return FALSE; + } + state->real_outname = tmp; + java_prolog(state); + } + g_free(basename); + } + + rc = interface_declaration(state); + + if (state->file != org_file) { + java_epilog(state); + fclose(state->file); + free(state->real_outname); + state->file = org_file; + state->real_outname = org_name; + state->priv = org_priv; + } + return rc; +} +#endif /* VBOX_XPIDL_EMULATE_GENJIFACES */ + +static gboolean +xpcom_to_java_type (TreeState *state) +{ + if (!state->tree) { + fputs("Object", state->file); + return TRUE; + } + + switch(IDL_NODE_TYPE(state->tree)) { + + case IDLN_TYPE_INTEGER: { + + switch(IDL_TYPE_INTEGER(state->tree).f_type) { + + case IDL_INTEGER_TYPE_SHORT: +#ifdef VBOX_XPIDL_EMULATE_GENJIFACES + if (IDL_TYPE_INTEGER(state->tree).f_signed) + fputs("short", state->file); + else + fputs("int", state->file); +#else + fputs("short", state->file); +#endif + break; + + case IDL_INTEGER_TYPE_LONG: +#ifdef VBOX_XPIDL_EMULATE_GENJIFACES + if (IDL_TYPE_INTEGER(state->tree).f_signed) + fputs("int", state->file); + else + fputs("long", state->file); +#else + fputs("int", state->file); +#endif + break; + + case IDL_INTEGER_TYPE_LONGLONG: +#ifdef VBOX_XPIDL_EMULATE_GENJIFACES + if (IDL_TYPE_INTEGER(state->tree).f_signed) + fputs("long", state->file); + else + fputs("double", state->file); +#else + fputs("long", state->file); +#endif + break; + + default: + g_error(" Unknown integer type: %d\n", + IDL_TYPE_INTEGER(state->tree).f_type); + return FALSE; + + } + + break; + } + + case IDLN_TYPE_CHAR: + case IDLN_TYPE_WIDE_CHAR: + fputs("char", state->file); + break; + + case IDLN_TYPE_WIDE_STRING: + case IDLN_TYPE_STRING: + fputs("String", state->file); + break; + + case IDLN_TYPE_BOOLEAN: + fputs("boolean", state->file); + break; + + case IDLN_TYPE_OCTET: +#ifdef VBOX_XPIDL_EMULATE_GENJIFACES + fputs("short", state->file); +#else + fputs("byte", state->file); +#endif + break; + + case IDLN_TYPE_FLOAT: + switch(IDL_TYPE_FLOAT(state->tree).f_type) { + + case IDL_FLOAT_TYPE_FLOAT: + fputs("float", state->file); + break; + + case IDL_FLOAT_TYPE_DOUBLE: + fputs("double", state->file); + break; + + default: + g_error(" Unknown floating point typ: %d\n", + IDL_NODE_TYPE(state->tree)); + break; + } + break; + + + case IDLN_IDENT: + if (IDL_NODE_UP(state->tree) && + IDL_NODE_TYPE(IDL_NODE_UP(state->tree)) == IDLN_NATIVE) { + const char *user_type = IDL_NATIVE(IDL_NODE_UP(state->tree)).user_type; + if (strcmp(user_type, "void") == 0) { +#ifdef VBOX_XPIDL_EMULATE_GENJIFACES + fputs("nsISupports", state->file); +#else + fputs("Object", state->file); +#endif + } + else if (strcmp(user_type, "nsID") == 0 || + strcmp(user_type, "nsIID") == 0 || + strcmp(user_type, "nsCID") == 0) { + /* XXX: s.b test for "iid" attribute */ + /* XXX: special class for nsIDs */ +#ifdef VBOX_XPIDL_EMULATE_GENJIFACES + fputs("String", state->file); +#else + fputs("nsID", state->file); +#endif + } + else { + /* XXX: special class for opaque types */ +#ifdef VBOX_XPIDL_EMULATE_GENJIFACES + fputs("String", state->file); +#else + fputs("OpaqueValue", state->file); +#endif + } + } else { + const char *ident_str = IDL_IDENT(state->tree).str; + + /* XXX: big kludge; s.b. way to match to typedefs */ +#ifdef VBOX_XPIDL_EMULATE_GENJIFACES + if (strcmp(ident_str, "PRInt8") == 0) { + fputs("byte", state->file); + } + else if (strcmp(ident_str, "PRInt16") == 0 || + strcmp(ident_str, "PRUint8") == 0) { + fputs("short", state->file); + } + else if (strcmp(ident_str, "PRInt32") == 0 || + strcmp(ident_str, "PRUint16") == 0) { + fputs("int", state->file); + } + else if (strcmp(ident_str, "PRInt64") == 0 || + strcmp(ident_str, "PRUint32") == 0 || + strcmp(ident_str, "PRThreadPriority") == 0 || + strcmp(ident_str, "PRThreadScope") == 0 || + strcmp(ident_str, "PRThreadState") == 0) { + fputs("long", state->file); + } + else if (strcmp(ident_str, "PRUint64") == 0) { + fputs("double", state->file); + } +#else + if (strcmp(ident_str, "PRInt8") == 0 || + strcmp(ident_str, "PRUint8") == 0) { + fputs("byte", state->file); + } + else if (strcmp(ident_str, "PRInt16") == 0 || + strcmp(ident_str, "PRUint16") == 0) { + fputs("short", state->file); + } + else if (strcmp(ident_str, "PRInt32") == 0 || + strcmp(ident_str, "PRUint32") == 0) { + fputs("int", state->file); + } + else if (strcmp(ident_str, "PRInt64") == 0 || + strcmp(ident_str, "PRUint64") == 0) { + fputs("long", state->file); + } +#endif + else if (strcmp(ident_str, "PRBool") == 0) { + fputs("boolean", state->file); + } + else if (strcmp(ident_str, "nsrefcnt") == 0) { + fputs("int", state->file); + } +#ifdef VBOX_XPIDL_EMULATE_GENJIFACES + /* XXX: Use find_underlying_type instead? */ + else if ( strcmp(ident_str, "nsresult") == 0 + || strcmp(ident_str, "size_t") == 0) { + fputs("long", state->file); + } + else if ( strcmp(ident_str, "PRTime") == 0) { + fputs("double", state->file); + } + /* In Javaconnect, we handle weak references internally; no need for the + |nsIWeakReference| interface. So just return |nsISupports|. */ + else if (strcmp(ident_str, "nsIWeakReference") == 0) { + fputs("nsISupports", state->file); + } +#endif + else { + IDL_tree real_type = + g_hash_table_lookup(TYPEDEFS(state), ident_str); + + if (real_type) { + IDL_tree orig_tree = state->tree; + + state->tree = real_type; + xpcom_to_java_type(state); + + state->tree = orig_tree; + } + else { + fputs(ident_str, state->file); + } + } + } + + break; + + case IDLN_TYPE_ENUM: + case IDLN_TYPE_OBJECT: + default: + g_error(" Unknown type: %d\n", + IDL_TYPE_FLOAT(state->tree).f_type); + break; + } + + return TRUE; + +} + +static gboolean +#ifdef VBOX_XPIDL_EMULATE_GENJIFACES_DIFF +xpcom_to_java_param(TreeState *state, unsigned nparam) +#else +xpcom_to_java_param(TreeState *state) +#endif +{ + IDL_tree param = state->tree; + state->tree = IDL_PARAM_DCL(param).param_type_spec; + + /* + * Put in type of parameter + */ + + if (!xpcom_to_java_type(state)) { + return FALSE; + } + + /* + * If the parameter is out or inout, make it a Java array of the + * appropriate type + */ + +#ifdef VBOX_XPIDL_EMULATE_GENJIFACES + /* XXX: Causes nsILineInputStream::readLine(String[] arg1) where genjifaces drops the []. */ +#endif + if (IDL_PARAM_DCL(param).attr != IDL_PARAM_IN) { + fputs("[]", state->file); + } +#ifdef VBOX_XPIDL_EMULATE_GENJIFACES + /*XXX: nsIConsoleService::getMessageArray ends up with [][] arg1... */ + /*else*/ if (IDL_tree_property_get(IDL_PARAM_DCL(param).simple_declarator, "array")) { + fputs("[]", state->file); + } +#endif + + /* + * Put in name of parameter + */ + + fputc(' ', state->file); + +#ifdef VBOX_XPIDL_EMULATE_GENJIFACES_DIFF + fprintf(state->file, "arg%u", nparam+1); +#else + fputs(IDL_IDENT(IDL_PARAM_DCL(param).simple_declarator).str, state->file); +#endif + + return TRUE; +} + +#ifdef VBOX_XPIDL_EMULATE_GENJIFACES +static gboolean is_java_keyword(char ch0, const char *name) +{ + static const char * const kJavaKeywords[] = { + "abstract", "default", "if" , "private" , "this" , + "boolean" , "do" , "implements", "protected" , "throw" , + "break" , "double" , "import", "public" , "throws" , + "byte" , "else" , "instanceof", "return" , "transient", + "case" , "extends", "int" , "short" , "try" , + "catch" , "final" , "interface" , "static" , "void" , + "char" , "finally", "long" , "strictfp" , "volatile" , + "class" , "float" , "native" , "super" , "while" , + "const" , "for" , "new" , "switch" , + "continue", "goto" , "package" , "synchronized", + "assert" , /* added in Java 1.4 */ + "enum" , /* added in Java 5.0 */ + "clone" , /* clone is a member function of java.lang.Object */ + "finalize" /* finalize is a member function of java.lang.Object */ + }; + unsigned i; + for (i = 0; i < sizeof(kJavaKeywords) / sizeof(kJavaKeywords[0]); i++) { + if (kJavaKeywords[i][0] == ch0 && !strcmp(&kJavaKeywords[i][1], &name[1])) { + return TRUE; + } + } + return FALSE; +} +#endif + +static gboolean +type_declaration(TreeState *state) +{ + /* + * Unlike C, Java has no type declaration directive. + * Instead, we record the mapping, and look up the actual type + * when needed. + */ + IDL_tree type = IDL_TYPE_DCL(state->tree).type_spec; + IDL_tree dcls = IDL_TYPE_DCL(state->tree).dcls; + + /* XXX: check for illegal types */ + + g_hash_table_insert(TYPEDEFS(state), + IDL_IDENT(IDL_LIST(dcls).data).str, + type); + + return TRUE; +} + +static gboolean +method_declaration(TreeState *state) +{ + /* IDL_tree method_tree = state->tree; */ + struct _IDL_OP_DCL *method = &IDL_OP_DCL(state->tree); + gboolean method_notxpcom = + (IDL_tree_property_get(method->ident, "notxpcom") != NULL); + gboolean method_noscript = + (IDL_tree_property_get(method->ident, "noscript") != NULL); + IDL_tree iterator = NULL; + IDL_tree retval_param = NULL; + const char *method_name = IDL_IDENT(method->ident).str; +#ifdef VBOX_XPIDL_EMULATE_GENJIFACES_DIFF + unsigned nparam = 0; +#endif + + if (!verify_method_declaration(state->tree)) + return FALSE; + +#ifdef VBOX_XPIDL_EMULATE_GENJIFACES + /* + * Skip most (todo) non-scriptable and not-xpcom methods. + */ + if (method_noscript || method_notxpcom) { + return TRUE; + } +#endif + + fputc('\n', state->file); +#ifndef VBOX_XPIDL_EMULATE_GENJIFACES_DIFF + xpidl_write_comment(state, 4); +#endif + + /* + * Write beginning of method declaration + */ +#ifdef VBOX_XPIDL_EMULATE_GENJIFACES_DIFF + fputs(" ", state->file); +#else + fputs(" ", state->file); +#endif + if (!method_noscript) { + /* Nonscriptable methods become package-protected */ + fputs("public ", state->file); + } + + /* + * Write return type + * Unlike C++ headers, Java interfaces return the declared + * return value; an exception indicates XPCOM method failure. + */ + if (method_notxpcom || method->op_type_spec) { + state->tree = method->op_type_spec; + if (!xpcom_to_java_type(state)) { + return FALSE; + } + } else { + /* Check for retval attribute */ + for (iterator = method->parameter_dcls; iterator != NULL; + iterator = IDL_LIST(iterator).next) { + + IDL_tree original_tree = state->tree; + + state->tree = IDL_LIST(iterator).data; + + if (IDL_tree_property_get(IDL_PARAM_DCL(state->tree).simple_declarator, + "retval")) { + retval_param = iterator; + + state->tree = IDL_PARAM_DCL(state->tree).param_type_spec; + + /* + * Put in type of parameter + */ + + if (!xpcom_to_java_type(state)) { + return FALSE; + } +#ifdef VBOX_XPIDL_EMULATE_GENJIFACES + if (IDL_tree_property_get(IDL_PARAM_DCL(IDL_LIST(iterator).data).simple_declarator, "array")) { + fputs("[]", state->file); + } +#endif + } + + state->tree = original_tree; + } + + if (retval_param == NULL) { + fputs("void", state->file); + } + } + + /* + * Write method name + */ +#ifdef VBOX_XPIDL_EMULATE_GENJIFACES + if (is_java_keyword(tolower(method_name[0]), method_name)) { + fprintf(state->file, " %c%s_(", tolower(method_name[0]), method_name + 1); + } else { + fprintf(state->file, " %c%s(", tolower(method_name[0]), method_name + 1); + } +#else + fprintf(state->file, " %c%s(", tolower(method_name[0]), method_name + 1); +#endif + + /* + * Write parameters + */ + for (iterator = method->parameter_dcls; iterator != NULL; + iterator = IDL_LIST(iterator).next) { + + /* Skip "retval" */ + if (iterator == retval_param) { + continue; + } + + if (iterator != method->parameter_dcls) { + fputs(", ", state->file); + } + + state->tree = IDL_LIST(iterator).data; + +#ifdef VBOX_XPIDL_EMULATE_GENJIFACES_DIFF + if (!xpcom_to_java_param(state, nparam++)) { +#else + if (!xpcom_to_java_param(state)) { +#endif + return FALSE; + } + } + + fputs(")", state->file); + + if (method->raises_expr) { + IDL_tree iter = method->raises_expr; + IDL_tree dataNode = IDL_LIST(iter).data; + + fputs(" throws ", state->file); + fputs(IDL_IDENT(dataNode).str, state->file); + iter = IDL_LIST(iter).next; + + while (iter) { + dataNode = IDL_LIST(iter).data; + fprintf(state->file, ", %s", IDL_IDENT(dataNode).str); + iter = IDL_LIST(iter).next; + } + } + + fputs(";\n", state->file); + + return TRUE; + +} + + +static gboolean +constant_declaration(TreeState *state) +{ + struct _IDL_CONST_DCL *declaration = &IDL_CONST_DCL(state->tree); + const char *name = IDL_IDENT(declaration->ident).str; + IDL_tree real_type; + + if (!verify_const_declaration(state->tree)) + return FALSE; + + /* Could be a typedef; try to map it to the real type. */ + real_type = find_underlying_type(declaration->const_type); + real_type = real_type ? real_type : declaration->const_type; + + fputc('\n', state->file); +#ifndef VBOX_XPIDL_EMULATE_GENJIFACES_DIFF + xpidl_write_comment(state, 4); +#endif + +#ifdef VBOX_XPIDL_EMULATE_GENJIFACES +# ifdef VBOX_XPIDL_EMULATE_GENJIFACES_DIFF + fputs(" public static final ", state->file); +# else + fputs(" public static final ", state->file); +# endif + if (IDL_TYPE_INTEGER(real_type).f_type == IDL_INTEGER_TYPE_LONG) { + if (IDL_TYPE_INTEGER(real_type).f_signed) + fprintf(state->file, "int %s = %" IDL_LL "d;\n", name, IDL_INTEGER(declaration->const_exp).value); + else + fprintf(state->file, "long %s = %" IDL_LL "uL;\n", name, IDL_INTEGER(declaration->const_exp).value); + } else { + if (IDL_TYPE_INTEGER(real_type).f_signed) + fprintf(state->file, "short %s = %" IDL_LL "d;\n", name, IDL_INTEGER(declaration->const_exp).value); + else + fprintf(state->file, "int %s = %" IDL_LL "u;\n", name, IDL_INTEGER(declaration->const_exp).value); + } +#else /* !VBOX_XPIDL_EMULATE_GENJIFACES */ + fprintf(state->file, " public static final %s %s = %d;\n", + (IDL_TYPE_INTEGER(real_type).f_type == IDL_INTEGER_TYPE_LONG + ? "long" : "short"), + name, (int) IDL_INTEGER(declaration->const_exp).value); +#endif /* !VBOX_XPIDL_EMULATE_GENJIFACES */ + + return TRUE; + +} + +#define ATTR_IDENT(tree) (IDL_IDENT(IDL_LIST(IDL_ATTR_DCL((tree)).simple_declarations).data)) +#define ATTR_PROPS(tree) (IDL_LIST(IDL_ATTR_DCL((tree)).simple_declarations).data) +#define ATTR_TYPE_DECL(tree) (IDL_ATTR_DCL((tree)).param_type_spec) + + +static gboolean +attribute_declaration(TreeState *state) +{ + gboolean read_only = IDL_ATTR_DCL(state->tree).f_readonly; + char *attribute_name = ATTR_IDENT(state->tree).str; + + gboolean method_noscript = + (IDL_tree_property_get(ATTR_PROPS(state->tree), "noscript") != NULL); + +#ifdef VBOX_XPIDL_EMULATE_GENJIFACES + /* + * Skip most non-scriptable attributes. + */ + if (method_noscript) { + return TRUE; + } +#endif + +#if 0 + /* + * Disabled here because I can't verify this check against possible + * users of the java xpidl backend. + */ + if (!verify_attribute_declaration(state->tree)) + return FALSE; +#endif + + /* Comment */ + fputc('\n', state->file); +#ifndef VBOX_XPIDL_EMULATE_GENJIFACES_DIFF + xpidl_write_comment(state, 4); +#endif + + state->tree = ATTR_TYPE_DECL(state->tree); + + /* + * Write access permission ("public" unless nonscriptable) + */ +#ifdef VBOX_XPIDL_EMULATE_GENJIFACES_DIFF + fputs(" ", state->file); +#else + fputs(" ", state->file); +#endif + if (!method_noscript) { + fputs("public ", state->file); + } + + /* + * Write the proper Java return value for the get operation + */ + if (!xpcom_to_java_type(state)) { + return FALSE; + } + + /* + * Write the name of the accessor ("get") method. + */ + fprintf(state->file, " get%c%s();\n", + toupper(attribute_name[0]), attribute_name + 1); + + + if (!read_only) { + /* Nonscriptable methods become package-protected */ +#ifdef VBOX_XPIDL_EMULATE_GENJIFACES_DIFF + fputs("\n ", state->file); +#else + fputs(" ", state->file); +#endif + if (!method_noscript) { + fputs("public ", state->file); + } + + /* + * Write attribute access method name and return type + */ + fprintf(state->file, "void set%c%s(", + toupper(attribute_name[0]), + attribute_name+1); + + /* + * Write the proper Java type for the set operation + */ + if (!xpcom_to_java_type(state)) { + return FALSE; + } + + /* + * Write the name of the formal parameter. + */ +#ifdef VBOX_XPIDL_EMULATE_GENJIFACES_DIFF + fputs(" arg1);\n", state->file); +#else + fputs(" value);\n", state->file); +#endif + } + + return TRUE; +} + + +static gboolean +enum_declaration(TreeState *state) +{ + XPIDL_WARNING((state->tree, IDL_WARNING1, + "enums not supported, enum \'%s\' ignored", + IDL_IDENT(IDL_TYPE_ENUM(state->tree).ident).str)); + return TRUE; +} + +backend * +xpidl_java_dispatch(void) +{ + static backend result; + static nodeHandler table[IDLN_LAST]; + static gboolean initialized = FALSE; + + result.emit_prolog = java_prolog; + result.emit_epilog = java_epilog; + + if (!initialized) { +#ifdef VBOX_XPIDL_EMULATE_GENJIFACES + table[IDLN_INTERFACE] = interface_declaration_wrapper; +#else + table[IDLN_INTERFACE] = interface_declaration; +#endif + table[IDLN_LIST] = process_list; + + table[IDLN_OP_DCL] = method_declaration; + table[IDLN_ATTR_DCL] = attribute_declaration; + table[IDLN_CONST_DCL] = constant_declaration; + + table[IDLN_TYPE_DCL] = type_declaration; + table[IDLN_FORWARD_DCL] = forward_declaration; + + table[IDLN_TYPE_ENUM] = enum_declaration; + + initialized = TRUE; + } + + result.dispatch_table = table; + return &result; +} + diff --git a/src/libs/xpcom18a4/xpcom/typelib/xpidl/xpidl_typelib.c b/src/libs/xpcom18a4/xpcom/typelib/xpidl/xpidl_typelib.c new file mode 100644 index 00000000..f2daae0d --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/typelib/xpidl/xpidl_typelib.c @@ -0,0 +1,1237 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: NPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Netscape 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/NPL/ + * + * 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * 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 NPL, 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 NPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * Generate typelib files for use with InterfaceInfo. + * http://www.mozilla.org/scriptable/typelib_file.html + */ + +#include "xpidl.h" +#include +#include +#include /* XXX XP? */ + +struct priv_data { + XPTHeader *header; + uint16 ifaces; + GHashTable *interface_map; + XPTInterfaceDescriptor *current; + XPTArena *arena; + uint16 next_method; + uint16 next_const; + uint16 next_type; /* used for 'additional_types' for idl arrays */ +}; + +#define HEADER(state) (((struct priv_data *)state->priv)->header) +#define IFACES(state) (((struct priv_data *)state->priv)->ifaces) +#define IFACE_MAP(state) (((struct priv_data *)state->priv)->interface_map) +#define CURRENT(state) (((struct priv_data *)state->priv)->current) +#define ARENA(state) (((struct priv_data *)state->priv)->arena) +#define NEXT_METH(state) (((struct priv_data *)state->priv)->next_method) +#define NEXT_CONST(state) (((struct priv_data *)state->priv)->next_const) +#define NEXT_TYPE(state) (((struct priv_data *)state->priv)->next_type) + +#ifdef DEBUG_shaver +/* #define DEBUG_shaver_sort */ +#endif + +typedef struct { + char *full_name; + char *name; + char *name_space; + char *iid; + gboolean is_forward_dcl; +} NewInterfaceHolder; + +static NewInterfaceHolder* +CreateNewInterfaceHolder(char *name, char *name_space, char *iid, + gboolean is_forward_dcl) +{ + NewInterfaceHolder *holder = calloc(1, sizeof(NewInterfaceHolder)); + if (holder) { + holder->is_forward_dcl = is_forward_dcl; + if (name) + holder->name = xpidl_strdup(name); + if (name_space) + holder->name_space = xpidl_strdup(name_space); + if (holder->name && holder->name_space) { + holder->full_name = calloc(1, strlen(holder->name) + + strlen(holder->name_space) + 2); + } + if (holder->full_name) { + strcpy(holder->full_name, holder->name_space); + strcat(holder->full_name, "."); + strcat(holder->full_name, holder->name); + } + else + holder->full_name = holder->name; + if (iid) + holder->iid = xpidl_strdup(iid); + } + return holder; +} + +static void +DeleteNewInterfaceHolder(NewInterfaceHolder *holder) +{ + if (holder) { + if (holder->full_name && holder->full_name != holder->name) + free(holder->full_name); + if (holder->name) + free(holder->name); + if (holder->name_space) + free(holder->name_space); + if (holder->iid) + free(holder->iid); + free(holder); + } +} + +/* + * If p is an ident for an interface, and we don't have an entry in the + * interface map yet, add one. + */ +static gboolean +add_interface_maybe(IDL_tree_func_data *tfd, gpointer user_data) +{ + TreeState *state = user_data; + IDL_tree up; + if (IDL_NODE_TYPE(tfd->tree) == IDLN_IDENT) { + IDL_tree_type node_type = IDL_NODE_TYPE((up = IDL_NODE_UP(tfd->tree))); + if (node_type == IDLN_INTERFACE || node_type == IDLN_FORWARD_DCL) { + + /* We only want to add a new entry if there is no entry by this + * name or if the previously found entry was just a forward + * declaration and the new entry is not. + */ + + char *iface = IDL_IDENT(tfd->tree).str; + NewInterfaceHolder *old_holder = (NewInterfaceHolder *) + g_hash_table_lookup(IFACE_MAP(state), iface); + if (old_holder && old_holder->is_forward_dcl && + node_type != IDLN_FORWARD_DCL) + { + g_hash_table_remove(IFACE_MAP(state), iface); + DeleteNewInterfaceHolder(old_holder); + old_holder = NULL; + } + if (!old_holder) { + /* XXX should we parse here and store a struct nsID *? */ + char *iid = (char *)IDL_tree_property_get(tfd->tree, "uuid"); + char *name_space = (char *) + IDL_tree_property_get(tfd->tree, "namespace"); + NewInterfaceHolder *holder = + CreateNewInterfaceHolder(iface, name_space, iid, + (gboolean) node_type == IDLN_FORWARD_DCL); + if (!holder) + return FALSE; + g_hash_table_insert(IFACE_MAP(state), + holder->full_name, holder); + IFACES(state)++; +#ifdef DEBUG_shaver_ifaces + fprintf(stderr, "adding interface #%d: %s/%s\n", IFACES(state), + iface, iid[0] ? iid : ""); +#endif + } + } else { +#ifdef DEBUG_shaver_ifaces + fprintf(stderr, "ident %s isn't an interface (%s)\n", + IDL_IDENT(tfd->tree).str, IDL_NODE_TYPE_NAME(up)); +#endif + } + } + + return TRUE; +} + +/* Find all the interfaces referenced in the tree (uses add_interface_maybe) */ +static gboolean +find_interfaces(IDL_tree_func_data *tfd, gpointer user_data) +{ + IDL_tree node = NULL; + + switch (IDL_NODE_TYPE(tfd->tree)) { + case IDLN_ATTR_DCL: + node = IDL_ATTR_DCL(tfd->tree).param_type_spec; + break; + case IDLN_OP_DCL: + IDL_tree_walk_in_order(IDL_OP_DCL(tfd->tree).parameter_dcls, find_interfaces, + user_data); + node = IDL_OP_DCL(tfd->tree).op_type_spec; + break; + case IDLN_PARAM_DCL: + node = IDL_PARAM_DCL(tfd->tree).param_type_spec; + break; + case IDLN_INTERFACE: + node = IDL_INTERFACE(tfd->tree).inheritance_spec; + if (node) + xpidl_list_foreach(node, add_interface_maybe, user_data); + node = IDL_INTERFACE(tfd->tree).ident; + break; + case IDLN_FORWARD_DCL: + node = IDL_FORWARD_DCL(tfd->tree).ident; + break; + default: + node = NULL; + } + + if (node && IDL_NODE_TYPE(node) == IDLN_IDENT) { + IDL_tree_func_data new_tfd; + new_tfd.tree = node; + add_interface_maybe(&new_tfd, user_data); + } + + return TRUE; +} + +#ifdef DEBUG_shaver +/* for calling from gdb */ +static void +print_IID(struct nsID *iid, FILE *file) +{ + char iid_buf[UUID_LENGTH]; + + xpidl_sprint_iid(iid, iid_buf); + fprintf(file, "%s\n", iid_buf); +} +#endif + +/* fill the interface_directory IDE table from the interface_map */ +static gboolean +fill_ide_table(gpointer key, gpointer value, gpointer user_data) +{ + TreeState *state = user_data; + NewInterfaceHolder *holder = (NewInterfaceHolder *) value; + struct nsID id; + XPTInterfaceDirectoryEntry *ide; + + XPT_ASSERT(holder); + +#ifdef DEBUG_shaver_ifaces + fprintf(stderr, "filling %s\n", holder->full_name); +#endif + + if (holder->iid) { + if (strlen(holder->iid) != 36) { + IDL_tree_error(state->tree, "IID %s is the wrong length\n", + holder->iid); + return FALSE; + } + if (!xpidl_parse_iid(&id, holder->iid)) { + IDL_tree_error(state->tree, "cannot parse IID %s\n", holder->iid); + return FALSE; + } + } else { + memset(&id, 0, sizeof(id)); + } + + ide = &(HEADER(state)->interface_directory[IFACES(state)]); + if (!XPT_FillInterfaceDirectoryEntry(ARENA(state), ide, &id, holder->name, + holder->name_space, NULL)) { + IDL_tree_error(state->tree, "INTERNAL: XPT_FillIDE failed for %s\n", + holder->full_name); + return FALSE; + } + + IFACES(state)++; + DeleteNewInterfaceHolder(holder); + return TRUE; +} + +static int +compare_IDEs(const void *ap, const void *bp) +{ + const XPTInterfaceDirectoryEntry *a = ap, *b = bp; + const nsID *aid = &a->iid, *bid = &b->iid; + const char *ans, *bns; + + int i; +#define COMPARE(field) if (aid->field > bid->field) return 1; \ + if (bid->field > aid->field) return -1; + COMPARE(m0); + COMPARE(m1); + COMPARE(m2); + for (i = 0; i < 8; i++) { + COMPARE(m3[i]); + } + + /* defend against NULL name_space by using empty string. */ + ans = a->name_space ? a->name_space : ""; + bns = b->name_space ? b->name_space : ""; + + if (a->name_space && b->name_space) { + if ((i = strcmp(a->name_space, b->name_space))) + return i; + } else { + if (a->name_space || b->name_space) { + if (a->name_space) + return -1; + return 1; + } + } + /* these had better not be NULL... */ + return strcmp(a->name, b->name); +#undef COMPARE +} + +/* sort the IDE block as per the typelib spec: IID order, unresolved first */ +static void +sort_ide_block(TreeState *state) +{ + XPTInterfaceDirectoryEntry *ide; + int i; + + /* boy, I sure hope qsort works correctly everywhere */ +#ifdef DEBUG_shaver_sort + fputs("before sort:\n", stderr); + for (i = 0; i < IFACES(state); i++) { + fputs(" ", stderr); + print_IID(&HEADER(state)->interface_directory[i].iid, stderr); + fputc('\n', stderr); + } +#endif + qsort(HEADER(state)->interface_directory, IFACES(state), + sizeof(*ide), compare_IDEs); +#ifdef DEBUG_shaver_sort + fputs("after sort:\n", stderr); + for (i = 0; i < IFACES(state); i++) { + fputs(" ", stderr); + print_IID(&HEADER(state)->interface_directory[i].iid, stderr); + fputc('\n', stderr); + } +#endif + + for (i = 0; i < IFACES(state); i++) { + ide = HEADER(state)->interface_directory + i; + g_hash_table_insert(IFACE_MAP(state), ide->name, (void *)(i + 1)); + } + + return; +} + +static gboolean +typelib_list(TreeState *state) +{ + IDL_tree iter; + for (iter = state->tree; iter; iter = IDL_LIST(iter).next) { + state->tree = IDL_LIST(iter).data; + if (!xpidl_process_node(state)) + return FALSE; + } + return TRUE; +} + +static gboolean +typelib_prolog(TreeState *state) +{ + state->priv = calloc(1, sizeof(struct priv_data)); + if (!state->priv) + return FALSE; + IFACES(state) = 0; + IFACE_MAP(state) = g_hash_table_new(g_str_hash, g_str_equal); + if (!IFACE_MAP(state)) { + /* XXX report error */ + free(state->priv); + return FALSE; + } + /* find all interfaces, top-level and referenced by others */ + IDL_tree_walk_in_order(state->tree, find_interfaces, state); + ARENA(state) = XPT_NewArena(1024, sizeof(double), "main xpidl arena"); + HEADER(state) = XPT_NewHeader(ARENA(state), IFACES(state), + major_version, minor_version); + + /* fill IDEs from hash table */ + IFACES(state) = 0; + g_hash_table_foreach_remove(IFACE_MAP(state), fill_ide_table, state); + + /* if any are left then we must have failed in fill_ide_table */ + if (g_hash_table_size(IFACE_MAP(state))) + return FALSE; + + /* sort the IDEs by IID order and store indices in the interface map */ + sort_ide_block(state); + + return TRUE; +} + +static gboolean +typelib_epilog(TreeState *state) +{ + XPTState *xstate = XPT_NewXDRState(XPT_ENCODE, NULL, 0); + XPTCursor curs, *cursor = &curs; + PRUint32 i, len, header_sz; + PRUint32 oldOffset; + PRUint32 newOffset; + char *data; + + /* Write any annotations */ + if (emit_typelib_annotations) { + PRUint32 annotation_len, written_so_far; + char *annotate_val, *timestr; + time_t now; + static char *annotation_format = + "Created from %s.idl\nCreation date: %sInterfaces:"; + + /* fill in the annotations, listing resolved interfaces in order */ + + (void)time(&now); + timestr = ctime(&now); + + /* Avoid dependence on nspr; no PR_smprintf and friends. */ + + /* How large should the annotation string be? */ + annotation_len = strlen(annotation_format) + strlen(state->basename) + + strlen(timestr); +#ifdef VBOX + /* note that '%s' is contained two times in annotation_format and both + * format specifiers are replaced by a string. So in fact we reserve 4 + * bytes minus one byte (for the terminating '\0') more than necessary. */ +#endif + for (i = 0; i < HEADER(state)->num_interfaces; i++) { + XPTInterfaceDirectoryEntry *ide; + ide = &HEADER(state)->interface_directory[i]; + if (ide->interface_descriptor) { + annotation_len += strlen(ide->name) + 1; + } + } + + annotate_val = (char *) malloc(annotation_len); + written_so_far = sprintf(annotate_val, annotation_format, + state->basename, timestr); + + for (i = 0; i < HEADER(state)->num_interfaces; i++) { + XPTInterfaceDirectoryEntry *ide; + ide = &HEADER(state)->interface_directory[i]; + if (ide->interface_descriptor) { + written_so_far += sprintf(annotate_val + written_so_far, " %s", + ide->name); + } + } + + HEADER(state)->annotations = + XPT_NewAnnotation(ARENA(state), + XPT_ANN_LAST | XPT_ANN_PRIVATE, + XPT_NewStringZ(ARENA(state), "xpidl 0.99.9"), + XPT_NewStringZ(ARENA(state), annotate_val)); + free(annotate_val); + } else { + HEADER(state)->annotations = + XPT_NewAnnotation(ARENA(state), XPT_ANN_LAST, NULL, NULL); + } + + if (!HEADER(state)->annotations) { + /* XXX report out of memory error */ + return FALSE; + } + + /* Write the typelib */ + header_sz = XPT_SizeOfHeaderBlock(HEADER(state)); + + if (!xstate || + !XPT_MakeCursor(xstate, XPT_HEADER, header_sz, cursor)) + goto destroy_header; + oldOffset = cursor->offset; + if (!XPT_DoHeader(ARENA(state), cursor, &HEADER(state))) + goto destroy; + newOffset = cursor->offset; + XPT_GetXDRDataLength(xstate, XPT_HEADER, &len); + HEADER(state)->file_length = len; + XPT_GetXDRDataLength(xstate, XPT_DATA, &len); + HEADER(state)->file_length += len; + XPT_SeekTo(cursor, oldOffset); + if (!XPT_DoHeaderPrologue(ARENA(state), cursor, &HEADER(state), NULL)) + goto destroy; + XPT_SeekTo(cursor, newOffset); + XPT_GetXDRData(xstate, XPT_HEADER, &data, &len); + fwrite(data, len, 1, state->file); + XPT_GetXDRData(xstate, XPT_DATA, &data, &len); + fwrite(data, len, 1, state->file); + + destroy: + XPT_DestroyXDRState(xstate); + destroy_header: + /* XXX XPT_DestroyHeader(HEADER(state)) */ + + XPT_FreeHeader(ARENA(state), HEADER(state)); + XPT_DestroyArena(ARENA(state)); + + /* XXX should destroy priv_data here */ + + return TRUE; +} + +static XPTInterfaceDirectoryEntry * +FindInterfaceByName(XPTInterfaceDirectoryEntry *ides, uint16 num_interfaces, + const char *name) +{ + uint16 i; + for (i = 0; i < num_interfaces; i++) { + if (!strcmp(ides[i].name, name)) + return &ides[i]; + } + return NULL; +} + +static gboolean +typelib_interface(TreeState *state) +{ + IDL_tree iface = state->tree, iter; + char *name = IDL_IDENT(IDL_INTERFACE(iface).ident).str; + XPTInterfaceDirectoryEntry *ide; + XPTInterfaceDescriptor *id; + uint16 parent_id = 0; + PRUint8 interface_flags = 0; + + if (!verify_interface_declaration(iface)) + return FALSE; + + if (IDL_tree_property_get(IDL_INTERFACE(iface).ident, "scriptable")) + interface_flags |= XPT_ID_SCRIPTABLE; + + if (IDL_tree_property_get(IDL_INTERFACE(iface).ident, "function")) + interface_flags |= XPT_ID_FUNCTION; + + ide = FindInterfaceByName(HEADER(state)->interface_directory, + HEADER(state)->num_interfaces, name); + if (!ide) { + IDL_tree_error(iface, "ERROR: didn't find interface %s in " + "IDE block. Giving up.\n", name); + return FALSE; + } + + if ((iter = IDL_INTERFACE(iface).inheritance_spec)) { + char *parent; + if (IDL_LIST(iter).next) { + IDL_tree_error(iface, + "ERROR: more than one parent interface for %s\n", + name); + return FALSE; + } + parent = IDL_IDENT(IDL_LIST(iter).data).str; + parent_id = (uint16)(uint32)g_hash_table_lookup(IFACE_MAP(state), + parent); + if (!parent_id) { + IDL_tree_error(iface, + "ERROR: no index found for %s. Giving up.\n", + parent); + return FALSE; + } + } + + id = XPT_NewInterfaceDescriptor(ARENA(state), parent_id, 0, 0, + interface_flags); + if (!id) + return FALSE; + + CURRENT(state) = ide->interface_descriptor = id; +#ifdef DEBUG_shaver_ifaces + fprintf(stderr, "DBG: starting interface %s @ %p\n", name, id); +#endif + + NEXT_METH(state) = 0; + NEXT_CONST(state) = 0; + NEXT_TYPE(state) = 0; + + state->tree = IDL_INTERFACE(iface).body; + if (state->tree && !xpidl_process_node(state)) + return FALSE; +#ifdef DEBUG_shaver_ifaces + fprintf(stderr, "DBG: ending interface %s\n", name); +#endif + return TRUE; +} + +static gboolean +find_arg_with_name(TreeState *state, const char *name, int16 *argnum) +{ + int16 count; + IDL_tree params; + + XPT_ASSERT(state); + XPT_ASSERT(name); + XPT_ASSERT(argnum); + + params = IDL_OP_DCL(IDL_NODE_UP(IDL_NODE_UP(state->tree))).parameter_dcls; + for (count = 0; + params != NULL && IDL_LIST(params).data != NULL; + params = IDL_LIST(params).next, count++) + { + const char *cur_name = IDL_IDENT( + IDL_PARAM_DCL(IDL_LIST(params).data).simple_declarator).str; + if (!strcmp(cur_name, name)) { + /* XXX ought to verify that this is the right type here */ + /* XXX for iid_is this must be an iid */ + /* XXX for size_is and length_is this must be a uint32 */ + *argnum = count; + return TRUE; + } + } + return FALSE; +} + +/* return value is for success or failure */ +static gboolean +get_size_and_length(TreeState *state, IDL_tree type, + int16 *size_is_argnum, int16 *length_is_argnum, + gboolean *has_size_is, gboolean *has_length_is) +{ + *has_size_is = FALSE; + *has_length_is = FALSE; + + if (IDL_NODE_TYPE(state->tree) == IDLN_PARAM_DCL) { + IDL_tree sd = IDL_PARAM_DCL(state->tree).simple_declarator; + const char *size_is; + const char *length_is; + + /* only if size_is is found does any of this matter */ + size_is = IDL_tree_property_get(sd, "size_is"); + if (!size_is) + return TRUE; + + if (!find_arg_with_name(state, size_is, size_is_argnum)) { + IDL_tree_error(state->tree, "can't find matching argument for " + "[size_is(%s)]\n", size_is); + return FALSE; + } + *has_size_is = TRUE; + + /* length_is is optional */ + length_is = IDL_tree_property_get(sd, "length_is"); + if (length_is) { + *has_length_is = TRUE; + if (!find_arg_with_name(state, length_is, length_is_argnum)) { + IDL_tree_error(state->tree, "can't find matching argument for " + "[length_is(%s)]\n", length_is); + return FALSE; + } + } + } + return TRUE; +} + +static gboolean +fill_td_from_type(TreeState *state, XPTTypeDescriptor *td, IDL_tree type) +{ + IDL_tree up; + int16 size_is_argnum; + int16 length_is_argnum; + gboolean has_size_is; + gboolean has_length_is; + gboolean is_array = FALSE; + + if (type) { + + /* deal with array */ + + if (IDL_NODE_TYPE(state->tree) == IDLN_PARAM_DCL) { + IDL_tree sd = IDL_PARAM_DCL(state->tree).simple_declarator; + if (IDL_tree_property_get(sd, "array")) { + + is_array = TRUE; + + /* size_is is required! */ + if (!get_size_and_length(state, type, + &size_is_argnum, &length_is_argnum, + &has_size_is, &has_length_is)) { + /* error was reported by helper function */ + return FALSE; + } + + if (!has_size_is) { + IDL_tree_error(state->tree, "[array] requires [size_is()]\n"); + return FALSE; + } + + td->prefix.flags = TD_ARRAY | XPT_TDP_POINTER; + td->argnum = size_is_argnum; + + if (has_length_is) + td->argnum2 = length_is_argnum; + else + td->argnum2 = size_is_argnum; + + /* + * XXX - NOTE - this will be broken for multidimensional + * arrays because of the realloc XPT_InterfaceDescriptorAddTypes + * uses. The underlying 'td' can change as we recurse in to get + * additional dimensions. Luckily, we don't yet support more + * than on dimension in the arrays + */ + /* setup the additional_type */ + if (!XPT_InterfaceDescriptorAddTypes(ARENA(state), + CURRENT(state), 1)) { + g_error("out of memory\n"); + return FALSE; + } + td->type.additional_type = NEXT_TYPE(state); + td = &CURRENT(state)->additional_types[NEXT_TYPE(state)]; + NEXT_TYPE(state)++ ; + } + } + +handle_typedef: + switch (IDL_NODE_TYPE(type)) { + case IDLN_TYPE_INTEGER: { + gboolean sign = IDL_TYPE_INTEGER(type).f_signed; + switch(IDL_TYPE_INTEGER(type).f_type) { + case IDL_INTEGER_TYPE_SHORT: + td->prefix.flags = sign ? TD_INT16 : TD_UINT16; + break; + case IDL_INTEGER_TYPE_LONG: + td->prefix.flags = sign ? TD_INT32 : TD_UINT32; + break; + case IDL_INTEGER_TYPE_LONGLONG: + td->prefix.flags = sign ? TD_INT64 : TD_UINT64; + break; + } + break; + } + case IDLN_TYPE_CHAR: + td->prefix.flags = TD_CHAR; + break; + case IDLN_TYPE_WIDE_CHAR: + td->prefix.flags = TD_WCHAR; + break; + case IDLN_TYPE_STRING: + if (is_array) { + td->prefix.flags = TD_PSTRING | XPT_TDP_POINTER; + } else { + if (!get_size_and_length(state, type, + &size_is_argnum, &length_is_argnum, + &has_size_is, &has_length_is)) { + /* error was reported by helper function */ + return FALSE; + } + if (has_size_is) { + td->prefix.flags = TD_PSTRING_SIZE_IS | XPT_TDP_POINTER; + td->argnum = size_is_argnum; + if (has_length_is) + td->argnum2 = length_is_argnum; + else + td->argnum2 = size_is_argnum; + } else { + td->prefix.flags = TD_PSTRING | XPT_TDP_POINTER; + } + } + break; + case IDLN_TYPE_WIDE_STRING: + if (is_array) { + td->prefix.flags = TD_PWSTRING | XPT_TDP_POINTER; + } else { + if (!get_size_and_length(state, type, + &size_is_argnum, &length_is_argnum, + &has_size_is, &has_length_is)) { + /* error was reported by helper function */ + return FALSE; + } + if (has_size_is) { + td->prefix.flags = TD_PWSTRING_SIZE_IS | XPT_TDP_POINTER; + td->argnum = size_is_argnum; + if (has_length_is) + td->argnum2 = length_is_argnum; + else + td->argnum2 = size_is_argnum; + } else { + td->prefix.flags = TD_PWSTRING | XPT_TDP_POINTER; + } + } + break; + case IDLN_TYPE_BOOLEAN: + td->prefix.flags = TD_BOOL; + break; + case IDLN_TYPE_OCTET: + td->prefix.flags = TD_UINT8; + break; + case IDLN_TYPE_FLOAT: + switch (IDL_TYPE_FLOAT (type).f_type) { + case IDL_FLOAT_TYPE_FLOAT: + td->prefix.flags = TD_FLOAT; + break; + case IDL_FLOAT_TYPE_DOUBLE: + td->prefix.flags = TD_DOUBLE; + break; + /* XXX 'long double' just ignored, or what? */ + default: break; + } + break; + case IDLN_IDENT: + if (!(up = IDL_NODE_UP(type))) { + IDL_tree_error(state->tree, + "ERROR: orphan ident %s in param list\n", + IDL_IDENT(type).str); + return FALSE; + } + switch (IDL_NODE_TYPE(up)) { + /* This whole section is abominably ugly */ + case IDLN_FORWARD_DCL: + case IDLN_INTERFACE: { + XPTInterfaceDirectoryEntry *ide, *ides; + uint16 num_ifaces; + char *className; + const char *iid_is; +handle_iid_is: + ides = HEADER(state)->interface_directory; + num_ifaces = HEADER(state)->num_interfaces; + /* might get here via the goto, so re-check type */ + if (IDL_NODE_TYPE(up) == IDLN_INTERFACE) + className = IDL_IDENT(IDL_INTERFACE(up).ident).str; + else if (IDL_NODE_TYPE(up) == IDLN_FORWARD_DCL) + className = IDL_IDENT(IDL_FORWARD_DCL(up).ident).str; + else + className = IDL_IDENT(IDL_NATIVE(up).ident).str; + iid_is = NULL; + + if (IDL_NODE_TYPE(state->tree) == IDLN_PARAM_DCL) { + iid_is = + IDL_tree_property_get(IDL_PARAM_DCL(state->tree).simple_declarator, + "iid_is"); + } + if (iid_is) { + int16 argnum; + if (!find_arg_with_name(state, iid_is, &argnum)) { + IDL_tree_error(state->tree, + "can't find matching argument for " + "[iid_is(%s)]\n", iid_is); + return FALSE; + } + td->prefix.flags = TD_INTERFACE_IS_TYPE | XPT_TDP_POINTER; + td->argnum = argnum; + } else { + td->prefix.flags = TD_INTERFACE_TYPE | XPT_TDP_POINTER; + ide = FindInterfaceByName(ides, num_ifaces, className); + if (!ide || ide < ides || ide > ides + num_ifaces) { + IDL_tree_error(state->tree, + "unknown iface %s in param\n", + className); + return FALSE; + } + td->type.iface = ide - ides + 1; +#ifdef DEBUG_shaver_index + fprintf(stderr, "DBG: index %d for %s\n", + td->type.iface, className); +#endif + } + break; + } + case IDLN_NATIVE: { + char *ident; + + /* jband - adding goto for iid_is when type is native */ + if (IDL_NODE_TYPE(state->tree) == IDLN_PARAM_DCL && + IDL_tree_property_get(IDL_PARAM_DCL(state->tree).simple_declarator, + "iid_is")) + goto handle_iid_is; + + ident = IDL_IDENT(type).str; + if (IDL_tree_property_get(type, "nsid")) { + td->prefix.flags = TD_PNSIID; + if (IDL_tree_property_get(type, "ref")) + td->prefix.flags |= XPT_TDP_POINTER | XPT_TDP_REFERENCE; + else if (IDL_tree_property_get(type,"ptr")) + td->prefix.flags |= XPT_TDP_POINTER; + } else if (IDL_tree_property_get(type, "domstring")) { + td->prefix.flags = TD_DOMSTRING | XPT_TDP_POINTER; + if (IDL_tree_property_get(type, "ref")) + td->prefix.flags |= XPT_TDP_REFERENCE; + } else if (IDL_tree_property_get(type, "astring")) { + td->prefix.flags = TD_ASTRING | XPT_TDP_POINTER; + if (IDL_tree_property_get(type, "ref")) + td->prefix.flags |= XPT_TDP_REFERENCE; + } else if (IDL_tree_property_get(type, "utf8string")) { + td->prefix.flags = TD_UTF8STRING | XPT_TDP_POINTER; + if (IDL_tree_property_get(type, "ref")) + td->prefix.flags |= XPT_TDP_REFERENCE; + } else if (IDL_tree_property_get(type, "cstring")) { + td->prefix.flags = TD_CSTRING | XPT_TDP_POINTER; + if (IDL_tree_property_get(type, "ref")) + td->prefix.flags |= XPT_TDP_REFERENCE; + } else { + td->prefix.flags = TD_VOID | XPT_TDP_POINTER; + } + break; + } + default: + if (IDL_NODE_TYPE(IDL_NODE_UP(up)) == IDLN_TYPE_DCL) { + /* restart with the underlying type */ + IDL_tree new_type; + new_type = IDL_TYPE_DCL(IDL_NODE_UP(up)).type_spec; +#ifdef DEBUG_shaver_misc + fprintf(stderr, "following %s typedef to %s\n", + IDL_IDENT(type).str, IDL_NODE_TYPE_NAME(new_type)); +#endif + /* + * Do a nice messy goto rather than recursion so that + * we can avoid screwing up the *array* information. + */ +/* return fill_td_from_type(state, td, new_type); */ + if (new_type) { + type = new_type; + goto handle_typedef; + } else { + /* do what we would do in recursion if !type */ + td->prefix.flags = TD_VOID; + return TRUE; + } + } + IDL_tree_error(state->tree, + "can't handle %s ident in param list\n", +#ifdef DEBUG_shaver + /* XXX is this safe to use on Win now? */ + IDL_NODE_TYPE_NAME(IDL_NODE_UP(type)) +#else + "that type of" +#endif + ); +#ifdef DEBUG_shaver + XPT_ASSERT(0); +#endif + return FALSE; + } + break; + default: + IDL_tree_error(state->tree, "can't handle %s in param list\n", +#ifdef DEBUG_shaver + /* XXX is this safe to use on Win now? */ + IDL_NODE_TYPE_NAME(IDL_NODE_UP(type)) +#else + "that type" +#endif + ); + return FALSE; + } + } else { + td->prefix.flags = TD_VOID; + } + + return TRUE; +} + +static gboolean +fill_pd_from_type(TreeState *state, XPTParamDescriptor *pd, uint8 flags, + IDL_tree type) +{ + pd->flags = flags; + return fill_td_from_type(state, &pd->type, type); +} + +static gboolean +fill_pd_from_param(TreeState *state, XPTParamDescriptor *pd, IDL_tree tree) +{ + uint8 flags = 0; + gboolean is_dipper_type = DIPPER_TYPE(IDL_PARAM_DCL(tree).param_type_spec); + + switch (IDL_PARAM_DCL(tree).attr) { + case IDL_PARAM_IN: + flags = XPT_PD_IN; + break; + case IDL_PARAM_OUT: + flags = XPT_PD_OUT; + break; + case IDL_PARAM_INOUT: + flags = XPT_PD_IN | XPT_PD_OUT; + break; + } + + if (IDL_tree_property_get(IDL_PARAM_DCL(tree).simple_declarator, + "retval")) { + if (flags != XPT_PD_OUT) { + IDL_tree_error(tree, "can't have [retval] with in%s param " + "(only out)\n", + flags & XPT_PD_OUT ? "out" : ""); + return FALSE; + } + flags |= XPT_PD_RETVAL; + } + + if (is_dipper_type && (flags & XPT_PD_OUT)) { + flags &= ~XPT_PD_OUT; + flags |= XPT_PD_IN | XPT_PD_DIPPER; + } + + if (IDL_tree_property_get(IDL_PARAM_DCL(tree).simple_declarator, + "shared")) { + if (flags & XPT_PD_IN) { + IDL_tree_error(tree, "can't have [shared] with in%s param " + "(only out)\n", + flags & XPT_PD_OUT ? "out" : ""); + return FALSE; + } + flags |= XPT_PD_SHARED; + } + + /* stick param where we can see it later */ + state->tree = tree; + return fill_pd_from_type(state, pd, flags, + IDL_PARAM_DCL(tree).param_type_spec); +} + +/* XXXshaver common with xpidl_header.c */ +#define ATTR_IDENT(tree) (IDL_IDENT(IDL_LIST(IDL_ATTR_DCL(tree).simple_declarations).data)) +#define ATTR_TYPE_DECL(tree) (IDL_ATTR_DCL(tree).param_type_spec) +#define ATTR_TYPE(tree) (IDL_NODE_TYPE(ATTR_TYPE_DECL(tree))) + +static gboolean +fill_pd_as_nsresult(XPTParamDescriptor *pd) +{ + pd->type.prefix.flags = TD_UINT32; /* TD_NSRESULT */ + return TRUE; +} + +static gboolean +typelib_attr_accessor(TreeState *state, XPTMethodDescriptor *meth, + gboolean getter, gboolean hidden) +{ + uint8 methflags = 0; + uint8 pdflags = 0; + + methflags |= getter ? XPT_MD_GETTER : XPT_MD_SETTER; + methflags |= hidden ? XPT_MD_HIDDEN : 0; + if (!XPT_FillMethodDescriptor(ARENA(state), meth, methflags, + ATTR_IDENT(state->tree).str, 1)) + return FALSE; + + if (getter) { + if (DIPPER_TYPE(ATTR_TYPE_DECL(state->tree))) { + pdflags |= (XPT_PD_RETVAL | XPT_PD_IN | XPT_PD_DIPPER); + } else { + pdflags |= (XPT_PD_RETVAL | XPT_PD_OUT); + } + } else { + pdflags |= XPT_PD_IN; + } + + if (!fill_pd_from_type(state, meth->params, pdflags, + ATTR_TYPE_DECL(state->tree))) + return FALSE; + + fill_pd_as_nsresult(meth->result); + NEXT_METH(state)++; + return TRUE; +} + +static gboolean +typelib_attr_dcl(TreeState *state) +{ + XPTInterfaceDescriptor *id = CURRENT(state); + XPTMethodDescriptor *meth; + gboolean read_only = IDL_ATTR_DCL(state->tree).f_readonly; + + /* XXX this only handles the first ident; elsewhere too... */ + IDL_tree ident = + IDL_LIST(IDL_ATTR_DCL(state->tree).simple_declarations).data; + + /* If it's marked [noscript], mark it as hidden in the typelib. */ + gboolean hidden = (IDL_tree_property_get(ident, "noscript") != NULL); + + if (!verify_attribute_declaration(state->tree)) + return FALSE; + + if (!XPT_InterfaceDescriptorAddMethods(ARENA(state), id, + (PRUint16) (read_only ? 1 : 2))) + return FALSE; + + meth = &id->method_descriptors[NEXT_METH(state)]; + + return typelib_attr_accessor(state, meth, TRUE, hidden) && + (read_only || typelib_attr_accessor(state, meth + 1, FALSE, hidden)); +} + +static gboolean +typelib_op_dcl(TreeState *state) +{ + XPTInterfaceDescriptor *id = CURRENT(state); + XPTMethodDescriptor *meth; + struct _IDL_OP_DCL *op = &IDL_OP_DCL(state->tree); + IDL_tree iter; + uint16 num_args = 0; + uint8 op_flags = 0; + gboolean op_notxpcom = (IDL_tree_property_get(op->ident, "notxpcom") + != NULL); + gboolean op_noscript = (IDL_tree_property_get(op->ident, "noscript") + != NULL); + + if (!verify_method_declaration(state->tree)) + return FALSE; + + if (!XPT_InterfaceDescriptorAddMethods(ARENA(state), id, 1)) + return FALSE; + + meth = &id->method_descriptors[NEXT_METH(state)]; + + for (iter = op->parameter_dcls; iter; iter = IDL_LIST(iter).next) + num_args++; /* count params */ + if (op->op_type_spec && !op_notxpcom) + num_args++; /* fake param for _retval */ + + if (op_noscript) + op_flags |= XPT_MD_HIDDEN; + if (op_notxpcom) + op_flags |= XPT_MD_NOTXPCOM; + + /* XXXshaver constructor? */ + +#ifdef DEBUG_shaver_method + fprintf(stdout, "DBG: adding method %s (nargs %d)\n", + IDL_IDENT(op->ident).str, num_args); +#endif + if (!XPT_FillMethodDescriptor(ARENA(state), meth, op_flags, + IDL_IDENT(op->ident).str, + (uint8) num_args)) + return FALSE; + + for (num_args = 0, iter = op->parameter_dcls; iter; + iter = IDL_LIST(iter).next, num_args++) { + XPTParamDescriptor *pd = &meth->params[num_args]; + if (!fill_pd_from_param(state, pd, IDL_LIST(iter).data)) + return FALSE; + } + + /* stick retval param where we can see it later */ + state->tree = op->op_type_spec; + + /* XXX unless [notxpcom] */ + if (!op_notxpcom) { + if (op->op_type_spec) { + uint8 pdflags = DIPPER_TYPE(op->op_type_spec) ? + (XPT_PD_RETVAL | XPT_PD_IN | XPT_PD_DIPPER) : + (XPT_PD_RETVAL | XPT_PD_OUT); + + if (!fill_pd_from_type(state, &meth->params[num_args], + pdflags, op->op_type_spec)) + return FALSE; + } + + if (!fill_pd_as_nsresult(meth->result)) + return FALSE; + } else { +#ifdef DEBUG_shaver_notxpcom + fprintf(stderr, "%s is notxpcom\n", IDL_IDENT(op->ident).str); +#endif + if (!fill_pd_from_type(state, meth->result, XPT_PD_RETVAL, + op->op_type_spec)) + return FALSE; + } + NEXT_METH(state)++; + return TRUE; +} + +static gboolean +typelib_const_dcl(TreeState *state) +{ + struct _IDL_CONST_DCL *dcl = &IDL_CONST_DCL(state->tree); + const char *name = IDL_IDENT(dcl->ident).str; + gboolean is_long; + gboolean sign; + IDL_tree real_type; + XPTInterfaceDescriptor *id; + XPTConstDescriptor *cd; + IDL_longlong_t value; + + if (!verify_const_declaration(state->tree)) + return FALSE; + + /* Could be a typedef; try to map it to the real type. */ + real_type = find_underlying_type(dcl->const_type); + real_type = real_type ? real_type : dcl->const_type; + is_long = (IDL_TYPE_INTEGER(real_type).f_type == IDL_INTEGER_TYPE_LONG); + + id = CURRENT(state); + if (!XPT_InterfaceDescriptorAddConsts(ARENA(state), id, 1)) + return FALSE; + cd = &id->const_descriptors[NEXT_CONST(state)]; + + cd->name = IDL_IDENT(dcl->ident).str; +#ifdef DEBUG_shaver_const + fprintf(stderr, "DBG: adding const %s\n", cd->name); +#endif + if (!fill_td_from_type(state, &cd->type, dcl->const_type)) + return FALSE; + + value = IDL_INTEGER(dcl->const_exp).value; + sign = IDL_TYPE_INTEGER(dcl->const_type).f_signed; + if (is_long) { + if (sign) + cd->value.i32 = value; + else + cd->value.ui32 = value; + } else { + if (sign) + cd->value.i16 = value; + else + cd->value.ui16 = value; + } + NEXT_CONST(state)++; + return TRUE; +} + +static gboolean +typelib_enum(TreeState *state) +{ + XPIDL_WARNING((state->tree, IDL_WARNING1, + "enums not supported, enum \'%s\' ignored", + IDL_IDENT(IDL_TYPE_ENUM(state->tree).ident).str)); + return TRUE; +} + +backend * +xpidl_typelib_dispatch(void) +{ + static backend result; + static nodeHandler table[IDLN_LAST]; + static gboolean initialized = FALSE; + + result.emit_prolog = typelib_prolog; + result.emit_epilog = typelib_epilog; + + if (!initialized) { + /* Initialize non-NULL elements */ + table[IDLN_LIST] = typelib_list; + table[IDLN_ATTR_DCL] = typelib_attr_dcl; + table[IDLN_OP_DCL] = typelib_op_dcl; + table[IDLN_INTERFACE] = typelib_interface; + table[IDLN_CONST_DCL] = typelib_const_dcl; + table[IDLN_TYPE_ENUM] = typelib_enum; + table[IDLN_NATIVE] = check_native; + initialized = TRUE; + } + + result.dispatch_table = table; + return &result; +} + + + diff --git a/src/libs/xpcom18a4/xpcom/typelib/xpidl/xpidl_util.c b/src/libs/xpcom18a4/xpcom/typelib/xpidl/xpidl_util.c new file mode 100644 index 00000000..25d04212 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/typelib/xpidl/xpidl_util.c @@ -0,0 +1,851 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: NPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Netscape 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/NPL/ + * + * 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * 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 NPL, 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 NPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * Utility functions called by various backends. + */ + +#include "xpidl.h" + +/* XXXbe static */ char OOM[] = "ERROR: out of memory\n"; + +void * +xpidl_malloc(size_t nbytes) +{ + void *p = malloc(nbytes); + if (!p) { + fputs(OOM, stderr); + exit(1); + } + return p; +} + +char * +xpidl_strdup(const char *s) +{ +#if defined(XP_MAC) || defined(XP_SOLARIS) /* bird: dunno why this is required, but whatever*/ + size_t len = strlen(s); + char *ns = malloc(len + 1); + if (ns) + memcpy(ns, s, len + 1); +#else + char *ns = strdup(s); +#endif + if (!ns) { + fputs(OOM, stderr); + exit(1); + } + return ns; +} + +void +xpidl_write_comment(TreeState *state, int indent) +{ + fprintf(state->file, "%*s/* ", indent, ""); + IDL_tree_to_IDL(state->tree, state->ns, state->file, + IDLF_OUTPUT_NO_NEWLINES | + IDLF_OUTPUT_NO_QUALIFY_IDENTS | + IDLF_OUTPUT_PROPERTIES); + fputs(" */\n", state->file); +} + +/* + * Print an iid to into a supplied buffer; the buffer should be at least + * UUID_LENGTH bytes. + */ +gboolean +xpidl_sprint_iid(nsID *id, char iidbuf[]) +{ + int printed; + + printed = sprintf(iidbuf, + "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", + (PRUint32) id->m0, (PRUint32) id->m1,(PRUint32) id->m2, + (PRUint32) id->m3[0], (PRUint32) id->m3[1], + (PRUint32) id->m3[2], (PRUint32) id->m3[3], + (PRUint32) id->m3[4], (PRUint32) id->m3[5], + (PRUint32) id->m3[6], (PRUint32) id->m3[7]); + +#ifdef SPRINTF_RETURNS_STRING + return (printed && strlen((char *)printed) == 36); +#else + return (printed == 36); +#endif +} + +/* We only parse the {}-less format. */ +static const char nsIDFmt2[] = + "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x"; + +/* + * Parse a uuid string into an nsID struct. We cannot link against libxpcom, + * so we re-implement nsID::Parse here. + */ +gboolean +xpidl_parse_iid(nsID *id, const char *str) +{ + PRInt32 count = 0; + PRInt32 n1, n2, n3[8]; + PRInt32 n0, i; + + XPT_ASSERT(str != NULL); + + if (strlen(str) != 36) { + return FALSE; + } + +#ifdef DEBUG_shaver_iid + fprintf(stderr, "parsing iid %s\n", str); +#endif + + count = sscanf(str, nsIDFmt2, + &n0, &n1, &n2, + &n3[0],&n3[1],&n3[2],&n3[3], + &n3[4],&n3[5],&n3[6],&n3[7]); + + id->m0 = (PRInt32) n0; + id->m1 = (PRInt16) n1; + id->m2 = (PRInt16) n2; + for (i = 0; i < 8; i++) { + id->m3[i] = (PRInt8) n3[i]; + } + +#ifdef DEBUG_shaver_iid + if (count == 11) { + fprintf(stderr, "IID parsed to "); + print_IID(id, stderr); + fputs("\n", stderr); + } +#endif + return (gboolean)(count == 11); +} + +gboolean +verify_const_declaration(IDL_tree const_tree) { + struct _IDL_CONST_DCL *dcl = &IDL_CONST_DCL(const_tree); + const char *name = IDL_IDENT(dcl->ident).str; + IDL_tree real_type; + + /* const -> list -> interface */ + if (!IDL_NODE_UP(IDL_NODE_UP(const_tree)) || + IDL_NODE_TYPE(IDL_NODE_UP(IDL_NODE_UP(const_tree))) + != IDLN_INTERFACE) { + IDL_tree_error(const_tree, + "const declaration \'%s\' outside interface", + name); + return FALSE; + } + + /* Could be a typedef; try to map it to the real type. */ + real_type = find_underlying_type(dcl->const_type); + real_type = real_type ? real_type : dcl->const_type; + if (IDL_NODE_TYPE(real_type) == IDLN_TYPE_INTEGER && + (IDL_TYPE_INTEGER(real_type).f_type == IDL_INTEGER_TYPE_SHORT || + IDL_TYPE_INTEGER(real_type).f_type == IDL_INTEGER_TYPE_LONG)) + { + if (!IDL_TYPE_INTEGER(real_type).f_signed && + IDL_INTEGER(dcl->const_exp).value < 0) + { +#ifndef G_HAVE_GINT64 + /* + * For platforms without longlong support turned on we can get + * confused by the high bit of the long value and think that it + * represents a negative value in an unsigned declaration. + * In that case we don't know if it is the programmer who is + * confused or the compiler. So we issue a warning instead of + * an error. + */ + if (IDL_TYPE_INTEGER(real_type).f_type == IDL_INTEGER_TYPE_LONG) + { + XPIDL_WARNING((const_tree, IDL_WARNING1, + "unsigned const declaration \'%s\' " + "initialized with (possibly) negative constant", + name)); + return TRUE; + } +#endif + IDL_tree_error(const_tree, + "unsigned const declaration \'%s\' initialized with " + "negative constant", + name); + return FALSE; + } + } else { + IDL_tree_error(const_tree, + "const declaration \'%s\' must be of type short or long", + name); + return FALSE; + } + + return TRUE; +} + + + +/* + * This method consolidates error checking needed when coercing the XPIDL compiler + * via the -t flag to generate output for a specific version of XPConnect. + */ +static gboolean +verify_type_fits_version(IDL_tree in_tree, IDL_tree error_tree) +{ + if (major_version == 1 && minor_version == 1) + { + /* XPIDL Version 1.1 checks */ + + /* utf8string, cstring, and astring types are not supported */ + if (IDL_tree_property_get(in_tree, "utf8string") != NULL || + IDL_tree_property_get(in_tree, "cstring") != NULL || + IDL_tree_property_get(in_tree, "astring") != NULL) + { + IDL_tree_error(error_tree, + "Cannot use [utf8string], [cstring] and [astring] " + "types when generating version 1.1 typelibs\n"); + return FALSE; + } + } + return TRUE; +} + +gboolean +verify_attribute_declaration(IDL_tree attr_tree) +{ + IDL_tree iface; + IDL_tree ident; + IDL_tree attr_type; + gboolean scriptable_interface; + + /* We don't support attributes named IID, conflicts with static GetIID + * member. The conflict is due to certain compilers (VC++) choosing a + * different vtable order, placing GetIID at the beginning regardless + * of it's placement + */ + if (strcmp( + IDL_IDENT( + IDL_LIST(IDL_ATTR_DCL(attr_tree).simple_declarations).data).str, + "IID") == 0) { + IDL_tree_error(attr_tree, + "Attributes named IID not supported, causes vtable " + "ordering problems"); + return FALSE; + } + /* + * Verify that we've been called on an interface, and decide if the + * interface was marked [scriptable]. + */ + if (IDL_NODE_UP(attr_tree) && IDL_NODE_UP(IDL_NODE_UP(attr_tree)) && + IDL_NODE_TYPE(iface = IDL_NODE_UP(IDL_NODE_UP(attr_tree))) + == IDLN_INTERFACE) + { + scriptable_interface = + (IDL_tree_property_get(IDL_INTERFACE(iface).ident, "scriptable") + != NULL); + } else { + IDL_tree_error(attr_tree, + "verify_attribute_declaration called on a non-interface?"); + return FALSE; + } + + /* + * Grab the first of the list of idents and hope that it'll + * say scriptable or no. + */ + ident = IDL_LIST(IDL_ATTR_DCL(attr_tree).simple_declarations).data; + + /* + * If the interface isn't scriptable, or the attribute is marked noscript, + * there's no need to check. + */ + if (!scriptable_interface || + IDL_tree_property_get(ident, "noscript") != NULL) + return TRUE; + + /* + * If it should be scriptable, check that the type is non-native. nsid, + * domstring, utf8string, cstring, astring are exempted. + */ + attr_type = IDL_ATTR_DCL(attr_tree).param_type_spec; + + if (attr_type != NULL) + { + if (UP_IS_NATIVE(attr_type) && + IDL_tree_property_get(attr_type, "nsid") == NULL && + IDL_tree_property_get(attr_type, "domstring") == NULL && + IDL_tree_property_get(attr_type, "utf8string") == NULL && + IDL_tree_property_get(attr_type, "cstring") == NULL && + IDL_tree_property_get(attr_type, "astring") == NULL) + { + IDL_tree_error(attr_tree, + "attributes in [scriptable] interfaces that are " + "non-scriptable because they refer to native " + "types must be marked [noscript]\n"); + return FALSE; + } + /* + * We currently don't support properties of type nsid that aren't + * pointers or references, unless they are marked [notxpcom} and + * must be read-only + */ + + if ((IDL_tree_property_get(ident, "notxpcom") == NULL || !(IDL_ATTR_DCL(attr_tree).f_readonly)) && + IDL_tree_property_get(attr_type,"nsid") != NULL && + IDL_tree_property_get(attr_type,"ptr") == NULL && + IDL_tree_property_get(attr_type,"ref") == NULL) + { + IDL_tree_error(attr_tree, + "Feature not currently supported: " + "attributes with a type of nsid must be marked " + "either [ptr] or [ref], or " + "else must be marked [notxpcom] " + "and must be read-only\n"); + return FALSE; + } + + /* + * Run additional error checks on the attribute type if targetting an + * older version of XPConnect. + */ + + if (!verify_type_fits_version(attr_type, attr_tree)) + return FALSE; + } + + if (IDL_LIST(IDL_ATTR_DCL(attr_tree).simple_declarations).next != NULL) + { + IDL_tree_error(attr_tree, + "multiple attributes in a single declaration is not supported\n"); + return FALSE; + } + return TRUE; +} + +/* + * Find the underlying type of an identifier typedef. + * + * All the needed tree-walking seems pretty shaky; isn't there something in + * libIDL to automate this? + */ +IDL_tree /* IDL_TYPE_DCL */ +find_underlying_type(IDL_tree typedef_ident) +{ + IDL_tree up; + + if (typedef_ident == NULL || IDL_NODE_TYPE(typedef_ident) != IDLN_IDENT) + return NULL; + + up = IDL_NODE_UP(typedef_ident); + if (up == NULL || IDL_NODE_TYPE(up) != IDLN_LIST) + return NULL; + up = IDL_NODE_UP(up); + if (up == NULL || IDL_NODE_TYPE(up) != IDLN_TYPE_DCL) + return NULL; + + return IDL_TYPE_DCL(up).type_spec; +} + +static IDL_tree /* IDL_PARAM_DCL */ +find_named_parameter(IDL_tree method_tree, const char *param_name) +{ + IDL_tree iter; + for (iter = IDL_OP_DCL(method_tree).parameter_dcls; iter; + iter = IDL_LIST(iter).next) + { + IDL_tree param = IDL_LIST(iter).data; + IDL_tree simple_decl = IDL_PARAM_DCL(param).simple_declarator; + const char *current_name = IDL_IDENT(simple_decl).str; + if (strcmp(current_name, param_name) == 0) + return param; + } + return NULL; +} + +typedef enum ParamAttrType { + IID_IS, + LENGTH_IS, + SIZE_IS +} ParamAttrType; + +/* + * Check that parameters referred to by attributes such as size_is exist and + * refer to parameters of the appropriate type. + */ +static gboolean +check_param_attribute(IDL_tree method_tree, IDL_tree param, + ParamAttrType whattocheck) +{ + const char *method_name = IDL_IDENT(IDL_OP_DCL(method_tree).ident).str; + const char *referred_name = NULL; + IDL_tree param_type = IDL_PARAM_DCL(param).param_type_spec; + IDL_tree simple_decl = IDL_PARAM_DCL(param).simple_declarator; + const char *param_name = IDL_IDENT(simple_decl).str; + const char *attr_name; + const char *needed_type; + + if (whattocheck == IID_IS) { + attr_name = "iid_is"; + needed_type = "IID"; + } else if (whattocheck == LENGTH_IS) { + attr_name = "length_is"; + needed_type = "unsigned long (or PRUint32)"; + } else if (whattocheck == SIZE_IS) { + attr_name = "size_is"; + needed_type = "unsigned long (or PRUint32)"; + } else { + XPT_ASSERT("asked to check an unknown attribute type!"); + return TRUE; + } + + referred_name = IDL_tree_property_get(simple_decl, attr_name); + if (referred_name != NULL) { + IDL_tree referred_param = find_named_parameter(method_tree, + referred_name); + IDL_tree referred_param_type; + if (referred_param == NULL) { + IDL_tree_error(method_tree, + "attribute [%s(%s)] refers to missing " + "parameter \"%s\"", + attr_name, referred_name, referred_name); + return FALSE; + } + if (referred_param == param) { + IDL_tree_error(method_tree, + "attribute [%s(%s)] refers to it's own parameter", + attr_name, referred_name); + return FALSE; + } + + referred_param_type = IDL_PARAM_DCL(referred_param).param_type_spec; + if (whattocheck == IID_IS) { + /* require IID type */ + if (IDL_tree_property_get(referred_param_type, "nsid") == NULL) { + IDL_tree_error(method_tree, + "target \"%s\" of [%s(%s)] attribute " + "must be of %s type", + referred_name, attr_name, referred_name, + needed_type); + return FALSE; + } + } else if (whattocheck == LENGTH_IS || whattocheck == SIZE_IS) { + /* require PRUint32 type */ + IDL_tree real_type; + + /* Could be a typedef; try to map it to the real type. */ + real_type = find_underlying_type(referred_param_type); + real_type = real_type ? real_type : referred_param_type; + + if (IDL_NODE_TYPE(real_type) != IDLN_TYPE_INTEGER || + IDL_TYPE_INTEGER(real_type).f_signed != FALSE || + IDL_TYPE_INTEGER(real_type).f_type != IDL_INTEGER_TYPE_LONG) + { + IDL_tree_error(method_tree, + "target \"%s\" of [%s(%s)] attribute " + "must be of %s type", + referred_name, attr_name, referred_name, + needed_type); + + return FALSE; + } + } + } + + return TRUE; +} + + +/* + * Common method verification code, called by *op_dcl in the various backends. + */ +gboolean +verify_method_declaration(IDL_tree method_tree) +{ + struct _IDL_OP_DCL *op = &IDL_OP_DCL(method_tree); + IDL_tree iface; + IDL_tree iter; + gboolean notxpcom; + gboolean scriptable_interface; + gboolean scriptable_method; + gboolean seen_retval = FALSE; + const char *method_name = IDL_IDENT(IDL_OP_DCL(method_tree).ident).str; + + /* We don't support attributes named IID, conflicts with static GetIID + * member. The conflict is due to certain compilers (VC++) choosing a + * different vtable order, placing GetIID at the beginning regardless + * of it's placement + */ + if (strcmp(method_name, "GetIID") == 0) { + IDL_tree_error(method_tree, + "Methods named GetIID not supported, causes vtable " + "ordering problems"); + return FALSE; + } + if (op->f_varargs) { + /* We don't currently support varargs. */ + IDL_tree_error(method_tree, "varargs are not currently supported"); + return FALSE; + } + + /* + * Verify that we've been called on an interface, and decide if the + * interface was marked [scriptable]. + */ + if (IDL_NODE_UP(method_tree) && IDL_NODE_UP(IDL_NODE_UP(method_tree)) && + IDL_NODE_TYPE(iface = IDL_NODE_UP(IDL_NODE_UP(method_tree))) + == IDLN_INTERFACE) + { + scriptable_interface = + (IDL_tree_property_get(IDL_INTERFACE(iface).ident, "scriptable") + != NULL); + } else { + IDL_tree_error(method_tree, + "verify_method_declaration called on a non-interface?"); + return FALSE; + } + + /* + * Require that any method in an interface marked as [scriptable], that + * *isn't* scriptable because it refers to some native type, be marked + * [noscript] or [notxpcom]. + * + * Also check that iid_is points to nsid, and length_is, size_is points + * to unsigned long. + */ + notxpcom = IDL_tree_property_get(op->ident, "notxpcom") != NULL; + + scriptable_method = scriptable_interface && + !notxpcom && + IDL_tree_property_get(op->ident, "noscript") == NULL; + + /* Loop through the parameters and check. */ + for (iter = op->parameter_dcls; iter; iter = IDL_LIST(iter).next) { + IDL_tree param = IDL_LIST(iter).data; + IDL_tree param_type = + IDL_PARAM_DCL(param).param_type_spec; + IDL_tree simple_decl = + IDL_PARAM_DCL(param).simple_declarator; + const char *param_name = IDL_IDENT(simple_decl).str; + + /* + * Reject this method if it should be scriptable and some parameter is + * native that isn't marked with either nsid, domstring, utf8string, + * cstring, astring or iid_is. + */ + if (scriptable_method && + UP_IS_NATIVE(param_type) && + IDL_tree_property_get(param_type, "nsid") == NULL && + IDL_tree_property_get(simple_decl, "iid_is") == NULL && + IDL_tree_property_get(param_type, "domstring") == NULL && + IDL_tree_property_get(param_type, "utf8string") == NULL && + IDL_tree_property_get(param_type, "cstring") == NULL && + IDL_tree_property_get(param_type, "astring") == NULL) + { + IDL_tree_error(method_tree, + "methods in [scriptable] interfaces that are " + "non-scriptable because they refer to native " + "types (parameter \"%s\") must be marked " + "[noscript]", param_name); + return FALSE; + } + + /* + * nsid's parameters that aren't ptr's or ref's are not currently + * supported in xpcom or non-xpcom (marked with [notxpcom]) methods + * as input parameters + */ + if (!(notxpcom && IDL_PARAM_DCL(param).attr != IDL_PARAM_IN) && + IDL_tree_property_get(param_type, "nsid") != NULL && + IDL_tree_property_get(param_type, "ptr") == NULL && + IDL_tree_property_get(param_type, "ref") == NULL) + { + IDL_tree_error(method_tree, + "Feature currently not supported: " + "parameter \"%s\" is of type nsid and " + "must be marked either [ptr] or [ref] " + "or method \"%s\" must be marked [notxpcom] " + "and must not be an input parameter", + param_name, + method_name); + return FALSE; + } + /* + * Sanity checks on return values. + */ + if (IDL_tree_property_get(simple_decl, "retval") != NULL) { + if (IDL_LIST(iter).next != NULL) { + IDL_tree_error(method_tree, + "only the last parameter can be marked [retval]"); + return FALSE; + } + if (op->op_type_spec) { + IDL_tree_error(method_tree, + "can't have [retval] with non-void return type"); + return FALSE; + } + /* In case XPConnect relaxes the retval-is-last restriction. */ + if (seen_retval) { + IDL_tree_error(method_tree, + "can't have more than one [retval] parameter"); + return FALSE; + } + seen_retval = TRUE; + } + + /* + * Confirm that [shared] attributes are only used with string, wstring, + * or native (but not nsid, domstring, utf8string, cstring or astring) + * and can't be used with [array]. + */ + if (IDL_tree_property_get(simple_decl, "shared") != NULL) { + IDL_tree real_type; + real_type = find_underlying_type(param_type); + real_type = real_type ? real_type : param_type; + + if (IDL_tree_property_get(simple_decl, "array") != NULL) { + IDL_tree_error(method_tree, + "[shared] parameter \"%s\" cannot " + "be of array type", param_name); + return FALSE; + } + + if (!(IDL_NODE_TYPE(real_type) == IDLN_TYPE_STRING || + IDL_NODE_TYPE(real_type) == IDLN_TYPE_WIDE_STRING || + (UP_IS_NATIVE(real_type) && + !IDL_tree_property_get(real_type, "nsid") && + !IDL_tree_property_get(real_type, "domstring") && + !IDL_tree_property_get(real_type, "utf8string") && + !IDL_tree_property_get(real_type, "cstring") && + !IDL_tree_property_get(real_type, "astring")))) + { + IDL_tree_error(method_tree, + "[shared] parameter \"%s\" must be of type " + "string, wstring or native", param_name); + return FALSE; + } + } + + /* + * inout is not allowed with "domstring", "UTF8String", "CString" + * and "AString" types + */ + if (IDL_PARAM_DCL(param).attr == IDL_PARAM_INOUT && + UP_IS_NATIVE(param_type) && + (IDL_tree_property_get(param_type, "domstring") != NULL || + IDL_tree_property_get(param_type, "utf8string") != NULL || + IDL_tree_property_get(param_type, "cstring") != NULL || + IDL_tree_property_get(param_type, "astring") != NULL )) { + IDL_tree_error(method_tree, + "[domstring], [utf8string], [cstring], [astring] " + "types cannot be used as inout parameters"); + return FALSE; + } + + + /* + * arrays of domstring, utf8string, cstring, astring types not allowed + */ + if (IDL_tree_property_get(simple_decl, "array") != NULL && + UP_IS_NATIVE(param_type) && + (IDL_tree_property_get(param_type, "domstring") != NULL || + IDL_tree_property_get(param_type, "utf8string") != NULL || + IDL_tree_property_get(param_type, "cstring") != NULL || + IDL_tree_property_get(param_type, "astring") != NULL)) { + IDL_tree_error(method_tree, + "[domstring], [utf8string], [cstring], [astring] " + "types cannot be used in array parameters"); + return FALSE; + } + + if (!check_param_attribute(method_tree, param, IID_IS) || + !check_param_attribute(method_tree, param, LENGTH_IS) || + !check_param_attribute(method_tree, param, SIZE_IS)) + return FALSE; + + /* + * Run additional error checks on the parameter type if targetting an + * older version of XPConnect. + */ + + if (!verify_type_fits_version(param_type, method_tree)) + return FALSE; + + } + + /* XXX q: can return type be nsid? */ + /* Native return type? */ + if (scriptable_method && + op->op_type_spec != NULL && UP_IS_NATIVE(op->op_type_spec) && + IDL_tree_property_get(op->op_type_spec, "nsid") == NULL && + IDL_tree_property_get(op->op_type_spec, "domstring") == NULL && + IDL_tree_property_get(op->op_type_spec, "utf8string") == NULL && + IDL_tree_property_get(op->op_type_spec, "cstring") == NULL && + IDL_tree_property_get(op->op_type_spec, "astring") == NULL) + { + IDL_tree_error(method_tree, + "methods in [scriptable] interfaces that are " + "non-scriptable because they return native " + "types must be marked [noscript]"); + return FALSE; + } + + + /* + * nsid's parameters that aren't ptr's or ref's are not currently + * supported in xpcom + */ + if (!notxpcom && + op->op_type_spec != NULL && + IDL_tree_property_get(op->op_type_spec, "nsid") != NULL && + IDL_tree_property_get(op->op_type_spec, "ptr") == NULL && + IDL_tree_property_get(op->op_type_spec, "ref") == NULL) + { + IDL_tree_error(method_tree, + "Feature currently not supported: " + "return value is of type nsid and " + "must be marked either [ptr] or [ref], " + "or else method \"%s\" must be marked [notxpcom] ", + method_name); + return FALSE; + } + + /* + * Run additional error checks on the return type if targetting an + * older version of XPConnect. + */ + + if (op->op_type_spec != NULL && + !verify_type_fits_version(op->op_type_spec, method_tree)) + { + return FALSE; + } + + return TRUE; +} + +/* + * Verify that a native declaration has an associated C++ expression, i.e. that + * it's of the form native () + */ +gboolean +check_native(TreeState *state) +{ + char *native_name; + /* require that native declarations give a native type */ + if (IDL_NATIVE(state->tree).user_type) + return TRUE; + native_name = IDL_IDENT(IDL_NATIVE(state->tree).ident).str; + IDL_tree_error(state->tree, + "``native %s;'' needs C++ type: ``native %s();''", + native_name, native_name); + return FALSE; +} + +/* + * Print a GSList as char strings to a file. + */ +void +printlist(FILE *outfile, GSList *slist) +{ + guint i; + guint len = g_slist_length(slist); + + for(i = 0; i < len; i++) { + fprintf(outfile, + "%s\n", (char *)g_slist_nth_data(slist, i)); + } +} + +void +xpidl_list_foreach(IDL_tree p, IDL_tree_func foreach, gpointer user_data) +{ + IDL_tree_func_data tfd; + + while (p) { + struct _IDL_LIST *list = &IDL_LIST(p); + tfd.tree = list->data; + if (!foreach(&tfd, user_data)) + return; + p = list->next; + } +} + +/* + * Verify that the interface declaration is correct + */ +gboolean +verify_interface_declaration(IDL_tree interface_tree) +{ + IDL_tree iter; + /* + * If we have the scriptable attribute then make sure all of our direct + * parents have it as well. + * NOTE: We don't recurse since all interfaces will fall through here + */ + if (IDL_tree_property_get(IDL_INTERFACE(interface_tree).ident, + "scriptable")) { + for (iter = IDL_INTERFACE(interface_tree).inheritance_spec; iter; + iter = IDL_LIST(iter).next) { + if (IDL_tree_property_get( + IDL_INTERFACE(iter).ident, "scriptable") == 0) { + XPIDL_WARNING((interface_tree,IDL_WARNING1, + "%s is scriptable but inherits from the non-scriptable interface %s\n", + IDL_IDENT(IDL_INTERFACE(interface_tree).ident).str, + IDL_IDENT(IDL_INTERFACE(iter).ident).str)); + } + } + } + return TRUE; +} + +/* + * Return a pointer to the start of the base filename of path + */ +char * +xpidl_basename(const char * path) +{ + char * result = g_path_get_basename(path); + /* + *If this is windows then we'll handle either / or \ as a separator + * g_basename only handles \ for windows + */ +#if defined(XP_WIN32) +# error adapt regarding g_basename() vs. g_path_get_basename()! + const char * slash = strrchr(path, '/'); + /* If we found a slash and its after the current default OS separator */ + if (slash != NULL && (slash > result)) + result = slash + 1; +#endif + return result; +} diff --git a/src/libs/xpcom18a4/xpcom/typelib/xpt/.cvsignore b/src/libs/xpcom18a4/xpcom/typelib/xpt/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/typelib/xpt/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/xpcom/typelib/xpt/Makefile.in b/src/libs/xpcom18a4/xpcom/typelib/xpt/Makefile.in new file mode 100644 index 00000000..1447128f --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/typelib/xpt/Makefile.in @@ -0,0 +1,50 @@ +# +# ***** 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.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of 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 ***** + +DEPTH = ../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = xpcom + +DIRS = public src tools + +include $(topsrcdir)/config/rules.mk + diff --git a/src/libs/xpcom18a4/xpcom/typelib/xpt/public/.cvsignore b/src/libs/xpcom18a4/xpcom/typelib/xpt/public/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/typelib/xpt/public/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/xpcom/typelib/xpt/public/Makefile.in b/src/libs/xpcom18a4/xpcom/typelib/xpt/public/Makefile.in new file mode 100644 index 00000000..3e452486 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/typelib/xpt/public/Makefile.in @@ -0,0 +1,51 @@ +# +# ***** 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.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of 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 ***** + +DEPTH = ../../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = xpcom + +EXPORTS = xpt_arena.h xpt_struct.h xpt_xdr.h +EXPORTS := $(addprefix $(srcdir)/, $(EXPORTS)) + +include $(topsrcdir)/config/rules.mk + diff --git a/src/libs/xpcom18a4/xpcom/typelib/xpt/public/xpt_arena.h b/src/libs/xpcom18a4/xpcom/typelib/xpt/public/xpt_arena.h new file mode 100644 index 00000000..2b277467 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/typelib/xpt/public/xpt_arena.h @@ -0,0 +1,145 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* + * Simple arena allocator for xpt (which avoids using NSPR). + */ + +#ifndef __xpt_arena_h__ +#define __xpt_arena_h__ + +#include "prtypes.h" +#include + +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +#define XPT_NewArena VBoxNsxpXPT_NewArena +#define XPT_ArenaMalloc VBoxNsxpXPT_ArenaMalloc +#define XPT_DestroyArena VBoxNsxpXPT_DestroyArena +#define XPT_ArenaFree VBoxNsxpXPT_ArenaFree +#define XPT_DestroyArena VBoxNsxpXPT_DestroyArena +#define XPT_DumpStats VBoxNsxpXPT_DumpStats +#define XPT_NotifyDoneLoading VBoxNsxpXPT_NotifyDoneLoading +#define XPT_ArenaStrDup VBoxNsxpXPT_ArenaStrDup +#define XPT_AssertFailed VBoxNsxpXPT_AssertFailed +#endif /* VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + +/* + * The linkage of XPT API functions differs depending on whether the file is + * used within the XPT library or not. Any source file within the XPT + * library should define EXPORT_XPT_API whereas any client of the library + * should not. + */ +#ifdef EXPORT_XPT_API +#define XPT_PUBLIC_API(t) PR_IMPLEMENT(t) +#define XPT_PUBLIC_DATA(t) PR_IMPLEMENT_DATA(t) +#else +#ifdef _WIN32 +# define XPT_PUBLIC_API(t) __declspec(dllimport) t +# define XPT_PUBLIC_DATA(t) __declspec(dllimport) t +#else +# define XPT_PUBLIC_API(t) PR_IMPLEMENT(t) +# define XPT_PUBLIC_DATA(t) t +#endif +#endif +#define XPT_FRIEND_API(t) XPT_PUBLIC_API(t) +#define XPT_FRIEND_DATA(t) XPT_PUBLIC_DATA(t) + +PR_BEGIN_EXTERN_C + +/* + * Simple Arena support. Use with caution! + */ + +typedef struct XPTArena XPTArena; + +XPT_PUBLIC_API(XPTArena *) +XPT_NewArena(PRUint32 block_size, size_t alignment, const char* name); + +XPT_PUBLIC_API(void) +XPT_DestroyArena(XPTArena *arena); + +XPT_PUBLIC_API(void) +XPT_DumpStats(XPTArena *arena); + +XPT_PUBLIC_API(void *) +XPT_ArenaMalloc(XPTArena *arena, size_t size); + +XPT_PUBLIC_API(char *) +XPT_ArenaStrDup(XPTArena *arena, const char * s); + +XPT_PUBLIC_API(void) +XPT_NotifyDoneLoading(XPTArena *arena); + +XPT_PUBLIC_API(void) +XPT_ArenaFree(XPTArena *arena, void* block); + +/* --------------------------------------------------------- */ + +#define XPT_MALLOC(_arena, _bytes) \ + XPT_ArenaMalloc((_arena), (_bytes)) + +#ifdef DEBUG +#define XPT_FREE(_arena, _ptr) \ + XPT_ArenaFree((_arena), (_ptr)) +#else +#define XPT_FREE(_arena, _ptr) \ + ((void)0) +#endif + +#define XPT_STRDUP(_arena, _s) \ + XPT_ArenaStrDup((_arena), (_s)) + +#define XPT_CALLOC(_arena, _size) XPT_MALLOC((_arena), (_size)) +#define XPT_NEW(_arena, _struct) ((_struct *) XPT_MALLOC((_arena), sizeof(_struct))) +#define XPT_NEWZAP(_arena, _struct) XPT_NEW((_arena), _struct) +#define XPT_DELETE(_arena, _ptr) do{XPT_FREE((_arena), (_ptr)); ((_ptr)) = NULL;}while(0) +#define XPT_FREEIF(_arena, _ptr) do{if ((_ptr)) XPT_FREE((_arena), (_ptr));}while(0) + +/* --------------------------------------------------------- */ + +#ifdef DEBUG +XPT_PUBLIC_API(void) +XPT_AssertFailed(const char *s, const char *file, PRUint32 lineno); +#define XPT_ASSERT(_expr) \ + ((_expr)?((void)0):XPT_AssertFailed(# _expr, __FILE__, __LINE__)) +#else +#define XPT_ASSERT(_expr) ((void)0) +#endif + +PR_END_EXTERN_C + +#endif /* __xpt_arena_h__ */ diff --git a/src/libs/xpcom18a4/xpcom/typelib/xpt/public/xpt_struct.h b/src/libs/xpcom18a4/xpcom/typelib/xpt/public/xpt_struct.h new file mode 100644 index 00000000..c7f36f2d --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/typelib/xpt/public/xpt_struct.h @@ -0,0 +1,562 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* + * Structures matching the in-memory representation of typelib structures. + * http://www.mozilla.org/scriptable/typelib_file.html + */ + +#ifndef __xpt_struct_h__ +#define __xpt_struct_h__ + +#include "xpt_arena.h" + +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +#define XPT_NewHeader VBoxNsxpXPT_NewHeader +#define XPT_NewStringZ VBoxNsxpXPT_NewStringZ +#define XPT_NewAnnotation VBoxNsxpXPT_NewAnnotation +#define XPT_SizeOfHeaderBlock VBoxNsxpXPT_SizeOfHeaderBlock +#define XPT_NewInterfaceDescriptor VBoxNsxpXPT_NewInterfaceDescriptor +#define XPT_FillInterfaceDirectoryEntry VBoxNsxpXPT_FillInterfaceDirectoryEntry +#define XPT_FillMethodDescriptor VBoxNsxpXPT_FillMethodDescriptor +#define XPT_FreeHeader VBoxNsxpXPT_FreeHeader +#define XPT_ParseVersionString VBoxNsxpXPT_ParseVersionString +#define XPT_DestroyInterfaceDirectoryEntry VBoxNsxpXPT_DestroyInterfaceDirectoryEntry +#define XPT_FillParamDescriptor VBoxNsxpXPT_FillParamDescriptor +#define XPT_FreeInterfaceDescriptor VBoxNsxpXPT_FreeInterfaceDescriptor +#define XPT_InterfaceDescriptorAddConsts VBoxNsxpXPT_InterfaceDescriptorAddConsts +#define XPT_InterfaceDescriptorAddMethods VBoxNsxpXPT_InterfaceDescriptorAddMethods +#define XPT_InterfaceDescriptorAddTypes VBoxNsxpXPT_InterfaceDescriptorAddTypes +#define XPT_GetInterfaceIndexByName VBoxNsxpXPT_GetInterfaceIndexByName +#define XPT_NewString VBoxNsxpXPT_NewString +#define XPT_SizeOfHeader VBoxNsxpXPT_SizeOfHeader +#endif /* VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + +PR_BEGIN_EXTERN_C + +/* + * Originally, I was going to have structures that exactly matched the on-disk + * representation, but that proved difficult: different compilers can pack + * their structs differently, and that makes overlaying them atop a + * read-from-disk byte buffer troublesome. So now I just have some structures + * that are used in memory, and we're going to write a nice XDR library to + * write them to disk and stuff. It is pure joy. -- shaver + */ + +/* Structures for the typelib components */ + +typedef struct XPTHeader XPTHeader; +typedef struct XPTInterfaceDirectoryEntry XPTInterfaceDirectoryEntry; +typedef struct XPTInterfaceDescriptor XPTInterfaceDescriptor; +typedef struct XPTConstDescriptor XPTConstDescriptor; +typedef struct XPTMethodDescriptor XPTMethodDescriptor; +typedef struct XPTParamDescriptor XPTParamDescriptor; +typedef struct XPTTypeDescriptor XPTTypeDescriptor; +typedef struct XPTTypeDescriptorPrefix XPTTypeDescriptorPrefix; +typedef struct XPTString XPTString; +typedef struct XPTAnnotation XPTAnnotation; +#ifndef nsID_h__ +/* + * We can't include nsID.h, because it's full of C++ goop and we're not doing + * C++ here, so we define our own minimal struct. We protect against multiple + * definitions of this struct, though, and use the same field naming. + */ +struct nsID { + PRUint32 m0; + PRUint16 m1; + PRUint16 m2; + PRUint8 m3[8]; +}; + +typedef struct nsID nsID; +#endif + +#define XPT_COPY_IID(to, from) \ + (to).m0 = (from).m0; \ + (to).m1 = (from).m1; \ + (to).m2 = (from).m2; \ + (to).m3[0] = (from).m3[0]; \ + (to).m3[1] = (from).m3[1]; \ + (to).m3[2] = (from).m3[2]; \ + (to).m3[3] = (from).m3[3]; \ + (to).m3[4] = (from).m3[4]; \ + (to).m3[5] = (from).m3[5]; \ + (to).m3[6] = (from).m3[6]; \ + (to).m3[7] = (from).m3[7]; + + +/* + * Every XPCOM typelib file begins with a header. + */ +struct XPTHeader { + PRUint8 magic[16]; + PRUint8 major_version; + PRUint8 minor_version; + PRUint16 num_interfaces; + PRUint32 file_length; + XPTInterfaceDirectoryEntry *interface_directory; + PRUint32 data_pool; + XPTAnnotation *annotations; +}; + +#define XPT_MAGIC "XPCOM\nTypeLib\r\n\032" +/* For error messages. */ +#define XPT_MAGIC_STRING "XPCOM\\nTypeLib\\r\\n\\032" +#define XPT_MAJOR_VERSION 0x01 +#define XPT_MINOR_VERSION 0x02 + +/* Any file with a major version number of XPT_MAJOR_INCOMPATIBLE_VERSION + * or higher is to be considered incompatible by this version of xpt and + * we will refuse to read it. We will return a header with magic, major and + * minor versions set from the file. num_interfaces and file_length will be + * set to zero to confirm our inability to read the file; i.e. even if some + * client of this library gets out of sync with us regarding the agreed upon + * value for XPT_MAJOR_INCOMPATIBLE_VERSION, anytime num_interfaces and + * file_length are both zero we *know* that this library refused to read the + * file due to version imcompatibility. + */ +#define XPT_MAJOR_INCOMPATIBLE_VERSION 0x02 + +/* + * The "[-t version number]" cmd line parameter to the XPIDL compiler and XPT + * linker specifies the major and minor version number of the output + * type library. + * + * The goal is for the compiler to check that the input IDL file only uses + * constructs that are supported in the version specified. The linker will + * check that all typelib files it reads are of the version specified or + * below. + * + * Both the compiler and the linker will report errors and abort if these + * checks fail. + * + * When you rev up major or minor versions of the type library in the future, + * think about the new stuff that you added to the type library and add checks + * to make sure that occurrences of that new "stuff" will get caught when [-t + * version number] is used with the compiler. Here's what you'll probably + * have to do each time you rev up major/minor versions: + * + * 1) Add the current version number string (before your change) to the + * XPT_TYPELIB_VERSIONS list. + * + * 2) Do your changes add new features to XPIDL? Ensure that those new + * features are rejected by the XPIDL compiler when any version number in + * the XPT_TYPELIB_VERSIONS list is specified on the command line. The + * one place that currently does this kind of error checking is the function + * verify_type_fits_version() in xpidl_util.c. It currently checks + * attribute types, parameter types, and return types. You'll probably have + * to add to it or generalize it further based on what kind of changes you + * are making. + * + * 3) You will probably NOT need to make any changes to the error checking + * in the linker. + */ + +#define XPT_VERSION_UNKNOWN 0 +#define XPT_VERSION_UNSUPPORTED 1 +#define XPT_VERSION_OLD 2 +#define XPT_VERSION_CURRENT 3 + +typedef struct { + const char* str; + PRUint8 major; + PRUint8 minor; + PRUint16 code; +} XPT_TYPELIB_VERSIONS_STRUCT; + +/* Currently accepted list of versions for typelibs */ +#define XPT_TYPELIB_VERSIONS { \ + {"1.0", 1, 0, XPT_VERSION_UNSUPPORTED}, \ + {"1.1", 1, 1, XPT_VERSION_OLD}, \ + {"1.2", 1, 2, XPT_VERSION_CURRENT} \ +} + +extern XPT_PUBLIC_API(PRUint16) +XPT_ParseVersionString(const char* str, PRUint8* major, PRUint8* minor); + +extern XPT_PUBLIC_API(XPTHeader *) +XPT_NewHeader(XPTArena *arena, PRUint16 num_interfaces, + PRUint8 major_version, PRUint8 minor_version); + +extern XPT_PUBLIC_API(void) +XPT_FreeHeader(XPTArena *arena, XPTHeader* aHeader); + +/* size of header and annotations */ +extern XPT_PUBLIC_API(PRUint32) +XPT_SizeOfHeader(XPTHeader *header); + +/* size of header and annotations and InterfaceDirectoryEntries */ +extern XPT_PUBLIC_API(PRUint32) +XPT_SizeOfHeaderBlock(XPTHeader *header); + +/* + * A contiguous array of fixed-size InterfaceDirectoryEntry records begins at + * the byte offset identified by the interface_directory field in the file + * header. The array is used to quickly locate an interface description + * using its IID. No interface should appear more than once in the array. + */ +struct XPTInterfaceDirectoryEntry { + nsID iid; + char *name; + char *name_space; + XPTInterfaceDescriptor *interface_descriptor; + +#if 0 /* not yet */ + /* not stored on disk */ + PRUint32 offset; /* the offset for an ID still to be read */ +#endif +}; + +extern XPT_PUBLIC_API(PRBool) +XPT_FillInterfaceDirectoryEntry(XPTArena *arena, + XPTInterfaceDirectoryEntry *ide, + nsID *iid, char *name, char *name_space, + XPTInterfaceDescriptor *descriptor); + +extern XPT_PUBLIC_API(void) +XPT_DestroyInterfaceDirectoryEntry(XPTArena *arena, + XPTInterfaceDirectoryEntry* ide); + +/* + * An InterfaceDescriptor is a variable-size record used to describe a + * single XPCOM interface, including all of its methods. + */ +struct XPTInterfaceDescriptor { + PRUint16 parent_interface; + PRUint16 num_methods; + XPTMethodDescriptor *method_descriptors; + PRUint16 num_constants; + XPTConstDescriptor *const_descriptors; + PRUint8 flags; + + /* additional_types are used for arrays where we may need multiple + * XPTTypeDescriptors for a single XPTMethodDescriptor. Since we still + * want to have a simple array of XPTMethodDescriptor (each with a single + * embedded XPTTypeDescriptor), a XPTTypeDescriptor can have a reference + * to an 'additional_type'. That reference is an index in this + * "additional_types" array. So a given XPTMethodDescriptor might have + * a whole chain of these XPTTypeDescriptors to represent, say, a multi + * dimensional array. + * + * Note that in the typelib file these additional types are stored 'inline' + * in the MethodDescriptor. But, in the typelib MethodDescriptors can be + * of varying sizes, where in XPT's in memory mapping of the data we want + * them to be of fixed size. This additional_types scheme is here to allow + * for that. + */ + + XPTTypeDescriptor *additional_types; + PRUint16 num_additional_types; +}; + +#define XPT_ID_SCRIPTABLE 0x80 +#define XPT_ID_FUNCTION 0x40 +#define XPT_ID_FLAGMASK 0xc0 +#define XPT_ID_TAGMASK (~XPT_ID_FLAGMASK) +#define XPT_ID_TAG(id) ((id).flags & XPT_ID_TAGMASK) + +#define XPT_ID_IS_SCRIPTABLE(flags) (flags & XPT_ID_SCRIPTABLE) +#define XPT_ID_IS_FUNCTION(flags) (flags & XPT_ID_FUNCTION) + +extern XPT_PUBLIC_API(PRBool) +XPT_GetInterfaceIndexByName(XPTInterfaceDirectoryEntry *ide_block, + PRUint16 num_interfaces, char *name, + PRUint16 *indexp); + +extern XPT_PUBLIC_API(XPTInterfaceDescriptor *) +XPT_NewInterfaceDescriptor(XPTArena *arena, + PRUint16 parent_interface, PRUint16 num_methods, + PRUint16 num_constants, PRUint8 flags); + +extern XPT_PUBLIC_API(void) +XPT_FreeInterfaceDescriptor(XPTArena *arena, XPTInterfaceDescriptor* id); + +extern XPT_PUBLIC_API(PRBool) +XPT_InterfaceDescriptorAddTypes(XPTArena *arena, XPTInterfaceDescriptor *id, + PRUint16 num); + +extern XPT_PUBLIC_API(PRBool) +XPT_InterfaceDescriptorAddMethods(XPTArena *arena, XPTInterfaceDescriptor *id, + PRUint16 num); + +extern XPT_PUBLIC_API(PRBool) +XPT_InterfaceDescriptorAddConsts(XPTArena *arena, XPTInterfaceDescriptor *id, + PRUint16 num); + +/* + * This is our special string struct with a length value associated with it, + * which means that it can contains embedded NULs. + */ +struct XPTString { + PRUint16 length; + char *bytes; +}; + +extern XPT_PUBLIC_API(XPTString *) +XPT_NewString(XPTArena *arena, PRUint16 length, char *bytes); + +extern XPT_PUBLIC_API(XPTString *) +XPT_NewStringZ(XPTArena *arena, char *bytes); + +/* + * A TypeDescriptor is a variable-size record used to identify the type of a + * method argument or return value. + * + * There are three types of TypeDescriptors: + * + * SimpleTypeDescriptor + * InterfaceTypeDescriptor + * InterfaceIsTypeDescriptor + * + * The tag field in the prefix indicates which of the variant TypeDescriptor + * records is being used, and hence the way any remaining fields should be + * parsed. Values from 0 to 17 refer to SimpleTypeDescriptors. The value 18 + * designates an InterfaceTypeDescriptor, while 19 represents an + * InterfaceIsTypeDescriptor. + */ + +/* why bother with a struct? - other code relies on this being a struct */ +struct XPTTypeDescriptorPrefix { + PRUint8 flags; +}; + +/* flag bits -- fur and jband were right, I was miserably wrong */ +#define XPT_TDP_POINTER 0x80 +#define XPT_TDP_UNIQUE_POINTER 0x40 +#define XPT_TDP_REFERENCE 0x20 +#define XPT_TDP_FLAGMASK 0xe0 +#define XPT_TDP_TAGMASK (~XPT_TDP_FLAGMASK) +#define XPT_TDP_TAG(tdp) ((tdp).flags & XPT_TDP_TAGMASK) + +#define XPT_TDP_IS_POINTER(flags) (flags & XPT_TDP_POINTER) +#define XPT_TDP_IS_UNIQUE_POINTER(flags) (flags & XPT_TDP_UNIQUE_POINTER) +#define XPT_TDP_IS_REFERENCE(flags) (flags & XPT_TDP_REFERENCE) + +/* + * The following enum maps mnemonic names to the different numeric values + * of XPTTypeDescriptor->tag. + */ +enum XPTTypeDescriptorTags { + TD_INT8 = 0, + TD_INT16 = 1, + TD_INT32 = 2, + TD_INT64 = 3, + TD_UINT8 = 4, + TD_UINT16 = 5, + TD_UINT32 = 6, + TD_UINT64 = 7, + TD_FLOAT = 8, + TD_DOUBLE = 9, + TD_BOOL = 10, + TD_CHAR = 11, + TD_WCHAR = 12, + TD_VOID = 13, + TD_PNSIID = 14, + TD_DOMSTRING = 15, + TD_PSTRING = 16, + TD_PWSTRING = 17, + TD_INTERFACE_TYPE = 18, + TD_INTERFACE_IS_TYPE = 19, + TD_ARRAY = 20, + TD_PSTRING_SIZE_IS = 21, + TD_PWSTRING_SIZE_IS = 22, + TD_UTF8STRING = 23, + TD_CSTRING = 24, + TD_ASTRING = 25 +}; + +struct XPTTypeDescriptor { + XPTTypeDescriptorPrefix prefix; + PRUint8 argnum; /* used for iid_is and size_is */ + PRUint8 argnum2; /* used for length_is */ + union { + PRUint16 iface; /* used for TD_INTERFACE_TYPE */ + PRUint16 additional_type; /* used for TD_ARRAY */ + } type; +}; + +#define XPT_COPY_TYPE(to, from) \ + (to).prefix.flags = (from).prefix.flags; \ + (to).argnum = (from).argnum; \ + (to).argnum2 = (from).argnum2; \ + (to).type.additional_type = (from).type.additional_type; + +/* + * A ConstDescriptor is a variable-size record that records the name and + * value of a scoped interface constant. + * + * The types of the method parameter are restricted to the following subset + * of TypeDescriptors: + * + * int8, uint8, int16, uint16, int32, uint32, + * int64, uint64, wchar_t, char, string + * + * The type (and thus the size) of the value record is determined by the + * contents of the associated TypeDescriptor record. For instance, if type + * corresponds to int16, then value is a two-byte record consisting of a + * 16-bit signed integer. For a ConstDescriptor type of string, the value + * record is of type String*, i.e. an offset within the data pool to a + * String record containing the constant string. + */ +union XPTConstValue { + PRInt8 i8; + PRUint8 ui8; + PRInt16 i16; + PRUint16 ui16; + PRInt32 i32; + PRUint32 ui32; + PRInt64 i64; + PRUint64 ui64; + float flt; + double dbl; + PRBool bul; + char ch; + PRUint16 wch; + nsID *iid; + XPTString *string; + char *str; + PRUint16 *wstr; +}; /* varies according to type */ + +struct XPTConstDescriptor { + char *name; + XPTTypeDescriptor type; + union XPTConstValue value; +}; + +/* + * A ParamDescriptor is a variable-size record used to describe either a + * single argument to a method or a method's result. + */ +struct XPTParamDescriptor { + PRUint8 flags; + XPTTypeDescriptor type; +}; + +/* flag bits -- jband and fur were right, and I was miserably wrong */ +#define XPT_PD_IN 0x80 +#define XPT_PD_OUT 0x40 +#define XPT_PD_RETVAL 0x20 +#define XPT_PD_SHARED 0x10 +#define XPT_PD_DIPPER 0x08 +#define XPT_PD_FLAGMASK 0xf8 + +#define XPT_PD_IS_IN(flags) (flags & XPT_PD_IN) +#define XPT_PD_IS_OUT(flags) (flags & XPT_PD_OUT) +#define XPT_PD_IS_RETVAL(flags) (flags & XPT_PD_RETVAL) +#define XPT_PD_IS_SHARED(flags) (flags & XPT_PD_SHARED) +#define XPT_PD_IS_DIPPER(flags) (flags & XPT_PD_DIPPER) + +/* this is bogus +#define XPT_PARAMDESCRIPTOR_SIZE (XPT_TYPEDESCRIPTOR_SIZE + 1) +*/ + +extern XPT_PUBLIC_API(PRBool) +XPT_FillParamDescriptor(XPTArena *arena, + XPTParamDescriptor *pd, PRUint8 flags, + XPTTypeDescriptor *type); + +/* + * A MethodDescriptor is a variable-size record used to describe a single + * interface method. + */ +struct XPTMethodDescriptor { + char *name; + XPTParamDescriptor *params; + XPTParamDescriptor *result; + PRUint8 flags; + PRUint8 num_args; +}; + +/* flag bits -- jband and fur were right, and I was miserably wrong */ +#define XPT_MD_GETTER 0x80 +#define XPT_MD_SETTER 0x40 +#define XPT_MD_NOTXPCOM 0x20 +#define XPT_MD_CTOR 0x10 +#define XPT_MD_HIDDEN 0x08 +#define XPT_MD_FLAGMASK 0xf8 + +#define XPT_MD_IS_GETTER(flags) (flags & XPT_MD_GETTER) +#define XPT_MD_IS_SETTER(flags) (flags & XPT_MD_SETTER) +#define XPT_MD_IS_NOTXPCOM(flags) (flags & XPT_MD_NOTXPCOM) +#define XPT_MD_IS_CTOR(flags) (flags & XPT_MD_CTOR) +#define XPT_MD_IS_HIDDEN(flags) (flags & XPT_MD_HIDDEN) + +extern XPT_PUBLIC_API(PRBool) +XPT_FillMethodDescriptor(XPTArena *arena, + XPTMethodDescriptor *meth, PRUint8 flags, char *name, + PRUint8 num_args); + +/* + * Annotation records are variable-size records used to store secondary + * information about the typelib, e.g. such as the name of the tool that + * generated the typelib file, the date it was generated, etc. The + * information is stored with very loose format requirements so as to + * allow virtually any private data to be stored in the typelib. + * + * There are two types of Annotations: + * + * EmptyAnnotation + * PrivateAnnotation + * + * The tag field of the prefix discriminates among the variant record + * types for Annotation's. If the tag is 0, this record is an + * EmptyAnnotation. EmptyAnnotation's are ignored - they're only used to + * indicate an array of Annotation's that's completely empty. If the tag + * is 1, the record is a PrivateAnnotation. + */ + +struct XPTAnnotation { + XPTAnnotation *next; + PRUint8 flags; + /* remaining fields are present in typelib iff XPT_ANN_IS_PRIVATE */ + XPTString *creator; + XPTString *private_data; +}; + +#define XPT_ANN_LAST 0x80 +#define XPT_ANN_IS_LAST(flags) (flags & XPT_ANN_LAST) +#define XPT_ANN_PRIVATE 0x40 +#define XPT_ANN_IS_PRIVATE(flags) (flags & XPT_ANN_PRIVATE) + +extern XPT_PUBLIC_API(XPTAnnotation *) +XPT_NewAnnotation(XPTArena *arena, PRUint8 flags, XPTString *creator, + XPTString *private_data); + +PR_END_EXTERN_C + +#endif /* __xpt_struct_h__ */ diff --git a/src/libs/xpcom18a4/xpcom/typelib/xpt/public/xpt_xdr.h b/src/libs/xpcom18a4/xpcom/typelib/xpt/public/xpt_xdr.h new file mode 100644 index 00000000..89d1c3f6 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/typelib/xpt/public/xpt_xdr.h @@ -0,0 +1,240 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* + * Basic APIs for streaming typelib structures to/from disk. + */ + +#ifndef __xpt_xdr_h__ +#define __xpt_xdr_h__ + +#include "xpt_struct.h" + +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +#define XPT_Do8 VBoxNsxpXPT_Do8 +#define XPT_Do16 VBoxNsxpXPT_Do16 +#define XPT_Do32 VBoxNsxpXPT_Do32 +#define XPT_Do64 VBoxNsxpXPT_Do64 +#define XPT_DoIID VBoxNsxpXPT_DoIID +#define XPT_DoCString VBoxNsxpXPT_DoCString +#define XPT_DoString VBoxNsxpXPT_DoString +#define XPT_DoStringInline VBoxNsxpXPT_DoStringInline +#define XPT_NewXDRState VBoxNsxpXPT_NewXDRState +#define XPT_SetDataOffset VBoxNsxpXPT_SetDataOffset +#define XPT_SeekTo VBoxNsxpXPT_SeekTo +#define XPT_MakeCursor VBoxNsxpXPT_MakeCursor +#define XPT_DestroyXDRState VBoxNsxpXPT_DestroyXDRState +#define XPT_GetXDRData VBoxNsxpXPT_GetXDRData +#define XPT_GetXDRDataLength VBoxNsxpXPT_GetXDRDataLength +#define XPT_DoHeader VBoxNsxpXPT_DoHeader +#define XPT_DoHeaderPrologue VBoxNsxpXPT_DoHeaderPrologue +#define XPT_UpdateFileLength VBoxNsxpXPT_UpdateFileLength +#define XPT_DataOffset VBoxNsxpXPT_DataOffset +#define XPT_GetOffsetForAddr VBoxNsxpXPT_GetOffsetForAddr +#define XPT_SetOffsetForAddr VBoxNsxpXPT_SetOffsetForAddr +#define XPT_SetAddrForOffset VBoxNsxpXPT_SetAddrForOffset +#define XPT_GetAddrForOffset VBoxNsxpXPT_GetAddrForOffset +#endif /* VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + +PR_BEGIN_EXTERN_C + +typedef struct XPTState XPTState; +typedef struct XPTDatapool XPTDatapool; +typedef struct XPTCursor XPTCursor; + +/* Opaque type, for internal use */ +typedef struct XPTHashTable XPTHashTable; + +extern XPT_PUBLIC_API(PRBool) +XPT_DoString(XPTArena *arena, XPTCursor *cursor, XPTString **strp); + +extern XPT_PUBLIC_API(PRBool) +XPT_DoStringInline(XPTArena *arena, XPTCursor *cursor, XPTString **strp); + +extern XPT_PUBLIC_API(PRBool) +XPT_DoCString(XPTArena *arena, XPTCursor *cursor, char **strp); + +extern XPT_PUBLIC_API(PRBool) +XPT_DoIID(XPTCursor *cursor, nsID *iidp); + +extern XPT_PUBLIC_API(PRBool) +XPT_Do64(XPTCursor *cursor, PRInt64 *u64p); + +extern XPT_PUBLIC_API(PRBool) +XPT_Do32(XPTCursor *cursor, PRUint32 *u32p); + +extern XPT_PUBLIC_API(PRBool) +XPT_Do16(XPTCursor *cursor, PRUint16 *u16p); + +extern XPT_PUBLIC_API(PRBool) +XPT_Do8(XPTCursor *cursor, PRUint8 *u8p); + +extern XPT_PUBLIC_API(PRBool) +XPT_DoHeaderPrologue(XPTArena *arena, XPTCursor *cursor, XPTHeader **headerp, PRUint32 * ide_offset); +extern XPT_PUBLIC_API(PRBool) +XPT_DoHeader(XPTArena *arena, XPTCursor *cursor, XPTHeader **headerp); + +typedef enum { + XPT_ENCODE, + XPT_DECODE +} XPTMode; + +typedef enum { + XPT_HEADER = 0, + XPT_DATA = 1 +} XPTPool; + +struct XPTState { + XPTMode mode; + PRUint32 data_offset; + PRUint32 next_cursor[2]; + XPTDatapool *pool; + XPTArena *arena; +}; + +struct XPTDatapool { + XPTHashTable *offset_map; + char *data; + PRUint32 count; + PRUint32 allocated; +}; + +struct XPTCursor { + XPTState *state; + XPTPool pool; + PRUint32 offset; + PRUint8 bits; +}; + +extern XPT_PUBLIC_API(XPTState *) +XPT_NewXDRState(XPTMode mode, char *data, PRUint32 len); + +extern XPT_PUBLIC_API(PRBool) +XPT_MakeCursor(XPTState *state, XPTPool pool, PRUint32 len, XPTCursor *cursor); + +extern XPT_PUBLIC_API(PRBool) +XPT_SeekTo(XPTCursor *cursor, PRUint32 offset); + +extern XPT_PUBLIC_API(void) +XPT_DestroyXDRState(XPTState *state); + +/* Set file_length based on the data used in the state. (Only ENCODE.) */ +extern XPT_PUBLIC_API(PRBool) +XPT_UpdateFileLength(XPTState *state); + +/* returns the length of the specified data block */ +extern XPT_PUBLIC_API(void) +XPT_GetXDRDataLength(XPTState *state, XPTPool pool, PRUint32 *len); + +extern XPT_PUBLIC_API(void) +XPT_GetXDRData(XPTState *state, XPTPool pool, char **data, PRUint32 *len); + +/* set or get the data offset for the state, depending on mode */ +extern XPT_PUBLIC_API(void) +XPT_DataOffset(XPTState *state, PRUint32 *data_offsetp); + +extern XPT_PUBLIC_API(void) +XPT_SetDataOffset(XPTState *state, PRUint32 data_offset); + +extern XPT_PUBLIC_API(PRUint32) +XPT_GetOffsetForAddr(XPTCursor *cursor, void *addr); + +extern XPT_PUBLIC_API(PRBool) +XPT_SetOffsetForAddr(XPTCursor *cursor, void *addr, PRUint32 offset); + +extern XPT_PUBLIC_API(PRBool) +XPT_SetAddrForOffset(XPTCursor *cursor, PRUint32 offset, void *addr); + +extern XPT_PUBLIC_API(void *) +XPT_GetAddrForOffset(XPTCursor *cursor, PRUint32 offset); + +/* all data structures are big-endian */ + +#if defined IS_BIG_ENDIAN +# ifdef VBOX +# error "Misconfigured endian!" +# endif +# define XPT_SWAB32(x) x +# define XPT_SWAB16(x) x +#elif defined IS_LITTLE_ENDIAN +# define XPT_SWAB32(x) (((x) >> 24) | \ + (((x) >> 8) & 0xff00) | \ + (((x) << 8) & 0xff0000) | \ + ((x) << 24)) +# define XPT_SWAB16(x) (((x) >> 8) | ((x) << 8)) +#else +# error "unknown byte order" +#endif + +/* + * If we're decoding, we want to read the offset before we check + * for already-decoded values. + * + * Then we check for repetition: CheckForRepeat will see if we've already + * encoded/decoded this value, and if so will set offset/addr correctly + * and make already be true. If not, it will set up the cursor for + * encoding (reserve space) or decoding (seek to correct location) as + * appropriate. In the encode case, it will also set the addr->offset + * mapping. + */ + +#define XPT_PREAMBLE_(cursor, addrp, pool, size, new_curs, already) \ + XPTMode mode = cursor->state->mode; \ + if (!(mode == XPT_ENCODE || XPT_Do32(cursor, &new_curs.offset)) || \ + !CheckForRepeat(cursor, (void **)addrp, pool, \ + mode == XPT_ENCODE ? size : 0u, &new_curs, \ + &already) || \ + !(mode == XPT_DECODE || XPT_Do32(cursor, &new_curs.offset))) \ + return PR_FALSE; \ + if (already) \ + return PR_TRUE; \ + +#define XPT_PREAMBLE_NO_ALLOC(cursor, addrp, pool, size, new_curs, already) \ + { \ + XPT_PREAMBLE_(cursor, addrp, pool, size, new_curs, already) \ + } + +#define XPT_ERROR_HANDLE(arena, free_it) \ + error: \ + if (cursor->state->mode == XPT_DECODE) \ + XPT_FREEIF(arena, free_it); \ + return PR_FALSE; + + +PR_END_EXTERN_C + +#endif /* __xpt_xdr_h__ */ diff --git a/src/libs/xpcom18a4/xpcom/typelib/xpt/src/.cvsignore b/src/libs/xpcom18a4/xpcom/typelib/xpt/src/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/typelib/xpt/src/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/xpcom/typelib/xpt/src/Makefile.in b/src/libs/xpcom18a4/xpcom/typelib/xpt/src/Makefile.in new file mode 100644 index 00000000..e0578556 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/typelib/xpt/src/Makefile.in @@ -0,0 +1,76 @@ +# +# ***** 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.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of 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 ***** + +DEPTH = ../../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = xpcom +LIBRARY_NAME = xpt +LIB_IS_C_ONLY = 1 +ifdef CROSS_COMPILE +HOST_LIBRARY_NAME = hostxpt +endif + +CSRCS = xpt_arena.c xpt_struct.c xpt_xdr.c +HOST_CSRCS = $(CSRCS) + +# we don't want the shared lib, but we want to force the creation of a static lib. +FORCE_STATIC_LIB = 1 + +# Force use of PIC +FORCE_USE_PIC = 1 + +include $(topsrcdir)/config/rules.mk + +DEFINES += -DEXPORT_XPT_API +HOST_CFLAGS += -DEXPORT_XPT_API + +# Build libxpt early so that it'll be available to xpidl, which also +# must be built early. +export:: + @$(MAKE) libs + +ifdef CROSS_COMPILE +ifdef HOST_NSPR_MDCPUCFG +HOST_CFLAGS += -DMDCPUCFG=$(HOST_NSPR_MDCPUCFG) +endif +endif + diff --git a/src/libs/xpcom18a4/xpcom/typelib/xpt/src/xpt_arena.c b/src/libs/xpcom18a4/xpcom/typelib/xpt/src/xpt_arena.c new file mode 100644 index 00000000..a0813b8f --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/typelib/xpt/src/xpt_arena.c @@ -0,0 +1,358 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Quick arena hack for xpt. */ + +/* XXX This exists because we don't want to drag in NSPR. It *seemed* +* to make more sense to write a quick and dirty arena than to clone +* plarena (like js/src did). This is not optimal, but it works. +* Half of the code here is instrumentation. +*/ + +#include "xpt_arena.h" +#include +#include +#include +#ifdef VBOX_USE_IPRT_IN_XPCOM +# include +#endif + + +/*************************/ +/* logging stats support */ + +#if 0 && defined(DEBUG_jband) +#define XPT_ARENA_LOGGING 1 +#endif + +#ifdef XPT_ARENA_LOGGING + +#define LOG_MALLOC(_a, _req, _used) \ + do{ \ + XPT_ASSERT((_a)); \ + ++(_a)->LOG_MallocCallCount; \ + (_a)->LOG_MallocTotalBytesRequested += (_req); \ + (_a)->LOG_MallocTotalBytesUsed += (_used); \ + } while(0) + +#define LOG_REAL_MALLOC(_a, _size) \ + do{ \ + XPT_ASSERT((_a)); \ + ++(_a)->LOG_RealMallocCallCount; \ + (_a)->LOG_RealMallocTotalBytesRequested += (_size); \ + } while(0) + +#define LOG_FREE(_a) \ + do{ \ + XPT_ASSERT((_a)); \ + ++(_a)->LOG_FreeCallCount; \ + } while(0) + +#define LOG_DONE_LOADING(_a) \ + do{ \ + XPT_ASSERT((_a)); \ + (_a)->LOG_LoadingFreeCallCount = (_a)->LOG_FreeCallCount; \ + } while(0) + +#define PRINT_STATS(_a) xpt_DebugPrintArenaStats((_a)) +static void xpt_DebugPrintArenaStats(XPTArena *arena); + +#else /* !XPT_ARENA_LOGGING */ + +#define LOG_MALLOC(_a, _req, _used) ((void)0) +#define LOG_REAL_MALLOC(_a, _size) ((void)0) +#define LOG_FREE(_a) ((void)0) + +#define LOG_DONE_LOADING(_a) ((void)0) +#define PRINT_STATS(_a) ((void)0) + +#endif /* XPT_ARENA_LOGGING */ + +/****************************************************/ + +/* Block header for each block in the arena */ +typedef struct BLK_HDR BLK_HDR; +struct BLK_HDR +{ + BLK_HDR *next; + size_t size; +}; + +#define XPT_MIN_BLOCK_SIZE 32 + +/* XXX this is lame. Should clone the code to do this bitwise */ +#define ALIGN_RND(s,a) ((a)==1?(s):((((s)+(a)-1)/(a))*(a))) + +struct XPTArena +{ + BLK_HDR *first; + PRUint8 *next; + size_t space; + size_t alignment; + size_t block_size; + char *name; + +#ifdef XPT_ARENA_LOGGING + PRUint32 LOG_MallocCallCount; + PRUint32 LOG_MallocTotalBytesRequested; + PRUint32 LOG_MallocTotalBytesUsed; + PRUint32 LOG_FreeCallCount; + PRUint32 LOG_LoadingFreeCallCount; + PRUint32 LOG_RealMallocCallCount; + PRUint32 LOG_RealMallocTotalBytesRequested; +#endif /* XPT_ARENA_LOGGING */ +}; + +XPT_PUBLIC_API(XPTArena *) +XPT_NewArena(PRUint32 block_size, size_t alignment, const char* name) +{ +#ifdef VBOX_USE_IPRT_IN_XPCOM + XPTArena *arena = RTMemAllocZ(sizeof(XPTArena)); +#else + XPTArena *arena = calloc(1, sizeof(XPTArena)); +#endif + if (arena) { + XPT_ASSERT(alignment); + if (alignment > sizeof(double)) + alignment = sizeof(double); + arena->alignment = alignment; + + if (block_size < XPT_MIN_BLOCK_SIZE) + block_size = XPT_MIN_BLOCK_SIZE; + arena->block_size = ALIGN_RND(block_size, alignment); + + /* must have room for at least one item! */ + XPT_ASSERT(arena->block_size >= + ALIGN_RND(sizeof(BLK_HDR), alignment) + + ALIGN_RND(1, alignment)); + + if (name) { + arena->name = XPT_STRDUP(arena, name); +#ifdef XPT_ARENA_LOGGING + /* fudge the stats since we are using space in the arena */ + arena->LOG_MallocCallCount = 0; + arena->LOG_MallocTotalBytesRequested = 0; + arena->LOG_MallocTotalBytesUsed = 0; +#endif /* XPT_ARENA_LOGGING */ + } + } + return arena; +} + +XPT_PUBLIC_API(void) +XPT_DestroyArena(XPTArena *arena) +{ + BLK_HDR* cur; + BLK_HDR* next; + + cur = arena->first; + while (cur) { + next = cur->next; +#ifdef VBOX_USE_IPRT_IN_XPCOM + RTMemFree(cur); +#else + free(cur); +#endif + cur = next; + } +#ifdef VBOX_USE_IPRT_IN_XPCOM + RTMemFree(arena); +#else + free(arena); +#endif +} + +XPT_PUBLIC_API(void) +XPT_DumpStats(XPTArena *arena) +{ + PRINT_STATS(arena); +} + + +/* +* Our alignment rule is that we always round up the size of each allocation +* so that the 'arena->next' pointer one will point to properly aligned space. +*/ + +XPT_PUBLIC_API(void *) +XPT_ArenaMalloc(XPTArena *arena, size_t size) +{ + PRUint8 *cur; + size_t bytes; + + if (!size) + return NULL; + + if (!arena) { + XPT_ASSERT(0); + return NULL; + } + + bytes = ALIGN_RND(size, arena->alignment); + + LOG_MALLOC(arena, size, bytes); + + if (bytes > arena->space) { + BLK_HDR* new_block; + size_t block_header_size = ALIGN_RND(sizeof(BLK_HDR), arena->alignment); + size_t new_space = arena->block_size; + + if (bytes > new_space - block_header_size) + new_space += bytes; + +#ifdef VBOX_USE_IPRT_IN_XPCOM + new_block = (BLK_HDR*) RTMemAllocZ(new_space/arena->alignment * (size_t)arena->alignment); +#else + new_block = (BLK_HDR*) calloc(new_space/arena->alignment, + arena->alignment); +#endif + if (!new_block) { + arena->next = NULL; + arena->space = 0; + return NULL; + } + + LOG_REAL_MALLOC(arena, new_space); + + /* link block into the list of blocks for use when we destroy */ + new_block->next = arena->first; + arena->first = new_block; + + /* save other block header info */ + new_block->size = new_space; + + /* set info for current block */ + arena->next = ((PRUint8*)new_block) + block_header_size; + arena->space = new_space - block_header_size; + +#ifdef DEBUG + /* mark block for corruption check */ + memset(arena->next, 0xcd, arena->space); +#endif + } + +#ifdef DEBUG + { + /* do corruption check */ + size_t i; + for (i = 0; i < bytes; ++i) { + XPT_ASSERT(arena->next[i] == 0xcd); + } + /* we guarantee that the block will be filled with zeros */ + memset(arena->next, 0, bytes); + } +#endif + + cur = arena->next; + arena->next += bytes; + arena->space -= bytes; + + return cur; +} + + +XPT_PUBLIC_API(char *) +XPT_ArenaStrDup(XPTArena *arena, const char * s) +{ + size_t len; + char* cur; + + if (!s) + return NULL; + + len = strlen(s)+1; + cur = XPT_ArenaMalloc(arena, len); + memcpy(cur, s, len); + return cur; +} + +XPT_PUBLIC_API(void) +XPT_NotifyDoneLoading(XPTArena *arena) +{ +#ifdef XPT_ARENA_LOGGING + if (arena) { + LOG_DONE_LOADING(arena); + } +#endif +} + +XPT_PUBLIC_API(void) +XPT_ArenaFree(XPTArena *arena, void *block) +{ + LOG_FREE(arena); +} + +#ifdef XPT_ARENA_LOGGING +static void xpt_DebugPrintArenaStats(XPTArena *arena) +{ + printf("()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()\n"); + printf("Start xpt arena stats for \"%s\"\n", + arena->name ? arena->name : "unnamed arena"); + printf("\n"); + printf("%d times arena malloc called\n", (int) arena->LOG_MallocCallCount); + printf("%d total bytes requested from arena malloc\n", (int) arena->LOG_MallocTotalBytesRequested); + printf("%d average bytes requested per call to arena malloc\n", (int)arena->LOG_MallocCallCount ? (arena->LOG_MallocTotalBytesRequested/arena->LOG_MallocCallCount) : 0); + printf("%d average bytes used per call (accounts for alignment overhead)\n", (int)arena->LOG_MallocCallCount ? (arena->LOG_MallocTotalBytesUsed/arena->LOG_MallocCallCount) : 0); + printf("%d average bytes used per call (accounts for all overhead and waste)\n", (int)arena->LOG_MallocCallCount ? (arena->LOG_RealMallocTotalBytesRequested/arena->LOG_MallocCallCount) : 0); + printf("\n"); + printf("%d during loading times arena free called\n", (int) arena->LOG_LoadingFreeCallCount); + printf("%d during loading approx total bytes not freed\n", (int) arena->LOG_LoadingFreeCallCount * (int) (arena->LOG_MallocCallCount ? (arena->LOG_MallocTotalBytesUsed/arena->LOG_MallocCallCount) : 0)); + printf("\n"); + printf("%d total times arena free called\n", (int) arena->LOG_FreeCallCount); + printf("%d approx total bytes not freed until arena destruction\n", (int) arena->LOG_FreeCallCount * (int) (arena->LOG_MallocCallCount ? (arena->LOG_MallocTotalBytesUsed/arena->LOG_MallocCallCount) : 0 )); + printf("\n"); + printf("%d times arena called system malloc\n", (int) arena->LOG_RealMallocCallCount); + printf("%d total bytes arena requested from system\n", (int) arena->LOG_RealMallocTotalBytesRequested); + printf("%d byte block size specified at arena creation time\n", (int) arena->block_size); + printf("%d byte block alignment specified at arena creation time\n", (int) arena->alignment); + printf("\n"); + printf("End xpt arena stats\n"); + printf("()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()\n"); +} +#endif + +/***************************************************************************/ + +#ifdef DEBUG +XPT_PUBLIC_API(void) +XPT_AssertFailed(const char *s, const char *file, PRUint32 lineno) +{ + fprintf(stderr, "Assertion failed: %s, file %s, line %d\n", + s, file, lineno); + abort(); +} +#endif diff --git a/src/libs/xpcom18a4/xpcom/typelib/xpt/src/xpt_struct.c b/src/libs/xpcom18a4/xpcom/typelib/xpt/src/xpt_struct.c new file mode 100644 index 00000000..93435910 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/typelib/xpt/src/xpt_struct.c @@ -0,0 +1,956 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Implementation of XDR routines for typelib structures. */ + +#include "xpt_xdr.h" +#include "xpt_struct.h" +#include +#include + +/***************************************************************************/ +/* Forward declarations. */ + +static PRUint32 +SizeOfTypeDescriptor(XPTTypeDescriptor *td, XPTInterfaceDescriptor *id); + +static PRUint32 +SizeOfMethodDescriptor(XPTMethodDescriptor *md, XPTInterfaceDescriptor *id); + +static PRUint32 +SizeOfConstDescriptor(XPTConstDescriptor *cd, XPTInterfaceDescriptor *id); + +static PRUint32 +SizeOfInterfaceDescriptor(XPTInterfaceDescriptor *id); + +static PRBool +DoInterfaceDirectoryEntry(XPTArena *arena, XPTCursor *cursor, + XPTInterfaceDirectoryEntry *ide, PRUint16 entry_index); + +static PRBool +DoConstDescriptor(XPTArena *arena, XPTCursor *cursor, XPTConstDescriptor *cd, + XPTInterfaceDescriptor *id); + +static PRBool +DoMethodDescriptor(XPTArena *arena, XPTCursor *cursor, XPTMethodDescriptor *md, + XPTInterfaceDescriptor *id); + +static PRBool +DoAnnotation(XPTArena *arena, XPTCursor *cursor, XPTAnnotation **annp); + +static PRBool +DoInterfaceDescriptor(XPTArena *arena, XPTCursor *outer, XPTInterfaceDescriptor **idp); + +static PRBool +DoTypeDescriptorPrefix(XPTArena *arena, XPTCursor *cursor, XPTTypeDescriptorPrefix *tdp); + +static PRBool +DoTypeDescriptor(XPTArena *arena, XPTCursor *cursor, XPTTypeDescriptor *td, + XPTInterfaceDescriptor *id); + +static PRBool +DoParamDescriptor(XPTArena *arena, XPTCursor *cursor, XPTParamDescriptor *pd, + XPTInterfaceDescriptor *id); + +/***************************************************************************/ + +XPT_PUBLIC_API(PRUint32) +XPT_SizeOfHeader(XPTHeader *header) +{ + XPTAnnotation *ann, *last; + PRUint32 size = 16 /* magic */ + + 1 /* major */ + 1 /* minor */ + + 2 /* num_interfaces */ + 4 /* file_length */ + + 4 /* interface_directory */ + 4 /* data_pool */; + + ann = header->annotations; + do { + size += 1; /* Annotation prefix */ + if (XPT_ANN_IS_PRIVATE(ann->flags)) + size += 2 + ann->creator->length + 2 + ann->private_data->length; + last = ann; + ann = ann->next; + } while (!XPT_ANN_IS_LAST(last->flags)); + + return size; +} + +XPT_PUBLIC_API(PRUint32) +XPT_SizeOfHeaderBlock(XPTHeader *header) +{ + PRUint32 size = XPT_SizeOfHeader(header); + + size += header->num_interfaces * sizeof (XPTInterfaceDirectoryEntry); + + return size; +} + +XPT_PUBLIC_API(XPTHeader *) +XPT_NewHeader(XPTArena *arena, PRUint16 num_interfaces, PRUint8 major_version, PRUint8 minor_version) +{ + XPTHeader *header = XPT_NEWZAP(arena, XPTHeader); + if (!header) + return NULL; + memcpy(header->magic, XPT_MAGIC, 16); + header->major_version = major_version; + header->minor_version = minor_version; + header->num_interfaces = num_interfaces; + if (num_interfaces) { + header->interface_directory = + XPT_CALLOC(arena, + num_interfaces * sizeof(XPTInterfaceDirectoryEntry)); + if (!header->interface_directory) { + XPT_DELETE(arena, header); + return NULL; + } + } + header->data_pool = 0; /* XXX do we even need this struct any more? */ + + return header; +} + +XPT_PUBLIC_API(void) +XPT_FreeHeader(XPTArena *arena, XPTHeader* aHeader) +{ + if (aHeader) { + XPTAnnotation* ann; + XPTInterfaceDirectoryEntry* entry = aHeader->interface_directory; + XPTInterfaceDirectoryEntry* end = entry + aHeader->num_interfaces; + for (; entry < end; entry++) { + XPT_DestroyInterfaceDirectoryEntry(arena, entry); + } + + ann = aHeader->annotations; + while (ann) { + XPTAnnotation* next = ann->next; + if (XPT_ANN_IS_PRIVATE(ann->flags)) { + XPT_FREEIF(arena, ann->creator); + XPT_FREEIF(arena, ann->private_data); + } + XPT_DELETE(arena, ann); + ann = next; + } + + XPT_FREEIF(arena, aHeader->interface_directory); + XPT_DELETE(arena, aHeader); + } +} + +XPT_PUBLIC_API(PRBool) +XPT_DoHeaderPrologue(XPTArena *arena, XPTCursor *cursor, XPTHeader **headerp, PRUint32 * ide_offset) +{ + XPTMode mode = cursor->state->mode; + unsigned int i; + XPTHeader * header; + + if (mode == XPT_DECODE) { + header = XPT_NEWZAP(arena, XPTHeader); + if (!header) + return PR_FALSE; + *headerp = header; + } else { + header = *headerp; + } + + if (mode == XPT_ENCODE) { + /* IDEs appear after header, including annotations */ + if (ide_offset != NULL) + { + *ide_offset = XPT_SizeOfHeader(*headerp) + 1; /* one-based offset */ + } + header->data_pool = XPT_SizeOfHeaderBlock(*headerp); + XPT_SetDataOffset(cursor->state, header->data_pool); + } + + for (i = 0; i < sizeof(header->magic); i++) { + if (!XPT_Do8(cursor, &header->magic[i])) + goto error; + } + + if (mode == XPT_DECODE && + strncmp((const char*)header->magic, XPT_MAGIC, 16) != 0) + { + /* Require that the header contain the proper magic */ + fprintf(stderr, + "libxpt: bad magic header in input file; " + "found '%s', expected '%s'\n", + header->magic, XPT_MAGIC_STRING); + goto error; + } + + if (!XPT_Do8(cursor, &header->major_version) || + !XPT_Do8(cursor, &header->minor_version)) { + goto error; + } + + if (mode == XPT_DECODE && + header->major_version >= XPT_MAJOR_INCOMPATIBLE_VERSION) { + /* This file is newer than we are and set to an incompatible version + * number. We must set the header state thusly and return. + */ + header->num_interfaces = 0; + header->file_length = 0; + return PR_TRUE; + } + + if (!XPT_Do16(cursor, &header->num_interfaces) || + !XPT_Do32(cursor, &header->file_length) || + (ide_offset != NULL && !XPT_Do32(cursor, ide_offset))) { + goto error; + } + return PR_TRUE; + /* XXX need to free child data sometimes! */ + XPT_ERROR_HANDLE(arena, header); +} + +XPT_PUBLIC_API(PRBool) +XPT_DoHeader(XPTArena *arena, XPTCursor *cursor, XPTHeader **headerp) +{ + const int HEADER_SIZE = 24; + XPTMode mode = cursor->state->mode; + XPTHeader * header; + PRUint32 ide_offset; + int i; + XPTAnnotation *ann, *next, **annp; + + if (!XPT_DoHeaderPrologue(arena, cursor, headerp, &ide_offset)) + return PR_FALSE; + header = *headerp; + /* + * Make sure the file length reported in the header is the same size as + * as our buffer unless it is zero (not set) + */ + if (mode == XPT_DECODE && (header->file_length != 0 && + cursor->state->pool->allocated < header->file_length)) { + fputs("libxpt: File length in header does not match actual length. File may be corrupt\n", + stderr); + goto error; + } + + if (mode == XPT_ENCODE) + XPT_DataOffset(cursor->state, &header->data_pool); + if (!XPT_Do32(cursor, &header->data_pool)) + goto error; + if (mode == XPT_DECODE) + XPT_DataOffset(cursor->state, &header->data_pool); + + if (mode == XPT_DECODE && header->num_interfaces) { + header->interface_directory = + XPT_CALLOC(arena, header->num_interfaces * + sizeof(XPTInterfaceDirectoryEntry)); + if (!header->interface_directory) + goto error; + } + + /* + * Iterate through the annotations rather than recurring, to avoid blowing + * the stack on large xpt files. + */ + ann = next = header->annotations; + annp = &header->annotations; + do { + ann = next; + if (!DoAnnotation(arena, cursor, &ann)) + goto error; + if (mode == XPT_DECODE) { + /* + * Make sure that we store the address of the newly allocated + * annotation in the previous annotation's ``next'' slot, or + * header->annotations for the first one. + */ + *annp = ann; + annp = &ann->next; + } + next = ann->next; + } while (!XPT_ANN_IS_LAST(ann->flags)); + + /* shouldn't be necessary now, but maybe later */ + XPT_SeekTo(cursor, ide_offset); + + for (i = 0; i < header->num_interfaces; i++) { + if (!DoInterfaceDirectoryEntry(arena, cursor, + &header->interface_directory[i], + (PRUint16)(i + 1))) + goto error; + } + + return PR_TRUE; + + /* XXX need to free child data sometimes! */ + XPT_ERROR_HANDLE(arena, header); +} + +XPT_PUBLIC_API(PRBool) +XPT_FillInterfaceDirectoryEntry(XPTArena *arena, + XPTInterfaceDirectoryEntry *ide, + nsID *iid, char *name, char *name_space, + XPTInterfaceDescriptor *descriptor) +{ + XPT_COPY_IID(ide->iid, *iid); + ide->name = name ? XPT_STRDUP(arena, name) : NULL; /* what good is it w/o a name? */ + ide->name_space = name_space ? XPT_STRDUP(arena, name_space) : NULL; + ide->interface_descriptor = descriptor; + return PR_TRUE; +} + +XPT_PUBLIC_API(void) +XPT_DestroyInterfaceDirectoryEntry(XPTArena *arena, + XPTInterfaceDirectoryEntry* ide) +{ + if (ide) { + if (ide->name) XPT_FREE(arena, ide->name); + if (ide->name_space) XPT_FREE(arena, ide->name_space); + XPT_FreeInterfaceDescriptor(arena, ide->interface_descriptor); + } +} + +/* InterfaceDirectoryEntry records go in the header */ +PRBool +DoInterfaceDirectoryEntry(XPTArena *arena, XPTCursor *cursor, + XPTInterfaceDirectoryEntry *ide, PRUint16 entry_index) +{ + XPTMode mode = cursor->state->mode; + + /* write the IID in our cursor space */ + if (!XPT_DoIID(cursor, &(ide->iid)) || + + /* write the name string in the data pool, and the offset in our + cursor space */ + !XPT_DoCString(arena, cursor, &(ide->name)) || + + /* write the name_space string in the data pool, and the offset in our + cursor space */ + !XPT_DoCString(arena, cursor, &(ide->name_space)) || + + /* do InterfaceDescriptors -- later, only on encode (see below) */ + !DoInterfaceDescriptor(arena, cursor, &ide->interface_descriptor)) { + goto error; + } + + if (mode == XPT_DECODE) + XPT_SetOffsetForAddr(cursor, ide, entry_index); + + return PR_TRUE; + + XPT_ERROR_HANDLE(arena, ide); +} + +XPT_PUBLIC_API(XPTInterfaceDescriptor *) +XPT_NewInterfaceDescriptor(XPTArena *arena, + PRUint16 parent_interface, PRUint16 num_methods, + PRUint16 num_constants, PRUint8 flags) +{ + + XPTInterfaceDescriptor *id = XPT_NEWZAP(arena, XPTInterfaceDescriptor); + if (!id) + return NULL; + + if (num_methods) { + id->method_descriptors = XPT_CALLOC(arena, num_methods * + sizeof(XPTMethodDescriptor)); + if (!id->method_descriptors) + goto free_id; + id->num_methods = num_methods; + } + + if (num_constants) { + id->const_descriptors = XPT_CALLOC(arena, num_constants * + sizeof(XPTConstDescriptor)); + if (!id->const_descriptors) + goto free_meth; + id->num_constants = num_constants; + } + + if (parent_interface) { + id->parent_interface = parent_interface; + } else { + id->parent_interface = 0; + } + + id->flags = flags; + + return id; + + free_meth: + XPT_FREEIF(arena, id->method_descriptors); + free_id: + XPT_DELETE(arena, id); + return NULL; +} + +XPT_PUBLIC_API(void) +XPT_FreeInterfaceDescriptor(XPTArena *arena, XPTInterfaceDescriptor* id) +{ + if (id) { + XPTMethodDescriptor *md, *mdend; + XPTConstDescriptor *cd, *cdend; + + /* Free up method descriptors */ + md = id->method_descriptors; + mdend = md + id->num_methods; + for (; md < mdend; md++) { + XPT_FREEIF(arena, md->name); + XPT_FREEIF(arena, md->params); + XPT_FREEIF(arena, md->result); + } + XPT_FREEIF(arena, id->method_descriptors); + + /* Free up const descriptors */ + cd = id->const_descriptors; + cdend = cd + id->num_constants; + for (; cd < cdend; cd++) { + XPT_FREEIF(arena, cd->name); + } + XPT_FREEIF(arena, id->const_descriptors); + + /* Free up type descriptors */ + XPT_FREEIF(arena, id->additional_types); + + XPT_DELETE(arena, id); + } +} + +XPT_PUBLIC_API(PRBool) +XPT_InterfaceDescriptorAddTypes(XPTArena *arena, XPTInterfaceDescriptor *id, + PRUint16 num) +{ + XPTTypeDescriptor *old = id->additional_types; + XPTTypeDescriptor *new; + size_t old_size = id->num_additional_types * sizeof(XPTTypeDescriptor); + size_t new_size = (num * sizeof(XPTTypeDescriptor)) + old_size; + + /* XXX should grow in chunks to minimize alloc overhead */ + new = XPT_CALLOC(arena, new_size); + if (!new) + return PR_FALSE; + if (old) { + if (old_size) + memcpy(new, old, old_size); + XPT_FREE(arena, old); + } + id->additional_types = new; + id->num_additional_types += num; + return PR_TRUE; +} + +XPT_PUBLIC_API(PRBool) +XPT_InterfaceDescriptorAddMethods(XPTArena *arena, XPTInterfaceDescriptor *id, + PRUint16 num) +{ + XPTMethodDescriptor *old = id->method_descriptors; + XPTMethodDescriptor *new; + size_t old_size = id->num_methods * sizeof(XPTMethodDescriptor); + size_t new_size = (num * sizeof(XPTMethodDescriptor)) + old_size; + + /* XXX should grow in chunks to minimize alloc overhead */ + new = XPT_CALLOC(arena, new_size); + if (!new) + return PR_FALSE; + if (old) { + if (old_size) + memcpy(new, old, old_size); + XPT_FREE(arena, old); + } + id->method_descriptors = new; + id->num_methods += num; + return PR_TRUE; +} + +XPT_PUBLIC_API(PRBool) +XPT_InterfaceDescriptorAddConsts(XPTArena *arena, XPTInterfaceDescriptor *id, + PRUint16 num) +{ + XPTConstDescriptor *old = id->const_descriptors; + XPTConstDescriptor *new; + size_t old_size = id->num_constants * sizeof(XPTConstDescriptor); + size_t new_size = (num * sizeof(XPTConstDescriptor)) + old_size; + + /* XXX should grow in chunks to minimize alloc overhead */ + new = XPT_CALLOC(arena, new_size); + if (!new) + return PR_FALSE; + if (old) { + if (old_size) + memcpy(new, old, old_size); + XPT_FREE(arena, old); + } + id->const_descriptors = new; + id->num_constants += num; + return PR_TRUE; +} + +PRUint32 +SizeOfTypeDescriptor(XPTTypeDescriptor *td, XPTInterfaceDescriptor *id) +{ + PRUint32 size = 1; /* prefix */ + + switch (XPT_TDP_TAG(td->prefix)) { + case TD_INTERFACE_TYPE: + size += 2; /* interface_index */ + break; + case TD_INTERFACE_IS_TYPE: + size += 1; /* argnum */ + break; + case TD_ARRAY: + size += 2 + SizeOfTypeDescriptor( + &id->additional_types[td->type.additional_type], id); + break; + case TD_PSTRING_SIZE_IS: + size += 2; /* argnum + argnum2 */ + break; + case TD_PWSTRING_SIZE_IS: + size += 2; /* argnum + argnum2 */ + break; + default: + /* nothing special */ + break; + } + return size; +} + +PRUint32 +SizeOfMethodDescriptor(XPTMethodDescriptor *md, XPTInterfaceDescriptor *id) +{ + PRUint32 i, size = 1 /* flags */ + 4 /* name */ + 1 /* num_args */; + + for (i = 0; i < md->num_args; i++) + size += 1 + SizeOfTypeDescriptor(&md->params[i].type, id); + + size += 1 + SizeOfTypeDescriptor(&md->result->type, id); + return size; +} + +PRUint32 +SizeOfConstDescriptor(XPTConstDescriptor *cd, XPTInterfaceDescriptor *id) +{ + PRUint32 size = 4 /* name */ + SizeOfTypeDescriptor(&cd->type, id); + + switch (XPT_TDP_TAG(cd->type.prefix)) { + case TD_INT8: + case TD_UINT8: + case TD_CHAR: + size ++; + break; + case TD_INT16: + case TD_UINT16: + case TD_WCHAR: + size += 2; + break; + case TD_INT32: + case TD_UINT32: + case TD_PSTRING: + size += 4; + break; + case TD_INT64: + case TD_UINT64: + size += 8; + break; + default: + fprintf(stderr, "libxpt: illegal type in ConstDescriptor: 0x%02x\n", + XPT_TDP_TAG(cd->type.prefix)); + return 0; + } + + return size; +} + +PRUint32 +SizeOfInterfaceDescriptor(XPTInterfaceDescriptor *id) +{ + PRUint32 size = 2 /* parent interface */ + 2 /* num_methods */ + + 2 /* num_constants */ + 1 /* flags */, i; + for (i = 0; i < id->num_methods; i++) + size += SizeOfMethodDescriptor(&id->method_descriptors[i], id); + for (i = 0; i < id->num_constants; i++) + size += SizeOfConstDescriptor(&id->const_descriptors[i], id); + return size; +} + +PRBool +DoInterfaceDescriptor(XPTArena *arena, XPTCursor *outer, + XPTInterfaceDescriptor **idp) +{ + XPTMode mode = outer->state->mode; + XPTInterfaceDescriptor *id; + XPTCursor curs, *cursor = &curs; + PRUint32 i, id_sz = 0; + + if (mode == XPT_DECODE) { + id = XPT_NEWZAP(arena, XPTInterfaceDescriptor); + if (!id) + return PR_FALSE; + *idp = id; + } else { + id = *idp; + if (!id) { + id_sz = 0; + return XPT_Do32(outer, &id_sz); + } + id_sz = SizeOfInterfaceDescriptor(id); + } + + if (!XPT_MakeCursor(outer->state, XPT_DATA, id_sz, cursor)) + goto error; + + if (!XPT_Do32(outer, &cursor->offset)) + goto error; + if (mode == XPT_DECODE && !cursor->offset) { + XPT_DELETE(arena, *idp); + return PR_TRUE; + } + if(!XPT_Do16(cursor, &id->parent_interface) || + !XPT_Do16(cursor, &id->num_methods)) { + goto error; + } + + if (mode == XPT_DECODE && id->num_methods) { + id->method_descriptors = XPT_CALLOC(arena, id->num_methods * + sizeof(XPTMethodDescriptor)); + if (!id->method_descriptors) + goto error; + } + + for (i = 0; i < id->num_methods; i++) { + if (!DoMethodDescriptor(arena, cursor, &id->method_descriptors[i], id)) + goto error; + } + + if (!XPT_Do16(cursor, &id->num_constants)) { + goto error; + } + + if (mode == XPT_DECODE && id->num_constants) { + id->const_descriptors = XPT_CALLOC(arena, id->num_constants * + sizeof(XPTConstDescriptor)); + if (!id->const_descriptors) + goto error; + } + + for (i = 0; i < id->num_constants; i++) { + if (!DoConstDescriptor(arena, cursor, &id->const_descriptors[i], id)) { + goto error; + } + } + + if (!XPT_Do8(cursor, &id->flags)) { + goto error; + } + + return PR_TRUE; + + XPT_ERROR_HANDLE(arena, id); +} + +PRBool +DoConstDescriptor(XPTArena *arena, XPTCursor *cursor, XPTConstDescriptor *cd, + XPTInterfaceDescriptor *id) +{ + PRBool ok = PR_FALSE; + + if (!XPT_DoCString(arena, cursor, &cd->name) || + !DoTypeDescriptor(arena, cursor, &cd->type, id)) { + + return PR_FALSE; + } + + switch(XPT_TDP_TAG(cd->type.prefix)) { + case TD_INT8: + ok = XPT_Do8(cursor, (PRUint8*) &cd->value.i8); + break; + case TD_INT16: + ok = XPT_Do16(cursor, (PRUint16*) &cd->value.i16); + break; + case TD_INT32: + ok = XPT_Do32(cursor, (PRUint32*) &cd->value.i32); + break; + case TD_INT64: + ok = XPT_Do64(cursor, &cd->value.i64); + break; + case TD_UINT8: + ok = XPT_Do8(cursor, &cd->value.ui8); + break; + case TD_UINT16: + ok = XPT_Do16(cursor, &cd->value.ui16); + break; + case TD_UINT32: + ok = XPT_Do32(cursor, &cd->value.ui32); + break; + case TD_UINT64: + ok = XPT_Do64(cursor, (PRInt64 *)&cd->value.ui64); + break; + case TD_CHAR: + ok = XPT_Do8(cursor, (PRUint8*) &cd->value.ch); + break; + case TD_WCHAR: + ok = XPT_Do16(cursor, &cd->value.wch); + break; + /* fall-through */ + default: + fprintf(stderr, "illegal type!\n"); + break; + } + + return ok; + +} + +XPT_PUBLIC_API(PRBool) +XPT_FillMethodDescriptor(XPTArena *arena, XPTMethodDescriptor *meth, + PRUint8 flags, char *name, PRUint8 num_args) +{ + meth->flags = flags & XPT_MD_FLAGMASK; + meth->name = XPT_STRDUP(arena, name); + if (!meth->name) + return PR_FALSE; + meth->num_args = num_args; + if (num_args) { + meth->params = XPT_CALLOC(arena, num_args * sizeof(XPTParamDescriptor)); + if (!meth->params) + goto free_name; + } else { + meth->params = NULL; + } + meth->result = XPT_NEWZAP(arena, XPTParamDescriptor); + if (!meth->result) + goto free_params; + return PR_TRUE; + + free_params: + XPT_DELETE(arena, meth->params); + free_name: + XPT_DELETE(arena, meth->name); + return PR_FALSE; +} + +PRBool +DoMethodDescriptor(XPTArena *arena, XPTCursor *cursor, XPTMethodDescriptor *md, + XPTInterfaceDescriptor *id) +{ + XPTMode mode = cursor->state->mode; + int i; + + if (!XPT_Do8(cursor, &md->flags) || + !XPT_DoCString(arena, cursor, &md->name) || + !XPT_Do8(cursor, &md->num_args)) + return PR_FALSE; + + if (mode == XPT_DECODE && md->num_args) { + md->params = XPT_CALLOC(arena, md->num_args * sizeof(XPTParamDescriptor)); + if (!md->params) + return PR_FALSE; + } + + for(i = 0; i < md->num_args; i++) { + if (!DoParamDescriptor(arena, cursor, &md->params[i], id)) + goto error; + } + + if (mode == XPT_DECODE) { + md->result = XPT_NEWZAP(arena, XPTParamDescriptor); + if (!md->result) + return PR_FALSE; + } + + if (!md->result || + !DoParamDescriptor(arena, cursor, md->result, id)) + goto error; + + return PR_TRUE; + + XPT_ERROR_HANDLE(arena, md->params); +} + +XPT_PUBLIC_API(PRBool) +XPT_FillParamDescriptor(XPTArena *arena, XPTParamDescriptor *pd, PRUint8 flags, + XPTTypeDescriptor *type) +{ + pd->flags = flags & XPT_PD_FLAGMASK; + XPT_COPY_TYPE(pd->type, *type); + return PR_TRUE; +} + +PRBool +DoParamDescriptor(XPTArena *arena, XPTCursor *cursor, XPTParamDescriptor *pd, + XPTInterfaceDescriptor *id) +{ + if (!XPT_Do8(cursor, &pd->flags) || + !DoTypeDescriptor(arena, cursor, &pd->type, id)) + return PR_FALSE; + + return PR_TRUE; +} + +PRBool +DoTypeDescriptorPrefix(XPTArena *arena, XPTCursor *cursor, XPTTypeDescriptorPrefix *tdp) +{ + return XPT_Do8(cursor, &tdp->flags); +} + +PRBool +DoTypeDescriptor(XPTArena *arena, XPTCursor *cursor, XPTTypeDescriptor *td, + XPTInterfaceDescriptor *id) +{ + if (!DoTypeDescriptorPrefix(arena, cursor, &td->prefix)) { + goto error; + } + + switch (XPT_TDP_TAG(td->prefix)) { + case TD_INTERFACE_TYPE: + if (!XPT_Do16(cursor, &td->type.iface)) + goto error; + break; + case TD_INTERFACE_IS_TYPE: + if (!XPT_Do8(cursor, &td->argnum)) + goto error; + break; + case TD_ARRAY: + if (!XPT_Do8(cursor, &td->argnum) || + !XPT_Do8(cursor, &td->argnum2)) + goto error; + + if (cursor->state->mode == XPT_DECODE) { + if(!XPT_InterfaceDescriptorAddTypes(arena, id, 1)) + goto error; + td->type.additional_type = id->num_additional_types - 1; + } + + if (!DoTypeDescriptor(arena, cursor, + &id->additional_types[td->type.additional_type], + id)) + goto error; + break; + case TD_PSTRING_SIZE_IS: + case TD_PWSTRING_SIZE_IS: + if (!XPT_Do8(cursor, &td->argnum) || + !XPT_Do8(cursor, &td->argnum2)) + goto error; + break; + + default: + /* nothing special */ + break; + } + return PR_TRUE; + + XPT_ERROR_HANDLE(arena, td); +} + +XPT_PUBLIC_API(XPTAnnotation *) +XPT_NewAnnotation(XPTArena *arena, PRUint8 flags, XPTString *creator, + XPTString *private_data) +{ + XPTAnnotation *ann = XPT_NEWZAP(arena, XPTAnnotation); + if (!ann) + return NULL; + ann->flags = flags; + if (XPT_ANN_IS_PRIVATE(flags)) { + ann->creator = creator; + ann->private_data = private_data; + } + return ann; +} + +PRBool +DoAnnotation(XPTArena *arena, XPTCursor *cursor, XPTAnnotation **annp) +{ + XPTMode mode = cursor->state->mode; + XPTAnnotation *ann; + + if (mode == XPT_DECODE) { + ann = XPT_NEWZAP(arena, XPTAnnotation); + if (!ann) + return PR_FALSE; + *annp = ann; + } else { + ann = *annp; + } + + if (!XPT_Do8(cursor, &ann->flags)) + goto error; + + if (XPT_ANN_IS_PRIVATE(ann->flags)) { + if (!XPT_DoStringInline(arena, cursor, &ann->creator) || + !XPT_DoStringInline(arena, cursor, &ann->private_data)) + goto error_2; + } + + return PR_TRUE; + + error_2: + if (ann && XPT_ANN_IS_PRIVATE(ann->flags)) { + XPT_FREEIF(arena, ann->creator); + XPT_FREEIF(arena, ann->private_data); + } + XPT_ERROR_HANDLE(arena, ann); +} + +PRBool +XPT_GetInterfaceIndexByName(XPTInterfaceDirectoryEntry *ide_block, + PRUint16 num_interfaces, char *name, + PRUint16 *indexp) +{ + int i; + + for (i=1; i<=num_interfaces; i++) { + fprintf(stderr, "%s == %s ?\n", ide_block[i].name, name); + if (strcmp(ide_block[i].name, name) == 0) { + *indexp = i; + return PR_TRUE; + } + } + *indexp = 0; + return PR_FALSE; +} + +static XPT_TYPELIB_VERSIONS_STRUCT versions[] = XPT_TYPELIB_VERSIONS; +#define XPT_TYPELIB_VERSIONS_COUNT (sizeof(versions) / sizeof(versions[0])) + +XPT_PUBLIC_API(PRUint16) +XPT_ParseVersionString(const char* str, PRUint8* major, PRUint8* minor) +{ + int i; + for (i = 0; i < XPT_TYPELIB_VERSIONS_COUNT; i++) { + if (!strcmp(versions[i].str, str)) { + *major = versions[i].major; + *minor = versions[i].minor; + return versions[i].code; + } + } + return XPT_VERSION_UNKNOWN; +} + + diff --git a/src/libs/xpcom18a4/xpcom/typelib/xpt/src/xpt_xdr.c b/src/libs/xpcom18a4/xpcom/typelib/xpt/src/xpt_xdr.c new file mode 100644 index 00000000..cd9261d0 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/typelib/xpt/src/xpt_xdr.c @@ -0,0 +1,665 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Implementation of XDR primitives. */ + +#include "xpt_xdr.h" +#include "nspr.h" +#include /* strchr */ + +static PRBool +CheckForRepeat(XPTCursor *cursor, void **addrp, XPTPool pool, PRUint32 len, + XPTCursor *new_cursor, PRBool *already); + +#define ENCODING(cursor) \ + ((cursor)->state->mode == XPT_ENCODE) + +#define CURS_POOL_OFFSET_RAW(cursor) \ + ((cursor)->pool == XPT_HEADER \ + ? (cursor)->offset \ + : (XPT_ASSERT((cursor)->state->data_offset), \ + (cursor)->offset + (cursor)->state->data_offset)) + +#define CURS_POOL_OFFSET(cursor) \ + (CURS_POOL_OFFSET_RAW(cursor) - 1) + +/* can be used as lvalue */ +#define CURS_POINT(cursor) \ + ((cursor)->state->pool->data[CURS_POOL_OFFSET(cursor)]) + +#if defined(DEBUG_shaver) || defined(DEBUG_jband) || defined(DEBUG_mccabe) +#define DBG(x) printf##x +#else +#define DBG(x) (0) +#endif + +/* XXX fail if XPT_DATA and !state->data_offset */ +#define CHECK_COUNT_(cursor, space) \ + /* if we're in the header, then exceeding the data_offset is illegal */ \ +((cursor)->pool == XPT_HEADER ? \ + (ENCODING(cursor) && \ + ((cursor)->state->data_offset && \ + ((cursor)->offset - 1 + (space) > (cursor)->state->data_offset)) \ + ? (DBG(("no space left in HEADER %d + %d > %d\n", (cursor)->offset, \ + (space), (cursor)->state->data_offset)) && PR_FALSE) \ + : PR_TRUE) : \ + /* if we're in the data area and we're about to exceed the allocation */ \ + (CURS_POOL_OFFSET(cursor) + (space) > (cursor)->state->pool->allocated ? \ + /* then grow if we're in ENCODE mode */ \ + (ENCODING(cursor) ? GrowPool((cursor)->state->arena, \ + (cursor)->state->pool, \ + (cursor)->state->pool->allocated, \ + 0, CURS_POOL_OFFSET(cursor) + (space)) \ + /* and fail if we're in DECODE mode */ \ + : (DBG(("can't extend in DECODE")) && PR_FALSE)) \ + /* otherwise we're OK */ \ + : PR_TRUE)) + +#define CHECK_COUNT(cursor, space) \ + (CHECK_COUNT_(cursor, space) \ + ? PR_TRUE \ + : (XPT_ASSERT(0), \ + fprintf(stderr, "FATAL: can't no room for %d in cursor\n", space), \ + PR_FALSE)) + +/* increase the data allocation for the pool by XPT_GROW_CHUNK */ +#define XPT_GROW_CHUNK 8192 + +/* + * quick and dirty hardcoded hashtable, to avoid dependence on nspr or glib. + * XXXmccabe it might turn out that we could use a simpler data structure here. + */ +typedef struct XPTHashRecord { + void *key; + void *value; + struct XPTHashRecord *next; +} XPTHashRecord; + +#define XPT_HASHSIZE 512 + +struct XPTHashTable { /* it's already typedef'ed from before. */ + XPTHashRecord *buckets[XPT_HASHSIZE]; + XPTArena *arena; +}; + +static XPTHashTable * +XPT_NewHashTable(XPTArena *arena) { + XPTHashTable *table; + table = XPT_NEWZAP(arena, XPTHashTable); + if (table) + table->arena = arena; + return table; +} + +static void trimrecord(XPTArena* arena, XPTHashRecord *record) { + if (record == NULL) + return; + trimrecord(arena, record->next); + XPT_DELETE(arena, record); +} + +static void +XPT_HashTableDestroy(XPTHashTable *table) { + int i; + for (i = 0; i < XPT_HASHSIZE; i++) + trimrecord(table->arena, table->buckets[i]); + XPT_FREE(table->arena, table); +} + +static void * +XPT_HashTableAdd(XPTHashTable *table, void *key, void *value) { + XPTHashRecord **bucketloc = table->buckets + + (((PRUint32)(uintptr_t)key) % XPT_HASHSIZE); + XPTHashRecord *bucket; + + while (*bucketloc != NULL) + bucketloc = &((*bucketloc)->next); + + bucket = XPT_NEW(table->arena, XPTHashRecord); + bucket->key = key; + bucket->value = value; + bucket->next = NULL; + *bucketloc = bucket; + return value; +} + +static void * +XPT_HashTableLookup(XPTHashTable *table, void *key) { + XPTHashRecord *bucket = table->buckets[(PRUint32)(uintptr_t)key % XPT_HASHSIZE]; + while (bucket != NULL) { + if (bucket->key == key) + return bucket->value; + bucket = bucket->next; + } + return NULL; +} + +XPT_PUBLIC_API(XPTState *) +XPT_NewXDRState(XPTMode mode, char *data, PRUint32 len) +{ + XPTState *state; + XPTArena *arena; + + arena = XPT_NewArena(512, sizeof(double), "an XDRState"); + if (!arena) + return NULL; + + state = XPT_NEWZAP(arena, XPTState); + if (!state) + goto err_free_arena; + + state->arena = arena; + state->mode = mode; + state->pool = XPT_NEW(arena, XPTDatapool); + state->next_cursor[0] = state->next_cursor[1] = 1; + if (!state->pool) + goto err_free_state; + + state->pool->count = 0; + state->pool->offset_map = XPT_NewHashTable(arena); + + if (!state->pool->offset_map) + goto err_free_pool; + if (mode == XPT_DECODE) { + state->pool->data = data; + state->pool->allocated = len; + } else { + state->pool->data = XPT_MALLOC(arena, XPT_GROW_CHUNK); + if (!state->pool->data) + goto err_free_hash; + state->pool->allocated = XPT_GROW_CHUNK; + } + + return state; + + err_free_hash: + XPT_HashTableDestroy(state->pool->offset_map); + err_free_pool: + XPT_DELETE(arena, state->pool); + err_free_state: + XPT_DELETE(arena, state); + err_free_arena: + if (arena) + XPT_DestroyArena(arena); + return NULL; +} + +XPT_PUBLIC_API(void) +XPT_DestroyXDRState(XPTState *state) +{ + XPTArena *arena = state->arena; + + if (state->pool->offset_map) + XPT_HashTableDestroy(state->pool->offset_map); + if (state->mode == XPT_ENCODE) + XPT_DELETE(arena, state->pool->data); + XPT_DELETE(arena, state->pool); + XPT_DELETE(arena, state); + if (arena) + XPT_DestroyArena(arena); +} + +XPT_PUBLIC_API(void) +XPT_GetXDRDataLength(XPTState *state, XPTPool pool, PRUint32 *len) +{ + *len = state->next_cursor[pool] - 1; +} + +XPT_PUBLIC_API(void) +XPT_GetXDRData(XPTState *state, XPTPool pool, char **data, PRUint32 *len) +{ + if (pool == XPT_HEADER) { + *data = state->pool->data; + } else { + *data = state->pool->data + state->data_offset; + } + *len = state->next_cursor[pool] - 1; +} + +/* All offsets are 1-based */ +XPT_PUBLIC_API(void) +XPT_DataOffset(XPTState *state, PRUint32 *data_offsetp) +{ + if (state->mode == XPT_DECODE) + XPT_SetDataOffset(state, *data_offsetp); + else + *data_offsetp = state->data_offset; +} + +/* if 'exact' is set use that, else grow by the next chunk but + * be sure to grow no less that 'at_least' so that we can't get + * behind on required space. + */ +static PRBool +GrowPool(XPTArena *arena, XPTDatapool *pool, PRUint32 old_size, + PRUint32 exact, PRUint32 at_least) +{ + PRUint32 total_size; + char *newdata; + + if (exact) { + XPT_ASSERT(exact > pool->allocated); + total_size = exact; + } else { + total_size = pool->allocated + XPT_GROW_CHUNK; + if (at_least > total_size) + total_size = at_least; + } + + newdata = XPT_MALLOC(arena, total_size); + if (!newdata) + return PR_FALSE; + if (pool->data) { + if (old_size) + memcpy(newdata, pool->data, old_size); + XPT_FREE(arena, pool->data); + } + pool->data = newdata; + pool->allocated = total_size; + return PR_TRUE; +} + +XPT_PUBLIC_API(void) +XPT_SetDataOffset(XPTState *state, PRUint32 data_offset) +{ + state->data_offset = data_offset; + /* make sure we've allocated enough space for the header */ + if (state->mode == XPT_ENCODE && + data_offset > state->pool->allocated) { + (void)GrowPool(state->arena, state->pool, state->pool->allocated, + data_offset, 0); + } +} + +XPT_PUBLIC_API(PRBool) +XPT_MakeCursor(XPTState *state, XPTPool pool, PRUint32 len, XPTCursor *cursor) +{ + cursor->state = state; + cursor->pool = pool; + cursor->bits = 0; + cursor->offset = state->next_cursor[pool]; + + if (!(CHECK_COUNT(cursor, len))) + return PR_FALSE; + + /* this check should be in CHECK_CURSOR */ + if (pool == XPT_DATA && !state->data_offset) { + fprintf(stderr, "no data offset for XPT_DATA cursor!\n"); + return PR_FALSE; + } + + state->next_cursor[pool] += len; + + return PR_TRUE; +} + +XPT_PUBLIC_API(PRBool) +XPT_SeekTo(XPTCursor *cursor, PRUint32 offset) +{ + /* XXX do some real checking and update len and stuff */ + cursor->offset = offset; + return PR_TRUE; +} + +XPT_PUBLIC_API(XPTString *) +XPT_NewString(XPTArena *arena, PRUint16 length, char *bytes) +{ + XPTString *str = XPT_NEW(arena, XPTString); + if (!str) + return NULL; + str->length = length; + /* Alloc one extra to store the trailing nul. */ + str->bytes = XPT_MALLOC(arena, length + 1u); + if (!str->bytes) { + XPT_DELETE(arena, str); + return NULL; + } + memcpy(str->bytes, bytes, length); + /* nul-terminate it. */ + str->bytes[length] = '\0'; + return str; +} + +XPT_PUBLIC_API(XPTString *) +XPT_NewStringZ(XPTArena *arena, char *bytes) +{ + PRUint32 length = strlen(bytes); + if (length > 0xffff) + return NULL; /* too long */ + return XPT_NewString(arena, (PRUint16)length, bytes); +} + +XPT_PUBLIC_API(PRBool) +XPT_DoStringInline(XPTArena *arena, XPTCursor *cursor, XPTString **strp) +{ + XPTString *str = *strp; + XPTMode mode = cursor->state->mode; + int i; + + if (mode == XPT_DECODE) { + str = XPT_NEWZAP(arena, XPTString); + if (!str) + return PR_FALSE; + *strp = str; + } + + if (!XPT_Do16(cursor, &str->length)) + goto error; + + if (mode == XPT_DECODE) + if (!(str->bytes = XPT_MALLOC(arena, str->length + 1u))) + goto error; + + for (i = 0; i < str->length; i++) + if (!XPT_Do8(cursor, (PRUint8 *)&str->bytes[i])) + goto error_2; + + if (mode == XPT_DECODE) + str->bytes[str->length] = 0; + + return PR_TRUE; + error_2: + XPT_DELETE(arena, str->bytes); + error: + XPT_DELETE(arena, str); + return PR_FALSE; +} + +XPT_PUBLIC_API(PRBool) +XPT_DoString(XPTArena *arena, XPTCursor *cursor, XPTString **strp) +{ + XPTCursor my_cursor; + XPTString *str = *strp; + PRBool already; + + XPT_PREAMBLE_NO_ALLOC(cursor, strp, XPT_DATA, str->length + 2, my_cursor, + already) + + return XPT_DoStringInline(arena, &my_cursor, strp); +} + +XPT_PUBLIC_API(PRBool) +XPT_DoCString(XPTArena *arena, XPTCursor *cursor, char **identp) +{ + XPTCursor my_cursor; + char *ident = *identp; + PRUint32 offset = 0; + + XPTMode mode = cursor->state->mode; + + if (mode == XPT_DECODE) { + char *start, *end; + int len; + + if (!XPT_Do32(cursor, &offset)) + return PR_FALSE; + + if (!offset) { + *identp = NULL; + return PR_TRUE; + } + + my_cursor.pool = XPT_DATA; + my_cursor.offset = offset; + my_cursor.state = cursor->state; + start = &CURS_POINT(&my_cursor); + + end = strchr(start, 0); /* find the end of the string */ + if (!end) { + fprintf(stderr, "didn't find end of string on decode!\n"); + return PR_FALSE; + } + len = end - start; + XPT_ASSERT(len > 0); + + ident = XPT_MALLOC(arena, len + 1u); + if (!ident) + return PR_FALSE; + + memcpy(ident, start, (size_t)len); + ident[len] = 0; + *identp = ident; + + } else { + + if (!ident) { + offset = 0; + if (!XPT_Do32(cursor, &offset)) + return PR_FALSE; + return PR_TRUE; + } + + if (!XPT_MakeCursor(cursor->state, XPT_DATA, strlen(ident) + 1, + &my_cursor) || + !XPT_Do32(cursor, &my_cursor.offset)) + return PR_FALSE; + + while(*ident) + if (!XPT_Do8(&my_cursor, (PRUint8 *)ident++)) + return PR_FALSE; + if (!XPT_Do8(&my_cursor, (PRUint8 *)ident)) /* write trailing zero */ + return PR_FALSE; + } + + return PR_TRUE; +} + +/* XXXjband it bothers me that this is one hashtable instead of two. + */ +XPT_PUBLIC_API(PRUint32) +XPT_GetOffsetForAddr(XPTCursor *cursor, void *addr) +{ + return (PRUint32)(uintptr_t)XPT_HashTableLookup(cursor->state->pool->offset_map, addr); +} + +XPT_PUBLIC_API(PRBool) +XPT_SetOffsetForAddr(XPTCursor *cursor, void *addr, PRUint32 offset) +{ + return XPT_HashTableAdd(cursor->state->pool->offset_map, + addr, (void *)(uintptr_t)offset) != NULL; +} + +XPT_PUBLIC_API(PRBool) +XPT_SetAddrForOffset(XPTCursor *cursor, PRUint32 offset, void *addr) +{ + return XPT_HashTableAdd(cursor->state->pool->offset_map, + (void *)(uintptr_t)offset, addr) != NULL; +} + +XPT_PUBLIC_API(void *) +XPT_GetAddrForOffset(XPTCursor *cursor, PRUint32 offset) +{ + return XPT_HashTableLookup(cursor->state->pool->offset_map, (void *)(uintptr_t)offset); +} + +/* Used by XPT_PREAMBLE_NO_ALLOC. */ +static PRBool +CheckForRepeat(XPTCursor *cursor, void **addrp, XPTPool pool, PRUint32 len, + XPTCursor *new_cursor, PRBool *already) +{ + void *last = *addrp; + + *already = PR_FALSE; + new_cursor->state = cursor->state; + new_cursor->pool = pool; + new_cursor->bits = 0; + + if (cursor->state->mode == XPT_DECODE) { + + last = XPT_GetAddrForOffset(new_cursor, new_cursor->offset); + + if (last) { + *already = PR_TRUE; + *addrp = last; + } + + } else { + + new_cursor->offset = XPT_GetOffsetForAddr(new_cursor, last); + if (new_cursor->offset) { + *already = PR_TRUE; + return PR_TRUE; + } + + /* haven't already found it, so allocate room for it. */ + if (!XPT_MakeCursor(cursor->state, pool, len, new_cursor) || + !XPT_SetOffsetForAddr(new_cursor, *addrp, new_cursor->offset)) + return PR_FALSE; + } + return PR_TRUE; +} + +/* + * IIDs are written in struct order, in the usual big-endian way. From the + * typelib file spec: + * + * "For example, this IID: + * {00112233-4455-6677-8899-aabbccddeeff} + * is converted to the 128-bit value + * 0x00112233445566778899aabbccddeeff + * Note that the byte storage order corresponds to the layout of the nsIID + * C-struct on a big-endian architecture." + * + * (http://www.mozilla.org/scriptable/typelib_file.html#iid) + */ +XPT_PUBLIC_API(PRBool) +XPT_DoIID(XPTCursor *cursor, nsID *iidp) +{ + int i; + + if (!XPT_Do32(cursor, &iidp->m0) || + !XPT_Do16(cursor, &iidp->m1) || + !XPT_Do16(cursor, &iidp->m2)) + return PR_FALSE; + + for (i = 0; i < 8; i++) + if (!XPT_Do8(cursor, (PRUint8 *)&iidp->m3[i])) + return PR_FALSE; + + return PR_TRUE; +} + +XPT_PUBLIC_API(PRBool) +XPT_Do64(XPTCursor *cursor, PRInt64 *u64p) +{ + return XPT_Do32(cursor, (PRUint32 *)u64p) && + XPT_Do32(cursor, ((PRUint32 *)u64p) + 1); +} + +/* + * When we're writing 32- or 16-bit quantities, we write a byte at a time to + * avoid alignment issues. Someone could come and optimize this to detect + * well-aligned cases and do a single store, if they cared. I might care + * later. + */ +XPT_PUBLIC_API(PRBool) +XPT_Do32(XPTCursor *cursor, PRUint32 *u32p) +{ + union { + PRUint8 b8[4]; + PRUint32 b32; + } u; + + if (!CHECK_COUNT(cursor, 4)) + return PR_FALSE; + + if (ENCODING(cursor)) { + u.b32 = XPT_SWAB32(*u32p); + CURS_POINT(cursor) = u.b8[0]; + cursor->offset++; + CURS_POINT(cursor) = u.b8[1]; + cursor->offset++; + CURS_POINT(cursor) = u.b8[2]; + cursor->offset++; + CURS_POINT(cursor) = u.b8[3]; + } else { + u.b8[0] = CURS_POINT(cursor); + cursor->offset++; + u.b8[1] = CURS_POINT(cursor); + cursor->offset++; + u.b8[2] = CURS_POINT(cursor); + cursor->offset++; + u.b8[3] = CURS_POINT(cursor); + *u32p = XPT_SWAB32(u.b32); + } + cursor->offset++; + return PR_TRUE; +} + +XPT_PUBLIC_API(PRBool) +XPT_Do16(XPTCursor *cursor, PRUint16 *u16p) +{ + union { + PRUint8 b8[2]; + PRUint16 b16; + } u; + + if (!CHECK_COUNT(cursor, 2)) + return PR_FALSE; + + if (ENCODING(cursor)) { + u.b16 = XPT_SWAB16(*u16p); + CURS_POINT(cursor) = u.b8[0]; + cursor->offset++; + CURS_POINT(cursor) = u.b8[1]; + } else { + u.b8[0] = CURS_POINT(cursor); + cursor->offset++; + u.b8[1] = CURS_POINT(cursor); + *u16p = XPT_SWAB16(u.b16); + } + cursor->offset++; + + return PR_TRUE; +} + +XPT_PUBLIC_API(PRBool) +XPT_Do8(XPTCursor *cursor, PRUint8 *u8p) +{ + if (!CHECK_COUNT(cursor, 1)) + return PR_FALSE; + if (cursor->state->mode == XPT_ENCODE) + CURS_POINT(cursor) = *u8p; + else + *u8p = CURS_POINT(cursor); + + cursor->offset++; + + return PR_TRUE; +} + + diff --git a/src/libs/xpcom18a4/xpcom/typelib/xpt/tests/.cvsignore b/src/libs/xpcom18a4/xpcom/typelib/xpt/tests/.cvsignore new file mode 100644 index 00000000..ebc62d94 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/typelib/xpt/tests/.cvsignore @@ -0,0 +1,3 @@ +Makefile +PrimitiveTest +SimpleTypeLib diff --git a/src/libs/xpcom18a4/xpcom/typelib/xpt/tests/Makefile.in b/src/libs/xpcom18a4/xpcom/typelib/xpt/tests/Makefile.in new file mode 100644 index 00000000..afdc31b3 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/typelib/xpt/tests/Makefile.in @@ -0,0 +1,59 @@ +# +# ***** 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.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of 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 ***** + +DEPTH = ../../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = xpcom +CPP_PROG_LINK = 1 + +SIMPLE_PROGRAMS = PrimitiveTest$(BIN_SUFFIX) SimpleTypeLib$(BIN_SUFFIX) + +CSRCS = PrimitiveTest.c SimpleTypeLib.c + +LIBS = \ + $(XPCOM_LIBS) \ + $(NSPR_LIBS) \ + $(NULL) + +include $(topsrcdir)/config/rules.mk + +DEFINES += -DEXPORT_XPT_API diff --git a/src/libs/xpcom18a4/xpcom/typelib/xpt/tests/PrimitiveTest.c b/src/libs/xpcom18a4/xpcom/typelib/xpt/tests/PrimitiveTest.c new file mode 100644 index 00000000..aad33ccc --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/typelib/xpt/tests/PrimitiveTest.c @@ -0,0 +1,157 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Test the xdr primitives from xpt_xdr.c */ + +#include "xpt_xdr.h" +#include +#include /* for memcpy */ + +#define PASS(msg) \ + fprintf(stderr, "PASSED : %s\n", msg); + +#define FAIL(msg) \ + fprintf(stderr, "FAILURE: %s\n", msg); + +#define TRY_(msg, cond, silent) \ + if ((cond) && !silent) { \ + PASS(msg); \ + } else { \ + FAIL(msg); \ + return 1; \ + } + +#define TRY(msg, cond) TRY_(msg, cond, 0) +#define TRY_Q(msg, cond) TRY_(msg, cond, 1); + +XPTString in_str = { 4, "bazz" }; + +struct TestData { + PRUint32 bit32; + PRUint16 bit16; + PRUint8 bit8[2]; + char *cstr; + XPTString *str; +} input = { 0xdeadbeef, 0xcafe, {0xba, 0xbe}, "foobar", &in_str}, + output = {0, 0, {0, 0}, NULL, NULL }; + +void +dump_struct(char *label, struct TestData *str) +{ + fprintf(stderr, "%s: {%#08x, %#04x, {%#02x, %#02x}, %s, %d/%s}\n", + label, str->bit32, str->bit16, str->bit8[0], str->bit8[1], + str->cstr, str->str->length, str->str->bytes); +} + +PRBool +XDR(XPTArena *arena, XPTCursor *cursor, struct TestData *str) +{ + TRY("Do32", XPT_Do32(cursor, &str->bit32)); + TRY("Do16", XPT_Do16(cursor, &str->bit16)); + TRY("Do8", XPT_Do8 (cursor, &str->bit8[0])); + TRY("Do8", XPT_Do8 (cursor, &str->bit8[1])); + TRY("DoCString", XPT_DoCString(arena, cursor, &str->cstr)); + TRY("DoString", XPT_DoString(arena, cursor, &str->str)); + return 0; +} + +int +main(int argc, char **argv) +{ + XPTArena *arena; + XPTState *state; + XPTCursor curs, *cursor = &curs; + char *header, *data, *whole; + PRUint32 hlen, dlen, i; + + TRY("XPT_NewArena", (arena = XPT_NewArena(1024, sizeof(double), "main"))); + + TRY("NewState (ENCODE)", (state = XPT_NewXDRState(XPT_ENCODE, NULL, 0))); + + XPT_SetDataOffset(state, sizeof input); + + TRY("MakeCursor", XPT_MakeCursor(state, XPT_HEADER, sizeof input, cursor)); + + dump_struct("before", &input); + + if (XDR(arena, cursor, &input)) + return 1; + + fprintf(stderr, "ENCODE successful\n"); + XPT_GetXDRData(state, XPT_HEADER, &header, &hlen); + fprintf(stderr, "XDR header %d bytes at %p:", + hlen, header); + for (i = 0; i < hlen; i++) + fprintf(stderr, "%c%02x", i ? ',' : ' ', (uint8)header[i]); + fprintf(stderr, "\n"); + + XPT_GetXDRData(state, XPT_DATA, &data, &dlen); + + fprintf(stderr, "XDR data %d bytes at %p:", + dlen, data); + for (i = 0; i < dlen; i++) + fprintf(stderr, "%c%02x/%c", i ? ',' : ' ', (uint8)data[i], + (uint8)data[i]); + fprintf(stderr, "\n"); + + whole = malloc(dlen + hlen); + if (!whole) { + fprintf(stderr, "malloc %d failed!\n", dlen + hlen); + return 1; + } + + /* TRY_Q("malloc", (data2 = malloc(len))); */ + memcpy(whole, header, hlen); + memcpy(whole + hlen, data, dlen); + XPT_DestroyXDRState(state); + + TRY("NewState (DECODE)", (state = XPT_NewXDRState(XPT_DECODE, whole, + hlen + dlen))); + + TRY("MakeCursor", XPT_MakeCursor(state, XPT_HEADER, sizeof input, cursor)); + XPT_SetDataOffset(state, sizeof input); + + if (XDR(arena, cursor, &output)) + return 1; + + dump_struct("after", &output); + XPT_DestroyXDRState(state); + XPT_DestroyArena(arena); + free(whole); + + return 0; +} diff --git a/src/libs/xpcom18a4/xpcom/typelib/xpt/tests/SimpleTypeLib.c b/src/libs/xpcom18a4/xpcom/typelib/xpt/tests/SimpleTypeLib.c new file mode 100644 index 00000000..305b8520 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/typelib/xpt/tests/SimpleTypeLib.c @@ -0,0 +1,192 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Test the structure creation and serialization APIs from xpt_struct.c */ +#include + +#include "xpt_xdr.h" +#include "xpt_struct.h" + +#define PASS(msg) \ + fprintf(stderr, "PASSED : %s\n", msg); + +#define FAIL(msg) \ + fprintf(stderr, "FAILURE: %s\n", msg); + +#define TRY_(msg, cond, silent) \ + if ((cond) && !silent) { \ + PASS(msg); \ + } else { \ + FAIL(msg); \ + return 1; \ + } + +#define TRY(msg, cond) TRY_(msg, cond, 0) +#define TRY_Q(msg, cond) TRY_(msg, cond, 1); + +struct nsID iid = { + 0x00112233, + 0x4455, + 0x6677, + {0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff} +}; + +XPTTypeDescriptor td_void; + +int +main(int argc, char **argv) +{ + XPTArena *arena; + XPTHeader *header; + XPTAnnotation *ann; + XPTInterfaceDescriptor *id; + XPTMethodDescriptor *meth; + + XPTState *state; + XPTCursor curs, *cursor = &curs; + char *data, *head; + FILE *out; + PRUint32 len, header_sz; + + PRBool ok; + + td_void.prefix.flags = TD_VOID; + +#ifdef XP_MAC + if (argc == 0) { + static char* args[] = { "SimpleTypeLib", "simple.xpt", NULL }; + argc = 2; + argv = args; + } +#endif + + if (argc != 2) { + fprintf(stderr, "Usage: %s \n" + " Creates a simple typelib file.\n", argv[0]); + + return 1; + } + + arena = XPT_NewArena(1024, sizeof(double), "main"); + TRY("XPT_NewArena", arena); + + /* construct a header */ + header = XPT_NewHeader(arena, 1, XPT_MAJOR_VERSION, XPT_MINOR_VERSION); + TRY("NewHeader", header); + + + ann = XPT_NewAnnotation(arena, XPT_ANN_LAST | XPT_ANN_PRIVATE, + XPT_NewStringZ(arena, "SimpleTypeLib 1.0"), + XPT_NewStringZ(arena, "See You In Rome")); + TRY("NewAnnotation", ann); + header->annotations = ann; + + header_sz = XPT_SizeOfHeaderBlock(header); + + id = XPT_NewInterfaceDescriptor(arena, 0, 2, 2, 0); + TRY("NewInterfaceDescriptor", id); + + ok = XPT_FillInterfaceDirectoryEntry(arena, header->interface_directory, &iid, + "Interface", "NS", id); + TRY("FillInterfaceDirectoryEntry", ok); + + /* void method1(void) */ + meth = &id->method_descriptors[0]; + ok = XPT_FillMethodDescriptor(arena, meth, 0, "method1", 0); + TRY("FillMethodDescriptor", ok); + meth->result->flags = 0; + meth->result->type.prefix.flags = TD_VOID; + + /* wstring method2(in uint32, in bool) */ + meth = &id->method_descriptors[1]; + ok = XPT_FillMethodDescriptor(arena, meth, 0, "method2", 2); + TRY("FillMethodDescriptor", ok); + + meth->result->flags = 0; + meth->result->type.prefix.flags = TD_PSTRING | XPT_TDP_POINTER; + meth->params[0].type.prefix.flags = TD_UINT32; + meth->params[0].flags = XPT_PD_IN; + meth->params[1].type.prefix.flags = TD_BOOL; + meth->params[1].flags = XPT_PD_IN; + +#if 0 + /* const one = 1; */ + id->const_descriptors[0].name = "one"; + id->const_descriptors[0].type.prefix.flags = TD_UINT16; + id->const_descriptors[0].value.ui16 = 1; + + /* const squeamish = "ossifrage"; */ + id->const_descriptors[1].name = "squeamish"; + id->const_descriptors[1].type.prefix.flags = TD_PBSTR | XPT_TDP_POINTER; + id->const_descriptors[1].value.string = XPT_NewStringZ(arena, "ossifrage"); +#endif + + /* serialize it */ + state = XPT_NewXDRState(XPT_ENCODE, NULL, 0); + TRY("NewState (ENCODE)", state); + + ok = XPT_MakeCursor(state, XPT_HEADER, header_sz, cursor); + TRY("MakeCursor", ok); + + ok = XPT_DoHeader(arena, cursor, &header); + TRY("DoHeader", ok); + + out = fopen(argv[1], "wb"); + if (!out) { + perror("FAILED: fopen"); + return 1; + } + + XPT_GetXDRData(state, XPT_HEADER, &head, &len); + fwrite(head, len, 1, out); + + XPT_GetXDRData(state, XPT_DATA, &data, &len); + fwrite(data, len, 1, out); + + if (ferror(out) != 0 || fclose(out) != 0) { + fprintf(stderr, "\nError writing file: %s\n\n", argv[1]); + } else { + fprintf(stderr, "\nFile written: %s\n\n", argv[1]); + } + XPT_DestroyXDRState(state); + + XPT_FreeHeader(arena, header); + XPT_DestroyArena(arena); + + return 0; +} + diff --git a/src/libs/xpcom18a4/xpcom/typelib/xpt/tools/.cvsignore b/src/libs/xpcom18a4/xpcom/typelib/xpt/tools/.cvsignore new file mode 100644 index 00000000..985cc7a7 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/typelib/xpt/tools/.cvsignore @@ -0,0 +1,3 @@ +Makefile +xpt_dump +xpt_link diff --git a/src/libs/xpcom18a4/xpcom/typelib/xpt/tools/Makefile.in b/src/libs/xpcom18a4/xpcom/typelib/xpt/tools/Makefile.in new file mode 100644 index 00000000..bedece8e --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/typelib/xpt/tools/Makefile.in @@ -0,0 +1,90 @@ +# +# ***** 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.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of 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 ***** + +DEPTH = ../../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = xpcom +INTERNAL_TOOLS = 1 + +SIMPLE_PROGRAMS = xpt_dump$(BIN_SUFFIX) xpt_link$(BIN_SUFFIX) + +CSRCS = xpt_dump.c xpt_link.c + +SDK_BINARY = \ + $(SIMPLE_PROGRAMS) \ + $(NULL) + +ifdef CROSS_COMPILE +HOST_SIMPLE_PROGRAMS = $(addprefix host_, $(SIMPLE_PROGRAMS:$(BIN_SUFFIX)=$(HOST_BIN_SUFFIX))) +HOST_CSRCS = $(CSRCS) +endif + +include $(topsrcdir)/config/rules.mk + +# Compile directly against the static lib, so we can use the tools +# during the build without the shared library path being set. +ifeq ($(OS_ARCH),WINNT) +DEFINES += -DEXPORT_XPT_API +endif + +LIBS = $(DIST)/lib/$(LIB_PREFIX)xpt.$(LIB_SUFFIX) + +# Tell the $(SIMPLE_PROGRAMS) target that we need to be recompiled +# when libxpt changes. +EXTRA_DEPS = $(wildcard $(DIST)/lib/$(LIB_PREFIX)xpt.*) + +ifdef CROSS_COMPILE +HOST_LIBS = $(DIST)/host/lib/libhostxpt.$(LIB_SUFFIX) +HOST_EXTRA_DEPS = $(wildcard $(DIST)/host/lib/libhostxpt.*) + +ifdef HOST_NSPR_MDCPUCFG +HOST_CFLAGS += -DMDCPUCFG=$(HOST_NSPR_MDCPUCFG) +endif +endif + + +# Build xpt_link and xpt_dump early. (libs creates .deps used by libs.) +export:: + @$(MAKE) libs + + + diff --git a/src/libs/xpcom18a4/xpcom/typelib/xpt/tools/xpt_dump.c b/src/libs/xpcom18a4/xpcom/typelib/xpt/tools/xpt_dump.c new file mode 100644 index 00000000..8926b9c9 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/typelib/xpt/tools/xpt_dump.c @@ -0,0 +1,941 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* + * A utility for dumping the contents of a typelib file (.xpt) to screen + */ + +#include "xpt_xdr.h" +#include +#ifdef XP_MAC +#include +#include +#include "FullPath.h" +#else +#ifdef XP_OS2_EMX +#include +#endif +#include +#endif +#include +#include +#include "prprf.h" + +#define BASE_INDENT 3 + +static char *type_array[32] = + {"int8", "int16", "int32", "int64", + "uint8", "uint16", "uint32", "uint64", + "float", "double", "boolean", "char", + "wchar_t", "void", "reserved", "reserved", + "reserved", "reserved", "reserved", "reserved", + "reserved", "reserved", "reserved", "reserved", + "reserved", "reserved", "reserved", "reserved", + "reserved", "reserved", "reserved", "reserved"}; + +static char *ptype_array[32] = + {"int8 *", "int16 *", "int32 *", "int64 *", + "uint8 *", "uint16 *", "uint32 *", "uint64 *", + "float *", "double *", "boolean *", "char *", + "wchar_t *", "void *", "nsIID *", "DOMString *", + "string", "wstring", "Interface *", "InterfaceIs *", + "array", "string_s", "wstring_s", "UTF8String *", + "CString *", "AString *", "reserved", "reserved", + "reserved", "reserved", "reserved", "reserved"}; + +static char *rtype_array[32] = + {"int8 &", "int16 &", "int32 &", "int64 &", + "uint8 &", "uint16 &", "uint32 &", "uint64 &", + "float &", "double &", "boolean &", "char &", + "wchar_t &", "void &", "nsIID &", "DOMString &", + "string &", "wstring &", "Interface &", "InterfaceIs &", + "array &", "string_s &", "wstring_s &", "UTF8String &", + "CString &", "AString &", "reserved", "reserved", + "reserved", "reserved", "reserved", "reserved"}; + +PRBool param_problems = PR_FALSE; + +PRBool +XPT_DumpHeader(XPTCursor *cursor, XPTHeader *header, + const int indent, PRBool verbose_mode); + +PRBool +XPT_DumpAnnotations(XPTAnnotation *ann, const int indent, PRBool verbose_mode); + +PRBool +XPT_DumpInterfaceDirectoryEntry(XPTCursor *cursor, + XPTInterfaceDirectoryEntry *ide, + XPTHeader *header, const int indent, + PRBool verbose_mode); + +PRBool +XPT_DumpInterfaceDescriptor(XPTCursor *cursor, XPTInterfaceDescriptor *id, + XPTHeader *header, const int indent, + PRBool verbose_mode); + +PRBool +XPT_DumpMethodDescriptor(XPTHeader *header, XPTMethodDescriptor *md, + XPTInterfaceDescriptor *id, + const int indent, PRBool verbose_mode); +PRBool +XPT_GetStringForType(XPTHeader *header, XPTTypeDescriptor *td, + XPTInterfaceDescriptor *id, + char **type_string); + +PRBool +XPT_DumpXPTString(XPTString *str); + +PRBool +XPT_DumpParamDescriptor(XPTHeader *header, XPTParamDescriptor *pd, + XPTInterfaceDescriptor *id, + const int indent, PRBool verbose_mode, + PRBool is_result); + +PRBool +XPT_DumpTypeDescriptor(XPTTypeDescriptor *td, + XPTInterfaceDescriptor *id, + int indent, PRBool verbose_mode); + +PRBool +XPT_DumpConstDescriptor(XPTHeader *header, XPTConstDescriptor *cd, + XPTInterfaceDescriptor *id, + const int indent, PRBool verbose_mode); + +static void +xpt_dump_usage(char *argv[]) { + fprintf(stdout, "Usage: %s [-v] \n" + " -v verbose mode\n", argv[0]); +} + +#if defined(XP_MAC) && defined(XPIDL_PLUGIN) + +#define main xptdump_main +int xptdump_main(int argc, char *argv[]); + +#define get_file_length mac_get_file_length +extern size_t mac_get_file_length(const char* filename); + +#else /* !(XP_MAC && XPIDL_PLUGIN) */ + +static size_t get_file_length(const char* filename) +{ + struct stat file_stat; + if (stat(filename, &file_stat) != 0) { + perror("FAILED: get_file_length"); + exit(1); + } + return file_stat.st_size; +} + +#endif /* !(XP_MAC && XPIDL_PLUGIN) */ + +int +main(int argc, char **argv) +{ + PRBool verbose_mode = PR_FALSE; + XPTArena *arena; + XPTState *state; + XPTCursor curs, *cursor = &curs; + XPTHeader *header; + size_t flen; + char *name; + char *whole; + FILE *in; + int result = 1; + + switch (argc) { + case 2: + if (argv[1][0] == '-') { + xpt_dump_usage(argv); + return 1; + } + name = argv[1]; + flen = get_file_length(name); + in = fopen(name, "rb"); + break; + case 3: + verbose_mode = PR_TRUE; + if (argv[1][0] != '-' || argv[1][1] != 'v') { + xpt_dump_usage(argv); + return 1; + } + name = argv[2]; + flen = get_file_length(name); + in = fopen(name, "rb"); + break; + default: + xpt_dump_usage(argv); + return 1; + } + + if (!in) { + perror("FAILED: fopen"); + return 1; + } + + arena = XPT_NewArena(1024, sizeof(double), "main xpt_dump arena"); + if (!arena) { + perror("XPT_NewArena failed"); + return 1; + } + + /* after arena creation all exits via 'goto out' */ + + whole = XPT_MALLOC(arena, flen); + if (!whole) { + perror("FAILED: XPT_MALLOC for whole"); + goto out; + } + + if (flen > 0) { + size_t rv = fread(whole, 1, flen, in); + if (rv < flen) { + fprintf(stderr, "short read (%zd vs %zd)! ouch!\n", rv, flen); + goto out; + } + if (ferror(in) != 0 || fclose(in) != 0) + perror("FAILED: Unable to read typelib file.\n"); + + state = XPT_NewXDRState(XPT_DECODE, whole, flen); + if (!XPT_MakeCursor(state, XPT_HEADER, 0, cursor)) { + fprintf(stdout, "XPT_MakeCursor failed for %s\n", name); + goto out; + } + if (!XPT_DoHeader(arena, cursor, &header)) { + fprintf(stdout, + "DoHeader failed for %s. Is %s a valid .xpt file?\n", + name, name); + goto out; + } + + if (!XPT_DumpHeader(cursor, header, BASE_INDENT, verbose_mode)) { + perror("FAILED: XPT_DumpHeader"); + goto out; + } + + if (param_problems) { + fprintf(stdout, "\nWARNING: ParamDescriptors are present with " + "bad in/out/retval flag information.\n" + "These have been marked with 'XXX'.\n" + "Remember, retval params should always be marked as out!\n"); + } + + XPT_DestroyXDRState(state); + XPT_FREE(arena, whole); + + } else { + fclose(in); + perror("FAILED: file length <= 0"); + goto out; + } + + result = 0; + +out: + XPT_DestroyArena(arena); + return result; +} + +PRBool +XPT_DumpHeader(XPTCursor *cursor, XPTHeader *header, + const int indent, PRBool verbose_mode) +{ + int i; + + fprintf(stdout, "Header:\n"); + + if (verbose_mode) { + fprintf(stdout, "%*sMagic beans: ", indent, " "); + for (i=0; i<16; i++) { + fprintf(stdout, "%02x", header->magic[i]); + } + fprintf(stdout, "\n"); + if (strncmp((const char*)header->magic, XPT_MAGIC, 16) == 0) + fprintf(stdout, "%*s PASSED\n", indent, " "); + else + fprintf(stdout, "%*s FAILED\n", indent, " "); + } + fprintf(stdout, "%*sMajor version: %d\n", indent, " ", + header->major_version); + fprintf(stdout, "%*sMinor version: %d\n", indent, " ", + header->minor_version); + fprintf(stdout, "%*sNumber of interfaces: %d\n", indent, " ", + header->num_interfaces); + + if (verbose_mode) { + fprintf(stdout, "%*sFile length: %d\n", indent, " ", + header->file_length); + fprintf(stdout, "%*sData pool offset: %d\n\n", indent, " ", + header->data_pool); + } + + fprintf(stdout, "%*sAnnotations:\n", indent, " "); + if (!XPT_DumpAnnotations(header->annotations, indent*2, verbose_mode)) + return PR_FALSE; + + fprintf(stdout, "\nInterface Directory:\n"); + for (i=0; inum_interfaces; i++) { + if (verbose_mode) { + fprintf(stdout, "%*sInterface #%d:\n", indent, " ", i); + if (!XPT_DumpInterfaceDirectoryEntry(cursor, + &header->interface_directory[i], + header, indent*2, + verbose_mode)) { + return PR_FALSE; + } + } else { + if (!XPT_DumpInterfaceDirectoryEntry(cursor, + &header->interface_directory[i], + header, indent, + verbose_mode)) { + return PR_FALSE; + } + } + } + + return PR_TRUE; +} + +PRBool +XPT_DumpAnnotations(XPTAnnotation *ann, const int indent, PRBool verbose_mode) +{ + int i = -1; + XPTAnnotation *last; + int new_indent = indent + BASE_INDENT; + + do { + i++; + if (XPT_ANN_IS_PRIVATE(ann->flags)) { + if (verbose_mode) { + fprintf(stdout, "%*sAnnotation #%d is private.\n", + indent, " ", i); + } else { + fprintf(stdout, "%*sAnnotation #%d:\n", + indent, " ", i); + } + fprintf(stdout, "%*sCreator: ", new_indent, " "); + if (!XPT_DumpXPTString(ann->creator)) + return PR_FALSE; + fprintf(stdout, "\n"); + fprintf(stdout, "%*sPrivate Data: ", new_indent, " "); + if (!XPT_DumpXPTString(ann->private_data)) + return PR_FALSE; + fprintf(stdout, "\n"); + } else { + fprintf(stdout, "%*sAnnotation #%d is empty.\n", + indent, " ", i); + } + last = ann; + ann = ann->next; + } while (!XPT_ANN_IS_LAST(last->flags)); + + if (verbose_mode) { + fprintf(stdout, "%*sAnnotation #%d is the last annotation.\n", + indent, " ", i); + } + + return PR_TRUE; +} + +static void +print_IID(struct nsID *iid, FILE *file) +{ + fprintf(file, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", + (PRUint32) iid->m0, (PRUint32) iid->m1,(PRUint32) iid->m2, + (PRUint32) iid->m3[0], (PRUint32) iid->m3[1], + (PRUint32) iid->m3[2], (PRUint32) iid->m3[3], + (PRUint32) iid->m3[4], (PRUint32) iid->m3[5], + (PRUint32) iid->m3[6], (PRUint32) iid->m3[7]); + +} + +PRBool +XPT_DumpInterfaceDirectoryEntry(XPTCursor *cursor, + XPTInterfaceDirectoryEntry *ide, + XPTHeader *header, const int indent, + PRBool verbose_mode) +{ + int new_indent = indent + BASE_INDENT; + + if (verbose_mode) { + fprintf(stdout, "%*sIID: ", indent, " "); + print_IID(&ide->iid, stdout); + fprintf(stdout, "\n"); + + fprintf(stdout, "%*sName: %s\n", + indent, " ", ide->name); + fprintf(stdout, "%*sNamespace: %s\n", + indent, " ", ide->name_space ? ide->name_space : "none"); + fprintf(stdout, "%*sAddress of interface descriptor: %p\n", + indent, " ", ide->interface_descriptor); + + fprintf(stdout, "%*sDescriptor:\n", indent, " "); + + if (!XPT_DumpInterfaceDescriptor(cursor, ide->interface_descriptor, + header, new_indent, verbose_mode)) { + return PR_FALSE; + } + } else { + fprintf(stdout, "%*s- %s::%s (", indent, " ", + ide->name_space ? ide->name_space : "", ide->name); + print_IID(&ide->iid, stdout); + fprintf(stdout, "):\n"); + if (!XPT_DumpInterfaceDescriptor(cursor, ide->interface_descriptor, + header, new_indent, verbose_mode)) { + return PR_FALSE; + } + } + + return PR_TRUE; +} + +PRBool +XPT_DumpInterfaceDescriptor(XPTCursor *cursor, XPTInterfaceDescriptor *id, + XPTHeader *header, const int indent, + PRBool verbose_mode) +{ + XPTInterfaceDirectoryEntry *parent_ide; + int i; + int new_indent = indent + BASE_INDENT; + int more_indent = new_indent + BASE_INDENT; + + if (!id) { + fprintf(stdout, "%*s[Unresolved]\n", indent, " "); + return PR_TRUE; + } + + if (id->parent_interface) { + + parent_ide = &header->interface_directory[id->parent_interface - 1]; + + fprintf(stdout, "%*sParent: %s::%s\n", indent, " ", + parent_ide->name_space ? + parent_ide->name_space : "", + parent_ide->name); + } + + fprintf(stdout, "%*sFlags:\n", indent, " "); + + fprintf(stdout, "%*sScriptable: %s\n", new_indent, " ", + XPT_ID_IS_SCRIPTABLE(id->flags) ? "TRUE" : "FALSE"); + + fprintf(stdout, "%*sFunction: %s\n", new_indent, " ", + XPT_ID_IS_FUNCTION(id->flags) ? "TRUE" : "FALSE"); + + if (verbose_mode) { + if (id->parent_interface) { + fprintf(stdout, + "%*sIndex of parent interface (in data pool): %d\n", + indent, " ", id->parent_interface); + + } + } else { + } + + if (id->num_methods > 0) { + if (verbose_mode) { + fprintf(stdout, + "%*s# of Method Descriptors: %d\n", + indent, " ", id->num_methods); + } else { + fprintf(stdout, "%*sMethods:\n", indent, " "); + } + + for (i=0; inum_methods; i++) { + if (verbose_mode) { + fprintf(stdout, "%*sMethod #%d:\n", new_indent, " ", i); + if (!XPT_DumpMethodDescriptor(header, + &id->method_descriptors[i], id, + more_indent, verbose_mode)) { + return PR_FALSE; + } + } else { + if (!XPT_DumpMethodDescriptor(header, + &id->method_descriptors[i], id, + new_indent, verbose_mode)) { + return PR_FALSE; + } + } + } + } else { + fprintf(stdout, "%*sMethods:\n", indent, " "); + fprintf(stdout, "%*sNo Methods\n", new_indent, " "); + } + + if (id->num_constants > 0) { + if (verbose_mode) { + fprintf(stdout, + "%*s# of Constant Descriptors: %d\n", + indent, " ", id->num_constants); + } else { + fprintf(stdout, "%*sConstants:\n", indent, " "); + } + + for (i=0; inum_constants; i++) { + if (verbose_mode) { + fprintf(stdout, "%*sConstant #%d:\n", new_indent, " ", i); + if (!XPT_DumpConstDescriptor(header, + &id->const_descriptors[i], id, + more_indent, verbose_mode)) + return PR_FALSE; + } else { + if (!XPT_DumpConstDescriptor(header, + &id->const_descriptors[i], id, + new_indent, verbose_mode)) { + return PR_FALSE; + } + } + } + } else { + fprintf(stdout, "%*sConstants:\n", indent, " "); + fprintf(stdout, "%*sNo Constants\n", new_indent, " "); + } + + return PR_TRUE; +} + +PRBool +XPT_DumpMethodDescriptor(XPTHeader *header, XPTMethodDescriptor *md, + XPTInterfaceDescriptor *id, + const int indent, PRBool verbose_mode) +{ + int i; + int new_indent = indent + BASE_INDENT; + int more_indent = new_indent + BASE_INDENT; + + if (verbose_mode) { + fprintf(stdout, "%*sName: %s\n", indent, " ", md->name); + fprintf(stdout, "%*sIs Getter? ", indent, " "); + if (XPT_MD_IS_GETTER(md->flags)) + fprintf(stdout, "TRUE\n"); + else + fprintf(stdout, "FALSE\n"); + + fprintf(stdout, "%*sIs Setter? ", indent, " "); + if (XPT_MD_IS_SETTER(md->flags)) + fprintf(stdout, "TRUE\n"); + else + fprintf(stdout, "FALSE\n"); + + fprintf(stdout, "%*sIs NotXPCOM? ", indent, " "); + if (XPT_MD_IS_NOTXPCOM(md->flags)) + fprintf(stdout, "TRUE\n"); + else + fprintf(stdout, "FALSE\n"); + + fprintf(stdout, "%*sIs Constructor? ", indent, " "); + if (XPT_MD_IS_CTOR(md->flags)) + fprintf(stdout, "TRUE\n"); + else + fprintf(stdout, "FALSE\n"); + + fprintf(stdout, "%*sIs Hidden? ", indent, " "); + if (XPT_MD_IS_HIDDEN(md->flags)) + fprintf(stdout, "TRUE\n"); + else + fprintf(stdout, "FALSE\n"); + + fprintf(stdout, "%*s# of arguments: %d\n", indent, " ", md->num_args); + fprintf(stdout, "%*sParameter Descriptors:\n", indent, " "); + + for (i=0; inum_args; i++) { + fprintf(stdout, "%*sParameter #%d:\n", new_indent, " ", i); + + if (!XPT_DumpParamDescriptor(header, &md->params[i], id, + more_indent, verbose_mode, PR_FALSE)) + return PR_FALSE; + } + + fprintf(stdout, "%*sResult:\n", indent, " "); + if (!XPT_DumpParamDescriptor(header, md->result, id, new_indent, + verbose_mode, PR_TRUE)) { + return PR_FALSE; + } + } else { + char *param_type; + XPTParamDescriptor *pd; + + if (!XPT_GetStringForType(header, &md->result->type, id, ¶m_type)) { + return PR_FALSE; + } + fprintf(stdout, "%*s%c%c%c%c%c %s %s(", indent - 6, " ", + XPT_MD_IS_GETTER(md->flags) ? 'G' : ' ', + XPT_MD_IS_SETTER(md->flags) ? 'S' : ' ', + XPT_MD_IS_HIDDEN(md->flags) ? 'H' : ' ', + XPT_MD_IS_NOTXPCOM(md->flags) ? 'N' : ' ', + XPT_MD_IS_CTOR(md->flags) ? 'C' : ' ', + param_type, md->name); + for (i=0; inum_args; i++) { + if (i!=0) { + fprintf(stdout, ", "); + } + pd = &md->params[i]; + if (XPT_PD_IS_IN(pd->flags)) { + fprintf(stdout, "in"); + if (XPT_PD_IS_OUT(pd->flags)) { + fprintf(stdout, "out "); + if (XPT_PD_IS_RETVAL(pd->flags)) { + fprintf(stdout, "retval "); + } + if (XPT_PD_IS_SHARED(pd->flags)) { + fprintf(stdout, "shared "); + } + } else { + fprintf(stdout, " "); + if (XPT_PD_IS_DIPPER(pd->flags)) { + fprintf(stdout, "dipper "); + } + if (XPT_PD_IS_RETVAL(pd->flags)) { + fprintf(stdout, "retval "); + } + } + } else { + if (XPT_PD_IS_OUT(pd->flags)) { + fprintf(stdout, "out "); + if (XPT_PD_IS_RETVAL(pd->flags)) { + fprintf(stdout, "retval "); + } + if (XPT_PD_IS_SHARED(pd->flags)) { + fprintf(stdout, "shared "); + } + } else { + param_problems = PR_TRUE; + fprintf(stdout, "XXX "); + } + } + if (!XPT_GetStringForType(header, &pd->type, id, ¶m_type)) { + return PR_FALSE; + } + fprintf(stdout, "%s", param_type); + } + fprintf(stdout, ");\n"); + } + return PR_TRUE; +} + +PRBool +XPT_GetStringForType(XPTHeader *header, XPTTypeDescriptor *td, + XPTInterfaceDescriptor *id, + char **type_string) +{ + static char buf[128]; /* ugly non-reentrant use of static buffer! */ + PRBool isArray = PR_FALSE; + + int tag = XPT_TDP_TAG(td->prefix); + + if (tag == TD_ARRAY) { + isArray = PR_TRUE; + td = &id->additional_types[td->type.additional_type]; + tag = XPT_TDP_TAG(td->prefix); + } + + if (tag == TD_INTERFACE_TYPE) { + int idx = td->type.iface; + if (!idx || idx > header->num_interfaces) + *type_string = "UNKNOWN_INTERFACE"; + else + *type_string = header->interface_directory[idx-1].name; + } else if (XPT_TDP_IS_POINTER(td->prefix.flags)) { + if (XPT_TDP_IS_REFERENCE(td->prefix.flags)) + *type_string = rtype_array[tag]; + else + *type_string = ptype_array[tag]; + } else { + *type_string = type_array[tag]; + } + + if(isArray) { + sprintf(buf, "%s []", *type_string); + *type_string = buf; + } + + return PR_TRUE; +} + +PRBool +XPT_DumpXPTString(XPTString *str) +{ + int i; + for (i=0; ilength; i++) { + fprintf(stdout, "%c", str->bytes[i]); + } + return PR_TRUE; +} + +PRBool +XPT_DumpParamDescriptor(XPTHeader *header, XPTParamDescriptor *pd, + XPTInterfaceDescriptor *id, + const int indent, PRBool verbose_mode, + PRBool is_result) +{ + int new_indent = indent + BASE_INDENT; + + if (!XPT_PD_IS_IN(pd->flags) && + !XPT_PD_IS_OUT(pd->flags) && + (XPT_PD_IS_RETVAL(pd->flags) || + XPT_PD_IS_SHARED(pd->flags))) { + param_problems = PR_TRUE; + fprintf(stdout, "XXX\n"); + } else { + if (!XPT_PD_IS_IN(pd->flags) && !XPT_PD_IS_OUT(pd->flags)) { + if (is_result) { + if (XPT_TDP_TAG(pd->type.prefix) != TD_UINT32 && + XPT_TDP_TAG(pd->type.prefix) != TD_VOID) { + param_problems = PR_TRUE; + fprintf(stdout, "XXX\n"); + } + } else { + param_problems = PR_TRUE; + fprintf(stdout, "XXX\n"); + } + } + } + + fprintf(stdout, "%*sIn Param? ", indent, " "); + if (XPT_PD_IS_IN(pd->flags)) + fprintf(stdout, "TRUE\n"); + else + fprintf(stdout, "FALSE\n"); + + fprintf(stdout, "%*sOut Param? ", indent, " "); + if (XPT_PD_IS_OUT(pd->flags)) + fprintf(stdout, "TRUE\n"); + else + fprintf(stdout, "FALSE\n"); + + fprintf(stdout, "%*sRetval? ", indent, " "); + if (XPT_PD_IS_RETVAL(pd->flags)) + fprintf(stdout, "TRUE\n"); + else + fprintf(stdout, "FALSE\n"); + + fprintf(stdout, "%*sShared? ", indent, " "); + if (XPT_PD_IS_SHARED(pd->flags)) + fprintf(stdout, "TRUE\n"); + else + fprintf(stdout, "FALSE\n"); + + fprintf(stdout, "%*sDipper? ", indent, " "); + if (XPT_PD_IS_DIPPER(pd->flags)) + fprintf(stdout, "TRUE\n"); + else + fprintf(stdout, "FALSE\n"); + + + fprintf(stdout, "%*sType Descriptor:\n", indent, " "); + if (!XPT_DumpTypeDescriptor(&pd->type, id, new_indent, verbose_mode)) + return PR_FALSE; + + return PR_TRUE; +} + +PRBool +XPT_DumpTypeDescriptor(XPTTypeDescriptor *td, + XPTInterfaceDescriptor *id, + int indent, PRBool verbose_mode) +{ + int new_indent; + + if (XPT_TDP_TAG(td->prefix) == TD_ARRAY) { + fprintf(stdout, "%*sArray (size in arg %d and length in arg %d) of...\n", + indent, " ", td->argnum, td->argnum2); + td = &id->additional_types[td->type.additional_type]; + indent += BASE_INDENT; + } + + new_indent = indent + BASE_INDENT; + + fprintf(stdout, "%*sIs Pointer? ", indent, " "); + if (XPT_TDP_IS_POINTER(td->prefix.flags)) + fprintf(stdout, "TRUE\n"); + else + fprintf(stdout, "FALSE\n"); + + fprintf(stdout, "%*sIs Unique Pointer? ", indent, " "); + if (XPT_TDP_IS_UNIQUE_POINTER(td->prefix.flags)) + fprintf(stdout, "TRUE\n"); + else + fprintf(stdout, "FALSE\n"); + + fprintf(stdout, "%*sIs Reference? ", indent, " "); + if (XPT_TDP_IS_REFERENCE(td->prefix.flags)) + fprintf(stdout, "TRUE\n"); + else + fprintf(stdout, "FALSE\n"); + + fprintf(stdout, "%*sTag: %d\n", indent, " ", + XPT_TDP_TAG(td->prefix)); + + if (XPT_TDP_TAG(td->prefix) == TD_PSTRING_SIZE_IS || + XPT_TDP_TAG(td->prefix) == TD_PWSTRING_SIZE_IS) { + fprintf(stdout, "%*s - size in arg %d and length in arg %d\n", + indent, " ", td->argnum, td->argnum2); + } + + if (XPT_TDP_TAG(td->prefix) == TD_INTERFACE_TYPE) { + fprintf(stdout, "%*sInterfaceTypeDescriptor:\n", indent, " "); + fprintf(stdout, "%*sIndex of IDE: %d\n", new_indent, " ", + td->type.iface); + } + + if (XPT_TDP_TAG(td->prefix) == TD_INTERFACE_IS_TYPE) { + fprintf(stdout, "%*sInterfaceTypeDescriptor:\n", indent, " "); + fprintf(stdout, "%*sIndex of Method Argument: %d\n", new_indent, " ", + td->argnum); + } + + return PR_TRUE; +} + +PRBool +XPT_DumpConstDescriptor(XPTHeader *header, XPTConstDescriptor *cd, + XPTInterfaceDescriptor *id, + const int indent, PRBool verbose_mode) +{ + int new_indent = indent + BASE_INDENT; + char *const_type; +/* char *out; */ + PRUint32 uintout; + PRInt32 intout; + + if (verbose_mode) { + fprintf(stdout, "%*sName: %s\n", indent, " ", cd->name); + fprintf(stdout, "%*sType Descriptor: \n", indent, " "); + if (!XPT_DumpTypeDescriptor(&cd->type, id, new_indent, verbose_mode)) + return PR_FALSE; + fprintf(stdout, "%*sValue: ", indent, " "); + } else { + if (!XPT_GetStringForType(header, &cd->type, id, &const_type)) { + return PR_FALSE; + } + fprintf(stdout, "%*s%s %s = ", indent, " ", const_type, cd->name); + } + + switch(XPT_TDP_TAG(cd->type.prefix)) { + case TD_INT8: + fprintf(stdout, "%d", cd->value.i8); + break; + case TD_INT16: + fprintf(stdout, "%d", cd->value.i16); + break; + case TD_INT64: + /* XXX punt for now to remove NSPR linkage... + * borrow from mozilla/nsprpub/pr/src/io/prprf.c::cvt_ll? */ + +/* out = PR_smprintf("%lld", cd->value.i64); */ +/* fputs(out, stdout); */ +/* PR_smprintf_free(out); */ + LL_L2I(intout, cd->value.i64); + fprintf(stdout, "%d", intout); + break; + case TD_INT32: + fprintf(stdout, "%d", cd->value.i32); + break; + case TD_UINT8: + fprintf(stdout, "%u", cd->value.ui8); + break; + case TD_UINT16: + fprintf(stdout, "%u", cd->value.ui16); + break; + case TD_UINT64: +/* out = PR_smprintf("%lld", cd->value.ui64); */ +/* fputs(out, stdout); */ +/* PR_smprintf_free(out); */ + /* XXX punt for now to remove NSPR linkage. */ + LL_L2UI(uintout, cd->value.ui64); + fprintf(stdout, "%u", uintout); + break; + case TD_UINT32: + fprintf(stdout, "%u", cd->value.ui32); + break; + case TD_FLOAT: + fprintf(stdout, "%f", cd->value.flt); + break; + case TD_DOUBLE: + fprintf(stdout, "%g", cd->value.dbl); + break; + case TD_BOOL: + if (cd->value.bul) + fprintf(stdout, "TRUE"); + else + fprintf(stdout, "FALSE"); + break; + case TD_CHAR: + fprintf(stdout, "%c", cd->value.ch); + break; + case TD_WCHAR: + fprintf(stdout, "%c", cd->value.wch & 0xff); + break; + case TD_VOID: + fprintf(stdout, "VOID"); + break; + case TD_PNSIID: + if (XPT_TDP_IS_POINTER(cd->type.prefix.flags)) { + print_IID(cd->value.iid, stdout); + } else + return PR_FALSE; + break; + case TD_PSTRING: + if (XPT_TDP_IS_POINTER(cd->type.prefix.flags)) { + fprintf(stdout, "%s", cd->value.str); + } else + return PR_FALSE; + break; + case TD_PWSTRING: + if (XPT_TDP_IS_POINTER(cd->type.prefix.flags)) { + PRUint16 *ch = cd->value.wstr; + while (*ch) { + fprintf(stdout, "%c", *ch & 0xff); + ch++; + } + } else + return PR_FALSE; + break; + default: + perror("Unrecognized type"); + return PR_FALSE; + break; + } + + if (verbose_mode) { + fprintf(stdout, "\n"); + } else { + fprintf(stdout, ";\n"); + } + + return PR_TRUE; +} diff --git a/src/libs/xpcom18a4/xpcom/typelib/xpt/tools/xpt_link.c b/src/libs/xpcom18a4/xpcom/typelib/xpt/tools/xpt_link.c new file mode 100644 index 00000000..872b96fd --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/typelib/xpt/tools/xpt_link.c @@ -0,0 +1,883 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* + * A utility for linking multiple typelib files. + */ + +#include "xpt_xdr.h" +#include +#ifdef XP_MAC +#include +#else +#include +#endif +#include +#include +#include "prlong.h" + +#ifndef NULL +#define NULL (void *) 0 +#endif + +/* Forward declarations. */ +typedef struct fixElement fixElement; +static int compare_IDEs_by_IID(const void *ap, const void *bp); +static int compare_IDE_with_zero(const void *ap); +static int compare_IDEs_by_name(const void *ap, const void *bp); +static int compare_IDEs_by_name_space(const void *ap, const void *bp); +static int compare_strings(const void *ap, const void *bp); +static int compare_pointers(const void *ap, const void *bp); +static int compare_fixElements_by_IID(const void *ap, const void *bp); +static int compare_fixElements_by_name(const void *ap, const void *bp); +static int compare_IIDs(const void *ap, const void *bp); +PRBool shrink_IDE_array(XPTInterfaceDirectoryEntry *ide, + int element_to_delete, int num_interfaces); +PRBool update_fix_array(XPTArena *arena, fixElement *fix, int element_to_delete, + int num_interfaces, int replacement); +static int get_new_index(const fixElement *fix, int num_elements, + int target_file, int target_interface); +PRBool copy_IDE(XPTInterfaceDirectoryEntry *from, + XPTInterfaceDirectoryEntry *to); +PRBool copy_fixElement(fixElement *from, fixElement *to); +static void print_IID(struct nsID *iid, FILE *file); +static void xpt_link_usage(char *argv[]); + +struct fixElement { + nsID iid; + char* name; + int file_num; + int interface_num; + PRBool is_deleted; + /* These next two variables will point you to the substitute interface + * if this one has been deleted. + */ + int maps_to_file_num; + int maps_to_interface_num; +}; + +/* Global variables. */ +PRUint16 trueNumberOfInterfaces = 0; +PRUint16 totalNumberOfInterfaces = 0; +PRUint16 oldTotalNumberOfInterfaces = 0; + +/* The following globals are explained in xpt_struct.h */ +PRUint8 major_version = XPT_MAJOR_VERSION; +PRUint8 minor_version = XPT_MINOR_VERSION; + +#if defined(XP_MAC) && defined(XPIDL_PLUGIN) + +#define main xptlink_main +int xptlink_main(int argc, char *argv[]); +extern size_t mac_get_file_length(const char* filename); +#define get_file_length mac_get_file_length + +#else + +static size_t get_file_length(const char* filename) +{ + struct stat file_stat; + if (stat(filename, &file_stat) != 0) { + perror("FAILED: get_file_length"); + exit(1); + } + return file_stat.st_size; +} + +#endif /* XP_MAC && XPIDL_PLUGIN */ + +int +main(int argc, char **argv) +{ + XPTArena *arena; + XPTState *state; + XPTCursor curs, *cursor = &curs; + XPTHeader *header; + XPTInterfaceDirectoryEntry *IDE_array = NULL; + XPTInterfaceDescriptor *id; + XPTTypeDescriptor *td; + XPTAnnotation *ann, *first_ann; + PRUint32 header_sz, len; + PRUint32 oldOffset; + PRUint32 newOffset; + size_t flen = 0; + char *head, *data, *whole; + const char *outFileName; + FILE *in, *out; + fixElement *fix_array = NULL; + int i,j; + int k = 0; + + if (argc < 3) { + xpt_link_usage(argv); + return 1; + } + + arena = XPT_NewArena(1024 * 10, sizeof(double), "main xpt_link arena"); + if (!arena) { + perror("FAILED: XPT_NewArena"); + return 1; + } + + first_ann = XPT_NewAnnotation(arena, XPT_ANN_LAST, NULL, NULL); + + /* Check if the "-t version numnber" cmd line arg is present */ + i = 1; + if (argv[i][0] == '-' && argv[i][1] == 't') { + /* Parse for "-t version number" */ + + /* If -t is the last argument on the command line, we have a problem */ + if (i + 1 == argc) { + fprintf(stderr, "ERROR: missing version number after -t\n"); + xpt_link_usage(argv); + return 1; + } + + /* + * Assume that the argument after "-t" is the version number string + * and search for it in our internal list of acceptable version + * numbers. + */ + + switch (XPT_ParseVersionString(argv[++i], &major_version, + &minor_version)) { + case XPT_VERSION_CURRENT: + case XPT_VERSION_OLD: + break; + case XPT_VERSION_UNSUPPORTED: + fprintf(stderr, "ERROR: version \"%s\" not supported.\n", + argv[i]); + xpt_link_usage(argv); + return 1; + case XPT_VERSION_UNKNOWN: + default: + fprintf(stderr, "ERROR: version \"%s\" not recognised.\n", + argv[i]); + xpt_link_usage(argv); + return 1; + } + + /* Hang onto the output file name. It's needed later. */ + outFileName = argv[++i]; + + /* Increment i to the cmd line arg after outFileName */ + i++; + } + else { + outFileName = argv[1]; + i = 2; + } + + for ( /* use i from earlier */ ; i < argc; i++) { + char *name = argv[i]; + + flen = get_file_length(name); + if (!flen) { + fprintf(stderr, "ERROR: file %s is zero length\n", name); + return 1; + } + + in = fopen(name, "rb"); + if (!in) { + perror("FAILED: fopen"); + return 1; + } + + whole = XPT_MALLOC(arena, flen); + if (!whole) { + perror("FAILED: XPT_MALLOC for whole"); + return 1; + } + + if (flen > 0) { + size_t rv = fread(whole, 1, flen, in); + if (rv < flen) { + fprintf(stderr, "short read (%zd vs %zd)! ouch!\n", rv, flen); + return 1; + } + if (ferror(in) != 0 || fclose(in) != 0) { + perror("FAILED: Unable to read typelib file.\n"); + return 1; + } + + state = XPT_NewXDRState(XPT_DECODE, whole, flen); + if (!XPT_MakeCursor(state, XPT_HEADER, 0, cursor)) { + fprintf(stdout, "XPT_MakeCursor failed for %s\n", name); + return 1; + } + if (!XPT_DoHeader(arena, cursor, &header)) { + fprintf(stdout, + "DoHeader failed for %s. Is %s a valid .xpt file?\n", + name, name); + return 1; + } + + /* + * Make sure that the version of the typelib file is less than or + * equal to the version specified in the -t cmd line arg. + */ + + if (header && + (header->major_version > major_version || + (header->major_version == major_version && + header->minor_version > minor_version))) { + fprintf(stderr, "FAILED: %s's version, %d.%d, is newer than " + "the version (%d.%d) specified in the -t " + "command line argument.\n", + name, header->major_version, header->minor_version, + major_version, minor_version); + return 1; + } + + oldTotalNumberOfInterfaces = totalNumberOfInterfaces; + totalNumberOfInterfaces += header->num_interfaces; + if (header->num_interfaces > 0) { + XPTInterfaceDirectoryEntry *newIDE; + fixElement *newFix; + + newIDE = (XPTInterfaceDirectoryEntry *) + XPT_MALLOC(arena, totalNumberOfInterfaces * + sizeof(XPTInterfaceDirectoryEntry)); + if (!newIDE) { + perror("FAILED: XPT_MALLOC of IDE_array"); + return 1; + } + + if (IDE_array) { + if (oldTotalNumberOfInterfaces) + memcpy(newIDE, IDE_array, + oldTotalNumberOfInterfaces * + sizeof(XPTInterfaceDirectoryEntry)); + XPT_FREE(arena, IDE_array); + } + IDE_array = newIDE; + + + newFix = (fixElement *) + XPT_MALLOC(arena, + totalNumberOfInterfaces * sizeof(fixElement)); + if (!newFix) { + perror("FAILED: XPT_MALLOC of fix_array"); + return 1; + } + + if (fix_array) { + if (oldTotalNumberOfInterfaces) + memcpy(newFix, fix_array, + oldTotalNumberOfInterfaces * + sizeof(fixElement)); + XPT_FREE(arena, fix_array); + } + fix_array = newFix; + + for (j=0; jnum_interfaces; j++) { + if (!copy_IDE(&header->interface_directory[j], + &IDE_array[k])) { + perror("FAILED: 1st copying of IDE"); + return 1; + } + fix_array[k].iid = IDE_array[k].iid; + fix_array[k].name = IDE_array[k].name; + fix_array[k].file_num = i-2; + fix_array[k].interface_num = j+1; + fix_array[k].is_deleted = PR_FALSE; + fix_array[k].maps_to_file_num = i-2; + fix_array[k].maps_to_interface_num = j+1; + + k++; + } + } + + /* Copy the annotations if they are not 'empty' + */ + if (header->annotations != NULL && + header->annotations->flags != XPT_ANN_LAST) { + ann = first_ann; + while (ann->next != NULL) { + ann = ann->next; + } + ann->next = header->annotations; + } + + XPT_FREEIF(arena, header); + if (state) + XPT_DestroyXDRState(state); + XPT_FREE(arena, whole); + flen = 0; + + } else { + fclose(in); + perror("FAILED: file length <= 0"); + return 1; + } + } + + /* Make sure the last annotation is the only one marked as XP_ANN_LAST. + */ + ann = first_ann; + while (ann->next != NULL) { + ann->flags &= ~XPT_ANN_LAST; + ann = ann->next; + } + ann->flags |= XPT_ANN_LAST; + + /* Sort both IDE_array and fix_array by name so we can check for + * name_space::name collisions. + */ + qsort(IDE_array, + totalNumberOfInterfaces, + sizeof(XPTInterfaceDirectoryEntry), + compare_IDEs_by_name); + + qsort(fix_array, + totalNumberOfInterfaces, + sizeof(fixElement), + compare_fixElements_by_name); + + /* trueNumberOfInterfaces == number of interfaces left after deletions + * are made. Initialize it here to be the same as the total number of + * interfaces we'ce encountered thus far. + */ + trueNumberOfInterfaces = totalNumberOfInterfaces; + + /* Iterate through the sorted interfaces. Start at one so we don't + * accidentally walk off the end of the array. + */ + i = 1; + while (i != trueNumberOfInterfaces) { + + /* Check for name_space::name collision. + */ + if (compare_strings(IDE_array[i-1].name, + IDE_array[i].name) == 0 && + compare_strings(IDE_array[i-1].name_space, + IDE_array[i].name_space) == 0) { + + /* If one of the interfaces is unresolved, delete that one + * preferentailly. + */ + if (!IDE_array[i-1].interface_descriptor) { + /* Shrink the IDE_array to delete the duplicate interface. + */ + if (!shrink_IDE_array(IDE_array, + i-1, + trueNumberOfInterfaces)) { + perror("FAILED: shrink_IDE_array"); + return 1; + } + /* Update the fix array. This involves moving the deleted + * entry to the end of the array (rather than deleting it) + * and mapping it to the "replacement" element so we can + * update interface indices appropriately later. + */ + update_fix_array(arena, fix_array, i-1, + totalNumberOfInterfaces, i); + /* Decrement the true number of interfaces since we just + * deleted one. There's more than one way to get out of + * this loop. + */ + trueNumberOfInterfaces--; + } else { + if (!IDE_array[i].interface_descriptor || + (compare_IIDs(&IDE_array[i-1].iid, &IDE_array[i].iid) == 0)) + { + /* Shrink the IDE_array to delete the duplicate interface. + */ + if (!shrink_IDE_array(IDE_array, + i, + trueNumberOfInterfaces)) { + perror("FAILED: shrink_IDE_array"); + return 1; + } + /* Update the fix array. This involves moving the deleted + * entry to the end of the array (rather than deleting it) + * and mapping it to the "replacement" element so we can + * update interface indices appropriately later. + */ + update_fix_array(arena, fix_array, i, + totalNumberOfInterfaces, i-1); + /* Decrement the true number of interfaces since we just + * deleted one. There's more than one way to get out of + * this loop. + */ + trueNumberOfInterfaces--; + } else { + /* Found interfaces with duplicate names but different + * iids! */ + char *ns = IDE_array[i].name_space; + fprintf(stderr, + "ERROR: found duplicate definitions of interface " + "%s%s%s with iids \n", + ns ? ns : "", ns ? "::" : "", IDE_array[i].name); + print_IID(&IDE_array[i].iid, stderr); + fprintf(stderr, " and "); + print_IID(&IDE_array[i-1].iid, stderr); + fprintf(stderr, "\n"); + return 1; + } + } + } else { + /* Only increment if there was no name_space::name collision. + */ + i++; + } + } + + /* Sort the IDE_array (put them in their final order) so that updating + * of indices will be meaningful. + */ + qsort(IDE_array, + trueNumberOfInterfaces, + sizeof(XPTInterfaceDirectoryEntry), + compare_IDEs_by_IID); + + /* Sort the fix_array to match the IDE_array. + */ + qsort(fix_array, + trueNumberOfInterfaces, + sizeof(fixElement), + compare_fixElements_by_IID); + + /* Iterate through the remaining interfaces (those not deleted) + * looking for references to interfaces (such as id->parent_interface) + * which need an updated index number. + */ + for (i=0; iparent_interface && id->parent_interface != 0) { + id->parent_interface = + get_new_index(fix_array, totalNumberOfInterfaces, + fix_array[i].file_num, id->parent_interface); + } + /* Iterate through the method descriptors looking for params of + * type TD_INTERFACE_TYPE. + */ + for (j=0; jnum_methods; j++) { + /* Cycle through the params first. + */ + for (k=0; kmethod_descriptors[j].num_args; k++) { + /* Define td to save some keystrokes. + */ + td = &id->method_descriptors[j].params[k].type; + + while (XPT_TDP_TAG(td->prefix) == TD_ARRAY) { + td = &id->additional_types[td->type.additional_type]; + } + + if (XPT_TDP_TAG(td->prefix) == TD_INTERFACE_TYPE) { + td->type.iface = + get_new_index(fix_array, + totalNumberOfInterfaces, + fix_array[i].file_num, + td->type.iface); + } + } + + /* Check the result param too. Define td again to save + * some keystrokes. + */ + td = &id->method_descriptors[j].result->type; + if (XPT_TDP_TAG(td->prefix) == TD_INTERFACE_TYPE) { + td->type.iface = + get_new_index(fix_array, totalNumberOfInterfaces, + fix_array[i].file_num, + td->type.iface); + } + } + } + } + + /* Iterate through the array quickly looking for duplicate IIDS. + * This shouldn't happen, i.e. is a failure condition, so bail + * if we find a duplicate. If we have more than one entry, start + * at one so we don't accidentally grep the ether. + */ + if (trueNumberOfInterfaces>1) { + for (i=1; iannotations = first_ann; + for (i=0; iinterface_directory[i])) { + perror("FAILED: 2nd copying of IDE"); + return 1; + } + } + + header_sz = XPT_SizeOfHeaderBlock(header); + + state = XPT_NewXDRState(XPT_ENCODE, NULL, 0); + if (!state) { + perror("FAILED: error creating XDRState"); + return 1; + } + + XPT_SetDataOffset(state, header_sz); + + if (!XPT_MakeCursor(state, XPT_HEADER, header_sz, cursor)) { + perror("FAILED: error making cursor"); + return 1; + } + oldOffset = cursor->offset; + if (!XPT_DoHeader(arena, cursor, &header)) { + perror("FAILED: error doing Header"); + return 1; + } + newOffset = cursor->offset; + XPT_GetXDRDataLength(state, XPT_HEADER, &len); + header->file_length = len; + XPT_GetXDRDataLength(state, XPT_DATA, &len); + header->file_length += len; + XPT_SeekTo(cursor, oldOffset); + if (!XPT_DoHeaderPrologue(arena, cursor, &header, NULL)) { + perror("FAILED: error doing Header"); + return 1; + } + XPT_SeekTo(cursor, newOffset); + out = fopen(outFileName, "wb"); + if (!out) { + perror("FAILED: fopen"); + return 1; + } + + XPT_GetXDRData(state, XPT_HEADER, &head, &len); + fwrite(head, len, 1, out); + + XPT_GetXDRData(state, XPT_DATA, &data, &len); + fwrite(data, len, 1, out); + + if (ferror(out) != 0 || fclose(out) != 0) { + fprintf(stderr, "Error writing file: %s\n", argv[1]); + } else { +/* fprintf(stderr, "File written: %s\n", argv[1]); */ + } + + if (state) + XPT_DestroyXDRState(state); + + XPT_DestroyArena(arena); + + return 0; +} + +static int +compare_IDEs_by_IID(const void *ap, + const void *bp) +{ + const XPTInterfaceDirectoryEntry *ide1 = ap, *ide2 = bp; + + int answer = compare_IIDs(&ide1->iid, &ide2->iid); + if(!answer) + answer = compare_strings(ide1->name, ide2->name); + + return answer; +} + +/* For detecting unresolved interfaces. */ +const nsID iid_zero = { 0x0, 0x0, 0x0, + { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 } }; + +static int +compare_IDE_with_zero(const void *ap) +{ + const XPTInterfaceDirectoryEntry *ide1 = ap; + + return compare_IIDs(&ide1->iid, &iid_zero); +} + +static int +compare_fixElements_by_IID(const void *ap, + const void *bp) +{ + const fixElement *fix1 = ap, *fix2 = bp; + + int answer = compare_IIDs(&fix1->iid, &fix2->iid); + if(!answer) + answer = compare_strings(fix1->name, fix2->name); + + return answer; +} + +static int +compare_IDEs_by_name(const void *ap, + const void *bp) +{ + const XPTInterfaceDirectoryEntry *ide1 = ap, *ide2 = bp; + + int answer = compare_strings(ide1->name, ide2->name); + if(!answer) + answer = compare_pointers(ide1->name, ide2->name); + + return answer; +} + +static int +compare_IDEs_by_name_space(const void *ap, + const void *bp) +{ + const XPTInterfaceDirectoryEntry *ide1 = ap, *ide2 = bp; + + return compare_strings(ide1->name_space, ide2->name_space); +} + +static int +compare_strings(const void *ap, const void *bp) +{ + const char *string1 = ap, *string2 = bp; + + if (!string1 && !string2) + return 0; + if (!string1) + return -1; + if (!string2) + return 1; + + return strcmp(string1, string2); +} + +static int +compare_pointers(const void *ap, const void *bp) +{ + if (ap == bp) { +#ifdef DEBUG_jband + perror("name addresses were equal!"); +#endif + return 0; + } + if (ap > bp) + return 1; + return -1; +} + +static int +compare_fixElements_by_name(const void *ap, + const void *bp) +{ + const fixElement *fix1 = ap, *fix2 = bp; + + int answer= compare_strings(fix1->name, fix2->name); + if(!answer) + answer = compare_pointers(fix1->name, fix2->name); + + return answer; +} + +static int +compare_IIDs(const void *ap, const void *bp) +{ + const nsID *a = ap, *b = bp; + int i; +#define COMPARE(field) if (a->field > b->field) return 1; \ + if (b->field > a->field) return -1; + COMPARE(m0); + COMPARE(m1); + COMPARE(m2); + for (i = 0; i < 8; i++) { + COMPARE(m3[i]); + } + return 0; +#undef COMPARE +} + +PRBool +shrink_IDE_array(XPTInterfaceDirectoryEntry *ide, int element_to_delete, + int num_interfaces) +{ + int i; + + if (element_to_delete >= num_interfaces) { + return PR_FALSE; + } + + for (i=element_to_delete+1; i= num_interfaces) { + return PR_FALSE; + } + + deleted = XPT_CALLOC(arena, sizeof(fixElement)); + if (!copy_fixElement(&fix[element_to_delete], deleted)) { + return PR_FALSE; + } + deleted->is_deleted = PR_TRUE; + deleted->maps_to_file_num = fix[replacement].file_num; + deleted->maps_to_interface_num = fix[replacement].interface_num; + + for (i=element_to_delete+1; iiid = from->iid; + to->name = from->name; + to->name_space = from->name_space; + to->interface_descriptor = from->interface_descriptor; + return PR_TRUE; +} + +PRBool +copy_fixElement(fixElement *from, fixElement *to) +{ + if (!from || !to) { + return PR_FALSE; + } + + to->iid = from->iid; + to->name = from->name; + to->file_num = from->file_num; + to->interface_num = from->interface_num; + to->is_deleted = from->is_deleted; + to->maps_to_file_num = from->maps_to_file_num; + to->maps_to_interface_num = from->maps_to_interface_num; + + return PR_TRUE; +} + +static void +print_IID(struct nsID *iid, FILE *file) +{ + fprintf(file, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", + (PRUint32) iid->m0, (PRUint32) iid->m1,(PRUint32) iid->m2, + (PRUint32) iid->m3[0], (PRUint32) iid->m3[1], + (PRUint32) iid->m3[2], (PRUint32) iid->m3[3], + (PRUint32) iid->m3[4], (PRUint32) iid->m3[5], + (PRUint32) iid->m3[6], (PRUint32) iid->m3[7]); +} + +static void +xpt_link_usage(char *argv[]) +{ + fprintf(stdout, "Usage: %s [-t version number] outfile file1.xpt file2.xpt ...\n" + " Links multiple typelib files into one outfile\n" + " -t create a typelib of an older version number\n", argv[0]); +} + diff --git a/src/libs/xpcom18a4/xpcom/windbgdlg/.cvsignore b/src/libs/xpcom18a4/xpcom/windbgdlg/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/windbgdlg/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/xpcom/windbgdlg/Makefile.in b/src/libs/xpcom18a4/xpcom/windbgdlg/Makefile.in new file mode 100644 index 00000000..da1bcfae --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/windbgdlg/Makefile.in @@ -0,0 +1,50 @@ +# +# ***** 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.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of 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 ***** + +DEPTH = ../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +SIMPLE_PROGRAMS = windbgdlg$(BIN_SUFFIX) + +CPPSRCS = windbgdlg.cpp + +include $(topsrcdir)/config/rules.mk + diff --git a/src/libs/xpcom18a4/xpcom/windbgdlg/windbgdlg.cpp b/src/libs/xpcom18a4/xpcom/windbgdlg/windbgdlg.cpp new file mode 100644 index 00000000..9023ef4d --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/windbgdlg/windbgdlg.cpp @@ -0,0 +1,60 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** 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 Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * John Bandhauer + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Windows only app to show a modal debug dialog - launched by nsDebug.cpp */ + +#include + +int WINAPI +WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, + LPSTR lpszCmdLine, int nCmdShow) +{ + static char msg[4048]; + + wsprintf(msg, + "%s\n\nClick Abort to exit the Application.\n" + "Click Retry to Debug the Application..\n" + "Click Ignore to continue running the Application.", + lpszCmdLine); + + return MessageBox(NULL, msg, "nsDebug::Assertion", + MB_ICONSTOP | MB_SYSTEMMODAL| + MB_ABORTRETRYIGNORE | MB_DEFBUTTON3); +} diff --git a/src/libs/xpcom18a4/xpcom/xpcom-config.h.in b/src/libs/xpcom18a4/xpcom/xpcom-config.h.in new file mode 100644 index 00000000..5338a41d --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/xpcom-config.h.in @@ -0,0 +1,65 @@ +/* Global defines needed by xpcom clients */ + +#ifndef _XPCOM_CONFIG_H_ +#define _XPCOM_CONFIG_H_ + +/* Define this to throw() if the compiler complains about + * constructors returning NULL + */ +#undef CPP_THROW_NEW + +/* Define if the c++ compiler supports a 2-byte wchar_t */ +#undef HAVE_CPP_2BYTE_WCHAR_T + +/* Define if the c++ compiler supports changing access with |using| */ +#undef HAVE_CPP_ACCESS_CHANGING_USING + +/* Define if the c++ compiler can resolve ambiguity with |using| */ +#undef HAVE_CPP_AMBIGUITY_RESOLVING_USING + +/* Define if the c++ compiler has builtin Bool type */ +#undef HAVE_CPP_BOOL + +/* Define if a dyanmic_cast to void* gives the most derived object */ +#undef HAVE_CPP_DYNAMIC_CAST_TO_VOID_PTR + +/* Define if the c++ compiler supports the |explicit| keyword */ +#undef HAVE_CPP_EXPLICIT + +/* Define if the c++ compiler supports the modern template + * specialization syntax + */ +#undef HAVE_CPP_MODERN_SPECIALIZE_TEMPLATE_SYNTAX + +/* Define if the c++ compiler supports the |std| namespace */ +#undef HAVE_CPP_NAMESPACE_STD + +/* Define if the c++ compiler supports reinterpret_cast */ +#undef HAVE_CPP_NEW_CASTS + +/* Define if the c++ compiler supports partial template specialization */ +#undef HAVE_CPP_PARTIAL_SPECIALIZATION + +/* Define if the c++ compiler has trouble comparing a constant + * reference to a templatized class to zero + */ +#undef HAVE_CPP_TROUBLE_COMPARING_TO_ZERO + +/* Define if the c++ compiler supports the |typename| keyword */ +#undef HAVE_CPP_TYPENAME + +/* Define if the stanard template operator!=() is ambiguous */ +#undef HAVE_CPP_UNAMBIGUOUS_STD_NOTEQUAL + +/* Define if statvfs() is available */ +#undef HAVE_STATVFS + +/* Define if the c++ compiler requires implementations of + * unused virtual methods + */ +#undef NEED_CPP_UNUSED_IMPLEMENTATIONS + +/* Define to either or */ +#undef NEW_H + +#endif /* _XPCOM_CONFIG_H_ */ diff --git a/src/libs/xpcom18a4/xpcom/xpcom-private.h.in b/src/libs/xpcom18a4/xpcom/xpcom-private.h.in new file mode 100644 index 00000000..ae1c4605 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/xpcom-private.h.in @@ -0,0 +1,31 @@ +/* The following defines are only used by the xpcom implementation */ + +#ifndef _XPCOM_PRIVATE_H_ +#define _XPCOM_PRIVATE_H_ + +/* Define to build the static component loader */ +#undef ENABLE_STATIC_COMPONENT_LOADER + +/* Define if getpagesize() is available */ +#undef HAVE_GETPAGESIZE + +/* Define if iconv() is available */ +#undef HAVE_ICONV + +/* Define if iconv() supports const input */ +#undef HAVE_ICONV_WITH_CONST_INPUT + +/* Define if mbrtowc() is available */ +#undef HAVE_MBRTOWC + +/* Define if is present */ +#undef HAVE_SYS_MOUNT_H + +/* Define if is present */ +#undef HAVE_SYS_VFS_H + +/* Define if wcrtomb() is available */ +#undef HAVE_WCRTOMB + +#endif /* _XPCOM_PRIVATE_H_ */ + -- cgit v1.2.3
The xptcall porting document has been moved to: +

+http://lxr.mozilla.org/mozilla/source/xpcom/reflect/xptcall/porting.html +

+Please update your links. +