Compare commits
107 Commits
tags/Makef
...
CacheInteg
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
22c40d96b2 | ||
|
|
06a79b2069 | ||
|
|
ebc4face0d | ||
|
|
150696bb86 | ||
|
|
683045595b | ||
|
|
7f09538b93 | ||
|
|
bb364ef512 | ||
|
|
7c96c92a19 | ||
|
|
a6defdef4c | ||
|
|
76159a2caf | ||
|
|
1988cb05b5 | ||
|
|
dd8c6b3bed | ||
|
|
bc64749366 | ||
|
|
2e9287bd58 | ||
|
|
0f2274a140 | ||
|
|
957fa10cac | ||
|
|
e603146886 | ||
|
|
cb698a0df1 | ||
|
|
1b918d9ef0 | ||
|
|
6407144c9f | ||
|
|
2ed563a178 | ||
|
|
4becc0b508 | ||
|
|
7d5427ea31 | ||
|
|
99904bcc48 | ||
|
|
bcb56c9593 | ||
|
|
f18bc8e6cd | ||
|
|
7d14c5669a | ||
|
|
c0dd3df02e | ||
|
|
e5cc84978f | ||
|
|
5694537330 | ||
|
|
297c5ceba3 | ||
|
|
e0311312f7 | ||
|
|
cf3dc77b02 | ||
|
|
dd2506a737 | ||
|
|
b1bee1f21c | ||
|
|
48ecc5625b | ||
|
|
1b791685e6 | ||
|
|
dc94d1d6e2 | ||
|
|
f5b437ade3 | ||
|
|
8c0b4b3e4a | ||
|
|
fb640ab144 | ||
|
|
106e263b33 | ||
|
|
85045a8552 | ||
|
|
a2279be132 | ||
|
|
0ce702d402 | ||
|
|
f14d03cd67 | ||
|
|
b91343fdf6 | ||
|
|
2c517489b5 | ||
|
|
ae57da58eb | ||
|
|
8d4586dd65 | ||
|
|
9b473ad9be | ||
|
|
2ad227a994 | ||
|
|
94d8da33c1 | ||
|
|
81c05809fd | ||
|
|
e30547b2b2 | ||
|
|
257f9cfaaa | ||
|
|
96e2654e43 | ||
|
|
3b023433be | ||
|
|
1b89716afe | ||
|
|
ad02058877 | ||
|
|
fa8a3196e7 | ||
|
|
5c2c543e58 | ||
|
|
c588721cc0 | ||
|
|
0b049b17ba | ||
|
|
854ef4631d | ||
|
|
051c558653 | ||
|
|
37a04adb09 | ||
|
|
c823c04b45 | ||
|
|
03cbd000eb | ||
|
|
a91e91a1c7 | ||
|
|
be7a5a48b6 | ||
|
|
b2bc7468e8 | ||
|
|
9692dfd994 | ||
|
|
f3edd4cfb5 | ||
|
|
33403345c1 | ||
|
|
20c850de23 | ||
|
|
e8b619cd02 | ||
|
|
eed396bb92 | ||
|
|
41d44c070b | ||
|
|
698ba42268 | ||
|
|
1a0fd23991 | ||
|
|
67dded330b | ||
|
|
936ff4777a | ||
|
|
96c55e42f7 | ||
|
|
82fa0cf06a | ||
|
|
98c8285334 | ||
|
|
bad4b683f4 | ||
|
|
cb5269a28a | ||
|
|
74712f3635 | ||
|
|
9f8ea739db | ||
|
|
97a10dd7c6 | ||
|
|
85a132fac0 | ||
|
|
e594eee877 | ||
|
|
9148eee3d6 | ||
|
|
b5989a8382 | ||
|
|
2b861f60d9 | ||
|
|
87db050b37 | ||
|
|
ffe483cf95 | ||
|
|
52aa17a1c3 | ||
|
|
5fdb3aa69e | ||
|
|
8cae473bc0 | ||
|
|
0719303755 | ||
|
|
90d3e40858 | ||
|
|
c792b2d35c | ||
|
|
7a4377d840 | ||
|
|
a5fa416010 | ||
|
|
49d00db5e2 |
1153
mozilla/netwerk/base/src/nsFileTransport.cpp
Normal file
1153
mozilla/netwerk/base/src/nsFileTransport.cpp
Normal file
File diff suppressed because it is too large
Load Diff
38
mozilla/netwerk/cache/Makefile.in
vendored
Normal file
38
mozilla/netwerk/cache/Makefile.in
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
#
|
||||
# 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
|
||||
|
||||
DIRS = \
|
||||
public \
|
||||
memcache \
|
||||
filecache \
|
||||
mgr \
|
||||
build \
|
||||
$(NULL)
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
33
mozilla/netwerk/cache/Makefile.win
vendored
Executable file
33
mozilla/netwerk/cache/Makefile.win
vendored
Executable file
@@ -0,0 +1,33 @@
|
||||
#!gmake
|
||||
#
|
||||
# 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=..\..
|
||||
DIRS= \
|
||||
public \
|
||||
mgr \
|
||||
memcache \
|
||||
filecache \
|
||||
build \
|
||||
$(NULL)
|
||||
|
||||
include <$(DEPTH)\config\rules.mak>
|
||||
|
||||
54
mozilla/netwerk/cache/build/Makefile.in
vendored
Normal file
54
mozilla/netwerk/cache/build/Makefile.in
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
#
|
||||
# The contents of this file are subject to the Netscape Public License
|
||||
# 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) 1998 Netscape Communications Corporation. All Rights
|
||||
# Reserved.
|
||||
#
|
||||
|
||||
DEPTH = ../../..
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
MODULE = nkcacke
|
||||
LIBRARY_NAME = necko_cache
|
||||
IS_COMPONENT = 1
|
||||
|
||||
CPPSRCS = nsNetDataCacheModule.cpp
|
||||
|
||||
SHARED_LIBRARY_LIBS = \
|
||||
$(DIST)/lib/libnkcachemgr_s.a \
|
||||
$(DIST)/lib/libnkfilecache_s.a \
|
||||
$(DIST)/lib/libnkmemcache_s.a \
|
||||
$(DIST)/lib/libmozdbm_s.a \
|
||||
$(DIST)/lib/libxpcomio_s.a \
|
||||
$(NULL)
|
||||
|
||||
LOCAL_INCLUDES = \
|
||||
-I$(DEPTH)/netwerk/cache/memcache \
|
||||
-I$(DEPTH)/netwerk/cache/filecache \
|
||||
-I$(DEPTH)/netwerk/cache/mgr \
|
||||
$(NULL)
|
||||
|
||||
EXTRA_DSO_LDOPTS = \
|
||||
$(MKSHLIB_FORCE_ALL) \
|
||||
$(SHARED_LIBRARY_LIBS) \
|
||||
$(MKSHLIB_UNFORCE_ALL) \
|
||||
$(NULL)
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
$(LIBRARY) $(SHARED_LIBRARY): $(SHARED_LIBRARY_LIBS) Makefile
|
||||
|
||||
51
mozilla/netwerk/cache/build/makefile.win
vendored
Normal file
51
mozilla/netwerk/cache/build/makefile.win
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
#!gmake
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
DEPTH=..\..\..
|
||||
MODULE=nkcache
|
||||
|
||||
MAKE_OBJ_TYPE=DLL
|
||||
DLLNAME=nkcache
|
||||
DLL=.\$(OBJDIR)\$(DLLNAME).dll
|
||||
|
||||
CPP_OBJS= \
|
||||
.\$(OBJDIR)\nsNetDataCacheModule.obj \
|
||||
$(NULL)
|
||||
|
||||
LLIBS= \
|
||||
$(DIST)\lib\nkcachemgr_s.lib \
|
||||
$(DIST)\lib\nkfilecache_s.lib \
|
||||
$(DIST)\lib\nkmemcache_s.lib \
|
||||
$(DIST)\lib\dbm32.lib \
|
||||
$(DIST)\lib\xpcom.lib \
|
||||
$(LIBNSPR)
|
||||
|
||||
INCS = $(INCS) \
|
||||
-I$(DEPTH)\netwerk\cache\memcache \
|
||||
-I$(DEPTH)\netwerk\cache\filecache \
|
||||
-I$(DEPTH)\netwerk\cache\mgr \
|
||||
$(NULL)
|
||||
|
||||
include <$(DEPTH)\config\rules.mak>
|
||||
|
||||
install:: $(DLL)
|
||||
$(MAKE_INSTALL) .\$(OBJDIR)\$(DLLNAME).dll $(DIST)\bin\components
|
||||
$(MAKE_INSTALL) .\$(OBJDIR)\$(DLLNAME).lib $(DIST)\lib
|
||||
|
||||
49
mozilla/netwerk/cache/build/nsNetDataCacheModule.cpp
vendored
Normal file
49
mozilla/netwerk/cache/build/nsNetDataCacheModule.cpp
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
/* -*- Mode: C++; tab-width: 4; 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 Communicator client code, released
|
||||
* March 31, 1998.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998-1999 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIModule.h"
|
||||
#include "nscore.h"
|
||||
#include "nsIComponentManager.h"
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsIGenericFactory.h"
|
||||
|
||||
#include "nsINetDataCache.h"
|
||||
#include "nsINetDataCacheManager.h"
|
||||
#include "nsMemCacheCID.h"
|
||||
#include "nsMemCache.h"
|
||||
#include "nsNetDiskCache.h"
|
||||
#include "nsNetDiskCacheCID.h"
|
||||
#include "nsCacheManager.h"
|
||||
|
||||
// Factory method to create a new nsMemCache instance. Used
|
||||
// by nsNetDataCacheModule
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsMemCache, Init)
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsNetDiskCache, Init)
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsCacheManager, Init)
|
||||
|
||||
static nsModuleComponentInfo components[] = {
|
||||
{ "Memory Cache", NS_MEM_CACHE_FACTORY_CID, NS_NETWORK_MEMORY_CACHE_PROGID, nsMemCacheConstructor },
|
||||
{ "File Cache", NS_NETDISKCACHE_CID, NS_NETWORK_FILE_CACHE_PROGID, nsNetDiskCacheConstructor },
|
||||
{ "Cache Manager",NS_CACHE_MANAGER_CID, NS_NETWORK_CACHE_MANAGER_PROGID,nsCacheManagerConstructor }
|
||||
};
|
||||
|
||||
NS_IMPL_NSGETMODULE("Network Data Cache", components)
|
||||
60
mozilla/netwerk/cache/filecache/Makefile.in
vendored
Normal file
60
mozilla/netwerk/cache/filecache/Makefile.in
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
#
|
||||
# The contents of this file are subject to the Mozilla Public
|
||||
# License Version 1.1 (the "License"); you may not use this file
|
||||
# except in compliance with the License. You may obtain a copy of
|
||||
# the License at http://www.mozilla.org/MPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS
|
||||
# IS" basis, WITHOUT WARRANTY OF ANY 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 Intel Corp.
|
||||
# Portions created by Intel Corp. are
|
||||
# Copyright (C) 1999, 1999 Intel Corp. All
|
||||
# Rights Reserved.
|
||||
#
|
||||
# Contributor(s): Yixiong Zou <yixiong.zou@intel.com>
|
||||
# Carl Wong <carl.wong@intel.com>
|
||||
#
|
||||
|
||||
DEPTH = ../../..
|
||||
topsrcdir = @top_srcdir@
|
||||
VPATH = @srcdir@
|
||||
srcdir = @srcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
MODULE = nkcache
|
||||
|
||||
LIBRARY_NAME = nkfilecache_s
|
||||
|
||||
REQUIRES = nspr dbm
|
||||
|
||||
EXTRA_DSO_LDOPTS += -L$(DIST)/lib -lmozdbm_s
|
||||
|
||||
EXPORTS=nsNetDiskCacheCID.h \
|
||||
nsNetDiskCache.h \
|
||||
nsIDBAccessor.h \
|
||||
nsDBAccessor.h \
|
||||
$(NULL)
|
||||
|
||||
CPPSRCS = \
|
||||
nsDBAccessor.cpp\
|
||||
nsDBEnumerator.cpp \
|
||||
nsNetDiskCache.cpp \
|
||||
nsDiskCacheRecord.cpp \
|
||||
nsDiskCacheRecordChannel.cpp \
|
||||
$(NULL)
|
||||
|
||||
EXTRA_LIBS = $(NSPR_LIBS)
|
||||
|
||||
# we don't want the shared lib, but we want to force the creation of a
|
||||
# static lib.
|
||||
override NO_SHARED_LIB=1
|
||||
override NO_STATIC_LIB=
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
44
mozilla/netwerk/cache/filecache/makefile.win
vendored
Normal file
44
mozilla/netwerk/cache/filecache/makefile.win
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
#!gmake
|
||||
#
|
||||
# The contents of this file are subject to the Netscape Public License
|
||||
# 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) 1998 Netscape Communications Corporation. All Rights
|
||||
# Reserved.
|
||||
|
||||
DEPTH=..\..\..
|
||||
|
||||
include <$(DEPTH)/config/config.mak>
|
||||
|
||||
MODULE = nkcache
|
||||
|
||||
LIBRARY_NAME = nkfilecache_s
|
||||
|
||||
CPP_OBJS= \
|
||||
.\$(OBJDIR)\nsDBAccessor.obj \
|
||||
.\$(OBJDIR)\nsDBEnumerator.obj \
|
||||
.\$(OBJDIR)\nsNetDiskCache.obj \
|
||||
.\$(OBJDIR)\nsDiskCacheRecord.obj \
|
||||
.\$(OBJDIR)\nsDiskCacheRecordChannel.obj \
|
||||
$(NULL)
|
||||
|
||||
EXPORTS=nsNetDiskCacheCID.h
|
||||
|
||||
include <$(DEPTH)\config\rules.mak>
|
||||
|
||||
install:: $(LIBRARY)
|
||||
$(MAKE_INSTALL) $(LIBRARY) $(DIST)\lib
|
||||
|
||||
clobber::
|
||||
rm -rf $(OBJDIR)
|
||||
rm -f $(DIST)\lib\$(LIBRARY_NAME).lib
|
||||
|
||||
416
mozilla/netwerk/cache/filecache/nsDBAccessor.cpp
vendored
Normal file
416
mozilla/netwerk/cache/filecache/nsDBAccessor.cpp
vendored
Normal file
@@ -0,0 +1,416 @@
|
||||
/* -*- Mode: C++; 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 Communicator.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Intel Corp.
|
||||
* Portions created by Intel Corp. are
|
||||
* Copyright (C) 1999, 1999 Intel Corp. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s): Yixiong Zou <yixiong.zou@intel.com>
|
||||
* Carl Wong <carl.wong@intel.com>
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is part of filecache implementation.
|
||||
*
|
||||
* nsIDBAccessor is a interface that shields all the direct database access
|
||||
* method from nsNetDiskCache.
|
||||
*
|
||||
* nsDBAccessor is a implementation of the nsIDBAccessor interface. It
|
||||
* uses dbm(Berkely) as the database.
|
||||
*
|
||||
* a nsDiskCacheRecord is mapped into two entries in the database,
|
||||
* key->recordID
|
||||
* recordID->metadata
|
||||
*/
|
||||
|
||||
#include "nsDBAccessor.h"
|
||||
#include "nscore.h"
|
||||
|
||||
#include "prtypes.h"
|
||||
#include "plhash.h"
|
||||
#include "nsCRT.h"
|
||||
|
||||
nsDBAccessor::nsDBAccessor() :
|
||||
mDB(0) ,
|
||||
mDBFile(0) ,
|
||||
mSessionID(0) ,
|
||||
mSessionCntr(0) ,
|
||||
mDBFilesize(0)
|
||||
{
|
||||
mLastSyncTime = PR_IntervalNow() ;
|
||||
|
||||
NS_INIT_REFCNT();
|
||||
}
|
||||
|
||||
nsDBAccessor::~nsDBAccessor()
|
||||
{
|
||||
Shutdown() ;
|
||||
}
|
||||
|
||||
//
|
||||
// Implement nsISupports methods
|
||||
//
|
||||
NS_IMPL_ISUPPORTS(nsDBAccessor, NS_GET_IID(nsIDBAccessor))
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////
|
||||
// nsIDBAccessor methods
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDBAccessor::Init(nsIFileSpec* dbfile)
|
||||
{
|
||||
char* dbname ;
|
||||
|
||||
// this should cover all platforms.
|
||||
dbfile->GetNativePath(&dbname) ;
|
||||
|
||||
mDBFile = dbfile ;
|
||||
|
||||
// FUR - how is page size chosen ? It's worth putting a comment
|
||||
// in here about the possible usefulness of tuning these parameters
|
||||
HASHINFO hash_info = {
|
||||
16*1024 , /* bucket size */
|
||||
0 , /* fill factor */
|
||||
0 , /* number of elements */
|
||||
0 , /* bytes to cache */
|
||||
0 , /* hash function */
|
||||
0} ; /* byte order */
|
||||
|
||||
mDB = dbopen(dbname,
|
||||
O_RDWR | O_CREAT ,
|
||||
0600 ,
|
||||
DB_HASH ,
|
||||
& hash_info) ;
|
||||
|
||||
nsCRT::free(dbname) ;
|
||||
|
||||
if(!mDB)
|
||||
return NS_ERROR_FAILURE ;
|
||||
|
||||
// set mSessionID
|
||||
DBT db_key, db_data ;
|
||||
|
||||
db_key.data = NS_CONST_CAST(char*, SessionKey) ;
|
||||
db_key.size = PL_strlen(SessionKey) ;
|
||||
|
||||
int status = (*mDB->get)(mDB, &db_key, &db_data, 0) ;
|
||||
if(status == -1) {
|
||||
NS_ERROR("ERROR: failed get session id in database.") ;
|
||||
return NS_ERROR_FAILURE ;
|
||||
}
|
||||
|
||||
if(status == 0) {
|
||||
// get the last session id
|
||||
PRInt16 *old_ID = NS_STATIC_CAST(PRInt16*, db_data.data) ;
|
||||
if(*old_ID < ini_sessionID) {
|
||||
NS_ERROR("ERROR: Bad Session ID in database, corrupted db.") ;
|
||||
return NS_ERROR_FAILURE ;
|
||||
}
|
||||
|
||||
mSessionID = *old_ID + 1 ;
|
||||
}
|
||||
else if(status == 1) {
|
||||
// must be a new db
|
||||
mSessionID = ini_sessionID ;
|
||||
}
|
||||
db_data.data = NS_REINTERPRET_CAST(void*, &mSessionID) ;
|
||||
db_data.size = sizeof(PRInt16) ;
|
||||
|
||||
// store the new session id
|
||||
status = (*mDB->put)(mDB, &db_key, &db_data, 0) ;
|
||||
|
||||
if(status == 0) {
|
||||
(*mDB->sync)(mDB, 0) ;
|
||||
|
||||
// initialize database filesize
|
||||
return mDBFile->GetFileSize(&mDBFilesize) ;
|
||||
}
|
||||
else {
|
||||
NS_ERROR("reset session ID failure.") ;
|
||||
return NS_ERROR_FAILURE ;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDBAccessor::Shutdown(void)
|
||||
{
|
||||
if(mDB) {
|
||||
(*mDB->sync)(mDB, 0) ;
|
||||
(*mDB->close)(mDB) ;
|
||||
mDB = nsnull ;
|
||||
}
|
||||
|
||||
return NS_OK ;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDBAccessor::Get(PRInt32 aID, void** anEntry, PRUint32 *aLength)
|
||||
{
|
||||
if(!anEntry)
|
||||
return NS_ERROR_NULL_POINTER ;
|
||||
|
||||
*anEntry = nsnull ;
|
||||
*aLength = 0 ;
|
||||
|
||||
NS_ASSERTION(mDB, "no database") ;
|
||||
|
||||
DBT db_key, db_data ;
|
||||
|
||||
db_key.data = NS_REINTERPRET_CAST(void*, &aID) ;
|
||||
db_key.size = sizeof(PRInt32) ;
|
||||
|
||||
int status = 0 ;
|
||||
status = (*mDB->get)(mDB, &db_key, &db_data, 0) ;
|
||||
|
||||
if(status == 0) {
|
||||
*anEntry = db_data.data ;
|
||||
*aLength = db_data.size ;
|
||||
return NS_OK ;
|
||||
}
|
||||
else if(status == 1)
|
||||
return NS_OK ;
|
||||
else
|
||||
return NS_ERROR_FAILURE ;
|
||||
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDBAccessor::Put(PRInt32 aID, void* anEntry, PRUint32 aLength)
|
||||
{
|
||||
NS_ASSERTION(mDB, "no database") ;
|
||||
|
||||
DBT db_key, db_data ;
|
||||
|
||||
db_key.data = NS_REINTERPRET_CAST(void*, &aID) ;
|
||||
db_key.size = sizeof(PRInt32) ;
|
||||
|
||||
db_data.data = anEntry ;
|
||||
db_data.size = aLength ;
|
||||
|
||||
if(0 == (*mDB->put)(mDB, &db_key, &db_data, 0)) {
|
||||
return Sync() ;
|
||||
}
|
||||
else {
|
||||
return NS_ERROR_FAILURE ;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* It's more important to remove the id->metadata entry first since
|
||||
* key->id mapping is just a reference
|
||||
*/
|
||||
NS_IMETHODIMP
|
||||
nsDBAccessor::Del(PRInt32 aID, void* anEntry, PRUint32 aLength)
|
||||
{
|
||||
NS_ASSERTION(mDB, "no database") ;
|
||||
|
||||
DBT db_key ;
|
||||
|
||||
// delete recordID->metadata
|
||||
db_key.data = NS_REINTERPRET_CAST(void*, &aID) ;
|
||||
db_key.size = sizeof(PRInt32) ;
|
||||
|
||||
PRInt32 status = -1 ;
|
||||
status = (*mDB->del)(mDB, &db_key, 0) ;
|
||||
|
||||
if(-1 == status) {
|
||||
return NS_ERROR_FAILURE ;
|
||||
}
|
||||
|
||||
// delete key->recordID
|
||||
db_key.data = anEntry ;
|
||||
db_key.size = aLength ;
|
||||
status = (*mDB->del)(mDB, &db_key, 0) ;
|
||||
if(-1 == status) {
|
||||
return NS_ERROR_FAILURE ;
|
||||
}
|
||||
|
||||
return Sync() ;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDBAccessor::GetID(const char* key, PRUint32 length, PRInt32* aID)
|
||||
{
|
||||
NS_ASSERTION(mDB, "no database") ;
|
||||
|
||||
DBT db_key, db_data ;
|
||||
|
||||
db_key.data = NS_CONST_CAST(char*, key) ;
|
||||
db_key.size = length ;
|
||||
|
||||
int status = (*mDB->get)(mDB, &db_key, &db_data, 0) ;
|
||||
if(status == 0) {
|
||||
// found recordID
|
||||
*aID = *(NS_REINTERPRET_CAST(PRInt32*, db_data.data)) ;
|
||||
return NS_OK ;
|
||||
}
|
||||
else if(status == 1) {
|
||||
// create a new one
|
||||
PRInt32 id = 0 ;
|
||||
id = mSessionID << 16 | mSessionCntr++ ;
|
||||
|
||||
// add new id into mDB
|
||||
db_data.data = NS_REINTERPRET_CAST(void*, &id) ;
|
||||
db_data.size = sizeof(PRInt32) ;
|
||||
|
||||
status = (*mDB->put)(mDB, &db_key, &db_data, 0) ;
|
||||
if(status != 0) {
|
||||
NS_ERROR("updating db failure.") ;
|
||||
return NS_ERROR_FAILURE ;
|
||||
}
|
||||
*aID = id ;
|
||||
return Sync() ;
|
||||
}
|
||||
else {
|
||||
NS_ERROR("ERROR: keydb failure.") ;
|
||||
return NS_ERROR_FAILURE ;
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDBAccessor::EnumEntry(void** anEntry, PRUint32* aLength, PRBool bReset)
|
||||
{
|
||||
if(!anEntry)
|
||||
return NS_ERROR_NULL_POINTER ;
|
||||
|
||||
*anEntry = nsnull ;
|
||||
*aLength = 0 ;
|
||||
|
||||
NS_ASSERTION(mDB, "no database") ;
|
||||
|
||||
PRUint32 flag ;
|
||||
|
||||
if(bReset)
|
||||
flag = R_FIRST ;
|
||||
else
|
||||
flag = R_NEXT ;
|
||||
|
||||
DBT db_key, db_data ;
|
||||
|
||||
PRUint32 len = PL_strlen(SessionKey) ;
|
||||
|
||||
int status ;
|
||||
|
||||
do {
|
||||
status = (*mDB->seq)(mDB, &db_key, &db_data, flag) ;
|
||||
flag = R_NEXT ;
|
||||
if(status == -1)
|
||||
return NS_ERROR_FAILURE ;
|
||||
// get next if it's a key->recordID
|
||||
if(db_key.size > sizeof(PRInt32) && db_data.size == sizeof(PRInt32))
|
||||
continue ;
|
||||
// get next if it's a sessionID entry
|
||||
if(db_key.size == len && db_data.size == sizeof(PRInt16))
|
||||
continue ;
|
||||
// recordID is always 32 bits long
|
||||
if(db_key.size == sizeof(PRInt32))
|
||||
break ;
|
||||
} while(!status) ;
|
||||
|
||||
if (0 == status) {
|
||||
*anEntry = db_data.data ;
|
||||
*aLength = db_data.size ;
|
||||
}
|
||||
return NS_OK ;
|
||||
}
|
||||
|
||||
/*
|
||||
* returns the cached database file size.
|
||||
* mDBFilesize will be updated during Sync().
|
||||
*/
|
||||
NS_IMETHODIMP
|
||||
nsDBAccessor::GetDBFilesize(PRUint32* aSize)
|
||||
{
|
||||
*aSize = mDBFilesize ;
|
||||
return NS_OK ;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDBAccessor::GetSpecialEntry(void** anEntry, PRUint32* aLength)
|
||||
{
|
||||
if(!anEntry)
|
||||
return NS_ERROR_NULL_POINTER ;
|
||||
|
||||
*anEntry = nsnull ;
|
||||
*aLength = 0 ;
|
||||
|
||||
DBT db_key, db_data ;
|
||||
|
||||
db_key.data = NS_CONST_CAST(char*, SpecialEntry) ;
|
||||
db_key.size = PL_strlen(SpecialEntry) ;
|
||||
|
||||
int status = (*mDB->get)(mDB, &db_key, &db_data, 0) ;
|
||||
|
||||
if(status == -1) {
|
||||
NS_ERROR("ERROR: failed get special entry in database.") ;
|
||||
return NS_ERROR_FAILURE ;
|
||||
}
|
||||
|
||||
if(status == 0) {
|
||||
*anEntry = db_data.data ;
|
||||
*aLength = db_data.size ;
|
||||
}
|
||||
|
||||
return NS_OK ;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDBAccessor::SetSpecialEntry(void* anEntry, PRUint32 aLength)
|
||||
{
|
||||
DBT db_key, db_data ;
|
||||
|
||||
db_key.data = NS_CONST_CAST(char*, SpecialEntry) ;
|
||||
db_key.size = PL_strlen(SpecialEntry) ;
|
||||
|
||||
db_data.data = anEntry ;
|
||||
db_data.size = aLength ;
|
||||
|
||||
if(0 == (*mDB->put)(mDB, &db_key, &db_data, 0)) {
|
||||
(*mDB->sync)(mDB, 0) ;
|
||||
return NS_OK ;
|
||||
}
|
||||
else {
|
||||
return NS_ERROR_FAILURE ;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* sync routine is only called when the SyncInterval is reached. Otherwise
|
||||
* it just returns. If db synced, the filesize will be updated at the
|
||||
* same time.
|
||||
*/
|
||||
nsresult
|
||||
nsDBAccessor::Sync(void)
|
||||
{
|
||||
PRIntervalTime time = PR_IntervalNow() ;
|
||||
PRIntervalTime duration = time - mLastSyncTime ;
|
||||
|
||||
if (PR_IntervalToMilliseconds(duration) > SyncInterval) {
|
||||
int status = (*mDB->sync)(mDB, 0) ;
|
||||
if(status == 0) {
|
||||
// printf("\tsynced\n") ;
|
||||
mLastSyncTime = time ;
|
||||
|
||||
// update db filesize here
|
||||
return mDBFile->GetFileSize(&mDBFilesize) ;
|
||||
|
||||
} else
|
||||
return NS_ERROR_FAILURE ;
|
||||
} else {
|
||||
// printf("\tnot synced\n") ;
|
||||
return NS_OK ;
|
||||
}
|
||||
}
|
||||
93
mozilla/netwerk/cache/filecache/nsDBAccessor.h
vendored
Normal file
93
mozilla/netwerk/cache/filecache/nsDBAccessor.h
vendored
Normal file
@@ -0,0 +1,93 @@
|
||||
/*- Mode: C++; 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 Communicator.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Intel Corp.
|
||||
* Portions created by Intel Corp. are
|
||||
* Copyright (C) 1999, 1999 Intel Corp. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s): Yixiong Zou <yixiong.zou@intel.com>
|
||||
* Carl Wong <carl.wong@intel.com>
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is part of filecache implementation.
|
||||
*
|
||||
* nsIDBAccessor is a interface that shields all the direct database access
|
||||
* method from nsNetDiskCache.
|
||||
*
|
||||
* nsDBAccessor is a implementation of the nsIDBAccessor interface. It
|
||||
* uses dbm(Berkely) as the database.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _NSIDBACCESSOR_H_
|
||||
#define _NSIDBACCESSOR_H_
|
||||
|
||||
#include "nsIDBAccessor.h"
|
||||
#include "mcom_db.h"
|
||||
#include "prinrval.h"
|
||||
#include "nsCOMPtr.h"
|
||||
|
||||
// bogus string for the key of session id
|
||||
static const char * const SessionKey = "SK" ;
|
||||
|
||||
// bogus string for the size
|
||||
static const char * const SpecialEntry = "SE" ;
|
||||
|
||||
// initial session id number
|
||||
static const PRInt16 ini_sessionID = 0xff ;
|
||||
|
||||
static const PRUint16 SyncInterval = 1000 ;
|
||||
|
||||
class nsDBAccessor : public nsIDBAccessor
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
nsDBAccessor() ;
|
||||
virtual ~nsDBAccessor() ;
|
||||
|
||||
NS_IMETHOD Init(nsIFileSpec* dbfile) ;
|
||||
NS_IMETHOD Shutdown(void) ;
|
||||
|
||||
NS_IMETHOD Put(PRInt32 aID, void* anEntry, PRUint32 aLength) ;
|
||||
|
||||
NS_IMETHOD Get(PRInt32 aID, void** anEntry, PRUint32 *aLength) ;
|
||||
|
||||
NS_IMETHOD Del(PRInt32 aID, void* anEntry, PRUint32 aLength) ;
|
||||
|
||||
NS_IMETHOD GetID(const char* key, PRUint32 length, PRInt32* aID) ;
|
||||
|
||||
NS_IMETHOD EnumEntry(void* *anEntry, PRUint32* aLength, PRBool bReset) ;
|
||||
|
||||
NS_IMETHOD GetDBFilesize(PRUint32* aSize) ;
|
||||
|
||||
NS_IMETHOD GetSpecialEntry(void** anEntry, PRUint32 *aLength) ;
|
||||
NS_IMETHOD SetSpecialEntry(void* anEntry, PRUint32 aLength) ;
|
||||
|
||||
protected:
|
||||
nsresult Sync(void) ;
|
||||
|
||||
private:
|
||||
DB * mDB ;
|
||||
nsCOMPtr<nsIFileSpec> mDBFile ;
|
||||
PRInt16 mSessionID ;
|
||||
PRInt16 mSessionCntr ;
|
||||
PRIntervalTime mLastSyncTime ;
|
||||
PRUint32 mDBFilesize ; // cached DB filesize,
|
||||
// updated on every sync for now
|
||||
} ;
|
||||
|
||||
#endif // _NSIDBACCESSOR_H_
|
||||
108
mozilla/netwerk/cache/filecache/nsDBEnumerator.cpp
vendored
Normal file
108
mozilla/netwerk/cache/filecache/nsDBEnumerator.cpp
vendored
Normal file
@@ -0,0 +1,108 @@
|
||||
/* -*- Mode: C++; 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 Communicator.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Intel Corp.
|
||||
* Portions created by Intel Corp. are
|
||||
* Copyright (C) 1999, 1999 Intel Corp. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s): Yixiong Zou <yixiong.zou@intel.com>
|
||||
* Carl Wong <carl.wong@intel.com>
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is part of filecache implementation.
|
||||
*
|
||||
* It implements a simple iterator for the database, see nsDBAccessor.
|
||||
*/
|
||||
|
||||
#include "nsDBEnumerator.h"
|
||||
#include "nsDiskCacheRecord.h"
|
||||
|
||||
nsDBEnumerator::nsDBEnumerator(nsIDBAccessor* aDB, nsNetDiskCache* aCache) :
|
||||
m_DB(aDB) ,
|
||||
m_DiskCache(aCache) ,
|
||||
m_tempEntry(0) ,
|
||||
m_tempEntry_length(0) ,
|
||||
m_CacheEntry(0) ,
|
||||
m_bReset(PR_TRUE)
|
||||
{
|
||||
NS_INIT_REFCNT();
|
||||
|
||||
}
|
||||
|
||||
nsDBEnumerator::~nsDBEnumerator()
|
||||
{
|
||||
NS_IF_RELEASE(m_CacheEntry) ;
|
||||
}
|
||||
|
||||
//
|
||||
// Implement nsISupports methods
|
||||
//
|
||||
NS_IMPL_ISUPPORTS(nsDBEnumerator, NS_GET_IID(nsIEnumerator))
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// nsISimpleEnumerator methods
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDBEnumerator::HasMoreElements(PRBool *_retval)
|
||||
{
|
||||
*_retval = PR_FALSE ;
|
||||
|
||||
nsresult rv = m_DB->EnumEntry(&m_tempEntry, &m_tempEntry_length, m_bReset) ;
|
||||
|
||||
if(NS_FAILED(rv)) {
|
||||
// do some error recovery
|
||||
m_DiskCache->DBRecovery() ;
|
||||
return rv ;
|
||||
}
|
||||
|
||||
m_bReset = PR_FALSE ;
|
||||
|
||||
if(m_tempEntry && m_tempEntry_length != 0)
|
||||
*_retval = PR_TRUE ;
|
||||
|
||||
return NS_OK ;
|
||||
}
|
||||
|
||||
// this routine does not create a new item by itself
|
||||
// Rather it reuses the item inside the object. So if you need to use the
|
||||
// item later, you have to
|
||||
// create a new item specifically, using copy constructor or some other dup
|
||||
// function. And don't forget to release it after you're done
|
||||
//
|
||||
NS_IMETHODIMP
|
||||
nsDBEnumerator::GetNext(nsISupports **_retval)
|
||||
{
|
||||
if(!m_CacheEntry) {
|
||||
m_CacheEntry = new nsDiskCacheRecord(m_DB, m_DiskCache) ;
|
||||
if(m_CacheEntry)
|
||||
NS_ADDREF(m_CacheEntry) ;
|
||||
else
|
||||
return NS_ERROR_OUT_OF_MEMORY ;
|
||||
}
|
||||
|
||||
if(!_retval)
|
||||
return NS_ERROR_NULL_POINTER ;
|
||||
*_retval = nsnull ;
|
||||
|
||||
nsresult rv = m_CacheEntry->RetrieveInfo(m_tempEntry, m_tempEntry_length) ;
|
||||
if(NS_FAILED(rv))
|
||||
return rv ;
|
||||
|
||||
*_retval = NS_STATIC_CAST(nsISupports*, m_CacheEntry) ;
|
||||
NS_ADDREF(*_retval) ; // all good getter addref
|
||||
|
||||
return NS_OK ;
|
||||
}
|
||||
60
mozilla/netwerk/cache/filecache/nsDBEnumerator.h
vendored
Normal file
60
mozilla/netwerk/cache/filecache/nsDBEnumerator.h
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
/* -*- Mode: C++; 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 Communicator.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Intel Corp.
|
||||
* Portions created by Intel Corp. are
|
||||
* Copyright (C) 1999, 1999 Intel Corp. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s): Yixiong Zou <yixiong.zou@intel.com>
|
||||
* Carl Wong <carl.wong@intel.com>
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is part of filecache implementation.
|
||||
*
|
||||
* It implements a simple iterator for the database, see nsDBAccessor.
|
||||
*/
|
||||
|
||||
#ifndef _NS_DBENUMERATOR_H_
|
||||
#define _NS_DBENUMERATOR_H_
|
||||
|
||||
#include "nsISimpleEnumerator.h"
|
||||
#include "nsINetDataCacheRecord.h"
|
||||
#include "nsIDBAccessor.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsNetDiskCache.h"
|
||||
#include "nsDiskCacheRecord.h"
|
||||
|
||||
class nsCachedDiskData ; /* forward decl */
|
||||
|
||||
class nsDBEnumerator : public nsISimpleEnumerator {
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
NS_DECL_NSISIMPLEENUMERATOR
|
||||
|
||||
nsDBEnumerator(nsIDBAccessor* aDB, nsNetDiskCache* aCache) ;
|
||||
virtual ~nsDBEnumerator() ;
|
||||
|
||||
private:
|
||||
nsCOMPtr<nsIDBAccessor> m_DB ;
|
||||
nsCOMPtr<nsNetDiskCache> m_DiskCache ;
|
||||
void * m_tempEntry ;
|
||||
PRUint32 m_tempEntry_length ;
|
||||
nsDiskCacheRecord* m_CacheEntry ;
|
||||
PRBool m_bReset ;
|
||||
};
|
||||
|
||||
#endif // _NS_DBENUMERATOR_H_
|
||||
456
mozilla/netwerk/cache/filecache/nsDiskCacheRecord.cpp
vendored
Normal file
456
mozilla/netwerk/cache/filecache/nsDiskCacheRecord.cpp
vendored
Normal file
@@ -0,0 +1,456 @@
|
||||
/* -*- Mode: C++; 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 Communicator.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Intel Corp.
|
||||
* Portions created by Intel Corp. are
|
||||
* Copyright (C) 1999, 1999 Intel Corp. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s): Yixiong Zou <yixiong.zou@intel.com>
|
||||
* Carl Wong <carl.wong@intel.com>
|
||||
*/
|
||||
|
||||
#include "nsDiskCacheRecord.h"
|
||||
#include "nsINetDataDiskCache.h"
|
||||
#include "nsNetDiskCacheCID.h"
|
||||
#include "nsDiskCacheRecordChannel.h"
|
||||
#include "nsFileStream.h"
|
||||
|
||||
#include "nsIComponentManager.h"
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsIProtocolHandler.h"
|
||||
#include "nsIIOService.h"
|
||||
#include "nsIAllocator.h"
|
||||
|
||||
#include "plstr.h"
|
||||
#include "prprf.h"
|
||||
#include "prmem.h"
|
||||
#include "prlog.h"
|
||||
#include "prtypes.h"
|
||||
#include "netCore.h"
|
||||
|
||||
#include "nsDBAccessor.h"
|
||||
|
||||
#if !defined(IS_LITTLE_ENDIAN) && !defined(IS_BIG_ENDIAN)
|
||||
ERROR! Must have a byte order
|
||||
#endif
|
||||
|
||||
#ifdef IS_LITTLE_ENDIAN
|
||||
#define COPY_INT32(_a,_b) memcpy(_a, _b, sizeof(int32))
|
||||
#else
|
||||
#define COPY_INT32(_a,_b) /* swap */ \
|
||||
do { \
|
||||
((char *)(_a))[0] = ((char *)(_b))[3]; \
|
||||
((char *)(_a))[1] = ((char *)(_b))[2]; \
|
||||
((char *)(_a))[2] = ((char *)(_b))[1]; \
|
||||
((char *)(_a))[3] = ((char *)(_b))[0]; \
|
||||
} while(0)
|
||||
#endif
|
||||
|
||||
nsDiskCacheRecord::nsDiskCacheRecord(nsIDBAccessor* db, nsNetDiskCache* aCache) :
|
||||
mKey(0) ,
|
||||
mKeyLength(0) ,
|
||||
mRecordID(0) ,
|
||||
mMetaData(0) ,
|
||||
mMetaDataLength(0) ,
|
||||
mDB(db) ,
|
||||
mInfo(0) ,
|
||||
mInfoSize(0) ,
|
||||
mNumChannels(0) ,
|
||||
mDiskCache(aCache)
|
||||
{
|
||||
NS_INIT_REFCNT();
|
||||
NS_ASSERTION(mDiskCache, "Must have an nsNetDiskCache");
|
||||
NS_ADDREF(mDiskCache);
|
||||
}
|
||||
|
||||
// mem alloced. so caller should do free() on key.
|
||||
NS_IMETHODIMP
|
||||
nsDiskCacheRecord::Init(const char* key, PRUint32 length, PRInt32 ID)
|
||||
{
|
||||
NS_NewFileSpec(getter_AddRefs(mFile));
|
||||
if(!mFile)
|
||||
return NS_ERROR_OUT_OF_MEMORY ;
|
||||
|
||||
// copy key
|
||||
mKeyLength = length ;
|
||||
mKey = NS_STATIC_CAST(char*, nsAllocator::Alloc(mKeyLength*sizeof(char))) ;
|
||||
if(!mKey)
|
||||
return NS_ERROR_OUT_OF_MEMORY ;
|
||||
|
||||
memcpy(mKey, key, length) ;
|
||||
|
||||
// get RecordID
|
||||
mRecordID = ID ;
|
||||
|
||||
// setup the file name
|
||||
nsCOMPtr<nsIFileSpec> dbFolder ;
|
||||
mDiskCache->GetDiskCacheFolder(getter_AddRefs(dbFolder)) ;
|
||||
|
||||
nsresult rv = mFile->FromFileSpec(dbFolder) ;
|
||||
if(NS_FAILED(rv))
|
||||
return NS_ERROR_FAILURE ;
|
||||
|
||||
// dir is a hash result of mRecordID%32, hope it's enough
|
||||
char filename[9], dirName[3] ;
|
||||
|
||||
PR_snprintf(dirName, 3, "%02x", (((PRUint32)mRecordID) % 32)) ;
|
||||
mFile->AppendRelativeUnixPath(dirName) ;
|
||||
|
||||
PR_snprintf(filename, 9, "%08x", mRecordID) ;
|
||||
mFile->AppendRelativeUnixPath(filename) ;
|
||||
|
||||
return NS_OK ;
|
||||
}
|
||||
|
||||
nsDiskCacheRecord::~nsDiskCacheRecord()
|
||||
{
|
||||
if(mKey)
|
||||
nsAllocator::Free(mKey) ;
|
||||
if(mMetaData)
|
||||
nsAllocator::Free(mMetaData) ;
|
||||
if(mInfo)
|
||||
nsAllocator::Free(mInfo) ;
|
||||
|
||||
NS_IF_RELEASE(mDiskCache);
|
||||
}
|
||||
|
||||
//
|
||||
// Implement nsISupports methods
|
||||
//
|
||||
NS_IMPL_ISUPPORTS(nsDiskCacheRecord, NS_GET_IID(nsINetDataCacheRecord))
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// nsINetDataCacheRecord methods
|
||||
|
||||
// yes, mem alloced on *_retval.
|
||||
NS_IMETHODIMP
|
||||
nsDiskCacheRecord::GetKey(PRUint32 *length, char** _retval)
|
||||
{
|
||||
if(!_retval)
|
||||
return NS_ERROR_NULL_POINTER ;
|
||||
|
||||
*length = mKeyLength ;
|
||||
*_retval = NS_STATIC_CAST(char*, nsAllocator::Alloc(mKeyLength*sizeof(char))) ;
|
||||
if(!*_retval)
|
||||
return NS_ERROR_OUT_OF_MEMORY ;
|
||||
|
||||
memcpy(*_retval, mKey, mKeyLength) ;
|
||||
|
||||
return NS_OK ;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDiskCacheRecord::GetRecordID(PRInt32* aRecordID)
|
||||
{
|
||||
*aRecordID = mRecordID ;
|
||||
return NS_OK ;
|
||||
}
|
||||
|
||||
// yes, mem alloced on *_retval.
|
||||
NS_IMETHODIMP
|
||||
nsDiskCacheRecord::GetMetaData(PRUint32 *length, char **_retval)
|
||||
{
|
||||
if(!_retval)
|
||||
return NS_ERROR_NULL_POINTER ;
|
||||
|
||||
// always null the return value first.
|
||||
*_retval = nsnull ;
|
||||
|
||||
*length = mMetaDataLength ;
|
||||
|
||||
if(mMetaDataLength) {
|
||||
*_retval = NS_STATIC_CAST(char*, nsAllocator::Alloc(mMetaDataLength*sizeof(char))) ;
|
||||
if(!*_retval)
|
||||
return NS_ERROR_OUT_OF_MEMORY ;
|
||||
|
||||
memcpy(*_retval, mMetaData, mMetaDataLength) ;
|
||||
}
|
||||
|
||||
return NS_OK ;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDiskCacheRecord::SetMetaData(PRUint32 length, const char* data)
|
||||
{
|
||||
// set the mMetaData
|
||||
mMetaDataLength = length ;
|
||||
if(mMetaData)
|
||||
nsAllocator::Free(mMetaData) ;
|
||||
mMetaData = NS_STATIC_CAST(char*, nsAllocator::Alloc(mMetaDataLength*sizeof(char))) ;
|
||||
if(!mMetaData) {
|
||||
return NS_ERROR_OUT_OF_MEMORY ;
|
||||
}
|
||||
memcpy(mMetaData, data, length) ;
|
||||
|
||||
// Generate mInfo
|
||||
nsresult rv = GenInfo() ;
|
||||
if(NS_FAILED(rv))
|
||||
return rv ;
|
||||
|
||||
// write through into mDB
|
||||
rv = mDB->Put(mRecordID, mInfo, mInfoSize) ;
|
||||
|
||||
return rv ;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDiskCacheRecord::GetStoredContentLength(PRUint32 *aStoredContentLength)
|
||||
{
|
||||
return mFile->GetFileSize(aStoredContentLength) ;
|
||||
}
|
||||
|
||||
// untill nsIFileSpec::Truncate() is in, we have to do all this ugly stuff
|
||||
NS_IMETHODIMP
|
||||
nsDiskCacheRecord::SetStoredContentLength(PRUint32 aStoredContentLength)
|
||||
{
|
||||
PRUint32 len = 0 ;
|
||||
nsresult rv = mFile->GetFileSize(&len) ;
|
||||
if(NS_FAILED(rv))
|
||||
return rv ;
|
||||
|
||||
if(len < aStoredContentLength)
|
||||
{
|
||||
NS_ERROR("Error: can not set filesize to something bigger than itself.\n") ;
|
||||
return NS_ERROR_FAILURE ;
|
||||
}
|
||||
else {
|
||||
rv = mFile->Truncate(aStoredContentLength) ;
|
||||
if(NS_FAILED(rv))
|
||||
return rv ;
|
||||
|
||||
mDiskCache->m_StorageInUse -= (len - aStoredContentLength) ;
|
||||
return NS_OK ;
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDiskCacheRecord::Delete(void)
|
||||
{
|
||||
if(mNumChannels)
|
||||
return NS_ERROR_NOT_AVAILABLE ;
|
||||
|
||||
PRUint32 len ;
|
||||
mFile->GetFileSize(&len) ;
|
||||
|
||||
nsFileSpec cache_file ;
|
||||
nsresult rv = mFile->GetFileSpec(&cache_file) ;
|
||||
|
||||
if(NS_FAILED(rv))
|
||||
return NS_ERROR_FAILURE ;
|
||||
|
||||
cache_file.Delete(PR_TRUE) ;
|
||||
|
||||
// updata the storage size
|
||||
mDiskCache->m_StorageInUse -= len ;
|
||||
|
||||
rv = mDB->Del(mRecordID, mKey, mKeyLength) ;
|
||||
if(NS_FAILED(rv))
|
||||
return NS_ERROR_FAILURE ;
|
||||
else
|
||||
return NS_OK ;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDiskCacheRecord::GetFilename(nsIFileSpec * *aFilename)
|
||||
{
|
||||
if(!aFilename)
|
||||
return NS_ERROR_NULL_POINTER ;
|
||||
|
||||
*aFilename = mFile ;
|
||||
NS_ADDREF(*aFilename) ;
|
||||
|
||||
return NS_OK ;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDiskCacheRecord::NewChannel(nsILoadGroup *loadGroup, nsIChannel **_retval)
|
||||
{
|
||||
nsDiskCacheRecordChannel* channel = new nsDiskCacheRecordChannel(this, loadGroup) ;
|
||||
if(!channel)
|
||||
return NS_ERROR_OUT_OF_MEMORY ;
|
||||
|
||||
nsresult rv = channel->Init() ;
|
||||
if(NS_FAILED(rv))
|
||||
return rv ;
|
||||
|
||||
NS_ADDREF(channel) ;
|
||||
*_retval = NS_STATIC_CAST(nsIChannel*, channel) ;
|
||||
return NS_OK ;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// nsDiskCacheRecord methods
|
||||
|
||||
// file name is represented by a url string. I hope this would be more
|
||||
// generic
|
||||
nsresult
|
||||
nsDiskCacheRecord::GenInfo()
|
||||
{
|
||||
if(mInfo)
|
||||
nsAllocator::Free(mInfo) ;
|
||||
|
||||
char* file_url=nsnull ;
|
||||
PRUint32 name_len ;
|
||||
mFile->GetURLString(&file_url) ;
|
||||
name_len = PL_strlen(file_url)+1 ;
|
||||
|
||||
mInfoSize = sizeof(PRUint32) ; // checksum for mInfoSize
|
||||
mInfoSize += sizeof(PRInt32) ; // RecordID
|
||||
mInfoSize += sizeof(PRUint32) ; // key length
|
||||
mInfoSize += mKeyLength ; // key
|
||||
mInfoSize += sizeof(PRUint32) ; // metadata length
|
||||
mInfoSize += mMetaDataLength ; // metadata
|
||||
mInfoSize += sizeof(PRUint32) ; // filename length
|
||||
mInfoSize += name_len ; // filename
|
||||
|
||||
void* newInfo = nsAllocator::Alloc(mInfoSize*sizeof(char)) ;
|
||||
if(!newInfo) {
|
||||
return NS_ERROR_OUT_OF_MEMORY ;
|
||||
}
|
||||
|
||||
// copy the checksum mInfoSize
|
||||
char* cur_ptr = NS_STATIC_CAST(char*, newInfo) ;
|
||||
COPY_INT32(cur_ptr, &mInfoSize) ;
|
||||
cur_ptr += sizeof(PRUint32) ;
|
||||
|
||||
// copy RecordID
|
||||
COPY_INT32(cur_ptr, &mRecordID) ;
|
||||
cur_ptr += sizeof(PRInt32) ;
|
||||
|
||||
// copy key length
|
||||
COPY_INT32(cur_ptr, &mKeyLength) ;
|
||||
cur_ptr += sizeof(PRUint32) ;
|
||||
|
||||
// copy key
|
||||
memcpy(cur_ptr, mKey, mKeyLength) ;
|
||||
cur_ptr += mKeyLength ;
|
||||
|
||||
// copy metadata length
|
||||
COPY_INT32(cur_ptr, &mMetaDataLength) ;
|
||||
cur_ptr += sizeof(PRUint32) ;
|
||||
|
||||
// copy metadata
|
||||
memcpy(cur_ptr, mMetaData, mMetaDataLength) ;
|
||||
cur_ptr += mMetaDataLength ;
|
||||
|
||||
// copy file name length
|
||||
COPY_INT32(cur_ptr, &name_len) ;
|
||||
cur_ptr += sizeof(PRUint32) ;
|
||||
|
||||
// copy file name
|
||||
memcpy(cur_ptr, file_url, name_len) ;
|
||||
cur_ptr += name_len ;
|
||||
|
||||
PR_ASSERT(cur_ptr == NS_STATIC_CAST(char*, newInfo) + mInfoSize);
|
||||
mInfo = newInfo ;
|
||||
|
||||
return NS_OK ;
|
||||
}
|
||||
|
||||
/*
|
||||
* This Method suppose to get all the info from the db record
|
||||
* and set them to accroding members. the original values
|
||||
* will all be overwritten. only minimal error checking is performed.
|
||||
*/
|
||||
NS_IMETHODIMP
|
||||
nsDiskCacheRecord::RetrieveInfo(void* aInfo, PRUint32 aInfoLength)
|
||||
{
|
||||
// reset everything
|
||||
if(mInfo) {
|
||||
nsAllocator::Free(mInfo) ;
|
||||
mInfo = nsnull ;
|
||||
}
|
||||
|
||||
if(mKey) {
|
||||
nsAllocator::Free(mKey) ;
|
||||
mKey = nsnull ;
|
||||
}
|
||||
if(mMetaData) {
|
||||
nsAllocator::Free(mMetaData) ;
|
||||
mMetaData = nsnull ;
|
||||
}
|
||||
|
||||
char * cur_ptr = NS_STATIC_CAST(char*, aInfo) ;
|
||||
|
||||
char* file_url ;
|
||||
PRUint32 name_len ;
|
||||
|
||||
// set mInfoSize
|
||||
COPY_INT32(&mInfoSize, cur_ptr) ;
|
||||
cur_ptr += sizeof(PRUint32) ;
|
||||
|
||||
// check this at least
|
||||
if(mInfoSize != aInfoLength)
|
||||
return NS_ERROR_FAILURE ;
|
||||
|
||||
// set mRecordID
|
||||
COPY_INT32(&mRecordID, cur_ptr) ;
|
||||
cur_ptr += sizeof(PRInt32) ;
|
||||
|
||||
// set mKeyLength
|
||||
COPY_INT32(&mKeyLength, cur_ptr) ;
|
||||
cur_ptr += sizeof(PRUint32) ;
|
||||
|
||||
// set mKey
|
||||
mKey = NS_STATIC_CAST(char*, nsAllocator::Alloc(mKeyLength*sizeof(char))) ;
|
||||
if(!mKey)
|
||||
return NS_ERROR_OUT_OF_MEMORY ;
|
||||
|
||||
memcpy(mKey, cur_ptr, mKeyLength) ;
|
||||
cur_ptr += mKeyLength ;
|
||||
|
||||
PRInt32 id ;
|
||||
mDB->GetID(mKey, mKeyLength, &id) ;
|
||||
NS_ASSERTION(id==mRecordID, "\t ++++++ bad record, somethings wrong\n") ;
|
||||
|
||||
// set mMetaDataLength
|
||||
COPY_INT32(&mMetaDataLength, cur_ptr) ;
|
||||
cur_ptr += sizeof(PRUint32) ;
|
||||
|
||||
// set mMetaData
|
||||
mMetaData = NS_STATIC_CAST(char*, nsAllocator::Alloc(mMetaDataLength*sizeof(char))) ;
|
||||
if(!mMetaData)
|
||||
return NS_ERROR_OUT_OF_MEMORY ;
|
||||
|
||||
memcpy(mMetaData, cur_ptr, mMetaDataLength) ;
|
||||
cur_ptr += mMetaDataLength ;
|
||||
|
||||
// get mFile name length
|
||||
COPY_INT32(&name_len, cur_ptr) ;
|
||||
cur_ptr += sizeof(PRUint32) ;
|
||||
|
||||
// get mFile native name
|
||||
file_url = NS_STATIC_CAST(char*, nsAllocator::Alloc(name_len*sizeof(char))) ;
|
||||
if(!file_url)
|
||||
return NS_ERROR_OUT_OF_MEMORY ;
|
||||
|
||||
memcpy(file_url, cur_ptr, name_len) ;
|
||||
cur_ptr += name_len ;
|
||||
|
||||
PR_ASSERT(cur_ptr == NS_STATIC_CAST(char*, aInfo) + mInfoSize);
|
||||
|
||||
// create mFile if Init() isn't called
|
||||
if(!mFile) {
|
||||
NS_NewFileSpec(getter_AddRefs(mFile));
|
||||
if(!mFile)
|
||||
return NS_ERROR_OUT_OF_MEMORY ;
|
||||
}
|
||||
|
||||
// setup mFile
|
||||
mFile->SetURLString(file_url) ;
|
||||
|
||||
return NS_OK ;
|
||||
}
|
||||
|
||||
71
mozilla/netwerk/cache/filecache/nsDiskCacheRecord.h
vendored
Normal file
71
mozilla/netwerk/cache/filecache/nsDiskCacheRecord.h
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
/* -*- Mode: C++; 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 Communicator.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Intel Corp.
|
||||
* Portions created by Intel Corp. are
|
||||
* Copyright (C) 1999, 1999 Intel Corp. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s): Yixiong Zou <yixiong.zou@intel.com>
|
||||
* Carl Wong <carl.wong@intel.com>
|
||||
*/
|
||||
|
||||
#ifndef _NET_CACHEDDISKDATA_H_
|
||||
#define _NET_CACHEDDISKDATA_H_
|
||||
|
||||
#include "nsINetDataCacheRecord.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIDBAccessor.h"
|
||||
#include "prtypes.h"
|
||||
#include "nsILoadGroup.h"
|
||||
#include "nsIFileChannel.h"
|
||||
#include "nsNetDiskCache.h"
|
||||
|
||||
class nsDiskCacheRecord : public nsINetDataCacheRecord
|
||||
{
|
||||
public:
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSINETDATACACHERECORD
|
||||
|
||||
protected:
|
||||
|
||||
nsDiskCacheRecord(nsIDBAccessor* db, nsNetDiskCache* aCache) ;
|
||||
virtual ~nsDiskCacheRecord() ;
|
||||
|
||||
NS_IMETHOD RetrieveInfo(void* aInfo, PRUint32 aInfoLength) ;
|
||||
NS_IMETHOD Init(const char* key, PRUint32 length, PRInt32 ID) ;
|
||||
|
||||
nsresult GenInfo(void) ;
|
||||
|
||||
private:
|
||||
|
||||
char* mKey ;
|
||||
PRUint32 mKeyLength ;
|
||||
PRInt32 mRecordID ;
|
||||
char* mMetaData ;
|
||||
PRUint32 mMetaDataLength ;
|
||||
nsCOMPtr<nsIFileSpec> mFile ;
|
||||
nsCOMPtr<nsIDBAccessor> mDB ;
|
||||
void* mInfo ;
|
||||
PRUint32 mInfoSize ;
|
||||
PRUint32 mNumChannels ;
|
||||
nsNetDiskCache* mDiskCache ;
|
||||
|
||||
friend class nsDiskCacheRecordChannel ;
|
||||
friend class nsDBEnumerator ;
|
||||
friend class nsNetDiskCache ;
|
||||
} ;
|
||||
|
||||
#endif // _NET_CACHEDDISKDATA_H_
|
||||
552
mozilla/netwerk/cache/filecache/nsDiskCacheRecordChannel.cpp
vendored
Normal file
552
mozilla/netwerk/cache/filecache/nsDiskCacheRecordChannel.cpp
vendored
Normal file
@@ -0,0 +1,552 @@
|
||||
/* -*- Mode: C++; 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 Communicator.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Intel Corp.
|
||||
* Portions created by Intel Corp. are
|
||||
* Copyright (C) 1999, 1999 Intel Corp. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s): Yixiong Zou <yixiong.zou@intel.com>
|
||||
* Carl Wong <carl.wong@intel.com>
|
||||
*/
|
||||
|
||||
/*
|
||||
* Most of the code are taken from nsFileChannel.
|
||||
*/
|
||||
|
||||
#include "nsDiskCacheRecordChannel.h"
|
||||
#include "nsIFileTransportService.h"
|
||||
//#include "nsIIOService.h"
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsIURL.h"
|
||||
#include "nsIOutputStream.h"
|
||||
#include "netCore.h"
|
||||
#include "nsIMIMEService.h"
|
||||
#include "nsISupportsUtils.h"
|
||||
|
||||
//static NS_DEFINE_CID(kIOServiceCID, NS_IOSERVICE_CID);
|
||||
static NS_DEFINE_CID(kFileTransportServiceCID, NS_FILETRANSPORTSERVICE_CID);
|
||||
static NS_DEFINE_CID(kStandardURLCID, NS_STANDARDURL_CID);
|
||||
static NS_DEFINE_CID(kMIMEServiceCID, NS_MIMESERVICE_CID);
|
||||
|
||||
// This is copied from nsMemCacheChannel, We should consolidate these two.
|
||||
class WriteStreamWrapper : public nsIOutputStream
|
||||
{
|
||||
public:
|
||||
WriteStreamWrapper(nsDiskCacheRecordChannel* aChannel,
|
||||
nsIOutputStream *aBaseStream) ;
|
||||
|
||||
virtual ~WriteStreamWrapper() ;
|
||||
|
||||
static nsresult
|
||||
Create(nsDiskCacheRecordChannel* aChannel, nsIOutputStream *aBaseStream, nsIOutputStream* *aWrapper) ;
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIBASESTREAM
|
||||
NS_DECL_NSIOUTPUTSTREAM
|
||||
|
||||
private:
|
||||
nsDiskCacheRecordChannel* mChannel;
|
||||
nsCOMPtr<nsIOutputStream> mBaseStream;
|
||||
} ;
|
||||
|
||||
// implement nsISupports
|
||||
NS_IMPL_ISUPPORTS(WriteStreamWrapper, NS_GET_IID(nsIOutputStream))
|
||||
|
||||
WriteStreamWrapper::WriteStreamWrapper(nsDiskCacheRecordChannel* aChannel,
|
||||
nsIOutputStream *aBaseStream)
|
||||
: mChannel(aChannel), mBaseStream(aBaseStream)
|
||||
{
|
||||
NS_INIT_REFCNT();
|
||||
NS_ADDREF(mChannel);
|
||||
}
|
||||
|
||||
WriteStreamWrapper::~WriteStreamWrapper()
|
||||
{
|
||||
NS_RELEASE(mChannel);
|
||||
}
|
||||
|
||||
nsresult
|
||||
WriteStreamWrapper::Create(nsDiskCacheRecordChannel*aChannel, nsIOutputStream *aBaseStream, nsIOutputStream* * aWrapper)
|
||||
{
|
||||
WriteStreamWrapper *wrapper = new WriteStreamWrapper(aChannel, aBaseStream);
|
||||
if (!wrapper) return NS_ERROR_OUT_OF_MEMORY;
|
||||
NS_ADDREF(wrapper);
|
||||
*aWrapper = wrapper;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
WriteStreamWrapper::Write(const char *aBuffer, PRUint32 aCount, PRUint32 *aNumWritten)
|
||||
{
|
||||
*aNumWritten = 0;
|
||||
nsresult rv = mBaseStream->Write(aBuffer, aCount, aNumWritten);
|
||||
mChannel->NotifyStorageInUse(*aNumWritten);
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
WriteStreamWrapper::Flush()
|
||||
{
|
||||
return mBaseStream->Flush();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
WriteStreamWrapper::Close()
|
||||
{
|
||||
return mBaseStream->Close();
|
||||
}
|
||||
|
||||
nsDiskCacheRecordChannel::nsDiskCacheRecordChannel(nsDiskCacheRecord *aRecord,
|
||||
nsILoadGroup *aLoadGroup)
|
||||
: mRecord(aRecord) ,
|
||||
mLoadGroup(aLoadGroup)
|
||||
{
|
||||
NS_INIT_REFCNT() ;
|
||||
NS_ADDREF(mRecord);
|
||||
mRecord->mNumChannels++ ;
|
||||
}
|
||||
|
||||
nsDiskCacheRecordChannel::~nsDiskCacheRecordChannel()
|
||||
{
|
||||
mRecord->mNumChannels-- ;
|
||||
NS_RELEASE(mRecord);
|
||||
}
|
||||
|
||||
// I know that I gave conflicting advice on the issue of file
|
||||
// transport versus file protocol handler, but I thought that the
|
||||
// last word was that we would use the raw transport, when I wrote:
|
||||
//
|
||||
// > I just thought of an argument for the other side of the coin, i.e. the
|
||||
// > benefit of *not* reusing the file protocol handler: On the Mac, it's
|
||||
// > expensive to convert from a string URL to an nsFileSpec, because the Mac
|
||||
// > is brain-dead and scans every directory on the path to the file. It's
|
||||
// > cheaper to create a nsFileSpec for a cache file by combining a single,
|
||||
// > static nsFileSpec that corresponds to the cache directory with the
|
||||
// > relative path to the cache file (using nsFileSpec's operator +). This
|
||||
// > operation is optimized on the Mac to avoid the scanning operation.
|
||||
//
|
||||
// The Mac guys will eat us alive if we do path string to nsFileSpec
|
||||
// conversions for every cache file we open.
|
||||
|
||||
nsresult
|
||||
nsDiskCacheRecordChannel::Init(void)
|
||||
{
|
||||
nsresult rv = mRecord->mFile->GetFileSpec(&mSpec) ;
|
||||
|
||||
#ifdef XP_MAC
|
||||
|
||||
// Don't assume we actually created a good file spec
|
||||
FSSpec theSpec = mSpec.GetFSSpec();
|
||||
if (!theSpec.name[0]) {
|
||||
NS_ERROR("failed to create a file spec");
|
||||
|
||||
// Since we didn't actually create the file spec
|
||||
// we return an error
|
||||
return NS_ERROR_MALFORMED_URI;
|
||||
}
|
||||
#endif
|
||||
|
||||
return rv ;
|
||||
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsDiskCacheRecordChannel::NotifyStorageInUse(PRInt32 aBytesUsed)
|
||||
{
|
||||
return mRecord->mDiskCache->m_StorageInUse += aBytesUsed ;
|
||||
}
|
||||
|
||||
// implement nsISupports
|
||||
NS_IMPL_ISUPPORTS4(nsDiskCacheRecordChannel,
|
||||
nsIChannel,
|
||||
nsIRequest,
|
||||
nsIStreamListener,
|
||||
nsIStreamObserver)
|
||||
|
||||
// implement nsIRequest
|
||||
NS_IMETHODIMP
|
||||
nsDiskCacheRecordChannel::IsPending(PRBool *aIsPending)
|
||||
{
|
||||
*aIsPending = PR_FALSE ;
|
||||
if(!mFileTransport)
|
||||
return NS_OK ;
|
||||
|
||||
return mFileTransport->IsPending(aIsPending) ;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDiskCacheRecordChannel::Cancel(void)
|
||||
{
|
||||
if(!mFileTransport)
|
||||
return NS_ERROR_FAILURE ;
|
||||
|
||||
return mFileTransport->Cancel() ;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDiskCacheRecordChannel::Suspend(void)
|
||||
{
|
||||
if(!mFileTransport)
|
||||
return NS_ERROR_FAILURE ;
|
||||
|
||||
return mFileTransport->Suspend() ;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDiskCacheRecordChannel::Resume(void)
|
||||
{
|
||||
if(!mFileTransport)
|
||||
return NS_ERROR_FAILURE ;
|
||||
|
||||
return mFileTransport->Resume() ;
|
||||
}
|
||||
|
||||
// implement nsIChannel
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDiskCacheRecordChannel::GetOriginalURI(nsIURI* *aURI)
|
||||
{
|
||||
// FUR - might need to implement this - not sure
|
||||
return NS_ERROR_NOT_IMPLEMENTED ;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDiskCacheRecordChannel::GetURI(nsIURI * *aURI)
|
||||
{
|
||||
if(!mFileTransport)
|
||||
return NS_ERROR_FAILURE ;
|
||||
|
||||
return mFileTransport->GetURI(aURI) ;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDiskCacheRecordChannel::OpenInputStream(PRUint32 aStartPosition,
|
||||
PRInt32 aReadCount,
|
||||
nsIInputStream* *aResult)
|
||||
{
|
||||
nsresult rv ;
|
||||
|
||||
if(mFileTransport)
|
||||
return NS_ERROR_IN_PROGRESS ;
|
||||
|
||||
NS_WITH_SERVICE(nsIFileTransportService, fts, kFileTransportServiceCID, &rv) ;
|
||||
if(NS_FAILED(rv)) return rv ;
|
||||
|
||||
rv = fts->CreateTransport(mSpec, "load", 0, 0, getter_AddRefs(mFileTransport)) ;
|
||||
if(NS_FAILED(rv))
|
||||
return rv ;
|
||||
|
||||
// we don't need to worry about notification callbacks
|
||||
|
||||
rv = mFileTransport->OpenInputStream(aStartPosition, aReadCount, aResult) ;
|
||||
if(NS_FAILED(rv))
|
||||
mFileTransport = nsnull ;
|
||||
|
||||
return rv ;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDiskCacheRecordChannel::OpenOutputStream(PRUint32 startPosition,
|
||||
nsIOutputStream* *aResult)
|
||||
{
|
||||
nsresult rv ;
|
||||
NS_ENSURE_ARG(aResult) ;
|
||||
|
||||
if(mFileTransport)
|
||||
return NS_ERROR_IN_PROGRESS ;
|
||||
|
||||
nsCOMPtr<nsIOutputStream> outputStream ;
|
||||
|
||||
NS_WITH_SERVICE(nsIFileTransportService, fts, kFileTransportServiceCID, &rv) ;
|
||||
if(NS_FAILED(rv)) return rv ;
|
||||
|
||||
rv = fts->CreateTransport(mSpec, "load", 0, 0, getter_AddRefs(mFileTransport)) ;
|
||||
if(NS_FAILED(rv))
|
||||
return rv ;
|
||||
|
||||
// we don't need to worry about notification callbacks
|
||||
|
||||
rv = mFileTransport->OpenOutputStream(startPosition, getter_AddRefs(outputStream)) ;
|
||||
if(NS_FAILED(rv)) {
|
||||
mFileTransport = nsnull ;
|
||||
return rv ;
|
||||
}
|
||||
|
||||
return WriteStreamWrapper::Create(this, outputStream, aResult) ;
|
||||
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDiskCacheRecordChannel::AsyncOpen(nsIStreamObserver *observer,
|
||||
nsISupports *ctxt)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED ;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDiskCacheRecordChannel::AsyncRead(PRUint32 aStartPosition,
|
||||
PRInt32 aReadCount,
|
||||
nsISupports *aContext,
|
||||
nsIStreamListener *aListener)
|
||||
{
|
||||
nsresult rv ;
|
||||
|
||||
if(mFileTransport)
|
||||
return NS_ERROR_IN_PROGRESS ;
|
||||
|
||||
mRealListener = aListener;
|
||||
nsCOMPtr<nsIStreamListener> tempListener = this;
|
||||
|
||||
if (mLoadGroup) {
|
||||
nsCOMPtr<nsILoadGroupListenerFactory> factory;
|
||||
//
|
||||
// Create a load group "proxy" listener...
|
||||
//
|
||||
rv = mLoadGroup->GetGroupListenerFactory(getter_AddRefs(factory));
|
||||
if (factory) {
|
||||
nsIStreamListener *newListener;
|
||||
rv = factory->CreateLoadGroupListener(mRealListener, &newListener);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
mRealListener = newListener;
|
||||
NS_RELEASE(newListener);
|
||||
}
|
||||
}
|
||||
|
||||
rv = mLoadGroup->AddChannel(this, nsnull);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
}
|
||||
|
||||
|
||||
NS_WITH_SERVICE(nsIFileTransportService, fts, kFileTransportServiceCID, &rv);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
rv = fts->CreateTransport(mSpec, "load", 0, 0, getter_AddRefs(mFileTransport));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// no callbacks
|
||||
|
||||
rv = mFileTransport->AsyncRead(aStartPosition,
|
||||
aReadCount,
|
||||
aContext,
|
||||
tempListener);
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
// release the transport so that we don't think we're in progress
|
||||
mFileTransport = nsnull;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDiskCacheRecordChannel::AsyncWrite(nsIInputStream *fromStream,
|
||||
PRUint32 startPosition,
|
||||
PRInt32 writeCount,
|
||||
nsISupports *ctxt,
|
||||
nsIStreamObserver *observer)
|
||||
|
||||
{
|
||||
/*
|
||||
if(!mFileTransport)
|
||||
return NS_ERROR_FAILURE ;
|
||||
|
||||
return mFileTransport->AsyncWrite(fromStream,
|
||||
startPosition,
|
||||
writeCount,
|
||||
ctxt,
|
||||
observer) ;
|
||||
*/
|
||||
|
||||
// I can't do this since the write is not monitored, and I won't be
|
||||
// able to updata the storage.
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDiskCacheRecordChannel::GetLoadAttributes(nsLoadFlags *aLoadAttributes)
|
||||
{
|
||||
// Not required to be implemented, since it is implemented by cache manager
|
||||
NS_ASSERTION(0, "nsDiskCacheRecordChannel method unexpectedly called");
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDiskCacheRecordChannel::SetLoadAttributes(nsLoadFlags aLoadAttributes)
|
||||
{
|
||||
// Not required to be implemented, since it is implemented by cache manager
|
||||
NS_ASSERTION(0, "nsDiskCacheRecordChannel method unexpectedly called");
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
#define DUMMY_TYPE "text/html"
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDiskCacheRecordChannel::GetContentType(char * *aContentType)
|
||||
{
|
||||
nsresult rv ;
|
||||
|
||||
if (mSpec.IsDirectory()) {
|
||||
*aContentType = nsCRT::strdup("application/http-index-format");
|
||||
return *aContentType ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
else {
|
||||
// I wish I can make this simplier
|
||||
|
||||
char* urlStr ;
|
||||
mRecord->mFile->GetURLString(&urlStr) ;
|
||||
|
||||
// file: URLs (currently) have no additional structure beyond that provided by standard
|
||||
// URLs, so there is no "outer" given to CreateInstance
|
||||
|
||||
nsCOMPtr<nsIURI> url;
|
||||
rv = nsComponentManager::CreateInstance(kStandardURLCID, nsnull,
|
||||
NS_GET_IID(nsIURI),
|
||||
//(void**)&url);
|
||||
getter_AddRefs(url)) ;
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
rv = url->SetSpec((char*)urlStr);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
NS_WITH_SERVICE(nsIMIMEService, MIMEService, kMIMEServiceCID, &rv);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
rv = MIMEService->GetTypeFromURI(url, aContentType);
|
||||
if (NS_SUCCEEDED(rv)) return rv;
|
||||
}
|
||||
|
||||
// if all else fails treat it as text/html?
|
||||
*aContentType = nsCRT::strdup(DUMMY_TYPE);
|
||||
if (!*aContentType) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
} else {
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDiskCacheRecordChannel::GetContentLength(PRInt32 *aContentLength)
|
||||
{
|
||||
nsresult rv;
|
||||
PRUint32 length;
|
||||
|
||||
rv = mRecord->mFile->GetFileSize(&length);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
*aContentLength = (PRInt32)length;
|
||||
} else {
|
||||
*aContentLength = -1;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDiskCacheRecordChannel::GetOwner(nsISupports* *aOwner)
|
||||
{
|
||||
*aOwner = mOwner.get() ;
|
||||
NS_IF_ADDREF(*aOwner) ;
|
||||
return NS_OK ;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDiskCacheRecordChannel::SetOwner(nsISupports* aOwner)
|
||||
{
|
||||
mOwner = aOwner ;
|
||||
return NS_OK ;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDiskCacheRecordChannel::GetLoadGroup(nsILoadGroup* *aLoadGroup)
|
||||
{
|
||||
// Not required to be implemented, since it is implemented by cache manager
|
||||
NS_ASSERTION(0, "nsDiskCacheRecordChannel method unexpectedly called");
|
||||
return NS_OK ;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDiskCacheRecordChannel::SetLoadGroup(nsILoadGroup* aLoadGroup)
|
||||
{
|
||||
// Not required to be implemented, since it is implemented by cache manager
|
||||
NS_ASSERTION(0, "nsDiskCacheRecordChannel method unexpectedly called");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDiskCacheRecordChannel::GetNotificationCallbacks(nsIInterfaceRequestor* *aNotificationCallbacks)
|
||||
{
|
||||
// Not required to be implemented, since it is implemented by cache manager
|
||||
NS_ASSERTION(0, "nsDiskCacheRecordChannel method unexpectedly called");
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDiskCacheRecordChannel::SetNotificationCallbacks(nsIInterfaceRequestor* aNotificationCallbacks)
|
||||
{
|
||||
// Not required to be implemented, since it is implemented by cache manager
|
||||
NS_ASSERTION(0, "nsDiskCacheRecordChannel method unexpectedly called");
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// nsIStreamListener methods:
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDiskCacheRecordChannel::OnStartRequest(nsIChannel* transportChannel, nsISupports* context)
|
||||
{
|
||||
NS_ASSERTION(mRealListener, "No listener...");
|
||||
return mRealListener->OnStartRequest(this, context);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDiskCacheRecordChannel::OnStopRequest(nsIChannel* transportChannel, nsISupports* context,
|
||||
nsresult aStatus, const PRUnichar* aMsg)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
rv = mRealListener->OnStopRequest(this, context, aStatus, aMsg);
|
||||
|
||||
if (mLoadGroup) {
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
mLoadGroup->RemoveChannel(this, context, aStatus, aMsg);
|
||||
}
|
||||
}
|
||||
|
||||
// Release the reference to the consumer stream listener...
|
||||
mRealListener = null_nsCOMPtr();
|
||||
mFileTransport = null_nsCOMPtr();
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDiskCacheRecordChannel::OnDataAvailable(nsIChannel* transportChannel, nsISupports* context,
|
||||
nsIInputStream *aIStream, PRUint32 aSourceOffset,
|
||||
PRUint32 aLength)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
rv = mRealListener->OnDataAvailable(this, context, aIStream,
|
||||
aSourceOffset, aLength);
|
||||
|
||||
//
|
||||
// If the connection is being aborted cancel the transport. This will
|
||||
// insure that the transport will go away even if it is blocked waiting
|
||||
// for the consumer to empty the pipe...
|
||||
//
|
||||
if (NS_FAILED(rv)) {
|
||||
mFileTransport->Cancel();
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
76
mozilla/netwerk/cache/filecache/nsDiskCacheRecordChannel.h
vendored
Normal file
76
mozilla/netwerk/cache/filecache/nsDiskCacheRecordChannel.h
vendored
Normal file
@@ -0,0 +1,76 @@
|
||||
/* -*- Mode: C++; 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 Communicator.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Intel Corp.
|
||||
* Portions created by Intel Corp. are
|
||||
* Copyright (C) 1999, 1999 Intel Corp. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s): Yixiong Zou <yixiong.zou@intel.com>
|
||||
* Carl Wong <carl.wong@intel.com>
|
||||
*/
|
||||
|
||||
#ifndef _ns_DiskCacheRecordChannel_h_
|
||||
#define _ns_DiskCacheRecordChannel_h_
|
||||
|
||||
#include "nsIChannel.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsDiskCacheRecord.h"
|
||||
#include "nsIStreamListener.h"
|
||||
|
||||
/*
|
||||
* This class is plagiarized from nsMemCacheChannel
|
||||
*/
|
||||
|
||||
class nsDiskCacheRecordChannel : public nsIChannel,
|
||||
public nsIStreamListener
|
||||
{
|
||||
public:
|
||||
|
||||
nsDiskCacheRecordChannel(nsDiskCacheRecord *aRecord, nsILoadGroup *aLoadGroup);
|
||||
virtual ~nsDiskCacheRecordChannel() ;
|
||||
|
||||
// Declare nsISupports methods
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
// Declare nsIRequest methods
|
||||
NS_DECL_NSIREQUEST
|
||||
|
||||
// Declare nsIChannel methods
|
||||
NS_DECL_NSICHANNEL
|
||||
|
||||
// Declare nsIStreamObserver methods
|
||||
NS_DECL_NSISTREAMOBSERVER
|
||||
|
||||
// Declare nsIStreamListener methods
|
||||
NS_DECL_NSISTREAMLISTENER
|
||||
|
||||
nsresult Init(void) ;
|
||||
|
||||
private:
|
||||
|
||||
nsresult NotifyStorageInUse(PRInt32 aBytesUsed) ;
|
||||
|
||||
nsDiskCacheRecord* mRecord ;
|
||||
nsCOMPtr<nsILoadGroup> mLoadGroup ;
|
||||
nsCOMPtr<nsISupports> mOwner ;
|
||||
nsCOMPtr<nsIChannel> mFileTransport ;
|
||||
nsFileSpec mSpec ;
|
||||
nsCOMPtr<nsIStreamListener> mRealListener;
|
||||
|
||||
friend class WriteStreamWrapper ;
|
||||
} ;
|
||||
|
||||
#endif // _ns_DiskCacheRecordChannel_h_
|
||||
|
||||
66
mozilla/netwerk/cache/filecache/nsIDBAccessor.h
vendored
Normal file
66
mozilla/netwerk/cache/filecache/nsIDBAccessor.h
vendored
Normal file
@@ -0,0 +1,66 @@
|
||||
/* -*- Mode: C++; 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 Communicator.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Intel Corp.
|
||||
* Portions created by Intel Corp. are
|
||||
* Copyright (C) 1999, 1999 Intel Corp. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s): Yixiong Zou <yixiong.zou@intel.com>
|
||||
* Carl Wong <carl.wong@intel.com>
|
||||
*/
|
||||
|
||||
#ifndef _NS_IDBACCESSOR_H_
|
||||
#define _NS_IDBACCESSOR_H_
|
||||
|
||||
#include "nsISupports.h"
|
||||
#include "nsIFileSpec.h"
|
||||
|
||||
// nsIDBAccessorIID {6AADD4D0-7785-11d3-87FE-000629D01344}
|
||||
#define NS_IDBACCESSOR_IID \
|
||||
{ 0x6aadd4d0, 0x7785, 0x11d3, \
|
||||
{0x87, 0xfe, 0x0, 0x6, 0x29, 0xd0, 0x13, 0x44}}
|
||||
|
||||
// nsDBAccessorCID {6AADD4D1-7785-11d3-87FE-000629D01344}
|
||||
#define NS_DBACCESSOR_CID \
|
||||
{ 0x6aadd4d1, 0x7785, 0x11d3, \
|
||||
{ 0x87, 0xfe, 0x0, 0x6, 0x29, 0xd0, 0x13, 0x44 }}
|
||||
|
||||
class nsIDBAccessor : public nsISupports
|
||||
{
|
||||
public:
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(NS_IDBACCESSOR_IID)
|
||||
|
||||
NS_IMETHOD Init(nsIFileSpec* DBFile) = 0 ;
|
||||
NS_IMETHOD Shutdown(void) = 0 ;
|
||||
|
||||
NS_IMETHOD Put(PRInt32 aID, void* anEntry, PRUint32 aLength) = 0 ;
|
||||
|
||||
NS_IMETHOD Get(PRInt32 aID, void** anEntry, PRUint32 *aLength) = 0 ;
|
||||
|
||||
NS_IMETHOD Del(PRInt32 aID, void* anEntry, PRUint32 aLength) = 0 ;
|
||||
|
||||
NS_IMETHOD GetID(const char* key, PRUint32 length, PRInt32* aID) = 0 ;
|
||||
|
||||
NS_IMETHOD EnumEntry(void* *anEntry, PRUint32* aLength, PRBool bReset) = 0 ;
|
||||
|
||||
NS_IMETHOD GetDBFilesize(PRUint32* aSize) = 0 ;
|
||||
|
||||
NS_IMETHOD GetSpecialEntry(void** anEntry, PRUint32 *aLength) = 0 ;
|
||||
NS_IMETHOD SetSpecialEntry(void* anEntry, PRUint32 aLength) = 0 ;
|
||||
|
||||
} ;
|
||||
|
||||
#endif // _NS_IDBACCESSOR_H_
|
||||
|
||||
704
mozilla/netwerk/cache/filecache/nsNetDiskCache.cpp
vendored
Normal file
704
mozilla/netwerk/cache/filecache/nsNetDiskCache.cpp
vendored
Normal file
@@ -0,0 +1,704 @@
|
||||
/* -*- Mode: C++; 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 Communicator.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Intel Corp.
|
||||
* Portions created by Intel Corp. are
|
||||
* Copyright (C) 1999, 1999 Intel Corp. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s): Yixiong Zou <yixiong.zou@intel.com>
|
||||
* Carl Wong <carl.wong@intel.com>
|
||||
*/
|
||||
|
||||
#include "nsNetDiskCache.h"
|
||||
#include "nscore.h"
|
||||
|
||||
#include "plstr.h"
|
||||
#include "prprf.h"
|
||||
#include "prtypes.h"
|
||||
#include "prio.h"
|
||||
#include "prsystem.h" // Directory Seperator
|
||||
#include "plhash.h"
|
||||
#include "prclist.h"
|
||||
#include "prmem.h"
|
||||
#include "prlog.h"
|
||||
|
||||
#include "nsIComponentManager.h"
|
||||
#include "nsIServiceManager.h"
|
||||
|
||||
#include "nsIPref.h"
|
||||
#include "mcom_db.h"
|
||||
#include "nsDBEnumerator.h"
|
||||
|
||||
#include "nsDiskCacheRecord.h"
|
||||
#include "netCore.h"
|
||||
|
||||
#if !defined(IS_LITTLE_ENDIAN) && !defined(IS_BIG_ENDIAN)
|
||||
ERROR! Must have a byte order
|
||||
#endif
|
||||
|
||||
#ifdef IS_LITTLE_ENDIAN
|
||||
#define COPY_INT32(_a,_b) memcpy(_a, _b, sizeof(int32))
|
||||
#else
|
||||
#define COPY_INT32(_a,_b) /* swap */ \
|
||||
do { \
|
||||
((char *)(_a))[0] = ((char *)(_b))[3]; \
|
||||
((char *)(_a))[1] = ((char *)(_b))[2]; \
|
||||
((char *)(_a))[2] = ((char *)(_b))[1]; \
|
||||
((char *)(_a))[3] = ((char *)(_b))[0]; \
|
||||
} while(0)
|
||||
#endif
|
||||
|
||||
static NS_DEFINE_CID(kPrefCID, NS_PREF_CID) ;
|
||||
static NS_DEFINE_CID(kDBAccessorCID, NS_DBACCESSOR_CID) ;
|
||||
|
||||
static const PRUint32 DISK_CACHE_SIZE_DEFAULT = 5*1024*1024 ; // 5MB
|
||||
static const char * const DISK_CACHE_PREF = "browser.cache.disk_cache_size";
|
||||
static const char * const CACHE_DIR_PREF = "browser.cache.directory";
|
||||
|
||||
class nsDiskCacheRecord ;
|
||||
|
||||
nsNetDiskCache::nsNetDiskCache() :
|
||||
m_Enabled(PR_TRUE) ,
|
||||
m_NumEntries(0) ,
|
||||
m_pNextCache(0) ,
|
||||
m_pDiskCacheFolder(0) ,
|
||||
m_StorageInUse(0) ,
|
||||
m_DB(0) ,
|
||||
m_DBCorrupted(PR_FALSE)
|
||||
{
|
||||
// set it to INF for now
|
||||
m_MaxEntries = (PRUint32)-1 ;
|
||||
|
||||
NS_INIT_REFCNT();
|
||||
|
||||
}
|
||||
|
||||
nsNetDiskCache::~nsNetDiskCache()
|
||||
{
|
||||
SetSpecialEntry() ;
|
||||
|
||||
NS_IF_RELEASE(m_DB) ;
|
||||
|
||||
|
||||
// FUR
|
||||
// I think that, eventually, we also want a distinguished key in the DB which
|
||||
// means "clean cache shutdown". You clear this flag when the db is first
|
||||
// opened and set it just before the db is closed. If the db wasn't shutdown
|
||||
// cleanly in a prior session, i.e. because the app crashed, on startup you
|
||||
// scan all the individual files in directories and look for "orphans",
|
||||
// i.e. cache files which don't have corresponding entries in the db. That's
|
||||
// also when storage-in-use and number of entries would be recomputed.
|
||||
//
|
||||
// We don't necessarily need all this functionality immediately, though.
|
||||
|
||||
|
||||
if(m_DBCorrupted) {
|
||||
|
||||
nsFileSpec cacheFolder ;
|
||||
m_pDiskCacheFolder->GetFileSpec(&cacheFolder) ;
|
||||
|
||||
char nameInt[6] ;
|
||||
|
||||
for(nsDirectoryIterator di(cacheFolder, PR_FALSE); di.Exists(); di++) {
|
||||
char* filename = di.Spec().GetLeafName() ;
|
||||
char* pname = nameInt ;
|
||||
pname = PL_strncpyz(pname, filename, 6) ;
|
||||
|
||||
if(PL_strcmp(pname, "trash") == 0)
|
||||
RemoveFolder(di.Spec()) ;
|
||||
|
||||
nsCRT::free(filename) ;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNetDiskCache::Init(void)
|
||||
{
|
||||
nsresult rv ;
|
||||
|
||||
// don't initialize if no cache folder is set.
|
||||
if(!m_pDiskCacheFolder) return NS_OK ;
|
||||
|
||||
if(!m_DB) {
|
||||
m_DB = new nsDBAccessor() ;
|
||||
if(!m_DB)
|
||||
return NS_ERROR_OUT_OF_MEMORY ;
|
||||
else
|
||||
NS_ADDREF(m_DB) ;
|
||||
}
|
||||
|
||||
// create cache sub directories
|
||||
nsCOMPtr<nsIFileSpec> cacheSubDir;
|
||||
rv = NS_NewFileSpec(getter_AddRefs(cacheSubDir));
|
||||
|
||||
for (int i=0; i < 32; i++) {
|
||||
rv = cacheSubDir->FromFileSpec(m_pDiskCacheFolder) ;
|
||||
if(NS_FAILED(rv))
|
||||
return rv ;
|
||||
|
||||
char dirName[3];
|
||||
PR_snprintf (dirName, 3, "%0.2x", i);
|
||||
cacheSubDir->AppendRelativeUnixPath (dirName) ;
|
||||
CreateDir(cacheSubDir);
|
||||
}
|
||||
|
||||
return InitDB() ;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNetDiskCache::InitDB(void)
|
||||
{
|
||||
nsresult rv ;
|
||||
|
||||
if(!m_DBFile) {
|
||||
NS_NewFileSpec(getter_AddRefs(m_DBFile)) ;
|
||||
if(!m_DBFile)
|
||||
return NS_ERROR_OUT_OF_MEMORY ;
|
||||
}
|
||||
|
||||
rv = m_DBFile->FromFileSpec(m_pDiskCacheFolder) ;
|
||||
if(NS_FAILED(rv))
|
||||
return rv ;
|
||||
|
||||
m_DBFile->AppendRelativeUnixPath("cache.db") ;
|
||||
|
||||
rv = m_DB->Init(m_DBFile) ;
|
||||
|
||||
if(rv == NS_ERROR_FAILURE) {
|
||||
// try recovery if error
|
||||
DBRecovery() ;
|
||||
}
|
||||
|
||||
rv = GetSpecialEntry() ;
|
||||
if(rv == NS_ERROR_FAILURE) {
|
||||
// try recovery if error
|
||||
DBRecovery() ;
|
||||
}
|
||||
|
||||
return rv ;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// nsISupports methods
|
||||
|
||||
NS_IMPL_ISUPPORTS3(nsNetDiskCache,
|
||||
nsINetDataDiskCache,
|
||||
nsINetDataCache,
|
||||
nsISupports)
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// nsINetDataCache Method
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNetDiskCache::GetDescription(PRUnichar* *aDescription)
|
||||
{
|
||||
nsAutoString description("Disk Cache") ;
|
||||
*aDescription = description.ToNewUnicode() ;
|
||||
if(!*aDescription)
|
||||
return NS_ERROR_OUT_OF_MEMORY ;
|
||||
|
||||
return NS_OK ;
|
||||
}
|
||||
|
||||
/* don't alloc mem for nsICachedNetData.
|
||||
* RecordID is generated using the same scheme in nsCacheDiskData,
|
||||
* see GetCachedNetData() for detail.
|
||||
*/
|
||||
NS_IMETHODIMP
|
||||
nsNetDiskCache::Contains(const char* key, PRUint32 length, PRBool *_retval)
|
||||
{
|
||||
*_retval = PR_FALSE ;
|
||||
|
||||
NS_ASSERTION(m_DB, "no db.") ;
|
||||
|
||||
PRInt32 id = 0 ;
|
||||
nsresult rv = m_DB->GetID(key, length, &id) ;
|
||||
|
||||
if(NS_FAILED(rv)) {
|
||||
// try recovery if error
|
||||
DBRecovery() ;
|
||||
return rv ;
|
||||
}
|
||||
|
||||
void* info = 0 ;
|
||||
PRUint32 info_size = 0 ;
|
||||
|
||||
rv = m_DB->Get(id, &info, &info_size) ;
|
||||
if(NS_SUCCEEDED(rv) && info)
|
||||
*_retval = PR_TRUE ;
|
||||
|
||||
if(NS_FAILED(rv)) {
|
||||
// try recovery if error
|
||||
DBRecovery() ;
|
||||
}
|
||||
|
||||
return rv ;
|
||||
}
|
||||
|
||||
/* regardless if it's cached or not, a copy of nsNetDiskCache would
|
||||
* always be returned. so release it appropriately.
|
||||
* if mem alloced, updata m_NumEntries also.
|
||||
* for now, the new nsCachedNetData is not written into db yet since
|
||||
* we have nothing to write.
|
||||
*/
|
||||
NS_IMETHODIMP
|
||||
nsNetDiskCache::GetCachedNetData(const char* key, PRUint32 length, nsINetDataCacheRecord **_retval)
|
||||
{
|
||||
NS_ASSERTION(m_DB, "no db.") ;
|
||||
|
||||
nsresult rv = 0 ;
|
||||
if (!_retval)
|
||||
return NS_ERROR_NULL_POINTER ;
|
||||
|
||||
*_retval = nsnull ;
|
||||
|
||||
PRInt32 id = 0 ;
|
||||
rv = m_DB->GetID(key, length, &id) ;
|
||||
if(NS_FAILED(rv)) {
|
||||
// try recovery if error
|
||||
DBRecovery() ;
|
||||
return rv ;
|
||||
}
|
||||
|
||||
// construct an empty record
|
||||
nsDiskCacheRecord* newRecord = new nsDiskCacheRecord(m_DB, this) ;
|
||||
if(!newRecord)
|
||||
return NS_ERROR_OUT_OF_MEMORY ;
|
||||
|
||||
rv = newRecord->Init(key, length, id) ;
|
||||
if(NS_FAILED(rv)) {
|
||||
delete newRecord ;
|
||||
return rv ;
|
||||
}
|
||||
|
||||
NS_ADDREF(newRecord) ; // addref for _retval
|
||||
*_retval = (nsINetDataCacheRecord*) newRecord ;
|
||||
|
||||
void* info = 0 ;
|
||||
PRUint32 info_size = 0 ;
|
||||
|
||||
rv = m_DB->Get(id, &info, &info_size) ;
|
||||
if(NS_SUCCEEDED(rv) && info) {
|
||||
|
||||
// this is a previously cached record
|
||||
nsresult r1 ;
|
||||
r1 = newRecord->RetrieveInfo(info, info_size) ;
|
||||
|
||||
if(NS_SUCCEEDED(rv))
|
||||
return NS_OK ;
|
||||
else {
|
||||
// probably a bad one
|
||||
NS_RELEASE(newRecord) ;
|
||||
*_retval = nsnull ;
|
||||
return r1;
|
||||
}
|
||||
|
||||
} else if (NS_SUCCEEDED(rv) && !info) {
|
||||
// this is a new record.
|
||||
m_NumEntries ++ ;
|
||||
return NS_OK ;
|
||||
} else {
|
||||
// database error.
|
||||
DBRecovery() ;
|
||||
return rv ;
|
||||
}
|
||||
}
|
||||
|
||||
/* get an nsICachedNetData, mem needs to be de-alloced if not found. */
|
||||
NS_IMETHODIMP
|
||||
nsNetDiskCache::GetCachedNetDataByID(PRInt32 RecordID, nsINetDataCacheRecord **_retval)
|
||||
{
|
||||
NS_ASSERTION(m_DB, "no db.") ;
|
||||
|
||||
if (!_retval)
|
||||
return NS_ERROR_NULL_POINTER ;
|
||||
|
||||
*_retval = nsnull ;
|
||||
|
||||
nsresult rv ;
|
||||
|
||||
void* info = 0 ;
|
||||
PRUint32 info_size = 0 ;
|
||||
|
||||
rv = m_DB->Get(RecordID, &info, &info_size) ;
|
||||
if(NS_SUCCEEDED(rv) && info) {
|
||||
|
||||
// construct an empty record if only found in db
|
||||
nsDiskCacheRecord* newRecord = new nsDiskCacheRecord(m_DB, this) ;
|
||||
if(!newRecord)
|
||||
return NS_ERROR_OUT_OF_MEMORY ;
|
||||
|
||||
NS_ADDREF(newRecord) ; // addref for _retval
|
||||
rv = newRecord->RetrieveInfo(info, info_size) ;
|
||||
|
||||
if(NS_SUCCEEDED(rv)) {
|
||||
*_retval = (nsINetDataCacheRecord*) newRecord ;
|
||||
return NS_OK ;
|
||||
}
|
||||
else {
|
||||
// bad record, I guess
|
||||
NS_RELEASE(newRecord) ; // release if bad things happen
|
||||
return rv ;
|
||||
}
|
||||
} else {
|
||||
NS_ERROR("Error: RecordID not in DB\n") ;
|
||||
DBRecovery() ;
|
||||
return rv ;
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNetDiskCache::GetEnabled(PRBool *aEnabled)
|
||||
{
|
||||
*aEnabled = m_Enabled ;
|
||||
return NS_OK ;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNetDiskCache::SetEnabled(PRBool aEnabled)
|
||||
{
|
||||
m_Enabled = aEnabled ;
|
||||
return NS_OK ;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNetDiskCache::GetFlags(PRUint32 *aFlags)
|
||||
{
|
||||
*aFlags = FILE_PER_URL_CACHE;
|
||||
return NS_OK ;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNetDiskCache::GetNumEntries(PRUint32 *aNumEntries)
|
||||
{
|
||||
*aNumEntries = m_NumEntries ;
|
||||
return NS_OK ;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNetDiskCache::GetMaxEntries(PRUint32 *aMaxEntries)
|
||||
{
|
||||
*aMaxEntries = m_MaxEntries ;
|
||||
return NS_OK ;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNetDiskCache::NewCacheEntryIterator(nsISimpleEnumerator **_retval)
|
||||
{
|
||||
NS_ASSERTION(m_DB, "no db.") ;
|
||||
|
||||
if(!_retval)
|
||||
return NS_ERROR_NULL_POINTER ;
|
||||
|
||||
*_retval = nsnull ;
|
||||
|
||||
nsISimpleEnumerator* enumerator = new nsDBEnumerator(m_DB, this) ;
|
||||
if(enumerator) {
|
||||
NS_ADDREF(enumerator) ;
|
||||
*_retval = enumerator ;
|
||||
return NS_OK ;
|
||||
}
|
||||
else
|
||||
return NS_ERROR_OUT_OF_MEMORY ;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNetDiskCache::GetNextCache(nsINetDataCache * *aNextCache)
|
||||
{
|
||||
if(!aNextCache)
|
||||
return NS_ERROR_NULL_POINTER ;
|
||||
|
||||
*aNextCache = m_pNextCache ;
|
||||
return NS_OK ;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNetDiskCache::SetNextCache(nsINetDataCache *aNextCache)
|
||||
{
|
||||
m_pNextCache = aNextCache ;
|
||||
return NS_OK ;
|
||||
}
|
||||
|
||||
// db size can always be measured at the last minute. Since it's hard
|
||||
// to know before hand.
|
||||
NS_IMETHODIMP
|
||||
nsNetDiskCache::GetStorageInUse(PRUint32 *aStorageInUse)
|
||||
{
|
||||
NS_ASSERTION(m_DB, "no db.") ;
|
||||
|
||||
PRUint32 total_size = m_StorageInUse ;
|
||||
|
||||
/*
|
||||
PRUint32 len = 0 ;
|
||||
// add the size of the db.
|
||||
m_DB->GetDBFilesize(&len) ;
|
||||
total_size += len ;
|
||||
*/
|
||||
|
||||
// we need size in kB
|
||||
total_size = total_size >> 10 ;
|
||||
|
||||
*aStorageInUse = total_size ;
|
||||
return NS_OK ;
|
||||
}
|
||||
|
||||
/*
|
||||
* The whole cache dirs can be whiped clean since all the cache
|
||||
* files are resides in seperate hashed dirs. It's safe to do so.
|
||||
*/
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNetDiskCache::RemoveAll(void)
|
||||
{
|
||||
NS_ASSERTION(m_DB, "no db.") ;
|
||||
NS_ASSERTION(m_pDiskCacheFolder, "no cache folder.") ;
|
||||
|
||||
// remove all the sub folders
|
||||
nsFileSpec cacheSubDir;
|
||||
|
||||
for (int i=0; i < 32; i++) {
|
||||
m_pDiskCacheFolder->GetFileSpec(&cacheSubDir) ;
|
||||
|
||||
char dirName[3];
|
||||
PR_snprintf (dirName, 3, "%0.2x", i);
|
||||
cacheSubDir += dirName ;
|
||||
RemoveFolder(cacheSubDir) ;
|
||||
}
|
||||
|
||||
// don't forget the db file itself
|
||||
m_DB->Shutdown() ;
|
||||
nsFileSpec dbfile ;
|
||||
m_DBFile->GetFileSpec(&dbfile) ;
|
||||
dbfile.Delete(PR_TRUE) ;
|
||||
|
||||
// reinitilize
|
||||
return Init() ;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
// nsINetDataDiskCache methods
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNetDiskCache::GetDiskCacheFolder(nsIFileSpec * *aDiskCacheFolder)
|
||||
{
|
||||
*aDiskCacheFolder = nsnull ;
|
||||
NS_ASSERTION(m_pDiskCacheFolder, "no cache folder.") ;
|
||||
|
||||
*aDiskCacheFolder = m_pDiskCacheFolder ;
|
||||
NS_ADDREF(*aDiskCacheFolder) ;
|
||||
return NS_OK ;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNetDiskCache::SetDiskCacheFolder(nsIFileSpec * aDiskCacheFolder)
|
||||
{
|
||||
if(!m_pDiskCacheFolder) {
|
||||
NS_NewFileSpec(getter_AddRefs(m_pDiskCacheFolder));
|
||||
if(!m_pDiskCacheFolder)
|
||||
return NS_ERROR_OUT_OF_MEMORY ;
|
||||
|
||||
m_pDiskCacheFolder = aDiskCacheFolder ;
|
||||
return Init() ;
|
||||
}
|
||||
else {
|
||||
char *newfolder, *oldfolder ;
|
||||
m_pDiskCacheFolder->GetNativePath(&oldfolder) ;
|
||||
aDiskCacheFolder->GetNativePath(&newfolder) ;
|
||||
|
||||
if(PL_strcmp(newfolder, oldfolder) != 0) {
|
||||
m_pDiskCacheFolder = aDiskCacheFolder ;
|
||||
|
||||
// do we need to blow away old cache before building a new one?
|
||||
// return RemoveAll() ;
|
||||
|
||||
m_DB->Shutdown() ;
|
||||
return Init() ;
|
||||
|
||||
} else
|
||||
return NS_OK ;
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
// nsNetDiskCache methods
|
||||
|
||||
// create a directory (recursively)
|
||||
NS_IMETHODIMP
|
||||
nsNetDiskCache::CreateDir(nsIFileSpec* dir_spec)
|
||||
{
|
||||
PRBool does_exist ;
|
||||
nsCOMPtr<nsIFileSpec> p_spec ;
|
||||
|
||||
dir_spec->Exists(&does_exist) ;
|
||||
if(does_exist)
|
||||
return NS_OK ;
|
||||
|
||||
nsresult rv = dir_spec->GetParent(getter_AddRefs(p_spec)) ;
|
||||
if(NS_FAILED(rv))
|
||||
return rv ;
|
||||
|
||||
p_spec->Exists(&does_exist) ;
|
||||
if(!does_exist) {
|
||||
CreateDir(p_spec) ;
|
||||
rv = dir_spec->CreateDir() ;
|
||||
if(NS_FAILED(rv))
|
||||
return rv ;
|
||||
}
|
||||
else {
|
||||
rv = dir_spec->CreateDir() ;
|
||||
if(NS_FAILED(rv))
|
||||
return rv ;
|
||||
}
|
||||
|
||||
return NS_OK ;
|
||||
}
|
||||
|
||||
// We can't afford to make a *separate* pass over the whole db on every
|
||||
// startup, just to figure out m_NumEntries and m_StorageInUse. (This is a
|
||||
// several second operation on a large db). We'll likely need to store
|
||||
// distinguished keys in the db that contain these values and update them
|
||||
// incrementally, except when failure to shut down the db cleanly is detected.
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNetDiskCache::GetSpecialEntry(void)
|
||||
{
|
||||
void* pInfo ;
|
||||
PRUint32 InfoSize ;
|
||||
|
||||
nsresult rv = m_DB->GetSpecialEntry(&pInfo, &InfoSize) ;
|
||||
if(NS_FAILED(rv))
|
||||
return rv ;
|
||||
|
||||
if(!pInfo && InfoSize == 0) {
|
||||
// must be a new DB
|
||||
m_NumEntries = 0 ;
|
||||
m_StorageInUse = 0 ;
|
||||
}
|
||||
else {
|
||||
char * cur_ptr = NS_STATIC_CAST(char*, pInfo) ;
|
||||
|
||||
// get m_NumEntries
|
||||
COPY_INT32(&m_NumEntries, cur_ptr) ;
|
||||
cur_ptr += sizeof(PRUint32) ;
|
||||
|
||||
// get m_StorageInUse
|
||||
COPY_INT32(&m_StorageInUse, cur_ptr) ;
|
||||
cur_ptr += sizeof(PRUint32) ;
|
||||
|
||||
PR_ASSERT(cur_ptr == NS_STATIC_CAST(char*, pInfo) + InfoSize);
|
||||
}
|
||||
|
||||
return NS_OK ;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNetDiskCache::SetSpecialEntry(void)
|
||||
{
|
||||
PRUint32 InfoSize ;
|
||||
|
||||
InfoSize = sizeof m_NumEntries ;
|
||||
InfoSize += sizeof m_StorageInUse ;
|
||||
|
||||
void* pInfo = nsAllocator::Alloc(InfoSize*sizeof(char)) ;
|
||||
if(!pInfo)
|
||||
return NS_ERROR_OUT_OF_MEMORY ;
|
||||
|
||||
char* cur_ptr = NS_STATIC_CAST(char*, pInfo) ;
|
||||
|
||||
COPY_INT32(cur_ptr, &m_NumEntries) ;
|
||||
cur_ptr += sizeof(PRUint32) ;
|
||||
|
||||
COPY_INT32(cur_ptr, &m_StorageInUse) ;
|
||||
cur_ptr += sizeof(PRUint32) ;
|
||||
|
||||
PR_ASSERT(cur_ptr == NS_STATIC_CAST(char*, pInfo) + InfoSize);
|
||||
|
||||
return m_DB->SetSpecialEntry(pInfo, InfoSize) ;
|
||||
}
|
||||
|
||||
// this routine will be called everytime we have a db corruption.
|
||||
// m_DB will be re-initialized, m_StorageInUse and m_NumEntries will
|
||||
// be reset.
|
||||
NS_IMETHODIMP
|
||||
nsNetDiskCache::DBRecovery(void)
|
||||
{
|
||||
// rename all the sub cache dirs and remove them later during dtor.
|
||||
nsresult rv = RenameCacheSubDirs() ;
|
||||
if(NS_FAILED(rv))
|
||||
return rv ;
|
||||
|
||||
// remove corrupted db file, don't care if db->shutdown fails or not.
|
||||
m_DB->Shutdown() ;
|
||||
|
||||
nsFileSpec dbfile ;
|
||||
m_DBFile->GetFileSpec(&dbfile) ;
|
||||
dbfile.Delete(PR_TRUE) ;
|
||||
|
||||
// make sure it's not there any more
|
||||
PRBool exists = dbfile.Exists() ;
|
||||
if(exists) {
|
||||
NS_ERROR("can't remove old db.") ;
|
||||
return NS_ERROR_FAILURE ;
|
||||
}
|
||||
|
||||
// reinitilize DB
|
||||
return InitDB() ;
|
||||
}
|
||||
|
||||
// this routine will add string "trash" to current CacheSubDir names.
|
||||
// e.g. 00->trash00, 1f->trash1f. and update the m_DBCorrupted.
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNetDiskCache::RenameCacheSubDirs(void)
|
||||
{
|
||||
nsCOMPtr<nsIFileSpec> cacheSubDir;
|
||||
nsresult rv = NS_NewFileSpec(getter_AddRefs(cacheSubDir)) ;
|
||||
|
||||
for (int i=0; i < 32; i++) {
|
||||
rv = cacheSubDir->FromFileSpec(m_pDiskCacheFolder) ;
|
||||
if(NS_FAILED(rv))
|
||||
return rv ;
|
||||
|
||||
char oldName[3], newName[8];
|
||||
PR_snprintf(oldName, 3, "%0.2x", i) ;
|
||||
cacheSubDir->AppendRelativeUnixPath(oldName) ;
|
||||
|
||||
// re-name the directory
|
||||
PR_snprintf(newName, 8, "trash%0.2x", i) ;
|
||||
rv = cacheSubDir->Rename(newName) ;
|
||||
if(NS_FAILED(rv))
|
||||
// TODO, error checking
|
||||
return NS_ERROR_FAILURE ;
|
||||
}
|
||||
|
||||
// update m_DBCorrupted
|
||||
m_DBCorrupted = PR_TRUE ;
|
||||
|
||||
return NS_OK ;
|
||||
}
|
||||
|
||||
// this routine is used by dtor and RemoveAll() to clean up dirs.
|
||||
NS_IMETHODIMP
|
||||
nsNetDiskCache::RemoveFolder(nsFileSpec aFolder)
|
||||
{
|
||||
for(nsDirectoryIterator di(aFolder, PR_FALSE); di.Exists(); di++) {
|
||||
di.Spec().Delete(PR_TRUE) ;
|
||||
}
|
||||
|
||||
aFolder.Delete(PR_FALSE) ; // recursive delete
|
||||
|
||||
return NS_OK ;
|
||||
}
|
||||
91
mozilla/netwerk/cache/filecache/nsNetDiskCache.h
vendored
Normal file
91
mozilla/netwerk/cache/filecache/nsNetDiskCache.h
vendored
Normal file
@@ -0,0 +1,91 @@
|
||||
/* -*- Mode: C++; 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 Communicator.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Intel Corp.
|
||||
* Portions created by Intel Corp. are
|
||||
* Copyright (C) 1999, 1999 Intel Corp. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s): Yixiong Zou <yixiong.zou@intel.com>
|
||||
* Carl Wong <carl.wong@intel.com>
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is part of filecache implementation.
|
||||
*
|
||||
* nsNetDiskCache is the main disk cache module that will create
|
||||
* the cache database, and then store and retrieve nsDiskCacheRecord
|
||||
* objects from it. It also contains some basic error recovery procedure.
|
||||
*/
|
||||
|
||||
#ifndef __gen_nsNetDiskCache_h__
|
||||
#define __gen_nsNetDiskCache_h__
|
||||
|
||||
#include "nsINetDataDiskCache.h"
|
||||
#include "nsNetDiskCacheCID.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIPref.h"
|
||||
#include "nsDBAccessor.h"
|
||||
|
||||
class nsIURI; /* forward decl */
|
||||
class nsICachedNetData; /* forward decl */
|
||||
class nsISimpleEnumerator; /* forward decl */
|
||||
class nsIFileSpec; /* forward decl */
|
||||
|
||||
/* starting interface: nsNetDiskCache */
|
||||
|
||||
class nsNetDiskCache : public nsINetDataDiskCache {
|
||||
public:
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSINETDATACACHE
|
||||
NS_DECL_NSINETDATADISKCACHE
|
||||
|
||||
NS_IMETHOD Init(void) ;
|
||||
|
||||
nsNetDiskCache() ;
|
||||
virtual ~nsNetDiskCache() ;
|
||||
|
||||
protected:
|
||||
|
||||
NS_IMETHOD InitDB(void) ;
|
||||
NS_IMETHOD CreateDir(nsIFileSpec* dir_spec) ;
|
||||
NS_IMETHOD GetSpecialEntry(void) ;
|
||||
NS_IMETHOD SetSpecialEntry(void) ;
|
||||
|
||||
NS_IMETHOD RenameCacheSubDirs(void) ;
|
||||
NS_IMETHOD DBRecovery(void) ;
|
||||
NS_IMETHOD RemoveFolder(nsFileSpec aFolder) ;
|
||||
|
||||
private:
|
||||
|
||||
PRBool m_Enabled ;
|
||||
PRUint32 m_NumEntries ;
|
||||
nsCOMPtr<nsINetDataCache> m_pNextCache ;
|
||||
nsCOMPtr<nsIFileSpec> m_pDiskCacheFolder ;
|
||||
nsCOMPtr<nsIFileSpec> m_DBFile ;
|
||||
|
||||
PRUint32 m_MaxEntries ;
|
||||
PRUint32 m_StorageInUse ;
|
||||
nsIDBAccessor* m_DB ;
|
||||
|
||||
// this is used to indicate a db corruption
|
||||
PRBool m_DBCorrupted ;
|
||||
|
||||
friend class nsDiskCacheRecord ;
|
||||
friend class nsDiskCacheRecordChannel ;
|
||||
friend class nsDBEnumerator ;
|
||||
} ;
|
||||
|
||||
#endif /* __gen_nsNetDiskCache_h__ */
|
||||
32
mozilla/netwerk/cache/filecache/nsNetDiskCacheCID.h
vendored
Normal file
32
mozilla/netwerk/cache/filecache/nsNetDiskCacheCID.h
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* The contents of this file are subject to the Mozilla Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY 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 Intel Corp.
|
||||
* Portions created by Intel Corp. are
|
||||
* Copyright (C) 1999, 1999 Intel Corp. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s): Yixiong Zou <yixiong.zou@intel.com>
|
||||
* Carl Wong <carl.wong@intel.com>
|
||||
*/
|
||||
|
||||
#ifndef _nsNetDiskCacheCID_h_
|
||||
#define _nsNetDiskCacheCID_h_
|
||||
|
||||
#define NS_NETDISKCACHE_CID_STR "ECFEEA00-7201-11d3-87FE-000629D01344"
|
||||
|
||||
#define NS_NETDISKCACHE_CID \
|
||||
{ 0xecfeea00, 0x7201, 0x11d3, \
|
||||
{ 0x87, 0xfe, 0x0, 0x6, 0x29, 0xd0, 0x13, 0x44 }}
|
||||
|
||||
#endif /* _nsNetDiskCacheCID_h_ */
|
||||
50
mozilla/netwerk/cache/filecache/test/Makefile.in
vendored
Normal file
50
mozilla/netwerk/cache/filecache/test/Makefile.in
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
#
|
||||
# The contents of this file are subject to the Netscape Public License
|
||||
# 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) 1998 Netscape Communications Corporation. All Rights
|
||||
# Reserved.
|
||||
#
|
||||
|
||||
DEPTH = ../../../..
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
REQUIRES = libreg xpcom
|
||||
|
||||
CPPSRCS = \
|
||||
diskcache.cpp \
|
||||
$(NULL)
|
||||
|
||||
SIMPLE_PROGRAMS = $(CPPSRCS:.cpp=)
|
||||
|
||||
ifdef NO_LD_ARCHIVE_FLAGS
|
||||
LOST_SYM_LIBS = -lxpcomds_s -lxptinfo -lmozreg_s
|
||||
endif
|
||||
|
||||
LIBS = \
|
||||
-lmozjs \
|
||||
-lxpcom \
|
||||
-lmozdbm_s \
|
||||
$(MOZ_NECKO_UTIL_LIBS) \
|
||||
$(LOST_SYM_LIBS) \
|
||||
$(NSPR_LIBS) \
|
||||
$(NULL)
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
LOCAL_INCLUDES = -I$(srcdir)/..
|
||||
|
||||
DEFINES += -DUSE_NSREG -DCACHE
|
||||
836
mozilla/netwerk/cache/filecache/test/diskcache.cpp
vendored
Normal file
836
mozilla/netwerk/cache/filecache/test/diskcache.cpp
vendored
Normal file
@@ -0,0 +1,836 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* 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) 1998 Netscape Communications Corporation. All Rights
|
||||
* Reserved.
|
||||
*/
|
||||
|
||||
#include "nsIStreamListener.h"
|
||||
#include "nsIStreamObserver.h"
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsIInputStream.h"
|
||||
#include "nsIOutputStream.h"
|
||||
#include "nsIEventQueue.h"
|
||||
#include "nsIEventQueueService.h"
|
||||
#include "nsIChannel.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsString.h"
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "nsINetDataCache.h"
|
||||
#include "nsINetDataCacheRecord.h"
|
||||
//#include "nsMemCacheCID.h"
|
||||
#include "nsNetDiskCache.h"
|
||||
#include "nsIPref.h"
|
||||
#include "prenv.h"
|
||||
#include "nsIFileStream.h"
|
||||
|
||||
// Number of test entries to be placed in the cache
|
||||
#define NUM_CACHE_ENTRIES 250
|
||||
|
||||
// Cache content stream length will have random length between zero and
|
||||
// MAX_CONTENT_LENGTH bytes
|
||||
#define MAX_CONTENT_LENGTH 20000
|
||||
|
||||
// Length of random-data cache entry key
|
||||
#define CACHE_KEY_LENGTH 15
|
||||
|
||||
// Length of random-data cache entry meta-data
|
||||
#define CACHE_METADATA_LENGTH 100
|
||||
|
||||
//static NS_DEFINE_CID(kMemCacheCID, NS_MEM_CACHE_FACTORY_CID);
|
||||
static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID);
|
||||
static NS_DEFINE_CID(kDiskCacheCID, NS_NETDISKCACHE_CID) ;
|
||||
static NS_DEFINE_CID(kPrefCID, NS_PREF_CID);
|
||||
static NS_DEFINE_IID(kIPrefIID, NS_IPREF_IID);
|
||||
|
||||
// Mapping from test case number to RecordID
|
||||
static PRInt32 recordID[NUM_CACHE_ENTRIES];
|
||||
|
||||
static PRInt32
|
||||
mapRecordIdToTestNum(PRInt32 aRecordID)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < NUM_CACHE_ENTRIES; i++) {
|
||||
if (recordID[i] == aRecordID)
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
// A supply of stream data to either store or compare with
|
||||
class nsITestDataStream {
|
||||
public:
|
||||
virtual ~nsITestDataStream() {};
|
||||
virtual PRUint32 Next() = 0;
|
||||
virtual void Read(char* aBuf, PRUint32 aCount) = 0;
|
||||
|
||||
virtual PRBool Match(char* aBuf, PRUint32 aCount) = 0;
|
||||
virtual void Skip(PRUint32 aCount) = 0;
|
||||
};
|
||||
|
||||
// A reproducible stream of random data.
|
||||
class RandomStream : public nsITestDataStream {
|
||||
public:
|
||||
RandomStream(PRUint32 aSeed) {
|
||||
mStartSeed = mState = aSeed;
|
||||
}
|
||||
|
||||
PRUint32 GetStartSeed() {
|
||||
return mStartSeed;
|
||||
}
|
||||
|
||||
PRUint32 Next() {
|
||||
mState = 1103515245 * mState + 12345;
|
||||
return mState;
|
||||
}
|
||||
|
||||
void Read(char* aBuf, PRUint32 aCount) {
|
||||
PRUint32 i;
|
||||
for (i = 0; i < aCount; i++) {
|
||||
*aBuf++ = Next();
|
||||
}
|
||||
}
|
||||
|
||||
PRBool
|
||||
Match(char* aBuf, PRUint32 aCount) {
|
||||
PRUint32 i;
|
||||
for (i = 0; i < aCount; i++) {
|
||||
if (*aBuf++ != (char)(Next() & 0xff))
|
||||
return PR_FALSE;
|
||||
}
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
Skip(PRUint32 aCount) {
|
||||
while (aCount--)
|
||||
Next();
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
PRUint32 mState;
|
||||
PRUint32 mStartSeed;
|
||||
};
|
||||
|
||||
// A stream of data that increments on each byte that is read, modulo 256
|
||||
class CounterStream : public nsITestDataStream {
|
||||
public:
|
||||
CounterStream(PRUint32 aSeed) {
|
||||
mStartSeed = mState = aSeed;
|
||||
}
|
||||
|
||||
PRUint32 GetStartSeed() {
|
||||
return mStartSeed;
|
||||
}
|
||||
|
||||
PRUint32 Next() {
|
||||
mState += 1;
|
||||
mState &= 0xff;
|
||||
return mState;
|
||||
}
|
||||
|
||||
void Read(char* aBuf, PRUint32 aCount) {
|
||||
PRUint32 i;
|
||||
for (i = 0; i < aCount; i++) {
|
||||
*aBuf++ = Next();
|
||||
}
|
||||
}
|
||||
|
||||
PRBool
|
||||
Match(char* aBuf, PRUint32 aCount) {
|
||||
PRUint32 i;
|
||||
for (i = 0; i < aCount; i++) {
|
||||
if (*aBuf++ != (char)Next())
|
||||
return PR_FALSE;
|
||||
}
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
Skip(PRUint32 aCount) {
|
||||
mState += aCount;
|
||||
mState &= 0xff;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
PRUint32 mState;
|
||||
PRUint32 mStartSeed;
|
||||
};
|
||||
|
||||
static int gNumReaders = 0;
|
||||
static PRUint32 gTotalBytesRead = 0;
|
||||
static PRUint32 gTotalDuration = 0;
|
||||
|
||||
class nsReader : public nsIStreamListener {
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
nsReader()
|
||||
: mStartTime(0), mBytesRead(0)
|
||||
{
|
||||
NS_INIT_REFCNT();
|
||||
gNumReaders++;
|
||||
}
|
||||
|
||||
virtual ~nsReader() {
|
||||
delete mTestDataStream;
|
||||
gNumReaders--;
|
||||
}
|
||||
|
||||
nsresult
|
||||
Init(nsIChannel *aChannel, nsITestDataStream* aRandomStream, PRUint32 aExpectedStreamLength) {
|
||||
mChannel = aChannel;
|
||||
mTestDataStream = aRandomStream;
|
||||
mExpectedStreamLength = aExpectedStreamLength;
|
||||
mRefCnt = 1;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD OnStartRequest(nsIChannel* channel,
|
||||
nsISupports* context) {
|
||||
mStartTime = PR_IntervalNow();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD OnDataAvailable(nsIChannel* channel,
|
||||
nsISupports* context,
|
||||
nsIInputStream *aIStream,
|
||||
PRUint32 aSourceOffset,
|
||||
PRUint32 aLength) {
|
||||
char buf[1025];
|
||||
while (aLength > 0) {
|
||||
PRUint32 amt;
|
||||
PRBool match;
|
||||
aIStream->Read(buf, sizeof buf, &amt);
|
||||
if (amt == 0) break;
|
||||
aLength -= amt;
|
||||
mBytesRead += amt;
|
||||
match = mTestDataStream->Match(buf, amt);
|
||||
NS_ASSERTION(match, "Stored data was corrupted on read");
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD OnStopRequest(nsIChannel* channel,
|
||||
nsISupports* context,
|
||||
nsresult aStatus,
|
||||
const PRUnichar* aMsg) {
|
||||
PRIntervalTime endTime;
|
||||
PRIntervalTime duration;
|
||||
|
||||
endTime = PR_IntervalNow();
|
||||
duration = (endTime - mStartTime);
|
||||
|
||||
if (NS_FAILED(aStatus)) printf("channel failed.\n");
|
||||
// printf("read %d bytes\n", mBytesRead);
|
||||
|
||||
NS_ASSERTION(mBytesRead == mExpectedStreamLength,
|
||||
"Stream in cache is wrong length");
|
||||
|
||||
gTotalBytesRead += mBytesRead;
|
||||
gTotalDuration += duration;
|
||||
|
||||
// Release channel
|
||||
mChannel = 0;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
protected:
|
||||
PRIntervalTime mStartTime;
|
||||
PRUint32 mBytesRead;
|
||||
nsITestDataStream* mTestDataStream;
|
||||
PRUint32 mExpectedStreamLength;
|
||||
nsCOMPtr<nsIChannel> mChannel;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS2(nsReader, nsIStreamListener, nsIStreamObserver)
|
||||
|
||||
static nsIEventQueue* eventQueue;
|
||||
|
||||
nsresult
|
||||
InitQueue() {
|
||||
nsresult rv;
|
||||
|
||||
NS_WITH_SERVICE(nsIEventQueueService, eventQService, kEventQueueServiceCID, &rv);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get event queue service");
|
||||
|
||||
rv = eventQService->CreateThreadEventQueue();
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't create event queue");
|
||||
|
||||
rv = eventQService->GetThreadEventQueue(PR_CurrentThread(), &eventQueue);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get event queue for main thread");
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Process events until all streams are OnStopRequest'ed
|
||||
nsresult
|
||||
WaitForEvents() {
|
||||
while (gNumReaders) {
|
||||
eventQueue->ProcessPendingEvents();
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Read data for a single cache record and compare against testDataStream
|
||||
nsresult
|
||||
TestReadStream(nsINetDataCacheRecord *record, nsITestDataStream *testDataStream,
|
||||
PRUint32 expectedStreamLength)
|
||||
{
|
||||
nsCOMPtr<nsIChannel> channel;
|
||||
nsresult rv;
|
||||
PRUint32 actualContentLength;
|
||||
|
||||
rv = record->NewChannel(0, getter_AddRefs(channel));
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
|
||||
|
||||
rv = record->GetStoredContentLength(&actualContentLength);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
|
||||
NS_ASSERTION(actualContentLength == expectedStreamLength,
|
||||
"nsINetDataCacheRecord::GetContentLength() busted ?");
|
||||
|
||||
nsReader *reader = new nsReader;
|
||||
reader->AddRef();
|
||||
rv = reader->Init(channel, testDataStream, expectedStreamLength);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
|
||||
|
||||
rv = channel->AsyncRead(0, -1, 0, reader);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
|
||||
reader->Release();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Check that records can be retrieved using their record-ID, in addition
|
||||
// to using the opaque key.
|
||||
nsresult
|
||||
TestRecordID(nsINetDataCache *cache)
|
||||
{
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsINetDataCacheRecord> record;
|
||||
RandomStream *randomStream;
|
||||
PRUint32 metaDataLength;
|
||||
char cacheKey[CACHE_KEY_LENGTH];
|
||||
char *metaData;
|
||||
PRUint32 testNum;
|
||||
PRBool match;
|
||||
|
||||
for (testNum = 0; testNum < NUM_CACHE_ENTRIES; testNum++) {
|
||||
randomStream = new RandomStream(testNum);
|
||||
randomStream->Read(cacheKey, sizeof cacheKey);
|
||||
|
||||
rv = cache->GetCachedNetDataByID(recordID[testNum], getter_AddRefs(record));
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't obtain record using record ID");
|
||||
|
||||
// Match against previously stored meta-data
|
||||
rv = record->GetMetaData(&metaDataLength, &metaData);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get record meta-data");
|
||||
match = randomStream->Match(metaData, metaDataLength);
|
||||
NS_ASSERTION(match, "Meta-data corrupted or incorrect");
|
||||
|
||||
nsAllocator::Free(metaData);
|
||||
delete randomStream;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Check that all cache entries in the database are enumerated and that
|
||||
// no duplicates appear.
|
||||
nsresult
|
||||
TestEnumeration(nsINetDataCache *cache)
|
||||
{
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsINetDataCacheRecord> record;
|
||||
nsCOMPtr<nsISupports> tempISupports;
|
||||
nsCOMPtr<nsISimpleEnumerator> iterator;
|
||||
RandomStream *randomStream;
|
||||
PRUint32 metaDataLength;
|
||||
char cacheKey[CACHE_KEY_LENGTH];
|
||||
char *metaData;
|
||||
PRUint32 testNum;
|
||||
PRBool match;
|
||||
PRInt32 recID;
|
||||
|
||||
int numRecords = 0;
|
||||
|
||||
// Iterate over all records in the cache
|
||||
rv = cache->NewCacheEntryIterator(getter_AddRefs(iterator));
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't create new cache entry iterator");
|
||||
|
||||
PRBool notDone;
|
||||
while (1) {
|
||||
|
||||
// Done iterating ?
|
||||
rv = iterator->HasMoreElements(¬Done);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
if (!notDone)
|
||||
break;
|
||||
|
||||
// Get next record in iteration
|
||||
rv = iterator->GetNext(getter_AddRefs(tempISupports));
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "iterator bustage");
|
||||
record = do_QueryInterface(tempISupports);
|
||||
|
||||
numRecords++;
|
||||
|
||||
// Get record ID
|
||||
rv = record->GetRecordID(&recID);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get Record ID");
|
||||
testNum = mapRecordIdToTestNum(recID);
|
||||
NS_ASSERTION(testNum != -1, "Corrupted Record ID ?");
|
||||
|
||||
// Erase mapping from table, so that duplicate enumerations are detected
|
||||
recordID[testNum] = -1;
|
||||
|
||||
// Make sure stream matches test data
|
||||
randomStream = new RandomStream(testNum);
|
||||
randomStream->Read(cacheKey, sizeof cacheKey);
|
||||
|
||||
// Match against previously stored meta-data
|
||||
rv = record->GetMetaData(&metaDataLength, &metaData);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get record meta-data");
|
||||
match = randomStream->Match(metaData, metaDataLength);
|
||||
NS_ASSERTION(match, "Meta-data corrupted or incorrect");
|
||||
nsAllocator::Free(metaData);
|
||||
|
||||
delete randomStream;
|
||||
}
|
||||
|
||||
NS_ASSERTION(numRecords == NUM_CACHE_ENTRIES, "Iteration bug");
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Read the test data that was written in FillCache(), checking for
|
||||
// corruption, truncation.
|
||||
nsresult
|
||||
TestRead(nsINetDataCache *cache)
|
||||
{
|
||||
nsresult rv;
|
||||
PRBool inCache;
|
||||
nsCOMPtr<nsINetDataCacheRecord> record;
|
||||
RandomStream *randomStream;
|
||||
PRUint32 metaDataLength;
|
||||
char cacheKey[CACHE_KEY_LENGTH];
|
||||
char *metaData, *storedCacheKey;
|
||||
PRUint32 testNum, storedCacheKeyLength;
|
||||
PRBool match;
|
||||
|
||||
for (testNum = 0; testNum < NUM_CACHE_ENTRIES; testNum++) {
|
||||
randomStream = new RandomStream(testNum);
|
||||
randomStream->Read(cacheKey, sizeof cacheKey);
|
||||
|
||||
// Ensure that entry is in the cache
|
||||
rv = cache->Contains(cacheKey, sizeof cacheKey, &inCache);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
|
||||
NS_ASSERTION(inCache, "nsINetDataCache::Contains error");
|
||||
|
||||
rv = cache->GetCachedNetData(cacheKey, sizeof cacheKey, getter_AddRefs(record));
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
|
||||
|
||||
// Match against previously stored meta-data
|
||||
match = record->GetMetaData(&metaDataLength, &metaData);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
|
||||
match = randomStream->Match(metaData, metaDataLength);
|
||||
NS_ASSERTION(match, "Meta-data corrupted or incorrect");
|
||||
nsAllocator::Free(metaData);
|
||||
|
||||
// Test GetKey() method
|
||||
rv = record->GetKey(&storedCacheKeyLength, &storedCacheKey);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv) &&
|
||||
(storedCacheKeyLength == sizeof cacheKey) &&
|
||||
!memcmp(storedCacheKey, &cacheKey[0], sizeof cacheKey),
|
||||
"nsINetDataCacheRecord::GetKey failed");
|
||||
nsAllocator::Free(storedCacheKey);
|
||||
|
||||
PRUint32 expectedStreamLength = randomStream->Next() & 0xffff;
|
||||
|
||||
TestReadStream(record, randomStream, expectedStreamLength);
|
||||
}
|
||||
|
||||
WaitForEvents();
|
||||
|
||||
// Compute rate in MB/s
|
||||
double rate = gTotalBytesRead / PR_IntervalToMilliseconds(gTotalDuration);
|
||||
rate *= NUM_CACHE_ENTRIES;
|
||||
rate *= 1000;
|
||||
rate /= (1024 * 1024);
|
||||
printf("Read %d bytes at a rate of %5.1f MB per second \n",
|
||||
gTotalBytesRead, rate);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Repeatedly call SetStoredContentLength() on a cache entry and make
|
||||
// read the stream's data to ensure that it's not corrupted by the effect
|
||||
nsresult
|
||||
TestTruncation(nsINetDataCache *cache)
|
||||
{
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsINetDataCacheRecord> record;
|
||||
RandomStream *randomStream;
|
||||
char cacheKey[CACHE_KEY_LENGTH];
|
||||
|
||||
randomStream = new RandomStream(0);
|
||||
randomStream->Read(cacheKey, sizeof cacheKey);
|
||||
|
||||
rv = cache->GetCachedNetData(cacheKey, sizeof cacheKey, getter_AddRefs(record));
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
|
||||
|
||||
randomStream->Skip(CACHE_METADATA_LENGTH);
|
||||
PRUint32 initialStreamLength = randomStream->Next() & 0xffff;
|
||||
delete randomStream;
|
||||
|
||||
PRUint32 i;
|
||||
PRUint32 delta = initialStreamLength / 64;
|
||||
for (i = initialStreamLength; i >= delta; i -= delta) {
|
||||
PRUint32 expectedStreamLength = i;
|
||||
|
||||
// Do the truncation
|
||||
record->SetStoredContentLength(expectedStreamLength);
|
||||
randomStream = new RandomStream(0);
|
||||
randomStream->Skip(CACHE_KEY_LENGTH + CACHE_METADATA_LENGTH + 1);
|
||||
|
||||
TestReadStream(record, randomStream, expectedStreamLength);
|
||||
WaitForEvents();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Write known data to random offsets in a single cache entry and test
|
||||
// resulting stream for correctness.
|
||||
nsresult
|
||||
TestOffsetWrites(nsINetDataCache *cache)
|
||||
{
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsINetDataCacheRecord> record;
|
||||
nsCOMPtr<nsIChannel> channel;
|
||||
nsCOMPtr<nsIOutputStream> outStream;
|
||||
char buf[512];
|
||||
char cacheKey[CACHE_KEY_LENGTH];
|
||||
RandomStream *randomStream;
|
||||
|
||||
randomStream = new RandomStream(0);
|
||||
randomStream->Read(cacheKey, sizeof cacheKey);
|
||||
|
||||
rv = cache->GetCachedNetData(cacheKey, sizeof cacheKey, getter_AddRefs(record));
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't access record via opaque cache key");
|
||||
|
||||
|
||||
nsCOMPtr<nsIFileSpec> file ;
|
||||
record->GetFilename(getter_AddRefs(file)) ;
|
||||
char* name ;
|
||||
file->GetUnixStyleFilePath(&name) ;
|
||||
printf(" file name is %s \n", name) ;
|
||||
|
||||
// Write buffer-fulls of data at random offsets into the cache entry.
|
||||
// Data written is (offset % 0xff)
|
||||
PRUint32 startingOffset;
|
||||
PRUint32 streamLength = 0;
|
||||
PRUint32 len = 0 ;
|
||||
CounterStream *counterStream;
|
||||
|
||||
int i = 0;
|
||||
for (i = 0; i < 257; i++) {
|
||||
rv = record->NewChannel(0, getter_AddRefs(channel));
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
|
||||
|
||||
startingOffset = streamLength ? streamLength - (randomStream->Next() % sizeof buf): 0;
|
||||
rv = channel->OpenOutputStream(startingOffset, getter_AddRefs(outStream));
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
|
||||
|
||||
truncate(name, startingOffset) ;
|
||||
|
||||
counterStream = new CounterStream(startingOffset);
|
||||
counterStream->Read(buf, sizeof buf);
|
||||
|
||||
nsresult status ;
|
||||
nsCOMPtr<nsIRandomAccessStore> ras = do_QueryInterface(outStream, &status);
|
||||
if (NS_FAILED(status)) {
|
||||
// mState = END_WRITE;
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
PRIntn offset ;
|
||||
ras->Tell(&offset) ;
|
||||
// printf(" offset is %d \n", offset) ;
|
||||
|
||||
PRUint32 numWritten;
|
||||
rv = outStream->Write(buf, sizeof buf, &numWritten);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
|
||||
NS_ASSERTION(numWritten == sizeof buf, "Write() bug?");
|
||||
streamLength = startingOffset + sizeof buf;
|
||||
|
||||
rv = outStream->Close();
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't close channel");
|
||||
delete counterStream;
|
||||
|
||||
record->GetStoredContentLength(&len) ;
|
||||
if(len != streamLength)
|
||||
printf(" offset = %d is wrong, filesize = %d\n", startingOffset, len) ;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
rv = record->NewChannel(0, getter_AddRefs(channel));
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
|
||||
|
||||
startingOffset = 208;
|
||||
rv = channel->OpenOutputStream(startingOffset, getter_AddRefs(outStream));
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
|
||||
|
||||
counterStream = new CounterStream(startingOffset);
|
||||
counterStream->Read(buf, sizeof buf);
|
||||
|
||||
nsresult status ;
|
||||
nsCOMPtr<nsIRandomAccessStore> ras = do_QueryInterface(outStream, &status);
|
||||
if (NS_FAILED(status)) {
|
||||
// mState = END_WRITE;
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
PRIntn offset = 0 ;
|
||||
ras->Tell(&offset) ;
|
||||
printf(" offset is %d \n", offset) ;
|
||||
|
||||
PRUint32 numWritten;
|
||||
rv = outStream->Write(buf, sizeof buf, &numWritten);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
|
||||
NS_ASSERTION(numWritten == sizeof buf, "Write() bug?");
|
||||
streamLength = startingOffset + sizeof buf;
|
||||
|
||||
rv = outStream->Close();
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't close channel");
|
||||
delete counterStream;
|
||||
|
||||
record->GetStoredContentLength(&len) ;
|
||||
if(len != streamLength)
|
||||
printf(" offset = %d is wrong, filesize = %d\n", startingOffset, len) ;
|
||||
*/
|
||||
|
||||
delete randomStream;
|
||||
|
||||
counterStream = new CounterStream(0);
|
||||
TestReadStream(record, counterStream, streamLength);
|
||||
WaitForEvents();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Create entries in the network data cache, using random data for the
|
||||
// key, the meta-data and the stored content data.
|
||||
nsresult
|
||||
FillCache(nsINetDataCache *cache)
|
||||
{
|
||||
nsresult rv;
|
||||
PRBool inCache;
|
||||
nsCOMPtr<nsINetDataCacheRecord> record;
|
||||
nsCOMPtr<nsIChannel> channel;
|
||||
nsCOMPtr<nsIOutputStream> outStream;
|
||||
char buf[1000];
|
||||
PRUint32 metaDataLength;
|
||||
char cacheKey[CACHE_KEY_LENGTH];
|
||||
char metaData[CACHE_METADATA_LENGTH];
|
||||
PRUint32 testNum;
|
||||
char *data;
|
||||
RandomStream *randomStream;
|
||||
|
||||
PRIntervalTime startTime = PR_IntervalNow();
|
||||
|
||||
for (testNum = 0; testNum < NUM_CACHE_ENTRIES; testNum++) {
|
||||
randomStream = new RandomStream(testNum);
|
||||
randomStream->Read(cacheKey, sizeof cacheKey);
|
||||
|
||||
// No entry should be in cache until we add it
|
||||
rv = cache->Contains(cacheKey, sizeof cacheKey, &inCache);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
|
||||
NS_ASSERTION(!inCache, "nsINetDataCache::Contains error");
|
||||
|
||||
rv = cache->GetCachedNetData(cacheKey, sizeof cacheKey, getter_AddRefs(record));
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't access record via opaque cache key");
|
||||
|
||||
// Test nsINetDataCacheRecord::GetRecordID()
|
||||
rv = record->GetRecordID(&recordID[testNum]);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get Record ID");
|
||||
|
||||
// Test nsINetDataCache::GetNumEntries()
|
||||
PRUint32 numEntries = (PRUint32)-1;
|
||||
rv = cache->GetNumEntries(&numEntries);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get number of cache entries");
|
||||
NS_ASSERTION(numEntries == testNum + 1, "GetNumEntries failure");
|
||||
|
||||
// Record meta-data should be initially empty
|
||||
rv = record->GetMetaData(&metaDataLength, &data);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
|
||||
if ((metaDataLength != 0) || (data != 0))
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
// Store random data as meta-data
|
||||
randomStream->Read(metaData, sizeof metaData);
|
||||
record->SetMetaData(sizeof metaData, metaData);
|
||||
|
||||
rv = record->NewChannel(0, getter_AddRefs(channel));
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
|
||||
|
||||
rv = channel->OpenOutputStream(0, getter_AddRefs(outStream));
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
|
||||
|
||||
PRUint32 beforeOccupancy;
|
||||
rv = cache->GetStorageInUse(&beforeOccupancy);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get cache occupancy");
|
||||
|
||||
int streamLength = randomStream->Next() & 0xffff;
|
||||
int remaining = streamLength;
|
||||
while (remaining) {
|
||||
PRUint32 numWritten;
|
||||
int amount = PR_MIN(sizeof buf, remaining);
|
||||
randomStream->Read(buf, amount);
|
||||
|
||||
rv = outStream->Write(buf, amount, &numWritten);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
|
||||
NS_ASSERTION(numWritten == (PRUint32)amount, "Write() bug?");
|
||||
|
||||
remaining -= amount;
|
||||
}
|
||||
outStream->Close();
|
||||
|
||||
PRUint32 afterOccupancy;
|
||||
rv = cache->GetStorageInUse(&afterOccupancy);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get cache occupancy");
|
||||
PRUint32 streamLengthInKB = streamLength >> 10;
|
||||
NS_ASSERTION((afterOccupancy - beforeOccupancy) >= streamLengthInKB,
|
||||
"nsINetDataCache::GetStorageInUse() is busted");
|
||||
|
||||
|
||||
// *Now* there should be an entry in the cache
|
||||
rv = cache->Contains(cacheKey, sizeof cacheKey, &inCache);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
|
||||
NS_ASSERTION(inCache, "nsINetDataCache::Contains error");
|
||||
|
||||
delete randomStream;
|
||||
}
|
||||
|
||||
PRIntervalTime endTime = PR_IntervalNow();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult NS_AutoregisterComponents()
|
||||
{
|
||||
nsresult rv = nsComponentManager::AutoRegister(nsIComponentManager::NS_Startup,
|
||||
NULL /* default */);
|
||||
return rv;
|
||||
}
|
||||
|
||||
PRBool initPref ()
|
||||
{
|
||||
nsresult rv;
|
||||
NS_WITH_SERVICE(nsIPref, prefPtr, kPrefCID, &rv);
|
||||
if (NS_FAILED(rv))
|
||||
return false;
|
||||
|
||||
nsCOMPtr<nsIFileSpec> fileSpec;
|
||||
rv = NS_NewFileSpec (getter_AddRefs(fileSpec));
|
||||
if (NS_FAILED(rv))
|
||||
return false;
|
||||
|
||||
nsCString defaultPrefFile = PR_GetEnv ("MOZILLA_FIVE_HOME");
|
||||
if (defaultPrefFile.Length())
|
||||
defaultPrefFile += "/";
|
||||
else
|
||||
defaultPrefFile = "./";
|
||||
defaultPrefFile += "default_prefs.js";
|
||||
|
||||
fileSpec->SetUnixStyleFilePath (defaultPrefFile.GetBuffer());
|
||||
|
||||
PRBool exists = false;
|
||||
fileSpec->Exists(&exists);
|
||||
if (exists)
|
||||
prefPtr->ReadUserPrefsFrom(fileSpec);
|
||||
else
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char* argv[])
|
||||
{
|
||||
initPref() ;
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsINetDataCache> cache;
|
||||
|
||||
rv = NS_AutoregisterComponents();
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't register XPCOM components");
|
||||
|
||||
rv = nsComponentManager::CreateInstance(kDiskCacheCID, nsnull,
|
||||
NS_GET_IID(nsINetDataCache),
|
||||
getter_AddRefs(cache));
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't create memory cache factory");
|
||||
|
||||
InitQueue();
|
||||
|
||||
PRUnichar* description;
|
||||
rv = cache->GetDescription(&description);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get cache description");
|
||||
nsCAutoString descStr(description);
|
||||
printf("Testing: %s\n", descStr.GetBuffer());
|
||||
|
||||
rv = cache->RemoveAll();
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't clear cache");
|
||||
|
||||
PRUint32 startOccupancy;
|
||||
rv = cache->GetStorageInUse(&startOccupancy);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get cache occupancy");
|
||||
|
||||
PRUint32 numEntries = (PRUint32)-1;
|
||||
rv = cache->GetNumEntries(&numEntries);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get number of cache entries");
|
||||
NS_ASSERTION(numEntries == 0, "Couldn't clear cache");
|
||||
|
||||
rv = FillCache(cache);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't fill cache with random test data");
|
||||
|
||||
rv = TestRead(cache);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't read random test data from cache");
|
||||
|
||||
rv = TestRecordID(cache);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't index records using record ID");
|
||||
|
||||
rv = TestEnumeration(cache);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't successfully enumerate records");
|
||||
|
||||
rv = TestTruncation(cache);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't successfully truncate records");
|
||||
|
||||
rv = TestOffsetWrites(cache);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't successfully write to records using non-zero offsets");
|
||||
|
||||
rv = cache->RemoveAll();
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't clear cache");
|
||||
rv = cache->GetNumEntries(&numEntries);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get number of cache entries");
|
||||
NS_ASSERTION(numEntries == 0, "Couldn't clear cache");
|
||||
|
||||
PRUint32 endOccupancy;
|
||||
rv = cache->GetStorageInUse(&endOccupancy);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get cache occupancy");
|
||||
|
||||
NS_ASSERTION(startOccupancy == endOccupancy, "Cache occupancy not correctly computed ?");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
48
mozilla/netwerk/cache/memcache/Makefile.in
vendored
Normal file
48
mozilla/netwerk/cache/memcache/Makefile.in
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
# Generated automatically from Makefile.in by configure.
|
||||
#
|
||||
# The contents of this file are subject to the Netscape Public License
|
||||
# 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) 1998 Netscape Communications Corporation. All Rights
|
||||
# Reserved.
|
||||
#
|
||||
|
||||
DEPTH = ../../..
|
||||
topsrcdir = @top_srcdir@
|
||||
VPATH = @srcdir@
|
||||
srcdir = @srcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
MODULE = nkcache
|
||||
|
||||
LIBRARY_NAME = nkmemcache_s
|
||||
|
||||
REQUIRES = nspr dbm
|
||||
|
||||
EXPORTS=nsMemCacheCID.h \
|
||||
nsMemCache.h \
|
||||
$(NULL)
|
||||
|
||||
CPPSRCS = \
|
||||
nsMemCache.cpp \
|
||||
nsMemCacheRecord.cpp \
|
||||
nsMemCacheChannel.cpp \
|
||||
$(NULL)
|
||||
|
||||
# we don't want the shared lib, but we want to force the creation of a
|
||||
# static lib.
|
||||
override NO_SHARED_LIB=1
|
||||
override NO_STATIC_LIB=
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
42
mozilla/netwerk/cache/memcache/makefile.win
vendored
Normal file
42
mozilla/netwerk/cache/memcache/makefile.win
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
#!nmake
|
||||
#
|
||||
# The contents of this file are subject to the Netscape Public License
|
||||
# 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) 1998 Netscape Communications Corporation. All Rights
|
||||
# Reserved.
|
||||
|
||||
DEPTH=..\..\..
|
||||
|
||||
include <$(DEPTH)/config/config.mak>
|
||||
|
||||
MODULE = nkcache
|
||||
|
||||
LIBRARY_NAME = nkmemcache_s
|
||||
|
||||
CPP_OBJS = \
|
||||
.\$(OBJDIR)\nsMemCache.obj \
|
||||
.\$(OBJDIR)\nsMemCacheRecord.obj \
|
||||
.\$(OBJDIR)\nsMemCacheChannel.obj \
|
||||
$(NULL)
|
||||
|
||||
EXPORTS=nsMemCacheCID.h
|
||||
|
||||
include <$(DEPTH)\config\rules.mak>
|
||||
|
||||
install:: $(LIBRARY)
|
||||
$(MAKE_INSTALL) $(LIBRARY) $(DIST)\lib
|
||||
|
||||
clobber::
|
||||
rm -rf $(OBJDIR)
|
||||
rm -f $(DIST)\lib\$(LIBRARY_NAME).lib
|
||||
|
||||
334
mozilla/netwerk/cache/memcache/nsMemCache.cpp
vendored
Normal file
334
mozilla/netwerk/cache/memcache/nsMemCache.cpp
vendored
Normal file
@@ -0,0 +1,334 @@
|
||||
/* -*- Mode: C++; tab-width: 4; 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 Communicator client code, released
|
||||
* March 31, 1998.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998-1999 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* nsMemCache is the implementation of an in-memory network-data
|
||||
* cache, used to cache the responses to network retrieval commands.
|
||||
* Each cache entry may contain both content, e.g. GIF image data, and
|
||||
* associated metadata, e.g. HTTP headers. Each entry is indexed by
|
||||
* two different keys: a record id number and an opaque key, which is
|
||||
* created by the cache manager by combining the URI with a "secondary
|
||||
* key", e.g. HTTP post data.
|
||||
*/
|
||||
|
||||
#include "nsMemCache.h"
|
||||
#include "nsMemCacheRecord.h"
|
||||
#include "nsIGenericFactory.h"
|
||||
#include "nsString.h"
|
||||
#include "nsHashtable.h"
|
||||
#include "nsHashtableEnumerator.h"
|
||||
#include "nsEnumeratorUtils.h"
|
||||
|
||||
PRInt32 nsMemCache::gRecordSerialNumber = 0;
|
||||
|
||||
nsMemCache::nsMemCache()
|
||||
: mNumEntries(0), mOccupancy(0), mEnabled(PR_TRUE),
|
||||
mHashTable(0)
|
||||
{
|
||||
NS_INIT_REFCNT();
|
||||
}
|
||||
|
||||
nsMemCache::~nsMemCache()
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
rv = RemoveAll();
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv) && (mNumEntries == 0),
|
||||
"Failure to shut down memory cache. "
|
||||
"Somewhere, someone is holding references to at least one cache record");
|
||||
delete mHashTable;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsMemCache::Init()
|
||||
{
|
||||
mHashTable = new nsHashtable(256);
|
||||
if (!mHashTable)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsMemCache, NS_GET_IID(nsINetDataCache))
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMemCache::GetDescription(PRUnichar * *aDescription)
|
||||
{
|
||||
nsAutoString description("Memory Cache");
|
||||
*aDescription = description.ToNewUnicode();
|
||||
if (!*aDescription)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMemCache::Contains(const char *aKey, PRUint32 aKeyLength, PRBool *aFound)
|
||||
{
|
||||
nsOpaqueKey *opaqueKey = new nsOpaqueKey(aKey, aKeyLength);
|
||||
if (!opaqueKey)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
*aFound = mHashTable->Exists(opaqueKey);
|
||||
delete opaqueKey;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMemCache::GetCachedNetData(const char *aKey, PRUint32 aKeyLength,
|
||||
nsINetDataCacheRecord* *aRecord)
|
||||
{
|
||||
nsresult rv;
|
||||
nsMemCacheRecord* record = 0;
|
||||
nsOpaqueKey *opaqueKey2 = 0;
|
||||
nsOpaqueKey *opaqueKey3 = 0;
|
||||
nsOpaqueKey *opaqueKey;
|
||||
|
||||
opaqueKey = new nsOpaqueKey(aKey, aKeyLength);
|
||||
if (!opaqueKey)
|
||||
goto out_of_memory;
|
||||
record = (nsMemCacheRecord*)mHashTable->Get(opaqueKey);
|
||||
delete opaqueKey;
|
||||
|
||||
// No existing cache database entry was found. Create a new one.
|
||||
// This requires two mappings in the hash table:
|
||||
// Record ID ==> record
|
||||
// Opaque key ==> record
|
||||
if (!record) {
|
||||
record = new nsMemCacheRecord;
|
||||
if (!record)
|
||||
goto out_of_memory;
|
||||
rv = record->Init(aKey, aKeyLength, ++gRecordSerialNumber, this);
|
||||
if (NS_FAILED(rv)) goto out_of_memory;
|
||||
|
||||
// Index the record by opaque key
|
||||
opaqueKey2 = new nsOpaqueKey(record->mKey, record->mKeyLength);
|
||||
if (!opaqueKey2) goto out_of_memory;
|
||||
mHashTable->Put(opaqueKey2, record);
|
||||
|
||||
// Index the record by it's record ID
|
||||
char *recordIDbytes = NS_REINTERPRET_CAST(char *, &record->mRecordID);
|
||||
opaqueKey3 = new nsOpaqueKey(recordIDbytes,
|
||||
sizeof record->mRecordID);
|
||||
if (!opaqueKey3) {
|
||||
// Clean up the first record from the hash table
|
||||
mHashTable->Remove(opaqueKey);
|
||||
goto out_of_memory;
|
||||
}
|
||||
mHashTable->Put(opaqueKey3, record);
|
||||
|
||||
// The hash table holds on to the record
|
||||
record->AddRef();
|
||||
|
||||
delete opaqueKey2;
|
||||
delete opaqueKey3;
|
||||
mNumEntries++;
|
||||
}
|
||||
|
||||
record->AddRef();
|
||||
*aRecord = record;
|
||||
return NS_OK;
|
||||
|
||||
out_of_memory:
|
||||
delete opaqueKey2;
|
||||
delete opaqueKey3;
|
||||
delete record;
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMemCache::GetCachedNetDataByID(PRInt32 RecordID,
|
||||
nsINetDataCacheRecord* *aRecord)
|
||||
{
|
||||
nsOpaqueKey opaqueKey(NS_REINTERPRET_CAST(const char *, &RecordID),
|
||||
sizeof RecordID);
|
||||
*aRecord = (nsINetDataCacheRecord*)mHashTable->Get(&opaqueKey);
|
||||
if (*aRecord) {
|
||||
NS_ADDREF(*aRecord);
|
||||
return NS_OK;
|
||||
}
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_METHOD
|
||||
nsMemCache::Delete(nsMemCacheRecord* aRecord)
|
||||
{
|
||||
nsMemCacheRecord *removedRecord;
|
||||
|
||||
char *recordIDbytes = NS_REINTERPRET_CAST(char *, &aRecord->mRecordID);
|
||||
nsOpaqueKey opaqueRecordIDKey(recordIDbytes,
|
||||
sizeof aRecord->mRecordID);
|
||||
removedRecord = (nsMemCacheRecord*)mHashTable->Remove(&opaqueRecordIDKey);
|
||||
NS_ASSERTION(removedRecord == aRecord, "memory cache database inconsistent");
|
||||
|
||||
nsOpaqueKey opaqueKey(aRecord->mKey, aRecord->mKeyLength);
|
||||
removedRecord = (nsMemCacheRecord*)mHashTable->Remove(&opaqueKey);
|
||||
NS_ASSERTION(removedRecord == aRecord, "memory cache database inconsistent");
|
||||
|
||||
aRecord->Release();
|
||||
|
||||
mNumEntries--;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMemCache::GetEnabled(PRBool *aEnabled)
|
||||
{
|
||||
NS_ENSURE_ARG(aEnabled);
|
||||
*aEnabled = mEnabled;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMemCache::SetEnabled(PRBool aEnabled)
|
||||
{
|
||||
mEnabled = aEnabled;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMemCache::GetFlags(PRUint32 *aFlags)
|
||||
{
|
||||
NS_ENSURE_ARG(aFlags);
|
||||
*aFlags = MEMORY_CACHE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMemCache::GetNumEntries(PRUint32 *aNumEntries)
|
||||
{
|
||||
NS_ENSURE_ARG(aNumEntries);
|
||||
*aNumEntries = mNumEntries;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMemCache::GetMaxEntries(PRUint32 *aMaxEntries)
|
||||
{
|
||||
NS_ENSURE_ARG(aMaxEntries);
|
||||
*aMaxEntries = MEM_CACHE_MAX_ENTRIES;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
static NS_METHOD
|
||||
HashEntryConverter(nsHashKey *aKey, void *aValue,
|
||||
void *unused, nsISupports **retval)
|
||||
{
|
||||
nsMemCacheRecord *record;
|
||||
nsOpaqueKey *opaqueKey;
|
||||
|
||||
record = (nsMemCacheRecord*)aValue;
|
||||
opaqueKey = (nsOpaqueKey*)aKey;
|
||||
|
||||
// Hash table keys that index cache entries by their record ID
|
||||
// shouldn't be enumerated.
|
||||
if ((opaqueKey->GetKeyLength() == sizeof(PRInt32))) {
|
||||
|
||||
#ifdef DEBUG
|
||||
PRInt32 recordID;
|
||||
record->GetRecordID(&recordID);
|
||||
NS_ASSERTION(*((PRInt32*)opaqueKey->GetKey()) == recordID,
|
||||
"Key has incorrect key length");
|
||||
#endif
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_IF_ADDREF(record);
|
||||
*retval = NS_STATIC_CAST(nsISupports*, record);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMemCache::NewCacheEntryIterator(nsISimpleEnumerator* *aIterator)
|
||||
{
|
||||
nsCOMPtr<nsIEnumerator> iterator;
|
||||
|
||||
NS_ENSURE_ARG(aIterator);
|
||||
NS_NewHashtableEnumerator(mHashTable, HashEntryConverter,
|
||||
mHashTable, getter_AddRefs(iterator));
|
||||
return NS_NewAdapterEnumerator(aIterator, iterator);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMemCache::GetNextCache(nsINetDataCache* *aNextCache)
|
||||
{
|
||||
NS_ENSURE_ARG(aNextCache);
|
||||
*aNextCache = mNextCache;
|
||||
NS_ADDREF(*aNextCache);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMemCache::SetNextCache(nsINetDataCache* aNextCache)
|
||||
{
|
||||
mNextCache = aNextCache;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMemCache::GetStorageInUse(PRUint32 *aStorageInUse)
|
||||
{
|
||||
NS_ENSURE_ARG(aStorageInUse);
|
||||
|
||||
// Convert from bytes to KB
|
||||
*aStorageInUse = (mOccupancy >> 10);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMemCache::RemoveAll(void)
|
||||
{
|
||||
PRBool failed;
|
||||
|
||||
nsCOMPtr<nsISimpleEnumerator> iterator;
|
||||
nsCOMPtr<nsISupports> recordSupports;
|
||||
nsCOMPtr<nsINetDataCacheRecord> record;
|
||||
nsresult rv;
|
||||
|
||||
failed = PR_FALSE;
|
||||
rv = NewCacheEntryIterator(getter_AddRefs(iterator));
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
PRBool notDone;
|
||||
while (1) {
|
||||
rv = iterator->HasMoreElements(¬Done);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
if (!notDone)
|
||||
break;
|
||||
|
||||
iterator->GetNext(getter_AddRefs(recordSupports));
|
||||
record = do_QueryInterface(recordSupports);
|
||||
recordSupports = 0;
|
||||
|
||||
PRUint32 bytesUsed;
|
||||
record->GetStoredContentLength(&bytesUsed);
|
||||
rv = record->Delete();
|
||||
if (NS_FAILED(rv)) {
|
||||
failed = PR_TRUE;
|
||||
continue;
|
||||
}
|
||||
mOccupancy -= bytesUsed;
|
||||
}
|
||||
|
||||
if (failed)
|
||||
return NS_ERROR_FAILURE;
|
||||
return NS_OK;
|
||||
}
|
||||
83
mozilla/netwerk/cache/memcache/nsMemCache.h
vendored
Normal file
83
mozilla/netwerk/cache/memcache/nsMemCache.h
vendored
Normal file
@@ -0,0 +1,83 @@
|
||||
/* -*- Mode: C++; tab-width: 4; 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 Communicator client code, released
|
||||
* March 31, 1998.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998-1999 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* nsMemCache is the implementation of an in-memory network-data
|
||||
* cache, used to cache the responses to network retrieval commands.
|
||||
* Each cache entry may contain both content, e.g. GIF image data, and
|
||||
* associated metadata, e.g. HTTP headers. Each entry is indexed by
|
||||
* two different keys: a record id number and an opaque key, which is
|
||||
* created by the cache manager by combining the URI with a "secondary
|
||||
* key", e.g. HTTP post data.
|
||||
*/
|
||||
|
||||
#ifndef _nsMemCache_h_
|
||||
#define _nsMemCache_h_
|
||||
|
||||
#include "nsINetDataCache.h"
|
||||
|
||||
// Maximum number of URIs that may be resident in the cache
|
||||
#define MEM_CACHE_MAX_ENTRIES 1000
|
||||
|
||||
#define MEM_CACHE_SEGMENT_SIZE (1 << 12)
|
||||
#define MEM_CACHE_MAX_ENTRY_SIZE (1 << 20)
|
||||
|
||||
class nsHashtable;
|
||||
class nsMemCacheRecord;
|
||||
|
||||
class nsMemCache : public nsINetDataCache
|
||||
{
|
||||
public:
|
||||
nsMemCache();
|
||||
virtual ~nsMemCache();
|
||||
nsresult Init();
|
||||
|
||||
// nsISupports methods
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
// nsINetDataCache methods
|
||||
NS_DECL_NSINETDATACACHE
|
||||
|
||||
// Factory
|
||||
static NS_METHOD nsMemCacheConstructor(nsISupports *aOuter, REFNSIID aIID,
|
||||
void **aResult);
|
||||
|
||||
protected:
|
||||
|
||||
PRUint32 mNumEntries;
|
||||
PRUint32 mOccupancy; // Memory used, in bytes
|
||||
PRBool mEnabled; // If false, bypass mem cache
|
||||
|
||||
nsINetDataCache* mNextCache;
|
||||
|
||||
// Mapping from either opaque key or record ID to nsMemCacheRecord
|
||||
nsHashtable* mHashTable;
|
||||
|
||||
// Used to assign record ID's
|
||||
static PRInt32 gRecordSerialNumber;
|
||||
|
||||
NS_METHOD Delete(nsMemCacheRecord* aRecord);
|
||||
|
||||
friend class nsMemCacheRecord;
|
||||
friend class nsMemCacheChannel;
|
||||
};
|
||||
|
||||
#endif // _nsMemCache_h_
|
||||
36
mozilla/netwerk/cache/memcache/nsMemCacheCID.h
vendored
Normal file
36
mozilla/netwerk/cache/memcache/nsMemCacheCID.h
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
/* -*- Mode: C++; tab-width: 4; 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 Communicator client code, released
|
||||
* March 31, 1998.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998-1999 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
*/
|
||||
|
||||
// XPCOM Class ID for the network data in-memory cache
|
||||
|
||||
#ifndef nsMEMCACHECID_h__
|
||||
#define nsMEMCACHECID_h__
|
||||
|
||||
// {e4710560-7de2-11d3-90cb-0040056a906e}
|
||||
#define NS_MEM_CACHE_FACTORY_CID \
|
||||
{ \
|
||||
0xe4710560, \
|
||||
0x7de2, \
|
||||
0x11d3, \
|
||||
{0x90, 0xcb, 0x00, 0x40, 0x05, 0x6a, 0x90, 0x6e} \
|
||||
}
|
||||
|
||||
#endif // nsMEMCACHECID_h__
|
||||
462
mozilla/netwerk/cache/memcache/nsMemCacheChannel.cpp
vendored
Normal file
462
mozilla/netwerk/cache/memcache/nsMemCacheChannel.cpp
vendored
Normal file
@@ -0,0 +1,462 @@
|
||||
/* -*- Mode: C++; tab-width: 4; 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 Communicator client code, released
|
||||
* March 31, 1998.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998-1999 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "nsMemCache.h"
|
||||
#include "nsMemCacheChannel.h"
|
||||
#include "nsIStreamListener.h"
|
||||
#include "nsIChannel.h"
|
||||
#include "nsIStorageStream.h"
|
||||
#include "nsIOutputStream.h"
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsIEventQueueService.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsILoadGroup.h"
|
||||
|
||||
static NS_DEFINE_CID(kIOServiceCID, NS_IOSERVICE_CID);
|
||||
static NS_DEFINE_CID(kEventQueueService, NS_EVENTQUEUESERVICE_CID);
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsMemCacheChannel, NS_GET_IID(nsIChannel))
|
||||
|
||||
void
|
||||
nsMemCacheChannel::NotifyStorageInUse(PRInt32 aBytesUsed)
|
||||
{
|
||||
mRecord->mCache->mOccupancy += aBytesUsed;
|
||||
}
|
||||
|
||||
/**
|
||||
* This class acts as an adaptor around a synchronous input stream to add async
|
||||
* read capabilities. It adds methods for initiating, suspending, resuming and
|
||||
* cancelling async reads.
|
||||
*/
|
||||
class AsyncReadStreamAdaptor : public nsIInputStream {
|
||||
public:
|
||||
AsyncReadStreamAdaptor(nsMemCacheChannel* aChannel, nsIInputStream *aSyncStream):
|
||||
mSyncStream(aSyncStream), mDataAvailCursor(0),
|
||||
mRemaining(0), mAvailable(0), mChannel(aChannel), mAborted(PR_FALSE), mSuspended(PR_FALSE)
|
||||
{
|
||||
NS_INIT_REFCNT();
|
||||
NS_ADDREF(mChannel);
|
||||
}
|
||||
|
||||
virtual ~AsyncReadStreamAdaptor() {
|
||||
mChannel->mAsyncReadStream = 0;
|
||||
NS_RELEASE(mChannel);
|
||||
}
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
nsresult
|
||||
IsPending(PRBool* aIsPending) {
|
||||
*aIsPending = (mRemaining != 0) && !mAborted;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
Cancel(void) {
|
||||
mAborted = PR_TRUE;
|
||||
return mStreamListener->OnStopRequest(mChannel, mContext, NS_BINDING_ABORTED, nsnull);
|
||||
}
|
||||
|
||||
nsresult
|
||||
Suspend(void) { mSuspended = PR_TRUE; return NS_OK; }
|
||||
|
||||
nsresult
|
||||
Resume(void) {
|
||||
if (!mSuspended)
|
||||
return NS_ERROR_FAILURE;
|
||||
mSuspended = PR_FALSE;
|
||||
return NextListenerEvent();
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
Available(PRUint32 *aNumBytes) { return mAvailable; }
|
||||
|
||||
NS_IMETHOD
|
||||
Read(char* aBuf, PRUint32 aCount, PRUint32 *aBytesRead) {
|
||||
if (mAborted)
|
||||
return NS_ERROR_ABORT;
|
||||
|
||||
*aBytesRead = 0;
|
||||
aCount = PR_MIN(aCount, mAvailable);
|
||||
nsresult rv = mSyncStream->Read(aBuf, aCount, aBytesRead);
|
||||
mAvailable -= *aBytesRead;
|
||||
|
||||
if (NS_FAILED(rv) && (rv != NS_BASE_STREAM_WOULD_BLOCK)) {
|
||||
Fail();
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (!mSuspended && !mAvailable) {
|
||||
rv = NextListenerEvent();
|
||||
if (NS_FAILED(rv)) {
|
||||
Fail();
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
Close() {
|
||||
nsresult rv = mSyncStream->Close();
|
||||
mSyncStream = 0;
|
||||
mContext = 0;
|
||||
mStreamListener = 0;
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult
|
||||
AsyncRead(PRUint32 aStartPosition, PRInt32 aReadCount,
|
||||
nsISupports* aContext, nsIStreamListener* aListener) {
|
||||
|
||||
nsresult rv;
|
||||
nsIEventQueue *eventQ;
|
||||
|
||||
mContext = aContext;
|
||||
mStreamListener = aListener;
|
||||
mRemaining = aReadCount;
|
||||
|
||||
NS_WITH_SERVICE(nsIIOService, serv, kIOServiceCID, &rv);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
NS_WITH_SERVICE(nsIEventQueueService, eventQService, kEventQueueService, &rv);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
rv = eventQService->GetThreadEventQueue(PR_CurrentThread(), &eventQ);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
rv = NS_NewAsyncStreamListener(aListener, eventQ,
|
||||
getter_AddRefs(mStreamListener));
|
||||
NS_RELEASE(eventQ);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
rv = mStreamListener->OnStartRequest(mChannel, aContext);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
return NextListenerEvent();
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
nsresult
|
||||
Fail(void) {
|
||||
mAborted = PR_TRUE;
|
||||
return mStreamListener->OnStopRequest(mChannel, mContext, NS_BINDING_FAILED, nsnull);
|
||||
}
|
||||
|
||||
nsresult
|
||||
NextListenerEvent() {
|
||||
PRUint32 available;
|
||||
nsresult rv = mSyncStream->Available(&available);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
available -= mAvailable;
|
||||
available = PR_MIN(available, mRemaining);
|
||||
|
||||
if (available) {
|
||||
PRUint32 size = PR_MIN(available, MEM_CACHE_SEGMENT_SIZE);
|
||||
rv = mStreamListener->OnDataAvailable(mChannel, mContext, this,
|
||||
mDataAvailCursor, size);
|
||||
mDataAvailCursor += size;
|
||||
mRemaining -= size;
|
||||
mAvailable += size;
|
||||
return rv;
|
||||
} else {
|
||||
rv = mStreamListener->OnStopRequest(mChannel, mContext, NS_OK, nsnull);
|
||||
AsyncReadStreamAdaptor* thisAlias = this;
|
||||
NS_RELEASE(thisAlias);
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
nsCOMPtr<nsISupports> mContext; // Opaque context passed to AsyncRead()
|
||||
nsCOMPtr<nsIStreamListener> mStreamListener; // Stream listener that has been proxied
|
||||
nsCOMPtr<nsIInputStream> mSyncStream; // Underlying synchronous stream that is
|
||||
// being converted to an async stream
|
||||
PRUint32 mDataAvailCursor;
|
||||
PRUint32 mRemaining; // Size of AsyncRead request less bytes for
|
||||
// consumer OnDataAvailable's that were fired
|
||||
PRUint32 mAvailable; // Number of bytes for which OnDataAvailable fired
|
||||
nsMemCacheChannel* mChannel; // Associated memory cache channel, strong link
|
||||
// but can not use nsCOMPtr
|
||||
PRBool mAborted; // Abort() has been called
|
||||
PRBool mSuspended; // Suspend() has been called
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(AsyncReadStreamAdaptor, NS_GET_IID(nsIInputStream))
|
||||
|
||||
// The only purpose of this output stream wrapper is to adjust the cache's
|
||||
// overall occupancy as new data flows into the cache entry.
|
||||
class MemCacheWriteStreamWrapper : public nsIOutputStream {
|
||||
public:
|
||||
MemCacheWriteStreamWrapper(nsMemCacheChannel* aChannel, nsIOutputStream *aBaseStream):
|
||||
mBaseStream(aBaseStream), mChannel(aChannel)
|
||||
{
|
||||
NS_INIT_REFCNT();
|
||||
NS_ADDREF(mChannel);
|
||||
}
|
||||
|
||||
virtual ~MemCacheWriteStreamWrapper() { NS_RELEASE(mChannel); };
|
||||
|
||||
static nsresult
|
||||
Create(nsMemCacheChannel* aChannel, nsIOutputStream *aBaseStream, nsIOutputStream* *aWrapper) {
|
||||
MemCacheWriteStreamWrapper *wrapper =
|
||||
new MemCacheWriteStreamWrapper(aChannel, aBaseStream);
|
||||
if (!wrapper) return NS_ERROR_OUT_OF_MEMORY;
|
||||
NS_ADDREF(wrapper);
|
||||
*aWrapper = wrapper;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
NS_IMETHOD
|
||||
Write(const char *aBuffer, PRUint32 aCount, PRUint32 *aNumWritten) {
|
||||
*aNumWritten = 0;
|
||||
nsresult rv = mBaseStream->Write(aBuffer, aCount, aNumWritten);
|
||||
mChannel->NotifyStorageInUse(*aNumWritten);
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
Flush() { return mBaseStream->Flush(); }
|
||||
|
||||
NS_IMETHOD
|
||||
Close() { return mBaseStream->Close(); }
|
||||
|
||||
private:
|
||||
nsCOMPtr<nsIOutputStream> mBaseStream;
|
||||
nsMemCacheChannel* mChannel;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(MemCacheWriteStreamWrapper, NS_GET_IID(nsIOutputStream))
|
||||
|
||||
nsMemCacheChannel::nsMemCacheChannel(nsMemCacheRecord *aRecord, nsILoadGroup *aLoadGroup)
|
||||
: mRecord(aRecord)
|
||||
{
|
||||
NS_INIT_REFCNT();
|
||||
mRecord->mNumChannels++;
|
||||
}
|
||||
|
||||
nsMemCacheChannel::~nsMemCacheChannel()
|
||||
{
|
||||
mRecord->mNumChannels--;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMemCacheChannel::IsPending(PRBool* aIsPending)
|
||||
{
|
||||
*aIsPending = PR_FALSE;
|
||||
if (!mAsyncReadStream)
|
||||
return NS_OK;
|
||||
return mAsyncReadStream->IsPending(aIsPending);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMemCacheChannel::Cancel(void)
|
||||
{
|
||||
if (!mAsyncReadStream)
|
||||
return NS_ERROR_FAILURE;
|
||||
return mAsyncReadStream->Cancel();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMemCacheChannel::Suspend(void)
|
||||
{
|
||||
if (!mAsyncReadStream)
|
||||
return NS_ERROR_FAILURE;
|
||||
return mAsyncReadStream->Suspend();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMemCacheChannel::Resume(void)
|
||||
{
|
||||
if (!mAsyncReadStream)
|
||||
return NS_ERROR_FAILURE;
|
||||
return mAsyncReadStream->Resume();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMemCacheChannel::GetOriginalURI(nsIURI * *aURI)
|
||||
{
|
||||
// Not required
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMemCacheChannel::GetURI(nsIURI * *aURI)
|
||||
{
|
||||
// Not required to be implemented, since it is implemented by cache manager
|
||||
NS_ASSERTION(0, "nsMemCacheChannel method unexpectedly called");
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMemCacheChannel::OpenInputStream(PRUint32 aStartPosition, PRInt32 aReadCount,
|
||||
nsIInputStream* *aResult)
|
||||
{
|
||||
nsresult rv;
|
||||
NS_ENSURE_ARG(aResult);
|
||||
if (mInputStream)
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
|
||||
rv = mRecord->mStorageStream->NewInputStream(aStartPosition, getter_AddRefs(mInputStream));
|
||||
*aResult = mInputStream;
|
||||
NS_ADDREF(*aResult);
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMemCacheChannel::OpenOutputStream(PRUint32 startPosition, nsIOutputStream* *aResult)
|
||||
{
|
||||
nsresult rv;
|
||||
NS_ENSURE_ARG(aResult);
|
||||
|
||||
nsCOMPtr<nsIOutputStream> outputStream;
|
||||
|
||||
PRUint32 oldLength;
|
||||
mRecord->mStorageStream->GetLength(&oldLength);
|
||||
rv = mRecord->mStorageStream->GetOutputStream(startPosition, getter_AddRefs(outputStream));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
if (startPosition < oldLength)
|
||||
NotifyStorageInUse(startPosition - oldLength);
|
||||
|
||||
return MemCacheWriteStreamWrapper::Create(this, outputStream, aResult);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMemCacheChannel::AsyncOpen(nsIStreamObserver *observer, nsISupports *ctxt)
|
||||
{
|
||||
// Not required
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMemCacheChannel::AsyncRead(PRUint32 aStartPosition, PRInt32 aReadCount,
|
||||
nsISupports *aContext, nsIStreamListener *aListener)
|
||||
{
|
||||
nsCOMPtr<nsIInputStream> inputStream;
|
||||
nsresult rv = OpenInputStream(aStartPosition, aReadCount, getter_AddRefs(inputStream));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
AsyncReadStreamAdaptor *asyncReadStreamAdaptor;
|
||||
asyncReadStreamAdaptor = new AsyncReadStreamAdaptor(this, inputStream);
|
||||
if (!asyncReadStreamAdaptor)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
NS_ADDREF(asyncReadStreamAdaptor);
|
||||
mAsyncReadStream = asyncReadStreamAdaptor;
|
||||
|
||||
rv = asyncReadStreamAdaptor->AsyncRead(aStartPosition, aReadCount, aContext, aListener);
|
||||
if (NS_FAILED(rv))
|
||||
delete asyncReadStreamAdaptor;
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMemCacheChannel::AsyncWrite(nsIInputStream *fromStream, PRUint32 startPosition,
|
||||
PRInt32 writeCount, nsISupports *ctxt,
|
||||
nsIStreamObserver *observer)
|
||||
{
|
||||
// Not required to be implemented
|
||||
NS_ASSERTION(0, "nsMemCacheChannel method unexpectedly called");
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMemCacheChannel::GetLoadAttributes(nsLoadFlags *aLoadAttributes)
|
||||
{
|
||||
// Not required to be implemented, since it is implemented by cache manager
|
||||
NS_ASSERTION(0, "nsMemCacheChannel method unexpectedly called");
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMemCacheChannel::SetLoadAttributes(nsLoadFlags aLoadAttributes)
|
||||
{
|
||||
// Not required to be implemented, since it is implemented by cache manager
|
||||
NS_ASSERTION(0, "nsMemCacheChannel method unexpectedly called");
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMemCacheChannel::GetContentType(char* *aContentType)
|
||||
{
|
||||
// Not required to be implemented, since it is implemented by cache manager
|
||||
NS_ASSERTION(0, "nsMemCacheChannel method unexpectedly called");
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMemCacheChannel::GetContentLength(PRInt32 *aContentLength)
|
||||
{
|
||||
// Not required to be implemented, since it is implemented by cache manager
|
||||
NS_ASSERTION(0, "nsMemCacheChannel method unexpectedly called");
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMemCacheChannel::GetOwner(nsISupports* *aOwner)
|
||||
{
|
||||
*aOwner = mOwner.get();
|
||||
NS_IF_ADDREF(*aOwner);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMemCacheChannel::SetOwner(nsISupports* aOwner)
|
||||
{
|
||||
// Not required to be implemented, since it is implemented by cache manager
|
||||
mOwner = aOwner;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMemCacheChannel::GetLoadGroup(nsILoadGroup* *aLoadGroup)
|
||||
{
|
||||
// Not required to be implemented, since it is implemented by cache manager
|
||||
NS_ASSERTION(0, "nsMemCacheChannel method unexpectedly called");
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMemCacheChannel::SetLoadGroup(nsILoadGroup* aLoadGroup)
|
||||
{
|
||||
// Not required to be implemented, since it is implemented by cache manager
|
||||
NS_ASSERTION(0, "nsMemCacheChannel method unexpectedly called");
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMemCacheChannel::GetNotificationCallbacks(nsIInterfaceRequestor* *aNotificationCallbacks)
|
||||
{
|
||||
// Not required to be implemented, since it is implemented by cache manager
|
||||
NS_ASSERTION(0, "nsMemCacheChannel method unexpectedly called");
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMemCacheChannel::SetNotificationCallbacks(nsIInterfaceRequestor* aNotificationCallbacks)
|
||||
{
|
||||
// Not required to be implemented, since it is implemented by cache manager
|
||||
NS_ASSERTION(0, "nsMemCacheChannel method unexpectedly called");
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
61
mozilla/netwerk/cache/memcache/nsMemCacheChannel.h
vendored
Normal file
61
mozilla/netwerk/cache/memcache/nsMemCacheChannel.h
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
/* -*- Mode: C++; tab-width: 4; 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 Communicator client code, released
|
||||
* March 31, 1998.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998-1999 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _nsMemCacheChannel_h_
|
||||
#define _nsMemCacheChannel_h_
|
||||
|
||||
#include "nsMemCacheRecord.h"
|
||||
#include "nsIChannel.h"
|
||||
#include "nsIInputStream.h"
|
||||
#include "nsCOMPtr.h"
|
||||
|
||||
|
||||
class AsyncReadStreamAdaptor;
|
||||
|
||||
class nsMemCacheChannel : public nsIChannel
|
||||
{
|
||||
public:
|
||||
// Constructors and Destructor
|
||||
nsMemCacheChannel(nsMemCacheRecord *aRecord, nsILoadGroup *aLoadGroup);
|
||||
virtual ~nsMemCacheChannel();
|
||||
|
||||
// Declare nsISupports methods
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
// Declare nsIRequest methods
|
||||
NS_DECL_NSIREQUEST
|
||||
|
||||
// Declare nsIChannel methods
|
||||
NS_DECL_NSICHANNEL
|
||||
|
||||
protected:
|
||||
void NotifyStorageInUse(PRInt32 aBytesUsed);
|
||||
|
||||
nsCOMPtr<nsMemCacheRecord> mRecord;
|
||||
nsCOMPtr<nsIInputStream> mInputStream;
|
||||
nsCOMPtr<nsISupports> mOwner;
|
||||
AsyncReadStreamAdaptor* mAsyncReadStream; // non-owning pointer
|
||||
|
||||
friend class MemCacheWriteStreamWrapper;
|
||||
friend class AsyncReadStreamAdaptor;
|
||||
};
|
||||
|
||||
#endif // _nsMemCacheChannel_h_
|
||||
164
mozilla/netwerk/cache/memcache/nsMemCacheRecord.cpp
vendored
Normal file
164
mozilla/netwerk/cache/memcache/nsMemCacheRecord.cpp
vendored
Normal file
@@ -0,0 +1,164 @@
|
||||
/* -*- Mode: C++; tab-width: 4; 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 Communicator client code, released
|
||||
* March 31, 1998.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998-1999 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "nsMemCache.h"
|
||||
#include "nsMemCacheRecord.h"
|
||||
#include "nsMemCacheChannel.h"
|
||||
#include "nsIAllocator.h"
|
||||
#include "nsStorageStream.h"
|
||||
|
||||
static NS_DEFINE_IID(kINetDataCacheRecord, NS_INETDATACACHERECORD_IID);
|
||||
|
||||
nsMemCacheRecord::nsMemCacheRecord()
|
||||
: mKey(0), mKeyLength(0), mMetaData(0), mMetaDataLength(0), mNumChannels(0)
|
||||
{
|
||||
NS_INIT_REFCNT();
|
||||
}
|
||||
|
||||
nsMemCacheRecord::~nsMemCacheRecord()
|
||||
{
|
||||
if (mMetaData)
|
||||
delete[] mMetaData;
|
||||
if (mKey)
|
||||
delete[] mKey;
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsMemCacheRecord, NS_GET_IID(nsINetDataCacheRecord))
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMemCacheRecord::GetKey(PRUint32 *aLength, char **aResult)
|
||||
{
|
||||
NS_ENSURE_ARG(aResult);
|
||||
*aResult = (char *)nsAllocator::Alloc(mKeyLength);
|
||||
if (!*aResult)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
memcpy(*aResult, mKey, mKeyLength);
|
||||
*aLength = mKeyLength;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsMemCacheRecord::Init(const char *aKey, PRUint32 aKeyLength,
|
||||
PRUint32 aRecordID, nsMemCache *aCache)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
NS_ASSERTION(!mKey, "Memory cache record key set multiple times");
|
||||
|
||||
rv = NS_NewStorageStream(MEM_CACHE_SEGMENT_SIZE, MEM_CACHE_MAX_ENTRY_SIZE,
|
||||
getter_AddRefs(mStorageStream));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
mKey = new char[aKeyLength];
|
||||
if (!mKey)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
memcpy(mKey, aKey, aKeyLength);
|
||||
mKeyLength = aKeyLength;
|
||||
mRecordID = aRecordID;
|
||||
mCache = aCache;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMemCacheRecord::GetRecordID(PRInt32 *aRecordID)
|
||||
{
|
||||
NS_ENSURE_ARG(aRecordID);
|
||||
*aRecordID = mRecordID;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMemCacheRecord::GetMetaData(PRUint32 *aLength, char **aResult)
|
||||
{
|
||||
NS_ENSURE_ARG(aResult);
|
||||
|
||||
*aResult = 0;
|
||||
if (mMetaDataLength) {
|
||||
*aResult = (char*)nsAllocator::Alloc(mMetaDataLength);
|
||||
if (!*aResult)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
memcpy(*aResult, mMetaData, mMetaDataLength);
|
||||
}
|
||||
*aLength = mMetaDataLength;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMemCacheRecord::SetMetaData(PRUint32 aLength, const char *aData)
|
||||
{
|
||||
if (mMetaData)
|
||||
delete[] mMetaData;
|
||||
mMetaData = new char[aLength];
|
||||
if (!mMetaData)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
memcpy(mMetaData, aData, aLength);
|
||||
mMetaDataLength = aLength;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMemCacheRecord::GetStoredContentLength(PRUint32 *aStoredContentLength)
|
||||
{
|
||||
NS_ENSURE_ARG(aStoredContentLength);
|
||||
return mStorageStream->GetLength(aStoredContentLength);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMemCacheRecord::SetStoredContentLength(PRUint32 aStoredContentLength)
|
||||
{
|
||||
PRUint32 before, after;
|
||||
mStorageStream->GetLength(&before);
|
||||
nsresult rv = mStorageStream->SetLength(aStoredContentLength);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
mStorageStream->GetLength(&after);
|
||||
mCache->mOccupancy -= (before - after);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMemCacheRecord::Delete(void)
|
||||
{
|
||||
if (mNumChannels)
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
|
||||
return mCache->Delete(this);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMemCacheRecord::GetFilename(nsIFileSpec* *aFilename)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMemCacheRecord::NewChannel(nsILoadGroup *aLoadGroup, nsIChannel* *aResult)
|
||||
{
|
||||
NS_ENSURE_ARG(aResult);
|
||||
|
||||
nsMemCacheChannel* channel = new nsMemCacheChannel(this, aLoadGroup);
|
||||
if (!channel)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
NS_ADDREF(channel);
|
||||
*aResult = NS_STATIC_CAST(nsIChannel*, channel);
|
||||
return NS_OK;
|
||||
|
||||
}
|
||||
65
mozilla/netwerk/cache/memcache/nsMemCacheRecord.h
vendored
Normal file
65
mozilla/netwerk/cache/memcache/nsMemCacheRecord.h
vendored
Normal file
@@ -0,0 +1,65 @@
|
||||
/* -*- Mode: C++; tab-width: 4; 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 Communicator client code, released
|
||||
* March 31, 1998.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998-1999 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _nsMemCacheRecord_h_
|
||||
#define _nsMemCacheRecord_h_
|
||||
|
||||
#include "nsINetDataCacheRecord.h"
|
||||
#include "nsIStorageStream.h"
|
||||
#include "nsCOMPtr.h"
|
||||
|
||||
class nsMemCache;
|
||||
|
||||
class nsMemCacheRecord : public nsINetDataCacheRecord
|
||||
{
|
||||
|
||||
public:
|
||||
// Declare interface methods
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSINETDATACACHERECORD
|
||||
|
||||
protected:
|
||||
// Constructors and Destructor
|
||||
nsMemCacheRecord();
|
||||
virtual ~nsMemCacheRecord();
|
||||
|
||||
nsresult Init(const char *aKey, PRUint32 aKeyLength,
|
||||
PRUint32 aRecordID, nsMemCache *aCache);
|
||||
|
||||
char* mKey; // opaque database key for this record
|
||||
PRUint32 mKeyLength; // length, in bytes, of mKey
|
||||
|
||||
PRInt32 mRecordID; // An alternate key for this record
|
||||
|
||||
char* mMetaData; // opaque URI metadata
|
||||
PRUint32 mMetaDataLength; // length, in bytes, of mMetaData
|
||||
|
||||
nsMemCache* mCache; // weak pointer to the cache database
|
||||
// that this record inhabits
|
||||
|
||||
nsCOMPtr<nsIStorageStream> mStorageStream;
|
||||
PRUint32 mNumChannels; // Count un-Release'ed nsIChannels
|
||||
|
||||
friend class nsMemCache;
|
||||
friend class nsMemCacheChannel;
|
||||
};
|
||||
|
||||
#endif // _nsMemCacheRecord_h_
|
||||
55
mozilla/netwerk/cache/mgr/Makefile.in
vendored
Normal file
55
mozilla/netwerk/cache/mgr/Makefile.in
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
#
|
||||
# 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 = nkcache
|
||||
LIBRARY_NAME = nkcachemgr_s
|
||||
|
||||
REQUIRES = nspr
|
||||
|
||||
EXPORTS = \
|
||||
nsCacheManager.h \
|
||||
$(NULL)
|
||||
|
||||
CPPSRCS = \
|
||||
nsCacheManager.cpp \
|
||||
nsCachedNetData.cpp \
|
||||
nsReplacementPolicy.cpp \
|
||||
nsCacheEntryChannel.cpp \
|
||||
$(NULL)
|
||||
|
||||
LOCAL_INCLUDES = -I$(srcdir)/../public -I$(srcdir)/../include
|
||||
|
||||
EXTRA_LIBS = $(NSPR_LIBS)
|
||||
|
||||
# we don't want the shared lib, but we want to force the creation of a
|
||||
# static lib.
|
||||
override NO_SHARED_LIB=1
|
||||
override NO_STATIC_LIB=
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
45
mozilla/netwerk/cache/mgr/Makefile.win
vendored
Executable file
45
mozilla/netwerk/cache/mgr/Makefile.win
vendored
Executable file
@@ -0,0 +1,45 @@
|
||||
#!gmake
|
||||
#
|
||||
# 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=..\..\..
|
||||
|
||||
include <$(DEPTH)/config/config.mak>
|
||||
|
||||
MODULE = nkcache
|
||||
|
||||
LIBRARY_NAME = nkcachemgr_s
|
||||
|
||||
CPP_OBJS = \
|
||||
.\$(OBJDIR)\nsCacheManager.obj \
|
||||
.\$(OBJDIR)\nsCachedNetData.obj \
|
||||
.\$(OBJDIR)\nsReplacementPolicy.obj \
|
||||
.\$(OBJDIR)\nsCacheEntryChannel.obj \
|
||||
$(NULL)
|
||||
|
||||
include <$(DEPTH)\config\rules.mak>
|
||||
|
||||
install:: $(LIBRARY)
|
||||
$(MAKE_INSTALL) $(LIBRARY) $(DIST)\lib
|
||||
|
||||
clobber::
|
||||
rm -rf $(OBJDIR)
|
||||
rm -f $(DIST)\lib\$(LIBRARY_NAME).lib
|
||||
|
||||
261
mozilla/netwerk/cache/mgr/nsCacheEntryChannel.cpp
vendored
Normal file
261
mozilla/netwerk/cache/mgr/nsCacheEntryChannel.cpp
vendored
Normal file
@@ -0,0 +1,261 @@
|
||||
/* -*- Mode: C++; tab-width: 4; 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 Communicator client code, released
|
||||
* March 31, 1998.
|
||||
*
|
||||
* 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):
|
||||
* Scott Furman, fur@netscape.com
|
||||
*/
|
||||
|
||||
#include "nsCacheManager.h"
|
||||
#include "nsCacheEntryChannel.h"
|
||||
#include "nsIOutputStream.h"
|
||||
#include "nsIIOService.h"
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsIStreamListener.h"
|
||||
|
||||
nsCacheEntryChannel::nsCacheEntryChannel(nsCachedNetData* aCacheEntry, nsIChannel* aChannel,
|
||||
nsILoadGroup* aLoadGroup):
|
||||
nsChannelProxy(aChannel), mCacheEntry(aCacheEntry), mLoadGroup(aLoadGroup), mLoadAttributes(0)
|
||||
{
|
||||
NS_ASSERTION(aCacheEntry->mChannelCount < 0xFF, "Overflowed channel counter");
|
||||
mCacheEntry->mChannelCount++;
|
||||
NS_INIT_REFCNT();
|
||||
}
|
||||
|
||||
nsCacheEntryChannel::~nsCacheEntryChannel()
|
||||
{
|
||||
mCacheEntry->mChannelCount--;
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS3(nsCacheEntryChannel, nsISupports, nsIChannel, nsIRequest)
|
||||
|
||||
// A proxy for nsIOutputStream
|
||||
class CacheOutputStream : public nsIOutputStream {
|
||||
|
||||
public:
|
||||
CacheOutputStream(nsIOutputStream *aOutputStream, nsCachedNetData *aCacheEntry):
|
||||
mOutputStream(aOutputStream), mCacheEntry(aCacheEntry), mStartTime(PR_Now())
|
||||
{ NS_INIT_REFCNT(); }
|
||||
|
||||
virtual ~CacheOutputStream() {
|
||||
mCacheEntry->NoteDownloadTime(mStartTime, PR_Now());
|
||||
mCacheEntry->ClearFlag(nsCachedNetData::UPDATE_IN_PROGRESS);
|
||||
}
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
NS_IMETHOD Close() {
|
||||
return mOutputStream->Close();
|
||||
}
|
||||
|
||||
NS_IMETHOD Flush() { return mOutputStream->Flush(); }
|
||||
|
||||
NS_IMETHOD
|
||||
Write(const char *aBuf, PRUint32 aCount, PRUint32 *aActualBytes) {
|
||||
nsresult rv;
|
||||
|
||||
*aActualBytes = 0;
|
||||
rv = mOutputStream->Write(aBuf, aCount, aActualBytes);
|
||||
mCacheEntry->mLogicalLength += *aActualBytes;
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
nsCacheManager::LimitCacheSize();
|
||||
return rv;
|
||||
}
|
||||
|
||||
protected:
|
||||
nsCOMPtr<nsIOutputStream> mOutputStream;
|
||||
nsCOMPtr<nsCachedNetData> mCacheEntry;
|
||||
|
||||
// Time at which stream was opened
|
||||
PRTime mStartTime;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(CacheOutputStream, NS_GET_IID(nsIOutputStream))
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsCacheEntryChannel::OpenOutputStream(PRUint32 aStartPosition, nsIOutputStream* *aOutputStream)
|
||||
{
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIOutputStream> baseOutputStream;
|
||||
|
||||
rv = mChannel->OpenOutputStream(aStartPosition, getter_AddRefs(baseOutputStream));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
mCacheEntry->NoteUpdate();
|
||||
mCacheEntry->NoteAccess();
|
||||
mCacheEntry->mLogicalLength = aStartPosition;
|
||||
|
||||
*aOutputStream = new CacheOutputStream(baseOutputStream, mCacheEntry);
|
||||
if (!*aOutputStream)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
NS_ADDREF(*aOutputStream);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsCacheEntryChannel::OpenInputStream(PRUint32 aStartPosition, PRInt32 aReadCount,
|
||||
nsIInputStream* *aInputStream)
|
||||
{
|
||||
mCacheEntry->NoteAccess();
|
||||
return mChannel->OpenInputStream(aStartPosition, aReadCount, aInputStream);
|
||||
}
|
||||
|
||||
class CacheManagerStreamListener: public nsIStreamListener {
|
||||
|
||||
public:
|
||||
|
||||
CacheManagerStreamListener(nsIStreamListener *aListener,
|
||||
nsILoadGroup *aLoadGroup, nsIChannel *aChannel):
|
||||
mListener(aListener), mLoadGroup(aLoadGroup), mChannel(aChannel)
|
||||
{ NS_INIT_REFCNT(); }
|
||||
|
||||
virtual ~CacheManagerStreamListener() {}
|
||||
|
||||
private:
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
NS_IMETHOD
|
||||
OnDataAvailable(nsIChannel *channel, nsISupports *aContext,
|
||||
nsIInputStream *inStr, PRUint32 sourceOffset, PRUint32 count) {
|
||||
return mListener->OnDataAvailable(mChannel, aContext, inStr, sourceOffset, count);
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
OnStartRequest(nsIChannel *channel, nsISupports *aContext) {
|
||||
if (mLoadGroup)
|
||||
mLoadGroup->AddChannel(mChannel, aContext);
|
||||
return mListener->OnStartRequest(mChannel, aContext);
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
OnStopRequest(nsIChannel *channel, nsISupports *aContext,
|
||||
nsresult status, const PRUnichar *errorMsg) {
|
||||
nsresult rv;
|
||||
rv = mListener->OnStopRequest(mChannel, aContext, status, errorMsg);
|
||||
if (mLoadGroup)
|
||||
mLoadGroup->RemoveChannel(mChannel, aContext, status, errorMsg);
|
||||
return rv;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
nsCOMPtr<nsIStreamListener> mListener;
|
||||
nsCOMPtr<nsILoadGroup> mLoadGroup;
|
||||
nsCOMPtr<nsIChannel> mChannel;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS2(CacheManagerStreamListener, nsIStreamListener, nsIStreamObserver)
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsCacheEntryChannel::AsyncRead(PRUint32 aStartPosition, PRInt32 aReadCount,
|
||||
nsISupports *aContext, nsIStreamListener *aListener)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
mCacheEntry->NoteAccess();
|
||||
|
||||
nsCOMPtr<nsIStreamListener> headListener;
|
||||
if (mLoadGroup) {
|
||||
mLoadGroup->GetDefaultLoadAttributes(&mLoadAttributes);
|
||||
|
||||
// Create a load group "proxy" listener...
|
||||
nsCOMPtr<nsILoadGroupListenerFactory> factory;
|
||||
rv = mLoadGroup->GetGroupListenerFactory(getter_AddRefs(factory));
|
||||
if (NS_SUCCEEDED(rv) && factory) {
|
||||
rv = factory->CreateLoadGroupListener(aListener,
|
||||
getter_AddRefs(headListener));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
}
|
||||
|
||||
} else {
|
||||
headListener = aListener;
|
||||
}
|
||||
|
||||
CacheManagerStreamListener* cacheManagerStreamListener;
|
||||
nsIChannel *channelForListener;
|
||||
|
||||
channelForListener = mProxyChannel ? mProxyChannel.get() : NS_STATIC_CAST(nsIChannel*, this);
|
||||
cacheManagerStreamListener =
|
||||
new CacheManagerStreamListener(headListener, mLoadGroup, channelForListener);
|
||||
if (!cacheManagerStreamListener) return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
NS_ADDREF(cacheManagerStreamListener);
|
||||
rv = mChannel->AsyncRead(aStartPosition, aReadCount, aContext,
|
||||
cacheManagerStreamListener);
|
||||
NS_RELEASE(cacheManagerStreamListener);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
// No async writes allowed to the cache yet
|
||||
NS_IMETHODIMP
|
||||
nsCacheEntryChannel::AsyncWrite(nsIInputStream *aFromStream, PRUint32 aStartPosition,
|
||||
PRInt32 aWriteCount, nsISupports *aContext,
|
||||
nsIStreamObserver *aObserver)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsCacheEntryChannel::GetLoadGroup(nsILoadGroup* *aLoadGroup)
|
||||
{
|
||||
*aLoadGroup = mLoadGroup;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsCacheEntryChannel::GetLoadAttributes(nsLoadFlags *aLoadAttributes)
|
||||
{
|
||||
*aLoadAttributes = mLoadAttributes;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsCacheEntryChannel::SetLoadAttributes(nsLoadFlags aLoadAttributes)
|
||||
{
|
||||
mLoadAttributes = aLoadAttributes;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
static NS_DEFINE_CID(kIOServiceCID, NS_IOSERVICE_CID);
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsCacheEntryChannel::GetURI(nsIURI * *aURI)
|
||||
{
|
||||
char* spec;
|
||||
nsresult rv;
|
||||
|
||||
rv = mCacheEntry->GetUriSpec(&spec);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
NS_WITH_SERVICE(nsIIOService, serv, kIOServiceCID, &rv);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
rv = serv->NewURI(spec, 0, aURI);
|
||||
nsAllocator::Free(spec);
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsCacheEntryChannel::GetOriginalURI(nsIURI * *aURI)
|
||||
{
|
||||
// FIXME - should return original URI passed into NewChannel() ?
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
82
mozilla/netwerk/cache/mgr/nsCacheEntryChannel.h
vendored
Normal file
82
mozilla/netwerk/cache/mgr/nsCacheEntryChannel.h
vendored
Normal file
@@ -0,0 +1,82 @@
|
||||
/* -*- Mode: C++; tab-width: 4; 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 Communicator client code, released
|
||||
* March 31, 1998.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998-1999 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Scott Furman, fur@netscape.com
|
||||
*/
|
||||
|
||||
#ifndef _nsCacheEntryChannel_h_
|
||||
#define _nsCacheEntryChannel_h_
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIChannel.h"
|
||||
#include "nsCachedNetData.h"
|
||||
#include "nsILoadGroup.h"
|
||||
|
||||
class nsIStreamListener;
|
||||
|
||||
// A proxy for an nsIChannel, useful when only a few nsIChannel
|
||||
// methods must be overridden
|
||||
class nsChannelProxy : public nsIChannel {
|
||||
|
||||
public:
|
||||
NS_FORWARD_NSICHANNEL(mChannel->)
|
||||
NS_FORWARD_NSIREQUEST(mChannel->)
|
||||
|
||||
protected:
|
||||
nsChannelProxy(nsIChannel* aChannel):mChannel(aChannel) {};
|
||||
virtual ~nsChannelProxy() {};
|
||||
nsCOMPtr<nsIChannel> mChannel;
|
||||
};
|
||||
|
||||
// Override several nsIChannel methods so that they interact with the cache manager
|
||||
class nsCacheEntryChannel : public nsChannelProxy {
|
||||
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
NS_IMETHOD OpenOutputStream(PRUint32 aStartPosition, nsIOutputStream* *aOutputStream);
|
||||
NS_IMETHOD OpenInputStream(PRUint32 aStartPosition, PRInt32 aReadCount,
|
||||
nsIInputStream* *aInputStream);
|
||||
NS_IMETHOD AsyncRead(PRUint32 aStartPosition, PRInt32 aReadCount,
|
||||
nsISupports *aContext, nsIStreamListener *aListener);
|
||||
NS_IMETHOD AsyncWrite(nsIInputStream *aFromStream, PRUint32 aStartPosition,
|
||||
PRInt32 aWriteCount, nsISupports *aContext,
|
||||
nsIStreamObserver *aObserver);
|
||||
NS_IMETHOD GetLoadAttributes(nsLoadFlags *aLoadAttributes);
|
||||
NS_IMETHOD SetLoadAttributes(nsLoadFlags aLoadAttributes);
|
||||
NS_IMETHOD GetLoadGroup(nsILoadGroup* *aLoadGroup);
|
||||
NS_IMETHOD GetURI(nsIURI * *aURI);
|
||||
NS_IMETHOD GetOriginalURI(nsIURI * *aURI);
|
||||
|
||||
protected:
|
||||
nsCacheEntryChannel(nsCachedNetData* aCacheEntry, nsIChannel* aChannel, nsILoadGroup* aLoadGroup);
|
||||
virtual ~nsCacheEntryChannel();
|
||||
|
||||
friend class nsCachedNetData;
|
||||
|
||||
private:
|
||||
nsCOMPtr<nsCachedNetData> mCacheEntry;
|
||||
nsCOMPtr<nsILoadGroup> mLoadGroup;
|
||||
nsCOMPtr<nsIChannel> mProxyChannel;
|
||||
nsLoadFlags mLoadAttributes;
|
||||
};
|
||||
|
||||
#endif // _nsCacheEntryChannel_h_
|
||||
497
mozilla/netwerk/cache/mgr/nsCacheManager.cpp
vendored
Normal file
497
mozilla/netwerk/cache/mgr/nsCacheManager.cpp
vendored
Normal file
@@ -0,0 +1,497 @@
|
||||
/* -*- Mode: C++; tab-width: 4; 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 Communicator client code, released
|
||||
* March 31, 1998.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998-1999 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Scott Furman, fur@netscape.com
|
||||
*/
|
||||
|
||||
#include "nsINetDataCache.h"
|
||||
#include "nsCacheManager.h"
|
||||
#include "nsCachedNetData.h"
|
||||
#include "nsReplacementPolicy.h"
|
||||
#include "nsString.h"
|
||||
#include "nsIURI.h"
|
||||
#include "nsHashtable.h"
|
||||
#include "nsIComponentManager.h"
|
||||
#include "nsINetDataDiskCache.h"
|
||||
|
||||
// Limit the number of entries in the cache to conserve memory space
|
||||
// in the nsReplacementPolicy code
|
||||
#define MAX_MEM_CACHE_ENTRIES 800
|
||||
#define MAX_DISK_CACHE_ENTRIES 3200
|
||||
|
||||
// Cache capacities in MB, overridable via APIs
|
||||
#define DEFAULT_MEMORY_CACHE_CAPACITY 1024
|
||||
#define DEFAULT_DISK_CACHE_CAPACITY 10000
|
||||
|
||||
#define CACHE_HIGH_WATER_MARK(capacity) ((PRUint32)(0.98 * (capacity)))
|
||||
#define CACHE_LOW_WATER_MARK(capacity) ((PRUint32)(0.97 * (capacity)))
|
||||
|
||||
nsCacheManager* gCacheManager = 0;
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsCacheManager, NS_GET_IID(nsINetDataCacheManager))
|
||||
|
||||
nsCacheManager::nsCacheManager()
|
||||
: mActiveCacheRecords(0),
|
||||
mDiskCacheCapacity(DEFAULT_DISK_CACHE_CAPACITY),
|
||||
mMemCacheCapacity(DEFAULT_MEMORY_CACHE_CAPACITY)
|
||||
{
|
||||
NS_ASSERTION(!gCacheManager, "Multiple cache managers created");
|
||||
gCacheManager = this;
|
||||
NS_INIT_REFCNT();
|
||||
}
|
||||
|
||||
nsCacheManager::~nsCacheManager()
|
||||
{
|
||||
gCacheManager = 0;
|
||||
delete mActiveCacheRecords;
|
||||
delete mMemSpaceManager;
|
||||
delete mDiskSpaceManager;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsCacheManager::Init()
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
mActiveCacheRecords = new nsHashtable(64);
|
||||
if (!mActiveCacheRecords)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
// Instantiate the memory cache component
|
||||
rv = nsComponentManager::CreateInstance(NS_NETWORK_MEMORY_CACHE_PROGID,
|
||||
nsnull,
|
||||
NS_GET_IID(nsINetDataCache),
|
||||
getter_AddRefs(mMemCache));
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
rv = nsComponentManager::CreateInstance(NS_NETWORK_FLAT_CACHE_PROGID,
|
||||
nsnull,
|
||||
NS_GET_IID(nsINetDataCache),
|
||||
|
||||
getter_AddRefs(mFlatCache));
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
// For now, we don't require a flat cache module to be present
|
||||
if (rv != NS_ERROR_FACTORY_NOT_REGISTERED)
|
||||
return rv;
|
||||
}
|
||||
|
||||
#ifdef FILE_CACHE_IS_READY
|
||||
// Instantiate the file cache component
|
||||
rv = nsComponentManager::CreateInstance(NS_NETWORK_FILE_CACHE_PROGID,
|
||||
nsnull,
|
||||
NS_GET_IID(nsINetDataCache),
|
||||
getter_AddRefs(mFileCache));
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("No disk cache present");
|
||||
}
|
||||
#endif
|
||||
|
||||
// Set up linked list of caches in search order
|
||||
mCacheSearchChain = mMemCache;
|
||||
if (mFlatCache) {
|
||||
mMemCache->SetNextCache(mFlatCache);
|
||||
mFlatCache->SetNextCache(mFileCache);
|
||||
} else {
|
||||
mMemCache->SetNextCache(mFileCache);
|
||||
}
|
||||
|
||||
// TODO - Load any extension caches here
|
||||
|
||||
// Initialize replacement policy for memory cache module
|
||||
mMemSpaceManager = new nsReplacementPolicy;
|
||||
if (!mMemSpaceManager)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
rv = mMemSpaceManager->Init(MAX_MEM_CACHE_ENTRIES);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
rv = mMemSpaceManager->AddCache(mMemCache);
|
||||
|
||||
// Initialize replacement policy for disk cache modules (file
|
||||
// cache and flat cache)
|
||||
mDiskSpaceManager = new nsReplacementPolicy;
|
||||
if (!mDiskSpaceManager)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
rv = mDiskSpaceManager->Init(MAX_DISK_CACHE_ENTRIES);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
if (mFileCache) {
|
||||
rv = mDiskSpaceManager->AddCache(mFileCache);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
}
|
||||
if (mFlatCache) {
|
||||
rv = mDiskSpaceManager->AddCache(mFlatCache);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsCacheManager::GetCachedNetData(const char *aUriSpec, const char *aSecondaryKey,
|
||||
PRUint32 aSecondaryKeyLength,
|
||||
PRUint32 aFlags, nsICachedNetData* *aResult)
|
||||
{
|
||||
nsCachedNetData *cachedData;
|
||||
nsresult rv;
|
||||
nsINetDataCache *cache;
|
||||
nsReplacementPolicy *spaceManager;
|
||||
|
||||
if (aFlags & CACHE_AS_FILE) {
|
||||
cache = mFileCache;
|
||||
spaceManager = mDiskSpaceManager;
|
||||
|
||||
// Ensure that cache is initialized
|
||||
if (mDiskCacheCapacity == (PRUint32)-1)
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
|
||||
} else if ((aFlags & BYPASS_PERSISTENT_CACHE) ||
|
||||
(!mFileCache && !mFlatCache) || !mDiskCacheCapacity) {
|
||||
cache = mMemCache;
|
||||
spaceManager = mMemSpaceManager;
|
||||
} else {
|
||||
cache = mFlatCache ? mFlatCache : mFileCache;
|
||||
spaceManager = mDiskSpaceManager;
|
||||
}
|
||||
|
||||
// Construct the cache key by appending the secondary key to the URI spec
|
||||
nsCAutoString cacheKey(aUriSpec);
|
||||
|
||||
// Insert NUL at end of URI spec
|
||||
cacheKey += '\0';
|
||||
if (aSecondaryKey)
|
||||
cacheKey.Append(aSecondaryKey, aSecondaryKeyLength);
|
||||
|
||||
nsStringKey key(cacheKey);
|
||||
cachedData = (nsCachedNetData*)mActiveCacheRecords->Get(&key);
|
||||
|
||||
// There is no existing instance of nsCachedNetData for this URL.
|
||||
// Make one from the corresponding record in the cache module.
|
||||
if (cachedData) {
|
||||
NS_ASSERTION(cache == cachedData->mCache,
|
||||
"Cannot yet handle simultaneously active requests for the "
|
||||
"same URL using different caches");
|
||||
NS_ADDREF(cachedData);
|
||||
} else {
|
||||
rv = spaceManager->GetCachedNetData(cacheKey.GetBuffer(), cacheKey.Length(),
|
||||
cache, &cachedData);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
mActiveCacheRecords->Put(&key, cachedData);
|
||||
}
|
||||
|
||||
*aResult = cachedData;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Remove this cache entry from the list of active ones
|
||||
nsresult
|
||||
nsCacheManager::NoteDormant(nsCachedNetData* aEntry)
|
||||
{
|
||||
nsresult rv;
|
||||
PRUint32 keyLength;
|
||||
char* key;
|
||||
nsCOMPtr<nsINetDataCacheRecord> record;
|
||||
nsCachedNetData* deletedEntry;
|
||||
|
||||
rv = aEntry->GetRecord(getter_AddRefs(record));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
rv = record->GetKey(&keyLength, &key);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
nsStringKey hashTableKey(nsCString(key, keyLength));
|
||||
deletedEntry = (nsCachedNetData*)gCacheManager->mActiveCacheRecords->Remove(&hashTableKey);
|
||||
// NS_ASSERTION(deletedEntry == aEntry, "Hash table inconsistency");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsCacheManager::Contains(const char *aUriSpec, const char *aSecondaryKey,
|
||||
PRUint32 aSecondaryKeyLength,
|
||||
PRUint32 aFlags, PRBool *aResult)
|
||||
{
|
||||
nsINetDataCache *cache;
|
||||
nsReplacementPolicy *spaceManager;
|
||||
nsCachedNetData *cachedData;
|
||||
|
||||
if (aFlags & CACHE_AS_FILE) {
|
||||
cache = mFileCache;
|
||||
spaceManager = mDiskSpaceManager;
|
||||
} else if ((aFlags & BYPASS_PERSISTENT_CACHE) ||
|
||||
(!mFileCache && !mFlatCache) || !mDiskCacheCapacity) {
|
||||
cache = mMemCache;
|
||||
spaceManager = mMemSpaceManager;
|
||||
} else {
|
||||
cache = mFlatCache ? mFlatCache : mFileCache;
|
||||
spaceManager = mDiskSpaceManager;
|
||||
}
|
||||
|
||||
// Construct the cache key by appending the secondary key to the URI spec
|
||||
nsCAutoString cacheKey(aUriSpec);
|
||||
|
||||
// Insert NUL between URI spec and secondary key
|
||||
cacheKey += '\0';
|
||||
cacheKey.Append(aSecondaryKey, aSecondaryKeyLength);
|
||||
|
||||
// Locate the record using (URI + secondary key)
|
||||
nsStringKey key(cacheKey);
|
||||
cachedData = (nsCachedNetData*)mActiveCacheRecords->Get(&key);
|
||||
|
||||
if (cachedData && (cache == cachedData->mCache)) {
|
||||
*aResult = PR_TRUE;
|
||||
return NS_OK;
|
||||
} else {
|
||||
// No active cache entry, see if there is a dormant one
|
||||
return cache->Contains(cacheKey.GetBuffer(), cacheKey.Length(), aResult);
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsCacheManager::GetNumEntries(PRUint32 *aNumEntries)
|
||||
{
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsISimpleEnumerator> iterator;
|
||||
nsCOMPtr<nsISupports> cacheSupports;
|
||||
nsCOMPtr<nsINetDataCache> cache;
|
||||
|
||||
PRUint32 totalEntries = 0;
|
||||
|
||||
rv = NewCacheModuleIterator(getter_AddRefs(iterator));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
while (1) {
|
||||
PRBool notDone;
|
||||
rv = iterator->HasMoreElements(¬Done);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
if (!notDone)
|
||||
break;
|
||||
|
||||
iterator->GetNext(getter_AddRefs(cacheSupports));
|
||||
cache = do_QueryInterface(cacheSupports);
|
||||
|
||||
PRUint32 numEntries;
|
||||
rv = cache->GetNumEntries(&numEntries);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
totalEntries += numEntries;
|
||||
}
|
||||
|
||||
*aNumEntries = totalEntries;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsCacheManager::NewCacheEntryIterator(nsISimpleEnumerator* *aResult)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
class CacheEnumerator : public nsISimpleEnumerator
|
||||
{
|
||||
public:
|
||||
CacheEnumerator(nsINetDataCache* aFirstCache):mCache(aFirstCache)
|
||||
{ NS_INIT_REFCNT(); }
|
||||
|
||||
virtual ~CacheEnumerator() {};
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
NS_IMETHODIMP
|
||||
HasMoreElements(PRBool* aMoreElements) {
|
||||
*aMoreElements = (mCache != 0);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
GetNext(nsISupports* *aSupports) {
|
||||
*aSupports = mCache;
|
||||
if (!mCache)
|
||||
return NS_ERROR_FAILURE;
|
||||
NS_ADDREF(*aSupports);
|
||||
|
||||
nsCOMPtr<nsINetDataCache> nextCache;
|
||||
nsresult rv = mCache->GetNextCache(getter_AddRefs(nextCache));
|
||||
mCache = nextCache;
|
||||
return rv;
|
||||
}
|
||||
|
||||
private:
|
||||
nsCOMPtr<nsINetDataCache> mCache;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(CacheEnumerator, NS_GET_IID(nsISimpleEnumerator))
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsCacheManager::NewCacheModuleIterator(nsISimpleEnumerator* *aResult)
|
||||
{
|
||||
*aResult = new CacheEnumerator(mCacheSearchChain);
|
||||
if (!*aResult)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
NS_ADDREF(*aResult);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsCacheManager::RemoveAll(void)
|
||||
{
|
||||
nsresult rv, result;
|
||||
nsCOMPtr<nsISimpleEnumerator> iterator;
|
||||
nsCOMPtr<nsINetDataCache> cache;
|
||||
nsCOMPtr<nsISupports> iSupports;
|
||||
|
||||
result = NS_OK;
|
||||
rv = NewCacheModuleIterator(getter_AddRefs(iterator));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
while (1) {
|
||||
PRBool notDone;
|
||||
rv = iterator->HasMoreElements(¬Done);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
if (!notDone)
|
||||
break;
|
||||
|
||||
iterator->GetNext(getter_AddRefs(iSupports));
|
||||
cache = do_QueryInterface(iSupports);
|
||||
|
||||
PRUint32 cacheFlags;
|
||||
rv = cache->GetFlags(&cacheFlags);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
if ((cacheFlags & nsINetDataCache::READ_ONLY) == 0) {
|
||||
rv = cache->RemoveAll();
|
||||
if (NS_FAILED(rv))
|
||||
result = rv;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsCacheManager::LimitMemCacheSize()
|
||||
{
|
||||
nsresult rv;
|
||||
nsReplacementPolicy* spaceManager;
|
||||
|
||||
NS_ASSERTION(gCacheManager, "No cache manager");
|
||||
|
||||
spaceManager = gCacheManager->mMemSpaceManager;
|
||||
|
||||
PRUint32 occupancy;
|
||||
rv = spaceManager->GetStorageInUse(&occupancy);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
PRUint32 memCacheCapacity = gCacheManager->mMemCacheCapacity;
|
||||
if (occupancy > CACHE_HIGH_WATER_MARK(memCacheCapacity))
|
||||
return spaceManager->Evict(CACHE_LOW_WATER_MARK(memCacheCapacity));
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsCacheManager::LimitDiskCacheSize()
|
||||
{
|
||||
nsresult rv;
|
||||
nsReplacementPolicy* spaceManager;
|
||||
|
||||
NS_ASSERTION(gCacheManager, "No cache manager");
|
||||
|
||||
spaceManager = gCacheManager->mDiskSpaceManager;
|
||||
|
||||
PRUint32 occupancy;
|
||||
rv = spaceManager->GetStorageInUse(&occupancy);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
PRUint32 diskCacheCapacity = gCacheManager->mDiskCacheCapacity;
|
||||
if (occupancy > CACHE_HIGH_WATER_MARK(diskCacheCapacity))
|
||||
return spaceManager->Evict(CACHE_LOW_WATER_MARK(diskCacheCapacity));
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsCacheManager::LimitCacheSize()
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
rv = LimitDiskCacheSize();
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
rv = LimitMemCacheSize();
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsCacheManager::SetMemCacheCapacity(PRUint32 aCapacity)
|
||||
{
|
||||
mMemCacheCapacity = aCapacity;
|
||||
LimitCacheSize();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsCacheManager::GetMemCacheCapacity(PRUint32* aCapacity)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aCapacity);
|
||||
*aCapacity = mMemCacheCapacity;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsCacheManager::SetDiskCacheCapacity(PRUint32 aCapacity)
|
||||
{
|
||||
mDiskCacheCapacity = aCapacity;
|
||||
LimitCacheSize();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsCacheManager::GetDiskCacheCapacity(PRUint32* aCapacity)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aCapacity);
|
||||
*aCapacity = mDiskCacheCapacity;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsCacheManager::SetDiskCacheFolder(nsIFileSpec* aFolder)
|
||||
{
|
||||
NS_ENSURE_ARG(aFolder);
|
||||
|
||||
if (!mFileCache)
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
|
||||
nsCOMPtr<nsINetDataDiskCache> fileCache;
|
||||
fileCache = do_QueryInterface(mFileCache);
|
||||
return fileCache->SetDiskCacheFolder(aFolder);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsCacheManager::GetDiskCacheFolder(nsIFileSpec* *aFolder)
|
||||
{
|
||||
NS_ENSURE_ARG(aFolder);
|
||||
|
||||
if (!mFileCache)
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
|
||||
nsCOMPtr<nsINetDataDiskCache> fileCache;
|
||||
fileCache = do_QueryInterface(mFileCache);
|
||||
return fileCache->GetDiskCacheFolder(aFolder);
|
||||
}
|
||||
100
mozilla/netwerk/cache/mgr/nsCacheManager.h
vendored
Normal file
100
mozilla/netwerk/cache/mgr/nsCacheManager.h
vendored
Normal file
@@ -0,0 +1,100 @@
|
||||
/* -*- Mode: C++; tab-width: 4; 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 Communicator client code, released
|
||||
* March 31, 1998.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998-1999 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Scott Furman, fur@netscape.com
|
||||
*/
|
||||
|
||||
#ifndef _nsCacheManager_h_
|
||||
#define _nsCacheManager_h_
|
||||
|
||||
// 2030f0b0-9567-11d3-90d3-0040056a906e
|
||||
#define NS_CACHE_MANAGER_CID \
|
||||
{ \
|
||||
0x2030f0b0, \
|
||||
0x9567, \
|
||||
0x11d3, \
|
||||
{0x90, 0xd3, 0x00, 0x40, 0x05, 0x6a, 0x90, 0x6e} \
|
||||
}
|
||||
|
||||
#include "nsINetDataCacheManager.h"
|
||||
#include "nsINetDataCache.h"
|
||||
#include "nsCOMPtr.h"
|
||||
|
||||
class nsHashtable;
|
||||
class nsReplacementPolicy;
|
||||
class nsCachedNetData;
|
||||
|
||||
class nsCacheManager : public nsINetDataCacheManager {
|
||||
|
||||
public:
|
||||
nsCacheManager();
|
||||
virtual ~nsCacheManager();
|
||||
|
||||
NS_METHOD Init();
|
||||
|
||||
// nsISupports methods
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
// nsINetDataCacheManager methods
|
||||
NS_DECL_NSINETDATACACHEMANAGER
|
||||
|
||||
private:
|
||||
|
||||
// Mapping from cache key to nsCachedNetData, but only for those cache
|
||||
// entries with external references, i.e. those referred to outside the
|
||||
// cache manager
|
||||
nsHashtable* mActiveCacheRecords;
|
||||
|
||||
// Memory cache
|
||||
nsCOMPtr<nsINetDataCache> mMemCache;
|
||||
|
||||
// Flat-file database cache; All content aggregated into single disk file
|
||||
nsCOMPtr<nsINetDataCache> mFlatCache;
|
||||
|
||||
// stream-as-file cache
|
||||
nsCOMPtr<nsINetDataCache> mFileCache;
|
||||
|
||||
// Unified replacement policy for flat-cache and file-cache
|
||||
nsReplacementPolicy* mDiskSpaceManager;
|
||||
|
||||
// Replacement policy for memory cache
|
||||
nsReplacementPolicy* mMemSpaceManager;
|
||||
|
||||
// List of caches in search order
|
||||
nsINetDataCache* mCacheSearchChain;
|
||||
|
||||
// Combined file/flat cache capacity, in KB
|
||||
PRUint32 mDiskCacheCapacity;
|
||||
|
||||
// Memory cache capacity, in KB
|
||||
PRUint32 mMemCacheCapacity;
|
||||
|
||||
protected:
|
||||
static nsresult NoteDormant(nsCachedNetData* aEntry);
|
||||
static nsresult LimitCacheSize();
|
||||
static nsresult LimitMemCacheSize();
|
||||
static nsresult LimitDiskCacheSize();
|
||||
|
||||
friend class nsCachedNetData;
|
||||
friend class CacheOutputStream;
|
||||
};
|
||||
|
||||
#endif // _nsCacheManager_h_
|
||||
1155
mozilla/netwerk/cache/mgr/nsCachedNetData.cpp
vendored
Normal file
1155
mozilla/netwerk/cache/mgr/nsCachedNetData.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
242
mozilla/netwerk/cache/mgr/nsCachedNetData.h
vendored
Normal file
242
mozilla/netwerk/cache/mgr/nsCachedNetData.h
vendored
Normal file
@@ -0,0 +1,242 @@
|
||||
/* -*- Mode: C++; tab-width: 4; 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 Communicator client code, released
|
||||
* March 31, 1998.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998-1999 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Scott Furman, fur@netscape.com
|
||||
*/
|
||||
|
||||
#ifndef _nsCachedNetData_h_
|
||||
#define _nsCachedNetData_h_
|
||||
|
||||
#include "nsICachedNetData.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsINetDataCacheRecord.h"
|
||||
|
||||
class nsINetDataCache;
|
||||
class nsIStreamAsFileObserver;
|
||||
class nsIStreamAsFile;
|
||||
class nsIArena;
|
||||
class StreamAsFileObserverClosure;
|
||||
class CacheMetaData;
|
||||
|
||||
// Number of recent access times recorded
|
||||
#define MAX_K 3
|
||||
|
||||
/**
|
||||
* FIXME - add comment. There are a lot of these data structures resident in
|
||||
* memory, so be careful about adding members unnecessarily.
|
||||
*/
|
||||
class nsCachedNetData : public nsICachedNetData {
|
||||
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
// nsICachedNetData methods
|
||||
NS_DECL_NSICACHEDNETDATA
|
||||
|
||||
NS_METHOD Init(nsINetDataCacheRecord *aRecord, nsINetDataCache *aCache);
|
||||
|
||||
protected:
|
||||
|
||||
// Bits for mFlags, below
|
||||
typedef enum {
|
||||
DIRTY = 1 << 0, // Cache entry data needs to be flushed to database
|
||||
|
||||
// ==== Flags that can be set by the protocol handler ====
|
||||
ALLOW_PARTIAL = 1 << 1, // Protocol handler supports partial fetching
|
||||
UPDATE_IN_PROGRESS = 1 << 2, // Protocol handler now modifying cache data
|
||||
|
||||
// ==== Cache-entry state flags. At most one of these flags can be set ====
|
||||
TRUNCATED_CONTENT = 1 << 4, // Entry contains valid content, but it has
|
||||
// been truncated by cache manager
|
||||
|
||||
// A previously-used cache entry, which has been purged of all cached
|
||||
// content and protocol-private data. This cache entry can be refilled
|
||||
// with new content or it may be retained in this vestigial state
|
||||
// because the usage statistics it contains will be used by the
|
||||
// replacement policy if the same URI is ever cached again.
|
||||
VESTIGIAL = 1 << 5,
|
||||
|
||||
// ==== Memory usage status bits. At most one of these flags can be set ====
|
||||
RECYCLED = 1 << 8, // Previously associated database record has
|
||||
// been deleted; This cache entry is available
|
||||
// for recycling.
|
||||
|
||||
DORMANT = 1 << 9, // No references to this cache entry, except by
|
||||
// the cache manager itself
|
||||
|
||||
// ==== Setter bits ====
|
||||
LAST_MODIFIED_KNOWN = 1 <<12, // Protocol handler called SetLastModifiedTime()
|
||||
EXPIRATION_KNOWN = 1 <<13, // Protocol handler called SetExpirationTime()
|
||||
STALE_TIME_KNOWN = 1 <<14, // Protocol handler called SetStaleTime()
|
||||
|
||||
// ==== Useful flag combinations ====
|
||||
// Cache entry not eligible for eviction
|
||||
UNEVICTABLE = VESTIGIAL | RECYCLED | UPDATE_IN_PROGRESS,
|
||||
|
||||
// State flags that are in-memory only, i.e. not persistent
|
||||
TRANSIENT_FLAGS = DIRTY | RECYCLED | DORMANT
|
||||
} Flag;
|
||||
|
||||
PRBool GetFlag(Flag aFlag) { return (mFlags & aFlag) != 0; }
|
||||
nsresult GetFlag(PRBool *aResult, Flag aFlag) { *aResult = GetFlag(aFlag); return NS_OK; }
|
||||
|
||||
// Set a boolean flag for the cache entry
|
||||
nsresult SetFlag(PRBool aValue, Flag aFlag);
|
||||
nsresult SetFlag(Flag aFlag) { return SetFlag(PR_TRUE, aFlag); }
|
||||
nsresult ClearFlag(Flag aFlag) { return SetFlag(PR_FALSE, aFlag); }
|
||||
|
||||
void ComputeProfit(PRUint32 aCurrentTime);
|
||||
static int Compare(const void *a, const void *b, void *unused);
|
||||
|
||||
void NoteAccess();
|
||||
void NoteUpdate();
|
||||
|
||||
// Get underlying raw cache database record.
|
||||
nsresult GetRecord(nsINetDataCacheRecord* *aRecord);
|
||||
|
||||
nsresult GetRecordID(PRInt32 *aRecordID);
|
||||
|
||||
nsresult Evict(PRUint32 aTruncatedContentLength);
|
||||
|
||||
nsresult GetFileSpec(nsIFileSpec* *aFileSpec);
|
||||
|
||||
void NoteDownloadTime(PRTime start, PRTime end);
|
||||
|
||||
// placement new for arena-allocation
|
||||
void *operator new (size_t aSize, nsIArena *aArena);
|
||||
|
||||
friend class nsReplacementPolicy;
|
||||
friend class nsCacheManager;
|
||||
friend class StreamAsFile;
|
||||
friend class nsCacheEntryChannel;
|
||||
friend class CacheOutputStream;
|
||||
friend class InterceptStreamListener;
|
||||
|
||||
private:
|
||||
|
||||
nsCachedNetData() {};
|
||||
virtual ~nsCachedNetData() {};
|
||||
|
||||
// Initialize internal fields of this nsCachedNetData instance from the
|
||||
// underlying raw cache database record.
|
||||
nsresult Deserialize(PRBool aDeserializeFlags);
|
||||
|
||||
// Notify stream-as-file observers about change in cache entry status
|
||||
nsresult Notify(PRUint32 aMessage, nsresult aError);
|
||||
|
||||
// Add/Remove stream-as-file observers
|
||||
nsresult AddObserver(nsIStreamAsFile *aStreamAsFile, nsIStreamAsFileObserver* aObserver);
|
||||
nsresult RemoveObserver(nsIStreamAsFileObserver* aObserver);
|
||||
|
||||
// Mark cache entry to indicate a write out to the cache database is required
|
||||
void SetDirty() { mFlags |= DIRTY; }
|
||||
|
||||
nsresult Resurrect(nsINetDataCacheRecord *aRecord);
|
||||
|
||||
nsresult CommitFlags();
|
||||
|
||||
CacheMetaData* FindTaggedMetaData(const char* aTag, PRBool aCreate);
|
||||
|
||||
private:
|
||||
|
||||
// List of nsIStreamAsFileObserver's that will receive notification events
|
||||
// when the cache manager or a client desires to delete/truncate a cache
|
||||
// entry file.
|
||||
StreamAsFileObserverClosure* mObservers;
|
||||
|
||||
// Protocol-specific meta-data, opaque to the cache manager
|
||||
CacheMetaData *mMetaData;
|
||||
|
||||
// Next in chain for a single bucket in the replacement policy hash table
|
||||
// that maps from record ID to nsCachedNetData
|
||||
nsCachedNetData* mNext;
|
||||
|
||||
// See flag bits, above
|
||||
// NOTE: 16 bit member is combined with members below for
|
||||
// struct packing efficiency. Do not change order of members!
|
||||
PRUint16 mFlags;
|
||||
|
||||
protected:
|
||||
|
||||
// Number of nsCacheEntryChannels referring to this record
|
||||
PRUint8 mChannelCount;
|
||||
|
||||
// Below members are statistics kept per cache-entry, used to decide how
|
||||
// profitable it will be to evict a record from the cache relative to other
|
||||
// existing records. Note: times are measured in *seconds* since the
|
||||
// 1/1/70 epoch, same as a unix time_t.
|
||||
|
||||
// Number of accesses for this cache record
|
||||
// NOTE: 8 bit member is combined with members above for
|
||||
// struct packing efficiency. Do not change order of members!
|
||||
PRUint8 mNumAccesses;
|
||||
|
||||
// A reference to the underlying, raw cache database record, either as a
|
||||
// pointer to an in-memory object or as a database record identifier
|
||||
union {
|
||||
nsINetDataCacheRecord* mRecord;
|
||||
|
||||
// Database record ID of associated cache record. See
|
||||
// nsINetDataCache::GetRecordByID().
|
||||
PRInt32 mRecordID;
|
||||
};
|
||||
|
||||
// Weak link to parent cache
|
||||
nsINetDataCache* mCache;
|
||||
|
||||
// Length of stored content, which may be less than storage consumed if
|
||||
// compression is used
|
||||
PRUint32 mLogicalLength;
|
||||
|
||||
// Most recent cache entry access times, used to compute access frequency
|
||||
PRUint32 mAccessTime[MAX_K];
|
||||
|
||||
// We use modification time of the original document for replacement policy
|
||||
// computations, i.e. to compute a document's age, but if we don't know it,
|
||||
// we use the time that the document was last written to the cache.
|
||||
union {
|
||||
// Document modification time, if known.
|
||||
PRUint32 mLastModifiedTime;
|
||||
|
||||
// Time of last cache update for this doc
|
||||
PRUint32 mLastUpdateTime;
|
||||
};
|
||||
|
||||
union {
|
||||
// Time until which document is fresh, i.e. does not have to be validated
|
||||
// with server and, therefore, data in cache is guaranteed usable
|
||||
PRUint32 mExpirationTime;
|
||||
|
||||
// Heuristic time at which cached document is likely to be out-of-date
|
||||
// with respect to canonical copy on server. Used for cache replacement
|
||||
// policy, not for validation.
|
||||
PRUint32 mStaleTime;
|
||||
};
|
||||
|
||||
// Download time per byte, measure roughly in units of KB/s
|
||||
float mDownloadRate;
|
||||
|
||||
// Heuristic estimate of cache entry future benefits, based on above values
|
||||
float mProfit;
|
||||
};
|
||||
|
||||
#endif // _nsCachedNetData_h_
|
||||
|
||||
666
mozilla/netwerk/cache/mgr/nsReplacementPolicy.cpp
vendored
Normal file
666
mozilla/netwerk/cache/mgr/nsReplacementPolicy.cpp
vendored
Normal file
@@ -0,0 +1,666 @@
|
||||
/* -*- Mode: C++; tab-width: 4; 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 Communicator client code, released
|
||||
* March 31, 1998.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998-1999 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Scott Furman, fur@netscape.com
|
||||
*/
|
||||
|
||||
#include "nsReplacementPolicy.h"
|
||||
#include "nsCachedNetData.h"
|
||||
|
||||
#include "nsQuickSort.h"
|
||||
#include "nsIAllocator.h"
|
||||
#include "nsIEnumerator.h"
|
||||
#include "prtime.h"
|
||||
#include "prbit.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include <math.h>
|
||||
|
||||
// Constant used to estimate frequency of access to a document based on size
|
||||
#define CACHE_CONST_B 1.35
|
||||
|
||||
// A cache whose space is managed by this replacement policy
|
||||
class nsReplacementPolicy::CacheInfo {
|
||||
public:
|
||||
CacheInfo(nsINetDataCache* aCache):mCache(aCache),mNext(0) {}
|
||||
|
||||
nsINetDataCache* mCache;
|
||||
CacheInfo* mNext;
|
||||
};
|
||||
|
||||
nsReplacementPolicy::nsReplacementPolicy()
|
||||
: mRankedEntries(0), mCaches(0), mRecordsRemovedSinceLastRanking(0),
|
||||
mNumEntries(0), mCapacityRankedEntriesArray(0), mLastRankTime(0) {}
|
||||
|
||||
nsReplacementPolicy::~nsReplacementPolicy()
|
||||
{
|
||||
if (mRankedEntries)
|
||||
nsAllocator::Free(mRankedEntries);
|
||||
if (mMapRecordIdToEntry)
|
||||
nsAllocator::Free(mMapRecordIdToEntry);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsReplacementPolicy::Init(PRUint32 aMaxCacheEntries)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
rv = NS_NewHeapArena(getter_AddRefs(mArena), sizeof(nsCachedNetData) * 32);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
mMaxEntries = aMaxCacheEntries;
|
||||
|
||||
mHashArrayLength = PR_CeilingLog2(aMaxCacheEntries) >> 3;
|
||||
size_t numBytes = mHashArrayLength * sizeof(*mMapRecordIdToEntry);
|
||||
mMapRecordIdToEntry = (nsCachedNetData**)nsAllocator::Alloc(numBytes);
|
||||
if (!mMapRecordIdToEntry)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
nsCRT::zero(mMapRecordIdToEntry, numBytes);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsReplacementPolicy::AddCache(nsINetDataCache *aCache)
|
||||
{
|
||||
CacheInfo *cacheInfo = new CacheInfo(aCache);
|
||||
if (!cacheInfo)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
cacheInfo->mNext = mCaches;
|
||||
mCaches = cacheInfo;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
PRUint32
|
||||
nsReplacementPolicy::HashRecordID(PRInt32 aRecordID)
|
||||
{
|
||||
return ((aRecordID >> 16) ^ aRecordID) & (mHashArrayLength - 1);
|
||||
}
|
||||
|
||||
nsCachedNetData*
|
||||
nsReplacementPolicy::FindCacheEntryByRecordID(PRInt32 aRecordID, nsINetDataCache *aCache)
|
||||
{
|
||||
nsresult rv;
|
||||
nsCachedNetData* cacheEntry;
|
||||
PRUint32 bucket = HashRecordID(aRecordID);
|
||||
|
||||
cacheEntry = mMapRecordIdToEntry[bucket];
|
||||
for (;cacheEntry; cacheEntry = cacheEntry->mNext) {
|
||||
|
||||
PRInt32 recordID;
|
||||
rv = cacheEntry->GetRecordID(&recordID);
|
||||
if (NS_FAILED(rv))
|
||||
continue;
|
||||
|
||||
if ((recordID == aRecordID) && (cacheEntry->mCache == aCache))
|
||||
return cacheEntry;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Add a cache entry to the hash table that maps record ID to entries
|
||||
void
|
||||
nsReplacementPolicy::AddCacheEntry(nsCachedNetData* aCacheEntry, PRInt32 aRecordID)
|
||||
{
|
||||
nsCachedNetData** cacheEntryp;
|
||||
PRUint32 bucket = HashRecordID(aRecordID);
|
||||
|
||||
cacheEntryp = &mMapRecordIdToEntry[bucket];
|
||||
while (*cacheEntryp)
|
||||
cacheEntryp = &(*cacheEntryp)->mNext;
|
||||
*cacheEntryp = aCacheEntry;
|
||||
aCacheEntry->mNext = 0;
|
||||
}
|
||||
|
||||
// Delete a cache entry from the hash table that maps record ID to entries
|
||||
nsresult
|
||||
nsReplacementPolicy::DeleteCacheEntry(nsCachedNetData* aCacheEntry)
|
||||
{
|
||||
nsresult rv;
|
||||
PRInt32 recordID;
|
||||
rv = aCacheEntry->GetRecordID(&recordID);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
PRUint32 bucket = HashRecordID(recordID);
|
||||
|
||||
nsCachedNetData** cacheEntryp;
|
||||
cacheEntryp = &mMapRecordIdToEntry[bucket];
|
||||
while (*cacheEntryp) {
|
||||
if (*cacheEntryp == aCacheEntry) {
|
||||
*cacheEntryp = aCacheEntry->mNext;
|
||||
return NS_OK;
|
||||
}
|
||||
cacheEntryp = &(*cacheEntryp)->mNext;
|
||||
}
|
||||
|
||||
NS_ASSERTION(0, "hash table inconsistency");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsReplacementPolicy::AddAllRecordsInCache(nsINetDataCache *aCache)
|
||||
{
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsISimpleEnumerator> iterator;
|
||||
nsCOMPtr<nsISupports> iSupports;
|
||||
nsCOMPtr<nsINetDataCacheRecord> record;
|
||||
rv = aCache->NewCacheEntryIterator(getter_AddRefs(iterator));
|
||||
if (!NS_SUCCEEDED(rv)) return rv;
|
||||
|
||||
while (1) {
|
||||
PRBool notDone;
|
||||
|
||||
rv = iterator->HasMoreElements(¬Done);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
if (!notDone)
|
||||
break;
|
||||
|
||||
rv = iterator->GetNext(getter_AddRefs(iSupports));
|
||||
if (!NS_SUCCEEDED(rv)) return rv;
|
||||
record = do_QueryInterface(iSupports);
|
||||
|
||||
rv = AssociateCacheEntryWithRecord(record, aCache, 0);
|
||||
if (!NS_SUCCEEDED(rv)) return rv;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Get current time and convert to seconds since the epoch
|
||||
static PRUint32
|
||||
now32()
|
||||
{
|
||||
double nowFP;
|
||||
PRInt64 now64 = PR_Now();
|
||||
LL_L2D(nowFP, now64);
|
||||
PRUint32 now = (PRUint32)(nowFP * 1e-6);
|
||||
return now;
|
||||
}
|
||||
|
||||
void
|
||||
nsCachedNetData::NoteDownloadTime(PRTime start, PRTime end)
|
||||
{
|
||||
double startFP, endFP, rate, duration;
|
||||
|
||||
LL_L2D(startFP, start);
|
||||
LL_L2D(endFP, end);
|
||||
|
||||
duration = endFP - startFP;
|
||||
|
||||
// If the data arrives so fast that it can not be timed due to the clock
|
||||
// granularity, assume a data arrival duration of 10 ms
|
||||
if (!duration)
|
||||
duration = 10000;
|
||||
|
||||
// Compute download rate in kB/s
|
||||
rate = mLogicalLength / (duration * (1e-6 * 1024.0));
|
||||
|
||||
if (mDownloadRate) {
|
||||
// Exponentially smooth download rate
|
||||
const double alpha = 0.5;
|
||||
mDownloadRate = (float)(mDownloadRate * alpha + rate * (1.0 - alpha));
|
||||
} else {
|
||||
mDownloadRate = (float)rate;
|
||||
}
|
||||
}
|
||||
|
||||
// 1 hour
|
||||
#define MIN_HALFLIFE (60 * 60)
|
||||
|
||||
// 1 week
|
||||
#define TYPICAL_HALFLIFE (7 * 24 * 60 * 60)
|
||||
|
||||
/**
|
||||
* Estimate the profit that would be lost if the given cache entry was evicted
|
||||
* from the cache. Profit is defined as the future expected download delay per
|
||||
* byte of cached content. The profit computation is made based on projected
|
||||
* frequency of access, prior download performance and a heuristic staleness
|
||||
* criteria. The technique used is a variation of that described in the
|
||||
* following paper:
|
||||
*
|
||||
* "A Case for Delay-Conscious Caching of Web Documents"
|
||||
* http://www.bell-labs.com/user/rvingral/www97.html
|
||||
*
|
||||
* Briefly, expected profit is:
|
||||
*
|
||||
* (projected frequency of access) * (download time per byte) * (probability freshness)
|
||||
*/
|
||||
void
|
||||
nsCachedNetData::ComputeProfit(PRUint32 aNow)
|
||||
{
|
||||
PRUint32 K, now;
|
||||
|
||||
if (aNow)
|
||||
now = aNow;
|
||||
else
|
||||
now = now32();
|
||||
|
||||
K = PR_MIN(MAX_K, mNumAccesses);
|
||||
if (!K) {
|
||||
mProfit = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// Compute time, in seconds, since k'th most recent access
|
||||
double timeSinceKthAccess = now - mAccessTime[K - 1];
|
||||
if (timeSinceKthAccess <= 0.0) // Sanity check
|
||||
timeSinceKthAccess = 1.0;
|
||||
|
||||
// Estimate frequency of future document access based on past
|
||||
// access frequency
|
||||
double frequencyAccess = K / timeSinceKthAccess;
|
||||
|
||||
// If we don't have much historical data on access frequency
|
||||
// use a heuristic based on document size as an estimate
|
||||
if (mLogicalLength) {
|
||||
if (K == 1) {
|
||||
frequencyAccess /= pow(mLogicalLength, CACHE_CONST_B);
|
||||
} else if (K == 2) {
|
||||
frequencyAccess /= pow(mLogicalLength, CACHE_CONST_B / 2);
|
||||
}
|
||||
}
|
||||
|
||||
// Estimate likelihood that data in cache is fresh, i.e.
|
||||
// that it corresponds to the document on the server
|
||||
double probabilityFreshness;
|
||||
PRInt32 halfLife, age, docTime;
|
||||
PRBool potentiallyStale;
|
||||
|
||||
docTime = GetFlag(LAST_MODIFIED_KNOWN) ? mLastModifiedTime : mLastUpdateTime;
|
||||
age = now - docTime;
|
||||
|
||||
probabilityFreshness = 1.0; // Optimistic
|
||||
|
||||
if (GetFlag(EXPIRATION_KNOWN)) {
|
||||
potentiallyStale = now > mExpirationTime;
|
||||
halfLife = mExpirationTime - mLastModifiedTime;
|
||||
} else if (GetFlag(STALE_TIME_KNOWN)) {
|
||||
potentiallyStale = PR_TRUE;
|
||||
halfLife = mStaleTime - docTime;
|
||||
} else {
|
||||
potentiallyStale = PR_TRUE;
|
||||
halfLife = TYPICAL_HALFLIFE;
|
||||
}
|
||||
|
||||
if (potentiallyStale) {
|
||||
if (halfLife < MIN_HALFLIFE)
|
||||
halfLife = MIN_HALFLIFE;
|
||||
|
||||
probabilityFreshness = pow(0.5, (double)age / (double)halfLife);
|
||||
}
|
||||
|
||||
mProfit = (float)(frequencyAccess * probabilityFreshness);
|
||||
if (mDownloadRate)
|
||||
mProfit /= mDownloadRate;
|
||||
}
|
||||
|
||||
// Number of entries to grow mRankedEntries array when it's full
|
||||
#define STATS_GROWTH_INCREMENT 256
|
||||
|
||||
|
||||
// Sorting predicate for NS_Quicksort
|
||||
int
|
||||
nsCachedNetData::Compare(const void *a, const void *b, void *unused)
|
||||
{
|
||||
nsCachedNetData* entryA = *(nsCachedNetData**)a;
|
||||
nsCachedNetData* entryB = *(nsCachedNetData**)b;
|
||||
|
||||
// Percolate deleted or empty entries to the end of the mRankedEntries
|
||||
// array, so that they can be recycled.
|
||||
if (!entryA || entryA->GetFlag(RECYCLED)) {
|
||||
if (!entryB || entryB->GetFlag(RECYCLED))
|
||||
return 0;
|
||||
else
|
||||
return +1;
|
||||
}
|
||||
if (!entryB || entryB->GetFlag(RECYCLED))
|
||||
return -1;
|
||||
|
||||
// Evicted entries (those with no content data) and active entries (those
|
||||
// currently being updated) are collected towards the end of the sorted
|
||||
// array just prior to the deleted cache entries, since evicted entries
|
||||
// can't be re-evicted.
|
||||
if (entryA->GetFlag(UPDATE_IN_PROGRESS)) {
|
||||
if (entryB->GetFlag(UPDATE_IN_PROGRESS))
|
||||
return 0;
|
||||
else
|
||||
return +1;
|
||||
}
|
||||
if (entryB->GetFlag(UPDATE_IN_PROGRESS))
|
||||
return -1;
|
||||
|
||||
PRUint16 Ka = PR_MIN(MAX_K, entryA->mNumAccesses);
|
||||
PRUint16 Kb = PR_MIN(MAX_K, entryB->mNumAccesses);
|
||||
|
||||
// Order cache entries by the number of times they've been accessed
|
||||
if (Ka < Kb)
|
||||
return -1;
|
||||
if (Ka > Kb)
|
||||
return +1;
|
||||
|
||||
/*
|
||||
* Among records that have been accessed an equal number of times, order
|
||||
* them by profit.
|
||||
*/
|
||||
if (entryA->mProfit > entryB->mProfit)
|
||||
return +1;
|
||||
if (entryA->mProfit < entryB->mProfit)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Rank cache entries in terms of their elegibility for eviction.
|
||||
*/
|
||||
nsresult
|
||||
nsReplacementPolicy::RankRecords()
|
||||
{
|
||||
PRUint32 i, now;
|
||||
|
||||
// Add all cache records if this is the first ranking
|
||||
if (!mLastRankTime) {
|
||||
nsresult rv;
|
||||
CacheInfo *cacheInfo;
|
||||
|
||||
cacheInfo = mCaches;
|
||||
while (cacheInfo) {
|
||||
rv = AddAllRecordsInCache(cacheInfo->mCache);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
cacheInfo = cacheInfo->mNext;
|
||||
}
|
||||
}
|
||||
|
||||
// Get current time and convert to seconds since the epoch
|
||||
now = now32();
|
||||
|
||||
// Recompute profit for every known cache record, except deleted ones
|
||||
for (i = 0; i < mNumEntries; i++) {
|
||||
nsCachedNetData* entry = mRankedEntries[i];
|
||||
if (entry && !entry->GetFlag(nsCachedNetData::RECYCLED))
|
||||
entry->ComputeProfit(now);
|
||||
}
|
||||
NS_QuickSort(mRankedEntries, mNumEntries, sizeof *mRankedEntries,
|
||||
nsCachedNetData::Compare, 0);
|
||||
|
||||
mNumEntries -= mRecordsRemovedSinceLastRanking;
|
||||
mRecordsRemovedSinceLastRanking = 0;
|
||||
mLastRankTime = now;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// A heuristic policy to avoid the cost of re-ranking cache records by
|
||||
// profitability every single time space must be made available in the cache.
|
||||
void
|
||||
nsReplacementPolicy::MaybeRerankRecords()
|
||||
{
|
||||
// Rank at most once per minute
|
||||
PRUint32 now = now32();
|
||||
if ((now - mLastRankTime) >= 60)
|
||||
RankRecords();
|
||||
}
|
||||
|
||||
void
|
||||
nsReplacementPolicy::CompactRankedEntriesArray()
|
||||
{
|
||||
if (mRecordsRemovedSinceLastRanking || !mLastRankTime)
|
||||
RankRecords();
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsReplacementPolicy::CheckForTooManyCacheEntries()
|
||||
{
|
||||
if (mCapacityRankedEntriesArray == mMaxEntries) {
|
||||
return DeleteOneEntry(0);
|
||||
} else {
|
||||
nsresult rv;
|
||||
CacheInfo *cacheInfo;
|
||||
|
||||
cacheInfo = mCaches;
|
||||
while (cacheInfo) {
|
||||
PRUint32 numEntries, maxEntries;
|
||||
|
||||
rv = cacheInfo->mCache->GetNumEntries(&numEntries);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
rv = cacheInfo->mCache->GetMaxEntries(&maxEntries);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
if (numEntries == maxEntries)
|
||||
return DeleteOneEntry(cacheInfo->mCache);
|
||||
|
||||
cacheInfo = cacheInfo->mNext;
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create a new association between a low-level cache database record and a
|
||||
* cache entry. Add the entry to the set of entries eligible for eviction from
|
||||
* the cache. This would typically be done when the cache entry is created.
|
||||
*/
|
||||
nsresult
|
||||
nsReplacementPolicy::AssociateCacheEntryWithRecord(nsINetDataCacheRecord *aRecord,
|
||||
nsINetDataCache* aCache,
|
||||
nsCachedNetData** aResult)
|
||||
{
|
||||
nsCachedNetData* cacheEntry;
|
||||
nsresult rv;
|
||||
|
||||
// First, see if the record is already known to the replacement policy
|
||||
PRInt32 recordID;
|
||||
rv = aRecord->GetRecordID(&recordID);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
cacheEntry = FindCacheEntryByRecordID(recordID, aCache);
|
||||
if (cacheEntry) {
|
||||
if (aResult) {
|
||||
if (cacheEntry->GetFlag(nsCachedNetData::DORMANT))
|
||||
cacheEntry->Resurrect(aRecord);
|
||||
NS_ADDREF(cacheEntry);
|
||||
*aResult = cacheEntry;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Compact the array of cache entry statistics, so that free entries appear
|
||||
// at the end, for possible reuse.
|
||||
if (mNumEntries && (mNumEntries == mCapacityRankedEntriesArray))
|
||||
CompactRankedEntriesArray();
|
||||
|
||||
// If compaction doesn't yield available entries in the
|
||||
// mRankedEntries array, then extend the array.
|
||||
if (mNumEntries == mCapacityRankedEntriesArray) {
|
||||
PRUint32 newCapacity;
|
||||
|
||||
rv = CheckForTooManyCacheEntries();
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
newCapacity = mCapacityRankedEntriesArray + STATS_GROWTH_INCREMENT;
|
||||
if (newCapacity > mMaxEntries)
|
||||
newCapacity = mMaxEntries;
|
||||
|
||||
nsCachedNetData** newRankedEntriesArray;
|
||||
PRUint32 numBytes = sizeof(nsCachedNetData*) * newCapacity;
|
||||
newRankedEntriesArray =
|
||||
(nsCachedNetData**)nsAllocator::Realloc(mRankedEntries, numBytes);
|
||||
if (!newRankedEntriesArray)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
mRankedEntries = newRankedEntriesArray;
|
||||
mCapacityRankedEntriesArray = newCapacity;
|
||||
|
||||
PRUint32 i;
|
||||
for (i = mNumEntries; i < newCapacity; i++)
|
||||
mRankedEntries[i] = 0;
|
||||
}
|
||||
|
||||
// Recycle the record after the last in-use record in the array
|
||||
nsCachedNetData *entry = mRankedEntries[mNumEntries];
|
||||
NS_ASSERTION(!entry || !entry->GetFlag(nsCachedNetData::RECYCLED),
|
||||
"Only deleted cache entries should appear at end of array");
|
||||
|
||||
if (!entry) {
|
||||
entry = new(mArena) nsCachedNetData;
|
||||
if (!entry)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
mRankedEntries[mNumEntries] = entry;
|
||||
} else {
|
||||
// Clear out recycled data structure
|
||||
nsCRT::zero(entry, sizeof(*entry));
|
||||
}
|
||||
|
||||
entry->Init(aRecord, aCache);
|
||||
AddCacheEntry(entry, recordID);
|
||||
|
||||
// Add one reference to the cache entry from the cache manager
|
||||
NS_ADDREF(entry);
|
||||
|
||||
if (aResult) {
|
||||
// And one reference from our caller
|
||||
NS_ADDREF(entry);
|
||||
*aResult = entry;
|
||||
}
|
||||
|
||||
mNumEntries++;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsReplacementPolicy::GetCachedNetData(const char* cacheKey, PRUint32 cacheKeyLength,
|
||||
nsINetDataCache* aCache,
|
||||
nsCachedNetData** aResult)
|
||||
{
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsINetDataCacheRecord> record;
|
||||
|
||||
rv = aCache->GetCachedNetData(cacheKey, cacheKeyLength,
|
||||
getter_AddRefs(record));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
return AssociateCacheEntryWithRecord(record, aCache, aResult);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the least desirable record from the cache database. This is used
|
||||
* when the addition of another record would exceed either the cache manager or
|
||||
* the cache's maximum permitted number of records.
|
||||
*/
|
||||
nsresult
|
||||
nsReplacementPolicy::DeleteOneEntry(nsINetDataCache *aCache)
|
||||
{
|
||||
PRUint32 i;
|
||||
nsresult rv;
|
||||
nsCachedNetData *entry;
|
||||
|
||||
i = 0;
|
||||
while (1) {
|
||||
MaybeRerankRecords();
|
||||
for (; i < mNumEntries; i++) {
|
||||
entry = mRankedEntries[i];
|
||||
if (!entry || entry->GetFlag(nsCachedNetData::RECYCLED))
|
||||
continue;
|
||||
if (!aCache || (entry->mCache == aCache))
|
||||
break;
|
||||
}
|
||||
|
||||
// Report error if no record found to delete
|
||||
if (i == mNumEntries)
|
||||
return NS_ERROR_FAILURE;
|
||||
rv = entry->Delete();
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
rv = DeleteCacheEntry(entry);
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsReplacementPolicy::GetStorageInUse(PRUint32* aStorageInUse)
|
||||
{
|
||||
nsresult rv;
|
||||
CacheInfo *cacheInfo;
|
||||
|
||||
*aStorageInUse = 0;
|
||||
cacheInfo = mCaches;
|
||||
while (cacheInfo) {
|
||||
PRUint32 cacheStorage;
|
||||
rv = cacheInfo->mCache->GetStorageInUse(&cacheStorage);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
*aStorageInUse += cacheStorage;
|
||||
cacheInfo = cacheInfo->mNext;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the least desirable records from the cache until the occupancy of the
|
||||
* cache has been reduced by the given number of KB. This is used when the
|
||||
* addition of more cache data would exceed the cache's capacity.
|
||||
*/
|
||||
nsresult
|
||||
nsReplacementPolicy::Evict(PRUint32 aTargetOccupancy)
|
||||
{
|
||||
PRUint32 i;
|
||||
nsCachedNetData *entry;
|
||||
nsresult rv;
|
||||
PRUint32 occupancy;
|
||||
PRInt32 truncatedLength;
|
||||
nsCOMPtr<nsINetDataCacheRecord> record;
|
||||
|
||||
MaybeRerankRecords();
|
||||
for (i = 0; i < mNumEntries; i++) {
|
||||
rv = GetStorageInUse(&occupancy);
|
||||
if (!NS_SUCCEEDED(rv)) return rv;
|
||||
|
||||
if (occupancy <= aTargetOccupancy)
|
||||
return NS_OK;
|
||||
|
||||
entry = mRankedEntries[i];
|
||||
|
||||
// Skip deleted/empty cache entries and ones that have already been evicted
|
||||
if (!entry || entry->GetFlag(nsCachedNetData::UNEVICTABLE))
|
||||
continue;
|
||||
|
||||
if (entry->GetFlag(nsCachedNetData::ALLOW_PARTIAL)) {
|
||||
rv = entry->GetRecord(getter_AddRefs(record));
|
||||
if (NS_FAILED(rv))
|
||||
continue;
|
||||
|
||||
PRUint32 contentLength;
|
||||
rv = record->GetStoredContentLength(&contentLength);
|
||||
if (NS_FAILED(rv))
|
||||
continue;
|
||||
|
||||
// Additional cache storage required, in KB
|
||||
PRUint32 storageToReclaim = (occupancy - aTargetOccupancy) << 10;
|
||||
|
||||
truncatedLength = (PRInt32)(contentLength - storageToReclaim);
|
||||
if (truncatedLength < 0)
|
||||
truncatedLength = 0;
|
||||
} else {
|
||||
truncatedLength = 0;
|
||||
}
|
||||
rv = entry->Evict(truncatedLength);
|
||||
}
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
136
mozilla/netwerk/cache/mgr/nsReplacementPolicy.h
vendored
Normal file
136
mozilla/netwerk/cache/mgr/nsReplacementPolicy.h
vendored
Normal file
@@ -0,0 +1,136 @@
|
||||
/* -*- Mode: C++; tab-width: 4; 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 Communicator client code, released
|
||||
* March 31, 1998.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998-1999 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Scott Furman, fur@netscape.com
|
||||
*/
|
||||
|
||||
/**
|
||||
* This class manages one or more caches that share a storage resource, e.g. a
|
||||
* file cache and a flat-database cache might each occupy space on the disk and
|
||||
* they would share a single instance of nsReplacementPolicy. The replacement
|
||||
* policy heuristically chooses which cache entries to evict when storage is
|
||||
* required to accommodate incoming cache data.
|
||||
*/
|
||||
|
||||
#ifndef _nsReplacementPolicy_h_
|
||||
#define _nsReplacementPolicy_h_
|
||||
|
||||
#include "nscore.h"
|
||||
#include "nsISupportsUtils.h"
|
||||
#include "nsINetDataCache.h"
|
||||
#include "nsICachedNetData.h"
|
||||
#include "nsIArena.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsHashtable.h"
|
||||
|
||||
class nsCachedNetData;
|
||||
struct PL_HashTable;
|
||||
|
||||
/**
|
||||
* This private class is responsible for implementing the network data cache's
|
||||
* replacement policy, i.e. it decides which cache data should be evicted to
|
||||
* make room for new incoming data.
|
||||
*/
|
||||
class nsReplacementPolicy {
|
||||
|
||||
public:
|
||||
|
||||
nsReplacementPolicy();
|
||||
~nsReplacementPolicy();
|
||||
|
||||
protected:
|
||||
|
||||
nsresult Init(PRUint32 aMaxCacheEntries);
|
||||
nsresult AddCache(nsINetDataCache *aCache);
|
||||
nsresult GetCachedNetData(const char* cacheKey, PRUint32 cacheKeyLength,
|
||||
nsINetDataCache* aCache,
|
||||
nsCachedNetData** aResult);
|
||||
nsresult GetStorageInUse(PRUint32* aNumKBytes);
|
||||
|
||||
friend class nsCacheManager;
|
||||
|
||||
private:
|
||||
nsresult RankRecords();
|
||||
void MaybeRerankRecords();
|
||||
void CompactRankedEntriesArray();
|
||||
nsresult DeleteOneEntry(nsINetDataCache* aCache);
|
||||
nsresult Evict(PRUint32 aTargetOccupancy);
|
||||
|
||||
nsCachedNetData* FindCacheEntryByRecordID(PRInt32 aRecordID, nsINetDataCache *aCache);
|
||||
void AddCacheEntry(nsCachedNetData* aCacheEntry, PRInt32 aRecordID);
|
||||
nsresult DeleteCacheEntry(nsCachedNetData* aCacheEntry);
|
||||
PRUint32 HashRecordID(PRInt32 aRecordID);
|
||||
nsresult AssociateCacheEntryWithRecord(nsINetDataCacheRecord *aRecord,
|
||||
nsINetDataCache* aCache,
|
||||
nsCachedNetData** aResult);
|
||||
|
||||
nsresult AddAllRecordsInCache(nsINetDataCache *aCache);
|
||||
nsresult CheckForTooManyCacheEntries();
|
||||
|
||||
class CacheInfo;
|
||||
|
||||
private:
|
||||
|
||||
// Growable array of pointers to individual cache entries; It is sorted by
|
||||
// profitability, such that low-numbered array indices refer to cache
|
||||
// entries that are the least profitable to retain. New cache entries are
|
||||
// added to the end of the array. Deleted cache entries are specially
|
||||
// marked and percolate to the end of the array for recycling whenever
|
||||
// mRankedEntries is sorted. Evicted cache entries (those with no
|
||||
// associated content data) are retained for the purpose of improving the
|
||||
// replacement policy efficacy, and are percolated towards the end of the
|
||||
// array, just prior to the deleted cache entries.
|
||||
//
|
||||
// The array is not in sorted order 100% of the time; For efficiency
|
||||
// reasons, sorting is only done when heuristically deemed necessary.
|
||||
nsCachedNetData** mRankedEntries;
|
||||
|
||||
// Hash table buckets to map Record ID to cache entry. We use this instead
|
||||
// of a PL_HashTable to reduce storage requirements
|
||||
nsCachedNetData** mMapRecordIdToEntry;
|
||||
|
||||
// Length of mMapRecordIdToEntry array
|
||||
PRUint32 mHashArrayLength;
|
||||
|
||||
// Linked list of caches that share this replacement policy
|
||||
CacheInfo* mCaches;
|
||||
|
||||
// Allocation area for cache entry (nsCachedNetData) instances
|
||||
nsCOMPtr<nsIArena> mArena;
|
||||
|
||||
// Bookkeeping
|
||||
PRUint32 mRecordsRemovedSinceLastRanking;
|
||||
|
||||
// Maximum permitted length of mRankedEntries array
|
||||
PRUint32 mMaxEntries;
|
||||
|
||||
// Number of occupied slots in mRankedEntries array
|
||||
PRUint32 mNumEntries;
|
||||
|
||||
// Capacity of mRankedEntries array
|
||||
PRUint32 mCapacityRankedEntriesArray;
|
||||
|
||||
// Time at which cache entries were last ranked by profitability
|
||||
PRUint32 mLastRankTime;
|
||||
};
|
||||
|
||||
|
||||
#endif // _nsReplacementPolicy_h_
|
||||
43
mozilla/netwerk/cache/public/Makefile.in
vendored
Normal file
43
mozilla/netwerk/cache/public/Makefile.in
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
#
|
||||
# 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@
|
||||
|
||||
MODULE = nkcache
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
XPIDLSRCS = \
|
||||
nsICachedNetData.idl \
|
||||
nsINetDataCacheManager.idl \
|
||||
nsINetDataCache.idl \
|
||||
nsINetDataCacheRecord.idl \
|
||||
nsINetDataDiskCache.idl \
|
||||
nsIStreamAsFile.idl \
|
||||
$(NULL)
|
||||
|
||||
EXPORTS := $(addprefix $(srcdir)/, $(EXPORTS))
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
41
mozilla/netwerk/cache/public/Makefile.win
vendored
Executable file
41
mozilla/netwerk/cache/public/Makefile.win
vendored
Executable file
@@ -0,0 +1,41 @@
|
||||
#!gmake
|
||||
#
|
||||
# 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):
|
||||
|
||||
MODULE = nkcache
|
||||
|
||||
DEPTH = ..\..\..
|
||||
include <$(DEPTH)/config/config.mak>
|
||||
|
||||
|
||||
EXPORTS = \
|
||||
$(NULL)
|
||||
|
||||
XPIDLSRCS = \
|
||||
.\nsICachedNetData.idl \
|
||||
.\nsINetDataCacheManager.idl \
|
||||
.\nsINetDataCache.idl \
|
||||
.\nsINetDataCacheRecord.idl \
|
||||
.\nsINetDataDiskCache.idl \
|
||||
.\nsIStreamAsFile.idl \
|
||||
$(NULL)
|
||||
|
||||
include <$(DEPTH)/config/rules.mak>
|
||||
|
||||
229
mozilla/netwerk/cache/public/nsICachedNetData.idl
vendored
Normal file
229
mozilla/netwerk/cache/public/nsICachedNetData.idl
vendored
Normal file
@@ -0,0 +1,229 @@
|
||||
/* -*- Mode: C++; tab-width: 4; 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):
|
||||
*/
|
||||
|
||||
#include "nsrootidl.idl"
|
||||
#include "nsISupports.idl"
|
||||
|
||||
interface nsIFileSpec;
|
||||
interface nsIURI;
|
||||
interface nsIObserver;
|
||||
interface nsIChannel;
|
||||
interface nsINetDataCache;
|
||||
interface nsINetDataCacheRecord;
|
||||
interface nsILoadGroup;
|
||||
interface nsIStreamListener;
|
||||
|
||||
/**
|
||||
* The nsICachedNetData interface represents a single entry in a database that
|
||||
* caches data retrieved from the network. This interface is implemented by the
|
||||
* cache manager on top of the low-level nsINetDataCacheRecord and
|
||||
* nsINetDataCache interfaces that are implemented by the database.
|
||||
*
|
||||
* Each cache record may contain both content and metadata. The content may
|
||||
* be, for example, GIF image data or HTML, and it is accessed through
|
||||
* nsIChannel's streaming API. The opaque metadata, which may contain HTTP
|
||||
* headers among other things, is stored as a byte array. Each entry in the
|
||||
* cache is indexed by two different keys: a record id number and a key created
|
||||
* by combining the URI with a "secondary key", e.g. HTTP post data.
|
||||
*
|
||||
* @See nsINetDataCacheRecord
|
||||
* @See nsINetDataCache
|
||||
* @See nsINetDataDiskCache
|
||||
* @See nsINetDataCacheManager
|
||||
*/
|
||||
[scriptable, uuid(6aeb2a40-6d43-11d3-90c8-000064657374)]
|
||||
interface nsICachedNetData : nsISupports
|
||||
{
|
||||
/**
|
||||
* String form of the URI provided as an argument to the call to
|
||||
* nsINetDataCacheManager::GetCachedNetData() that created this record.
|
||||
*/
|
||||
readonly attribute string uriSpec;
|
||||
|
||||
/**
|
||||
* Getter for the opaque secondary database key provided as an argument to
|
||||
* the call to nsINetDataCacheManager::GetCachedNetData() that created this
|
||||
* record.
|
||||
*/
|
||||
void getSecondaryKey(out unsigned long length,
|
||||
[retval, size_is(length)] out string secondaryKey);
|
||||
|
||||
/**
|
||||
* This flag may be set by a protocol handler to indicate that it supports
|
||||
* partial fetching of data. In that case, the cache manager is permitted
|
||||
* to truncate the entry's content to accommodate incoming data for other
|
||||
* cache entries rather than deleting it wholesale.
|
||||
*/
|
||||
attribute boolean allowPartial;
|
||||
|
||||
/**
|
||||
* This flag indicates that the write stream supplying content data for the
|
||||
* cache did not complete normally and, therefore, the content may be
|
||||
* truncated.
|
||||
*/
|
||||
readonly attribute boolean partialFlag;
|
||||
|
||||
/**
|
||||
* This flag can be set and cleared by a protocol handler as a form of
|
||||
* self-notification, so as to avoid race conditions in which a protocol
|
||||
* handler issues two identical network requests to fill the same cache
|
||||
* entry. The cache manager itself largely ignores this flag.
|
||||
*/
|
||||
attribute boolean updateInProgress;
|
||||
|
||||
/**
|
||||
* inUse is set if any existing channels are associated with this cache
|
||||
* entry or if the updateInProgess flag is set. This can be used to
|
||||
* prevent writing to a cache entry by a protocol handler if it's being
|
||||
* read or written elsewhere.
|
||||
*/
|
||||
readonly attribute boolean inUse;
|
||||
|
||||
/**
|
||||
* Date/time that the document was last stored on the origin server, as
|
||||
* supplied by the protocol handler. This value is used as input to the
|
||||
* cache replacement policy, i.e. it is not used for validation. If the
|
||||
* protocol can't supply a last-modified time, this attribute should remain
|
||||
* unset. When unset, the value of this attribute is zero.
|
||||
*
|
||||
* FIXME: Should use nsIDateTime interface, once it's created
|
||||
* instead of PRTime, for improved scriptability ?
|
||||
*/
|
||||
attribute PRTime lastModifiedTime;
|
||||
|
||||
/**
|
||||
* Supplied by the protocol handler, the expirationTime attribute specifies
|
||||
* the time until which the document is guaranteed fresh, i.e. the document
|
||||
* does not have to be validated with the server and, therefore, any data
|
||||
* in cache is definitely usable. The value of this attribute serves as a
|
||||
* hint to the cache replacement policy. Only one of either staleTime or
|
||||
* expirationTime may be set for a single cache record. When unset, the
|
||||
* value of this attribute is zero.
|
||||
*/
|
||||
attribute PRTime expirationTime;
|
||||
|
||||
/**
|
||||
* Date/time supplied by the protocol handler, at which point the content
|
||||
* is *likely* to be stale, i.e. the data in the cache may be out-of-date
|
||||
* with respect to the data on the server. This heuristic date does not
|
||||
* necessarily correspond to the HTTP Expires header, as it does not
|
||||
* determine when cached network data must be validated with the origin
|
||||
* server, but only serves as a hint to the cache replacement policy. Only
|
||||
* one of either staleTime or expirationTime may be set for a single cache
|
||||
* record. When unset, the value of this attribute is zero.
|
||||
*/
|
||||
attribute PRTime staleTime;
|
||||
|
||||
/**
|
||||
* Date/time of last access of the data in this cache record, as determined
|
||||
* by the cache manager.
|
||||
*/
|
||||
readonly attribute PRTime lastAccessTime;
|
||||
|
||||
/**
|
||||
* Number of times this record has been accessed since it was first stored.
|
||||
*/
|
||||
readonly attribute PRUint16 numberAccesses;
|
||||
|
||||
/**
|
||||
* Accessor methods for opaque meta-data which can be read and updated
|
||||
* independently of the content data.
|
||||
*
|
||||
* The aTag argument can be used to accommodate multiple clients of the
|
||||
* cache API, each of which wants to store its own private meta-data into
|
||||
* the cache. For example, there could be a "headers" tag that the HTTP
|
||||
* protocol handler uses to store http response headers and a "image size"
|
||||
* tag used to store the image dimensions of a GIF file. The aData
|
||||
* argument refers to an opaque blob of arbitrary bytes.
|
||||
*
|
||||
* IMPORTANT: If aData does not contain byte-oriented data, i.e. it's not a
|
||||
* string, the contents of aData must be byte-swapped by the,
|
||||
* caller, so as to make the cache files endian-independent.
|
||||
*/
|
||||
void getAnnotation(in string aTag,
|
||||
out PRUint32 aLength, [size_is(aLength), retval] out string aData);
|
||||
void setAnnotation(in string aTag,
|
||||
in PRUint32 aLength, [size_is(aLength)] in string aData);
|
||||
|
||||
/**
|
||||
* As a getter, return the number of content bytes stored in the cache,
|
||||
* i.e. via the nsIChannel streaming APIs. This may be less than the
|
||||
* complete content length if a partial cache fill occurred. The cached
|
||||
* content can be truncated by setting the value of this attribute. The
|
||||
* value of the attribute represents a logical, not a physical, length. If
|
||||
* compression has been used, the content may consume less storage than
|
||||
* indicated by this attribute.
|
||||
*
|
||||
* When this attribute is set to zero the associated cache disk file, if
|
||||
* any, should be deleted.
|
||||
*/
|
||||
attribute PRUint32 storedContentLength;
|
||||
|
||||
/**
|
||||
* Notify any observers associated with this cache entry of the deletion
|
||||
* request. If all observers drop their reference to the cache entry,
|
||||
* proceed to delete the underlying cache database record and associated
|
||||
* content storage.
|
||||
*/
|
||||
void delete();
|
||||
|
||||
/**
|
||||
* Flush any changes in this entry's data to the cache database. This
|
||||
* method will automatically be called when the last reference to the cache
|
||||
* is dropped, but it can also be called explicitly for a synchronous
|
||||
* effect.
|
||||
*/
|
||||
void commit();
|
||||
|
||||
/**
|
||||
* Parent container cache for this entry.
|
||||
*/
|
||||
readonly attribute nsINetDataCache cache;
|
||||
|
||||
/**
|
||||
* Create a channel for reading or writing a stream of content into the
|
||||
* entry. It is expected that many of the nsIChannel methods return
|
||||
* NS_NOT_IMPLEMENTED, including:
|
||||
*
|
||||
* + GetURI()
|
||||
* + GetContentType()
|
||||
* + GetContentLength()
|
||||
*
|
||||
* Though nsIChannel provides for both async and synchronous I/O APIs, both
|
||||
* may not be implemented. Only AsyncRead() and OpenOutputStream() is
|
||||
* required. The aProxyChannel argument allows another channel to be
|
||||
* specified as the proffered argument to nsIStreamListener methods rather
|
||||
* than the cache's own channel.
|
||||
*/
|
||||
nsIChannel newChannel(in nsILoadGroup aLoadGroup,
|
||||
in nsIChannel aProxyChannel);
|
||||
|
||||
/**
|
||||
* This method can be used by a caching protocol handler to store data in
|
||||
* the cache by forking an asynchronous read stream so that it is
|
||||
* simultaneously sent to a requester and written into the cache. This
|
||||
* method implicitly sets the updateInProgress flag, if it has not already
|
||||
* been set.
|
||||
*/
|
||||
nsIStreamListener interceptAsyncRead(in nsIStreamListener aOriginalListener,
|
||||
in PRUint32 aStartOffset);
|
||||
};
|
||||
143
mozilla/netwerk/cache/public/nsINetDataCache.idl
vendored
Normal file
143
mozilla/netwerk/cache/public/nsINetDataCache.idl
vendored
Normal file
@@ -0,0 +1,143 @@
|
||||
/* -*- Mode: C++; tab-width: 4; 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):
|
||||
*/
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
interface nsIURI;
|
||||
interface nsINetDataCacheRecord;
|
||||
interface nsISimpleEnumerator;
|
||||
interface nsIFileSpec;
|
||||
|
||||
/**
|
||||
* The nsINetDataCache defines the low-level API for a network-data
|
||||
* cache, used to cache the responses to network retrieval commands.
|
||||
* This interface, along with nsINetDataCacheRecord, is implemented by
|
||||
* the memory cache, the file cache and, optionally, by some extension
|
||||
* caches. This interface is essentially a pseudo-private API for the
|
||||
* cache manager. Other clients should never use this interface.
|
||||
*
|
||||
* Each cache entry may contain both content, e.g. GIF image data, and
|
||||
* associated metadata, e.g. HTTP headers. Each entry is indexed by two
|
||||
* different keys: a record id number and a key created by combining the URI
|
||||
* with a "secondary key", e.g. HTTP post data.
|
||||
*
|
||||
* The nsINetDataCache interface is agnostic as to where the data is
|
||||
* stored and whether the storage is volatile or persistent. The
|
||||
* memory cache, any disk caches and any extension caches must all
|
||||
* implement this interface.
|
||||
*
|
||||
*/
|
||||
[scriptable, uuid(ccfc58c0-6dde-11d3-90c8-000064657374)]
|
||||
interface nsINetDataCache : nsISupports
|
||||
{
|
||||
/**
|
||||
* Human-readable description of the cache module, e.g. "Disk Cache"
|
||||
*/
|
||||
readonly attribute wstring description;
|
||||
|
||||
/**
|
||||
* Returns true if cached data is available for the given opaque key,
|
||||
* even if only partial data is stored.
|
||||
*/
|
||||
boolean contains([size_is(length)] in string key, in PRUint32 length);
|
||||
|
||||
/**
|
||||
* Fetch the cache entry record for the given opaque key. If one does not
|
||||
* exist, create a new, empty record.
|
||||
*/
|
||||
nsINetDataCacheRecord getCachedNetData([size_is(length)] in string key,
|
||||
in PRUint32 length);
|
||||
|
||||
/**
|
||||
* Fetch the cache entry record for the given URI using the record ID as a key.
|
||||
*/
|
||||
nsINetDataCacheRecord getCachedNetDataByID(in PRInt32 RecordID);
|
||||
|
||||
/**
|
||||
* False indicates that this cache is entirely bypassed.
|
||||
*/
|
||||
attribute boolean enabled;
|
||||
|
||||
/**
|
||||
* Constants for flags attribute, below
|
||||
*/
|
||||
|
||||
// Used for extension caches, e.g. a CD-ROM cache
|
||||
const long READ_ONLY = 1 << 0;
|
||||
|
||||
// One of these bits must be set
|
||||
const long MEMORY_CACHE = 1 << 1;
|
||||
const long FLAT_FILE_CACHE = 1 << 2;
|
||||
const long FILE_PER_URL_CACHE = 1 << 3;
|
||||
|
||||
/**
|
||||
* See constants defined above.
|
||||
*/
|
||||
readonly attribute PRUint32 flags;
|
||||
|
||||
/**
|
||||
* Total number of URI entries stored in the cache.
|
||||
*/
|
||||
readonly attribute PRUint32 numEntries;
|
||||
|
||||
/**
|
||||
* Maximum number of URI entries that may be stored in the cache.
|
||||
*/
|
||||
readonly attribute PRUint32 maxEntries;
|
||||
|
||||
/**
|
||||
* Enumerate the URI entries stored in the cache.
|
||||
*/
|
||||
nsISimpleEnumerator newCacheEntryIterator();
|
||||
|
||||
/**
|
||||
* Contains a reference to the next cache in search order. For the memory
|
||||
* cache, this attribute always references the disk cache. For the disk
|
||||
* cache, it contains a reference to the first extension cache.
|
||||
*/
|
||||
attribute nsINetDataCache nextCache;
|
||||
|
||||
/**
|
||||
* An estimate of the amount of storage occupied by the cache, in kB.
|
||||
* Actual use may be slightly higher than reported due to cache overhead
|
||||
* and heap fragmentation (in the memory cache) or block quantization (in
|
||||
* the disk cache).
|
||||
*/
|
||||
readonly attribute PRUint32 storageInUse;
|
||||
|
||||
/**
|
||||
* Remove all entries from a writable cache. This could be used, for
|
||||
* example, after a guest ends a browser session. This is equivalent to
|
||||
* setting the cache's Capacity to zero, except that all cache entries,
|
||||
* even those in active use, will be deleted. Also, any global cache
|
||||
* database files will be deleted.
|
||||
*/
|
||||
void removeAll();
|
||||
};
|
||||
|
||||
%{ C++
|
||||
// ProgID prefix for Components that implement this interface
|
||||
#define NS_NETWORK_CACHE_PROGID "component://netscape/network/cache"
|
||||
#define NS_NETWORK_MEMORY_CACHE_PROGID NS_NETWORK_CACHE_PROGID "?name=memory-cache"
|
||||
#define NS_NETWORK_FLAT_CACHE_PROGID NS_NETWORK_CACHE_PROGID "?name=flat-cache"
|
||||
#define NS_NETWORK_FILE_CACHE_PROGID NS_NETWORK_CACHE_PROGID "?name=file-cache"
|
||||
%}
|
||||
163
mozilla/netwerk/cache/public/nsINetDataCacheManager.idl
vendored
Normal file
163
mozilla/netwerk/cache/public/nsINetDataCacheManager.idl
vendored
Normal file
@@ -0,0 +1,163 @@
|
||||
/* -*- Mode: C++; tab-width: 4; 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):
|
||||
*/
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
interface nsISimpleEnumerator;
|
||||
interface nsICachedNetData;
|
||||
interface nsINetDataCache;
|
||||
interface nsINetDataDiskCache;
|
||||
interface nsIURI;
|
||||
interface nsIFileSpec;
|
||||
|
||||
/**
|
||||
* The network-response cache manager is partly responsible for the caching of
|
||||
* content and associated metadata that has been retrieved via the network.
|
||||
* (The remaining responsibility for caching lies with individual network
|
||||
* protocol handlers.)
|
||||
*
|
||||
* The cache manager supervises the actions of individual cache components,
|
||||
* such as the memory cache, the disk cache and any extension caches, e.g. a
|
||||
* read-only CD-ROM cache.
|
||||
*
|
||||
* @See nsINetDataCache
|
||||
* @See nsICachedNetData
|
||||
*/
|
||||
[scriptable, uuid(71c8ab00-6d5c-11d3-90c8-000064657374)]
|
||||
interface nsINetDataCacheManager : nsISupports
|
||||
{
|
||||
/**
|
||||
* Flag for the GetCachedNetData() method: If set, the memory cache is
|
||||
* neither searched nor will any data be stored into it. This might be
|
||||
* appropriate, for example, with images, because they have their own
|
||||
* cache for storing *decoded* images.
|
||||
*/
|
||||
const unsigned long BYPASS_MEMORY_CACHE = 1 << 0;
|
||||
|
||||
/**
|
||||
* Flag for the GetCachedNetData() method: If set, the disk cache
|
||||
* is neither searched nor will any be data stored into it.
|
||||
* However, read-only extension caches may be searched. This
|
||||
* might be used to avoid leaving persistent records of secure
|
||||
* data.
|
||||
*/
|
||||
const unsigned long BYPASS_PERSISTENT_CACHE = 1 << 1;
|
||||
|
||||
/**
|
||||
* Flag for the GetCachedNetData() method: If set, any stream
|
||||
* content is stored in the cache as a single disk file. Content
|
||||
* will not be cached in the memory cache nor is it cached in a
|
||||
* flat-file cache database. This is used to implement the jar
|
||||
* protocol handler and to provide the stream-as-file semantics
|
||||
* required by the classic bowser plugin API.
|
||||
*/
|
||||
const unsigned long CACHE_AS_FILE = 1 << 2;
|
||||
|
||||
/**
|
||||
* Fetch the cache entry record for the given URI. If one does not exist,
|
||||
* create a new, empty record. The normal search order for caches is:
|
||||
* + Memory cache
|
||||
* + Disk cache
|
||||
* + File cache (stream-as-file cache)
|
||||
* + All extension caches
|
||||
*
|
||||
* When writing, data is typically stored in both the memory cache and the
|
||||
* disk cache. Both the search order and this write policy can be modified by
|
||||
* setting one or more of the flag argument bits, as defined above.
|
||||
*
|
||||
* The optionally-NULL secondaryKey argument can be used, e.g. for form
|
||||
* post data or for HTTP headers in the case of HTTP.
|
||||
*/
|
||||
nsICachedNetData getCachedNetData(in string uri,
|
||||
[size_is(secondaryKeyLength)] in string secondaryKey,
|
||||
in PRUint32 secondaryKeyLength,
|
||||
in PRUint32 flags);
|
||||
|
||||
/**
|
||||
* Returns true if cached content is available for the given URI, even if
|
||||
* only partial data is stored. The flags argument behaves the same as for
|
||||
* the GetCachedNetData() method, above.
|
||||
*/
|
||||
boolean contains(in string uri,
|
||||
[size_is(secondaryKeyLength)] in string secondaryKey,
|
||||
in PRUint32 secondaryKeyLength,
|
||||
in PRUint32 flags);
|
||||
|
||||
/**
|
||||
* Total number of unexpired URI entries stored in all caches. This number
|
||||
* does not take into account duplicate URIs, e.g. because the memory cache
|
||||
* and the disk cache might each contain an entry for the same URI.
|
||||
*/
|
||||
readonly attribute PRUint32 numEntries;
|
||||
|
||||
/**
|
||||
* Enumerate the unexpired URI entries stored in all caches. Some URIs may
|
||||
* be enumerated more than once, e.g. because the the memory cache and the
|
||||
* disk cache might each contain an entry for the same URI.
|
||||
*/
|
||||
nsISimpleEnumerator newCacheEntryIterator();
|
||||
|
||||
/*
|
||||
* Enumerate all the loaded nsINetDataCache-implementing cache modules.
|
||||
* The first module enumerated will be the memory cache, the second will be
|
||||
* the disk cache, then the file cache, followed by all the extension
|
||||
* caches, in search order.
|
||||
*/
|
||||
nsISimpleEnumerator newCacheModuleIterator();
|
||||
|
||||
/**
|
||||
* Remove all entries from all writable caches. This could be used, for
|
||||
* example, after a guest ends a browser session. This is equivalent to
|
||||
* setting the DiskCacheCapacity to zero, except that all cache entries,
|
||||
* even those in active use, will be deleted. Also, any global cache
|
||||
* database files will be deleted.
|
||||
*/
|
||||
void RemoveAll();
|
||||
|
||||
/**
|
||||
* The disk cache is made up of the file cache (for stream-as-file
|
||||
* requests) and a (possibly independent) persistent cache that handles all
|
||||
* other cache requests. This attribute sets/gets the combined capacity of
|
||||
* these caches, measured in KBytes. Setting the capacity lower than the
|
||||
* current amount of space currently in use may cause cache entries to be
|
||||
* evicted from the cache to accomodate the requested capacity.
|
||||
*/
|
||||
attribute PRUint32 diskCacheCapacity;
|
||||
|
||||
/**
|
||||
* This attribute sets/gets the capacity of the memory cache, measured in
|
||||
* KBytes. Setting the capacity lower than the current amount of space
|
||||
* currently in use may cause cache entries to be evicted from the cache to
|
||||
* accomodate the requested capacity.
|
||||
*/
|
||||
attribute PRUint32 memCacheCapacity;
|
||||
|
||||
/**
|
||||
* This attribute must be set before attempting to store into the disk cache.
|
||||
*/
|
||||
attribute nsIFileSpec diskCacheFolder;
|
||||
};
|
||||
|
||||
%{ C++
|
||||
// ProgID prefix for Components that implement this interface
|
||||
#define NS_NETWORK_CACHE_MANAGER_PROGID NS_NETWORK_CACHE_PROGID "?name=manager"
|
||||
%}
|
||||
125
mozilla/netwerk/cache/public/nsINetDataCacheRecord.idl
vendored
Normal file
125
mozilla/netwerk/cache/public/nsINetDataCacheRecord.idl
vendored
Normal file
@@ -0,0 +1,125 @@
|
||||
/* -*- Mode: C++; tab-width: 4; 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):
|
||||
*/
|
||||
|
||||
#include "nsISupports.idl"
|
||||
#include "nsrootidl.idl"
|
||||
|
||||
interface nsIFileSpec;
|
||||
interface nsIChannel;
|
||||
interface nsINetDataCache;
|
||||
|
||||
/**
|
||||
* The nsINetDataCacheRecord represents a single entry in a database that
|
||||
* caches data retrieved from the network. On top of this low-level interface
|
||||
* to the raw record data, the cache manager implements a higher-level record
|
||||
* interface, nsICachedNetData. Each instance of nsINetDataCacheRecord is
|
||||
* (internally) associated with a parent database, an instance of the
|
||||
* nsINetDataCache interface. This interface is essentially a pseudo-private
|
||||
* API for the cache manager. Other clients should never use this interface.
|
||||
*
|
||||
* Each cache record may contain both content and metadata. The content may
|
||||
* be, for example, GIF image data or HTML, and it is accessed through
|
||||
* nsIChannel's streaming API. The opaque metadata, which may contain HTTP
|
||||
* headers among other things, is accessed as a contiguous byte array. Each
|
||||
* entry in the cache is indexed by two different keys: a unique record id
|
||||
* number, generated by the cache, and an opaque string. The latter contains
|
||||
* the URI and other secondary key information, e.g. HTTP form post key/value
|
||||
* pairs.
|
||||
*
|
||||
* The nsINetDataCacheRecord interface is agnostic as to where the data is
|
||||
* stored and whether the storage is volatile or persistent. The memory cache,
|
||||
* the disk cache, a flat-file cache and any read-only extension caches must
|
||||
* all implement this interface.
|
||||
*
|
||||
* @See nsICachedNetData
|
||||
* @See nsINetDataCache
|
||||
* @See nsINetDataDiskCache
|
||||
* @See nsINetDataCacheManager
|
||||
*/
|
||||
|
||||
interface nsILoadGroup;
|
||||
|
||||
[scriptable, uuid(fdcdd6a0-7461-11d3-90ca-0040056a906e)]
|
||||
interface nsINetDataCacheRecord : nsISupports
|
||||
{
|
||||
/**
|
||||
* As far as the nsINetDataCacheRecord implementation is concerned, the
|
||||
* cache entry database key is an opaque blob, but it's intended to contain
|
||||
* both the URI and any secondary keys, such as HTTP post data.
|
||||
*/
|
||||
void getKey(out unsigned long length, [size_is(length), retval] out string key);
|
||||
|
||||
/**
|
||||
* A persistent record number assigned by the cache which must be unique
|
||||
* among all entries stored within the same cache. The record ID serves as
|
||||
* an alternate key to the cache record. Providing that they satisfy the
|
||||
* afforementioned uniqueness requirement, record IDs can be assigned any
|
||||
* value by the database except that they may never be zero.
|
||||
*/
|
||||
readonly attribute PRInt32 recordID;
|
||||
|
||||
/**
|
||||
* Opaque data which can be updated for each cache entry independently of
|
||||
* the content data. This data is a combination of protocol-independent
|
||||
* data provided by the cache manager and protocol-specific meta-data,
|
||||
* e.g. HTTP headers.
|
||||
*/
|
||||
void getMetaData(out PRUint32 length, [size_is(length), retval] out string metaData);
|
||||
void setMetaData(in PRUint32 length, [size_is(length)] in string data);
|
||||
|
||||
/**
|
||||
* Number of content bytes stored in the cache, i.e. via the nsIChannel
|
||||
* streaming APIs. This may be less than the complete content length if a
|
||||
* partial cache fill occurred. Additionally, the cached content can be
|
||||
* truncated by reducing the value of this attribute. When this attribute
|
||||
* is set to zero the associated cache disk file, if any, should be
|
||||
* deleted.
|
||||
*/
|
||||
attribute PRUint32 storedContentLength;
|
||||
|
||||
/**
|
||||
* Delete this cache entry and its associated content.
|
||||
*/
|
||||
void delete();
|
||||
|
||||
/**
|
||||
* Create a channel for reading or writing a stream of content into the
|
||||
* entry. However, many of the nsIChannel methods may return
|
||||
* NS_NOT_IMPLEMENTED, including:
|
||||
*
|
||||
* + GetURI()
|
||||
* + GetContentType()
|
||||
* + GetContentLength()
|
||||
*/
|
||||
nsIChannel newChannel(in nsILoadGroup loadGroup);
|
||||
|
||||
/**
|
||||
* If a cache is implemented such that it stores each URI's content in an
|
||||
* individual disk file, this method will identify the file corresponding
|
||||
* to this record. This may be used to implement the "stream-as-file"
|
||||
* semantics required by some plugins and by the 'jar:' protocol handler.
|
||||
* However, not all cache implementations are *required* to store the data
|
||||
* from each URI in an individual file, so it is acceptable for an
|
||||
* implementation of this method to signal NS_NOT_IMPLEMENTED.
|
||||
*/
|
||||
readonly attribute nsIFileSpec filename;
|
||||
};
|
||||
42
mozilla/netwerk/cache/public/nsINetDataDiskCache.idl
vendored
Normal file
42
mozilla/netwerk/cache/public/nsINetDataDiskCache.idl
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
/* -*- Mode: C++; tab-width: 4; 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):
|
||||
*/
|
||||
|
||||
#include "nsINetDataCache.idl"
|
||||
|
||||
interface nsIFileSpec;
|
||||
|
||||
/**
|
||||
/**
|
||||
* A network-data disk cache is used to persistently cache the responses to
|
||||
* network retrieval commands. Each cache entry may contain both content,
|
||||
* e.g. GIF image data, and associated metadata, e.g. HTTP headers.
|
||||
*/
|
||||
[scriptable, uuid(6408e390-6f13-11d3-90c8-000064657374)]
|
||||
interface nsINetDataDiskCache : nsINetDataCache
|
||||
{
|
||||
/**
|
||||
* This attribute must be set before calling any other methods of this
|
||||
* interface.
|
||||
*/
|
||||
attribute nsIFileSpec diskCacheFolder;
|
||||
};
|
||||
|
||||
106
mozilla/netwerk/cache/public/nsIStreamAsFile.idl
vendored
Normal file
106
mozilla/netwerk/cache/public/nsIStreamAsFile.idl
vendored
Normal file
@@ -0,0 +1,106 @@
|
||||
/* -*- Mode: C++; tab-width: 4; 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 Communicator client code, released
|
||||
* March 31, 1998.
|
||||
*
|
||||
* 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):
|
||||
* Scott Furman, fur@netscape.com
|
||||
*/
|
||||
#include "nsrootidl.idl"
|
||||
#include "nsISupports.idl"
|
||||
|
||||
interface nsIFileSpec;
|
||||
interface nsIStreamAsFileObserver;
|
||||
|
||||
/**
|
||||
* In addition to enhancing effective network response time via caching, the
|
||||
* cache manager serves a second purpose by providing the stream-as-file
|
||||
* service required by traditional browser plugins and the jar: protocol
|
||||
* handler. The interface below provides a means for a client to determine the
|
||||
* filename associated with a stream and to detect modification/deletion of
|
||||
* that file.
|
||||
*/
|
||||
[scriptable, uuid(0eedbbf0-92d9-11d3-90d3-0040056a906e)]
|
||||
interface nsIStreamAsFile : nsISupports
|
||||
{
|
||||
/**
|
||||
* Filename containing stream-as-file
|
||||
*/
|
||||
readonly attribute nsIFileSpec fileSpec;
|
||||
|
||||
/**
|
||||
* Add an observer for this cache record. When the cache wants to delete
|
||||
* or truncate a record, so as to make space for another cache entry's
|
||||
* content data, it will call <code>aObserver</code>'s Observe() method,
|
||||
* passing the nsIStreamAsFile instance as the <code>aSubject</code>
|
||||
* argument and an appropriate message. If the observer does not wish to
|
||||
* inhibit deletion/truncation, it should Release() any references it has to the
|
||||
* cache record.
|
||||
*
|
||||
* @See nsIStreamAsFileObserver
|
||||
*/
|
||||
void addObserver(in nsIStreamAsFileObserver aObserver);
|
||||
|
||||
/**
|
||||
* Delete an observer that was added by the AddObserver() method.
|
||||
*/
|
||||
void removeObserver(in nsIStreamAsFileObserver aObserver);
|
||||
};
|
||||
|
||||
/**
|
||||
* This interface can be implemented by a client to receive notifications of
|
||||
* either modification or deletion of a file created by the cache manager using
|
||||
* the stream-as-file semantics.
|
||||
*/
|
||||
[scriptable, uuid(a26e27c0-92da-11d3-90d3-0040056a906e)]
|
||||
interface nsIStreamAsFileObserver : nsISupports
|
||||
{
|
||||
/**
|
||||
* Flag bits for argument to Observe() method.
|
||||
*/
|
||||
const long NOTIFY_AVAILABLE = 1 << 0; // Stream-as-file now available for reading
|
||||
const long NOTIFY_ERROR = 1 << 1; // Error while loading stream / creating file
|
||||
const long REQUEST_DELETION = 1 << 2; // Cache manager wishes to delete/truncate file
|
||||
const long INVALIDATE = 1 << 3; // File is out-of-date
|
||||
|
||||
// Convenience value
|
||||
const long MAKE_UNAVAILABLE = REQUEST_DELETION | INVALIDATE;
|
||||
|
||||
/**
|
||||
* Receive either a notification or a request concerning a file that has
|
||||
* been opened using stream-as-file. The aMessage and aError arguments
|
||||
* have varying values depending on the nature of the notification.
|
||||
* aMessage is set to NOTIFY_AVAILABLE when a complete stream has been read
|
||||
* and stored on disk in a file. At that point, and no sooner, may the
|
||||
* filename attribute of the associated nsIStreamAsFile be accessed via the
|
||||
* associated nsIStreamAsFile interface. If the aMessage argument is
|
||||
* NOTIFY_ERROR, the aError argument contains the relevant error code. If
|
||||
* the aMessage argument is either REQUEST_DELETION or REQUEST_TRUNCATION,
|
||||
* the callee should immediately Release() all references to the
|
||||
* nsIStreamAsFile (and any references to its associated nsICachedNetData
|
||||
* instances), unless it wishes to inhibit the requested file modification.
|
||||
* If the aMessage argument is INVALIDATE, the cache manager is replacing
|
||||
* the file with a more recent version. If a client wants to continue
|
||||
* using the (now out-of-date) file, it must delete it when it has finished,
|
||||
* as the cache manager will effectively relinquished ownership of the
|
||||
* file.
|
||||
*/
|
||||
void ObserveStreamAsFile(in nsIStreamAsFile aStreamAsFile,
|
||||
in PRUint32 aMessage,
|
||||
in nsresult aError);
|
||||
};
|
||||
39
mozilla/netwerk/makefile.win
Normal file
39
mozilla/netwerk/makefile.win
Normal file
@@ -0,0 +1,39 @@
|
||||
#!gmake
|
||||
#
|
||||
# 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 = ..
|
||||
|
||||
MODULE = necko
|
||||
|
||||
DIRS= \
|
||||
base \
|
||||
dns \
|
||||
build \
|
||||
protocol \
|
||||
socket \
|
||||
util \
|
||||
mime \
|
||||
streamconv \
|
||||
cache \
|
||||
test \
|
||||
$(NULL)
|
||||
|
||||
include <$(DEPTH)\config\rules.mak>
|
||||
32
mozilla/netwerk/protocol/http/public/nsIHTTPHeader.idl
Normal file
32
mozilla/netwerk/protocol/http/public/nsIHTTPHeader.idl
Normal file
@@ -0,0 +1,32 @@
|
||||
/* -*- Mode: IDL; tab-width: 4; 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):
|
||||
*/
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
interface nsIAtom;
|
||||
|
||||
[scriptable, uuid(a3ec67f0-465a-11d3-9a89-0080c7cb1080)]
|
||||
interface nsIHTTPHeader : nsISupports
|
||||
{
|
||||
nsIAtom GetField();
|
||||
string GetValue();
|
||||
};
|
||||
603
mozilla/netwerk/test/TestCacheMgr.cpp
Normal file
603
mozilla/netwerk/test/TestCacheMgr.cpp
Normal file
@@ -0,0 +1,603 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* 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) 1998 Netscape Communications Corporation. All Rights
|
||||
* Reserved.
|
||||
*/
|
||||
|
||||
#include "nsIStreamListener.h"
|
||||
#include "nsIStreamObserver.h"
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsIInputStream.h"
|
||||
#include "nsIOutputStream.h"
|
||||
#include "nsIEventQueue.h"
|
||||
#include "nsIEventQueueService.h"
|
||||
#include "nsIChannel.h"
|
||||
#include "nsCOMPtr.h"
|
||||
|
||||
#include "nsINetDataCache.h"
|
||||
#include "nsINetDataCacheManager.h"
|
||||
#include "nsICachedNetData.h"
|
||||
|
||||
|
||||
// Number of test entries to be placed in the cache
|
||||
// FIXME - temporary
|
||||
#define NUM_CACHE_ENTRIES 25
|
||||
|
||||
// Cache content stream length will have random length between zero and
|
||||
// MAX_CONTENT_LENGTH bytes
|
||||
#define MAX_CONTENT_LENGTH 20000
|
||||
|
||||
// Limits, converted to KB
|
||||
#define DISK_CACHE_CAPACITY ((MAX_CONTENT_LENGTH * 4) >> 10)
|
||||
#define MEM_CACHE_CAPACITY ((MAX_CONTENT_LENGTH * 3) >> 10)
|
||||
|
||||
// Length of random-data cache entry URI key
|
||||
#define CACHE_KEY_LENGTH 13
|
||||
|
||||
// Length of random-data cache entry secondary key
|
||||
#define CACHE_SECONDARY_KEY_LENGTH 10
|
||||
|
||||
// Length of random-data cache entry meta-data
|
||||
#define CACHE_PROTOCOL_PRIVATE_LENGTH 10
|
||||
|
||||
// Mapping from test case number to RecordID
|
||||
static PRInt32 recordID[NUM_CACHE_ENTRIES];
|
||||
|
||||
static PRInt32
|
||||
mapRecordIdToTestNum(PRInt32 aRecordID)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < NUM_CACHE_ENTRIES; i++) {
|
||||
if (recordID[i] == aRecordID)
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
// A supply of stream data to either store or compare with
|
||||
class nsITestDataStream {
|
||||
public:
|
||||
virtual ~nsITestDataStream() {};
|
||||
virtual PRUint32 Next() = 0;
|
||||
virtual void Read(char* aBuf, PRUint32 aCount) = 0;
|
||||
virtual void ReadString(char* aBuf, PRUint32 aCount) = 0;
|
||||
|
||||
virtual PRBool Match(char* aBuf, PRUint32 aCount) = 0;
|
||||
virtual PRBool MatchString(char* aBuf, PRUint32 aCount) = 0;
|
||||
virtual void Skip(PRUint32 aCount) = 0;
|
||||
virtual void SkipString(PRUint32 aCount) = 0;
|
||||
};
|
||||
|
||||
// A reproducible stream of random data.
|
||||
class RandomStream : public nsITestDataStream {
|
||||
public:
|
||||
RandomStream(PRUint32 aSeed) {
|
||||
mStartSeed = mState = aSeed;
|
||||
}
|
||||
|
||||
PRUint32 GetStartSeed() {
|
||||
return mStartSeed;
|
||||
}
|
||||
|
||||
PRUint32 Next() {
|
||||
mState = 1103515245 * mState + 12345 ^ (mState >> 16);
|
||||
return mState;
|
||||
}
|
||||
|
||||
PRUint8 NextChar() {
|
||||
PRUint8 c;
|
||||
do {
|
||||
c = Next();
|
||||
} while (!isalnum(c));
|
||||
return c;
|
||||
}
|
||||
|
||||
void Read(char* aBuf, PRUint32 aCount) {
|
||||
PRUint32 i;
|
||||
for (i = 0; i < aCount; i++) {
|
||||
*aBuf++ = Next();
|
||||
}
|
||||
}
|
||||
|
||||
// Same as Read(), but using only printable chars and
|
||||
// with a terminating NUL
|
||||
void ReadString(char* aBuf, PRUint32 aCount) {
|
||||
PRUint32 i;
|
||||
for (i = 0; i < aCount; i++) {
|
||||
*aBuf++ = NextChar();
|
||||
}
|
||||
*aBuf = 0;
|
||||
}
|
||||
|
||||
PRBool
|
||||
Match(char* aBuf, PRUint32 aCount) {
|
||||
PRUint32 i;
|
||||
for (i = 0; i < aCount; i++) {
|
||||
if (*aBuf++ != (char)(Next() & 0xff))
|
||||
return PR_FALSE;
|
||||
}
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
PRBool
|
||||
MatchString(char* aBuf, PRUint32 aCount) {
|
||||
PRUint32 i;
|
||||
for (i = 0; i < aCount; i++) {
|
||||
if (*aBuf++ != (char)(NextChar() & 0xff))
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
// Check for terminating NUL character
|
||||
if (*aBuf)
|
||||
return PR_FALSE;
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
Skip(PRUint32 aCount) {
|
||||
while (aCount--)
|
||||
Next();
|
||||
}
|
||||
|
||||
void
|
||||
SkipString(PRUint32 aCount) {
|
||||
while (aCount--)
|
||||
NextChar();
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
PRUint32 mState;
|
||||
PRUint32 mStartSeed;
|
||||
};
|
||||
|
||||
static int gNumReaders = 0;
|
||||
static PRUint32 gTotalBytesRead = 0;
|
||||
static PRUint32 gTotalBytesWritten = 0;
|
||||
static PRUint32 gTotalDuration = 0;
|
||||
|
||||
class nsReader : public nsIStreamListener {
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
nsReader()
|
||||
: mStartTime(0), mBytesRead(0)
|
||||
{
|
||||
NS_INIT_REFCNT();
|
||||
gNumReaders++;
|
||||
}
|
||||
|
||||
virtual ~nsReader() {
|
||||
delete mTestDataStream;
|
||||
gNumReaders--;
|
||||
}
|
||||
|
||||
nsresult
|
||||
Init(nsITestDataStream* aRandomStream, PRUint32 aExpectedStreamLength) {
|
||||
mTestDataStream = aRandomStream;
|
||||
mExpectedStreamLength = aExpectedStreamLength;
|
||||
mRefCnt = 1;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD OnStartRequest(nsIChannel* channel,
|
||||
nsISupports* context) {
|
||||
mStartTime = PR_IntervalNow();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD OnDataAvailable(nsIChannel* channel,
|
||||
nsISupports* context,
|
||||
nsIInputStream *aIStream,
|
||||
PRUint32 aSourceOffset,
|
||||
PRUint32 aLength) {
|
||||
char buf[1025];
|
||||
while (aLength > 0) {
|
||||
PRUint32 amt;
|
||||
PRBool match;
|
||||
aIStream->Read(buf, sizeof buf, &amt);
|
||||
if (amt == 0) break;
|
||||
aLength -= amt;
|
||||
mBytesRead += amt;
|
||||
match = mTestDataStream->Match(buf, amt);
|
||||
NS_ASSERTION(match, "Stored data was corrupted on read");
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD OnStopRequest(nsIChannel* channel,
|
||||
nsISupports* context,
|
||||
nsresult aStatus,
|
||||
const PRUnichar* aMsg) {
|
||||
PRIntervalTime endTime;
|
||||
PRIntervalTime duration;
|
||||
|
||||
endTime = PR_IntervalNow();
|
||||
duration = (endTime - mStartTime);
|
||||
|
||||
if (NS_FAILED(aStatus)) printf("channel failed.\n");
|
||||
// printf("read %d bytes\n", mBytesRead);
|
||||
|
||||
//FIXME NS_ASSERTION(mBytesRead == mExpectedStreamLength,
|
||||
// "Stream in cache is wrong length");
|
||||
|
||||
gTotalBytesRead += mBytesRead;
|
||||
gTotalDuration += duration;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
protected:
|
||||
PRIntervalTime mStartTime;
|
||||
PRUint32 mBytesRead;
|
||||
nsITestDataStream* mTestDataStream;
|
||||
PRUint32 mExpectedStreamLength;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS2(nsReader, nsIStreamListener, nsIStreamObserver)
|
||||
|
||||
static nsIEventQueue* eventQueue;
|
||||
|
||||
static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID);
|
||||
|
||||
nsresult
|
||||
InitQueue() {
|
||||
nsresult rv;
|
||||
|
||||
NS_WITH_SERVICE(nsIEventQueueService, eventQService, kEventQueueServiceCID, &rv);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get event queue service");
|
||||
|
||||
rv = eventQService->CreateThreadEventQueue();
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't create event queue");
|
||||
|
||||
rv = eventQService->GetThreadEventQueue(PR_CurrentThread(), &eventQueue);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get event queue for main thread");
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Process events until all streams are OnStopRequest'ed
|
||||
nsresult
|
||||
WaitForEvents() {
|
||||
while (gNumReaders) {
|
||||
eventQueue->ProcessPendingEvents();
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Read data for a single cache record and compare against testDataStream
|
||||
nsresult
|
||||
TestReadStream(nsICachedNetData *cacheEntry, nsITestDataStream *testDataStream,
|
||||
PRUint32 expectedStreamLength)
|
||||
{
|
||||
nsCOMPtr<nsIChannel> channel;
|
||||
nsresult rv;
|
||||
PRUint32 actualContentLength;
|
||||
|
||||
rv = cacheEntry->NewChannel(0, 0, getter_AddRefs(channel));
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
|
||||
|
||||
rv = cacheEntry->GetStoredContentLength(&actualContentLength);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
|
||||
// FIXME NS_ASSERTION(actualContentLength == expectedStreamLength,
|
||||
// "nsICachedNetData::GetContentLength() busted ?");
|
||||
|
||||
nsReader *reader = new nsReader;
|
||||
reader->AddRef();
|
||||
rv = reader->Init(testDataStream, expectedStreamLength);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
|
||||
|
||||
rv = channel->AsyncRead(0, -1, 0, reader);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
|
||||
reader->Release();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Convert PRTime to unix-style time_t, i.e. seconds since the epoch
|
||||
static PRUint32
|
||||
convertPRTimeToSeconds(PRTime aTime64)
|
||||
{
|
||||
double fpTime;
|
||||
LL_L2D(fpTime, aTime64);
|
||||
return (PRUint32)(fpTime * 1e-6 + 0.5);
|
||||
}
|
||||
|
||||
// Convert unix-style time_t, i.e. seconds since the epoch, to PRTime
|
||||
static PRTime
|
||||
convertSecondsToPRTime(PRUint32 aSeconds)
|
||||
{
|
||||
PRInt64 t64;
|
||||
LL_L2I(t64, aSeconds);
|
||||
LL_MUL(t64, t64, 1000000);
|
||||
return t64;
|
||||
}
|
||||
|
||||
// Read the test data that was written in FillCache(), checking for
|
||||
// corruption, truncation.
|
||||
nsresult
|
||||
TestRead(nsINetDataCacheManager *aCache, PRUint32 aFlags)
|
||||
{
|
||||
nsresult rv;
|
||||
PRBool inCache;
|
||||
nsCOMPtr<nsICachedNetData> cacheEntry;
|
||||
RandomStream *randomStream;
|
||||
char uriCacheKey[CACHE_KEY_LENGTH];
|
||||
char secondaryCacheKey[CACHE_SECONDARY_KEY_LENGTH];
|
||||
char *storedUriKey;
|
||||
PRUint32 testNum;
|
||||
|
||||
gTotalBytesRead = 0;
|
||||
gTotalDuration = 0;
|
||||
for (testNum = 0; testNum < NUM_CACHE_ENTRIES; testNum++) {
|
||||
randomStream = new RandomStream(testNum);
|
||||
randomStream->ReadString(uriCacheKey, sizeof uriCacheKey - 1);
|
||||
randomStream->Read(secondaryCacheKey, sizeof secondaryCacheKey);
|
||||
|
||||
// Ensure that entry is in the cache
|
||||
rv = aCache->Contains(uriCacheKey,
|
||||
secondaryCacheKey, sizeof secondaryCacheKey,
|
||||
aFlags, &inCache);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
|
||||
NS_ASSERTION(inCache, "nsINetDataCacheManager::Contains error");
|
||||
|
||||
rv = aCache->GetCachedNetData(uriCacheKey,
|
||||
secondaryCacheKey, sizeof secondaryCacheKey,
|
||||
aFlags,
|
||||
getter_AddRefs(cacheEntry));
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
|
||||
|
||||
// Test GetUriSpec() method
|
||||
rv = cacheEntry->GetUriSpec(&storedUriKey);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv) &&
|
||||
!memcmp(storedUriKey, &uriCacheKey[0], sizeof uriCacheKey),
|
||||
"nsICachedNetData::GetKey failed");
|
||||
nsAllocator::Free(storedUriKey);
|
||||
|
||||
// Test GetSecondaryKey() method
|
||||
PRUint32 storedSecondaryKeyLength;
|
||||
char* storedSecondaryKey;
|
||||
rv = cacheEntry->GetSecondaryKey(&storedSecondaryKeyLength, &storedSecondaryKey);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv) &&
|
||||
!memcmp(storedSecondaryKey, &secondaryCacheKey[0],
|
||||
sizeof secondaryCacheKey),
|
||||
"nsICachedNetData::GetSecondaryKey failed");
|
||||
|
||||
// Compare against stored protocol data
|
||||
char *storedProtocolData;
|
||||
PRUint32 storedProtocolDataLength;
|
||||
rv = cacheEntry->GetAnnotation("test data", &storedProtocolDataLength, &storedProtocolData);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv) &&
|
||||
storedProtocolDataLength == CACHE_PROTOCOL_PRIVATE_LENGTH,
|
||||
"nsICachedNetData::GetAnnotation() failed");
|
||||
randomStream->Match(storedProtocolData, storedProtocolDataLength);
|
||||
|
||||
// Test GetAllowPartial()
|
||||
PRBool allowPartial;
|
||||
rv = cacheEntry->GetAllowPartial(&allowPartial);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv) &&
|
||||
(allowPartial == (PRBool)(randomStream->Next() & 1)),
|
||||
"nsICachedNetData::GetAllowPartial() failed");
|
||||
|
||||
// Test GetExpirationTime()
|
||||
PRTime expirationTime;
|
||||
PRTime expectedExpirationTime = convertSecondsToPRTime(randomStream->Next() & 0xffffff);
|
||||
rv = cacheEntry->GetExpirationTime(&expirationTime);
|
||||
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv) && LL_EQ(expirationTime, expectedExpirationTime),
|
||||
"nsICachedNetData::GetExpirationTime() failed");
|
||||
|
||||
PRUint32 expectedStreamLength = randomStream->Next() % MAX_CONTENT_LENGTH;
|
||||
|
||||
TestReadStream(cacheEntry, randomStream, expectedStreamLength);
|
||||
}
|
||||
|
||||
WaitForEvents();
|
||||
|
||||
// Compute rate in MB/s
|
||||
double rate = gTotalBytesRead / PR_IntervalToMilliseconds(gTotalDuration);
|
||||
rate *= NUM_CACHE_ENTRIES;
|
||||
rate *= 1000;
|
||||
rate /= (1024 * 1024);
|
||||
printf("Read %7d bytes at a rate of %5.1f MB per second \n",
|
||||
gTotalBytesRead, rate);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Create entries in the network data cache, using random data for the
|
||||
// key, the meta-data and the stored content data.
|
||||
nsresult
|
||||
FillCache(nsINetDataCacheManager *aCache, PRUint32 aFlags, PRUint32 aCacheCapacity)
|
||||
{
|
||||
nsresult rv;
|
||||
PRBool inCache;
|
||||
nsCOMPtr<nsICachedNetData> cacheEntry;
|
||||
nsCOMPtr<nsIChannel> channel;
|
||||
nsCOMPtr<nsIOutputStream> outStream;
|
||||
nsCOMPtr<nsINetDataCache> containingCache;
|
||||
char buf[1000];
|
||||
PRUint32 protocolDataLength;
|
||||
char cacheKey[CACHE_KEY_LENGTH];
|
||||
char secondaryCacheKey[CACHE_SECONDARY_KEY_LENGTH];
|
||||
char protocolData[CACHE_PROTOCOL_PRIVATE_LENGTH];
|
||||
PRUint32 testNum;
|
||||
RandomStream *randomStream;
|
||||
|
||||
gTotalBytesWritten = 0;
|
||||
PRIntervalTime startTime = PR_IntervalNow();
|
||||
|
||||
for (testNum = 0; testNum < NUM_CACHE_ENTRIES; testNum++) {
|
||||
randomStream = new RandomStream(testNum);
|
||||
randomStream->ReadString(cacheKey, sizeof cacheKey - 1);
|
||||
randomStream->Read(secondaryCacheKey, sizeof secondaryCacheKey);
|
||||
|
||||
// No entry should be in cache until we add it
|
||||
rv = aCache->Contains(cacheKey,
|
||||
secondaryCacheKey, sizeof secondaryCacheKey,
|
||||
aFlags, &inCache);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
|
||||
NS_ASSERTION(!inCache, "nsINetDataCacheManager::Contains error");
|
||||
|
||||
rv = aCache->GetCachedNetData(cacheKey,
|
||||
secondaryCacheKey, sizeof secondaryCacheKey,
|
||||
aFlags,
|
||||
getter_AddRefs(cacheEntry));
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't access cacheEntry via cache key");
|
||||
|
||||
// Test nsINetDataCacheManager::GetNumEntries()
|
||||
PRUint32 numEntries = (PRUint32)-1;
|
||||
rv = aCache->GetNumEntries(&numEntries);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get number of cache entries");
|
||||
NS_ASSERTION(numEntries == testNum + 1, "GetNumEntries failure");
|
||||
|
||||
// Record meta-data should be initially empty
|
||||
char *protocolDatap;
|
||||
rv = cacheEntry->GetAnnotation("test data", &protocolDataLength, &protocolDatap);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
|
||||
if ((protocolDataLength != 0) || (protocolDatap != 0))
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
// Store random data as meta-data
|
||||
randomStream->Read(protocolData, sizeof protocolData);
|
||||
cacheEntry->SetAnnotation("test data", sizeof protocolData, protocolData);
|
||||
|
||||
// Store random data as allow-partial flag
|
||||
PRBool allowPartial = randomStream->Next() & 1;
|
||||
rv = cacheEntry->SetAllowPartial(allowPartial);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv),
|
||||
"nsICachedNetData::SetAllowPartial() failed");
|
||||
|
||||
// Store random data as expiration time
|
||||
PRTime expirationTime = convertSecondsToPRTime(randomStream->Next() & 0xffffff);
|
||||
rv = cacheEntry->SetExpirationTime(expirationTime);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv),
|
||||
"nsICachedNetData::SetExpirationTime() failed");
|
||||
|
||||
// Cache manager complains if expiration set without setting last-modified time
|
||||
rv = cacheEntry->SetLastModifiedTime(expirationTime);
|
||||
|
||||
rv = cacheEntry->NewChannel(0, 0, getter_AddRefs(channel));
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
|
||||
|
||||
rv = cacheEntry->GetCache(getter_AddRefs(containingCache));
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
|
||||
|
||||
rv = channel->OpenOutputStream(0, getter_AddRefs(outStream));
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
|
||||
|
||||
int streamLength = randomStream->Next() % MAX_CONTENT_LENGTH;
|
||||
int remaining = streamLength;
|
||||
while (remaining) {
|
||||
PRUint32 numWritten;
|
||||
int amount = PR_MIN(sizeof buf, remaining);
|
||||
randomStream->Read(buf, amount);
|
||||
|
||||
rv = outStream->Write(buf, amount, &numWritten);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
|
||||
NS_ASSERTION(numWritten == (PRUint32)amount, "Write() bug?");
|
||||
|
||||
remaining -= amount;
|
||||
|
||||
PRUint32 storageInUse;
|
||||
rv = containingCache->GetStorageInUse(&storageInUse);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv) && (storageInUse <= aCacheCapacity),
|
||||
"Cache manager failed to limit cache growth");
|
||||
}
|
||||
outStream->Close();
|
||||
gTotalBytesWritten += streamLength;
|
||||
|
||||
// *Now* there should be an entry in the cache
|
||||
rv = aCache->Contains(cacheKey,
|
||||
secondaryCacheKey, sizeof secondaryCacheKey,
|
||||
aFlags, &inCache);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
|
||||
NS_ASSERTION(inCache, "nsINetDataCacheManager::Contains error");
|
||||
|
||||
delete randomStream;
|
||||
}
|
||||
|
||||
PRIntervalTime endTime = PR_IntervalNow();
|
||||
|
||||
// Compute rate in MB/s
|
||||
double rate = gTotalBytesWritten / PR_IntervalToMilliseconds(endTime - startTime);
|
||||
rate *= 1000;
|
||||
rate /= (1024 * 1024);
|
||||
printf("Wrote %7d bytes at a rate of %5.1f MB per second \n",
|
||||
gTotalBytesWritten, rate);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult NS_AutoregisterComponents()
|
||||
{
|
||||
nsresult rv = nsComponentManager::AutoRegister(nsIComponentManager::NS_Startup,
|
||||
NULL /* default */);
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult
|
||||
Test(nsINetDataCacheManager *aCache, PRUint32 aFlags, PRUint32 aCacheCapacity)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
rv = aCache->RemoveAll();
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't clear cache");
|
||||
|
||||
PRUint32 numEntries = (PRUint32)-1;
|
||||
rv = aCache->GetNumEntries(&numEntries);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get number of cache entries");
|
||||
NS_ASSERTION(numEntries == 0, "Couldn't clear cache");
|
||||
|
||||
rv = FillCache(aCache, aFlags, aCacheCapacity);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't fill cache with random test data");
|
||||
|
||||
rv = TestRead(aCache, aFlags);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't read random test data from cache");
|
||||
|
||||
rv = aCache->RemoveAll();
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't clear cache");
|
||||
|
||||
rv = aCache->GetNumEntries(&numEntries);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get number of cache entries");
|
||||
NS_ASSERTION(numEntries == 0, "Couldn't clear cache");
|
||||
|
||||
return 0;
|
||||
}
|
||||
int
|
||||
main(int argc, char* argv[])
|
||||
{
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsINetDataCacheManager> cache;
|
||||
|
||||
rv = NS_AutoregisterComponents();
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't register XPCOM components");
|
||||
|
||||
rv = nsComponentManager::CreateInstance(NS_NETWORK_CACHE_MANAGER_PROGID,
|
||||
nsnull,
|
||||
NS_GET_IID(nsINetDataCacheManager),
|
||||
getter_AddRefs(cache));
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't create cache manager factory") ;
|
||||
|
||||
cache->SetDiskCacheCapacity(DISK_CACHE_CAPACITY);
|
||||
cache->SetMemCacheCapacity(MEM_CACHE_CAPACITY);
|
||||
|
||||
InitQueue();
|
||||
|
||||
Test(cache, nsINetDataCacheManager::BYPASS_PERSISTENT_CACHE, MEM_CACHE_CAPACITY);
|
||||
Test(cache, nsINetDataCacheManager::BYPASS_MEMORY_CACHE, DISK_CACHE_CAPACITY);
|
||||
return 0;
|
||||
}
|
||||
|
||||
820
mozilla/netwerk/test/TestRawCache.cpp
Normal file
820
mozilla/netwerk/test/TestRawCache.cpp
Normal file
@@ -0,0 +1,820 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* 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) 1998 Netscape Communications Corporation. All Rights
|
||||
* Reserved.
|
||||
*/
|
||||
|
||||
#include "nsIStreamListener.h"
|
||||
#include "nsIStreamObserver.h"
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsIInputStream.h"
|
||||
#include "nsIOutputStream.h"
|
||||
#include "nsIEventQueue.h"
|
||||
#include "nsIEventQueueService.h"
|
||||
#include "nsIChannel.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsString.h"
|
||||
#include <stdio.h>
|
||||
|
||||
#include "nsINetDataCache.h"
|
||||
#include "nsINetDataDiskCache.h"
|
||||
#include "nsINetDataCacheRecord.h"
|
||||
#include "nsMemCacheCID.h"
|
||||
// file cache include
|
||||
#include "nsNetDiskCacheCID.h"
|
||||
#include "nsIPref.h"
|
||||
#include "prenv.h"
|
||||
#include "nsIFileStream.h"
|
||||
|
||||
|
||||
// Number of test entries to be placed in the cache
|
||||
#define NUM_CACHE_ENTRIES 250
|
||||
|
||||
// Cache content stream length will have random length between zero and
|
||||
// MAX_CONTENT_LENGTH bytes
|
||||
#define MAX_CONTENT_LENGTH 20000
|
||||
|
||||
// Length of random-data cache entry key
|
||||
#define CACHE_KEY_LENGTH 15
|
||||
|
||||
// Length of random-data cache entry meta-data
|
||||
#define CACHE_METADATA_LENGTH 100
|
||||
|
||||
static NS_DEFINE_CID(kMemCacheCID, NS_MEM_CACHE_FACTORY_CID);
|
||||
static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID);
|
||||
|
||||
// file cache cid
|
||||
static NS_DEFINE_CID(kDiskCacheCID, NS_NETDISKCACHE_CID) ;
|
||||
static NS_DEFINE_CID(kPrefCID, NS_PREF_CID);
|
||||
static NS_DEFINE_IID(kIPrefIID, NS_IPREF_IID);
|
||||
|
||||
// Mapping from test case number to RecordID
|
||||
static PRInt32 recordID[NUM_CACHE_ENTRIES];
|
||||
|
||||
static PRInt32
|
||||
mapRecordIdToTestNum(PRInt32 aRecordID)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < NUM_CACHE_ENTRIES; i++) {
|
||||
if (recordID[i] == aRecordID)
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
// A supply of stream data to either store or compare with
|
||||
class nsITestDataStream {
|
||||
public:
|
||||
virtual ~nsITestDataStream() {};
|
||||
virtual PRUint32 Next() = 0;
|
||||
virtual void Read(char* aBuf, PRUint32 aCount) = 0;
|
||||
|
||||
virtual PRBool Match(char* aBuf, PRUint32 aCount) = 0;
|
||||
virtual void Skip(PRUint32 aCount) = 0;
|
||||
};
|
||||
|
||||
// A reproducible stream of random data.
|
||||
class RandomStream : public nsITestDataStream {
|
||||
public:
|
||||
RandomStream(PRUint32 aSeed) {
|
||||
mStartSeed = mState = aSeed;
|
||||
}
|
||||
|
||||
PRUint32 GetStartSeed() {
|
||||
return mStartSeed;
|
||||
}
|
||||
|
||||
PRUint32 Next() {
|
||||
mState = 1103515245 * mState + 12345;
|
||||
return mState;
|
||||
}
|
||||
|
||||
void Read(char* aBuf, PRUint32 aCount) {
|
||||
PRUint32 i;
|
||||
for (i = 0; i < aCount; i++) {
|
||||
*aBuf++ = Next();
|
||||
}
|
||||
}
|
||||
|
||||
PRBool
|
||||
Match(char* aBuf, PRUint32 aCount) {
|
||||
PRUint32 i;
|
||||
for (i = 0; i < aCount; i++) {
|
||||
if (*aBuf++ != (char)(Next() & 0xff))
|
||||
return PR_FALSE;
|
||||
}
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
Skip(PRUint32 aCount) {
|
||||
while (aCount--)
|
||||
Next();
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
PRUint32 mState;
|
||||
PRUint32 mStartSeed;
|
||||
};
|
||||
|
||||
// A stream of data that increments on each byte that is read, modulo 256
|
||||
class CounterStream : public nsITestDataStream {
|
||||
public:
|
||||
CounterStream(PRUint32 aSeed) {
|
||||
mStartSeed = mState = aSeed;
|
||||
}
|
||||
|
||||
PRUint32 GetStartSeed() {
|
||||
return mStartSeed;
|
||||
}
|
||||
|
||||
PRUint32 Next() {
|
||||
mState += 1;
|
||||
mState &= 0xff;
|
||||
return mState;
|
||||
}
|
||||
|
||||
void Read(char* aBuf, PRUint32 aCount) {
|
||||
PRUint32 i;
|
||||
for (i = 0; i < aCount; i++) {
|
||||
*aBuf++ = Next();
|
||||
}
|
||||
}
|
||||
|
||||
PRBool
|
||||
Match(char* aBuf, PRUint32 aCount) {
|
||||
PRUint32 i;
|
||||
for (i = 0; i < aCount; i++) {
|
||||
if (*aBuf++ != (char)Next())
|
||||
return PR_FALSE;
|
||||
}
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
Skip(PRUint32 aCount) {
|
||||
mState += aCount;
|
||||
mState &= 0xff;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
PRUint32 mState;
|
||||
PRUint32 mStartSeed;
|
||||
};
|
||||
|
||||
static int gNumReaders = 0;
|
||||
static PRUint32 gTotalBytesRead = 0;
|
||||
static PRUint32 gTotalDuration = 0;
|
||||
|
||||
class nsReader : public nsIStreamListener {
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
nsReader()
|
||||
: mStartTime(0), mBytesRead(0)
|
||||
{
|
||||
NS_INIT_REFCNT();
|
||||
gNumReaders++;
|
||||
}
|
||||
|
||||
virtual ~nsReader() {
|
||||
delete mTestDataStream;
|
||||
gNumReaders--;
|
||||
}
|
||||
|
||||
nsresult
|
||||
Init(nsITestDataStream* aRandomStream, PRUint32 aExpectedStreamLength) {
|
||||
mTestDataStream = aRandomStream;
|
||||
mExpectedStreamLength = aExpectedStreamLength;
|
||||
mRefCnt = 1;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD OnStartRequest(nsIChannel* channel,
|
||||
nsISupports* context) {
|
||||
mStartTime = PR_IntervalNow();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD OnDataAvailable(nsIChannel* channel,
|
||||
nsISupports* context,
|
||||
nsIInputStream *aIStream,
|
||||
PRUint32 aSourceOffset,
|
||||
PRUint32 aLength) {
|
||||
char buf[1025];
|
||||
while (aLength > 0) {
|
||||
PRUint32 amt;
|
||||
PRBool match;
|
||||
aIStream->Read(buf, sizeof buf, &amt);
|
||||
if (amt == 0) break;
|
||||
aLength -= amt;
|
||||
mBytesRead += amt;
|
||||
match = mTestDataStream->Match(buf, amt);
|
||||
NS_ASSERTION(match, "Stored data was corrupted on read");
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD OnStopRequest(nsIChannel* channel,
|
||||
nsISupports* context,
|
||||
nsresult aStatus,
|
||||
const PRUnichar* aMsg) {
|
||||
PRIntervalTime endTime;
|
||||
PRIntervalTime duration;
|
||||
|
||||
endTime = PR_IntervalNow();
|
||||
duration = (endTime - mStartTime);
|
||||
|
||||
if (NS_FAILED(aStatus)) printf("channel failed.\n");
|
||||
// printf("read %d bytes\n", mBytesRead);
|
||||
|
||||
NS_ASSERTION(mBytesRead == mExpectedStreamLength,
|
||||
"Stream in cache is wrong length");
|
||||
|
||||
gTotalBytesRead += mBytesRead;
|
||||
gTotalDuration += duration;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
protected:
|
||||
PRIntervalTime mStartTime;
|
||||
PRUint32 mBytesRead;
|
||||
nsITestDataStream* mTestDataStream;
|
||||
PRUint32 mExpectedStreamLength;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS2(nsReader, nsIStreamListener, nsIStreamObserver)
|
||||
|
||||
static nsIEventQueue* eventQueue;
|
||||
|
||||
nsresult
|
||||
InitQueue() {
|
||||
nsresult rv;
|
||||
|
||||
NS_WITH_SERVICE(nsIEventQueueService, eventQService, kEventQueueServiceCID, &rv);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get event queue service");
|
||||
|
||||
rv = eventQService->CreateThreadEventQueue();
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't create event queue");
|
||||
|
||||
rv = eventQService->GetThreadEventQueue(PR_CurrentThread(), &eventQueue);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get event queue for main thread");
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Process events until all streams are OnStopRequest'ed
|
||||
nsresult
|
||||
WaitForEvents() {
|
||||
while (gNumReaders) {
|
||||
eventQueue->ProcessPendingEvents();
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Read data for a single cache record and compare against testDataStream
|
||||
nsresult
|
||||
TestReadStream(nsINetDataCacheRecord *record, nsITestDataStream *testDataStream,
|
||||
PRUint32 expectedStreamLength)
|
||||
{
|
||||
nsCOMPtr<nsIChannel> channel;
|
||||
nsresult rv;
|
||||
PRUint32 actualContentLength;
|
||||
|
||||
rv = record->NewChannel(0, getter_AddRefs(channel));
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
|
||||
|
||||
rv = record->GetStoredContentLength(&actualContentLength);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
|
||||
NS_ASSERTION(actualContentLength == expectedStreamLength,
|
||||
"nsINetDataCacheRecord::GetContentLength() busted ?");
|
||||
|
||||
nsReader *reader = new nsReader;
|
||||
rv = reader->Init(testDataStream, expectedStreamLength);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
|
||||
|
||||
rv = channel->AsyncRead(0, -1, 0, reader);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
|
||||
reader->Release();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Check that records can be retrieved using their record-ID, in addition
|
||||
// to using the opaque key.
|
||||
nsresult
|
||||
TestRecordID(nsINetDataCache *cache)
|
||||
{
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsINetDataCacheRecord> record;
|
||||
RandomStream *randomStream;
|
||||
PRUint32 metaDataLength;
|
||||
char cacheKey[CACHE_KEY_LENGTH];
|
||||
char *metaData;
|
||||
PRUint32 testNum;
|
||||
PRBool match;
|
||||
|
||||
for (testNum = 0; testNum < NUM_CACHE_ENTRIES; testNum++) {
|
||||
randomStream = new RandomStream(testNum);
|
||||
randomStream->Read(cacheKey, sizeof cacheKey);
|
||||
|
||||
rv = cache->GetCachedNetDataByID(recordID[testNum], getter_AddRefs(record));
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't obtain record using record ID");
|
||||
|
||||
// Match against previously stored meta-data
|
||||
rv = record->GetMetaData(&metaDataLength, &metaData);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get record meta-data");
|
||||
match = randomStream->Match(metaData, metaDataLength);
|
||||
NS_ASSERTION(match, "Meta-data corrupted or incorrect");
|
||||
|
||||
nsAllocator::Free(metaData);
|
||||
delete randomStream;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Check that all cache entries in the database are enumerated and that
|
||||
// no duplicates appear.
|
||||
nsresult
|
||||
TestEnumeration(nsINetDataCache *cache)
|
||||
{
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsINetDataCacheRecord> record;
|
||||
nsCOMPtr<nsISupports> tempISupports;
|
||||
nsCOMPtr<nsISimpleEnumerator> iterator;
|
||||
RandomStream *randomStream;
|
||||
PRUint32 metaDataLength;
|
||||
char cacheKey[CACHE_KEY_LENGTH];
|
||||
char *metaData;
|
||||
PRUint32 testNum;
|
||||
PRBool match;
|
||||
PRInt32 recID;
|
||||
|
||||
int numRecords = 0;
|
||||
|
||||
// Iterate over all records in the cache
|
||||
rv = cache->NewCacheEntryIterator(getter_AddRefs(iterator));
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't create new cache entry iterator");
|
||||
|
||||
PRBool notDone;
|
||||
while (1) {
|
||||
|
||||
// Done iterating ?
|
||||
rv = iterator->HasMoreElements(¬Done);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
if (!notDone)
|
||||
break;
|
||||
|
||||
// Get next record in iteration
|
||||
rv = iterator->GetNext(getter_AddRefs(tempISupports));
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "iterator bustage");
|
||||
record = do_QueryInterface(tempISupports);
|
||||
|
||||
numRecords++;
|
||||
|
||||
// Get record ID
|
||||
rv = record->GetRecordID(&recID);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get Record ID");
|
||||
testNum = mapRecordIdToTestNum(recID);
|
||||
NS_ASSERTION(testNum != -1, "Corrupted Record ID ?");
|
||||
|
||||
// Erase mapping from table, so that duplicate enumerations are detected
|
||||
recordID[testNum] = -1;
|
||||
|
||||
// Make sure stream matches test data
|
||||
randomStream = new RandomStream(testNum);
|
||||
randomStream->Read(cacheKey, sizeof cacheKey);
|
||||
|
||||
// Match against previously stored meta-data
|
||||
rv = record->GetMetaData(&metaDataLength, &metaData);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get record meta-data");
|
||||
match = randomStream->Match(metaData, metaDataLength);
|
||||
NS_ASSERTION(match, "Meta-data corrupted or incorrect");
|
||||
nsAllocator::Free(metaData);
|
||||
|
||||
delete randomStream;
|
||||
}
|
||||
|
||||
NS_ASSERTION(numRecords == NUM_CACHE_ENTRIES, "Iteration bug");
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Read the test data that was written in FillCache(), checking for
|
||||
// corruption, truncation.
|
||||
nsresult
|
||||
TestRead(nsINetDataCache *cache)
|
||||
{
|
||||
nsresult rv;
|
||||
PRBool inCache;
|
||||
nsCOMPtr<nsINetDataCacheRecord> record;
|
||||
RandomStream *randomStream;
|
||||
PRUint32 metaDataLength;
|
||||
char cacheKey[CACHE_KEY_LENGTH];
|
||||
char *metaData, *storedCacheKey;
|
||||
PRUint32 testNum, storedCacheKeyLength;
|
||||
PRBool match;
|
||||
|
||||
for (testNum = 0; testNum < NUM_CACHE_ENTRIES; testNum++) {
|
||||
randomStream = new RandomStream(testNum);
|
||||
randomStream->Read(cacheKey, sizeof cacheKey);
|
||||
|
||||
// Ensure that entry is in the cache
|
||||
rv = cache->Contains(cacheKey, sizeof cacheKey, &inCache);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
|
||||
NS_ASSERTION(inCache, "nsINetDataCache::Contains error");
|
||||
|
||||
rv = cache->GetCachedNetData(cacheKey, sizeof cacheKey, getter_AddRefs(record));
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
|
||||
|
||||
// Match against previously stored meta-data
|
||||
match = record->GetMetaData(&metaDataLength, &metaData);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
|
||||
match = randomStream->Match(metaData, metaDataLength);
|
||||
NS_ASSERTION(match, "Meta-data corrupted or incorrect");
|
||||
nsAllocator::Free(metaData);
|
||||
|
||||
// Test GetKey() method
|
||||
rv = record->GetKey(&storedCacheKeyLength, &storedCacheKey);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv) &&
|
||||
(storedCacheKeyLength == sizeof cacheKey) &&
|
||||
!memcmp(storedCacheKey, &cacheKey[0], sizeof cacheKey),
|
||||
"nsINetDataCacheRecord::GetKey failed");
|
||||
nsAllocator::Free(storedCacheKey);
|
||||
|
||||
PRUint32 expectedStreamLength = randomStream->Next() % MAX_CONTENT_LENGTH;
|
||||
|
||||
TestReadStream(record, randomStream, expectedStreamLength);
|
||||
}
|
||||
|
||||
WaitForEvents();
|
||||
|
||||
// Compute rate in MB/s
|
||||
double rate = gTotalBytesRead / PR_IntervalToMilliseconds(gTotalDuration);
|
||||
rate *= NUM_CACHE_ENTRIES;
|
||||
rate *= 1000;
|
||||
rate /= (1024 * 1024);
|
||||
printf("Read %d bytes at a rate of %5.1f MB per second \n",
|
||||
gTotalBytesRead, rate);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Repeatedly call SetStoredContentLength() on a cache entry and make
|
||||
// read the stream's data to ensure that it's not corrupted by the effect
|
||||
nsresult
|
||||
TestTruncation(nsINetDataCache *cache)
|
||||
{
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsINetDataCacheRecord> record;
|
||||
RandomStream *randomStream;
|
||||
char cacheKey[CACHE_KEY_LENGTH];
|
||||
|
||||
randomStream = new RandomStream(0);
|
||||
randomStream->Read(cacheKey, sizeof cacheKey);
|
||||
|
||||
rv = cache->GetCachedNetData(cacheKey, sizeof cacheKey, getter_AddRefs(record));
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
|
||||
|
||||
randomStream->Skip(CACHE_METADATA_LENGTH);
|
||||
PRUint32 initialStreamLength = randomStream->Next() % MAX_CONTENT_LENGTH;
|
||||
delete randomStream;
|
||||
|
||||
PRUint32 i;
|
||||
PRUint32 delta = initialStreamLength / 64;
|
||||
for (i = initialStreamLength; i >= delta; i -= delta) {
|
||||
PRUint32 expectedStreamLength = i;
|
||||
|
||||
// Do the truncation
|
||||
record->SetStoredContentLength(expectedStreamLength);
|
||||
randomStream = new RandomStream(0);
|
||||
randomStream->Skip(CACHE_KEY_LENGTH + CACHE_METADATA_LENGTH + 1);
|
||||
|
||||
PRUint32 afterContentLength;
|
||||
rv = record->GetStoredContentLength(&afterContentLength);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
|
||||
|
||||
NS_ASSERTION(afterContentLength == expectedStreamLength,
|
||||
"nsINetDataCacheRecord::SetContentLength() failed to truncate record");
|
||||
|
||||
TestReadStream(record, randomStream, expectedStreamLength);
|
||||
WaitForEvents();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Write known data to random offsets in a single cache entry and test
|
||||
// resulting stream for correctness.
|
||||
nsresult
|
||||
TestOffsetWrites(nsINetDataCache *cache)
|
||||
{
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsINetDataCacheRecord> record;
|
||||
nsCOMPtr<nsIChannel> channel;
|
||||
nsCOMPtr<nsIOutputStream> outStream;
|
||||
char buf[512];
|
||||
char cacheKey[CACHE_KEY_LENGTH];
|
||||
RandomStream *randomStream;
|
||||
|
||||
randomStream = new RandomStream(0);
|
||||
randomStream->Read(cacheKey, sizeof cacheKey);
|
||||
|
||||
rv = cache->GetCachedNetData(cacheKey, sizeof cacheKey, getter_AddRefs(record));
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't access record via opaque cache key");
|
||||
|
||||
|
||||
// Write buffer-fulls of data at random offsets into the cache entry.
|
||||
// Data written is (offset % 0xff)
|
||||
PRUint32 startingOffset;
|
||||
PRUint32 streamLength = 0;
|
||||
CounterStream *counterStream;
|
||||
int i;
|
||||
for (i = 0; i < 100; i++) {
|
||||
rv = record->NewChannel(0, getter_AddRefs(channel));
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
|
||||
|
||||
startingOffset = streamLength ? streamLength - (randomStream->Next() % sizeof buf): 0;
|
||||
rv = channel->OpenOutputStream(startingOffset, getter_AddRefs(outStream));
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
|
||||
|
||||
counterStream = new CounterStream(startingOffset);
|
||||
counterStream->Read(buf, sizeof buf);
|
||||
|
||||
PRUint32 numWritten;
|
||||
rv = outStream->Write(buf, sizeof buf, &numWritten);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
|
||||
NS_ASSERTION(numWritten == sizeof buf, "Write() bug?");
|
||||
streamLength = startingOffset + sizeof buf;
|
||||
|
||||
rv = outStream->Close();
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't close channel");
|
||||
delete counterStream;
|
||||
}
|
||||
|
||||
delete randomStream;
|
||||
|
||||
counterStream = new CounterStream(0);
|
||||
TestReadStream(record, counterStream, streamLength);
|
||||
WaitForEvents();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Create entries in the network data cache, using random data for the
|
||||
// key, the meta-data and the stored content data.
|
||||
nsresult
|
||||
FillCache(nsINetDataCache *cache)
|
||||
{
|
||||
nsresult rv;
|
||||
PRBool inCache;
|
||||
nsCOMPtr<nsINetDataCacheRecord> record;
|
||||
nsCOMPtr<nsIChannel> channel;
|
||||
nsCOMPtr<nsIOutputStream> outStream;
|
||||
char buf[1000];
|
||||
PRUint32 metaDataLength;
|
||||
char cacheKey[CACHE_KEY_LENGTH];
|
||||
char metaData[CACHE_METADATA_LENGTH];
|
||||
PRUint32 testNum;
|
||||
char *data;
|
||||
RandomStream *randomStream;
|
||||
PRUint32 totalBytesWritten = 0;
|
||||
|
||||
PRIntervalTime startTime = PR_IntervalNow();
|
||||
|
||||
for (testNum = 0; testNum < NUM_CACHE_ENTRIES; testNum++) {
|
||||
randomStream = new RandomStream(testNum);
|
||||
randomStream->Read(cacheKey, sizeof cacheKey);
|
||||
|
||||
// No entry should be in cache until we add it
|
||||
rv = cache->Contains(cacheKey, sizeof cacheKey, &inCache);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
|
||||
NS_ASSERTION(!inCache, "nsINetDataCache::Contains error");
|
||||
|
||||
rv = cache->GetCachedNetData(cacheKey, sizeof cacheKey, getter_AddRefs(record));
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't access record via opaque cache key");
|
||||
|
||||
// Test nsINetDataCacheRecord::GetRecordID()
|
||||
rv = record->GetRecordID(&recordID[testNum]);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get Record ID");
|
||||
|
||||
// Test nsINetDataCache::GetNumEntries()
|
||||
PRUint32 numEntries = (PRUint32)-1;
|
||||
rv = cache->GetNumEntries(&numEntries);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get number of cache entries");
|
||||
NS_ASSERTION(numEntries == testNum + 1, "GetNumEntries failure");
|
||||
|
||||
// Record meta-data should be initially empty
|
||||
rv = record->GetMetaData(&metaDataLength, &data);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
|
||||
if ((metaDataLength != 0) || (data != 0))
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
// Store random data as meta-data
|
||||
randomStream->Read(metaData, sizeof metaData);
|
||||
record->SetMetaData(sizeof metaData, metaData);
|
||||
|
||||
rv = record->NewChannel(0, getter_AddRefs(channel));
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
|
||||
|
||||
rv = channel->OpenOutputStream(0, getter_AddRefs(outStream));
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
|
||||
|
||||
PRUint32 beforeOccupancy;
|
||||
rv = cache->GetStorageInUse(&beforeOccupancy);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get cache occupancy");
|
||||
|
||||
int streamLength = randomStream->Next() % MAX_CONTENT_LENGTH;
|
||||
int remaining = streamLength;
|
||||
while (remaining) {
|
||||
PRUint32 numWritten;
|
||||
int amount = PR_MIN(sizeof buf, remaining);
|
||||
randomStream->Read(buf, amount);
|
||||
|
||||
rv = outStream->Write(buf, amount, &numWritten);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
|
||||
NS_ASSERTION(numWritten == (PRUint32)amount, "Write() bug?");
|
||||
|
||||
remaining -= amount;
|
||||
}
|
||||
outStream->Close();
|
||||
totalBytesWritten += streamLength;
|
||||
|
||||
PRUint32 afterOccupancy;
|
||||
rv = cache->GetStorageInUse(&afterOccupancy);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get cache occupancy");
|
||||
PRUint32 streamLengthInKB = streamLength >> 10;
|
||||
NS_ASSERTION((afterOccupancy - beforeOccupancy) >= streamLengthInKB,
|
||||
"nsINetDataCache::GetStorageInUse() is busted");
|
||||
|
||||
|
||||
// *Now* there should be an entry in the cache
|
||||
rv = cache->Contains(cacheKey, sizeof cacheKey, &inCache);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
|
||||
NS_ASSERTION(inCache, "nsINetDataCache::Contains error");
|
||||
|
||||
delete randomStream;
|
||||
}
|
||||
|
||||
PRIntervalTime endTime = PR_IntervalNow();
|
||||
|
||||
// Compute rate in MB/s
|
||||
double rate = totalBytesWritten / PR_IntervalToMilliseconds(endTime - startTime);
|
||||
rate *= 1000;
|
||||
rate /= (1024 * 1024);
|
||||
printf("Wrote %7d bytes at a rate of %5.1f MB per second \n",
|
||||
totalBytesWritten, rate);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult NS_AutoregisterComponents()
|
||||
{
|
||||
nsresult rv = nsComponentManager::AutoRegister(nsIComponentManager::NS_Startup,
|
||||
NULL /* default */);
|
||||
return rv;
|
||||
}
|
||||
|
||||
PRBool initPref ()
|
||||
{
|
||||
nsresult rv;
|
||||
NS_WITH_SERVICE(nsIPref, prefPtr, kPrefCID, &rv);
|
||||
if (NS_FAILED(rv))
|
||||
return false;
|
||||
|
||||
nsCOMPtr<nsIFileSpec> fileSpec;
|
||||
rv = NS_NewFileSpec (getter_AddRefs(fileSpec));
|
||||
if (NS_FAILED(rv))
|
||||
return false;
|
||||
|
||||
nsCString defaultPrefFile = PR_GetEnv ("MOZILLA_FIVE_HOME");
|
||||
if (defaultPrefFile.Length())
|
||||
defaultPrefFile += "/";
|
||||
else
|
||||
defaultPrefFile = "./";
|
||||
defaultPrefFile += "default_prefs.js";
|
||||
|
||||
fileSpec->SetUnixStyleFilePath (defaultPrefFile.GetBuffer());
|
||||
|
||||
PRBool exists = false;
|
||||
fileSpec->Exists(&exists);
|
||||
if (exists)
|
||||
prefPtr->ReadUserPrefsFrom(fileSpec);
|
||||
else
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char* argv[])
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
if(argc <2) {
|
||||
printf(" %s -f to test filecache\n", argv[0]) ;
|
||||
printf(" %s -m to test memcache\n", argv[0]) ;
|
||||
return -1 ;
|
||||
}
|
||||
|
||||
|
||||
rv = NS_AutoregisterComponents();
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't register XPCOM components");
|
||||
|
||||
nsCOMPtr<nsINetDataCache> cache;
|
||||
|
||||
if (PL_strcasecmp(argv[1], "-m") == 0) {
|
||||
rv = nsComponentManager::CreateInstance(kMemCacheCID, nsnull,
|
||||
NS_GET_IID(nsINetDataCache),
|
||||
getter_AddRefs(cache));
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't create memory cache factory");
|
||||
} else if (PL_strcasecmp(argv[1], "-f") == 0) {
|
||||
|
||||
nsCOMPtr<nsINetDataDiskCache> diskcache ;
|
||||
|
||||
rv = nsComponentManager::CreateInstance(kDiskCacheCID, nsnull,
|
||||
NS_GET_IID(nsINetDataDiskCache),
|
||||
getter_AddRefs(diskcache));
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't create disk cache factory") ;
|
||||
|
||||
nsCOMPtr<nsIFileSpec> folder ;
|
||||
NS_NewFileSpec(getter_AddRefs(folder)) ;
|
||||
folder->SetUnixStyleFilePath("/tmp") ;
|
||||
diskcache->SetDiskCacheFolder(folder) ;
|
||||
|
||||
cache = diskcache ;
|
||||
|
||||
} else {
|
||||
printf(" %s -f to test filecache\n", argv[0]) ;
|
||||
printf(" %s -m to test memcache\n", argv[0]) ;
|
||||
return -1 ;
|
||||
}
|
||||
|
||||
InitQueue();
|
||||
|
||||
PRUnichar* description;
|
||||
rv = cache->GetDescription(&description);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get cache description");
|
||||
nsCAutoString descStr(description);
|
||||
printf("Testing: %s\n", descStr.GetBuffer());
|
||||
|
||||
rv = cache->RemoveAll();
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't clear cache");
|
||||
|
||||
PRUint32 startOccupancy;
|
||||
rv = cache->GetStorageInUse(&startOccupancy);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get cache occupancy");
|
||||
|
||||
PRUint32 numEntries = (PRUint32)-1;
|
||||
rv = cache->GetNumEntries(&numEntries);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get number of cache entries");
|
||||
NS_ASSERTION(numEntries == 0, "Couldn't clear cache");
|
||||
|
||||
rv = FillCache(cache);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't fill cache with random test data");
|
||||
|
||||
rv = TestRead(cache);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't read random test data from cache");
|
||||
|
||||
rv = TestRecordID(cache);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't index records using record ID");
|
||||
|
||||
rv = TestEnumeration(cache);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't successfully enumerate records");
|
||||
|
||||
rv = TestTruncation(cache);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't successfully truncate records");
|
||||
|
||||
rv = TestOffsetWrites(cache);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't successfully write to records using non-zero offsets");
|
||||
|
||||
rv = cache->RemoveAll();
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't clear cache");
|
||||
rv = cache->GetNumEntries(&numEntries);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get number of cache entries");
|
||||
NS_ASSERTION(numEntries == 0, "Couldn't clear cache");
|
||||
|
||||
PRUint32 endOccupancy;
|
||||
rv = cache->GetStorageInUse(&endOccupancy);
|
||||
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get cache occupancy");
|
||||
|
||||
NS_ASSERTION(startOccupancy == endOccupancy, "Cache occupancy not correctly computed ?");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
82
mozilla/netwerk/test/makefile.win
Normal file
82
mozilla/netwerk/test/makefile.win
Normal file
@@ -0,0 +1,82 @@
|
||||
#!nmake
|
||||
#
|
||||
# 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=..\..
|
||||
|
||||
MAKE_OBJ_TYPE = EXE
|
||||
PROG1 = .\$(OBJDIR)\TestFileInput.exe
|
||||
PROG2 = .\$(OBJDIR)\TestSocketInput.exe
|
||||
PROG3 = .\$(OBJDIR)\TestSocketIO.exe
|
||||
PROG4 = .\$(OBJDIR)\TestProtocols.exe
|
||||
PROG5 = .\$(OBJDIR)\TestSocketTransport.exe
|
||||
PROG6 = .\$(OBJDIR)\urltest.exe
|
||||
PROG7 = .\$(OBJDIR)\TestFileInput2.exe
|
||||
PROG8 = .\$(OBJDIR)\TestFileTransport.exe
|
||||
PROG9 = .\$(OBJDIR)\TestRes.exe
|
||||
PROGA = .\$(OBJDIR)\TestRawCache.exe
|
||||
PROGB = .\$(OBJDIR)\TestCacheMgr.exe
|
||||
PROGRAMS = \
|
||||
#$(PROG1) $(PROG2) $(PROG3) $(PROG4) $(PROG5) $(PROG6) $(PROG7) $(PROG8) $(PROG9)\
|
||||
$(PROGA) $(PROGB)
|
||||
|
||||
LCFLAGS=-DUSE_NSREG -GX
|
||||
|
||||
REQUIRES=libreg
|
||||
|
||||
INCS = $(INCS) \
|
||||
-I$(DEPTH)\dist\include \
|
||||
$(NULL)
|
||||
|
||||
LLIBS= \
|
||||
$(DIST)\lib\xpcom.lib \
|
||||
$(LIBNSPR) \
|
||||
$(NULL)
|
||||
|
||||
include <$(DEPTH)\config\rules.mak>
|
||||
|
||||
install:: $(PROGRAMS)
|
||||
-for %p in ($(PROGRAMS)) do $(MAKE_INSTALL) %p $(DIST)\bin
|
||||
|
||||
clobber::
|
||||
-for %p in ($(PROGRAMS)) do $(RM) %p $(DIST)\bin\%p
|
||||
|
||||
$(PROG1): $(OBJDIR) TestFileInput.cpp
|
||||
|
||||
$(PROG2): $(OBJDIR) TestSocketInput.cpp
|
||||
|
||||
$(PROG3): $(OBJDIR) TestSocketIO.cpp
|
||||
|
||||
$(PROG4): $(OBJDIR) TestProtocols.cpp
|
||||
|
||||
$(PROG5): $(OBJDIR) TestSocketTransport.cpp
|
||||
|
||||
$(PROG6): $(OBJDIR) urltest.cpp
|
||||
|
||||
$(PROG7): $(OBJDIR) TestFileInput2.cpp
|
||||
|
||||
$(PROG8): $(OBJDIR) TestFileTransport.cpp
|
||||
|
||||
$(PROG9): $(OBJDIR) TestRes.cpp
|
||||
|
||||
$(PROGA): $(OBJDIR) TestRawCache.cpp
|
||||
|
||||
$(PROGB): $(OBJDIR) TestCacheMgr.cpp
|
||||
|
||||
@@ -1,539 +0,0 @@
|
||||
/*
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF 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 elliptic curve math library for binary polynomial
|
||||
* field curves.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Sun Microsystems, Inc.
|
||||
* Portions created by Sun Microsystems, Inc. are Copyright (C) 2003
|
||||
* Sun Microsystems, Inc. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Douglas Stebila <douglas@stebila.ca>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef NSS_ENABLE_ECC
|
||||
/*
|
||||
* GF2m_ecl.c: Contains an implementation of elliptic curve math library
|
||||
* for curves over GF2m.
|
||||
*
|
||||
* XXX Can be moved to a separate subdirectory later.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "GF2m_ecl.h"
|
||||
#include "mpi/mplogic.h"
|
||||
#include "mpi/mp_gf2m.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
/* Checks if point P(px, py) is at infinity. Uses affine coordinates. */
|
||||
mp_err
|
||||
GF2m_ec_pt_is_inf_aff(const mp_int *px, const mp_int *py)
|
||||
{
|
||||
|
||||
if ((mp_cmp_z(px) == 0) && (mp_cmp_z(py) == 0)) {
|
||||
return MP_YES;
|
||||
} else {
|
||||
return MP_NO;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Sets P(px, py) to be the point at infinity. Uses affine coordinates. */
|
||||
mp_err
|
||||
GF2m_ec_pt_set_inf_aff(mp_int *px, mp_int *py)
|
||||
{
|
||||
mp_zero(px);
|
||||
mp_zero(py);
|
||||
return MP_OKAY;
|
||||
}
|
||||
|
||||
/* Computes R = P + Q based on IEEE P1363 A.10.2.
|
||||
* Elliptic curve points P, Q, and R can all be identical.
|
||||
* Uses affine coordinates.
|
||||
*/
|
||||
mp_err
|
||||
GF2m_ec_pt_add_aff(const mp_int *pp, const mp_int *a, const mp_int *px,
|
||||
const mp_int *py, const mp_int *qx, const mp_int *qy,
|
||||
mp_int *rx, mp_int *ry)
|
||||
{
|
||||
mp_err err = MP_OKAY;
|
||||
mp_int lambda, xtemp, ytemp;
|
||||
unsigned int *p;
|
||||
int p_size;
|
||||
|
||||
p_size = mp_bpoly2arr(pp, p, 0) + 1;
|
||||
p = (unsigned int *) (malloc(sizeof(unsigned int) * p_size));
|
||||
if (p == NULL) goto cleanup;
|
||||
mp_bpoly2arr(pp, p, p_size);
|
||||
|
||||
CHECK_MPI_OK( mp_init(&lambda) );
|
||||
CHECK_MPI_OK( mp_init(&xtemp) );
|
||||
CHECK_MPI_OK( mp_init(&ytemp) );
|
||||
/* if P = inf, then R = Q */
|
||||
if (GF2m_ec_pt_is_inf_aff(px, py) == 0) {
|
||||
CHECK_MPI_OK( mp_copy(qx, rx) );
|
||||
CHECK_MPI_OK( mp_copy(qy, ry) );
|
||||
err = MP_OKAY;
|
||||
goto cleanup;
|
||||
}
|
||||
/* if Q = inf, then R = P */
|
||||
if (GF2m_ec_pt_is_inf_aff(qx, qy) == 0) {
|
||||
CHECK_MPI_OK( mp_copy(px, rx) );
|
||||
CHECK_MPI_OK( mp_copy(py, ry) );
|
||||
err = MP_OKAY;
|
||||
goto cleanup;
|
||||
}
|
||||
/* if px != qx, then lambda = (py+qy) / (px+qx),
|
||||
* xtemp = a + lambda^2 + lambda + px + qx
|
||||
*/
|
||||
if (mp_cmp(px, qx) != 0) {
|
||||
CHECK_MPI_OK( mp_badd(py, qy, &ytemp) );
|
||||
CHECK_MPI_OK( mp_badd(px, qx, &xtemp) );
|
||||
CHECK_MPI_OK( mp_bdivmod(&ytemp, &xtemp, pp, p, &lambda) );
|
||||
CHECK_MPI_OK( mp_bsqrmod(&lambda, p, &xtemp) );
|
||||
CHECK_MPI_OK( mp_badd(&xtemp, &lambda, &xtemp) );
|
||||
CHECK_MPI_OK( mp_badd(&xtemp, a, &xtemp) );
|
||||
CHECK_MPI_OK( mp_badd(&xtemp, px, &xtemp) );
|
||||
CHECK_MPI_OK( mp_badd(&xtemp, qx, &xtemp) );
|
||||
} else {
|
||||
/* if py != qy or qx = 0, then R = inf */
|
||||
if (((mp_cmp(py, qy) != 0)) || (mp_cmp_z(qx) == 0)) {
|
||||
mp_zero(rx);
|
||||
mp_zero(ry);
|
||||
err = MP_OKAY;
|
||||
goto cleanup;
|
||||
}
|
||||
/* lambda = qx + qy / qx */
|
||||
CHECK_MPI_OK( mp_bdivmod(qy, qx, pp, p, &lambda) );
|
||||
CHECK_MPI_OK( mp_badd(&lambda, qx, &lambda) );
|
||||
/* xtemp = a + lambda^2 + lambda */
|
||||
CHECK_MPI_OK( mp_bsqrmod(&lambda, p, &xtemp) );
|
||||
CHECK_MPI_OK( mp_badd(&xtemp, &lambda, &xtemp) );
|
||||
CHECK_MPI_OK( mp_badd(&xtemp, a, &xtemp) );
|
||||
}
|
||||
/* ry = (qx + xtemp) * lambda + xtemp + qy */
|
||||
CHECK_MPI_OK( mp_badd(qx, &xtemp, &ytemp) );
|
||||
CHECK_MPI_OK( mp_bmulmod(&ytemp, &lambda, p, &ytemp) );
|
||||
CHECK_MPI_OK( mp_badd(&ytemp, &xtemp, &ytemp) );
|
||||
CHECK_MPI_OK( mp_badd(&ytemp, qy, ry) );
|
||||
/* rx = xtemp */
|
||||
CHECK_MPI_OK( mp_copy(&xtemp, rx) );
|
||||
|
||||
cleanup:
|
||||
mp_clear(&lambda);
|
||||
mp_clear(&xtemp);
|
||||
mp_clear(&ytemp);
|
||||
free(p);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Computes R = P - Q.
|
||||
* Elliptic curve points P, Q, and R can all be identical.
|
||||
* Uses affine coordinates.
|
||||
*/
|
||||
mp_err
|
||||
GF2m_ec_pt_sub_aff(const mp_int *pp, const mp_int *a, const mp_int *px,
|
||||
const mp_int *py, const mp_int *qx, const mp_int *qy,
|
||||
mp_int *rx, mp_int *ry)
|
||||
{
|
||||
mp_err err = MP_OKAY;
|
||||
mp_int nqy;
|
||||
MP_DIGITS(&nqy) = 0;
|
||||
CHECK_MPI_OK( mp_init(&nqy) );
|
||||
/* nqy = qx+qy */
|
||||
CHECK_MPI_OK( mp_badd(qx, qy, &nqy) );
|
||||
err = GF2m_ec_pt_add_aff(pp, a, px, py, qx, &nqy, rx, ry);
|
||||
cleanup:
|
||||
mp_clear(&nqy);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Computes R = 2P.
|
||||
* Elliptic curve points P and R can be identical.
|
||||
* Uses affine coordinates.
|
||||
*/
|
||||
mp_err
|
||||
GF2m_ec_pt_dbl_aff(const mp_int *pp, const mp_int *a, const mp_int *px,
|
||||
const mp_int *py, mp_int *rx, mp_int *ry)
|
||||
{
|
||||
return GF2m_ec_pt_add_aff(pp, a, px, py, px, py, rx, ry);
|
||||
}
|
||||
|
||||
/* Gets the i'th bit in the binary representation of a.
|
||||
* If i >= length(a), then return 0.
|
||||
* (The above behaviour differs from mpl_get_bit, which
|
||||
* causes an error if i >= length(a).)
|
||||
*/
|
||||
#define MP_GET_BIT(a, i) \
|
||||
((i) >= mpl_significant_bits((a))) ? 0 : mpl_get_bit((a), (i))
|
||||
|
||||
/* Computes R = nP based on IEEE P1363 A.10.3.
|
||||
* Elliptic curve points P and R can be identical.
|
||||
* Uses affine coordinates.
|
||||
*/
|
||||
mp_err
|
||||
GF2m_ec_pt_mul_aff(const mp_int *pp, const mp_int *a, const mp_int *b,
|
||||
const mp_int *px, const mp_int *py, const mp_int *n,
|
||||
mp_int *rx, mp_int *ry)
|
||||
{
|
||||
mp_err err = MP_OKAY;
|
||||
mp_int k, k3, qx, qy, sx, sy;
|
||||
int b1, b3, i, l;
|
||||
unsigned int *p;
|
||||
int p_size;
|
||||
|
||||
MP_DIGITS(&k) = 0;
|
||||
MP_DIGITS(&k3) = 0;
|
||||
MP_DIGITS(&qx) = 0;
|
||||
MP_DIGITS(&qy) = 0;
|
||||
MP_DIGITS(&sx) = 0;
|
||||
MP_DIGITS(&sy) = 0;
|
||||
CHECK_MPI_OK( mp_init(&k) );
|
||||
CHECK_MPI_OK( mp_init(&k3) );
|
||||
CHECK_MPI_OK( mp_init(&qx) );
|
||||
CHECK_MPI_OK( mp_init(&qy) );
|
||||
CHECK_MPI_OK( mp_init(&sx) );
|
||||
CHECK_MPI_OK( mp_init(&sy) );
|
||||
|
||||
p_size = mp_bpoly2arr(pp, p, 0) + 1;
|
||||
p = (unsigned int *) (malloc(sizeof(unsigned int) * p_size));
|
||||
if (p == NULL) goto cleanup;
|
||||
mp_bpoly2arr(pp, p, p_size);
|
||||
|
||||
/* if n = 0 then r = inf */
|
||||
if (mp_cmp_z(n) == 0) {
|
||||
mp_zero(rx);
|
||||
mp_zero(ry);
|
||||
err = MP_OKAY;
|
||||
goto cleanup;
|
||||
}
|
||||
/* Q = P, k = n */
|
||||
CHECK_MPI_OK( mp_copy(px, &qx) );
|
||||
CHECK_MPI_OK( mp_copy(py, &qy) );
|
||||
CHECK_MPI_OK( mp_copy(n, &k) );
|
||||
/* if n < 0 then Q = -Q, k = -k */
|
||||
if (mp_cmp_z(n) < 0) {
|
||||
CHECK_MPI_OK( mp_badd(&qx, &qy, &qy) );
|
||||
CHECK_MPI_OK( mp_neg(&k, &k) );
|
||||
}
|
||||
#ifdef EC_DEBUG /* basic double and add method */
|
||||
l = mpl_significant_bits(&k) - 1;
|
||||
mp_zero(&sx);
|
||||
mp_zero(&sy);
|
||||
for (i = l; i >= 0; i--) {
|
||||
/* if k_i = 1, then S = S + Q */
|
||||
if (mpl_get_bit(&k, i) != 0) {
|
||||
CHECK_MPI_OK( GF2m_ec_pt_add_aff(pp, a, &sx, &sy, &qx, &qy, &sx, &sy) );
|
||||
}
|
||||
if (i > 0) {
|
||||
/* S = 2S */
|
||||
CHECK_MPI_OK( GF2m_ec_pt_dbl_aff(pp, a, &sx, &sy, &sx, &sy) );
|
||||
}
|
||||
}
|
||||
#else /* double and add/subtract method from standard */
|
||||
/* k3 = 3 * k */
|
||||
mp_set(&k3, 0x3);
|
||||
CHECK_MPI_OK( mp_mul(&k, &k3, &k3) );
|
||||
/* S = Q */
|
||||
CHECK_MPI_OK( mp_copy(&qx, &sx) );
|
||||
CHECK_MPI_OK( mp_copy(&qy, &sy) );
|
||||
/* l = index of high order bit in binary representation of 3*k */
|
||||
l = mpl_significant_bits(&k3) - 1;
|
||||
/* for i = l-1 downto 1 */
|
||||
for (i = l - 1; i >= 1; i--) {
|
||||
/* S = 2S */
|
||||
CHECK_MPI_OK( GF2m_ec_pt_dbl_aff(pp, a, &sx, &sy, &sx, &sy) );
|
||||
b3 = MP_GET_BIT(&k3, i);
|
||||
b1 = MP_GET_BIT(&k, i);
|
||||
/* if k3_i = 1 and k_i = 0, then S = S + Q */
|
||||
if ((b3 == 1) && (b1 == 0)) {
|
||||
CHECK_MPI_OK( GF2m_ec_pt_add_aff(pp, a, &sx, &sy, &qx, &qy, &sx, &sy) );
|
||||
/* if k3_i = 0 and k_i = 1, then S = S - Q */
|
||||
} else if ((b3 == 0) && (b1 == 1)) {
|
||||
CHECK_MPI_OK( GF2m_ec_pt_sub_aff(pp, a, &sx, &sy, &qx, &qy, &sx, &sy) );
|
||||
}
|
||||
}
|
||||
#endif
|
||||
/* output S */
|
||||
CHECK_MPI_OK( mp_copy(&sx, rx) );
|
||||
CHECK_MPI_OK( mp_copy(&sy, ry) );
|
||||
|
||||
cleanup:
|
||||
mp_clear(&k);
|
||||
mp_clear(&k3);
|
||||
mp_clear(&qx);
|
||||
mp_clear(&qy);
|
||||
mp_clear(&sx);
|
||||
mp_clear(&sy);
|
||||
free(p);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Compute the x-coordinate x/z for the point 2*(x/z) in Montgomery projective
|
||||
* coordinates.
|
||||
* Uses algorithm Mdouble in appendix of
|
||||
* Lopez, J. and Dahab, R. "Fast multiplication on elliptic curves over
|
||||
* GF(2^m) without precomputation".
|
||||
* modified to not require precomputation of c=b^{2^{m-1}}.
|
||||
*/
|
||||
static mp_err
|
||||
gf2m_Mdouble(const mp_int *pp, const unsigned int p[], const mp_int *a,
|
||||
const mp_int *b, mp_int *x, mp_int *z)
|
||||
{
|
||||
mp_err err = MP_OKAY;
|
||||
mp_int t1;
|
||||
|
||||
MP_DIGITS(&t1) = 0;
|
||||
CHECK_MPI_OK( mp_init(&t1) );
|
||||
|
||||
CHECK_MPI_OK( mp_bsqrmod(x, p, x) );
|
||||
CHECK_MPI_OK( mp_bsqrmod(z, p, &t1) );
|
||||
CHECK_MPI_OK( mp_bmulmod(x, &t1, p, z) );
|
||||
CHECK_MPI_OK( mp_bsqrmod(x, p, x) );
|
||||
CHECK_MPI_OK( mp_bsqrmod(&t1, p, &t1) );
|
||||
CHECK_MPI_OK( mp_bmulmod(b, &t1, p, &t1) );
|
||||
CHECK_MPI_OK( mp_badd(x, &t1, x) );
|
||||
|
||||
cleanup:
|
||||
mp_clear(&t1);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Compute the x-coordinate x1/z1 for the point (x1/z1)+(x2/x2) in Montgomery
|
||||
* projective coordinates.
|
||||
* Uses algorithm Madd in appendix of
|
||||
* Lopex, J. and Dahab, R. "Fast multiplication on elliptic curves over
|
||||
* GF(2^m) without precomputation".
|
||||
*/
|
||||
static mp_err
|
||||
gf2m_Madd(const mp_int *pp, const unsigned int p[], const mp_int *a,
|
||||
const mp_int *b, const mp_int *x, mp_int *x1, mp_int *z1, mp_int *x2,
|
||||
mp_int *z2)
|
||||
{
|
||||
mp_err err = MP_OKAY;
|
||||
mp_int t1, t2;
|
||||
|
||||
MP_DIGITS(&t1) = 0;
|
||||
MP_DIGITS(&t2) = 0;
|
||||
CHECK_MPI_OK( mp_init(&t1) );
|
||||
CHECK_MPI_OK( mp_init(&t2) );
|
||||
|
||||
CHECK_MPI_OK( mp_copy(x, &t1) );
|
||||
CHECK_MPI_OK( mp_bmulmod(x1, z2, p, x1) );
|
||||
CHECK_MPI_OK( mp_bmulmod(z1, x2, p, z1) );
|
||||
CHECK_MPI_OK( mp_bmulmod(x1, z1, p, &t2) );
|
||||
CHECK_MPI_OK( mp_badd(z1, x1, z1) );
|
||||
CHECK_MPI_OK( mp_bsqrmod(z1, p, z1) );
|
||||
CHECK_MPI_OK( mp_bmulmod(z1, &t1, p, x1) );
|
||||
CHECK_MPI_OK( mp_badd(x1, &t2, x1) );
|
||||
|
||||
cleanup:
|
||||
mp_clear(&t1);
|
||||
mp_clear(&t2);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Compute the x, y affine coordinates from the point (x1, z1) (x2, z2)
|
||||
* using Montgomery point multiplication algorithm Mxy() in appendix of
|
||||
* Lopex, J. and Dahab, R. "Fast multiplication on elliptic curves over
|
||||
* GF(2^m) without precomputation".
|
||||
* Returns:
|
||||
* 0 on error
|
||||
* 1 if return value should be the point at infinity
|
||||
* 2 otherwise
|
||||
*/
|
||||
static int
|
||||
gf2m_Mxy(const mp_int *pp, const unsigned int p[], const mp_int *a,
|
||||
const mp_int *b, const mp_int *x, const mp_int *y, mp_int *x1, mp_int *z1,
|
||||
mp_int *x2, mp_int *z2)
|
||||
{
|
||||
mp_err err = MP_OKAY;
|
||||
int ret;
|
||||
mp_int t3, t4, t5;
|
||||
|
||||
MP_DIGITS(&t3) = 0;
|
||||
MP_DIGITS(&t4) = 0;
|
||||
MP_DIGITS(&t5) = 0;
|
||||
CHECK_MPI_OK( mp_init(&t3) );
|
||||
CHECK_MPI_OK( mp_init(&t4) );
|
||||
CHECK_MPI_OK( mp_init(&t5) );
|
||||
|
||||
if (mp_cmp_z(z1) == 0) {
|
||||
mp_zero(x2);
|
||||
mp_zero(z2);
|
||||
ret = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (mp_cmp_z(z2) == 0) {
|
||||
CHECK_MPI_OK( mp_copy(x, x2) );
|
||||
CHECK_MPI_OK( mp_badd(x, y, z2) );
|
||||
ret = 2;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
mp_set(&t5, 0x1);
|
||||
|
||||
CHECK_MPI_OK( mp_bmulmod(z1, z2, p, &t3) );
|
||||
|
||||
CHECK_MPI_OK( mp_bmulmod(z1, x, p, z1) );
|
||||
CHECK_MPI_OK( mp_badd(z1, x1, z1) );
|
||||
CHECK_MPI_OK( mp_bmulmod(z2, x, p, z2) );
|
||||
CHECK_MPI_OK( mp_bmulmod(z2, x1, p, x1) );
|
||||
CHECK_MPI_OK( mp_badd(z2, x2, z2) );
|
||||
|
||||
CHECK_MPI_OK( mp_bmulmod(z2, z1, p, z2) );
|
||||
CHECK_MPI_OK( mp_bsqrmod(x, p, &t4) );
|
||||
CHECK_MPI_OK( mp_badd(&t4, y, &t4) );
|
||||
CHECK_MPI_OK( mp_bmulmod(&t4, &t3, p, &t4) );
|
||||
CHECK_MPI_OK( mp_badd(&t4, z2, &t4) );
|
||||
|
||||
CHECK_MPI_OK( mp_bmulmod(&t3, x, p, &t3) );
|
||||
CHECK_MPI_OK( mp_bdivmod(&t5, &t3, pp, p, &t3) );
|
||||
CHECK_MPI_OK( mp_bmulmod(&t3, &t4, p, &t4) );
|
||||
CHECK_MPI_OK( mp_bmulmod(x1, &t3, p, x2) );
|
||||
CHECK_MPI_OK( mp_badd(x2, x, z2) );
|
||||
|
||||
CHECK_MPI_OK( mp_bmulmod(z2, &t4, p, z2) );
|
||||
CHECK_MPI_OK( mp_badd(z2, y, z2) );
|
||||
|
||||
ret = 2;
|
||||
|
||||
cleanup:
|
||||
mp_clear(&t3);
|
||||
mp_clear(&t4);
|
||||
mp_clear(&t5);
|
||||
if (err == MP_OKAY) {
|
||||
return ret;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Computes R = nP based on algorithm 2P of
|
||||
* Lopex, J. and Dahab, R. "Fast multiplication on elliptic curves over
|
||||
* GF(2^m) without precomputation".
|
||||
* Elliptic curve points P and R can be identical.
|
||||
* Uses Montgomery projective coordinates.
|
||||
*/
|
||||
mp_err
|
||||
GF2m_ec_pt_mul_mont(const mp_int *pp, const mp_int *a, const mp_int *b,
|
||||
const mp_int *px, const mp_int *py, const mp_int *n,
|
||||
mp_int *rx, mp_int *ry)
|
||||
{
|
||||
mp_err err = MP_OKAY;
|
||||
mp_int x1, x2, z1, z2;
|
||||
int i, j;
|
||||
mp_digit top_bit, mask;
|
||||
unsigned int *p;
|
||||
int p_size;
|
||||
|
||||
MP_DIGITS(&x1) = 0;
|
||||
MP_DIGITS(&x2) = 0;
|
||||
MP_DIGITS(&z1) = 0;
|
||||
MP_DIGITS(&z2) = 0;
|
||||
CHECK_MPI_OK( mp_init(&x1) );
|
||||
CHECK_MPI_OK( mp_init(&x2) );
|
||||
CHECK_MPI_OK( mp_init(&z1) );
|
||||
CHECK_MPI_OK( mp_init(&z2) );
|
||||
|
||||
p_size = mp_bpoly2arr(pp, p, 0) + 1;
|
||||
p = (unsigned int *) (malloc(sizeof(unsigned int) * p_size));
|
||||
if (p == NULL) goto cleanup;
|
||||
mp_bpoly2arr(pp, p, p_size);
|
||||
|
||||
/* if result should be point at infinity */
|
||||
if ((mp_cmp_z(n) == 0) || (GF2m_ec_pt_is_inf_aff(px, py) == MP_YES)) {
|
||||
CHECK_MPI_OK( GF2m_ec_pt_set_inf_aff(rx, ry) );
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
CHECK_MPI_OK( mp_copy(rx, &x2) ); /* x2 = rx */
|
||||
CHECK_MPI_OK( mp_copy(ry, &z2) ); /* z2 = ry */
|
||||
|
||||
CHECK_MPI_OK( mp_copy(px, &x1) ); /* x1 = px */
|
||||
mp_set(&z1, 0x1); /* z1 = 1 */
|
||||
CHECK_MPI_OK( mp_bsqrmod(&x1, p, &z2) ); /* z2 = x1^2 = x2^2 */
|
||||
CHECK_MPI_OK( mp_bsqrmod(&z2, p, &x2) );
|
||||
CHECK_MPI_OK( mp_badd(&x2, b, &x2) ); /* x2 = px^4 + b */
|
||||
|
||||
/* find top-most bit and go one past it */
|
||||
i = MP_USED(n) - 1;
|
||||
j = MP_DIGIT_BIT - 1;
|
||||
top_bit = 1;
|
||||
top_bit <<= MP_DIGIT_BIT - 1;
|
||||
mask = top_bit;
|
||||
while (!(MP_DIGITS(n)[i] & mask)) {
|
||||
mask >>= 1;
|
||||
j--;
|
||||
}
|
||||
mask >>= 1; j--;
|
||||
|
||||
/* if top most bit was at word break, go to next word */
|
||||
if (!mask) {
|
||||
i--;
|
||||
j = MP_DIGIT_BIT - 1;
|
||||
mask = top_bit;
|
||||
}
|
||||
|
||||
for (; i >= 0; i--) {
|
||||
for (; j >= 0; j--) {
|
||||
if (MP_DIGITS(n)[i] & mask) {
|
||||
CHECK_MPI_OK( gf2m_Madd(pp, p, a, b, px, &x1, &z1, &x2, &z2) );
|
||||
CHECK_MPI_OK( gf2m_Mdouble(pp, p, a, b, &x2, &z2) );
|
||||
} else {
|
||||
CHECK_MPI_OK( gf2m_Madd(pp, p, a, b, px, &x2, &z2, &x1, &z1) );
|
||||
CHECK_MPI_OK( gf2m_Mdouble(pp, p, a, b, &x1, &z1) );
|
||||
}
|
||||
mask >>= 1;
|
||||
}
|
||||
j = MP_DIGIT_BIT - 1;
|
||||
mask = top_bit;
|
||||
}
|
||||
|
||||
/* convert out of "projective" coordinates */
|
||||
i = gf2m_Mxy(pp, p, a, b, px, py, &x1, &z1, &x2, &z2);
|
||||
if (i == 0) {
|
||||
err = MP_BADARG;
|
||||
goto cleanup;
|
||||
} else if (i == 1) {
|
||||
CHECK_MPI_OK( GF2m_ec_pt_set_inf_aff(rx, ry) );
|
||||
} else {
|
||||
CHECK_MPI_OK( mp_copy(&x2, rx) );
|
||||
CHECK_MPI_OK( mp_copy(&z2, ry) );
|
||||
}
|
||||
|
||||
cleanup:
|
||||
mp_clear(&x1);
|
||||
mp_clear(&x2);
|
||||
mp_clear(&z1);
|
||||
mp_clear(&z2);
|
||||
free(p);
|
||||
return err;
|
||||
}
|
||||
|
||||
#endif /* NSS_ENABLE_ECC */
|
||||
@@ -1,96 +0,0 @@
|
||||
/*
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF 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 elliptic curve math library for binary polynomial
|
||||
* field curves.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Sun Microsystems, Inc.
|
||||
* Portions created by Sun Microsystems, Inc. are Copyright (C) 2003
|
||||
* Sun Microsystems, Inc. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Douglas Stebila <douglas@stebila.ca>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __gf2m_ecl_h_
|
||||
#define __gf2m_ecl_h_
|
||||
#ifdef NSS_ENABLE_ECC
|
||||
|
||||
#include "secmpi.h"
|
||||
|
||||
/* Checks if point P(px, py) is at infinity. Uses affine coordinates. */
|
||||
mp_err GF2m_ec_pt_is_inf_aff(const mp_int *px, const mp_int *py);
|
||||
|
||||
/* Sets P(px, py) to be the point at infinity. Uses affine coordinates. */
|
||||
mp_err GF2m_ec_pt_set_inf_aff(mp_int *px, mp_int *py);
|
||||
|
||||
/* Computes R = P + Q where R is (rx, ry), P is (px, py) and Q is (qx, qy).
|
||||
* Uses affine coordinates.
|
||||
*/
|
||||
mp_err GF2m_ec_pt_add_aff(const mp_int *pp, const mp_int *a,
|
||||
const mp_int *px, const mp_int *py, const mp_int *qx, const mp_int *qy,
|
||||
mp_int *rx, mp_int *ry);
|
||||
|
||||
/* Computes R = P - Q. Uses affine coordinates. */
|
||||
mp_err GF2m_ec_pt_sub_aff(const mp_int *pp, const mp_int *a,
|
||||
const mp_int *px, const mp_int *py, const mp_int *qx, const mp_int *qy,
|
||||
mp_int *rx, mp_int *ry);
|
||||
|
||||
/* Computes R = 2P. Uses affine coordinates. */
|
||||
mp_err GF2m_ec_pt_dbl_aff(const mp_int *pp, const mp_int *a,
|
||||
const mp_int *px, const mp_int *py, mp_int *rx, mp_int *ry);
|
||||
|
||||
/* Computes R = nP where R is (rx, ry) and P is (px, py). The parameters
|
||||
* a, b and p are the elliptic curve coefficients and the irreducible that
|
||||
* determines the field GF2m. Uses affine coordinates.
|
||||
*/
|
||||
mp_err GF2m_ec_pt_mul_aff(const mp_int *pp, const mp_int *a, const mp_int *b,
|
||||
const mp_int *px, const mp_int *py, const mp_int *n,
|
||||
mp_int *rx, mp_int *ry);
|
||||
|
||||
/* Computes R = nP where R is (rx, ry) and P is (px, py). The parameters
|
||||
* a, b and p are the elliptic curve coefficients and the irreducible that
|
||||
* determines the field GF2m. Uses Montgomery projective coordinates.
|
||||
*/
|
||||
mp_err GF2m_ec_pt_mul_mont(const mp_int *pp, const mp_int *a,
|
||||
const mp_int *b, const mp_int *px, const mp_int *py,
|
||||
const mp_int *n, mp_int *rx, mp_int *ry);
|
||||
|
||||
#define GF2m_ec_pt_is_inf(px, py) GF2m_ec_pt_is_inf_aff((px), (py))
|
||||
#define GF2m_ec_pt_add(p, a, px, py, qx, qy, rx, ry) \
|
||||
GF2m_ec_pt_add_aff((p), (a), (px), (py), (qx), (qy), (rx), (ry))
|
||||
|
||||
#define GF2m_ECL_MONTGOMERY
|
||||
#ifdef GF2m_ECL_AFFINE
|
||||
#define GF2m_ec_pt_mul(pp, a, b, px, py, n, rx, ry) \
|
||||
GF2m_ec_pt_mul_aff((pp), (a), (b), (px), (py), (n), (rx), (ry))
|
||||
#elif defined(GF2m_ECL_MONTGOMERY)
|
||||
#define GF2m_ec_pt_mul(pp, a, b, px, py, n, rx, ry) \
|
||||
GF2m_ec_pt_mul_mont((pp), (a), (b), (px), (py), (n), (rx), (ry))
|
||||
#endif /* GF2m_ECL_AFFINE or GF2m_ECL_MONTGOMERY */
|
||||
|
||||
#endif /* NSS_ENABLE_ECC */
|
||||
#endif /* __gf2m_ecl_h_ */
|
||||
@@ -1,647 +0,0 @@
|
||||
/*
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF 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 elliptic curve math library for prime
|
||||
* field curves.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Sun Microsystems, Inc.
|
||||
* Portions created by Sun Microsystems, Inc. are Copyright (C) 2003
|
||||
* Sun Microsystems, Inc. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Sheueling Chang Shantz <sheueling.chang@sun.com> and
|
||||
* Douglas Stebila <douglas@stebila.ca>, Sun Microsystems Laboratories
|
||||
*
|
||||
* Bodo Moeller <moeller@cdc.informatik.tu-darmstadt.de>,
|
||||
* Nils Larsch <nla@trustcenter.de>, and
|
||||
* Lenka Fibikova <fibikova@exp-math.uni-essen.de>, the OpenSSL Project.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
#ifdef NSS_ENABLE_ECC
|
||||
/*
|
||||
* GFp_ecl.c: Contains an implementation of elliptic curve math library
|
||||
* for curves over GFp.
|
||||
*
|
||||
* XXX Can be moved to a separate subdirectory later.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "GFp_ecl.h"
|
||||
#include "mpi/mplogic.h"
|
||||
|
||||
/* Checks if point P(px, py) is at infinity. Uses affine coordinates. */
|
||||
mp_err
|
||||
GFp_ec_pt_is_inf_aff(const mp_int *px, const mp_int *py)
|
||||
{
|
||||
|
||||
if ((mp_cmp_z(px) == 0) && (mp_cmp_z(py) == 0)) {
|
||||
return MP_YES;
|
||||
} else {
|
||||
return MP_NO;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Sets P(px, py) to be the point at infinity. Uses affine coordinates. */
|
||||
mp_err
|
||||
GFp_ec_pt_set_inf_aff(mp_int *px, mp_int *py)
|
||||
{
|
||||
mp_zero(px);
|
||||
mp_zero(py);
|
||||
return MP_OKAY;
|
||||
}
|
||||
|
||||
/* Computes R = P + Q based on IEEE P1363 A.10.1.
|
||||
* Elliptic curve points P, Q, and R can all be identical.
|
||||
* Uses affine coordinates.
|
||||
*/
|
||||
mp_err
|
||||
GFp_ec_pt_add_aff(const mp_int *p, const mp_int *a, const mp_int *px,
|
||||
const mp_int *py, const mp_int *qx, const mp_int *qy,
|
||||
mp_int *rx, mp_int *ry)
|
||||
{
|
||||
mp_err err = MP_OKAY;
|
||||
mp_int lambda, temp, xtemp, ytemp;
|
||||
|
||||
CHECK_MPI_OK( mp_init(&lambda) );
|
||||
CHECK_MPI_OK( mp_init(&temp) );
|
||||
CHECK_MPI_OK( mp_init(&xtemp) );
|
||||
CHECK_MPI_OK( mp_init(&ytemp) );
|
||||
/* if P = inf, then R = Q */
|
||||
if (GFp_ec_pt_is_inf_aff(px, py) == 0) {
|
||||
CHECK_MPI_OK( mp_copy(qx, rx) );
|
||||
CHECK_MPI_OK( mp_copy(qy, ry) );
|
||||
err = MP_OKAY;
|
||||
goto cleanup;
|
||||
}
|
||||
/* if Q = inf, then R = P */
|
||||
if (GFp_ec_pt_is_inf_aff(qx, qy) == 0) {
|
||||
CHECK_MPI_OK( mp_copy(px, rx) );
|
||||
CHECK_MPI_OK( mp_copy(py, ry) );
|
||||
err = MP_OKAY;
|
||||
goto cleanup;
|
||||
}
|
||||
/* if px != qx, then lambda = (py-qy) / (px-qx) */
|
||||
if (mp_cmp(px, qx) != 0) {
|
||||
CHECK_MPI_OK( mp_submod(py, qy, p, &ytemp) );
|
||||
CHECK_MPI_OK( mp_submod(px, qx, p, &xtemp) );
|
||||
CHECK_MPI_OK( mp_invmod(&xtemp, p, &xtemp) );
|
||||
CHECK_MPI_OK( mp_mulmod(&ytemp, &xtemp, p, &lambda) );
|
||||
} else {
|
||||
/* if py != qy or qy = 0, then R = inf */
|
||||
if (((mp_cmp(py, qy) != 0)) || (mp_cmp_z(qy) == 0)) {
|
||||
mp_zero(rx);
|
||||
mp_zero(ry);
|
||||
err = MP_OKAY;
|
||||
goto cleanup;
|
||||
}
|
||||
/* lambda = (3qx^2+a) / (2qy) */
|
||||
CHECK_MPI_OK( mp_sqrmod(qx, p, &xtemp) );
|
||||
mp_set(&temp, 0x3);
|
||||
CHECK_MPI_OK( mp_mulmod(&xtemp, &temp, p, &xtemp) );
|
||||
CHECK_MPI_OK( mp_addmod(&xtemp, a, p, &xtemp) );
|
||||
mp_set(&temp, 0x2);
|
||||
CHECK_MPI_OK( mp_mulmod(qy, &temp, p, &ytemp) );
|
||||
CHECK_MPI_OK( mp_invmod(&ytemp, p, &ytemp) );
|
||||
CHECK_MPI_OK( mp_mulmod(&xtemp, &ytemp, p, &lambda) );
|
||||
}
|
||||
/* rx = lambda^2 - px - qx */
|
||||
CHECK_MPI_OK( mp_sqrmod(&lambda, p, &xtemp) );
|
||||
CHECK_MPI_OK( mp_submod(&xtemp, px, p, &xtemp) );
|
||||
CHECK_MPI_OK( mp_submod(&xtemp, qx, p, &xtemp) );
|
||||
/* ry = (x1-x2) * lambda - y1 */
|
||||
CHECK_MPI_OK( mp_submod(qx, &xtemp, p, &ytemp) );
|
||||
CHECK_MPI_OK( mp_mulmod(&ytemp, &lambda, p, &ytemp) );
|
||||
CHECK_MPI_OK( mp_submod(&ytemp, qy, p, &ytemp) );
|
||||
CHECK_MPI_OK( mp_copy(&xtemp, rx) );
|
||||
CHECK_MPI_OK( mp_copy(&ytemp, ry) );
|
||||
|
||||
cleanup:
|
||||
mp_clear(&lambda);
|
||||
mp_clear(&temp);
|
||||
mp_clear(&xtemp);
|
||||
mp_clear(&ytemp);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Computes R = P - Q.
|
||||
* Elliptic curve points P, Q, and R can all be identical.
|
||||
* Uses affine coordinates.
|
||||
*/
|
||||
mp_err
|
||||
GFp_ec_pt_sub_aff(const mp_int *p, const mp_int *a, const mp_int *px,
|
||||
const mp_int *py, const mp_int *qx, const mp_int *qy,
|
||||
mp_int *rx, mp_int *ry)
|
||||
{
|
||||
mp_err err = MP_OKAY;
|
||||
mp_int nqy;
|
||||
MP_DIGITS(&nqy) = 0;
|
||||
CHECK_MPI_OK( mp_init(&nqy) );
|
||||
/* nqy = -qy */
|
||||
CHECK_MPI_OK( mp_neg(qy, &nqy) );
|
||||
err = GFp_ec_pt_add_aff(p, a, px, py, qx, &nqy, rx, ry);
|
||||
cleanup:
|
||||
mp_clear(&nqy);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Computes R = 2P.
|
||||
* Elliptic curve points P and R can be identical.
|
||||
* Uses affine coordinates.
|
||||
*/
|
||||
mp_err
|
||||
GFp_ec_pt_dbl_aff(const mp_int *p, const mp_int *a, const mp_int *px,
|
||||
const mp_int *py, mp_int *rx, mp_int *ry)
|
||||
{
|
||||
return GFp_ec_pt_add_aff(p, a, px, py, px, py, rx, ry);
|
||||
}
|
||||
|
||||
/* Gets the i'th bit in the binary representation of a.
|
||||
* If i >= length(a), then return 0.
|
||||
* (The above behaviour differs from mpl_get_bit, which
|
||||
* causes an error if i >= length(a).)
|
||||
*/
|
||||
#define MP_GET_BIT(a, i) \
|
||||
((i) >= mpl_significant_bits((a))) ? 0 : mpl_get_bit((a), (i))
|
||||
|
||||
/* Computes R = nP based on IEEE P1363 A.10.3.
|
||||
* Elliptic curve points P and R can be identical.
|
||||
* Uses affine coordinates.
|
||||
*/
|
||||
mp_err
|
||||
GFp_ec_pt_mul_aff(const mp_int *p, const mp_int *a, const mp_int *b,
|
||||
const mp_int *px, const mp_int *py, const mp_int *n, mp_int *rx,
|
||||
mp_int *ry)
|
||||
{
|
||||
mp_err err = MP_OKAY;
|
||||
mp_int k, k3, qx, qy, sx, sy;
|
||||
int b1, b3, i, l;
|
||||
|
||||
MP_DIGITS(&k) = 0;
|
||||
MP_DIGITS(&k3) = 0;
|
||||
MP_DIGITS(&qx) = 0;
|
||||
MP_DIGITS(&qy) = 0;
|
||||
MP_DIGITS(&sx) = 0;
|
||||
MP_DIGITS(&sy) = 0;
|
||||
CHECK_MPI_OK( mp_init(&k) );
|
||||
CHECK_MPI_OK( mp_init(&k3) );
|
||||
CHECK_MPI_OK( mp_init(&qx) );
|
||||
CHECK_MPI_OK( mp_init(&qy) );
|
||||
CHECK_MPI_OK( mp_init(&sx) );
|
||||
CHECK_MPI_OK( mp_init(&sy) );
|
||||
|
||||
/* if n = 0 then r = inf */
|
||||
if (mp_cmp_z(n) == 0) {
|
||||
mp_zero(rx);
|
||||
mp_zero(ry);
|
||||
err = MP_OKAY;
|
||||
goto cleanup;
|
||||
}
|
||||
/* Q = P, k = n */
|
||||
CHECK_MPI_OK( mp_copy(px, &qx) );
|
||||
CHECK_MPI_OK( mp_copy(py, &qy) );
|
||||
CHECK_MPI_OK( mp_copy(n, &k) );
|
||||
/* if n < 0 Q = -Q, k = -k */
|
||||
if (mp_cmp_z(n) < 0) {
|
||||
CHECK_MPI_OK( mp_neg(&qy, &qy) );
|
||||
CHECK_MPI_OK( mp_mod(&qy, p, &qy) );
|
||||
CHECK_MPI_OK( mp_neg(&k, &k) );
|
||||
CHECK_MPI_OK( mp_mod(&k, p, &k) );
|
||||
}
|
||||
#ifdef EC_DEBUG /* basic double and add method */
|
||||
l = mpl_significant_bits(&k) - 1;
|
||||
mp_zero(&sx);
|
||||
mp_zero(&sy);
|
||||
for (i = l; i >= 0; i--) {
|
||||
/* if k_i = 1, then S = S + Q */
|
||||
if (mpl_get_bit(&k, i) != 0) {
|
||||
CHECK_MPI_OK( GFp_ec_pt_add_aff(p, a, &sx, &sy,
|
||||
&qx, &qy, &sx, &sy) );
|
||||
}
|
||||
if (i > 0) {
|
||||
/* S = 2S */
|
||||
CHECK_MPI_OK( GFp_ec_pt_dbl_aff(p, a, &sx, &sy, &sx, &sy) );
|
||||
}
|
||||
}
|
||||
#else /* double and add/subtract method from standard */
|
||||
/* k3 = 3 * k */
|
||||
mp_set(&k3, 0x3);
|
||||
CHECK_MPI_OK( mp_mul(&k, &k3, &k3) );
|
||||
/* S = Q */
|
||||
CHECK_MPI_OK( mp_copy(&qx, &sx) );
|
||||
CHECK_MPI_OK( mp_copy(&qy, &sy) );
|
||||
/* l = index of high order bit in binary representation of 3*k */
|
||||
l = mpl_significant_bits(&k3) - 1;
|
||||
/* for i = l-1 downto 1 */
|
||||
for (i = l - 1; i >= 1; i--) {
|
||||
/* S = 2S */
|
||||
CHECK_MPI_OK( GFp_ec_pt_dbl_aff(p, a, &sx, &sy, &sx, &sy) );
|
||||
b3 = MP_GET_BIT(&k3, i);
|
||||
b1 = MP_GET_BIT(&k, i);
|
||||
/* if k3_i = 1 and k_i = 0, then S = S + Q */
|
||||
if ((b3 == 1) && (b1 == 0)) {
|
||||
CHECK_MPI_OK( GFp_ec_pt_add_aff(p, a, &sx, &sy,
|
||||
&qx, &qy, &sx, &sy) );
|
||||
/* if k3_i = 0 and k_i = 1, then S = S - Q */
|
||||
} else if ((b3 == 0) && (b1 == 1)) {
|
||||
CHECK_MPI_OK( GFp_ec_pt_sub_aff(p, a, &sx, &sy,
|
||||
&qx, &qy, &sx, &sy) );
|
||||
}
|
||||
}
|
||||
#endif
|
||||
/* output S */
|
||||
CHECK_MPI_OK( mp_copy(&sx, rx) );
|
||||
CHECK_MPI_OK( mp_copy(&sy, ry) );
|
||||
|
||||
cleanup:
|
||||
mp_clear(&k);
|
||||
mp_clear(&k3);
|
||||
mp_clear(&qx);
|
||||
mp_clear(&qy);
|
||||
mp_clear(&sx);
|
||||
mp_clear(&sy);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Converts a point P(px, py, pz) from Jacobian projective coordinates to
|
||||
* affine coordinates R(rx, ry). P and R can share x and y coordinates.
|
||||
*/
|
||||
mp_err
|
||||
GFp_ec_pt_jac2aff(const mp_int *px, const mp_int *py, const mp_int *pz,
|
||||
const mp_int *p, mp_int *rx, mp_int *ry)
|
||||
{
|
||||
mp_err err = MP_OKAY;
|
||||
mp_int z1, z2, z3;
|
||||
MP_DIGITS(&z1) = 0;
|
||||
MP_DIGITS(&z2) = 0;
|
||||
MP_DIGITS(&z3) = 0;
|
||||
CHECK_MPI_OK( mp_init(&z1) );
|
||||
CHECK_MPI_OK( mp_init(&z2) );
|
||||
CHECK_MPI_OK( mp_init(&z3) );
|
||||
|
||||
/* if point at infinity, then set point at infinity and exit */
|
||||
if (GFp_ec_pt_is_inf_jac(px, py, pz) == MP_YES) {
|
||||
CHECK_MPI_OK( GFp_ec_pt_set_inf_aff(rx, ry) );
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* transform (px, py, pz) into (px / pz^2, py / pz^3) */
|
||||
if (mp_cmp_d(pz, 1) == 0) {
|
||||
CHECK_MPI_OK( mp_copy(px, rx) );
|
||||
CHECK_MPI_OK( mp_copy(py, ry) );
|
||||
} else {
|
||||
CHECK_MPI_OK( mp_invmod(pz, p, &z1) );
|
||||
CHECK_MPI_OK( mp_sqrmod(&z1, p, &z2) );
|
||||
CHECK_MPI_OK( mp_mulmod(&z1, &z2, p, &z3) );
|
||||
CHECK_MPI_OK( mp_mulmod(px, &z2, p, rx) );
|
||||
CHECK_MPI_OK( mp_mulmod(py, &z3, p, ry) );
|
||||
}
|
||||
|
||||
cleanup:
|
||||
mp_clear(&z1);
|
||||
mp_clear(&z2);
|
||||
mp_clear(&z3);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Checks if point P(px, py, pz) is at infinity.
|
||||
* Uses Jacobian coordinates.
|
||||
*/
|
||||
mp_err
|
||||
GFp_ec_pt_is_inf_jac(const mp_int *px, const mp_int *py, const mp_int *pz)
|
||||
{
|
||||
return mp_cmp_z(pz);
|
||||
}
|
||||
|
||||
/* Sets P(px, py, pz) to be the point at infinity. Uses Jacobian
|
||||
* coordinates.
|
||||
*/
|
||||
mp_err
|
||||
GFp_ec_pt_set_inf_jac(mp_int *px, mp_int *py, mp_int *pz)
|
||||
{
|
||||
mp_zero(pz);
|
||||
return MP_OKAY;
|
||||
}
|
||||
|
||||
/* Computes R = P + Q where R is (rx, ry, rz), P is (px, py, pz) and
|
||||
* Q is (qx, qy, qz). Elliptic curve points P, Q, and R can all be
|
||||
* identical. Uses Jacobian coordinates.
|
||||
*
|
||||
* This routine implements Point Addition in the Jacobian Projective
|
||||
* space as described in the paper "Efficient elliptic curve exponentiation
|
||||
* using mixed coordinates", by H. Cohen, A Miyaji, T. Ono.
|
||||
*/
|
||||
mp_err
|
||||
GFp_ec_pt_add_jac(const mp_int *p, const mp_int *a, const mp_int *px,
|
||||
const mp_int *py, const mp_int *pz, const mp_int *qx,
|
||||
const mp_int *qy, const mp_int *qz, mp_int *rx, mp_int *ry, mp_int *rz)
|
||||
{
|
||||
mp_err err = MP_OKAY;
|
||||
mp_int n0, u1, u2, s1, s2, H, G;
|
||||
MP_DIGITS(&n0) = 0;
|
||||
MP_DIGITS(&u1) = 0;
|
||||
MP_DIGITS(&u2) = 0;
|
||||
MP_DIGITS(&s1) = 0;
|
||||
MP_DIGITS(&s2) = 0;
|
||||
MP_DIGITS(&H) = 0;
|
||||
MP_DIGITS(&G) = 0;
|
||||
CHECK_MPI_OK( mp_init(&n0) );
|
||||
CHECK_MPI_OK( mp_init(&u1) );
|
||||
CHECK_MPI_OK( mp_init(&u2) );
|
||||
CHECK_MPI_OK( mp_init(&s1) );
|
||||
CHECK_MPI_OK( mp_init(&s2) );
|
||||
CHECK_MPI_OK( mp_init(&H) );
|
||||
CHECK_MPI_OK( mp_init(&G) );
|
||||
|
||||
/* Use point double if pointers are equal. */
|
||||
if ((px == qx) && (py == qy) && (pz == qz)) {
|
||||
err = GFp_ec_pt_dbl_jac(p, a, px, py, pz, rx, ry, rz);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* If either P or Q is the point at infinity, then return
|
||||
* the other point
|
||||
*/
|
||||
if (GFp_ec_pt_is_inf_jac(px, py, pz) == MP_YES) {
|
||||
CHECK_MPI_OK( mp_copy(qx, rx) );
|
||||
CHECK_MPI_OK( mp_copy(qy, ry) );
|
||||
CHECK_MPI_OK( mp_copy(qz, rz) );
|
||||
goto cleanup;
|
||||
}
|
||||
if (GFp_ec_pt_is_inf_jac(qx, qy, qz) == MP_YES) {
|
||||
CHECK_MPI_OK( mp_copy(px, rx) );
|
||||
CHECK_MPI_OK( mp_copy(py, ry) );
|
||||
CHECK_MPI_OK( mp_copy(pz, rz) );
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Compute u1 = px * qz^2, s1 = py * qz^3 */
|
||||
if (mp_cmp_d(qz, 1) == 0) {
|
||||
CHECK_MPI_OK( mp_copy(px, &u1) );
|
||||
CHECK_MPI_OK( mp_copy(py, &s1) );
|
||||
} else {
|
||||
CHECK_MPI_OK( mp_sqrmod(qz, p, &n0) );
|
||||
CHECK_MPI_OK( mp_mulmod(px, &n0, p, &u1) );
|
||||
CHECK_MPI_OK( mp_mulmod(&n0, qz, p, &n0) );
|
||||
CHECK_MPI_OK( mp_mulmod(py, &n0, p, &s1) );
|
||||
}
|
||||
|
||||
/* Compute u2 = qx * pz^2, s2 = qy * pz^3 */
|
||||
if (mp_cmp_d(pz, 1) == 0) {
|
||||
CHECK_MPI_OK( mp_copy(qx, &u2) );
|
||||
CHECK_MPI_OK( mp_copy(qy, &s2) );
|
||||
} else {
|
||||
CHECK_MPI_OK( mp_sqrmod(pz, p, &n0) );
|
||||
CHECK_MPI_OK( mp_mulmod(qx, &n0, p, &u2) );
|
||||
CHECK_MPI_OK( mp_mulmod(&n0, pz, p, &n0) );
|
||||
CHECK_MPI_OK( mp_mulmod(qy, &n0, p, &s2) );
|
||||
}
|
||||
|
||||
/* Compute H = u2 - u1 ; G = s2 - s1 */
|
||||
CHECK_MPI_OK( mp_submod(&u2, &u1, p, &H) );
|
||||
CHECK_MPI_OK( mp_submod(&s2, &s1, p, &G) );
|
||||
|
||||
if (mp_cmp_z(&H) == 0) {
|
||||
if (mp_cmp_z(&G) == 0) {
|
||||
/* P = Q; double */
|
||||
err = GFp_ec_pt_dbl_jac(p, a, px, py, pz,
|
||||
rx, ry, rz);
|
||||
goto cleanup;
|
||||
} else {
|
||||
/* P = -Q; return point at infinity */
|
||||
CHECK_MPI_OK( GFp_ec_pt_set_inf_jac(rx, ry, rz) );
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
/* rz = pz * qz * H */
|
||||
if (mp_cmp_d(pz, 1) == 0) {
|
||||
if (mp_cmp_d(qz, 1) == 0) {
|
||||
/* if pz == qz == 1, then rz = H */
|
||||
CHECK_MPI_OK( mp_copy(&H, rz) );
|
||||
} else {
|
||||
CHECK_MPI_OK( mp_mulmod(qz, &H, p, rz) );
|
||||
}
|
||||
} else {
|
||||
if (mp_cmp_d(qz, 1) == 0) {
|
||||
CHECK_MPI_OK( mp_mulmod(pz, &H, p, rz) );
|
||||
} else {
|
||||
CHECK_MPI_OK( mp_mulmod(pz, qz, p, &n0) );
|
||||
CHECK_MPI_OK( mp_mulmod(&n0, &H, p, rz) );
|
||||
}
|
||||
}
|
||||
|
||||
/* rx = G^2 - H^3 - 2 * u1 * H^2 */
|
||||
CHECK_MPI_OK( mp_sqrmod(&G, p, rx) );
|
||||
CHECK_MPI_OK( mp_sqrmod(&H, p, &n0) );
|
||||
CHECK_MPI_OK( mp_mulmod(&n0, &u1, p, &u1) );
|
||||
CHECK_MPI_OK( mp_addmod(&u1, &u1, p, &u2) );
|
||||
CHECK_MPI_OK( mp_mulmod(&H, &n0, p, &H) );
|
||||
CHECK_MPI_OK( mp_submod(rx, &H, p, rx) );
|
||||
CHECK_MPI_OK( mp_submod(rx, &u2, p, rx) );
|
||||
|
||||
/* ry = - s1 * H^3 + G * (u1 * H^2 - rx) */
|
||||
/* (formula based on values of variables before block above) */
|
||||
CHECK_MPI_OK( mp_submod(&u1, rx, p, &u1) );
|
||||
CHECK_MPI_OK( mp_mulmod(&G, &u1, p, ry) );
|
||||
CHECK_MPI_OK( mp_mulmod(&s1, &H, p, &s1) );
|
||||
CHECK_MPI_OK( mp_submod(ry, &s1, p, ry) );
|
||||
|
||||
cleanup:
|
||||
mp_clear(&n0);
|
||||
mp_clear(&u1);
|
||||
mp_clear(&u2);
|
||||
mp_clear(&s1);
|
||||
mp_clear(&s2);
|
||||
mp_clear(&H);
|
||||
mp_clear(&G);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Computes R = 2P. Elliptic curve points P and R can be identical. Uses
|
||||
* Jacobian coordinates.
|
||||
*
|
||||
* This routine implements Point Doubling in the Jacobian Projective
|
||||
* space as described in the paper "Efficient elliptic curve exponentiation
|
||||
* using mixed coordinates", by H. Cohen, A Miyaji, T. Ono.
|
||||
*/
|
||||
mp_err
|
||||
GFp_ec_pt_dbl_jac(const mp_int *p, const mp_int *a, const mp_int *px,
|
||||
const mp_int *py, const mp_int *pz, mp_int *rx, mp_int *ry, mp_int *rz)
|
||||
{
|
||||
mp_err err = MP_OKAY;
|
||||
mp_int t0, t1, M, S;
|
||||
MP_DIGITS(&t0) = 0;
|
||||
MP_DIGITS(&t1) = 0;
|
||||
MP_DIGITS(&M) = 0;
|
||||
MP_DIGITS(&S) = 0;
|
||||
CHECK_MPI_OK( mp_init(&t0) );
|
||||
CHECK_MPI_OK( mp_init(&t1) );
|
||||
CHECK_MPI_OK( mp_init(&M) );
|
||||
CHECK_MPI_OK( mp_init(&S) );
|
||||
|
||||
if (GFp_ec_pt_is_inf_jac(px, py, pz) == MP_YES) {
|
||||
CHECK_MPI_OK( GFp_ec_pt_set_inf_jac(rx, ry, rz) );
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (mp_cmp_d(pz, 1) == 0) {
|
||||
/* M = 3 * px^2 + a */
|
||||
CHECK_MPI_OK( mp_sqrmod(px, p, &t0) );
|
||||
CHECK_MPI_OK( mp_addmod(&t0, &t0, p, &M) );
|
||||
CHECK_MPI_OK( mp_addmod(&t0, &M, p, &t0) );
|
||||
CHECK_MPI_OK( mp_addmod(&t0, a, p, &M) );
|
||||
} else if (mp_cmp_int(a, -3) == 0) {
|
||||
/* M = 3 * (px + pz^2) * (px - pz) */
|
||||
CHECK_MPI_OK( mp_sqrmod(pz, p, &M) );
|
||||
CHECK_MPI_OK( mp_addmod(px, &M, p, &t0) );
|
||||
CHECK_MPI_OK( mp_submod(px, &M, p, &t1) );
|
||||
CHECK_MPI_OK( mp_mulmod(&t0, &t1, p, &M) );
|
||||
CHECK_MPI_OK( mp_addmod(&M, &M, p, &t0) );
|
||||
CHECK_MPI_OK( mp_addmod(&t0, &M, p, &M) );
|
||||
} else {
|
||||
CHECK_MPI_OK( mp_sqrmod(px, p, &t0) );
|
||||
CHECK_MPI_OK( mp_addmod(&t0, &t0, p, &M) );
|
||||
CHECK_MPI_OK( mp_addmod(&t0, &M, p, &t0) );
|
||||
CHECK_MPI_OK( mp_sqrmod(pz, p, &M) );
|
||||
CHECK_MPI_OK( mp_sqrmod(&M, p, &M) );
|
||||
CHECK_MPI_OK( mp_mulmod(&M, a, p, &M) );
|
||||
CHECK_MPI_OK( mp_addmod(&M, &t0, p, &M) );
|
||||
}
|
||||
|
||||
/* rz = 2 * py * pz */
|
||||
if (mp_cmp_d(pz, 1) == 0) {
|
||||
CHECK_MPI_OK( mp_addmod(py, py, p, rz) );
|
||||
CHECK_MPI_OK( mp_sqrmod(rz, p, &t0) );
|
||||
} else {
|
||||
CHECK_MPI_OK( mp_addmod(py, py, p, &t0) );
|
||||
CHECK_MPI_OK( mp_mulmod(&t0, pz, p, rz) );
|
||||
CHECK_MPI_OK( mp_sqrmod(&t0, p, &t0) );
|
||||
}
|
||||
|
||||
/* S = 4 * px * py^2 = pz * (2 * py)^2 */
|
||||
CHECK_MPI_OK( mp_mulmod(px, &t0, p, &S) );
|
||||
|
||||
/* rx = M^2 - 2 * S */
|
||||
CHECK_MPI_OK( mp_addmod(&S, &S, p, &t1) );
|
||||
CHECK_MPI_OK( mp_sqrmod(&M, p, rx) );
|
||||
CHECK_MPI_OK( mp_submod(rx, &t1, p, rx) );
|
||||
|
||||
/* ry = M * (S - rx) - 8 * py^4 */
|
||||
CHECK_MPI_OK( mp_sqrmod(&t0, p, &t1) );
|
||||
if (mp_isodd(&t1)) {
|
||||
CHECK_MPI_OK( mp_add(&t1, p, &t1) );
|
||||
}
|
||||
CHECK_MPI_OK( mp_div_2(&t1, &t1) );
|
||||
CHECK_MPI_OK( mp_submod(&S, rx, p, &S) );
|
||||
CHECK_MPI_OK( mp_mulmod(&M, &S, p, &M) );
|
||||
CHECK_MPI_OK( mp_submod(&M, &t1, p, ry) );
|
||||
|
||||
cleanup:
|
||||
mp_clear(&t0);
|
||||
mp_clear(&t1);
|
||||
mp_clear(&M);
|
||||
mp_clear(&S);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Computes R = nP where R is (rx, ry) and P is (px, py). The parameters
|
||||
* a, b and p are the elliptic curve coefficients and the prime that
|
||||
* determines the field GFp. Elliptic curve points P and R can be
|
||||
* identical. Uses Jacobian coordinates.
|
||||
*/
|
||||
mp_err
|
||||
GFp_ec_pt_mul_jac(const mp_int *p, const mp_int *a, const mp_int *b,
|
||||
const mp_int *px, const mp_int *py, const mp_int *n,
|
||||
mp_int *rx, mp_int *ry)
|
||||
{
|
||||
mp_err err = MP_OKAY;
|
||||
mp_int k, qx, qy, qz, sx, sy, sz;
|
||||
int i, l;
|
||||
|
||||
MP_DIGITS(&k) = 0;
|
||||
MP_DIGITS(&qx) = 0;
|
||||
MP_DIGITS(&qy) = 0;
|
||||
MP_DIGITS(&qz) = 0;
|
||||
MP_DIGITS(&sx) = 0;
|
||||
MP_DIGITS(&sy) = 0;
|
||||
MP_DIGITS(&sz) = 0;
|
||||
CHECK_MPI_OK( mp_init(&k) );
|
||||
CHECK_MPI_OK( mp_init(&qx) );
|
||||
CHECK_MPI_OK( mp_init(&qy) );
|
||||
CHECK_MPI_OK( mp_init(&qz) );
|
||||
CHECK_MPI_OK( mp_init(&sx) );
|
||||
CHECK_MPI_OK( mp_init(&sy) );
|
||||
CHECK_MPI_OK( mp_init(&sz) );
|
||||
|
||||
/* if n = 0 then r = inf */
|
||||
if (mp_cmp_z(n) == 0) {
|
||||
mp_zero(rx);
|
||||
mp_zero(ry);
|
||||
err = MP_OKAY;
|
||||
goto cleanup;
|
||||
/* if n < 0 then out of range error */
|
||||
} else if (mp_cmp_z(n) < 0) {
|
||||
err = MP_RANGE;
|
||||
goto cleanup;
|
||||
}
|
||||
/* Q = P, k = n */
|
||||
CHECK_MPI_OK( mp_copy(px, &qx) );
|
||||
CHECK_MPI_OK( mp_copy(py, &qy) );
|
||||
CHECK_MPI_OK( mp_set_int(&qz, 1) );
|
||||
CHECK_MPI_OK( mp_copy(n, &k) );
|
||||
|
||||
/* double and add method */
|
||||
l = mpl_significant_bits(&k) - 1;
|
||||
mp_zero(&sx);
|
||||
mp_zero(&sy);
|
||||
mp_zero(&sz);
|
||||
for (i = l; i >= 0; i--) {
|
||||
/* if k_i = 1, then S = S + Q */
|
||||
if (MP_GET_BIT(&k, i) != 0) {
|
||||
CHECK_MPI_OK( GFp_ec_pt_add_jac(p, a, &sx, &sy, &sz,
|
||||
&qx, &qy, &qz, &sx, &sy, &sz) );
|
||||
}
|
||||
if (i > 0) {
|
||||
/* S = 2S */
|
||||
CHECK_MPI_OK( GFp_ec_pt_dbl_jac(p, a, &sx, &sy, &sz,
|
||||
&sx, &sy, &sz) );
|
||||
}
|
||||
}
|
||||
|
||||
/* convert result S to affine coordinates */
|
||||
CHECK_MPI_OK( GFp_ec_pt_jac2aff(&sx, &sy, &sz, p, rx, ry) );
|
||||
|
||||
cleanup:
|
||||
mp_clear(&k);
|
||||
mp_clear(&qx);
|
||||
mp_clear(&qy);
|
||||
mp_clear(&qz);
|
||||
mp_clear(&sx);
|
||||
mp_clear(&sy);
|
||||
mp_clear(&sz);
|
||||
return err;
|
||||
}
|
||||
#endif /* NSS_ENABLE_ECC */
|
||||
@@ -1,126 +0,0 @@
|
||||
/*
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF 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 elliptic curve math library for prime
|
||||
* field curves.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Sun Microsystems, Inc.
|
||||
* Portions created by Sun Microsystems, Inc. are Copyright (C) 2003
|
||||
* Sun Microsystems, Inc. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Douglas Stebila <douglas@stebila.ca>, Sun Microsystems Laboratories
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __gfp_ecl_h_
|
||||
#define __gfp_ecl_h_
|
||||
#ifdef NSS_ENABLE_ECC
|
||||
|
||||
#include "secmpi.h"
|
||||
|
||||
/* Checks if point P(px, py) is at infinity. Uses affine coordinates. */
|
||||
extern mp_err GFp_ec_pt_is_inf_aff(const mp_int *px, const mp_int *py);
|
||||
|
||||
/* Sets P(px, py) to be the point at infinity. Uses affine coordinates. */
|
||||
extern mp_err GFp_ec_pt_set_inf_aff(mp_int *px, mp_int *py);
|
||||
|
||||
/* Computes R = P + Q where R is (rx, ry), P is (px, py) and Q is (qx, qy).
|
||||
* Uses affine coordinates.
|
||||
*/
|
||||
extern mp_err GFp_ec_pt_add_aff(const mp_int *p, const mp_int *a,
|
||||
const mp_int *px, const mp_int *py, const mp_int *qx, const mp_int *qy,
|
||||
mp_int *rx, mp_int *ry);
|
||||
|
||||
/* Computes R = P - Q. Uses affine coordinates. */
|
||||
extern mp_err GFp_ec_pt_sub_aff(const mp_int *p, const mp_int *a,
|
||||
const mp_int *px, const mp_int *py, const mp_int *qx, const mp_int *qy,
|
||||
mp_int *rx, mp_int *ry);
|
||||
|
||||
/* Computes R = 2P. Uses affine coordinates. */
|
||||
extern mp_err GFp_ec_pt_dbl_aff(const mp_int *p, const mp_int *a,
|
||||
const mp_int *px, const mp_int *py, mp_int *rx, mp_int *ry);
|
||||
|
||||
/* Computes R = nP where R is (rx, ry) and P is (px, py). The parameters
|
||||
* a, b and p are the elliptic curve coefficients and the prime that
|
||||
* determines the field GFp. Uses affine coordinates.
|
||||
*/
|
||||
extern mp_err GFp_ec_pt_mul_aff(const mp_int *p, const mp_int *a,
|
||||
const mp_int *b, const mp_int *px, const mp_int *py, const mp_int *n,
|
||||
mp_int *rx, mp_int *ry);
|
||||
|
||||
/* Converts a point P(px, py, pz) from Jacobian projective coordinates to
|
||||
* affine coordinates R(rx, ry).
|
||||
*/
|
||||
extern mp_err GFp_ec_pt_jac2aff(const mp_int *px, const mp_int *py,
|
||||
const mp_int *pz, const mp_int *p, mp_int *rx, mp_int *ry);
|
||||
|
||||
/* Checks if point P(px, py, pz) is at infinity. Uses Jacobian
|
||||
* coordinates.
|
||||
*/
|
||||
extern mp_err GFp_ec_pt_is_inf_jac(const mp_int *px, const mp_int *py,
|
||||
const mp_int *pz);
|
||||
|
||||
/* Sets P(px, py, pz) to be the point at infinity. Uses Jacobian
|
||||
* coordinates.
|
||||
*/
|
||||
extern mp_err GFp_ec_pt_set_inf_jac(mp_int *px, mp_int *py, mp_int *pz);
|
||||
|
||||
/* Computes R = P + Q where R is (rx, ry, rz), P is (px, py, pz) and
|
||||
* Q is (qx, qy, qz). Uses Jacobian coordinates.
|
||||
*/
|
||||
extern mp_err GFp_ec_pt_add_jac(const mp_int *p, const mp_int *a,
|
||||
const mp_int *px, const mp_int *py, const mp_int *pz,
|
||||
const mp_int *qx, const mp_int *qy, const mp_int *qz,
|
||||
mp_int *rx, mp_int *ry, mp_int *rz);
|
||||
|
||||
/* Computes R = 2P. Uses Jacobian coordinates. */
|
||||
extern mp_err GFp_ec_pt_dbl_jac(const mp_int *p, const mp_int *a,
|
||||
const mp_int *px, const mp_int *py, const mp_int *pz,
|
||||
mp_int *rx, mp_int *ry, mp_int *rz);
|
||||
|
||||
/* Computes R = nP where R is (rx, ry) and P is (px, py). The parameters
|
||||
* a, b and p are the elliptic curve coefficients and the prime that
|
||||
* determines the field GFp. Uses Jacobian coordinates.
|
||||
*/
|
||||
mp_err GFp_ec_pt_mul_jac(const mp_int *p, const mp_int *a, const mp_int *b,
|
||||
const mp_int *px, const mp_int *py, const mp_int *n,
|
||||
mp_int *rx, mp_int *ry);
|
||||
|
||||
#define GFp_ec_pt_is_inf(px, py) GFp_ec_pt_is_inf_aff((px), (py))
|
||||
#define GFp_ec_pt_add(p, a, px, py, qx, qy, rx, ry) \
|
||||
GFp_ec_pt_add_aff((p), (a), (px), (py), (qx), (qy), (rx), (ry))
|
||||
|
||||
#define GFp_ECL_JACOBIAN
|
||||
#ifdef GFp_ECL_AFFINE
|
||||
#define GFp_ec_pt_mul(p, a, b, px, py, n, rx, ry) \
|
||||
GFp_ec_pt_mul_aff((p), (a), (b), (px), (py), (n), (rx), (ry))
|
||||
#elif defined(GFp_ECL_JACOBIAN)
|
||||
#define GFp_ec_pt_mul(p, a, b, px, py, n, rx, ry) \
|
||||
GFp_ec_pt_mul_jac((p), (a), (b), (px), (py), (n), (rx), (ry))
|
||||
#endif /* GFp_ECL_AFFINE or GFp_ECL_JACOBIAN*/
|
||||
|
||||
#endif /* NSS_ENABLE_ECC */
|
||||
#endif /* __gfp_ecl_h_ */
|
||||
@@ -1,339 +0,0 @@
|
||||
#! gmake
|
||||
#
|
||||
# The contents of this file are subject to the Mozilla Public
|
||||
# License Version 1.1 (the "License"); you may not use this file
|
||||
# except in compliance with the License. You may obtain a copy of
|
||||
# the License at http://www.mozilla.org/MPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS
|
||||
# IS" basis, WITHOUT WARRANTY OF 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 Netscape security libraries.
|
||||
#
|
||||
# The Initial Developer of the Original Code is Netscape
|
||||
# Communications Corporation. Portions created by Netscape are
|
||||
# Copyright (C) 1994-2000 Netscape Communications Corporation. All
|
||||
# Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
#
|
||||
# Alternatively, the contents of this file may be used under the
|
||||
# terms of the GNU General Public License Version 2 or later (the
|
||||
# "GPL"), in which case the provisions of the GPL are applicable
|
||||
# instead of those above. If you wish to allow use of your
|
||||
# version of this file only under the terms of the GPL and not to
|
||||
# allow others to use your version of this file under the MPL,
|
||||
# indicate your decision by deleting the provisions above and
|
||||
# replace them with the notice and other provisions required by
|
||||
# the GPL. If you do not delete the provisions above, a recipient
|
||||
# may use your version of this file under either the MPL or the
|
||||
# GPL.
|
||||
#
|
||||
|
||||
#######################################################################
|
||||
# (1) Include initial platform-independent assignments (MANDATORY). #
|
||||
#######################################################################
|
||||
|
||||
include manifest.mn
|
||||
|
||||
#######################################################################
|
||||
# (2) Include "global" configuration information. (OPTIONAL) #
|
||||
#######################################################################
|
||||
|
||||
include $(CORE_DEPTH)/coreconf/config.mk
|
||||
|
||||
#######################################################################
|
||||
# (3) Include "component" configuration information. (OPTIONAL) #
|
||||
#######################################################################
|
||||
|
||||
|
||||
|
||||
#######################################################################
|
||||
# (4) Include "local" platform-dependent assignments (OPTIONAL). #
|
||||
#######################################################################
|
||||
|
||||
-include config.mk
|
||||
|
||||
ifdef USE_64
|
||||
DEFINES += -DNSS_USE_64
|
||||
endif
|
||||
|
||||
ifdef USE_HYBRID
|
||||
DEFINES += -DNSS_USE_HYBRID
|
||||
endif
|
||||
|
||||
# des.c wants _X86_ defined for intel CPUs.
|
||||
# coreconf does this for windows, but not for Linux, FreeBSD, etc.
|
||||
ifeq ($(CPU_ARCH),x86)
|
||||
ifneq (,$(filter-out WIN%,$(OS_TARGET)))
|
||||
OS_REL_CFLAGS += -D_X86_
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(OS_TARGET),OSF1)
|
||||
DEFINES += -DMP_ASSEMBLY_MULTIPLY -DMP_NO_MP_WORD
|
||||
MPI_SRCS += mpvalpha.c
|
||||
endif
|
||||
|
||||
ifeq (,$(filter-out WINNT WIN95,$(OS_TARGET))) #omits WIN16 and WINCE
|
||||
ifdef NS_USE_GCC
|
||||
# Ideally, we want to use assembler
|
||||
# ASFILES = mpi_x86.s
|
||||
# DEFINES += -DMP_ASSEMBLY_MULTIPLY -DMP_ASSEMBLY_SQUARE \
|
||||
# -DMP_ASSEMBLY_DIV_2DX1D
|
||||
# but we haven't figured out how to make it work, so we are not
|
||||
# using assembler right now.
|
||||
ASFILES =
|
||||
DEFINES += -DMP_NO_MP_WORD -DMP_USE_UINT_DIGIT
|
||||
else
|
||||
ASFILES = mpi_x86.asm
|
||||
DEFINES += -DMP_ASSEMBLY_MULTIPLY -DMP_ASSEMBLY_SQUARE -DMP_ASSEMBLY_DIV_2DX1D
|
||||
endif
|
||||
ifdef BUILD_OPT
|
||||
ifndef NS_USE_GCC
|
||||
OPTIMIZER += -Ox # maximum optimization for freebl
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(OS_TARGET),WINCE)
|
||||
DEFINES += -DMP_ARGCHK=0 # no assert in WinCE
|
||||
DEFINES += -DSHA_NO_LONG_LONG # avoid 64-bit arithmetic in SHA512
|
||||
endif
|
||||
|
||||
ifdef XP_OS2_VACPP
|
||||
ASFILES = mpi_x86.asm
|
||||
DEFINES += -DMP_ASSEMBLY_MULTIPLY -DMP_ASSEMBLY_SQUARE -DMP_ASSEMBLY_DIV_2DX1D -DMP_USE_UINT_DIGIT -DMP_NO_MP_WORD
|
||||
endif
|
||||
|
||||
ifeq ($(OS_TARGET),IRIX)
|
||||
ifeq ($(USE_N32),1)
|
||||
ASFILES = mpi_mips.s
|
||||
ifeq ($(NS_USE_GCC),1)
|
||||
ASFLAGS = -Wp,-P -Wp,-traditional -O -mips3
|
||||
else
|
||||
ASFLAGS = -O -OPT:Olimit=4000 -dollar -fullwarn -xansi -n32 -mips3
|
||||
endif
|
||||
DEFINES += -DMP_ASSEMBLY_MULTIPLY -DMP_ASSEMBLY_SQUARE
|
||||
DEFINES += -DMP_USE_UINT_DIGIT
|
||||
else
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(OS_TARGET),Linux)
|
||||
ifeq ($(CPU_ARCH),x86)
|
||||
ASFILES = mpi_x86.s
|
||||
DEFINES += -DMP_ASSEMBLY_MULTIPLY -DMP_ASSEMBLY_SQUARE -DMP_ASSEMBLY_DIV_2DX1D
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(OS_TARGET),AIX)
|
||||
DEFINES += -DMP_USE_UINT_DIGIT
|
||||
ifndef USE_64
|
||||
DEFINES += -DMP_NO_DIV_WORD -DMP_NO_ADD_WORD -DMP_NO_SUB_WORD
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(OS_TARGET), HP-UX)
|
||||
ifneq ($(OS_TEST), ia64)
|
||||
MKSHLIB += +k +vshlibunsats -u FREEBL_GetVector +e FREEBL_GetVector
|
||||
ifndef FREEBL_EXTENDED_BUILD
|
||||
ifdef USE_PURE_32
|
||||
# build for DA1.1 (HP PA 1.1) pure 32 bit model
|
||||
DEFINES += -DMP_USE_UINT_DIGIT -DMP_NO_MP_WORD
|
||||
DEFINES += -DSHA_NO_LONG_LONG # avoid 64-bit arithmetic in SHA512
|
||||
else
|
||||
ifdef USE_64
|
||||
# this builds for DA2.0W (HP PA 2.0 Wide), the LP64 ABI, using 32-bit digits
|
||||
MPI_SRCS += mpi_hp.c
|
||||
ASFILES += hpma512.s hppa20.s
|
||||
DEFINES += -DMP_ASSEMBLY_MULTIPLY -DMP_ASSEMBLY_SQUARE
|
||||
else
|
||||
# this builds for DA2.0 (HP PA 2.0 Narrow) hybrid model
|
||||
# (the 32-bit ABI with 64-bit registers) using 32-bit digits
|
||||
MPI_SRCS += mpi_hp.c
|
||||
ASFILES += hpma512.s hppa20.s
|
||||
DEFINES += -DMP_ASSEMBLY_MULTIPLY -DMP_ASSEMBLY_SQUARE
|
||||
# This is done in coreconf by defining USE_LONG_LONGS
|
||||
# OS_CFLAGS += -Aa +e +DA2.0 +DS2.0
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
# Note: -xarch=v8 or v9 is now done in coreconf
|
||||
ifeq ($(OS_TARGET),SunOS)
|
||||
ifeq ($(CPU_ARCH),sparc)
|
||||
ifndef NS_USE_GCC
|
||||
ifdef USE_HYBRID
|
||||
OS_CFLAGS += -xchip=ultra2
|
||||
endif
|
||||
endif
|
||||
ifeq (5.5.1,$(firstword $(sort 5.5.1 $(OS_RELEASE))))
|
||||
SYSV_SPARC = 1
|
||||
endif
|
||||
ifeq ($(SYSV_SPARC),1)
|
||||
SOLARIS_AS = /usr/ccs/bin/as
|
||||
ifdef NS_USE_GCC
|
||||
ifdef GCC_USE_GNU_LD
|
||||
MKSHLIB += -Wl,-Bsymbolic,-z,defs,-z,now,-z,text,--version-script,mapfile.Solaris
|
||||
else
|
||||
MKSHLIB += -Wl,-B,symbolic,-z,defs,-z,now,-z,text,-M,mapfile.Solaris
|
||||
endif
|
||||
else
|
||||
MKSHLIB += -B symbolic -z defs -z now -z text -M mapfile.Solaris
|
||||
endif
|
||||
ifdef USE_PURE_32
|
||||
# this builds for Sparc v8 pure 32-bit architecture
|
||||
DEFINES += -DMP_USE_LONG_LONG_MULTIPLY -DMP_USE_UINT_DIGIT -DMP_NO_MP_WORD
|
||||
DEFINES += -DSHA_NO_LONG_LONG # avoid 64-bit arithmetic in SHA512
|
||||
else
|
||||
ifdef USE_64
|
||||
# this builds for Sparc v9a pure 64-bit architecture
|
||||
MPI_SRCS += mpi_sparc.c
|
||||
ASFILES = mpv_sparcv9.s montmulfv9.s
|
||||
DEFINES += -DMP_ASSEMBLY_MULTIPLY -DMP_USING_MONT_MULF
|
||||
DEFINES += -DMP_USE_UINT_DIGIT
|
||||
# MPI_SRCS += mpv_sparc.c
|
||||
# removed -xdepend from the following line
|
||||
SOLARIS_FLAGS = -fast -xO5 -xrestrict=%all -xchip=ultra -xarch=v9a -KPIC -mt
|
||||
SOLARIS_AS_FLAGS = -xarch=v9a -K PIC
|
||||
else
|
||||
# this builds for Sparc v8+a hybrid architecture, 64-bit registers, 32-bit ABI
|
||||
MPI_SRCS += mpi_sparc.c
|
||||
ASFILES = mpv_sparcv8.s montmulfv8.s
|
||||
DEFINES += -DMP_NO_MP_WORD -DMP_ASSEMBLY_MULTIPLY -DMP_USING_MONT_MULF
|
||||
DEFINES += -DMP_USE_UINT_DIGIT
|
||||
SOLARIS_AS_FLAGS = -xarch=v8plusa -K PIC
|
||||
# ASM_SUFFIX = .S
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
else
|
||||
# Solaris x86
|
||||
DEFINES += -D_X86_
|
||||
DEFINES += -DMP_USE_UINT_DIGIT
|
||||
DEFINES += -DMP_ASSEMBLY_MULTIPLY -DMP_ASSEMBLY_SQUARE -DMP_ASSEMBLY_DIV_2DX1D
|
||||
ASFILES = mpi_i86pc.s
|
||||
ifdef NS_USE_GCC
|
||||
LD = gcc
|
||||
AS = gcc
|
||||
ASFLAGS =
|
||||
endif
|
||||
|
||||
endif
|
||||
endif
|
||||
|
||||
$(OBJDIR)/sysrand$(OBJ_SUFFIX): sysrand.c unix_rand.c win_rand.c mac_rand.c os2_rand.c
|
||||
|
||||
#######################################################################
|
||||
# (5) Execute "global" rules. (OPTIONAL) #
|
||||
#######################################################################
|
||||
|
||||
include $(CORE_DEPTH)/coreconf/rules.mk
|
||||
|
||||
#######################################################################
|
||||
# (6) Execute "component" rules. (OPTIONAL) #
|
||||
#######################################################################
|
||||
|
||||
|
||||
|
||||
#######################################################################
|
||||
# (7) Execute "local" rules. (OPTIONAL). #
|
||||
#######################################################################
|
||||
|
||||
export:: private_export
|
||||
|
||||
rijndael_tables:
|
||||
$(CC) -o $(OBJDIR)/make_rijndael_tab rijndael_tables.c \
|
||||
$(DEFINES) $(INCLUDES) $(OBJDIR)/libfreebl.a
|
||||
$(OBJDIR)/make_rijndael_tab
|
||||
|
||||
ifdef MOZILLA_BSAFE_BUILD
|
||||
|
||||
private_export::
|
||||
ifeq (,$(filter-out WIN%,$(OS_TARGET)))
|
||||
rm -f $(DIST)/lib/bsafe$(BSAFEVER).lib
|
||||
endif
|
||||
$(NSINSTALL) -R $(BSAFEPATH) $(DIST)/lib
|
||||
endif
|
||||
|
||||
ifdef USE_PURE_32
|
||||
vpath %.h $(FREEBL_PARENT)/mpi:$(FREEBL_PARENT)
|
||||
vpath %.c $(FREEBL_PARENT)/mpi:$(FREEBL_PARENT)
|
||||
vpath %.S $(FREEBL_PARENT)/mpi:$(FREEBL_PARENT)
|
||||
vpath %.s $(FREEBL_PARENT)/mpi:$(FREEBL_PARENT)
|
||||
vpath %.asm $(FREEBL_PARENT)/mpi:$(FREEBL_PARENT)
|
||||
INCLUDES += -I$(FREEBL_PARENT) -I$(FREEBL_PARENT)/mpi
|
||||
else
|
||||
vpath %.h mpi
|
||||
vpath %.c mpi
|
||||
vpath %.S mpi
|
||||
vpath %.s mpi
|
||||
vpath %.asm mpi
|
||||
INCLUDES += -Impi
|
||||
endif
|
||||
|
||||
|
||||
DEFINES += -DMP_API_COMPATIBLE
|
||||
|
||||
MPI_USERS = dh.c pqg.c dsa.c rsa.c ec.c GFp_ecl.c
|
||||
|
||||
MPI_OBJS = $(addprefix $(OBJDIR)/$(PROG_PREFIX), $(MPI_SRCS:.c=$(OBJ_SUFFIX)))
|
||||
MPI_OBJS += $(addprefix $(OBJDIR)/$(PROG_PREFIX), $(MPI_USERS:.c=$(OBJ_SUFFIX)))
|
||||
|
||||
$(MPI_OBJS): $(MPI_HDRS)
|
||||
|
||||
$(OBJDIR)/$(PROG_PREFIX)mpprime$(OBJ_SUFFIX): primes.c
|
||||
|
||||
$(OBJDIR)/ldvector$(OBJ_SUFFIX) $(OBJDIR)/loader$(OBJ_SUFFIX) : loader.h
|
||||
|
||||
ifeq ($(SYSV_SPARC),1)
|
||||
|
||||
$(OBJDIR)/mpv_sparcv8.o $(OBJDIR)/montmulfv8.o : $(OBJDIR)/%.o : %.s
|
||||
@$(MAKE_OBJDIR)
|
||||
$(SOLARIS_AS) -o $@ $(SOLARIS_AS_FLAGS) $<
|
||||
|
||||
$(OBJDIR)/mpv_sparcv9.o $(OBJDIR)/montmulfv9.o : $(OBJDIR)/%.o : %.s
|
||||
@$(MAKE_OBJDIR)
|
||||
$(SOLARIS_AS) -o $@ $(SOLARIS_AS_FLAGS) $<
|
||||
|
||||
$(OBJDIR)/mpmontg.o: mpmontg.c montmulf.h
|
||||
|
||||
endif
|
||||
|
||||
ifdef FREEBL_EXTENDED_BUILD
|
||||
|
||||
PURE32DIR = $(OBJDIR)/$(OS_TARGET)pure32
|
||||
ALL_TRASH += $(PURE32DIR)
|
||||
|
||||
FILES2LN = \
|
||||
$(wildcard *.tab) \
|
||||
$(wildcard mapfile.*) \
|
||||
Makefile manifest.mn config.mk
|
||||
|
||||
LINKEDFILES = $(addprefix $(PURE32DIR)/, $(FILES2LN))
|
||||
|
||||
CDDIR := $(shell pwd)
|
||||
|
||||
$(PURE32DIR):
|
||||
-mkdir $(PURE32DIR)
|
||||
-ln -s $(CDDIR)/mpi $(PURE32DIR)
|
||||
|
||||
$(LINKEDFILES) : $(PURE32DIR)/% : %
|
||||
ln -s $(CDDIR)/$* $(PURE32DIR)
|
||||
|
||||
libs::
|
||||
$(MAKE) FREEBL_RECURSIVE_BUILD=1 USE_HYBRID=1 libs
|
||||
|
||||
libs:: $(PURE32DIR) $(LINKEDFILES)
|
||||
cd $(PURE32DIR) && $(MAKE) FREEBL_RECURSIVE_BUILD=1 USE_PURE_32=1 FREEBL_PARENT=$(CDDIR) CORE_DEPTH=$(CDDIR)/$(CORE_DEPTH) libs
|
||||
|
||||
release_md::
|
||||
$(MAKE) FREEBL_RECURSIVE_BUILD=1 USE_HYBRID=1 $@
|
||||
cd $(PURE32DIR) && $(MAKE) FREEBL_RECURSIVE_BUILD=1 USE_PURE_32=1 FREEBL_PARENT=$(CDDIR) CORE_DEPTH=$(CDDIR)/$(CORE_DEPTH) $@
|
||||
|
||||
endif
|
||||
@@ -1,383 +0,0 @@
|
||||
/*
|
||||
* aeskeywrap.c - implement AES Key Wrap algorithm from RFC 3394
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF 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 Netscape security libraries.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 2002, 2003 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the
|
||||
* terms of the GNU General Public License Version 2 or later (the
|
||||
* "GPL"), in which case the provisions of the GPL are applicable
|
||||
* instead of those above. If you wish to allow use of your
|
||||
* version of this file only under the terms of the GPL and not to
|
||||
* allow others to use your version of this file under the MPL,
|
||||
* indicate your decision by deleting the provisions above and
|
||||
* replace them with the notice and other provisions required by
|
||||
* the GPL. If you do not delete the provisions above, a recipient
|
||||
* may use your version of this file under either the MPL or the
|
||||
* GPL.
|
||||
*
|
||||
* $Id: aeskeywrap.c,v 1.1 2003-01-14 22:16:04 nelsonb%netscape.com Exp $
|
||||
*/
|
||||
|
||||
#include "prcpucfg.h"
|
||||
#if defined(IS_LITTLE_ENDIAN) || defined(SHA_NO_LONG_LONG)
|
||||
#define BIG_ENDIAN_WITH_64_BIT_REGISTERS 0
|
||||
#else
|
||||
#define BIG_ENDIAN_WITH_64_BIT_REGISTERS 1
|
||||
#endif
|
||||
#include "prtypes.h" /* for PRUintXX */
|
||||
#include "secport.h" /* for PORT_XXX */
|
||||
#include "secerr.h"
|
||||
#include "blapi.h" /* for AES_ functions */
|
||||
|
||||
|
||||
struct AESKeyWrapContextStr {
|
||||
AESContext * aescx;
|
||||
unsigned char iv[AES_KEY_WRAP_IV_BYTES];
|
||||
};
|
||||
|
||||
/******************************************/
|
||||
/*
|
||||
** AES key wrap algorithm, RFC 3394
|
||||
*/
|
||||
|
||||
/*
|
||||
** Create a new AES context suitable for AES encryption/decryption.
|
||||
** "key" raw key data
|
||||
** "keylen" the number of bytes of key data (16, 24, or 32)
|
||||
*/
|
||||
extern AESKeyWrapContext *
|
||||
AESKeyWrap_CreateContext(const unsigned char *key, const unsigned char *iv,
|
||||
int encrypt, unsigned int keylen)
|
||||
{
|
||||
AESKeyWrapContext * cx = PORT_ZNew(AESKeyWrapContext);
|
||||
if (!cx)
|
||||
return NULL; /* error is already set */
|
||||
cx->aescx = AES_CreateContext(key, NULL, NSS_AES, encrypt, keylen,
|
||||
AES_BLOCK_SIZE);
|
||||
if (!cx->aescx) {
|
||||
PORT_Free(cx);
|
||||
return NULL; /* error should already be set */
|
||||
}
|
||||
if (iv) {
|
||||
memcpy(cx->iv, iv, AES_KEY_WRAP_IV_BYTES);
|
||||
} else {
|
||||
memset(cx->iv, 0xA6, AES_KEY_WRAP_IV_BYTES);
|
||||
}
|
||||
return cx;
|
||||
}
|
||||
|
||||
/*
|
||||
** Destroy a AES KeyWrap context.
|
||||
** "cx" the context
|
||||
** "freeit" if PR_TRUE then free the object as well as its sub-objects
|
||||
*/
|
||||
extern void
|
||||
AESKeyWrap_DestroyContext(AESKeyWrapContext *cx, PRBool freeit)
|
||||
{
|
||||
if (cx) {
|
||||
if (cx->aescx)
|
||||
AES_DestroyContext(cx->aescx, PR_TRUE);
|
||||
memset(cx, 0, sizeof *cx);
|
||||
if (freeit)
|
||||
PORT_Free(cx);
|
||||
}
|
||||
}
|
||||
|
||||
#if !BIG_ENDIAN_WITH_64_BIT_REGISTERS
|
||||
|
||||
/* The AES Key Wrap algorithm has 64-bit values that are ALWAYS big-endian
|
||||
** (Most significant byte first) in memory. The only ALU operations done
|
||||
** on them are increment, decrement, and XOR. So, on little-endian CPUs,
|
||||
** and on CPUs that lack 64-bit registers, these big-endian 64-bit operations
|
||||
** are simulated in the following code. This is thought to be faster and
|
||||
** simpler than trying to convert the data to little-endian and back.
|
||||
*/
|
||||
|
||||
/* A and T point to two 64-bit values stored most signficant byte first
|
||||
** (big endian). This function increments the 64-bit value T, and then
|
||||
** XORs it with A, changing A.
|
||||
*/
|
||||
static void
|
||||
increment_and_xor(unsigned char *A, unsigned char *T)
|
||||
{
|
||||
if (!++T[7])
|
||||
if (!++T[6])
|
||||
if (!++T[5])
|
||||
if (!++T[4])
|
||||
if (!++T[3])
|
||||
if (!++T[2])
|
||||
if (!++T[1])
|
||||
++T[0];
|
||||
|
||||
A[0] ^= T[0];
|
||||
A[1] ^= T[1];
|
||||
A[2] ^= T[2];
|
||||
A[3] ^= T[3];
|
||||
A[4] ^= T[4];
|
||||
A[5] ^= T[5];
|
||||
A[6] ^= T[6];
|
||||
A[7] ^= T[7];
|
||||
}
|
||||
|
||||
/* A and T point to two 64-bit values stored most signficant byte first
|
||||
** (big endian). This function XORs T with A, giving a new A, then
|
||||
** decrements the 64-bit value T.
|
||||
*/
|
||||
static void
|
||||
xor_and_decrement(unsigned char *A, unsigned char *T)
|
||||
{
|
||||
A[0] ^= T[0];
|
||||
A[1] ^= T[1];
|
||||
A[2] ^= T[2];
|
||||
A[3] ^= T[3];
|
||||
A[4] ^= T[4];
|
||||
A[5] ^= T[5];
|
||||
A[6] ^= T[6];
|
||||
A[7] ^= T[7];
|
||||
|
||||
if (!T[7]--)
|
||||
if (!T[6]--)
|
||||
if (!T[5]--)
|
||||
if (!T[4]--)
|
||||
if (!T[3]--)
|
||||
if (!T[2]--)
|
||||
if (!T[1]--)
|
||||
T[0]--;
|
||||
|
||||
}
|
||||
|
||||
/* Given an unsigned long t (in host byte order), store this value as a
|
||||
** 64-bit big-endian value (MSB first) in *pt.
|
||||
*/
|
||||
static void
|
||||
set_t(unsigned char *pt, unsigned long t)
|
||||
{
|
||||
pt[7] = (unsigned char)t; t >>= 8;
|
||||
pt[6] = (unsigned char)t; t >>= 8;
|
||||
pt[5] = (unsigned char)t; t >>= 8;
|
||||
pt[4] = (unsigned char)t; t >>= 8;
|
||||
pt[3] = (unsigned char)t; t >>= 8;
|
||||
pt[2] = (unsigned char)t; t >>= 8;
|
||||
pt[1] = (unsigned char)t; t >>= 8;
|
||||
pt[0] = (unsigned char)t;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Perform AES key wrap.
|
||||
** "cx" the context
|
||||
** "output" the output buffer to store the encrypted data.
|
||||
** "outputLen" how much data is stored in "output". Set by the routine
|
||||
** after some data is stored in output.
|
||||
** "maxOutputLen" the maximum amount of data that can ever be
|
||||
** stored in "output"
|
||||
** "input" the input data
|
||||
** "inputLen" the amount of input data
|
||||
*/
|
||||
extern SECStatus
|
||||
AESKeyWrap_Encrypt(AESKeyWrapContext *cx, unsigned char *output,
|
||||
unsigned int *pOutputLen, unsigned int maxOutputLen,
|
||||
const unsigned char *input, unsigned int inputLen)
|
||||
{
|
||||
PRUint64 * R = NULL;
|
||||
unsigned int nBlocks;
|
||||
unsigned int i, j;
|
||||
unsigned int aesLen = AES_BLOCK_SIZE;
|
||||
unsigned int outLen = inputLen + AES_KEY_WRAP_BLOCK_SIZE;
|
||||
SECStatus s = SECFailure;
|
||||
/* These PRUint64s are ALWAYS big endian, regardless of CPU orientation. */
|
||||
PRUint64 t;
|
||||
PRUint64 B[2];
|
||||
|
||||
#define A B[0]
|
||||
|
||||
/* Check args */
|
||||
if (!inputLen || 0 != inputLen % AES_KEY_WRAP_BLOCK_SIZE) {
|
||||
PORT_SetError(SEC_ERROR_INPUT_LEN);
|
||||
return s;
|
||||
}
|
||||
#ifdef maybe
|
||||
if (!output && pOutputLen) { /* caller is asking for output size */
|
||||
*pOutputLen = outLen;
|
||||
return SECSuccess;
|
||||
}
|
||||
#endif
|
||||
if (maxOutputLen < outLen) {
|
||||
PORT_SetError(SEC_ERROR_OUTPUT_LEN);
|
||||
return s;
|
||||
}
|
||||
if (cx == NULL || output == NULL || input == NULL) {
|
||||
PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
||||
return s;
|
||||
}
|
||||
nBlocks = inputLen / AES_KEY_WRAP_BLOCK_SIZE;
|
||||
R = PORT_NewArray(PRUint64, nBlocks + 1);
|
||||
if (!R)
|
||||
return s; /* error is already set. */
|
||||
/*
|
||||
** 1) Initialize variables.
|
||||
*/
|
||||
memcpy(&A, cx->iv, AES_KEY_WRAP_IV_BYTES);
|
||||
memcpy(&R[1], input, inputLen);
|
||||
#if BIG_ENDIAN_WITH_64_BIT_REGISTERS
|
||||
t = 0;
|
||||
#else
|
||||
memset(&t, 0, sizeof t);
|
||||
#endif
|
||||
/*
|
||||
** 2) Calculate intermediate values.
|
||||
*/
|
||||
for (j = 0; j < 6; ++j) {
|
||||
for (i = 1; i <= nBlocks; ++i) {
|
||||
B[1] = R[i];
|
||||
s = AES_Encrypt(cx->aescx, (unsigned char *)B, &aesLen,
|
||||
sizeof B, (unsigned char *)B, sizeof B);
|
||||
if (s != SECSuccess)
|
||||
break;
|
||||
R[i] = B[1];
|
||||
/* here, increment t and XOR A with t (in big endian order); */
|
||||
#if BIG_ENDIAN_WITH_64_BIT_REGISTERS
|
||||
A ^= ++t;
|
||||
#else
|
||||
increment_and_xor((unsigned char *)&A, (unsigned char *)&t);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
/*
|
||||
** 3) Output the results.
|
||||
*/
|
||||
if (s == SECSuccess) {
|
||||
R[0] = A;
|
||||
memcpy(output, &R[0], outLen);
|
||||
if (pOutputLen)
|
||||
*pOutputLen = outLen;
|
||||
} else if (pOutputLen) {
|
||||
*pOutputLen = 0;
|
||||
}
|
||||
PORT_ZFree(R, outLen);
|
||||
return s;
|
||||
}
|
||||
#undef A
|
||||
|
||||
/*
|
||||
** Perform AES key unwrap.
|
||||
** "cx" the context
|
||||
** "output" the output buffer to store the decrypted data.
|
||||
** "outputLen" how much data is stored in "output". Set by the routine
|
||||
** after some data is stored in output.
|
||||
** "maxOutputLen" the maximum amount of data that can ever be
|
||||
** stored in "output"
|
||||
** "input" the input data
|
||||
** "inputLen" the amount of input data
|
||||
*/
|
||||
extern SECStatus
|
||||
AESKeyWrap_Decrypt(AESKeyWrapContext *cx, unsigned char *output,
|
||||
unsigned int *pOutputLen, unsigned int maxOutputLen,
|
||||
const unsigned char *input, unsigned int inputLen)
|
||||
{
|
||||
PRUint64 * R = NULL;
|
||||
unsigned int nBlocks;
|
||||
unsigned int i, j;
|
||||
unsigned int aesLen = AES_BLOCK_SIZE;
|
||||
unsigned int outLen;
|
||||
SECStatus s = SECFailure;
|
||||
/* These PRUint64s are ALWAYS big endian, regardless of CPU orientation. */
|
||||
PRUint64 t;
|
||||
PRUint64 B[2];
|
||||
|
||||
#define A B[0]
|
||||
|
||||
/* Check args */
|
||||
if (inputLen < 3 * AES_KEY_WRAP_BLOCK_SIZE ||
|
||||
0 != inputLen % AES_KEY_WRAP_BLOCK_SIZE) {
|
||||
PORT_SetError(SEC_ERROR_INPUT_LEN);
|
||||
return s;
|
||||
}
|
||||
outLen = inputLen - AES_KEY_WRAP_BLOCK_SIZE;
|
||||
#ifdef maybe
|
||||
if (!output && pOutputLen) { /* caller is asking for output size */
|
||||
*pOutputLen = outLen;
|
||||
return SECSuccess;
|
||||
}
|
||||
#endif
|
||||
if (maxOutputLen < outLen) {
|
||||
PORT_SetError(SEC_ERROR_OUTPUT_LEN);
|
||||
return s;
|
||||
}
|
||||
if (cx == NULL || output == NULL || input == NULL) {
|
||||
PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
||||
return s;
|
||||
}
|
||||
nBlocks = inputLen / AES_KEY_WRAP_BLOCK_SIZE;
|
||||
R = PORT_NewArray(PRUint64, nBlocks);
|
||||
if (!R)
|
||||
return s; /* error is already set. */
|
||||
nBlocks--;
|
||||
/*
|
||||
** 1) Initialize variables.
|
||||
*/
|
||||
memcpy(&R[0], input, inputLen);
|
||||
A = R[0];
|
||||
#if BIG_ENDIAN_WITH_64_BIT_REGISTERS
|
||||
t = 6UL * nBlocks;
|
||||
#else
|
||||
set_t((unsigned char *)&t, 6UL * nBlocks);
|
||||
#endif
|
||||
/*
|
||||
** 2) Calculate intermediate values.
|
||||
*/
|
||||
for (j = 0; j < 6; ++j) {
|
||||
for (i = nBlocks; i; --i) {
|
||||
/* here, XOR A with t (in big endian order) and decrement t; */
|
||||
#if BIG_ENDIAN_WITH_64_BIT_REGISTERS
|
||||
A ^= t--;
|
||||
#else
|
||||
xor_and_decrement((unsigned char *)&A, (unsigned char *)&t);
|
||||
#endif
|
||||
B[1] = R[i];
|
||||
s = AES_Decrypt(cx->aescx, (unsigned char *)B, &aesLen,
|
||||
sizeof B, (unsigned char *)B, sizeof B);
|
||||
if (s != SECSuccess)
|
||||
break;
|
||||
R[i] = B[1];
|
||||
}
|
||||
}
|
||||
/*
|
||||
** 3) Output the results.
|
||||
*/
|
||||
if (s == SECSuccess) {
|
||||
int bad = memcmp(&A, cx->iv, AES_KEY_WRAP_IV_BYTES);
|
||||
if (!bad) {
|
||||
memcpy(output, &R[1], outLen);
|
||||
if (pOutputLen)
|
||||
*pOutputLen = outLen;
|
||||
} else {
|
||||
PORT_SetError(SEC_ERROR_BAD_DATA);
|
||||
if (pOutputLen)
|
||||
*pOutputLen = 0;
|
||||
}
|
||||
} else if (pOutputLen) {
|
||||
*pOutputLen = 0;
|
||||
}
|
||||
PORT_ZFree(R, inputLen);
|
||||
return s;
|
||||
}
|
||||
#undef A
|
||||
@@ -1,493 +0,0 @@
|
||||
/*
|
||||
* alg2268.c - implementation of the algorithm in RFC 2268
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF 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 Netscape security libraries.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1994-2000 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the
|
||||
* terms of the GNU General Public License Version 2 or later (the
|
||||
* "GPL"), in which case the provisions of the GPL are applicable
|
||||
* instead of those above. If you wish to allow use of your
|
||||
* version of this file only under the terms of the GPL and not to
|
||||
* allow others to use your version of this file under the MPL,
|
||||
* indicate your decision by deleting the provisions above and
|
||||
* replace them with the notice and other provisions required by
|
||||
* the GPL. If you do not delete the provisions above, a recipient
|
||||
* may use your version of this file under either the MPL or the
|
||||
* GPL.
|
||||
*
|
||||
* $Id: alg2268.c,v 1.4 2002-11-16 06:09:57 nelsonb%netscape.com Exp $
|
||||
*/
|
||||
|
||||
|
||||
#include "blapi.h"
|
||||
#include "secerr.h"
|
||||
#ifdef XP_UNIX_XXX
|
||||
#include <stddef.h> /* for ptrdiff_t */
|
||||
#endif
|
||||
|
||||
/*
|
||||
** RC2 symmetric block cypher
|
||||
*/
|
||||
|
||||
typedef SECStatus (rc2Func)(RC2Context *cx, unsigned char *output,
|
||||
const unsigned char *input, unsigned int inputLen);
|
||||
|
||||
/* forward declarations */
|
||||
static rc2Func rc2_EncryptECB;
|
||||
static rc2Func rc2_DecryptECB;
|
||||
static rc2Func rc2_EncryptCBC;
|
||||
static rc2Func rc2_DecryptCBC;
|
||||
|
||||
typedef union {
|
||||
PRUint32 l[2];
|
||||
PRUint16 s[4];
|
||||
PRUint8 b[8];
|
||||
} RC2Block;
|
||||
|
||||
struct RC2ContextStr {
|
||||
union {
|
||||
PRUint8 Kb[128];
|
||||
PRUint16 Kw[64];
|
||||
} u;
|
||||
RC2Block iv;
|
||||
rc2Func *enc;
|
||||
rc2Func *dec;
|
||||
};
|
||||
|
||||
#define B u.Kb
|
||||
#define K u.Kw
|
||||
#define BYTESWAP(x) ((x) << 8 | (x) >> 8)
|
||||
#define SWAPK(i) cx->K[i] = (tmpS = cx->K[i], BYTESWAP(tmpS))
|
||||
#define RC2_BLOCK_SIZE 8
|
||||
|
||||
#define LOAD_HARD(R) \
|
||||
R[0] = (PRUint16)input[1] << 8 | input[0]; \
|
||||
R[1] = (PRUint16)input[3] << 8 | input[2]; \
|
||||
R[2] = (PRUint16)input[5] << 8 | input[4]; \
|
||||
R[3] = (PRUint16)input[7] << 8 | input[6];
|
||||
#define LOAD_EASY(R) \
|
||||
R[0] = ((PRUint16 *)input)[0]; \
|
||||
R[1] = ((PRUint16 *)input)[1]; \
|
||||
R[2] = ((PRUint16 *)input)[2]; \
|
||||
R[3] = ((PRUint16 *)input)[3];
|
||||
#define STORE_HARD(R) \
|
||||
output[0] = (PRUint8)(R[0]); output[1] = (PRUint8)(R[0] >> 8); \
|
||||
output[2] = (PRUint8)(R[1]); output[3] = (PRUint8)(R[1] >> 8); \
|
||||
output[4] = (PRUint8)(R[2]); output[5] = (PRUint8)(R[2] >> 8); \
|
||||
output[6] = (PRUint8)(R[3]); output[7] = (PRUint8)(R[3] >> 8);
|
||||
#define STORE_EASY(R) \
|
||||
((PRUint16 *)output)[0] = R[0]; \
|
||||
((PRUint16 *)output)[1] = R[1]; \
|
||||
((PRUint16 *)output)[2] = R[2]; \
|
||||
((PRUint16 *)output)[3] = R[3];
|
||||
|
||||
#if defined (_X86_)
|
||||
#define LOAD(R) LOAD_EASY(R)
|
||||
#define STORE(R) STORE_EASY(R)
|
||||
#elif !defined(IS_LITTLE_ENDIAN)
|
||||
#define LOAD(R) LOAD_HARD(R)
|
||||
#define STORE(R) STORE_HARD(R)
|
||||
#else
|
||||
#define LOAD(R) if ((ptrdiff_t)input & 1) { LOAD_HARD(R) } else { LOAD_EASY(R) }
|
||||
#define STORE(R) if ((ptrdiff_t)input & 1) { STORE_HARD(R) } else { STORE_EASY(R) }
|
||||
#endif
|
||||
|
||||
static const PRUint8 S[256] = {
|
||||
0331,0170,0371,0304,0031,0335,0265,0355,0050,0351,0375,0171,0112,0240,0330,0235,
|
||||
0306,0176,0067,0203,0053,0166,0123,0216,0142,0114,0144,0210,0104,0213,0373,0242,
|
||||
0027,0232,0131,0365,0207,0263,0117,0023,0141,0105,0155,0215,0011,0201,0175,0062,
|
||||
0275,0217,0100,0353,0206,0267,0173,0013,0360,0225,0041,0042,0134,0153,0116,0202,
|
||||
0124,0326,0145,0223,0316,0140,0262,0034,0163,0126,0300,0024,0247,0214,0361,0334,
|
||||
0022,0165,0312,0037,0073,0276,0344,0321,0102,0075,0324,0060,0243,0074,0266,0046,
|
||||
0157,0277,0016,0332,0106,0151,0007,0127,0047,0362,0035,0233,0274,0224,0103,0003,
|
||||
0370,0021,0307,0366,0220,0357,0076,0347,0006,0303,0325,0057,0310,0146,0036,0327,
|
||||
0010,0350,0352,0336,0200,0122,0356,0367,0204,0252,0162,0254,0065,0115,0152,0052,
|
||||
0226,0032,0322,0161,0132,0025,0111,0164,0113,0237,0320,0136,0004,0030,0244,0354,
|
||||
0302,0340,0101,0156,0017,0121,0313,0314,0044,0221,0257,0120,0241,0364,0160,0071,
|
||||
0231,0174,0072,0205,0043,0270,0264,0172,0374,0002,0066,0133,0045,0125,0227,0061,
|
||||
0055,0135,0372,0230,0343,0212,0222,0256,0005,0337,0051,0020,0147,0154,0272,0311,
|
||||
0323,0000,0346,0317,0341,0236,0250,0054,0143,0026,0001,0077,0130,0342,0211,0251,
|
||||
0015,0070,0064,0033,0253,0063,0377,0260,0273,0110,0014,0137,0271,0261,0315,0056,
|
||||
0305,0363,0333,0107,0345,0245,0234,0167,0012,0246,0040,0150,0376,0177,0301,0255
|
||||
};
|
||||
|
||||
/*
|
||||
** Create a new RC2 context suitable for RC2 encryption/decryption.
|
||||
** "key" raw key data
|
||||
** "len" the number of bytes of key data
|
||||
** "iv" is the CBC initialization vector (if mode is NSS_RC2_CBC)
|
||||
** "mode" one of NSS_RC2 or NSS_RC2_CBC
|
||||
** "effectiveKeyLen" in bytes, not bits.
|
||||
**
|
||||
** When mode is set to NSS_RC2_CBC the RC2 cipher is run in "cipher block
|
||||
** chaining" mode.
|
||||
*/
|
||||
RC2Context *
|
||||
RC2_CreateContext(const unsigned char *key, unsigned int len,
|
||||
const unsigned char *input, int mode, unsigned efLen8)
|
||||
{
|
||||
RC2Context *cx;
|
||||
PRUint8 *L,*L2;
|
||||
int i;
|
||||
#if !defined(IS_LITTLE_ENDIAN)
|
||||
PRUint16 tmpS;
|
||||
#endif
|
||||
PRUint8 tmpB;
|
||||
|
||||
if (!key || len == 0 || len > (sizeof cx->B) || efLen8 > (sizeof cx->B)) {
|
||||
return NULL;
|
||||
}
|
||||
if (mode == NSS_RC2) {
|
||||
/* groovy */
|
||||
} else if (mode == NSS_RC2_CBC) {
|
||||
if (!input) {
|
||||
return NULL; /* not groovy */
|
||||
}
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cx = PORT_ZNew(RC2Context);
|
||||
if (!cx)
|
||||
return cx;
|
||||
|
||||
if (mode == NSS_RC2_CBC) {
|
||||
cx->enc = & rc2_EncryptCBC;
|
||||
cx->dec = & rc2_DecryptCBC;
|
||||
LOAD(cx->iv.s);
|
||||
} else {
|
||||
cx->enc = & rc2_EncryptECB;
|
||||
cx->dec = & rc2_DecryptECB;
|
||||
}
|
||||
|
||||
/* Step 0. Copy key into table. */
|
||||
memcpy(cx->B, key, len);
|
||||
|
||||
/* Step 1. Compute all values to the right of the key. */
|
||||
L2 = cx->B;
|
||||
L = L2 + len;
|
||||
tmpB = L[-1];
|
||||
for (i = (sizeof cx->B) - len; i > 0; --i) {
|
||||
*L++ = tmpB = S[ (PRUint8)(tmpB + *L2++) ];
|
||||
}
|
||||
|
||||
/* step 2. Adjust left most byte of effective key. */
|
||||
i = (sizeof cx->B) - efLen8;
|
||||
L = cx->B + i;
|
||||
*L = tmpB = S[*L]; /* mask is always 0xff */
|
||||
|
||||
/* step 3. Recompute all values to the left of effective key. */
|
||||
L2 = --L + efLen8;
|
||||
while(L >= cx->B) {
|
||||
*L-- = tmpB = S[ tmpB ^ *L2-- ];
|
||||
}
|
||||
|
||||
#if !defined(IS_LITTLE_ENDIAN)
|
||||
for (i = 63; i >= 0; --i) {
|
||||
SWAPK(i); /* candidate for unrolling */
|
||||
}
|
||||
#endif
|
||||
return cx;
|
||||
}
|
||||
|
||||
/*
|
||||
** Destroy an RC2 encryption/decryption context.
|
||||
** "cx" the context
|
||||
** "freeit" if PR_TRUE then free the object as well as its sub-objects
|
||||
*/
|
||||
void
|
||||
RC2_DestroyContext(RC2Context *cx, PRBool freeit)
|
||||
{
|
||||
if (cx) {
|
||||
memset(cx, 0, sizeof *cx);
|
||||
if (freeit) {
|
||||
PORT_Free(cx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define ROL(x,k) (x << k | x >> (16-k))
|
||||
#define MIX(j) \
|
||||
R0 = R0 + cx->K[ 4*j+0] + (R3 & R2) + (~R3 & R1); R0 = ROL(R0,1);\
|
||||
R1 = R1 + cx->K[ 4*j+1] + (R0 & R3) + (~R0 & R2); R1 = ROL(R1,2);\
|
||||
R2 = R2 + cx->K[ 4*j+2] + (R1 & R0) + (~R1 & R3); R2 = ROL(R2,3);\
|
||||
R3 = R3 + cx->K[ 4*j+3] + (R2 & R1) + (~R2 & R0); R3 = ROL(R3,5)
|
||||
#define MASH \
|
||||
R0 = R0 + cx->K[R3 & 63];\
|
||||
R1 = R1 + cx->K[R0 & 63];\
|
||||
R2 = R2 + cx->K[R1 & 63];\
|
||||
R3 = R3 + cx->K[R2 & 63]
|
||||
|
||||
/* Encrypt one block */
|
||||
static void
|
||||
rc2_Encrypt1Block(RC2Context *cx, RC2Block *output, RC2Block *input)
|
||||
{
|
||||
register PRUint16 R0, R1, R2, R3;
|
||||
|
||||
/* step 1. Initialize input. */
|
||||
R0 = input->s[0];
|
||||
R1 = input->s[1];
|
||||
R2 = input->s[2];
|
||||
R3 = input->s[3];
|
||||
|
||||
/* step 2. Expand Key (already done, in context) */
|
||||
/* step 3. j = 0 */
|
||||
/* step 4. Perform 5 mixing rounds. */
|
||||
|
||||
MIX(0);
|
||||
MIX(1);
|
||||
MIX(2);
|
||||
MIX(3);
|
||||
MIX(4);
|
||||
|
||||
/* step 5. Perform 1 mashing round. */
|
||||
MASH;
|
||||
|
||||
/* step 6. Perform 6 mixing rounds. */
|
||||
|
||||
MIX(5);
|
||||
MIX(6);
|
||||
MIX(7);
|
||||
MIX(8);
|
||||
MIX(9);
|
||||
MIX(10);
|
||||
|
||||
/* step 7. Perform 1 mashing round. */
|
||||
MASH;
|
||||
|
||||
/* step 8. Perform 5 mixing rounds. */
|
||||
|
||||
MIX(11);
|
||||
MIX(12);
|
||||
MIX(13);
|
||||
MIX(14);
|
||||
MIX(15);
|
||||
|
||||
/* output results */
|
||||
output->s[0] = R0;
|
||||
output->s[1] = R1;
|
||||
output->s[2] = R2;
|
||||
output->s[3] = R3;
|
||||
}
|
||||
|
||||
#define ROR(x,k) (x >> k | x << (16-k))
|
||||
#define R_MIX(j) \
|
||||
R3 = ROR(R3,5); R3 = R3 - cx->K[ 4*j+3] - (R2 & R1) - (~R2 & R0); \
|
||||
R2 = ROR(R2,3); R2 = R2 - cx->K[ 4*j+2] - (R1 & R0) - (~R1 & R3); \
|
||||
R1 = ROR(R1,2); R1 = R1 - cx->K[ 4*j+1] - (R0 & R3) - (~R0 & R2); \
|
||||
R0 = ROR(R0,1); R0 = R0 - cx->K[ 4*j+0] - (R3 & R2) - (~R3 & R1)
|
||||
#define R_MASH \
|
||||
R3 = R3 - cx->K[R2 & 63];\
|
||||
R2 = R2 - cx->K[R1 & 63];\
|
||||
R1 = R1 - cx->K[R0 & 63];\
|
||||
R0 = R0 - cx->K[R3 & 63]
|
||||
|
||||
/* Encrypt one block */
|
||||
static void
|
||||
rc2_Decrypt1Block(RC2Context *cx, RC2Block *output, RC2Block *input)
|
||||
{
|
||||
register PRUint16 R0, R1, R2, R3;
|
||||
|
||||
/* step 1. Initialize input. */
|
||||
R0 = input->s[0];
|
||||
R1 = input->s[1];
|
||||
R2 = input->s[2];
|
||||
R3 = input->s[3];
|
||||
|
||||
/* step 2. Expand Key (already done, in context) */
|
||||
/* step 3. j = 63 */
|
||||
/* step 4. Perform 5 r_mixing rounds. */
|
||||
R_MIX(15);
|
||||
R_MIX(14);
|
||||
R_MIX(13);
|
||||
R_MIX(12);
|
||||
R_MIX(11);
|
||||
|
||||
/* step 5. Perform 1 r_mashing round. */
|
||||
R_MASH;
|
||||
|
||||
/* step 6. Perform 6 r_mixing rounds. */
|
||||
R_MIX(10);
|
||||
R_MIX(9);
|
||||
R_MIX(8);
|
||||
R_MIX(7);
|
||||
R_MIX(6);
|
||||
R_MIX(5);
|
||||
|
||||
/* step 7. Perform 1 r_mashing round. */
|
||||
R_MASH;
|
||||
|
||||
/* step 8. Perform 5 r_mixing rounds. */
|
||||
R_MIX(4);
|
||||
R_MIX(3);
|
||||
R_MIX(2);
|
||||
R_MIX(1);
|
||||
R_MIX(0);
|
||||
|
||||
/* output results */
|
||||
output->s[0] = R0;
|
||||
output->s[1] = R1;
|
||||
output->s[2] = R2;
|
||||
output->s[3] = R3;
|
||||
}
|
||||
|
||||
static SECStatus
|
||||
rc2_EncryptECB(RC2Context *cx, unsigned char *output,
|
||||
const unsigned char *input, unsigned int inputLen)
|
||||
{
|
||||
RC2Block iBlock;
|
||||
|
||||
while (inputLen > 0) {
|
||||
LOAD(iBlock.s)
|
||||
rc2_Encrypt1Block(cx, &iBlock, &iBlock);
|
||||
STORE(iBlock.s)
|
||||
output += RC2_BLOCK_SIZE;
|
||||
input += RC2_BLOCK_SIZE;
|
||||
inputLen -= RC2_BLOCK_SIZE;
|
||||
}
|
||||
return SECSuccess;
|
||||
}
|
||||
|
||||
static SECStatus
|
||||
rc2_DecryptECB(RC2Context *cx, unsigned char *output,
|
||||
const unsigned char *input, unsigned int inputLen)
|
||||
{
|
||||
RC2Block iBlock;
|
||||
|
||||
while (inputLen > 0) {
|
||||
LOAD(iBlock.s)
|
||||
rc2_Decrypt1Block(cx, &iBlock, &iBlock);
|
||||
STORE(iBlock.s)
|
||||
output += RC2_BLOCK_SIZE;
|
||||
input += RC2_BLOCK_SIZE;
|
||||
inputLen -= RC2_BLOCK_SIZE;
|
||||
}
|
||||
return SECSuccess;
|
||||
}
|
||||
|
||||
static SECStatus
|
||||
rc2_EncryptCBC(RC2Context *cx, unsigned char *output,
|
||||
const unsigned char *input, unsigned int inputLen)
|
||||
{
|
||||
RC2Block iBlock;
|
||||
|
||||
while (inputLen > 0) {
|
||||
|
||||
LOAD(iBlock.s)
|
||||
iBlock.l[0] ^= cx->iv.l[0];
|
||||
iBlock.l[1] ^= cx->iv.l[1];
|
||||
rc2_Encrypt1Block(cx, &iBlock, &iBlock);
|
||||
cx->iv = iBlock;
|
||||
STORE(iBlock.s)
|
||||
output += RC2_BLOCK_SIZE;
|
||||
input += RC2_BLOCK_SIZE;
|
||||
inputLen -= RC2_BLOCK_SIZE;
|
||||
}
|
||||
return SECSuccess;
|
||||
}
|
||||
|
||||
static SECStatus
|
||||
rc2_DecryptCBC(RC2Context *cx, unsigned char *output,
|
||||
const unsigned char *input, unsigned int inputLen)
|
||||
{
|
||||
RC2Block iBlock;
|
||||
RC2Block oBlock;
|
||||
|
||||
while (inputLen > 0) {
|
||||
LOAD(iBlock.s)
|
||||
rc2_Decrypt1Block(cx, &oBlock, &iBlock);
|
||||
oBlock.l[0] ^= cx->iv.l[0];
|
||||
oBlock.l[1] ^= cx->iv.l[1];
|
||||
cx->iv = iBlock;
|
||||
STORE(oBlock.s)
|
||||
output += RC2_BLOCK_SIZE;
|
||||
input += RC2_BLOCK_SIZE;
|
||||
inputLen -= RC2_BLOCK_SIZE;
|
||||
}
|
||||
return SECSuccess;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Perform RC2 encryption.
|
||||
** "cx" the context
|
||||
** "output" the output buffer to store the encrypted data.
|
||||
** "outputLen" how much data is stored in "output". Set by the routine
|
||||
** after some data is stored in output.
|
||||
** "maxOutputLen" the maximum amount of data that can ever be
|
||||
** stored in "output"
|
||||
** "input" the input data
|
||||
** "inputLen" the amount of input data
|
||||
*/
|
||||
SECStatus RC2_Encrypt(RC2Context *cx, unsigned char *output,
|
||||
unsigned int *outputLen, unsigned int maxOutputLen,
|
||||
const unsigned char *input, unsigned int inputLen)
|
||||
{
|
||||
SECStatus rv = SECSuccess;
|
||||
if (inputLen) {
|
||||
if (inputLen % RC2_BLOCK_SIZE) {
|
||||
PORT_SetError(SEC_ERROR_INPUT_LEN);
|
||||
return SECFailure;
|
||||
}
|
||||
if (maxOutputLen < inputLen) {
|
||||
PORT_SetError(SEC_ERROR_OUTPUT_LEN);
|
||||
return SECFailure;
|
||||
}
|
||||
rv = (*cx->enc)(cx, output, input, inputLen);
|
||||
}
|
||||
if (rv == SECSuccess) {
|
||||
*outputLen = inputLen;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
/*
|
||||
** Perform RC2 decryption.
|
||||
** "cx" the context
|
||||
** "output" the output buffer to store the decrypted data.
|
||||
** "outputLen" how much data is stored in "output". Set by the routine
|
||||
** after some data is stored in output.
|
||||
** "maxOutputLen" the maximum amount of data that can ever be
|
||||
** stored in "output"
|
||||
** "input" the input data
|
||||
** "inputLen" the amount of input data
|
||||
*/
|
||||
SECStatus RC2_Decrypt(RC2Context *cx, unsigned char *output,
|
||||
unsigned int *outputLen, unsigned int maxOutputLen,
|
||||
const unsigned char *input, unsigned int inputLen)
|
||||
{
|
||||
SECStatus rv = SECSuccess;
|
||||
if (inputLen) {
|
||||
if (inputLen % RC2_BLOCK_SIZE) {
|
||||
PORT_SetError(SEC_ERROR_INPUT_LEN);
|
||||
return SECFailure;
|
||||
}
|
||||
if (maxOutputLen < inputLen) {
|
||||
PORT_SetError(SEC_ERROR_OUTPUT_LEN);
|
||||
return SECFailure;
|
||||
}
|
||||
rv = (*cx->dec)(cx, output, input, inputLen);
|
||||
}
|
||||
if (rv == SECSuccess) {
|
||||
*outputLen = inputLen;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
@@ -1,114 +0,0 @@
|
||||
/*
|
||||
* arcfive.c - stubs for RC5 - NOT a working implementation!
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF 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 Netscape security libraries.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 2000 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the
|
||||
* terms of the GNU General Public License Version 2 or later (the
|
||||
* "GPL"), in which case the provisions of the GPL are applicable
|
||||
* instead of those above. If you wish to allow use of your
|
||||
* version of this file only under the terms of the GPL and not to
|
||||
* allow others to use your version of this file under the MPL,
|
||||
* indicate your decision by deleting the provisions above and
|
||||
* replace them with the notice and other provisions required by
|
||||
* the GPL. If you do not delete the provisions above, a recipient
|
||||
* may use your version of this file under either the MPL or the
|
||||
* GPL.
|
||||
*
|
||||
* $Id: arcfive.c,v 1.3 2002-11-16 06:09:57 nelsonb%netscape.com Exp $
|
||||
*/
|
||||
|
||||
#include "blapi.h"
|
||||
#include "prerror.h"
|
||||
|
||||
/******************************************/
|
||||
/*
|
||||
** RC5 symmetric block cypher -- 64-bit block size
|
||||
*/
|
||||
|
||||
/*
|
||||
** Create a new RC5 context suitable for RC5 encryption/decryption.
|
||||
** "key" raw key data
|
||||
** "len" the number of bytes of key data
|
||||
** "iv" is the CBC initialization vector (if mode is NSS_RC5_CBC)
|
||||
** "mode" one of NSS_RC5 or NSS_RC5_CBC
|
||||
**
|
||||
** When mode is set to NSS_RC5_CBC the RC5 cipher is run in "cipher block
|
||||
** chaining" mode.
|
||||
*/
|
||||
RC5Context *
|
||||
RC5_CreateContext(const SECItem *key, unsigned int rounds,
|
||||
unsigned int wordSize, const unsigned char *iv, int mode)
|
||||
{
|
||||
PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
** Destroy an RC5 encryption/decryption context.
|
||||
** "cx" the context
|
||||
** "freeit" if PR_TRUE then free the object as well as its sub-objects
|
||||
*/
|
||||
void
|
||||
RC5_DestroyContext(RC5Context *cx, PRBool freeit)
|
||||
{
|
||||
PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
|
||||
}
|
||||
|
||||
/*
|
||||
** Perform RC5 encryption.
|
||||
** "cx" the context
|
||||
** "output" the output buffer to store the encrypted data.
|
||||
** "outputLen" how much data is stored in "output". Set by the routine
|
||||
** after some data is stored in output.
|
||||
** "maxOutputLen" the maximum amount of data that can ever be
|
||||
** stored in "output"
|
||||
** "input" the input data
|
||||
** "inputLen" the amount of input data
|
||||
*/
|
||||
SECStatus
|
||||
RC5_Encrypt(RC5Context *cx, unsigned char *output, unsigned int *outputLen,
|
||||
unsigned int maxOutputLen,
|
||||
const unsigned char *input, unsigned int inputLen)
|
||||
{
|
||||
PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
/*
|
||||
** Perform RC5 decryption.
|
||||
** "cx" the context
|
||||
** "output" the output buffer to store the decrypted data.
|
||||
** "outputLen" how much data is stored in "output". Set by the routine
|
||||
** after some data is stored in output.
|
||||
** "maxOutputLen" the maximum amount of data that can ever be
|
||||
** stored in "output"
|
||||
** "input" the input data
|
||||
** "inputLen" the amount of input data
|
||||
*/
|
||||
SECStatus
|
||||
RC5_Decrypt(RC5Context *cx, unsigned char *output, unsigned int *outputLen,
|
||||
unsigned int maxOutputLen,
|
||||
const unsigned char *input, unsigned int inputLen)
|
||||
{
|
||||
PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
@@ -1,567 +0,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 the Netscape security libraries.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1994-2000 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the
|
||||
* terms of the GNU General Public License Version 2 or later (the
|
||||
* "GPL"), in which case the provisions of the GPL are applicable
|
||||
* instead of those above. If you wish to allow use of your
|
||||
* version of this file only under the terms of the GPL and not to
|
||||
* allow others to use your version of this file under the MPL,
|
||||
* indicate your decision by deleting the provisions above and
|
||||
* replace them with the notice and other provisions required by
|
||||
* the GPL. If you do not delete the provisions above, a recipient
|
||||
* may use your version of this file under either the MPL or the
|
||||
* GPL.
|
||||
*/
|
||||
|
||||
#include "prerr.h"
|
||||
#include "secerr.h"
|
||||
|
||||
#include "prtypes.h"
|
||||
#include "blapi.h"
|
||||
|
||||
/* Architecture-dependent defines */
|
||||
|
||||
#if defined(SOLARIS) || defined(HPUX) || defined(i386) || defined(IRIX)
|
||||
/* Convert the byte-stream to a word-stream */
|
||||
#define CONVERT_TO_WORDS
|
||||
#endif
|
||||
|
||||
#if defined(AIX) || defined(OSF1)
|
||||
/* Treat array variables as longs, not bytes */
|
||||
#define USE_LONG
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32_WCE)
|
||||
#undef WORD
|
||||
#define WORD ARC4WORD
|
||||
#endif
|
||||
|
||||
#if defined(NSS_USE_HYBRID) && !defined(SOLARIS) && !defined(NSS_USE_64)
|
||||
typedef unsigned long long WORD;
|
||||
#else
|
||||
typedef unsigned long WORD;
|
||||
#endif
|
||||
#define WORDSIZE sizeof(WORD)
|
||||
|
||||
#ifdef USE_LONG
|
||||
typedef unsigned long Stype;
|
||||
#else
|
||||
typedef PRUint8 Stype;
|
||||
#endif
|
||||
|
||||
#define ARCFOUR_STATE_SIZE 256
|
||||
|
||||
#define MASK1BYTE (WORD)(0xff)
|
||||
|
||||
#define SWAP(a, b) \
|
||||
tmp = a; \
|
||||
a = b; \
|
||||
b = tmp;
|
||||
|
||||
/*
|
||||
* State information for stream cipher.
|
||||
*/
|
||||
struct RC4ContextStr
|
||||
{
|
||||
Stype S[ARCFOUR_STATE_SIZE];
|
||||
PRUint8 i;
|
||||
PRUint8 j;
|
||||
};
|
||||
|
||||
/*
|
||||
* array indices [0..255] to initialize cx->S array (faster than loop).
|
||||
*/
|
||||
static const Stype Kinit[256] = {
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
|
||||
0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
|
||||
0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
|
||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
|
||||
0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
|
||||
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
|
||||
0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
|
||||
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
|
||||
0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
|
||||
0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
|
||||
0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
|
||||
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
|
||||
0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
|
||||
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
|
||||
0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
|
||||
0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
|
||||
0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
|
||||
0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
|
||||
0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
|
||||
0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
|
||||
0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
|
||||
0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
|
||||
0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
|
||||
0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
|
||||
0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
|
||||
0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
|
||||
0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
|
||||
0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
|
||||
0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
|
||||
};
|
||||
|
||||
/*
|
||||
* Initialize a new generator.
|
||||
*/
|
||||
RC4Context *
|
||||
RC4_CreateContext(const unsigned char *key, int len)
|
||||
{
|
||||
int i;
|
||||
PRUint8 j, tmp;
|
||||
RC4Context *cx;
|
||||
PRUint8 K[256];
|
||||
PRUint8 *L;
|
||||
/* verify the key length. */
|
||||
PORT_Assert(len > 0 && len < ARCFOUR_STATE_SIZE);
|
||||
if (len < 0 || len >= ARCFOUR_STATE_SIZE) {
|
||||
PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
||||
return NULL;
|
||||
}
|
||||
/* Create space for the context. */
|
||||
cx = (RC4Context *)PORT_ZAlloc(sizeof(RC4Context));
|
||||
if (cx == NULL) {
|
||||
PORT_SetError(PR_OUT_OF_MEMORY_ERROR);
|
||||
return NULL;
|
||||
}
|
||||
/* Initialize the state using array indices. */
|
||||
memcpy(cx->S, Kinit, sizeof cx->S);
|
||||
/* Fill in K repeatedly with values from key. */
|
||||
L = K;
|
||||
for (i = sizeof K; i > len; i-= len) {
|
||||
memcpy(L, key, len);
|
||||
L += len;
|
||||
}
|
||||
memcpy(L, key, i);
|
||||
/* Stir the state of the generator. At this point it is assumed
|
||||
* that the key is the size of the state buffer. If this is not
|
||||
* the case, the key bytes are repeated to fill the buffer.
|
||||
*/
|
||||
j = 0;
|
||||
#define ARCFOUR_STATE_STIR(ii) \
|
||||
j = j + cx->S[ii] + K[ii]; \
|
||||
SWAP(cx->S[ii], cx->S[j]);
|
||||
for (i=0; i<ARCFOUR_STATE_SIZE; i++) {
|
||||
ARCFOUR_STATE_STIR(i);
|
||||
}
|
||||
cx->i = 0;
|
||||
cx->j = 0;
|
||||
return cx;
|
||||
}
|
||||
|
||||
void
|
||||
RC4_DestroyContext(RC4Context *cx, PRBool freeit)
|
||||
{
|
||||
if (freeit)
|
||||
PORT_ZFree(cx, sizeof(*cx));
|
||||
}
|
||||
|
||||
/*
|
||||
* Generate the next byte in the stream.
|
||||
*/
|
||||
#define ARCFOUR_NEXT_BYTE() \
|
||||
tmpSi = cx->S[++tmpi]; \
|
||||
tmpj += tmpSi; \
|
||||
tmpSj = cx->S[tmpj]; \
|
||||
cx->S[tmpi] = tmpSj; \
|
||||
cx->S[tmpj] = tmpSi; \
|
||||
t = tmpSi + tmpSj;
|
||||
|
||||
#ifdef CONVERT_TO_WORDS
|
||||
/*
|
||||
* Straight RC4 op. No optimization.
|
||||
*/
|
||||
static SECStatus
|
||||
rc4_no_opt(RC4Context *cx, unsigned char *output,
|
||||
unsigned int *outputLen, unsigned int maxOutputLen,
|
||||
const unsigned char *input, unsigned int inputLen)
|
||||
{
|
||||
PRUint8 t;
|
||||
Stype tmpSi, tmpSj;
|
||||
register PRUint8 tmpi = cx->i;
|
||||
register PRUint8 tmpj = cx->j;
|
||||
unsigned int index;
|
||||
PORT_Assert(maxOutputLen >= inputLen);
|
||||
if (maxOutputLen < inputLen) {
|
||||
PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
||||
return SECFailure;
|
||||
}
|
||||
for (index=0; index < inputLen; index++) {
|
||||
/* Generate next byte from stream. */
|
||||
ARCFOUR_NEXT_BYTE();
|
||||
/* output = next stream byte XOR next input byte */
|
||||
output[index] = cx->S[t] ^ input[index];
|
||||
}
|
||||
*outputLen = inputLen;
|
||||
cx->i = tmpi;
|
||||
cx->j = tmpj;
|
||||
return SECSuccess;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef CONVERT_TO_WORDS
|
||||
/*
|
||||
* Byte-at-a-time RC4, unrolling the loop into 8 pieces.
|
||||
*/
|
||||
static SECStatus
|
||||
rc4_unrolled(RC4Context *cx, unsigned char *output,
|
||||
unsigned int *outputLen, unsigned int maxOutputLen,
|
||||
const unsigned char *input, unsigned int inputLen)
|
||||
{
|
||||
PRUint8 t;
|
||||
Stype tmpSi, tmpSj;
|
||||
register PRUint8 tmpi = cx->i;
|
||||
register PRUint8 tmpj = cx->j;
|
||||
int index;
|
||||
PORT_Assert(maxOutputLen >= inputLen);
|
||||
if (maxOutputLen < inputLen) {
|
||||
PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
||||
return SECFailure;
|
||||
}
|
||||
for (index = inputLen / 8; index-- > 0; input += 8, output += 8) {
|
||||
ARCFOUR_NEXT_BYTE();
|
||||
output[0] = cx->S[t] ^ input[0];
|
||||
ARCFOUR_NEXT_BYTE();
|
||||
output[1] = cx->S[t] ^ input[1];
|
||||
ARCFOUR_NEXT_BYTE();
|
||||
output[2] = cx->S[t] ^ input[2];
|
||||
ARCFOUR_NEXT_BYTE();
|
||||
output[3] = cx->S[t] ^ input[3];
|
||||
ARCFOUR_NEXT_BYTE();
|
||||
output[4] = cx->S[t] ^ input[4];
|
||||
ARCFOUR_NEXT_BYTE();
|
||||
output[5] = cx->S[t] ^ input[5];
|
||||
ARCFOUR_NEXT_BYTE();
|
||||
output[6] = cx->S[t] ^ input[6];
|
||||
ARCFOUR_NEXT_BYTE();
|
||||
output[7] = cx->S[t] ^ input[7];
|
||||
}
|
||||
index = inputLen % 8;
|
||||
if (index) {
|
||||
input += index;
|
||||
output += index;
|
||||
switch (index) {
|
||||
case 7:
|
||||
ARCFOUR_NEXT_BYTE();
|
||||
output[-7] = cx->S[t] ^ input[-7]; /* FALLTHRU */
|
||||
case 6:
|
||||
ARCFOUR_NEXT_BYTE();
|
||||
output[-6] = cx->S[t] ^ input[-6]; /* FALLTHRU */
|
||||
case 5:
|
||||
ARCFOUR_NEXT_BYTE();
|
||||
output[-5] = cx->S[t] ^ input[-5]; /* FALLTHRU */
|
||||
case 4:
|
||||
ARCFOUR_NEXT_BYTE();
|
||||
output[-4] = cx->S[t] ^ input[-4]; /* FALLTHRU */
|
||||
case 3:
|
||||
ARCFOUR_NEXT_BYTE();
|
||||
output[-3] = cx->S[t] ^ input[-3]; /* FALLTHRU */
|
||||
case 2:
|
||||
ARCFOUR_NEXT_BYTE();
|
||||
output[-2] = cx->S[t] ^ input[-2]; /* FALLTHRU */
|
||||
case 1:
|
||||
ARCFOUR_NEXT_BYTE();
|
||||
output[-1] = cx->S[t] ^ input[-1]; /* FALLTHRU */
|
||||
default:
|
||||
/* FALLTHRU */
|
||||
; /* hp-ux build breaks without this */
|
||||
}
|
||||
}
|
||||
cx->i = tmpi;
|
||||
cx->j = tmpj;
|
||||
*outputLen = inputLen;
|
||||
return SECSuccess;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef IS_LITTLE_ENDIAN
|
||||
#define ARCFOUR_NEXT4BYTES_L(n) \
|
||||
ARCFOUR_NEXT_BYTE(); streamWord |= (WORD)cx->S[t] << (n ); \
|
||||
ARCFOUR_NEXT_BYTE(); streamWord |= (WORD)cx->S[t] << (n + 8); \
|
||||
ARCFOUR_NEXT_BYTE(); streamWord |= (WORD)cx->S[t] << (n + 16); \
|
||||
ARCFOUR_NEXT_BYTE(); streamWord |= (WORD)cx->S[t] << (n + 24);
|
||||
#else
|
||||
#define ARCFOUR_NEXT4BYTES_B(n) \
|
||||
ARCFOUR_NEXT_BYTE(); streamWord |= (WORD)cx->S[t] << (n + 24); \
|
||||
ARCFOUR_NEXT_BYTE(); streamWord |= (WORD)cx->S[t] << (n + 16); \
|
||||
ARCFOUR_NEXT_BYTE(); streamWord |= (WORD)cx->S[t] << (n + 8); \
|
||||
ARCFOUR_NEXT_BYTE(); streamWord |= (WORD)cx->S[t] << (n );
|
||||
#endif
|
||||
|
||||
#if (defined(NSS_USE_HYBRID) && !defined(SOLARIS)) || defined(NSS_USE_64)
|
||||
/* 64-bit wordsize */
|
||||
#ifdef IS_LITTLE_ENDIAN
|
||||
#define ARCFOUR_NEXT_WORD() \
|
||||
{ streamWord = 0; ARCFOUR_NEXT4BYTES_L(0); ARCFOUR_NEXT4BYTES_L(32); }
|
||||
#else
|
||||
#define ARCFOUR_NEXT_WORD() \
|
||||
{ streamWord = 0; ARCFOUR_NEXT4BYTES_B(32); ARCFOUR_NEXT4BYTES_B(0); }
|
||||
#endif
|
||||
#else
|
||||
/* 32-bit wordsize */
|
||||
#ifdef IS_LITTLE_ENDIAN
|
||||
#define ARCFOUR_NEXT_WORD() \
|
||||
{ streamWord = 0; ARCFOUR_NEXT4BYTES_L(0); }
|
||||
#else
|
||||
#define ARCFOUR_NEXT_WORD() \
|
||||
{ streamWord = 0; ARCFOUR_NEXT4BYTES_B(0); }
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef IS_LITTLE_ENDIAN
|
||||
#define RSH <<
|
||||
#define LSH >>
|
||||
#else
|
||||
#define RSH >>
|
||||
#define LSH <<
|
||||
#endif
|
||||
|
||||
#ifdef CONVERT_TO_WORDS
|
||||
/*
|
||||
* Convert input and output buffers to words before performing
|
||||
* RC4 operations.
|
||||
*/
|
||||
static SECStatus
|
||||
rc4_wordconv(RC4Context *cx, unsigned char *output,
|
||||
unsigned int *outputLen, unsigned int maxOutputLen,
|
||||
const unsigned char *input, unsigned int inputLen)
|
||||
{
|
||||
ptrdiff_t inOffset = (ptrdiff_t)input % WORDSIZE;
|
||||
ptrdiff_t outOffset = (ptrdiff_t)output % WORDSIZE;
|
||||
register WORD streamWord, mask;
|
||||
register WORD *pInWord, *pOutWord;
|
||||
register WORD inWord, nextInWord;
|
||||
PRUint8 t;
|
||||
register Stype tmpSi, tmpSj;
|
||||
register PRUint8 tmpi = cx->i;
|
||||
register PRUint8 tmpj = cx->j;
|
||||
unsigned int byteCount;
|
||||
unsigned int bufShift, invBufShift;
|
||||
int i;
|
||||
|
||||
PORT_Assert(maxOutputLen >= inputLen);
|
||||
if (maxOutputLen < inputLen) {
|
||||
PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
||||
return SECFailure;
|
||||
}
|
||||
if (inputLen < 2*WORDSIZE) {
|
||||
/* Ignore word conversion, do byte-at-a-time */
|
||||
return rc4_no_opt(cx, output, outputLen, maxOutputLen, input, inputLen);
|
||||
}
|
||||
*outputLen = inputLen;
|
||||
pInWord = (WORD *)(input - inOffset);
|
||||
if (inOffset < outOffset) {
|
||||
bufShift = 8*(outOffset - inOffset);
|
||||
invBufShift = 8*WORDSIZE - bufShift;
|
||||
} else {
|
||||
invBufShift = 8*(inOffset - outOffset);
|
||||
bufShift = 8*WORDSIZE - invBufShift;
|
||||
}
|
||||
/*****************************************************************/
|
||||
/* Step 1: */
|
||||
/* If the first output word is partial, consume the bytes in the */
|
||||
/* first partial output word by loading one or two words of */
|
||||
/* input and shifting them accordingly. Otherwise, just load */
|
||||
/* in the first word of input. At the end of this block, at */
|
||||
/* least one partial word of input should ALWAYS be loaded. */
|
||||
/*****************************************************************/
|
||||
if (outOffset) {
|
||||
/* Generate input and stream words aligned relative to the
|
||||
* partial output buffer.
|
||||
*/
|
||||
byteCount = WORDSIZE - outOffset;
|
||||
pOutWord = (WORD *)(output - outOffset);
|
||||
mask = streamWord = 0;
|
||||
#ifdef IS_LITTLE_ENDIAN
|
||||
for (i = WORDSIZE - byteCount; i < WORDSIZE; i++) {
|
||||
#else
|
||||
for (i = byteCount - 1; i >= 0; --i) {
|
||||
#endif
|
||||
ARCFOUR_NEXT_BYTE();
|
||||
streamWord |= (WORD)(cx->S[t]) << 8*i;
|
||||
mask |= MASK1BYTE << 8*i;
|
||||
} /* } */
|
||||
inWord = *pInWord++;
|
||||
/* If buffers are relatively misaligned, shift the bytes in inWord
|
||||
* to be aligned to the output buffer.
|
||||
*/
|
||||
nextInWord = 0;
|
||||
if (inOffset < outOffset) {
|
||||
/* Have more bytes than needed, shift remainder into nextInWord */
|
||||
nextInWord = inWord LSH 8*(inOffset + byteCount);
|
||||
inWord = inWord RSH bufShift;
|
||||
} else if (inOffset > outOffset) {
|
||||
/* Didn't get enough bytes from current input word, load another
|
||||
* word and then shift remainder into nextInWord.
|
||||
*/
|
||||
nextInWord = *pInWord++;
|
||||
inWord = (inWord LSH invBufShift) |
|
||||
(nextInWord RSH bufShift);
|
||||
nextInWord = nextInWord LSH invBufShift;
|
||||
}
|
||||
/* Store output of first partial word */
|
||||
*pOutWord = (*pOutWord & ~mask) | ((inWord ^ streamWord) & mask);
|
||||
/* Consumed byteCount bytes of input */
|
||||
inputLen -= byteCount;
|
||||
/* move to next word of output */
|
||||
pOutWord++;
|
||||
/* inWord has been consumed, but there may be bytes in nextInWord */
|
||||
inWord = nextInWord;
|
||||
} else {
|
||||
/* output is word-aligned */
|
||||
pOutWord = (WORD *)output;
|
||||
if (inOffset) {
|
||||
/* Input is not word-aligned. The first word load of input
|
||||
* will not produce a full word of input bytes, so one word
|
||||
* must be pre-loaded. The main loop below will load in the
|
||||
* next input word and shift some of its bytes into inWord
|
||||
* in order to create a full input word. Note that the main
|
||||
* loop must execute at least once because the input must
|
||||
* be at least two words.
|
||||
*/
|
||||
inWord = *pInWord++;
|
||||
inWord = inWord LSH invBufShift;
|
||||
} else {
|
||||
/* Input is word-aligned. The first word load of input
|
||||
* will produce a full word of input bytes, so nothing
|
||||
* needs to be loaded here.
|
||||
*/
|
||||
inWord = 0;
|
||||
}
|
||||
}
|
||||
/* Output buffer is aligned, inOffset is now measured relative to
|
||||
* outOffset (and not a word boundary).
|
||||
*/
|
||||
inOffset = (inOffset + WORDSIZE - outOffset) % WORDSIZE;
|
||||
/*****************************************************************/
|
||||
/* Step 2: main loop */
|
||||
/* At this point the output buffer is word-aligned. Any unused */
|
||||
/* bytes from above will be in inWord (shifted correctly). If */
|
||||
/* the input buffer is unaligned relative to the output buffer, */
|
||||
/* shifting has to be done. */
|
||||
/*****************************************************************/
|
||||
if (inOffset) {
|
||||
for (; inputLen >= WORDSIZE; inputLen -= WORDSIZE) {
|
||||
nextInWord = *pInWord++;
|
||||
inWord |= nextInWord RSH bufShift;
|
||||
nextInWord = nextInWord LSH invBufShift;
|
||||
ARCFOUR_NEXT_WORD();
|
||||
*pOutWord++ = inWord ^ streamWord;
|
||||
inWord = nextInWord;
|
||||
}
|
||||
if (inputLen == 0) {
|
||||
/* Nothing left to do. */
|
||||
cx->i = tmpi;
|
||||
cx->j = tmpj;
|
||||
return SECSuccess;
|
||||
}
|
||||
/* If the amount of remaining input is greater than the amount
|
||||
* bytes pulled from the current input word, need to do another
|
||||
* word load. What's left in inWord will be consumed in step 3.
|
||||
*/
|
||||
if (inputLen > WORDSIZE - inOffset)
|
||||
inWord |= *pInWord RSH bufShift;
|
||||
} else {
|
||||
for (; inputLen >= WORDSIZE; inputLen -= WORDSIZE) {
|
||||
inWord = *pInWord++;
|
||||
ARCFOUR_NEXT_WORD();
|
||||
*pOutWord++ = inWord ^ streamWord;
|
||||
}
|
||||
if (inputLen == 0) {
|
||||
/* Nothing left to do. */
|
||||
cx->i = tmpi;
|
||||
cx->j = tmpj;
|
||||
return SECSuccess;
|
||||
} else {
|
||||
/* A partial input word remains at the tail. Load it. The
|
||||
* relevant bytes will be consumed in step 3.
|
||||
*/
|
||||
inWord = *pInWord;
|
||||
}
|
||||
}
|
||||
/*****************************************************************/
|
||||
/* Step 3: */
|
||||
/* A partial word of input remains, and it is already loaded */
|
||||
/* into nextInWord. Shift appropriately and consume the bytes */
|
||||
/* used in the partial word. */
|
||||
/*****************************************************************/
|
||||
mask = streamWord = 0;
|
||||
#ifdef IS_LITTLE_ENDIAN
|
||||
for (i = 0; i < inputLen; ++i) {
|
||||
#else
|
||||
for (i = WORDSIZE - 1; i >= WORDSIZE - inputLen; --i) {
|
||||
#endif
|
||||
ARCFOUR_NEXT_BYTE();
|
||||
streamWord |= (WORD)(cx->S[t]) << 8*i;
|
||||
mask |= MASK1BYTE << 8*i;
|
||||
} /* } */
|
||||
*pOutWord = (*pOutWord & ~mask) | ((inWord ^ streamWord) & mask);
|
||||
cx->i = tmpi;
|
||||
cx->j = tmpj;
|
||||
return SECSuccess;
|
||||
}
|
||||
#endif
|
||||
|
||||
SECStatus
|
||||
RC4_Encrypt(RC4Context *cx, unsigned char *output,
|
||||
unsigned int *outputLen, unsigned int maxOutputLen,
|
||||
const unsigned char *input, unsigned int inputLen)
|
||||
{
|
||||
PORT_Assert(maxOutputLen >= inputLen);
|
||||
if (maxOutputLen < inputLen) {
|
||||
PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
||||
return SECFailure;
|
||||
}
|
||||
#ifdef CONVERT_TO_WORDS
|
||||
/* Convert the byte-stream to a word-stream */
|
||||
return rc4_wordconv(cx, output, outputLen, maxOutputLen, input, inputLen);
|
||||
#else
|
||||
/* Operate on bytes, but unroll the main loop */
|
||||
return rc4_unrolled(cx, output, outputLen, maxOutputLen, input, inputLen);
|
||||
#endif
|
||||
}
|
||||
|
||||
SECStatus RC4_Decrypt(RC4Context *cx, unsigned char *output,
|
||||
unsigned int *outputLen, unsigned int maxOutputLen,
|
||||
const unsigned char *input, unsigned int inputLen)
|
||||
{
|
||||
PORT_Assert(maxOutputLen >= inputLen);
|
||||
if (maxOutputLen < inputLen) {
|
||||
PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
||||
return SECFailure;
|
||||
}
|
||||
/* decrypt and encrypt are same operation. */
|
||||
#ifdef CONVERT_TO_WORDS
|
||||
/* Convert the byte-stream to a word-stream */
|
||||
return rc4_wordconv(cx, output, outputLen, maxOutputLen, input, inputLen);
|
||||
#else
|
||||
/* Operate on bytes, but unroll the main loop */
|
||||
return rc4_unrolled(cx, output, outputLen, maxOutputLen, input, inputLen);
|
||||
#endif
|
||||
}
|
||||
|
||||
#undef CONVERT_TO_WORDS
|
||||
#undef USE_LONG
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,336 +0,0 @@
|
||||
/*
|
||||
* blapit.h - public data structures for the crypto library
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF 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 Netscape security libraries.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1994-2000 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Portions created by Sun Microsystems, Inc. are Copyright (C) 2003
|
||||
* Sun Microsystems, Inc. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Dr Vipul Gupta <vipul.gupta@sun.com>, Sun Microsystems Laboratories
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the
|
||||
* terms of the GNU General Public License Version 2 or later (the
|
||||
* "GPL"), in which case the provisions of the GPL are applicable
|
||||
* instead of those above. If you wish to allow use of your
|
||||
* version of this file only under the terms of the GPL and not to
|
||||
* allow others to use your version of this file under the MPL,
|
||||
* indicate your decision by deleting the provisions above and
|
||||
* replace them with the notice and other provisions required by
|
||||
* the GPL. If you do not delete the provisions above, a recipient
|
||||
* may use your version of this file under either the MPL or the
|
||||
* GPL.
|
||||
*
|
||||
* $Id: blapit.h,v 1.10 2003-03-29 00:18:18 nelsonb%netscape.com Exp $
|
||||
*/
|
||||
|
||||
#ifndef _BLAPIT_H_
|
||||
#define _BLAPIT_H_
|
||||
|
||||
#include "seccomon.h"
|
||||
#include "prlink.h"
|
||||
#include "plarena.h"
|
||||
|
||||
|
||||
/* RC2 operation modes */
|
||||
#define NSS_RC2 0
|
||||
#define NSS_RC2_CBC 1
|
||||
|
||||
/* RC5 operation modes */
|
||||
#define NSS_RC5 0
|
||||
#define NSS_RC5_CBC 1
|
||||
|
||||
/* DES operation modes */
|
||||
#define NSS_DES 0
|
||||
#define NSS_DES_CBC 1
|
||||
#define NSS_DES_EDE3 2
|
||||
#define NSS_DES_EDE3_CBC 3
|
||||
|
||||
#define DES_KEY_LENGTH 8 /* Bytes */
|
||||
|
||||
/* AES operation modes */
|
||||
#define NSS_AES 0
|
||||
#define NSS_AES_CBC 1
|
||||
|
||||
#define DSA_SIGNATURE_LEN 40 /* Bytes */
|
||||
#define DSA_SUBPRIME_LEN 20 /* Bytes */
|
||||
|
||||
/* XXX We shouldn't have to hard code this limit. For
|
||||
* now, this is the quickest way to support ECDSA signature
|
||||
* processing (ECDSA signature lengths depend on curve
|
||||
* size). This limit is sufficient for curves upto
|
||||
* 576 bits.
|
||||
*/
|
||||
#define MAX_ECKEY_LEN 72 /* Bytes */
|
||||
|
||||
/*
|
||||
* Number of bytes each hash algorithm produces
|
||||
*/
|
||||
#define MD2_LENGTH 16 /* Bytes */
|
||||
#define MD5_LENGTH 16 /* Bytes */
|
||||
#define SHA1_LENGTH 20 /* Bytes */
|
||||
#define SHA256_LENGTH 32 /* bytes */
|
||||
#define SHA384_LENGTH 48 /* bytes */
|
||||
#define SHA512_LENGTH 64 /* bytes */
|
||||
#define HASH_LENGTH_MAX SHA512_LENGTH
|
||||
|
||||
/*
|
||||
* Input block size for each hash algorithm.
|
||||
*/
|
||||
|
||||
#define SHA256_BLOCK_LENGTH 64 /* bytes */
|
||||
#define SHA384_BLOCK_LENGTH 128 /* bytes */
|
||||
#define SHA512_BLOCK_LENGTH 128 /* bytes */
|
||||
|
||||
#define AES_KEY_WRAP_IV_BYTES 8
|
||||
#define AES_KEY_WRAP_BLOCK_SIZE 8 /* bytes */
|
||||
#define AES_BLOCK_SIZE 16 /* bytes */
|
||||
|
||||
#define NSS_FREEBL_DEFAULT_CHUNKSIZE 2048
|
||||
|
||||
/*
|
||||
* The FIPS 186 algorithm for generating primes P and Q allows only 9
|
||||
* distinct values for the length of P, and only one value for the
|
||||
* length of Q.
|
||||
* The algorithm uses a variable j to indicate which of the 9 lengths
|
||||
* of P is to be used.
|
||||
* The following table relates j to the lengths of P and Q in bits.
|
||||
*
|
||||
* j bits in P bits in Q
|
||||
* _ _________ _________
|
||||
* 0 512 160
|
||||
* 1 576 160
|
||||
* 2 640 160
|
||||
* 3 704 160
|
||||
* 4 768 160
|
||||
* 5 832 160
|
||||
* 6 896 160
|
||||
* 7 960 160
|
||||
* 8 1024 160
|
||||
*
|
||||
* The FIPS-186 compliant PQG generator takes j as an input parameter.
|
||||
*/
|
||||
|
||||
#define DSA_Q_BITS 160
|
||||
#define DSA_MAX_P_BITS 1024
|
||||
#define DSA_MIN_P_BITS 512
|
||||
|
||||
/*
|
||||
* function takes desired number of bits in P,
|
||||
* returns index (0..8) or -1 if number of bits is invalid.
|
||||
*/
|
||||
#define PQG_PBITS_TO_INDEX(bits) ((((bits)-512) % 64) ? -1 : (int)((bits)-512)/64)
|
||||
|
||||
/*
|
||||
* function takes index (0-8)
|
||||
* returns number of bits in P for that index, or -1 if index is invalid.
|
||||
*/
|
||||
#define PQG_INDEX_TO_PBITS(j) (((unsigned)(j) > 8) ? -1 : (512 + 64 * (j)))
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
** Opaque objects
|
||||
*/
|
||||
|
||||
struct DESContextStr ;
|
||||
struct RC2ContextStr ;
|
||||
struct RC4ContextStr ;
|
||||
struct RC5ContextStr ;
|
||||
struct AESContextStr ;
|
||||
struct MD2ContextStr ;
|
||||
struct MD5ContextStr ;
|
||||
struct SHA1ContextStr ;
|
||||
struct SHA256ContextStr ;
|
||||
struct SHA512ContextStr ;
|
||||
struct AESKeyWrapContextStr ;
|
||||
|
||||
typedef struct DESContextStr DESContext;
|
||||
typedef struct RC2ContextStr RC2Context;
|
||||
typedef struct RC4ContextStr RC4Context;
|
||||
typedef struct RC5ContextStr RC5Context;
|
||||
typedef struct AESContextStr AESContext;
|
||||
typedef struct MD2ContextStr MD2Context;
|
||||
typedef struct MD5ContextStr MD5Context;
|
||||
typedef struct SHA1ContextStr SHA1Context;
|
||||
typedef struct SHA256ContextStr SHA256Context;
|
||||
typedef struct SHA512ContextStr SHA512Context;
|
||||
/* SHA384Context is really a SHA512ContextStr. This is not a mistake. */
|
||||
typedef struct SHA512ContextStr SHA384Context;
|
||||
typedef struct AESKeyWrapContextStr AESKeyWrapContext;
|
||||
|
||||
/***************************************************************************
|
||||
** RSA Public and Private Key structures
|
||||
*/
|
||||
|
||||
/* member names from PKCS#1, section 7.1 */
|
||||
struct RSAPublicKeyStr {
|
||||
PRArenaPool * arena;
|
||||
SECItem modulus;
|
||||
SECItem publicExponent;
|
||||
};
|
||||
typedef struct RSAPublicKeyStr RSAPublicKey;
|
||||
|
||||
/* member names from PKCS#1, section 7.2 */
|
||||
struct RSAPrivateKeyStr {
|
||||
PRArenaPool * arena;
|
||||
SECItem version;
|
||||
SECItem modulus;
|
||||
SECItem publicExponent;
|
||||
SECItem privateExponent;
|
||||
SECItem prime1;
|
||||
SECItem prime2;
|
||||
SECItem exponent1;
|
||||
SECItem exponent2;
|
||||
SECItem coefficient;
|
||||
};
|
||||
typedef struct RSAPrivateKeyStr RSAPrivateKey;
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
** DSA Public and Private Key and related structures
|
||||
*/
|
||||
|
||||
struct PQGParamsStr {
|
||||
PRArenaPool *arena;
|
||||
SECItem prime; /* p */
|
||||
SECItem subPrime; /* q */
|
||||
SECItem base; /* g */
|
||||
/* XXX chrisk: this needs to be expanded to hold j and validationParms (RFC2459 7.3.2) */
|
||||
};
|
||||
typedef struct PQGParamsStr PQGParams;
|
||||
|
||||
struct PQGVerifyStr {
|
||||
PRArenaPool * arena; /* includes this struct, seed, & h. */
|
||||
unsigned int counter;
|
||||
SECItem seed;
|
||||
SECItem h;
|
||||
};
|
||||
typedef struct PQGVerifyStr PQGVerify;
|
||||
|
||||
struct DSAPublicKeyStr {
|
||||
PQGParams params;
|
||||
SECItem publicValue;
|
||||
};
|
||||
typedef struct DSAPublicKeyStr DSAPublicKey;
|
||||
|
||||
struct DSAPrivateKeyStr {
|
||||
PQGParams params;
|
||||
SECItem publicValue;
|
||||
SECItem privateValue;
|
||||
};
|
||||
typedef struct DSAPrivateKeyStr DSAPrivateKey;
|
||||
|
||||
/***************************************************************************
|
||||
** Diffie-Hellman Public and Private Key and related structures
|
||||
** Structure member names suggested by PKCS#3.
|
||||
*/
|
||||
|
||||
struct DHParamsStr {
|
||||
PRArenaPool * arena;
|
||||
SECItem prime; /* p */
|
||||
SECItem base; /* g */
|
||||
};
|
||||
typedef struct DHParamsStr DHParams;
|
||||
|
||||
struct DHPublicKeyStr {
|
||||
PRArenaPool * arena;
|
||||
SECItem prime;
|
||||
SECItem base;
|
||||
SECItem publicValue;
|
||||
};
|
||||
typedef struct DHPublicKeyStr DHPublicKey;
|
||||
|
||||
struct DHPrivateKeyStr {
|
||||
PRArenaPool * arena;
|
||||
SECItem prime;
|
||||
SECItem base;
|
||||
SECItem publicValue;
|
||||
SECItem privateValue;
|
||||
};
|
||||
typedef struct DHPrivateKeyStr DHPrivateKey;
|
||||
|
||||
/***************************************************************************
|
||||
** Data structures used for elliptic curve parameters and
|
||||
** public and private keys.
|
||||
*/
|
||||
|
||||
/*
|
||||
** The ECParams data structures can encode elliptic curve
|
||||
** parameters for both GFp and GF2m curves.
|
||||
*/
|
||||
|
||||
typedef enum { ec_params_explicit,
|
||||
ec_params_named
|
||||
} ECParamsType;
|
||||
|
||||
typedef enum { ec_field_GFp = 1,
|
||||
ec_field_GF2m
|
||||
} ECFieldType;
|
||||
|
||||
struct ECFieldIDStr {
|
||||
int size; /* field size in bits */
|
||||
ECFieldType type;
|
||||
union {
|
||||
SECItem prime; /* prime p for (GFp) */
|
||||
SECItem poly; /* irreducible binary polynomial for (GF2m) */
|
||||
} u;
|
||||
int k1; /* first coefficient of pentanomial or
|
||||
* the only coefficient of trinomial
|
||||
*/
|
||||
int k2; /* two remaining coefficients of pentanomial */
|
||||
int k3;
|
||||
};
|
||||
typedef struct ECFieldIDStr ECFieldID;
|
||||
|
||||
struct ECCurveStr {
|
||||
SECItem a; /* contains octet stream encoding of
|
||||
* field element (X9.62 section 4.3.3)
|
||||
*/
|
||||
SECItem b;
|
||||
SECItem seed;
|
||||
};
|
||||
typedef struct ECCurveStr ECCurve;
|
||||
|
||||
struct ECParamsStr {
|
||||
PRArenaPool * arena;
|
||||
ECParamsType type;
|
||||
ECFieldID fieldID;
|
||||
ECCurve curve;
|
||||
SECItem base;
|
||||
SECItem order;
|
||||
int cofactor;
|
||||
SECItem DEREncoding;
|
||||
};
|
||||
typedef struct ECParamsStr ECParams;
|
||||
|
||||
struct ECPublicKeyStr {
|
||||
ECParams ecParams;
|
||||
SECItem publicValue; /* elliptic curve point encoded as
|
||||
* octet stream.
|
||||
*/
|
||||
};
|
||||
typedef struct ECPublicKeyStr ECPublicKey;
|
||||
|
||||
struct ECPrivateKeyStr {
|
||||
ECParams ecParams;
|
||||
SECItem publicValue; /* encoded ec point */
|
||||
SECItem privateValue; /* private big integer */
|
||||
};
|
||||
typedef struct ECPrivateKeyStr ECPrivateKey;
|
||||
|
||||
#endif /* _BLAPIT_H_ */
|
||||
@@ -1,103 +0,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 the Netscape security libraries.
|
||||
#
|
||||
# The Initial Developer of the Original Code is Netscape
|
||||
# Communications Corporation. Portions created by Netscape are
|
||||
# Copyright (C) 1994-2000 Netscape Communications Corporation. All
|
||||
# Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
#
|
||||
# Alternatively, the contents of this file may be used under the
|
||||
# terms of the GNU General Public License Version 2 or later (the
|
||||
# "GPL"), in which case the provisions of the GPL are applicable
|
||||
# instead of those above. If you wish to allow use of your
|
||||
# version of this file only under the terms of the GPL and not to
|
||||
# allow others to use your version of this file under the MPL,
|
||||
# indicate your decision by deleting the provisions above and
|
||||
# replace them with the notice and other provisions required by
|
||||
# the GPL. If you do not delete the provisions above, a recipient
|
||||
# may use your version of this file under either the MPL or the
|
||||
# GPL.
|
||||
#
|
||||
|
||||
# only do this in the outermost freebl build.
|
||||
ifndef FREEBL_RECURSIVE_BUILD
|
||||
# we only do this stuff for some of the 32-bit builds, no 64-bit builds
|
||||
ifndef USE_64
|
||||
|
||||
ifeq ($(OS_TARGET), HP-UX)
|
||||
ifneq ($(OS_TEST), ia64)
|
||||
FREEBL_EXTENDED_BUILD = 1
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(OS_TARGET),SunOS)
|
||||
ifeq ($(CPU_ARCH),sparc)
|
||||
FREEBL_EXTENDED_BUILD = 1
|
||||
endif
|
||||
endif
|
||||
|
||||
ifdef FREEBL_EXTENDED_BUILD
|
||||
# We're going to change this build so that it builds libfreebl.a with
|
||||
# just loader.c. Then we have to build this directory twice again to
|
||||
# build the two DSOs.
|
||||
# To build libfreebl.a with just loader.c, we must now override many
|
||||
# of the make variables setup by the prior inclusion of CORECONF's config.mk
|
||||
|
||||
CSRCS = loader.c sysrand.c
|
||||
SIMPLE_OBJS = $(CSRCS:.c=$(OBJ_SUFFIX))
|
||||
OBJS = $(addprefix $(OBJDIR)/$(PROG_PREFIX), $(SIMPLE_OBJS))
|
||||
ALL_TRASH := $(TARGETS) $(OBJS) $(OBJDIR) LOGS TAGS $(GARBAGE) \
|
||||
$(NOSUCHFILE) so_locations
|
||||
endif
|
||||
|
||||
#end of 32-bit only stuff.
|
||||
endif
|
||||
|
||||
# Override the values defined in coreconf's ruleset.mk.
|
||||
#
|
||||
# - (1) LIBRARY: a static (archival) library
|
||||
# - (2) SHARED_LIBRARY: a shared (dynamic link) library
|
||||
# - (3) IMPORT_LIBRARY: an import library, used only on Windows
|
||||
# - (4) PROGRAM: an executable binary
|
||||
#
|
||||
# override these variables to prevent building a DSO/DLL.
|
||||
TARGETS = $(LIBRARY)
|
||||
SHARED_LIBRARY =
|
||||
IMPORT_LIBRARY =
|
||||
PROGRAM =
|
||||
|
||||
else
|
||||
# This is a recursive build.
|
||||
|
||||
TARGETS = $(SHARED_LIBRARY)
|
||||
LIBRARY =
|
||||
PROGRAM =
|
||||
|
||||
#ifeq ($(OS_TARGET), HP-UX)
|
||||
EXTRA_LIBS += \
|
||||
$(DIST)/lib/libsecutil.$(LIB_SUFFIX) \
|
||||
$(NULL)
|
||||
|
||||
# $(PROGRAM) has NO explicit dependencies on $(EXTRA_SHARED_LIBS)
|
||||
# $(EXTRA_SHARED_LIBS) come before $(OS_LIBS), except on AIX.
|
||||
EXTRA_SHARED_LIBS += \
|
||||
-L$(DIST)/lib/ \
|
||||
-lplc4 \
|
||||
-lplds4 \
|
||||
-lnspr4 \
|
||||
-lc
|
||||
#endif
|
||||
|
||||
endif
|
||||
@@ -1,683 +0,0 @@
|
||||
/*
|
||||
* des.c
|
||||
*
|
||||
* core source file for DES-150 library
|
||||
* Make key schedule from DES key.
|
||||
* Encrypt/Decrypt one 8-byte block.
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF 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 DES-150 library.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Nelson B. Bolyard,
|
||||
* nelsonb@iname.com. Portions created by Nelson B. Bolyard are
|
||||
* Copyright (C) 1990, 2000 Nelson B. Bolyard, All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the
|
||||
* terms of the GNU General Public License Version 2 or later (the
|
||||
* "GPL"), in which case the provisions of the GPL are applicable
|
||||
* instead of those above. If you wish to allow use of your
|
||||
* version of this file only under the terms of the GPL and not to
|
||||
* allow others to use your version of this file under the MPL,
|
||||
* indicate your decision by deleting the provisions above and
|
||||
* replace them with the notice and other provisions required by
|
||||
* the GPL. If you do not delete the provisions above, a recipient
|
||||
* may use your version of this file under either the MPL or the GPL.
|
||||
*/
|
||||
|
||||
#include "des.h"
|
||||
#include <stddef.h> /* for ptrdiff_t */
|
||||
/* #define USE_INDEXING 1 */
|
||||
|
||||
/*
|
||||
* The tables below are the 8 sbox functions, with the 6-bit input permutation
|
||||
* and the 32-bit output permutation pre-computed.
|
||||
* They are shifted circularly to the left 3 bits, which removes 2 shifts
|
||||
* and an or from each round by reducing the number of sboxes whose
|
||||
* indices cross word broundaries from 2 to 1.
|
||||
*/
|
||||
|
||||
static const HALF SP[8][64] = {
|
||||
/* Box S1 */ {
|
||||
0x04041000, 0x00000000, 0x00040000, 0x04041010,
|
||||
0x04040010, 0x00041010, 0x00000010, 0x00040000,
|
||||
0x00001000, 0x04041000, 0x04041010, 0x00001000,
|
||||
0x04001010, 0x04040010, 0x04000000, 0x00000010,
|
||||
0x00001010, 0x04001000, 0x04001000, 0x00041000,
|
||||
0x00041000, 0x04040000, 0x04040000, 0x04001010,
|
||||
0x00040010, 0x04000010, 0x04000010, 0x00040010,
|
||||
0x00000000, 0x00001010, 0x00041010, 0x04000000,
|
||||
0x00040000, 0x04041010, 0x00000010, 0x04040000,
|
||||
0x04041000, 0x04000000, 0x04000000, 0x00001000,
|
||||
0x04040010, 0x00040000, 0x00041000, 0x04000010,
|
||||
0x00001000, 0x00000010, 0x04001010, 0x00041010,
|
||||
0x04041010, 0x00040010, 0x04040000, 0x04001010,
|
||||
0x04000010, 0x00001010, 0x00041010, 0x04041000,
|
||||
0x00001010, 0x04001000, 0x04001000, 0x00000000,
|
||||
0x00040010, 0x00041000, 0x00000000, 0x04040010
|
||||
},
|
||||
/* Box S2 */ {
|
||||
0x00420082, 0x00020002, 0x00020000, 0x00420080,
|
||||
0x00400000, 0x00000080, 0x00400082, 0x00020082,
|
||||
0x00000082, 0x00420082, 0x00420002, 0x00000002,
|
||||
0x00020002, 0x00400000, 0x00000080, 0x00400082,
|
||||
0x00420000, 0x00400080, 0x00020082, 0x00000000,
|
||||
0x00000002, 0x00020000, 0x00420080, 0x00400002,
|
||||
0x00400080, 0x00000082, 0x00000000, 0x00420000,
|
||||
0x00020080, 0x00420002, 0x00400002, 0x00020080,
|
||||
0x00000000, 0x00420080, 0x00400082, 0x00400000,
|
||||
0x00020082, 0x00400002, 0x00420002, 0x00020000,
|
||||
0x00400002, 0x00020002, 0x00000080, 0x00420082,
|
||||
0x00420080, 0x00000080, 0x00020000, 0x00000002,
|
||||
0x00020080, 0x00420002, 0x00400000, 0x00000082,
|
||||
0x00400080, 0x00020082, 0x00000082, 0x00400080,
|
||||
0x00420000, 0x00000000, 0x00020002, 0x00020080,
|
||||
0x00000002, 0x00400082, 0x00420082, 0x00420000
|
||||
},
|
||||
/* Box S3 */ {
|
||||
0x00000820, 0x20080800, 0x00000000, 0x20080020,
|
||||
0x20000800, 0x00000000, 0x00080820, 0x20000800,
|
||||
0x00080020, 0x20000020, 0x20000020, 0x00080000,
|
||||
0x20080820, 0x00080020, 0x20080000, 0x00000820,
|
||||
0x20000000, 0x00000020, 0x20080800, 0x00000800,
|
||||
0x00080800, 0x20080000, 0x20080020, 0x00080820,
|
||||
0x20000820, 0x00080800, 0x00080000, 0x20000820,
|
||||
0x00000020, 0x20080820, 0x00000800, 0x20000000,
|
||||
0x20080800, 0x20000000, 0x00080020, 0x00000820,
|
||||
0x00080000, 0x20080800, 0x20000800, 0x00000000,
|
||||
0x00000800, 0x00080020, 0x20080820, 0x20000800,
|
||||
0x20000020, 0x00000800, 0x00000000, 0x20080020,
|
||||
0x20000820, 0x00080000, 0x20000000, 0x20080820,
|
||||
0x00000020, 0x00080820, 0x00080800, 0x20000020,
|
||||
0x20080000, 0x20000820, 0x00000820, 0x20080000,
|
||||
0x00080820, 0x00000020, 0x20080020, 0x00080800
|
||||
},
|
||||
/* Box S4 */ {
|
||||
0x02008004, 0x00008204, 0x00008204, 0x00000200,
|
||||
0x02008200, 0x02000204, 0x02000004, 0x00008004,
|
||||
0x00000000, 0x02008000, 0x02008000, 0x02008204,
|
||||
0x00000204, 0x00000000, 0x02000200, 0x02000004,
|
||||
0x00000004, 0x00008000, 0x02000000, 0x02008004,
|
||||
0x00000200, 0x02000000, 0x00008004, 0x00008200,
|
||||
0x02000204, 0x00000004, 0x00008200, 0x02000200,
|
||||
0x00008000, 0x02008200, 0x02008204, 0x00000204,
|
||||
0x02000200, 0x02000004, 0x02008000, 0x02008204,
|
||||
0x00000204, 0x00000000, 0x00000000, 0x02008000,
|
||||
0x00008200, 0x02000200, 0x02000204, 0x00000004,
|
||||
0x02008004, 0x00008204, 0x00008204, 0x00000200,
|
||||
0x02008204, 0x00000204, 0x00000004, 0x00008000,
|
||||
0x02000004, 0x00008004, 0x02008200, 0x02000204,
|
||||
0x00008004, 0x00008200, 0x02000000, 0x02008004,
|
||||
0x00000200, 0x02000000, 0x00008000, 0x02008200
|
||||
},
|
||||
/* Box S5 */ {
|
||||
0x00000400, 0x08200400, 0x08200000, 0x08000401,
|
||||
0x00200000, 0x00000400, 0x00000001, 0x08200000,
|
||||
0x00200401, 0x00200000, 0x08000400, 0x00200401,
|
||||
0x08000401, 0x08200001, 0x00200400, 0x00000001,
|
||||
0x08000000, 0x00200001, 0x00200001, 0x00000000,
|
||||
0x00000401, 0x08200401, 0x08200401, 0x08000400,
|
||||
0x08200001, 0x00000401, 0x00000000, 0x08000001,
|
||||
0x08200400, 0x08000000, 0x08000001, 0x00200400,
|
||||
0x00200000, 0x08000401, 0x00000400, 0x08000000,
|
||||
0x00000001, 0x08200000, 0x08000401, 0x00200401,
|
||||
0x08000400, 0x00000001, 0x08200001, 0x08200400,
|
||||
0x00200401, 0x00000400, 0x08000000, 0x08200001,
|
||||
0x08200401, 0x00200400, 0x08000001, 0x08200401,
|
||||
0x08200000, 0x00000000, 0x00200001, 0x08000001,
|
||||
0x00200400, 0x08000400, 0x00000401, 0x00200000,
|
||||
0x00000000, 0x00200001, 0x08200400, 0x00000401
|
||||
},
|
||||
/* Box S6 */ {
|
||||
0x80000040, 0x81000000, 0x00010000, 0x81010040,
|
||||
0x81000000, 0x00000040, 0x81010040, 0x01000000,
|
||||
0x80010000, 0x01010040, 0x01000000, 0x80000040,
|
||||
0x01000040, 0x80010000, 0x80000000, 0x00010040,
|
||||
0x00000000, 0x01000040, 0x80010040, 0x00010000,
|
||||
0x01010000, 0x80010040, 0x00000040, 0x81000040,
|
||||
0x81000040, 0x00000000, 0x01010040, 0x81010000,
|
||||
0x00010040, 0x01010000, 0x81010000, 0x80000000,
|
||||
0x80010000, 0x00000040, 0x81000040, 0x01010000,
|
||||
0x81010040, 0x01000000, 0x00010040, 0x80000040,
|
||||
0x01000000, 0x80010000, 0x80000000, 0x00010040,
|
||||
0x80000040, 0x81010040, 0x01010000, 0x81000000,
|
||||
0x01010040, 0x81010000, 0x00000000, 0x81000040,
|
||||
0x00000040, 0x00010000, 0x81000000, 0x01010040,
|
||||
0x00010000, 0x01000040, 0x80010040, 0x00000000,
|
||||
0x81010000, 0x80000000, 0x01000040, 0x80010040
|
||||
},
|
||||
/* Box S7 */ {
|
||||
0x00800000, 0x10800008, 0x10002008, 0x00000000,
|
||||
0x00002000, 0x10002008, 0x00802008, 0x10802000,
|
||||
0x10802008, 0x00800000, 0x00000000, 0x10000008,
|
||||
0x00000008, 0x10000000, 0x10800008, 0x00002008,
|
||||
0x10002000, 0x00802008, 0x00800008, 0x10002000,
|
||||
0x10000008, 0x10800000, 0x10802000, 0x00800008,
|
||||
0x10800000, 0x00002000, 0x00002008, 0x10802008,
|
||||
0x00802000, 0x00000008, 0x10000000, 0x00802000,
|
||||
0x10000000, 0x00802000, 0x00800000, 0x10002008,
|
||||
0x10002008, 0x10800008, 0x10800008, 0x00000008,
|
||||
0x00800008, 0x10000000, 0x10002000, 0x00800000,
|
||||
0x10802000, 0x00002008, 0x00802008, 0x10802000,
|
||||
0x00002008, 0x10000008, 0x10802008, 0x10800000,
|
||||
0x00802000, 0x00000000, 0x00000008, 0x10802008,
|
||||
0x00000000, 0x00802008, 0x10800000, 0x00002000,
|
||||
0x10000008, 0x10002000, 0x00002000, 0x00800008
|
||||
},
|
||||
/* Box S8 */ {
|
||||
0x40004100, 0x00004000, 0x00100000, 0x40104100,
|
||||
0x40000000, 0x40004100, 0x00000100, 0x40000000,
|
||||
0x00100100, 0x40100000, 0x40104100, 0x00104000,
|
||||
0x40104000, 0x00104100, 0x00004000, 0x00000100,
|
||||
0x40100000, 0x40000100, 0x40004000, 0x00004100,
|
||||
0x00104000, 0x00100100, 0x40100100, 0x40104000,
|
||||
0x00004100, 0x00000000, 0x00000000, 0x40100100,
|
||||
0x40000100, 0x40004000, 0x00104100, 0x00100000,
|
||||
0x00104100, 0x00100000, 0x40104000, 0x00004000,
|
||||
0x00000100, 0x40100100, 0x00004000, 0x00104100,
|
||||
0x40004000, 0x00000100, 0x40000100, 0x40100000,
|
||||
0x40100100, 0x40000000, 0x00100000, 0x40004100,
|
||||
0x00000000, 0x40104100, 0x00100100, 0x40000100,
|
||||
0x40100000, 0x40004000, 0x40004100, 0x00000000,
|
||||
0x40104100, 0x00104000, 0x00104000, 0x00004100,
|
||||
0x00004100, 0x00100100, 0x40000000, 0x40104000
|
||||
}
|
||||
};
|
||||
|
||||
static const HALF PC2[8][64] = {
|
||||
/* table 0 */ {
|
||||
0x00000000, 0x00001000, 0x04000000, 0x04001000,
|
||||
0x00100000, 0x00101000, 0x04100000, 0x04101000,
|
||||
0x00008000, 0x00009000, 0x04008000, 0x04009000,
|
||||
0x00108000, 0x00109000, 0x04108000, 0x04109000,
|
||||
0x00000004, 0x00001004, 0x04000004, 0x04001004,
|
||||
0x00100004, 0x00101004, 0x04100004, 0x04101004,
|
||||
0x00008004, 0x00009004, 0x04008004, 0x04009004,
|
||||
0x00108004, 0x00109004, 0x04108004, 0x04109004,
|
||||
0x08000000, 0x08001000, 0x0c000000, 0x0c001000,
|
||||
0x08100000, 0x08101000, 0x0c100000, 0x0c101000,
|
||||
0x08008000, 0x08009000, 0x0c008000, 0x0c009000,
|
||||
0x08108000, 0x08109000, 0x0c108000, 0x0c109000,
|
||||
0x08000004, 0x08001004, 0x0c000004, 0x0c001004,
|
||||
0x08100004, 0x08101004, 0x0c100004, 0x0c101004,
|
||||
0x08008004, 0x08009004, 0x0c008004, 0x0c009004,
|
||||
0x08108004, 0x08109004, 0x0c108004, 0x0c109004
|
||||
},
|
||||
/* table 1 */ {
|
||||
0x00000000, 0x00002000, 0x80000000, 0x80002000,
|
||||
0x00000008, 0x00002008, 0x80000008, 0x80002008,
|
||||
0x00200000, 0x00202000, 0x80200000, 0x80202000,
|
||||
0x00200008, 0x00202008, 0x80200008, 0x80202008,
|
||||
0x20000000, 0x20002000, 0xa0000000, 0xa0002000,
|
||||
0x20000008, 0x20002008, 0xa0000008, 0xa0002008,
|
||||
0x20200000, 0x20202000, 0xa0200000, 0xa0202000,
|
||||
0x20200008, 0x20202008, 0xa0200008, 0xa0202008,
|
||||
0x00000400, 0x00002400, 0x80000400, 0x80002400,
|
||||
0x00000408, 0x00002408, 0x80000408, 0x80002408,
|
||||
0x00200400, 0x00202400, 0x80200400, 0x80202400,
|
||||
0x00200408, 0x00202408, 0x80200408, 0x80202408,
|
||||
0x20000400, 0x20002400, 0xa0000400, 0xa0002400,
|
||||
0x20000408, 0x20002408, 0xa0000408, 0xa0002408,
|
||||
0x20200400, 0x20202400, 0xa0200400, 0xa0202400,
|
||||
0x20200408, 0x20202408, 0xa0200408, 0xa0202408
|
||||
},
|
||||
/* table 2 */ {
|
||||
0x00000000, 0x00004000, 0x00000020, 0x00004020,
|
||||
0x00080000, 0x00084000, 0x00080020, 0x00084020,
|
||||
0x00000800, 0x00004800, 0x00000820, 0x00004820,
|
||||
0x00080800, 0x00084800, 0x00080820, 0x00084820,
|
||||
0x00000010, 0x00004010, 0x00000030, 0x00004030,
|
||||
0x00080010, 0x00084010, 0x00080030, 0x00084030,
|
||||
0x00000810, 0x00004810, 0x00000830, 0x00004830,
|
||||
0x00080810, 0x00084810, 0x00080830, 0x00084830,
|
||||
0x00400000, 0x00404000, 0x00400020, 0x00404020,
|
||||
0x00480000, 0x00484000, 0x00480020, 0x00484020,
|
||||
0x00400800, 0x00404800, 0x00400820, 0x00404820,
|
||||
0x00480800, 0x00484800, 0x00480820, 0x00484820,
|
||||
0x00400010, 0x00404010, 0x00400030, 0x00404030,
|
||||
0x00480010, 0x00484010, 0x00480030, 0x00484030,
|
||||
0x00400810, 0x00404810, 0x00400830, 0x00404830,
|
||||
0x00480810, 0x00484810, 0x00480830, 0x00484830
|
||||
},
|
||||
/* table 3 */ {
|
||||
0x00000000, 0x40000000, 0x00000080, 0x40000080,
|
||||
0x00040000, 0x40040000, 0x00040080, 0x40040080,
|
||||
0x00000040, 0x40000040, 0x000000c0, 0x400000c0,
|
||||
0x00040040, 0x40040040, 0x000400c0, 0x400400c0,
|
||||
0x10000000, 0x50000000, 0x10000080, 0x50000080,
|
||||
0x10040000, 0x50040000, 0x10040080, 0x50040080,
|
||||
0x10000040, 0x50000040, 0x100000c0, 0x500000c0,
|
||||
0x10040040, 0x50040040, 0x100400c0, 0x500400c0,
|
||||
0x00800000, 0x40800000, 0x00800080, 0x40800080,
|
||||
0x00840000, 0x40840000, 0x00840080, 0x40840080,
|
||||
0x00800040, 0x40800040, 0x008000c0, 0x408000c0,
|
||||
0x00840040, 0x40840040, 0x008400c0, 0x408400c0,
|
||||
0x10800000, 0x50800000, 0x10800080, 0x50800080,
|
||||
0x10840000, 0x50840000, 0x10840080, 0x50840080,
|
||||
0x10800040, 0x50800040, 0x108000c0, 0x508000c0,
|
||||
0x10840040, 0x50840040, 0x108400c0, 0x508400c0
|
||||
},
|
||||
/* table 4 */ {
|
||||
0x00000000, 0x00000008, 0x08000000, 0x08000008,
|
||||
0x00040000, 0x00040008, 0x08040000, 0x08040008,
|
||||
0x00002000, 0x00002008, 0x08002000, 0x08002008,
|
||||
0x00042000, 0x00042008, 0x08042000, 0x08042008,
|
||||
0x80000000, 0x80000008, 0x88000000, 0x88000008,
|
||||
0x80040000, 0x80040008, 0x88040000, 0x88040008,
|
||||
0x80002000, 0x80002008, 0x88002000, 0x88002008,
|
||||
0x80042000, 0x80042008, 0x88042000, 0x88042008,
|
||||
0x00080000, 0x00080008, 0x08080000, 0x08080008,
|
||||
0x000c0000, 0x000c0008, 0x080c0000, 0x080c0008,
|
||||
0x00082000, 0x00082008, 0x08082000, 0x08082008,
|
||||
0x000c2000, 0x000c2008, 0x080c2000, 0x080c2008,
|
||||
0x80080000, 0x80080008, 0x88080000, 0x88080008,
|
||||
0x800c0000, 0x800c0008, 0x880c0000, 0x880c0008,
|
||||
0x80082000, 0x80082008, 0x88082000, 0x88082008,
|
||||
0x800c2000, 0x800c2008, 0x880c2000, 0x880c2008
|
||||
},
|
||||
/* table 5 */ {
|
||||
0x00000000, 0x00400000, 0x00008000, 0x00408000,
|
||||
0x40000000, 0x40400000, 0x40008000, 0x40408000,
|
||||
0x00000020, 0x00400020, 0x00008020, 0x00408020,
|
||||
0x40000020, 0x40400020, 0x40008020, 0x40408020,
|
||||
0x00001000, 0x00401000, 0x00009000, 0x00409000,
|
||||
0x40001000, 0x40401000, 0x40009000, 0x40409000,
|
||||
0x00001020, 0x00401020, 0x00009020, 0x00409020,
|
||||
0x40001020, 0x40401020, 0x40009020, 0x40409020,
|
||||
0x00100000, 0x00500000, 0x00108000, 0x00508000,
|
||||
0x40100000, 0x40500000, 0x40108000, 0x40508000,
|
||||
0x00100020, 0x00500020, 0x00108020, 0x00508020,
|
||||
0x40100020, 0x40500020, 0x40108020, 0x40508020,
|
||||
0x00101000, 0x00501000, 0x00109000, 0x00509000,
|
||||
0x40101000, 0x40501000, 0x40109000, 0x40509000,
|
||||
0x00101020, 0x00501020, 0x00109020, 0x00509020,
|
||||
0x40101020, 0x40501020, 0x40109020, 0x40509020
|
||||
},
|
||||
/* table 6 */ {
|
||||
0x00000000, 0x00000040, 0x04000000, 0x04000040,
|
||||
0x00000800, 0x00000840, 0x04000800, 0x04000840,
|
||||
0x00800000, 0x00800040, 0x04800000, 0x04800040,
|
||||
0x00800800, 0x00800840, 0x04800800, 0x04800840,
|
||||
0x10000000, 0x10000040, 0x14000000, 0x14000040,
|
||||
0x10000800, 0x10000840, 0x14000800, 0x14000840,
|
||||
0x10800000, 0x10800040, 0x14800000, 0x14800040,
|
||||
0x10800800, 0x10800840, 0x14800800, 0x14800840,
|
||||
0x00000080, 0x000000c0, 0x04000080, 0x040000c0,
|
||||
0x00000880, 0x000008c0, 0x04000880, 0x040008c0,
|
||||
0x00800080, 0x008000c0, 0x04800080, 0x048000c0,
|
||||
0x00800880, 0x008008c0, 0x04800880, 0x048008c0,
|
||||
0x10000080, 0x100000c0, 0x14000080, 0x140000c0,
|
||||
0x10000880, 0x100008c0, 0x14000880, 0x140008c0,
|
||||
0x10800080, 0x108000c0, 0x14800080, 0x148000c0,
|
||||
0x10800880, 0x108008c0, 0x14800880, 0x148008c0
|
||||
},
|
||||
/* table 7 */ {
|
||||
0x00000000, 0x00000010, 0x00000400, 0x00000410,
|
||||
0x00000004, 0x00000014, 0x00000404, 0x00000414,
|
||||
0x00004000, 0x00004010, 0x00004400, 0x00004410,
|
||||
0x00004004, 0x00004014, 0x00004404, 0x00004414,
|
||||
0x20000000, 0x20000010, 0x20000400, 0x20000410,
|
||||
0x20000004, 0x20000014, 0x20000404, 0x20000414,
|
||||
0x20004000, 0x20004010, 0x20004400, 0x20004410,
|
||||
0x20004004, 0x20004014, 0x20004404, 0x20004414,
|
||||
0x00200000, 0x00200010, 0x00200400, 0x00200410,
|
||||
0x00200004, 0x00200014, 0x00200404, 0x00200414,
|
||||
0x00204000, 0x00204010, 0x00204400, 0x00204410,
|
||||
0x00204004, 0x00204014, 0x00204404, 0x00204414,
|
||||
0x20200000, 0x20200010, 0x20200400, 0x20200410,
|
||||
0x20200004, 0x20200014, 0x20200404, 0x20200414,
|
||||
0x20204000, 0x20204010, 0x20204400, 0x20204410,
|
||||
0x20204004, 0x20204014, 0x20204404, 0x20204414
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* The PC-1 Permutation
|
||||
* If we number the bits of the 8 bytes of key input like this (in octal):
|
||||
* 00 01 02 03 04 05 06 07
|
||||
* 10 11 12 13 14 15 16 17
|
||||
* 20 21 22 23 24 25 26 27
|
||||
* 30 31 32 33 34 35 36 37
|
||||
* 40 41 42 43 44 45 46 47
|
||||
* 50 51 52 53 54 55 56 57
|
||||
* 60 61 62 63 64 65 66 67
|
||||
* 70 71 72 73 74 75 76 77
|
||||
* then after the PC-1 permutation,
|
||||
* C0 is
|
||||
* 70 60 50 40 30 20 10 00
|
||||
* 71 61 51 41 31 21 11 01
|
||||
* 72 62 52 42 32 22 12 02
|
||||
* 73 63 53 43
|
||||
* D0 is
|
||||
* 76 66 56 46 36 26 16 06
|
||||
* 75 65 55 45 35 25 15 05
|
||||
* 74 64 54 44 34 24 14 04
|
||||
* 33 23 13 03
|
||||
* and these parity bits have been discarded:
|
||||
* 77 67 57 47 37 27 17 07
|
||||
*
|
||||
* We achieve this by flipping the input matrix about the diagonal from 70-07,
|
||||
* getting left =
|
||||
* 77 67 57 47 37 27 17 07 (these are the parity bits)
|
||||
* 76 66 56 46 36 26 16 06
|
||||
* 75 65 55 45 35 25 15 05
|
||||
* 74 64 54 44 34 24 14 04
|
||||
* right =
|
||||
* 73 63 53 43 33 23 13 03
|
||||
* 72 62 52 42 32 22 12 02
|
||||
* 71 61 51 41 31 21 11 01
|
||||
* 70 60 50 40 30 20 10 00
|
||||
* then byte swap right, ala htonl() on a little endian machine.
|
||||
* right =
|
||||
* 70 60 50 40 30 20 10 00
|
||||
* 71 67 57 47 37 27 11 07
|
||||
* 72 62 52 42 32 22 12 02
|
||||
* 73 63 53 43 33 23 13 03
|
||||
* then
|
||||
* c0 = right >> 4;
|
||||
* d0 = ((left & 0x00ffffff) << 4) | (right & 0xf);
|
||||
*/
|
||||
|
||||
#define FLIP_RIGHT_DIAGONAL(word, temp) \
|
||||
temp = (word ^ (word >> 18)) & 0x00003333; \
|
||||
word ^= temp | (temp << 18); \
|
||||
temp = (word ^ (word >> 9)) & 0x00550055; \
|
||||
word ^= temp | (temp << 9);
|
||||
|
||||
#define BYTESWAP(word, temp) \
|
||||
word = (word >> 16) | (word << 16); \
|
||||
temp = 0x00ff00ff; \
|
||||
word = ((word & temp) << 8) | ((word >> 8) & temp);
|
||||
|
||||
#define PC1(left, right, c0, d0, temp) \
|
||||
right ^= temp = ((left >> 4) ^ right) & 0x0f0f0f0f; \
|
||||
left ^= temp << 4; \
|
||||
FLIP_RIGHT_DIAGONAL(left, temp); \
|
||||
FLIP_RIGHT_DIAGONAL(right, temp); \
|
||||
BYTESWAP(right, temp); \
|
||||
c0 = right >> 4; \
|
||||
d0 = ((left & 0x00ffffff) << 4) | (right & 0xf);
|
||||
|
||||
#define LEFT_SHIFT_1( reg ) (((reg << 1) | (reg >> 27)) & 0x0FFFFFFF)
|
||||
#define LEFT_SHIFT_2( reg ) (((reg << 2) | (reg >> 26)) & 0x0FFFFFFF)
|
||||
|
||||
/*
|
||||
* setup key schedules from key
|
||||
*/
|
||||
|
||||
void
|
||||
DES_MakeSchedule( HALF * ks, const BYTE * key, DESDirection direction)
|
||||
{
|
||||
register HALF left, right;
|
||||
register HALF c0, d0;
|
||||
register HALF temp;
|
||||
int delta;
|
||||
unsigned int ls;
|
||||
|
||||
#if defined(_X86_)
|
||||
left = HALFPTR(key)[0];
|
||||
right = HALFPTR(key)[1];
|
||||
BYTESWAP(left, temp);
|
||||
BYTESWAP(right, temp);
|
||||
#else
|
||||
if (((ptrdiff_t)key & 0x03) == 0) {
|
||||
left = HALFPTR(key)[0];
|
||||
right = HALFPTR(key)[1];
|
||||
#if defined(IS_LITTLE_ENDIAN)
|
||||
BYTESWAP(left, temp);
|
||||
BYTESWAP(right, temp);
|
||||
#endif
|
||||
} else {
|
||||
left = ((HALF)key[0] << 24) | ((HALF)key[1] << 16) |
|
||||
((HALF)key[2] << 8) | key[3];
|
||||
right = ((HALF)key[4] << 24) | ((HALF)key[5] << 16) |
|
||||
((HALF)key[6] << 8) | key[7];
|
||||
}
|
||||
#endif
|
||||
|
||||
PC1(left, right, c0, d0, temp);
|
||||
|
||||
if (direction == DES_ENCRYPT) {
|
||||
delta = 2 * (int)sizeof(HALF);
|
||||
} else {
|
||||
ks += 30;
|
||||
delta = (-2) * (int)sizeof(HALF);
|
||||
}
|
||||
|
||||
for (ls = 0x8103; ls; ls >>= 1) {
|
||||
if ( ls & 1 ) {
|
||||
c0 = LEFT_SHIFT_1( c0 );
|
||||
d0 = LEFT_SHIFT_1( d0 );
|
||||
} else {
|
||||
c0 = LEFT_SHIFT_2( c0 );
|
||||
d0 = LEFT_SHIFT_2( d0 );
|
||||
}
|
||||
|
||||
#ifdef USE_INDEXING
|
||||
#define PC2LOOKUP(b,c) PC2[b][c]
|
||||
|
||||
left = PC2LOOKUP(0, ((c0 >> 22) & 0x3F) );
|
||||
left |= PC2LOOKUP(1, ((c0 >> 13) & 0x3F) );
|
||||
left |= PC2LOOKUP(2, ((c0 >> 4) & 0x38) | (c0 & 0x7) );
|
||||
left |= PC2LOOKUP(3, ((c0>>18)&0xC) | ((c0>>11)&0x3) | (c0&0x30));
|
||||
|
||||
right = PC2LOOKUP(4, ((d0 >> 22) & 0x3F) );
|
||||
right |= PC2LOOKUP(5, ((d0 >> 15) & 0x30) | ((d0 >> 14) & 0xf) );
|
||||
right |= PC2LOOKUP(6, ((d0 >> 7) & 0x3F) );
|
||||
right |= PC2LOOKUP(7, ((d0 >> 1) & 0x3C) | (d0 & 0x3));
|
||||
#else
|
||||
#define PC2LOOKUP(b,c) *(HALF *)((BYTE *)&PC2[b][0]+(c))
|
||||
|
||||
left = PC2LOOKUP(0, ((c0 >> 20) & 0xFC) );
|
||||
left |= PC2LOOKUP(1, ((c0 >> 11) & 0xFC) );
|
||||
left |= PC2LOOKUP(2, ((c0 >> 2) & 0xE0) | ((c0 << 2) & 0x1C) );
|
||||
left |= PC2LOOKUP(3, ((c0>>16)&0x30)|((c0>>9)&0xC)|((c0<<2)&0xC0));
|
||||
|
||||
right = PC2LOOKUP(4, ((d0 >> 20) & 0xFC) );
|
||||
right |= PC2LOOKUP(5, ((d0 >> 13) & 0xC0) | ((d0 >> 12) & 0x3C) );
|
||||
right |= PC2LOOKUP(6, ((d0 >> 5) & 0xFC) );
|
||||
right |= PC2LOOKUP(7, ((d0 << 1) & 0xF0) | ((d0 << 2) & 0x0C));
|
||||
#endif
|
||||
/* left contains key bits for S1 S3 S2 S4 */
|
||||
/* right contains key bits for S6 S8 S5 S7 */
|
||||
temp = (left << 16) /* S2 S4 XX XX */
|
||||
| (right >> 16); /* XX XX S6 S8 */
|
||||
ks[0] = temp;
|
||||
|
||||
temp = (left & 0xffff0000) /* S1 S3 XX XX */
|
||||
| (right & 0x0000ffff);/* XX XX S5 S7 */
|
||||
ks[1] = temp;
|
||||
|
||||
ks = (HALF*)((BYTE *)ks + delta);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The DES Initial Permutation
|
||||
* if we number the bits of the 8 bytes of input like this (in octal):
|
||||
* 00 01 02 03 04 05 06 07
|
||||
* 10 11 12 13 14 15 16 17
|
||||
* 20 21 22 23 24 25 26 27
|
||||
* 30 31 32 33 34 35 36 37
|
||||
* 40 41 42 43 44 45 46 47
|
||||
* 50 51 52 53 54 55 56 57
|
||||
* 60 61 62 63 64 65 66 67
|
||||
* 70 71 72 73 74 75 76 77
|
||||
* then after the initial permutation, they will be in this order.
|
||||
* 71 61 51 41 31 21 11 01
|
||||
* 73 63 53 43 33 23 13 03
|
||||
* 75 65 55 45 35 25 15 05
|
||||
* 77 67 57 47 37 27 17 07
|
||||
* 70 60 50 40 30 20 10 00
|
||||
* 72 62 52 42 32 22 12 02
|
||||
* 74 64 54 44 34 24 14 04
|
||||
* 76 66 56 46 36 26 16 06
|
||||
*
|
||||
* One way to do this is in two steps:
|
||||
* 1. Flip this matrix about the diagonal from 70-07 as done for PC1.
|
||||
* 2. Rearrange the bytes (rows in the matrix above) with the following code.
|
||||
*
|
||||
* #define swapHiLo(word, temp) \
|
||||
* temp = (word ^ (word >> 24)) & 0x000000ff; \
|
||||
* word ^= temp | (temp << 24);
|
||||
*
|
||||
* right ^= temp = ((left << 8) ^ right) & 0xff00ff00;
|
||||
* left ^= temp >> 8;
|
||||
* swapHiLo(left, temp);
|
||||
* swapHiLo(right,temp);
|
||||
*
|
||||
* However, the two steps can be combined, so that the rows are rearranged
|
||||
* while the matrix is being flipped, reducing the number of bit exchange
|
||||
* operations from 8 ot 5.
|
||||
*
|
||||
* Initial Permutation */
|
||||
#define IP(left, right, temp) \
|
||||
right ^= temp = ((left >> 4) ^ right) & 0x0f0f0f0f; \
|
||||
left ^= temp << 4; \
|
||||
right ^= temp = ((left >> 16) ^ right) & 0x0000ffff; \
|
||||
left ^= temp << 16; \
|
||||
right ^= temp = ((left << 2) ^ right) & 0xcccccccc; \
|
||||
left ^= temp >> 2; \
|
||||
right ^= temp = ((left << 8) ^ right) & 0xff00ff00; \
|
||||
left ^= temp >> 8; \
|
||||
right ^= temp = ((left >> 1) ^ right) & 0x55555555; \
|
||||
left ^= temp << 1;
|
||||
|
||||
/* The Final (Inverse Initial) permutation is done by reversing the
|
||||
** steps of the Initital Permutation
|
||||
*/
|
||||
|
||||
#define FP(left, right, temp) \
|
||||
right ^= temp = ((left >> 1) ^ right) & 0x55555555; \
|
||||
left ^= temp << 1; \
|
||||
right ^= temp = ((left << 8) ^ right) & 0xff00ff00; \
|
||||
left ^= temp >> 8; \
|
||||
right ^= temp = ((left << 2) ^ right) & 0xcccccccc; \
|
||||
left ^= temp >> 2; \
|
||||
right ^= temp = ((left >> 16) ^ right) & 0x0000ffff; \
|
||||
left ^= temp << 16; \
|
||||
right ^= temp = ((left >> 4) ^ right) & 0x0f0f0f0f; \
|
||||
left ^= temp << 4;
|
||||
|
||||
void
|
||||
DES_Do1Block(HALF * ks, const BYTE * inbuf, BYTE * outbuf)
|
||||
{
|
||||
register HALF left, right;
|
||||
register HALF temp;
|
||||
|
||||
#if defined(_X86_)
|
||||
left = HALFPTR(inbuf)[0];
|
||||
right = HALFPTR(inbuf)[1];
|
||||
BYTESWAP(left, temp);
|
||||
BYTESWAP(right, temp);
|
||||
#else
|
||||
if (((ptrdiff_t)inbuf & 0x03) == 0) {
|
||||
left = HALFPTR(inbuf)[0];
|
||||
right = HALFPTR(inbuf)[1];
|
||||
#if defined(IS_LITTLE_ENDIAN)
|
||||
BYTESWAP(left, temp);
|
||||
BYTESWAP(right, temp);
|
||||
#endif
|
||||
} else {
|
||||
left = ((HALF)inbuf[0] << 24) | ((HALF)inbuf[1] << 16) |
|
||||
((HALF)inbuf[2] << 8) | inbuf[3];
|
||||
right = ((HALF)inbuf[4] << 24) | ((HALF)inbuf[5] << 16) |
|
||||
((HALF)inbuf[6] << 8) | inbuf[7];
|
||||
}
|
||||
#endif
|
||||
|
||||
IP(left, right, temp);
|
||||
|
||||
/* shift the values left circularly 3 bits. */
|
||||
left = (left << 3) | (left >> 29);
|
||||
right = (right << 3) | (right >> 29);
|
||||
|
||||
#ifdef USE_INDEXING
|
||||
#define KSLOOKUP(s,b) SP[s][((temp >> (b+2)) & 0x3f)]
|
||||
#else
|
||||
#define KSLOOKUP(s,b) *(HALF*)((BYTE*)&SP[s][0]+((temp >> b) & 0xFC))
|
||||
#endif
|
||||
#define ROUND(out, in, r) \
|
||||
temp = in ^ ks[2*r]; \
|
||||
out ^= KSLOOKUP( 1, 24 ); \
|
||||
out ^= KSLOOKUP( 3, 16 ); \
|
||||
out ^= KSLOOKUP( 5, 8 ); \
|
||||
out ^= KSLOOKUP( 7, 0 ); \
|
||||
temp = ((in >> 4) | (in << 28)) ^ ks[2*r+1]; \
|
||||
out ^= KSLOOKUP( 0, 24 ); \
|
||||
out ^= KSLOOKUP( 2, 16 ); \
|
||||
out ^= KSLOOKUP( 4, 8 ); \
|
||||
out ^= KSLOOKUP( 6, 0 );
|
||||
|
||||
/* Do the 16 Feistel rounds */
|
||||
ROUND(left, right, 0)
|
||||
ROUND(right, left, 1)
|
||||
ROUND(left, right, 2)
|
||||
ROUND(right, left, 3)
|
||||
ROUND(left, right, 4)
|
||||
ROUND(right, left, 5)
|
||||
ROUND(left, right, 6)
|
||||
ROUND(right, left, 7)
|
||||
ROUND(left, right, 8)
|
||||
ROUND(right, left, 9)
|
||||
ROUND(left, right, 10)
|
||||
ROUND(right, left, 11)
|
||||
ROUND(left, right, 12)
|
||||
ROUND(right, left, 13)
|
||||
ROUND(left, right, 14)
|
||||
ROUND(right, left, 15)
|
||||
|
||||
/* now shift circularly right 3 bits to undo the shifting done
|
||||
** above. switch left and right here.
|
||||
*/
|
||||
temp = (left >> 3) | (left << 29);
|
||||
left = (right >> 3) | (right << 29);
|
||||
right = temp;
|
||||
|
||||
FP(left, right, temp);
|
||||
|
||||
#if defined(_X86_)
|
||||
BYTESWAP(left, temp);
|
||||
BYTESWAP(right, temp);
|
||||
HALFPTR(outbuf)[0] = left;
|
||||
HALFPTR(outbuf)[1] = right;
|
||||
#else
|
||||
if (((ptrdiff_t)inbuf & 0x03) == 0) {
|
||||
#if defined(IS_LITTLE_ENDIAN)
|
||||
BYTESWAP(left, temp);
|
||||
BYTESWAP(right, temp);
|
||||
#endif
|
||||
HALFPTR(outbuf)[0] = left;
|
||||
HALFPTR(outbuf)[1] = right;
|
||||
} else {
|
||||
outbuf[0] = (BYTE)(left >> 24);
|
||||
outbuf[1] = (BYTE)(left >> 16);
|
||||
outbuf[2] = (BYTE)(left >> 8);
|
||||
outbuf[3] = (BYTE)(left );
|
||||
|
||||
outbuf[4] = (BYTE)(right >> 24);
|
||||
outbuf[5] = (BYTE)(right >> 16);
|
||||
outbuf[6] = (BYTE)(right >> 8);
|
||||
outbuf[7] = (BYTE)(right );
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
/* Ackowledgements:
|
||||
** Two ideas used in this implementation were shown to me by Dennis Ferguson
|
||||
** in 1990. He credits them to Richard Outerbridge and Dan Hoey. They were:
|
||||
** 1. The method of computing the Initial and Final permutations.
|
||||
** 2. Circularly rotating the SP tables and the initial values of left and
|
||||
** right to reduce the number of shifts required during the 16 rounds.
|
||||
*/
|
||||
@@ -1,69 +0,0 @@
|
||||
/*
|
||||
* des.h
|
||||
*
|
||||
* header file for DES-150 library
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF 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 DES-150 library.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Nelson B. Bolyard,
|
||||
* nelsonb@iname.com. Portions created by Nelson B. Bolyard are
|
||||
* Copyright (C) 1990, 2000 Nelson B. Bolyard, All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the
|
||||
* terms of the GNU General Public License Version 2 or later (the
|
||||
* "GPL"), in which case the provisions of the GPL are applicable
|
||||
* instead of those above. If you wish to allow use of your
|
||||
* version of this file only under the terms of the GPL and not to
|
||||
* allow others to use your version of this file under the MPL,
|
||||
* indicate your decision by deleting the provisions above and
|
||||
* replace them with the notice and other provisions required by
|
||||
* the GPL. If you do not delete the provisions above, a recipient
|
||||
* may use your version of this file under either the MPL or the GPL.
|
||||
*/
|
||||
|
||||
#ifndef _DES_H_
|
||||
#define _DES_H_ 1
|
||||
|
||||
#include "blapi.h"
|
||||
|
||||
typedef unsigned char BYTE;
|
||||
typedef unsigned int HALF;
|
||||
|
||||
#define HALFPTR(x) ((HALF *)(x))
|
||||
#define SHORTPTR(x) ((unsigned short *)(x))
|
||||
#define BYTEPTR(x) ((BYTE *)(x))
|
||||
|
||||
typedef enum {
|
||||
DES_ENCRYPT = 0x5555,
|
||||
DES_DECRYPT = 0xAAAA
|
||||
} DESDirection;
|
||||
|
||||
typedef void DESFunc(struct DESContextStr *cx, BYTE *out, const BYTE *in,
|
||||
unsigned int len);
|
||||
|
||||
struct DESContextStr {
|
||||
/* key schedule, 16 internal keys, each with 8 6-bit parts */
|
||||
HALF ks0 [32];
|
||||
HALF ks1 [32];
|
||||
HALF ks2 [32];
|
||||
HALF iv [2];
|
||||
DESDirection direction;
|
||||
DESFunc *worker;
|
||||
};
|
||||
|
||||
void DES_MakeSchedule( HALF * ks, const BYTE * key, DESDirection direction);
|
||||
void DES_Do1Block( HALF * ks, const BYTE * inbuf, BYTE * outbuf);
|
||||
|
||||
#endif
|
||||
@@ -1,275 +0,0 @@
|
||||
/*
|
||||
* desblapi.c
|
||||
*
|
||||
* core source file for DES-150 library
|
||||
* Implement DES Modes of Operation and Triple-DES.
|
||||
* Adapt DES-150 to blapi API.
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF 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 DES-150 library.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Nelson B. Bolyard,
|
||||
* nelsonb@iname.com. Portions created by Nelson B. Bolyard are
|
||||
* Copyright (C) 1990, 2000 Nelson B. Bolyard, All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the
|
||||
* terms of the GNU General Public License Version 2 or later (the
|
||||
* "GPL"), in which case the provisions of the GPL are applicable
|
||||
* instead of those above. If you wish to allow use of your
|
||||
* version of this file only under the terms of the GPL and not to
|
||||
* allow others to use your version of this file under the MPL,
|
||||
* indicate your decision by deleting the provisions above and
|
||||
* replace them with the notice and other provisions required by
|
||||
* the GPL. If you do not delete the provisions above, a recipient
|
||||
* may use your version of this file under either the MPL or the GPL.
|
||||
*/
|
||||
|
||||
#include "des.h"
|
||||
#include <stddef.h>
|
||||
#include "secerr.h"
|
||||
|
||||
#if defined(_X86_)
|
||||
/* Intel X86 CPUs do unaligned loads and stores without complaint. */
|
||||
#define COPY8B(to, from, ptr) \
|
||||
HALFPTR(to)[0] = HALFPTR(from)[0]; \
|
||||
HALFPTR(to)[1] = HALFPTR(from)[1];
|
||||
#elif defined(USE_MEMCPY)
|
||||
#define COPY8B(to, from, ptr) memcpy(to, from, 8)
|
||||
#else
|
||||
#define COPY8B(to, from, ptr) \
|
||||
if (((ptrdiff_t)(ptr) & 0x3) == 0) { \
|
||||
HALFPTR(to)[0] = HALFPTR(from)[0]; \
|
||||
HALFPTR(to)[1] = HALFPTR(from)[1]; \
|
||||
} else if (((ptrdiff_t)(ptr) & 0x1) == 0) { \
|
||||
SHORTPTR(to)[0] = SHORTPTR(from)[0]; \
|
||||
SHORTPTR(to)[1] = SHORTPTR(from)[1]; \
|
||||
SHORTPTR(to)[2] = SHORTPTR(from)[2]; \
|
||||
SHORTPTR(to)[3] = SHORTPTR(from)[3]; \
|
||||
} else { \
|
||||
BYTEPTR(to)[0] = BYTEPTR(from)[0]; \
|
||||
BYTEPTR(to)[1] = BYTEPTR(from)[1]; \
|
||||
BYTEPTR(to)[2] = BYTEPTR(from)[2]; \
|
||||
BYTEPTR(to)[3] = BYTEPTR(from)[3]; \
|
||||
BYTEPTR(to)[4] = BYTEPTR(from)[4]; \
|
||||
BYTEPTR(to)[5] = BYTEPTR(from)[5]; \
|
||||
BYTEPTR(to)[6] = BYTEPTR(from)[6]; \
|
||||
BYTEPTR(to)[7] = BYTEPTR(from)[7]; \
|
||||
}
|
||||
#endif
|
||||
#define COPY8BTOHALF(to, from) COPY8B(to, from, from)
|
||||
#define COPY8BFROMHALF(to, from) COPY8B(to, from, to)
|
||||
|
||||
static void
|
||||
DES_ECB(DESContext *cx, BYTE *out, const BYTE *in, unsigned int len)
|
||||
{
|
||||
while (len) {
|
||||
DES_Do1Block(cx->ks0, in, out);
|
||||
len -= 8;
|
||||
in += 8;
|
||||
out += 8;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
DES_EDE3_ECB(DESContext *cx, BYTE *out, const BYTE *in, unsigned int len)
|
||||
{
|
||||
while (len) {
|
||||
DES_Do1Block(cx->ks0, in, out);
|
||||
len -= 8;
|
||||
in += 8;
|
||||
DES_Do1Block(cx->ks1, out, out);
|
||||
DES_Do1Block(cx->ks2, out, out);
|
||||
out += 8;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
DES_CBCEn(DESContext *cx, BYTE *out, const BYTE *in, unsigned int len)
|
||||
{
|
||||
const BYTE * bufend = in + len;
|
||||
HALF vec[2];
|
||||
|
||||
while (in != bufend) {
|
||||
COPY8BTOHALF(vec, in);
|
||||
in += 8;
|
||||
vec[0] ^= cx->iv[0];
|
||||
vec[1] ^= cx->iv[1];
|
||||
DES_Do1Block( cx->ks0, (BYTE *)vec, (BYTE *)cx->iv);
|
||||
COPY8BFROMHALF(out, cx->iv);
|
||||
out += 8;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
DES_CBCDe(DESContext *cx, BYTE *out, const BYTE *in, unsigned int len)
|
||||
{
|
||||
const BYTE * bufend;
|
||||
HALF oldciphertext[2];
|
||||
HALF plaintext [2];
|
||||
|
||||
for (bufend = in + len; in != bufend; ) {
|
||||
oldciphertext[0] = cx->iv[0];
|
||||
oldciphertext[1] = cx->iv[1];
|
||||
COPY8BTOHALF(cx->iv, in);
|
||||
in += 8;
|
||||
DES_Do1Block(cx->ks0, (BYTE *)cx->iv, (BYTE *)plaintext);
|
||||
plaintext[0] ^= oldciphertext[0];
|
||||
plaintext[1] ^= oldciphertext[1];
|
||||
COPY8BFROMHALF(out, plaintext);
|
||||
out += 8;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
DES_EDE3CBCEn(DESContext *cx, BYTE *out, const BYTE *in, unsigned int len)
|
||||
{
|
||||
const BYTE * bufend = in + len;
|
||||
HALF vec[2];
|
||||
|
||||
while (in != bufend) {
|
||||
COPY8BTOHALF(vec, in);
|
||||
in += 8;
|
||||
vec[0] ^= cx->iv[0];
|
||||
vec[1] ^= cx->iv[1];
|
||||
DES_Do1Block( cx->ks0, (BYTE *)vec, (BYTE *)cx->iv);
|
||||
DES_Do1Block( cx->ks1, (BYTE *)cx->iv, (BYTE *)cx->iv);
|
||||
DES_Do1Block( cx->ks2, (BYTE *)cx->iv, (BYTE *)cx->iv);
|
||||
COPY8BFROMHALF(out, cx->iv);
|
||||
out += 8;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
DES_EDE3CBCDe(DESContext *cx, BYTE *out, const BYTE *in, unsigned int len)
|
||||
{
|
||||
const BYTE * bufend;
|
||||
HALF oldciphertext[2];
|
||||
HALF plaintext [2];
|
||||
|
||||
for (bufend = in + len; in != bufend; ) {
|
||||
oldciphertext[0] = cx->iv[0];
|
||||
oldciphertext[1] = cx->iv[1];
|
||||
COPY8BTOHALF(cx->iv, in);
|
||||
in += 8;
|
||||
DES_Do1Block(cx->ks0, (BYTE *)cx->iv, (BYTE *)plaintext);
|
||||
DES_Do1Block(cx->ks1, (BYTE *)plaintext, (BYTE *)plaintext);
|
||||
DES_Do1Block(cx->ks2, (BYTE *)plaintext, (BYTE *)plaintext);
|
||||
plaintext[0] ^= oldciphertext[0];
|
||||
plaintext[1] ^= oldciphertext[1];
|
||||
COPY8BFROMHALF(out, plaintext);
|
||||
out += 8;
|
||||
}
|
||||
}
|
||||
|
||||
DESContext *
|
||||
DES_CreateContext(const BYTE * key, const BYTE *iv, int mode, PRBool encrypt)
|
||||
{
|
||||
DESContext *cx = PORT_ZNew(DESContext);
|
||||
DESDirection opposite;
|
||||
if (!cx)
|
||||
return 0;
|
||||
cx->direction = encrypt ? DES_ENCRYPT : DES_DECRYPT;
|
||||
opposite = encrypt ? DES_DECRYPT : DES_ENCRYPT;
|
||||
switch (mode) {
|
||||
case NSS_DES: /* DES ECB */
|
||||
DES_MakeSchedule( cx->ks0, key, cx->direction);
|
||||
cx->worker = &DES_ECB;
|
||||
break;
|
||||
|
||||
case NSS_DES_EDE3: /* DES EDE ECB */
|
||||
cx->worker = &DES_EDE3_ECB;
|
||||
if (encrypt) {
|
||||
DES_MakeSchedule(cx->ks0, key, cx->direction);
|
||||
DES_MakeSchedule(cx->ks1, key + 8, opposite);
|
||||
DES_MakeSchedule(cx->ks2, key + 16, cx->direction);
|
||||
} else {
|
||||
DES_MakeSchedule(cx->ks2, key, cx->direction);
|
||||
DES_MakeSchedule(cx->ks1, key + 8, opposite);
|
||||
DES_MakeSchedule(cx->ks0, key + 16, cx->direction);
|
||||
}
|
||||
break;
|
||||
|
||||
case NSS_DES_CBC: /* DES CBC */
|
||||
COPY8BTOHALF(cx->iv, iv);
|
||||
cx->worker = encrypt ? &DES_CBCEn : &DES_CBCDe;
|
||||
DES_MakeSchedule(cx->ks0, key, cx->direction);
|
||||
break;
|
||||
|
||||
case NSS_DES_EDE3_CBC: /* DES EDE CBC */
|
||||
COPY8BTOHALF(cx->iv, iv);
|
||||
if (encrypt) {
|
||||
cx->worker = &DES_EDE3CBCEn;
|
||||
DES_MakeSchedule(cx->ks0, key, cx->direction);
|
||||
DES_MakeSchedule(cx->ks1, key + 8, opposite);
|
||||
DES_MakeSchedule(cx->ks2, key + 16, cx->direction);
|
||||
} else {
|
||||
cx->worker = &DES_EDE3CBCDe;
|
||||
DES_MakeSchedule(cx->ks2, key, cx->direction);
|
||||
DES_MakeSchedule(cx->ks1, key + 8, opposite);
|
||||
DES_MakeSchedule(cx->ks0, key + 16, cx->direction);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
PORT_Free(cx);
|
||||
cx = 0;
|
||||
PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
||||
break;
|
||||
}
|
||||
return cx;
|
||||
}
|
||||
|
||||
void
|
||||
DES_DestroyContext(DESContext *cx, PRBool freeit)
|
||||
{
|
||||
if (cx) {
|
||||
memset(cx, 0, sizeof *cx);
|
||||
if (freeit)
|
||||
PORT_Free(cx);
|
||||
}
|
||||
}
|
||||
|
||||
SECStatus
|
||||
DES_Encrypt(DESContext *cx, BYTE *out, unsigned int *outLen,
|
||||
unsigned int maxOutLen, const BYTE *in, unsigned int inLen)
|
||||
{
|
||||
|
||||
if (inLen < 0 || (inLen % 8) != 0 || maxOutLen < inLen || !cx ||
|
||||
cx->direction != DES_ENCRYPT) {
|
||||
PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
cx->worker(cx, out, in, inLen);
|
||||
if (outLen)
|
||||
*outLen = inLen;
|
||||
return SECSuccess;
|
||||
}
|
||||
|
||||
SECStatus
|
||||
DES_Decrypt(DESContext *cx, BYTE *out, unsigned int *outLen,
|
||||
unsigned int maxOutLen, const BYTE *in, unsigned int inLen)
|
||||
{
|
||||
|
||||
if (inLen < 0 || (inLen % 8) != 0 || maxOutLen < inLen || !cx ||
|
||||
cx->direction != DES_DECRYPT) {
|
||||
PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
cx->worker(cx, out, in, inLen);
|
||||
if (outLen)
|
||||
*outLen = inLen;
|
||||
return SECSuccess;
|
||||
}
|
||||
@@ -1,385 +0,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 the Netscape security libraries.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1994-2000 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the
|
||||
* terms of the GNU General Public License Version 2 or later (the
|
||||
* "GPL"), in which case the provisions of the GPL are applicable
|
||||
* instead of those above. If you wish to allow use of your
|
||||
* version of this file only under the terms of the GPL and not to
|
||||
* allow others to use your version of this file under the MPL,
|
||||
* indicate your decision by deleting the provisions above and
|
||||
* replace them with the notice and other provisions required by
|
||||
* the GPL. If you do not delete the provisions above, a recipient
|
||||
* may use your version of this file under either the MPL or the
|
||||
* GPL.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Diffie-Hellman parameter generation, key generation, and secret derivation.
|
||||
* KEA secret generation and verification.
|
||||
*
|
||||
* $Id: dh.c,v 1.6 2001-09-20 22:14:06 relyea%netscape.com Exp $
|
||||
*/
|
||||
|
||||
#include "prerr.h"
|
||||
#include "secerr.h"
|
||||
|
||||
#include "blapi.h"
|
||||
#include "secitem.h"
|
||||
#include "mpi.h"
|
||||
#include "mpprime.h"
|
||||
#include "secmpi.h"
|
||||
|
||||
#define DH_SECRET_KEY_LEN 20
|
||||
#define KEA_DERIVED_SECRET_LEN 128
|
||||
|
||||
SECStatus
|
||||
DH_GenParam(int primeLen, DHParams **params)
|
||||
{
|
||||
PRArenaPool *arena;
|
||||
DHParams *dhparams;
|
||||
unsigned char *pb = NULL;
|
||||
unsigned char *ab = NULL;
|
||||
unsigned long counter = 0;
|
||||
mp_int p, q, a, h, psub1, test;
|
||||
mp_err err = MP_OKAY;
|
||||
SECStatus rv = SECSuccess;
|
||||
if (!params || primeLen < 0) {
|
||||
PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
||||
return SECFailure;
|
||||
}
|
||||
arena = PORT_NewArena(NSS_FREEBL_DEFAULT_CHUNKSIZE);
|
||||
if (!arena) {
|
||||
PORT_SetError(SEC_ERROR_NO_MEMORY);
|
||||
return SECFailure;
|
||||
}
|
||||
dhparams = (DHParams *)PORT_ArenaZAlloc(arena, sizeof(DHParams));
|
||||
if (!dhparams) {
|
||||
PORT_SetError(SEC_ERROR_NO_MEMORY);
|
||||
PORT_FreeArena(arena, PR_TRUE);
|
||||
return SECFailure;
|
||||
}
|
||||
dhparams->arena = arena;
|
||||
MP_DIGITS(&p) = 0;
|
||||
MP_DIGITS(&q) = 0;
|
||||
MP_DIGITS(&a) = 0;
|
||||
MP_DIGITS(&h) = 0;
|
||||
MP_DIGITS(&psub1) = 0;
|
||||
MP_DIGITS(&test) = 0;
|
||||
CHECK_MPI_OK( mp_init(&p) );
|
||||
CHECK_MPI_OK( mp_init(&q) );
|
||||
CHECK_MPI_OK( mp_init(&a) );
|
||||
CHECK_MPI_OK( mp_init(&h) );
|
||||
CHECK_MPI_OK( mp_init(&psub1) );
|
||||
CHECK_MPI_OK( mp_init(&test) );
|
||||
/* generate prime with MPI, uses Miller-Rabin to generate strong prime. */
|
||||
pb = PORT_Alloc(primeLen);
|
||||
CHECK_SEC_OK( RNG_GenerateGlobalRandomBytes(pb, primeLen) );
|
||||
pb[0] |= 0x80; /* set high-order bit */
|
||||
pb[primeLen-1] |= 0x01; /* set low-order bit */
|
||||
CHECK_MPI_OK( mp_read_unsigned_octets(&p, pb, primeLen) );
|
||||
CHECK_MPI_OK( mpp_make_prime(&p, primeLen * 8, PR_TRUE, &counter) );
|
||||
/* construct Sophie-Germain prime q = (p-1)/2. */
|
||||
CHECK_MPI_OK( mp_sub_d(&p, 1, &psub1) );
|
||||
CHECK_MPI_OK( mp_div_2(&psub1, &q) );
|
||||
/* construct a generator from the prime. */
|
||||
ab = PORT_Alloc(primeLen);
|
||||
/* generate a candidate number a in p's field */
|
||||
CHECK_SEC_OK( RNG_GenerateGlobalRandomBytes(ab, primeLen) );
|
||||
CHECK_MPI_OK( mp_read_unsigned_octets(&a, ab, primeLen) );
|
||||
/* force a < p (note that quot(a/p) <= 1) */
|
||||
if ( mp_cmp(&a, &p) > 0 )
|
||||
CHECK_MPI_OK( mp_sub(&a, &p, &a) );
|
||||
do {
|
||||
/* check that a is in the range [2..p-1] */
|
||||
if ( mp_cmp_d(&a, 2) < 0 || mp_cmp(&a, &psub1) >= 0) {
|
||||
/* a is outside of the allowed range. Set a=3 and keep going. */
|
||||
mp_set(&a, 3);
|
||||
}
|
||||
/* if a**q mod p != 1 then a is a generator */
|
||||
CHECK_MPI_OK( mp_exptmod(&a, &q, &p, &test) );
|
||||
if ( mp_cmp_d(&test, 1) != 0 )
|
||||
break;
|
||||
/* increment the candidate and try again. */
|
||||
CHECK_MPI_OK( mp_add_d(&a, 1, &a) );
|
||||
} while (PR_TRUE);
|
||||
MPINT_TO_SECITEM(&p, &dhparams->prime, arena);
|
||||
MPINT_TO_SECITEM(&a, &dhparams->base, arena);
|
||||
*params = dhparams;
|
||||
cleanup:
|
||||
mp_clear(&p);
|
||||
mp_clear(&q);
|
||||
mp_clear(&a);
|
||||
mp_clear(&h);
|
||||
mp_clear(&psub1);
|
||||
mp_clear(&test);
|
||||
if (pb) PORT_ZFree(pb, primeLen);
|
||||
if (ab) PORT_ZFree(ab, primeLen);
|
||||
if (err) {
|
||||
MP_TO_SEC_ERROR(err);
|
||||
rv = SECFailure;
|
||||
}
|
||||
if (rv)
|
||||
PORT_FreeArena(arena, PR_TRUE);
|
||||
return rv;
|
||||
}
|
||||
|
||||
SECStatus
|
||||
DH_NewKey(DHParams *params, DHPrivateKey **privKey)
|
||||
{
|
||||
PRArenaPool *arena;
|
||||
DHPrivateKey *key;
|
||||
mp_int g, xa, p, Ya;
|
||||
mp_err err = MP_OKAY;
|
||||
SECStatus rv = SECSuccess;
|
||||
if (!params || !privKey) {
|
||||
PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
||||
return SECFailure;
|
||||
}
|
||||
arena = PORT_NewArena(NSS_FREEBL_DEFAULT_CHUNKSIZE);
|
||||
if (!arena) {
|
||||
PORT_SetError(SEC_ERROR_NO_MEMORY);
|
||||
return SECFailure;
|
||||
}
|
||||
key = (DHPrivateKey *)PORT_ArenaZAlloc(arena, sizeof(DHPrivateKey));
|
||||
if (!key) {
|
||||
PORT_SetError(SEC_ERROR_NO_MEMORY);
|
||||
PORT_FreeArena(arena, PR_TRUE);
|
||||
return SECFailure;
|
||||
}
|
||||
key->arena = arena;
|
||||
MP_DIGITS(&g) = 0;
|
||||
MP_DIGITS(&xa) = 0;
|
||||
MP_DIGITS(&p) = 0;
|
||||
MP_DIGITS(&Ya) = 0;
|
||||
CHECK_MPI_OK( mp_init(&g) );
|
||||
CHECK_MPI_OK( mp_init(&xa) );
|
||||
CHECK_MPI_OK( mp_init(&p) );
|
||||
CHECK_MPI_OK( mp_init(&Ya) );
|
||||
/* Set private key's p */
|
||||
CHECK_SEC_OK( SECITEM_CopyItem(arena, &key->prime, ¶ms->prime) );
|
||||
SECITEM_TO_MPINT(key->prime, &p);
|
||||
/* Set private key's g */
|
||||
CHECK_SEC_OK( SECITEM_CopyItem(arena, &key->base, ¶ms->base) );
|
||||
SECITEM_TO_MPINT(key->base, &g);
|
||||
/* Generate private key xa */
|
||||
SECITEM_AllocItem(arena, &key->privateValue, DH_SECRET_KEY_LEN);
|
||||
RNG_GenerateGlobalRandomBytes(key->privateValue.data,
|
||||
key->privateValue.len);
|
||||
SECITEM_TO_MPINT( key->privateValue, &xa );
|
||||
/* xa < p */
|
||||
CHECK_MPI_OK( mp_mod(&xa, &p, &xa) );
|
||||
/* Compute public key Ya = g ** xa mod p */
|
||||
CHECK_MPI_OK( mp_exptmod(&g, &xa, &p, &Ya) );
|
||||
MPINT_TO_SECITEM(&Ya, &key->publicValue, key->arena);
|
||||
*privKey = key;
|
||||
cleanup:
|
||||
mp_clear(&g);
|
||||
mp_clear(&xa);
|
||||
mp_clear(&p);
|
||||
mp_clear(&Ya);
|
||||
if (err) {
|
||||
MP_TO_SEC_ERROR(err);
|
||||
rv = SECFailure;
|
||||
}
|
||||
if (rv)
|
||||
PORT_FreeArena(arena, PR_TRUE);
|
||||
return rv;
|
||||
}
|
||||
|
||||
SECStatus
|
||||
DH_Derive(SECItem *publicValue,
|
||||
SECItem *prime,
|
||||
SECItem *privateValue,
|
||||
SECItem *derivedSecret,
|
||||
unsigned int maxOutBytes)
|
||||
{
|
||||
mp_int p, Xa, Yb, ZZ;
|
||||
mp_err err = MP_OKAY;
|
||||
unsigned int len = 0, nb;
|
||||
unsigned char *secret = NULL;
|
||||
if (!publicValue || !prime || !privateValue || !derivedSecret) {
|
||||
PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
||||
return SECFailure;
|
||||
}
|
||||
memset(derivedSecret, 0, sizeof *derivedSecret);
|
||||
MP_DIGITS(&p) = 0;
|
||||
MP_DIGITS(&Xa) = 0;
|
||||
MP_DIGITS(&Yb) = 0;
|
||||
MP_DIGITS(&ZZ) = 0;
|
||||
CHECK_MPI_OK( mp_init(&p) );
|
||||
CHECK_MPI_OK( mp_init(&Xa) );
|
||||
CHECK_MPI_OK( mp_init(&Yb) );
|
||||
CHECK_MPI_OK( mp_init(&ZZ) );
|
||||
SECITEM_TO_MPINT(*publicValue, &Yb);
|
||||
SECITEM_TO_MPINT(*privateValue, &Xa);
|
||||
SECITEM_TO_MPINT(*prime, &p);
|
||||
/* ZZ = (Yb)**Xa mod p */
|
||||
CHECK_MPI_OK( mp_exptmod(&Yb, &Xa, &p, &ZZ) );
|
||||
/* number of bytes in the derived secret */
|
||||
len = mp_unsigned_octet_size(&ZZ);
|
||||
/* allocate a buffer which can hold the entire derived secret. */
|
||||
secret = PORT_Alloc(len);
|
||||
/* grab the derived secret */
|
||||
err = mp_to_unsigned_octets(&ZZ, secret, len);
|
||||
if (err >= 0) err = MP_OKAY;
|
||||
/* Take minimum of bytes requested and bytes in derived secret,
|
||||
** if maxOutBytes is 0 take all of the bytes from the derived secret.
|
||||
*/
|
||||
if (maxOutBytes > 0)
|
||||
nb = PR_MIN(len, maxOutBytes);
|
||||
else
|
||||
nb = len;
|
||||
SECITEM_AllocItem(NULL, derivedSecret, nb);
|
||||
memcpy(derivedSecret->data, secret, nb);
|
||||
cleanup:
|
||||
mp_clear(&p);
|
||||
mp_clear(&Xa);
|
||||
mp_clear(&Yb);
|
||||
mp_clear(&ZZ);
|
||||
if (secret) {
|
||||
/* free the buffer allocated for the full secret. */
|
||||
PORT_ZFree(secret, len);
|
||||
}
|
||||
if (err) {
|
||||
MP_TO_SEC_ERROR(err);
|
||||
if (derivedSecret->data)
|
||||
PORT_ZFree(derivedSecret->data, derivedSecret->len);
|
||||
return SECFailure;
|
||||
}
|
||||
return SECSuccess;
|
||||
}
|
||||
|
||||
SECStatus
|
||||
KEA_Derive(SECItem *prime,
|
||||
SECItem *public1,
|
||||
SECItem *public2,
|
||||
SECItem *private1,
|
||||
SECItem *private2,
|
||||
SECItem *derivedSecret)
|
||||
{
|
||||
mp_int p, Y, R, r, x, t, u, w;
|
||||
mp_err err;
|
||||
unsigned char *secret = NULL;
|
||||
unsigned int len = 0, offset;
|
||||
if (!prime || !public1 || !public2 || !private1 || !private2 ||
|
||||
!derivedSecret) {
|
||||
PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
||||
return SECFailure;
|
||||
}
|
||||
memset(derivedSecret, 0, sizeof *derivedSecret);
|
||||
MP_DIGITS(&p) = 0;
|
||||
MP_DIGITS(&Y) = 0;
|
||||
MP_DIGITS(&R) = 0;
|
||||
MP_DIGITS(&r) = 0;
|
||||
MP_DIGITS(&x) = 0;
|
||||
MP_DIGITS(&t) = 0;
|
||||
MP_DIGITS(&u) = 0;
|
||||
MP_DIGITS(&w) = 0;
|
||||
CHECK_MPI_OK( mp_init(&p) );
|
||||
CHECK_MPI_OK( mp_init(&Y) );
|
||||
CHECK_MPI_OK( mp_init(&R) );
|
||||
CHECK_MPI_OK( mp_init(&r) );
|
||||
CHECK_MPI_OK( mp_init(&x) );
|
||||
CHECK_MPI_OK( mp_init(&t) );
|
||||
CHECK_MPI_OK( mp_init(&u) );
|
||||
CHECK_MPI_OK( mp_init(&w) );
|
||||
SECITEM_TO_MPINT(*prime, &p);
|
||||
SECITEM_TO_MPINT(*public1, &Y);
|
||||
SECITEM_TO_MPINT(*public2, &R);
|
||||
SECITEM_TO_MPINT(*private1, &r);
|
||||
SECITEM_TO_MPINT(*private2, &x);
|
||||
/* t = DH(Y, r, p) = Y ** r mod p */
|
||||
CHECK_MPI_OK( mp_exptmod(&Y, &r, &p, &t) );
|
||||
/* u = DH(R, x, p) = R ** x mod p */
|
||||
CHECK_MPI_OK( mp_exptmod(&R, &x, &p, &u) );
|
||||
/* w = (t + u) mod p */
|
||||
CHECK_MPI_OK( mp_addmod(&t, &u, &p, &w) );
|
||||
/* allocate a buffer for the full derived secret */
|
||||
len = mp_unsigned_octet_size(&w);
|
||||
secret = PORT_Alloc(len);
|
||||
/* grab the secret */
|
||||
err = mp_to_unsigned_octets(&w, secret, len);
|
||||
if (err > 0) err = MP_OKAY;
|
||||
/* allocate output buffer */
|
||||
SECITEM_AllocItem(NULL, derivedSecret, KEA_DERIVED_SECRET_LEN);
|
||||
memset(derivedSecret->data, 0, derivedSecret->len);
|
||||
/* copy in the 128 lsb of the secret */
|
||||
if (len >= KEA_DERIVED_SECRET_LEN) {
|
||||
memcpy(derivedSecret->data, secret + (len - KEA_DERIVED_SECRET_LEN),
|
||||
KEA_DERIVED_SECRET_LEN);
|
||||
} else {
|
||||
offset = KEA_DERIVED_SECRET_LEN - len;
|
||||
memcpy(derivedSecret->data + offset, secret, len);
|
||||
}
|
||||
cleanup:
|
||||
mp_clear(&p);
|
||||
mp_clear(&Y);
|
||||
mp_clear(&R);
|
||||
mp_clear(&r);
|
||||
mp_clear(&x);
|
||||
mp_clear(&t);
|
||||
mp_clear(&u);
|
||||
mp_clear(&w);
|
||||
if (secret)
|
||||
PORT_ZFree(secret, len);
|
||||
if (err) {
|
||||
MP_TO_SEC_ERROR(err);
|
||||
return SECFailure;
|
||||
}
|
||||
return SECSuccess;
|
||||
}
|
||||
|
||||
PRBool
|
||||
KEA_Verify(SECItem *Y, SECItem *prime, SECItem *subPrime)
|
||||
{
|
||||
mp_int p, q, y, r;
|
||||
mp_err err;
|
||||
int cmp = 1; /* default is false */
|
||||
if (!Y || !prime || !subPrime) {
|
||||
PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
||||
return SECFailure;
|
||||
}
|
||||
MP_DIGITS(&p) = 0;
|
||||
MP_DIGITS(&q) = 0;
|
||||
MP_DIGITS(&y) = 0;
|
||||
MP_DIGITS(&r) = 0;
|
||||
CHECK_MPI_OK( mp_init(&p) );
|
||||
CHECK_MPI_OK( mp_init(&q) );
|
||||
CHECK_MPI_OK( mp_init(&y) );
|
||||
CHECK_MPI_OK( mp_init(&r) );
|
||||
SECITEM_TO_MPINT(*prime, &p);
|
||||
SECITEM_TO_MPINT(*subPrime, &q);
|
||||
SECITEM_TO_MPINT(*Y, &y);
|
||||
/* compute r = y**q mod p */
|
||||
CHECK_MPI_OK( mp_exptmod(&y, &q, &p, &r) );
|
||||
/* compare to 1 */
|
||||
cmp = mp_cmp_d(&r, 1);
|
||||
cleanup:
|
||||
mp_clear(&p);
|
||||
mp_clear(&q);
|
||||
mp_clear(&y);
|
||||
mp_clear(&r);
|
||||
if (err) {
|
||||
MP_TO_SEC_ERROR(err);
|
||||
return PR_FALSE;
|
||||
}
|
||||
return (cmp == 0) ? PR_TRUE : PR_FALSE;
|
||||
}
|
||||
@@ -1,82 +0,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 the Netscape security libraries.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1994-2000 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the
|
||||
* terms of the GNU General Public License Version 2 or later (the
|
||||
* "GPL"), in which case the provisions of the GPL are applicable
|
||||
* instead of those above. If you wish to allow use of your
|
||||
* version of this file only under the terms of the GPL and not to
|
||||
* allow others to use your version of this file under the MPL,
|
||||
* indicate your decision by deleting the provisions above and
|
||||
* replace them with the notice and other provisions required by
|
||||
* the GPL. If you do not delete the provisions above, a recipient
|
||||
* may use your version of this file under either the MPL or the
|
||||
* GPL.
|
||||
*/
|
||||
|
||||
#include "prerr.h"
|
||||
#include "secerr.h"
|
||||
|
||||
#include "blapi.h"
|
||||
|
||||
SECStatus
|
||||
DH_GenParam(int primeLen, DHParams ** params)
|
||||
{
|
||||
PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
SECStatus
|
||||
DH_NewKey(DHParams * params,
|
||||
DHPrivateKey ** privKey)
|
||||
{
|
||||
PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
SECStatus
|
||||
DH_Derive(SECItem * publicValue,
|
||||
SECItem * prime,
|
||||
SECItem * privateValue,
|
||||
SECItem * derivedSecret,
|
||||
unsigned int maxOutBytes)
|
||||
{
|
||||
PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
SECStatus
|
||||
KEA_Derive(SECItem *prime,
|
||||
SECItem *public1,
|
||||
SECItem *public2,
|
||||
SECItem *private1,
|
||||
SECItem *private2,
|
||||
SECItem *derivedSecret)
|
||||
{
|
||||
PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
PRBool
|
||||
KEA_Verify(SECItem *Y, SECItem *prime, SECItem *subPrime)
|
||||
{
|
||||
PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
|
||||
return PR_FALSE;
|
||||
}
|
||||
@@ -1,420 +0,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 the Netscape security libraries.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1994-2000 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the
|
||||
* terms of the GNU General Public License Version 2 or later (the
|
||||
* "GPL"), in which case the provisions of the GPL are applicable
|
||||
* instead of those above. If you wish to allow use of your
|
||||
* version of this file only under the terms of the GPL and not to
|
||||
* allow others to use your version of this file under the MPL,
|
||||
* indicate your decision by deleting the provisions above and
|
||||
* replace them with the notice and other provisions required by
|
||||
* the GPL. If you do not delete the provisions above, a recipient
|
||||
* may use your version of this file under either the MPL or the
|
||||
* GPL.
|
||||
*
|
||||
* $Id: dsa.c,v 1.11 2003-02-25 23:45:23 nelsonb%netscape.com Exp $
|
||||
*/
|
||||
|
||||
#include "secerr.h"
|
||||
|
||||
#include "prtypes.h"
|
||||
#include "prinit.h"
|
||||
#include "blapi.h"
|
||||
#include "nssilock.h"
|
||||
#include "secitem.h"
|
||||
#include "blapi.h"
|
||||
#include "mpi.h"
|
||||
|
||||
/* XXX to be replaced by define in blapit.h */
|
||||
#define NSS_FREEBL_DSA_DEFAULT_CHUNKSIZE 2048
|
||||
|
||||
#define CHECKOK(func) if (MP_OKAY > (err = func)) goto cleanup
|
||||
|
||||
#define SECITEM_TO_MPINT(it, mp) \
|
||||
CHECKOK(mp_read_unsigned_octets((mp), (it).data, (it).len))
|
||||
|
||||
/* DSA-specific random number functions defined in prng_fips1861.c. */
|
||||
extern SECStatus
|
||||
DSA_RandomUpdate(void *data, size_t bytes, unsigned char *q);
|
||||
|
||||
extern SECStatus
|
||||
DSA_GenerateGlobalRandomBytes(void *dest, size_t len, unsigned char *q);
|
||||
|
||||
static void translate_mpi_error(mp_err err)
|
||||
{
|
||||
switch (err) {
|
||||
case MP_MEM: PORT_SetError(SEC_ERROR_NO_MEMORY); break;
|
||||
case MP_RANGE: PORT_SetError(SEC_ERROR_BAD_DATA); break;
|
||||
case MP_BADARG: PORT_SetError(SEC_ERROR_INVALID_ARGS); break;
|
||||
default: PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); break;
|
||||
}
|
||||
}
|
||||
|
||||
SECStatus
|
||||
dsa_NewKey(const PQGParams *params, DSAPrivateKey **privKey,
|
||||
const unsigned char *xb)
|
||||
{
|
||||
unsigned int y_len;
|
||||
mp_int p, g;
|
||||
mp_int x, y;
|
||||
mp_err err;
|
||||
PRArenaPool *arena;
|
||||
DSAPrivateKey *key;
|
||||
/* Check args. */
|
||||
if (!params || !privKey) {
|
||||
PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
||||
return SECFailure;
|
||||
}
|
||||
/* Initialize an arena for the DSA key. */
|
||||
arena = PORT_NewArena(NSS_FREEBL_DSA_DEFAULT_CHUNKSIZE);
|
||||
if (!arena) {
|
||||
PORT_SetError(SEC_ERROR_NO_MEMORY);
|
||||
return SECFailure;
|
||||
}
|
||||
key = (DSAPrivateKey *)PORT_ArenaZAlloc(arena, sizeof(DSAPrivateKey));
|
||||
if (!key) {
|
||||
PORT_SetError(SEC_ERROR_NO_MEMORY);
|
||||
PORT_FreeArena(arena, PR_TRUE);
|
||||
return SECFailure;
|
||||
}
|
||||
key->params.arena = arena;
|
||||
/* Initialize MPI integers. */
|
||||
MP_DIGITS(&p) = 0;
|
||||
MP_DIGITS(&g) = 0;
|
||||
MP_DIGITS(&x) = 0;
|
||||
MP_DIGITS(&y) = 0;
|
||||
CHECKOK( mp_init(&p) );
|
||||
CHECKOK( mp_init(&g) );
|
||||
CHECKOK( mp_init(&x) );
|
||||
CHECKOK( mp_init(&y) );
|
||||
/* Copy over the PQG params */
|
||||
CHECKOK( SECITEM_CopyItem(arena, &key->params.prime, ¶ms->prime) );
|
||||
CHECKOK( SECITEM_CopyItem(arena, &key->params.subPrime, ¶ms->subPrime));
|
||||
CHECKOK( SECITEM_CopyItem(arena, &key->params.base, ¶ms->base) );
|
||||
/* Convert stored p, g, and received x into MPI integers. */
|
||||
SECITEM_TO_MPINT(params->prime, &p);
|
||||
SECITEM_TO_MPINT(params->base, &g);
|
||||
CHECKOK( mp_read_unsigned_octets(&x, xb, DSA_SUBPRIME_LEN) );
|
||||
/* Store x in private key */
|
||||
SECITEM_AllocItem(arena, &key->privateValue, DSA_SUBPRIME_LEN);
|
||||
memcpy(key->privateValue.data, xb, DSA_SUBPRIME_LEN);
|
||||
/* Compute public key y = g**x mod p */
|
||||
CHECKOK( mp_exptmod(&g, &x, &p, &y) );
|
||||
/* Store y in public key */
|
||||
y_len = mp_unsigned_octet_size(&y);
|
||||
SECITEM_AllocItem(arena, &key->publicValue, y_len);
|
||||
err = mp_to_unsigned_octets(&y, key->publicValue.data, y_len);
|
||||
/* mp_to_unsigned_octets returns bytes written (y_len) if okay */
|
||||
if (err < 0) goto cleanup; else err = MP_OKAY;
|
||||
*privKey = key;
|
||||
key = NULL;
|
||||
cleanup:
|
||||
mp_clear(&p);
|
||||
mp_clear(&g);
|
||||
mp_clear(&x);
|
||||
mp_clear(&y);
|
||||
if (key)
|
||||
PORT_FreeArena(key->params.arena, PR_TRUE);
|
||||
if (err) {
|
||||
translate_mpi_error(err);
|
||||
return SECFailure;
|
||||
}
|
||||
return SECSuccess;
|
||||
}
|
||||
|
||||
/*
|
||||
** Generate and return a new DSA public and private key pair,
|
||||
** both of which are encoded into a single DSAPrivateKey struct.
|
||||
** "params" is a pointer to the PQG parameters for the domain
|
||||
** Uses a random seed.
|
||||
*/
|
||||
SECStatus
|
||||
DSA_NewKey(const PQGParams *params, DSAPrivateKey **privKey)
|
||||
{
|
||||
SECStatus rv;
|
||||
unsigned char seed[DSA_SUBPRIME_LEN];
|
||||
/* Generate seed bytes for x according to FIPS 186-1 appendix 3 */
|
||||
if (DSA_GenerateGlobalRandomBytes(seed, DSA_SUBPRIME_LEN,
|
||||
params->subPrime.data))
|
||||
return SECFailure;
|
||||
/* Generate a new DSA key using random seed. */
|
||||
rv = dsa_NewKey(params, privKey, seed);
|
||||
return rv;
|
||||
}
|
||||
|
||||
/* For FIPS compliance testing. Seed must be exactly 20 bytes long */
|
||||
SECStatus
|
||||
DSA_NewKeyFromSeed(const PQGParams *params,
|
||||
const unsigned char *seed,
|
||||
DSAPrivateKey **privKey)
|
||||
{
|
||||
SECStatus rv;
|
||||
rv = dsa_NewKey(params, privKey, seed);
|
||||
return rv;
|
||||
}
|
||||
|
||||
static SECStatus
|
||||
dsa_SignDigest(DSAPrivateKey *key, SECItem *signature, const SECItem *digest,
|
||||
const unsigned char *kb)
|
||||
{
|
||||
mp_int p, q, g; /* PQG parameters */
|
||||
mp_int x, k; /* private key & pseudo-random integer */
|
||||
mp_int r, s; /* tuple (r, s) is signature) */
|
||||
mp_err err = MP_OKAY;
|
||||
SECStatus rv = SECSuccess;
|
||||
|
||||
/* FIPS-compliance dictates that digest is a SHA1 hash. */
|
||||
/* Check args. */
|
||||
if (!key || !signature || !digest ||
|
||||
(signature->len != DSA_SIGNATURE_LEN) ||
|
||||
(digest->len != SHA1_LENGTH)) {
|
||||
PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
||||
return SECFailure;
|
||||
}
|
||||
/* Initialize MPI integers. */
|
||||
MP_DIGITS(&p) = 0;
|
||||
MP_DIGITS(&q) = 0;
|
||||
MP_DIGITS(&g) = 0;
|
||||
MP_DIGITS(&x) = 0;
|
||||
MP_DIGITS(&k) = 0;
|
||||
MP_DIGITS(&r) = 0;
|
||||
MP_DIGITS(&s) = 0;
|
||||
CHECKOK( mp_init(&p) );
|
||||
CHECKOK( mp_init(&q) );
|
||||
CHECKOK( mp_init(&g) );
|
||||
CHECKOK( mp_init(&x) );
|
||||
CHECKOK( mp_init(&k) );
|
||||
CHECKOK( mp_init(&r) );
|
||||
CHECKOK( mp_init(&s) );
|
||||
/*
|
||||
** Convert stored PQG and private key into MPI integers.
|
||||
*/
|
||||
SECITEM_TO_MPINT(key->params.prime, &p);
|
||||
SECITEM_TO_MPINT(key->params.subPrime, &q);
|
||||
SECITEM_TO_MPINT(key->params.base, &g);
|
||||
SECITEM_TO_MPINT(key->privateValue, &x);
|
||||
CHECKOK( mp_read_unsigned_octets(&k, kb, DSA_SUBPRIME_LEN) );
|
||||
/*
|
||||
** FIPS 186-1, Section 5, Step 1
|
||||
**
|
||||
** r = (g**k mod p) mod q
|
||||
*/
|
||||
CHECKOK( mp_exptmod(&g, &k, &p, &r) ); /* r = g**k mod p */
|
||||
CHECKOK( mp_mod(&r, &q, &r) ); /* r = r mod q */
|
||||
/*
|
||||
** FIPS 186-1, Section 5, Step 2
|
||||
**
|
||||
** s = (k**-1 * (SHA1(M) + x*r)) mod q
|
||||
*/
|
||||
SECITEM_TO_MPINT(*digest, &s); /* s = SHA1(M) */
|
||||
CHECKOK( mp_invmod(&k, &q, &k) ); /* k = k**-1 mod q */
|
||||
CHECKOK( mp_mulmod(&x, &r, &q, &x) ); /* x = x * r mod q */
|
||||
CHECKOK( mp_addmod(&s, &x, &q, &s) ); /* s = s + x mod q */
|
||||
CHECKOK( mp_mulmod(&s, &k, &q, &s) ); /* s = s * k mod q */
|
||||
/*
|
||||
** verify r != 0 and s != 0
|
||||
** mentioned as optional in FIPS 186-1.
|
||||
*/
|
||||
if (mp_cmp_z(&r) == 0 || mp_cmp_z(&s) == 0) {
|
||||
PORT_SetError(SEC_ERROR_NEED_RANDOM);
|
||||
rv = SECFailure;
|
||||
goto cleanup;
|
||||
}
|
||||
/*
|
||||
** Step 4
|
||||
**
|
||||
** Signature is tuple (r, s)
|
||||
*/
|
||||
err = mp_to_fixlen_octets(&r, signature->data, DSA_SUBPRIME_LEN);
|
||||
if (err < 0) goto cleanup;
|
||||
err = mp_to_fixlen_octets(&s, signature->data + DSA_SUBPRIME_LEN,
|
||||
DSA_SUBPRIME_LEN);
|
||||
if (err < 0) goto cleanup;
|
||||
err = MP_OKAY;
|
||||
cleanup:
|
||||
mp_clear(&p);
|
||||
mp_clear(&q);
|
||||
mp_clear(&g);
|
||||
mp_clear(&x);
|
||||
mp_clear(&k);
|
||||
mp_clear(&r);
|
||||
mp_clear(&s);
|
||||
if (err) {
|
||||
translate_mpi_error(err);
|
||||
rv = SECFailure;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
/* signature is caller-supplied buffer of at least 20 bytes.
|
||||
** On input, signature->len == size of buffer to hold signature.
|
||||
** digest->len == size of digest.
|
||||
** On output, signature->len == size of signature in buffer.
|
||||
** Uses a random seed.
|
||||
*/
|
||||
SECStatus
|
||||
DSA_SignDigest(DSAPrivateKey *key, SECItem *signature, const SECItem *digest)
|
||||
{
|
||||
SECStatus rv;
|
||||
int retries = 10;
|
||||
unsigned char kSeed[DSA_SUBPRIME_LEN];
|
||||
|
||||
PORT_SetError(0);
|
||||
do {
|
||||
rv = DSA_GenerateGlobalRandomBytes(kSeed, DSA_SUBPRIME_LEN,
|
||||
key->params.subPrime.data);
|
||||
if (rv != SECSuccess)
|
||||
break;
|
||||
rv = dsa_SignDigest(key, signature, digest, kSeed);
|
||||
} while (rv != SECSuccess && PORT_GetError() == SEC_ERROR_NEED_RANDOM &&
|
||||
--retries > 0);
|
||||
return rv;
|
||||
}
|
||||
|
||||
/* For FIPS compliance testing. Seed must be exactly 20 bytes. */
|
||||
SECStatus
|
||||
DSA_SignDigestWithSeed(DSAPrivateKey * key,
|
||||
SECItem * signature,
|
||||
const SECItem * digest,
|
||||
const unsigned char * seed)
|
||||
{
|
||||
SECStatus rv;
|
||||
rv = dsa_SignDigest(key, signature, digest, seed);
|
||||
return rv;
|
||||
}
|
||||
|
||||
/* signature is caller-supplied buffer of at least 20 bytes.
|
||||
** On input, signature->len == size of buffer to hold signature.
|
||||
** digest->len == size of digest.
|
||||
*/
|
||||
SECStatus
|
||||
DSA_VerifyDigest(DSAPublicKey *key, const SECItem *signature,
|
||||
const SECItem *digest)
|
||||
{
|
||||
/* FIPS-compliance dictates that digest is a SHA1 hash. */
|
||||
mp_int p, q, g; /* PQG parameters */
|
||||
mp_int r_, s_; /* tuple (r', s') is received signature) */
|
||||
mp_int u1, u2, v, w; /* intermediate values used in verification */
|
||||
mp_int y; /* public key */
|
||||
mp_err err;
|
||||
SECStatus verified = SECFailure;
|
||||
|
||||
/* Check args. */
|
||||
if (!key || !signature || !digest ||
|
||||
(signature->len != DSA_SIGNATURE_LEN) ||
|
||||
(digest->len != SHA1_LENGTH)) {
|
||||
PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
||||
return SECFailure;
|
||||
}
|
||||
/* Initialize MPI integers. */
|
||||
MP_DIGITS(&p) = 0;
|
||||
MP_DIGITS(&q) = 0;
|
||||
MP_DIGITS(&g) = 0;
|
||||
MP_DIGITS(&y) = 0;
|
||||
MP_DIGITS(&r_) = 0;
|
||||
MP_DIGITS(&s_) = 0;
|
||||
MP_DIGITS(&u1) = 0;
|
||||
MP_DIGITS(&u2) = 0;
|
||||
MP_DIGITS(&v) = 0;
|
||||
MP_DIGITS(&w) = 0;
|
||||
CHECKOK( mp_init(&p) );
|
||||
CHECKOK( mp_init(&q) );
|
||||
CHECKOK( mp_init(&g) );
|
||||
CHECKOK( mp_init(&y) );
|
||||
CHECKOK( mp_init(&r_) );
|
||||
CHECKOK( mp_init(&s_) );
|
||||
CHECKOK( mp_init(&u1) );
|
||||
CHECKOK( mp_init(&u2) );
|
||||
CHECKOK( mp_init(&v) );
|
||||
CHECKOK( mp_init(&w) );
|
||||
/*
|
||||
** Convert stored PQG and public key into MPI integers.
|
||||
*/
|
||||
SECITEM_TO_MPINT(key->params.prime, &p);
|
||||
SECITEM_TO_MPINT(key->params.subPrime, &q);
|
||||
SECITEM_TO_MPINT(key->params.base, &g);
|
||||
SECITEM_TO_MPINT(key->publicValue, &y);
|
||||
/*
|
||||
** Convert received signature (r', s') into MPI integers.
|
||||
*/
|
||||
CHECKOK( mp_read_unsigned_octets(&r_, signature->data, DSA_SUBPRIME_LEN) );
|
||||
CHECKOK( mp_read_unsigned_octets(&s_, signature->data + DSA_SUBPRIME_LEN,
|
||||
DSA_SUBPRIME_LEN) );
|
||||
/*
|
||||
** Verify that 0 < r' < q and 0 < s' < q
|
||||
*/
|
||||
if (mp_cmp_z(&r_) <= 0 || mp_cmp_z(&s_) <= 0 ||
|
||||
mp_cmp(&r_, &q) >= 0 || mp_cmp(&s_, &q) >= 0)
|
||||
goto cleanup; /* will return verified == SECFailure */
|
||||
/*
|
||||
** FIPS 186-1, Section 6, Step 1
|
||||
**
|
||||
** w = (s')**-1 mod q
|
||||
*/
|
||||
CHECKOK( mp_invmod(&s_, &q, &w) ); /* w = (s')**-1 mod q */
|
||||
/*
|
||||
** FIPS 186-1, Section 6, Step 2
|
||||
**
|
||||
** u1 = ((SHA1(M')) * w) mod q
|
||||
*/
|
||||
SECITEM_TO_MPINT(*digest, &u1); /* u1 = SHA1(M') */
|
||||
CHECKOK( mp_mulmod(&u1, &w, &q, &u1) ); /* u1 = u1 * w mod q */
|
||||
/*
|
||||
** FIPS 186-1, Section 6, Step 3
|
||||
**
|
||||
** u2 = ((r') * w) mod q
|
||||
*/
|
||||
CHECKOK( mp_mulmod(&r_, &w, &q, &u2) );
|
||||
/*
|
||||
** FIPS 186-1, Section 6, Step 4
|
||||
**
|
||||
** v = ((g**u1 * y**u2) mod p) mod q
|
||||
*/
|
||||
CHECKOK( mp_exptmod(&g, &u1, &p, &g) ); /* g = g**u1 mod p */
|
||||
CHECKOK( mp_exptmod(&y, &u2, &p, &y) ); /* y = y**u2 mod p */
|
||||
CHECKOK( mp_mulmod(&g, &y, &p, &v) ); /* v = g * y mod p */
|
||||
CHECKOK( mp_mod(&v, &q, &v) ); /* v = v mod q */
|
||||
/*
|
||||
** Verification: v == r'
|
||||
*/
|
||||
if (mp_cmp(&v, &r_)) {
|
||||
PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
|
||||
verified = SECFailure; /* Signature failed to verify. */
|
||||
} else {
|
||||
verified = SECSuccess; /* Signature verified. */
|
||||
}
|
||||
cleanup:
|
||||
mp_clear(&p);
|
||||
mp_clear(&q);
|
||||
mp_clear(&g);
|
||||
mp_clear(&y);
|
||||
mp_clear(&r_);
|
||||
mp_clear(&s_);
|
||||
mp_clear(&u1);
|
||||
mp_clear(&u2);
|
||||
mp_clear(&v);
|
||||
mp_clear(&w);
|
||||
if (err) {
|
||||
translate_mpi_error(err);
|
||||
}
|
||||
return verified;
|
||||
}
|
||||
@@ -1,977 +0,0 @@
|
||||
/*
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF 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 Elliptic Curve Cryptography library.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Sun Microsystems, Inc.
|
||||
* Portions created by Sun Microsystems, Inc. are Copyright (C) 2003
|
||||
* Sun Microsystems, Inc. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Dr Vipul Gupta <vipul.gupta@sun.com>, Sun Microsystems Laboratories
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "blapi.h"
|
||||
#include "prerr.h"
|
||||
#include "secerr.h"
|
||||
#include "secmpi.h"
|
||||
#include "secitem.h"
|
||||
#include "ec.h"
|
||||
#include "GFp_ecl.h"
|
||||
#include "GF2m_ecl.h"
|
||||
|
||||
#ifdef NSS_ENABLE_ECC
|
||||
|
||||
/*
|
||||
* Returns true if pointP is the point at infinity, false otherwise
|
||||
*/
|
||||
PRBool
|
||||
ec_point_at_infinity(SECItem *pointP)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 1; i < pointP->len; i++) {
|
||||
if (pointP->data[i] != 0x00) return PR_FALSE;
|
||||
}
|
||||
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Computes point addition R = P + Q for the curve whose
|
||||
* parameters are encoded in params. Two or more of P, Q,
|
||||
* R may point to the same memory location.
|
||||
*/
|
||||
SECStatus
|
||||
ec_point_add(ECParams *params, SECItem *pointP,
|
||||
SECItem *pointQ, SECItem *pointR)
|
||||
{
|
||||
mp_int Px, Py, Qx, Qy, Rx, Ry;
|
||||
mp_int irreducible, a;
|
||||
SECStatus rv = SECFailure;
|
||||
mp_err err = MP_OKAY;
|
||||
int len;
|
||||
|
||||
#if EC_DEBUG
|
||||
int i;
|
||||
|
||||
printf("ec_point_add: params [len=%d]:", params->DEREncoding.len);
|
||||
for (i = 0; i < params->DEREncoding.len; i++)
|
||||
printf("%02x:", params->DEREncoding.data[i]);
|
||||
printf("\n");
|
||||
|
||||
printf("ec_point_add: pointP [len=%d]:", pointP->len);
|
||||
for (i = 0; i < pointP->len; i++)
|
||||
printf("%02x:", pointP->data[i]);
|
||||
printf("\n");
|
||||
|
||||
printf("ec_point_add: pointQ [len=%d]:", pointQ->len);
|
||||
for (i = 0; i < pointQ->len; i++)
|
||||
printf("%02x:", pointQ->data[i]);
|
||||
printf("\n");
|
||||
#endif
|
||||
|
||||
/* NOTE: We only support prime field curves for now */
|
||||
len = (params->fieldID.size + 7) >> 3;
|
||||
if ((pointP->data[0] != EC_POINT_FORM_UNCOMPRESSED) ||
|
||||
(pointP->len != (2 * len + 1)) ||
|
||||
(pointQ->data[0] != EC_POINT_FORM_UNCOMPRESSED) ||
|
||||
(pointQ->len != (2 * len + 1))) {
|
||||
PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
MP_DIGITS(&Px) = 0;
|
||||
MP_DIGITS(&Py) = 0;
|
||||
MP_DIGITS(&Qx) = 0;
|
||||
MP_DIGITS(&Qy) = 0;
|
||||
MP_DIGITS(&Rx) = 0;
|
||||
MP_DIGITS(&Ry) = 0;
|
||||
MP_DIGITS(&irreducible) = 0;
|
||||
MP_DIGITS(&a) = 0;
|
||||
CHECK_MPI_OK( mp_init(&Px) );
|
||||
CHECK_MPI_OK( mp_init(&Py) );
|
||||
CHECK_MPI_OK( mp_init(&Qx) );
|
||||
CHECK_MPI_OK( mp_init(&Qy) );
|
||||
CHECK_MPI_OK( mp_init(&Rx) );
|
||||
CHECK_MPI_OK( mp_init(&Ry) );
|
||||
CHECK_MPI_OK( mp_init(&irreducible) );
|
||||
CHECK_MPI_OK( mp_init(&a) );
|
||||
|
||||
/* Initialize Px and Py */
|
||||
CHECK_MPI_OK( mp_read_unsigned_octets(&Px, pointP->data + 1,
|
||||
(mp_size) len) );
|
||||
CHECK_MPI_OK( mp_read_unsigned_octets(&Py, pointP->data + 1 + len,
|
||||
(mp_size) len) );
|
||||
|
||||
/* Initialize Qx and Qy */
|
||||
CHECK_MPI_OK( mp_read_unsigned_octets(&Qx, pointQ->data + 1,
|
||||
(mp_size) len) );
|
||||
CHECK_MPI_OK( mp_read_unsigned_octets(&Qy, pointQ->data + 1 + len,
|
||||
(mp_size) len) );
|
||||
|
||||
/* Set up the curve coefficient */
|
||||
SECITEM_TO_MPINT( params->curve.a, &a );
|
||||
|
||||
/* Compute R = P + Q */
|
||||
if (params->fieldID.type == ec_field_GFp) {
|
||||
SECITEM_TO_MPINT( params->fieldID.u.prime, &irreducible );
|
||||
if (GFp_ec_pt_add(&irreducible, &a, &Px, &Py, &Qx, &Qy,
|
||||
&Rx, &Ry) != SECSuccess)
|
||||
goto cleanup;
|
||||
} else {
|
||||
SECITEM_TO_MPINT( params->fieldID.u.poly, &irreducible );
|
||||
if (GF2m_ec_pt_add(&irreducible, &a, &Px, &Py, &Qx, &Qy, &Rx, &Ry)
|
||||
!= SECSuccess)
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Construct the SECItem representation of the result */
|
||||
pointR->data[0] = EC_POINT_FORM_UNCOMPRESSED;
|
||||
CHECK_MPI_OK( mp_to_fixlen_octets(&Rx, pointR->data + 1,
|
||||
(mp_size) len) );
|
||||
CHECK_MPI_OK( mp_to_fixlen_octets(&Ry, pointR->data + 1 + len,
|
||||
(mp_size) len) );
|
||||
rv = SECSuccess;
|
||||
|
||||
#if EC_DEBUG
|
||||
printf("ec_point_add: pointR [len=%d]:", pointR->len);
|
||||
for (i = 0; i < pointR->len; i++)
|
||||
printf("%02x:", pointR->data[i]);
|
||||
printf("\n");
|
||||
#endif
|
||||
|
||||
cleanup:
|
||||
mp_clear(&Px);
|
||||
mp_clear(&Py);
|
||||
mp_clear(&Qx);
|
||||
mp_clear(&Qy);
|
||||
mp_clear(&Rx);
|
||||
mp_clear(&Ry);
|
||||
mp_clear(&irreducible);
|
||||
mp_clear(&a);
|
||||
if (err) {
|
||||
MP_TO_SEC_ERROR(err);
|
||||
rv = SECFailure;
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
/*
|
||||
* Computes scalar point multiplication pointQ = k * pointP for
|
||||
* the curve whose parameters are encoded in params.
|
||||
*/
|
||||
SECStatus
|
||||
ec_point_mul(ECParams *params, mp_int *k,
|
||||
SECItem *pointP, SECItem *pointQ)
|
||||
{
|
||||
mp_int Px, Py, Qx, Qy;
|
||||
mp_int irreducible, a, b;
|
||||
SECStatus rv = SECFailure;
|
||||
mp_err err = MP_OKAY;
|
||||
int len;
|
||||
|
||||
#if EC_DEBUG
|
||||
int i;
|
||||
char mpstr[256];
|
||||
|
||||
printf("ec_point_mul: params [len=%d]:", params->DEREncoding.len);
|
||||
for (i = 0; i < params->DEREncoding.len; i++)
|
||||
printf("%02x:", params->DEREncoding.data[i]);
|
||||
printf("\n");
|
||||
|
||||
mp_tohex(k, mpstr);
|
||||
printf("ec_point_mul: scalar : %s\n", mpstr);
|
||||
mp_todecimal(k, mpstr);
|
||||
printf("ec_point_mul: scalar : %s (dec)\n", mpstr);
|
||||
|
||||
printf("ec_point_mul: pointP [len=%d]:", pointP->len);
|
||||
for (i = 0; i < pointP->len; i++)
|
||||
printf("%02x:", pointP->data[i]);
|
||||
printf("\n");
|
||||
#endif
|
||||
|
||||
/* NOTE: We only support prime field curves for now */
|
||||
len = (params->fieldID.size + 7) >> 3;
|
||||
if ((pointP->data[0] != EC_POINT_FORM_UNCOMPRESSED) ||
|
||||
(pointP->len != (2 * len + 1))) {
|
||||
return SECFailure;
|
||||
};
|
||||
|
||||
MP_DIGITS(&Px) = 0;
|
||||
MP_DIGITS(&Py) = 0;
|
||||
MP_DIGITS(&Qx) = 0;
|
||||
MP_DIGITS(&Qy) = 0;
|
||||
MP_DIGITS(&irreducible) = 0;
|
||||
MP_DIGITS(&a) = 0;
|
||||
MP_DIGITS(&b) = 0;
|
||||
CHECK_MPI_OK( mp_init(&Px) );
|
||||
CHECK_MPI_OK( mp_init(&Py) );
|
||||
CHECK_MPI_OK( mp_init(&Qx) );
|
||||
CHECK_MPI_OK( mp_init(&Qy) );
|
||||
CHECK_MPI_OK( mp_init(&irreducible) );
|
||||
CHECK_MPI_OK( mp_init(&a) );
|
||||
CHECK_MPI_OK( mp_init(&b) );
|
||||
|
||||
/* Initialize Px and Py */
|
||||
CHECK_MPI_OK( mp_read_unsigned_octets(&Px, pointP->data + 1,
|
||||
(mp_size) len) );
|
||||
CHECK_MPI_OK( mp_read_unsigned_octets(&Py, pointP->data + 1 + len,
|
||||
(mp_size) len) );
|
||||
|
||||
/* Set up mp_ints containing the curve coefficients */
|
||||
SECITEM_TO_MPINT( params->curve.a, &a );
|
||||
SECITEM_TO_MPINT( params->curve.b, &b );
|
||||
|
||||
/* Compute Q = k * P */
|
||||
if (params->fieldID.type == ec_field_GFp) {
|
||||
SECITEM_TO_MPINT( params->fieldID.u.prime, &irreducible );
|
||||
if (GFp_ec_pt_mul(&irreducible, &a, &b, &Px, &Py, k, &Qx, &Qy)
|
||||
!= SECSuccess)
|
||||
goto cleanup;
|
||||
} else {
|
||||
SECITEM_TO_MPINT( params->fieldID.u.poly, &irreducible );
|
||||
if (GF2m_ec_pt_mul(&irreducible, &a, &b, &Px, &Py, k, &Qx, &Qy)
|
||||
!= SECSuccess) {
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
/* Construct the SECItem representation of point Q */
|
||||
pointQ->data[0] = EC_POINT_FORM_UNCOMPRESSED;
|
||||
CHECK_MPI_OK( mp_to_fixlen_octets(&Qx, pointQ->data + 1,
|
||||
(mp_size) len) );
|
||||
CHECK_MPI_OK( mp_to_fixlen_octets(&Qy, pointQ->data + 1 + len,
|
||||
(mp_size) len) );
|
||||
|
||||
rv = SECSuccess;
|
||||
|
||||
#if EC_DEBUG
|
||||
printf("ec_point_mul: pointQ [len=%d]:", pointQ->len);
|
||||
for (i = 0; i < pointQ->len; i++)
|
||||
printf("%02x:", pointQ->data[i]);
|
||||
printf("\n");
|
||||
#endif
|
||||
|
||||
cleanup:
|
||||
mp_clear(&Px);
|
||||
mp_clear(&Py);
|
||||
mp_clear(&Qx);
|
||||
mp_clear(&Qy);
|
||||
mp_clear(&irreducible);
|
||||
mp_clear(&a);
|
||||
mp_clear(&b);
|
||||
if (err) {
|
||||
MP_TO_SEC_ERROR(err);
|
||||
rv = SECFailure;
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
static unsigned char bitmask[] = {
|
||||
0xff, 0x7f, 0x3f, 0x1f,
|
||||
0x0f, 0x07, 0x03, 0x01
|
||||
};
|
||||
#endif /* NSS_ENABLE_ECC */
|
||||
|
||||
/* Generates a new EC key pair. The private key is a supplied
|
||||
* random value (in seed) and the public key is the result of
|
||||
* performing a scalar point multiplication of that value with
|
||||
* the curve's base point.
|
||||
*/
|
||||
SECStatus
|
||||
EC_NewKeyFromSeed(ECParams *ecParams, ECPrivateKey **privKey,
|
||||
const unsigned char *seed, int seedlen)
|
||||
{
|
||||
SECStatus rv = SECFailure;
|
||||
#ifdef NSS_ENABLE_ECC
|
||||
PRArenaPool *arena;
|
||||
ECPrivateKey *key;
|
||||
mp_int k;
|
||||
mp_err err = MP_OKAY;
|
||||
int len;
|
||||
|
||||
#if EC_DEBUG
|
||||
printf("EC_NewKeyFromSeed called\n");
|
||||
#endif
|
||||
|
||||
if (!ecParams || !privKey || !seed || (seedlen < 0)) {
|
||||
PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
/* Initialize an arena for the EC key. */
|
||||
if (!(arena = PORT_NewArena(NSS_FREEBL_DEFAULT_CHUNKSIZE)))
|
||||
return SECFailure;
|
||||
|
||||
key = (ECPrivateKey *)PORT_ArenaZAlloc(arena, sizeof(ECPrivateKey));
|
||||
if (!key) {
|
||||
PORT_FreeArena(arena, PR_TRUE);
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
|
||||
/* Copy all of the fields from the ECParams argument to the
|
||||
* ECParams structure within the private key.
|
||||
*/
|
||||
key->ecParams.arena = arena;
|
||||
key->ecParams.type = ecParams->type;
|
||||
key->ecParams.fieldID.size = ecParams->fieldID.size;
|
||||
key->ecParams.fieldID.type = ecParams->fieldID.type;
|
||||
if (ecParams->fieldID.type == ec_field_GFp) {
|
||||
CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.fieldID.u.prime,
|
||||
&ecParams->fieldID.u.prime));
|
||||
} else {
|
||||
CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.fieldID.u.poly,
|
||||
&ecParams->fieldID.u.poly));
|
||||
}
|
||||
key->ecParams.fieldID.k1 = ecParams->fieldID.k1;
|
||||
key->ecParams.fieldID.k2 = ecParams->fieldID.k2;
|
||||
key->ecParams.fieldID.k3 = ecParams->fieldID.k3;
|
||||
CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.curve.a,
|
||||
&ecParams->curve.a));
|
||||
CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.curve.b,
|
||||
&ecParams->curve.b));
|
||||
CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.curve.seed,
|
||||
&ecParams->curve.seed));
|
||||
CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.base,
|
||||
&ecParams->base));
|
||||
CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.order,
|
||||
&ecParams->order));
|
||||
key->ecParams.cofactor = ecParams->cofactor;
|
||||
CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.DEREncoding,
|
||||
&ecParams->DEREncoding));
|
||||
|
||||
len = (ecParams->fieldID.size + 7) >> 3;
|
||||
SECITEM_AllocItem(arena, &key->privateValue, len);
|
||||
SECITEM_AllocItem(arena, &key->publicValue, 2*len + 1);
|
||||
|
||||
/* Copy private key */
|
||||
if (seedlen >= len) {
|
||||
memcpy(key->privateValue.data, seed, len);
|
||||
} else {
|
||||
memset(key->privateValue.data, 0, (len - seedlen));
|
||||
memcpy(key->privateValue.data + (len - seedlen), seed, seedlen);
|
||||
}
|
||||
|
||||
/* Compute corresponding public key */
|
||||
MP_DIGITS(&k) = 0;
|
||||
CHECK_MPI_OK( mp_init(&k) );
|
||||
CHECK_MPI_OK( mp_read_unsigned_octets(&k, key->privateValue.data,
|
||||
(mp_size) len) );
|
||||
|
||||
rv = ec_point_mul(ecParams, &k, &(ecParams->base), &(key->publicValue));
|
||||
if (rv != SECSuccess) goto cleanup;
|
||||
*privKey = key;
|
||||
|
||||
cleanup:
|
||||
mp_clear(&k);
|
||||
if (rv)
|
||||
PORT_FreeArena(arena, PR_TRUE);
|
||||
|
||||
#if EC_DEBUG
|
||||
printf("EC_NewKeyFromSeed returning %s\n",
|
||||
(rv == SECSuccess) ? "success" : "failure");
|
||||
#endif
|
||||
#else
|
||||
PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG);
|
||||
#endif /* NSS_ENABLE_ECC */
|
||||
|
||||
return rv;
|
||||
|
||||
}
|
||||
|
||||
/* Generates a new EC key pair. The private key is a random value and
|
||||
* the public key is the result of performing a scalar point multiplication
|
||||
* of that value with the curve's base point.
|
||||
*/
|
||||
SECStatus
|
||||
EC_NewKey(ECParams *ecParams, ECPrivateKey **privKey)
|
||||
{
|
||||
SECStatus rv = SECFailure;
|
||||
#ifdef NSS_ENABLE_ECC
|
||||
int len;
|
||||
unsigned char *seed;
|
||||
|
||||
if (!ecParams || !privKey) {
|
||||
PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
/* Generate random private key */
|
||||
len = (ecParams->fieldID.size + 7) >> 3;
|
||||
if ((seed = PORT_Alloc(len)) == NULL) goto cleanup;
|
||||
if (RNG_GenerateGlobalRandomBytes(seed, len) != SECSuccess) goto cleanup;
|
||||
|
||||
/* Fit private key to the field size */
|
||||
seed[0] &= bitmask[len * 8 - ecParams->fieldID.size];
|
||||
rv = EC_NewKeyFromSeed(ecParams, privKey, seed, len);
|
||||
|
||||
cleanup:
|
||||
if (!seed) {
|
||||
PORT_ZFree(seed, len);
|
||||
}
|
||||
#if EC_DEBUG
|
||||
printf("EC_NewKey returning %s\n",
|
||||
(rv == SECSuccess) ? "success" : "failure");
|
||||
#endif
|
||||
#else
|
||||
PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG);
|
||||
#endif /* NSS_ENABLE_ECC */
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
/* Validates an EC public key as described in Section 5.2.2 of
|
||||
* X9.63. The ECDH primitive when used without the cofactor does
|
||||
* not address small subgroup attacks, which may occur when the
|
||||
* public key is not valid. These attacks can be prevented by
|
||||
* validating the public key before using ECDH.
|
||||
*/
|
||||
SECStatus
|
||||
EC_ValidatePublicKey(ECParams *ecParams, SECItem *publicValue)
|
||||
{
|
||||
#ifdef NSS_ENABLE_ECC
|
||||
if (!ecParams || !publicValue) {
|
||||
PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
/* XXX Add actual checks here. */
|
||||
return SECSuccess;
|
||||
#else
|
||||
PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG);
|
||||
return SECFailure;
|
||||
#endif /* NSS_ENABLE_ECC */
|
||||
}
|
||||
|
||||
/*
|
||||
** Performs an ECDH key derivation by computing the scalar point
|
||||
** multiplication of privateValue and publicValue (with or without the
|
||||
** cofactor) and returns the x-coordinate of the resulting elliptic
|
||||
** curve point in derived secret. If successful, derivedSecret->data
|
||||
** is set to the address of the newly allocated buffer containing the
|
||||
** derived secret, and derivedSecret->len is the size of the secret
|
||||
** produced. It is the caller's responsibility to free the allocated
|
||||
** buffer containing the derived secret.
|
||||
*/
|
||||
SECStatus
|
||||
ECDH_Derive(SECItem *publicValue,
|
||||
ECParams *ecParams,
|
||||
SECItem *privateValue,
|
||||
PRBool withCofactor,
|
||||
SECItem *derivedSecret)
|
||||
{
|
||||
SECStatus rv = SECFailure;
|
||||
#ifdef NSS_ENABLE_ECC
|
||||
unsigned int len = 0;
|
||||
SECItem pointQ = {siBuffer, NULL, 0};
|
||||
mp_int k; /* to hold the private value */
|
||||
mp_int cofactor;
|
||||
mp_err err = MP_OKAY;
|
||||
#if EC_DEBUG
|
||||
int i;
|
||||
#endif
|
||||
|
||||
if (!publicValue || !ecParams || !privateValue ||
|
||||
!derivedSecret) {
|
||||
PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
memset(derivedSecret, 0, sizeof *derivedSecret);
|
||||
len = (ecParams->fieldID.size + 7) >> 3;
|
||||
pointQ.len = 2*len + 1;
|
||||
if ((pointQ.data = PORT_Alloc(2*len + 1)) == NULL) goto cleanup;
|
||||
|
||||
MP_DIGITS(&k) = 0;
|
||||
CHECK_MPI_OK( mp_init(&k) );
|
||||
CHECK_MPI_OK( mp_read_unsigned_octets(&k, privateValue->data,
|
||||
(mp_size) privateValue->len) );
|
||||
|
||||
if (withCofactor && (ecParams->cofactor != 1)) {
|
||||
/* multiply k with the cofactor */
|
||||
MP_DIGITS(&cofactor) = 0;
|
||||
CHECK_MPI_OK( mp_init(&cofactor) );
|
||||
mp_set(&cofactor, ecParams->cofactor);
|
||||
CHECK_MPI_OK( mp_mul(&k, &cofactor, &k) );
|
||||
}
|
||||
|
||||
/* Multiply our private key and peer's public point */
|
||||
if ((ec_point_mul(ecParams, &k, publicValue, &pointQ) != SECSuccess) ||
|
||||
ec_point_at_infinity(&pointQ))
|
||||
goto cleanup;
|
||||
|
||||
/* Allocate memory for the derived secret and copy
|
||||
* the x co-ordinate of pointQ into it.
|
||||
*/
|
||||
SECITEM_AllocItem(NULL, derivedSecret, len);
|
||||
memcpy(derivedSecret->data, pointQ.data + 1, len);
|
||||
|
||||
rv = SECSuccess;
|
||||
|
||||
#if EC_DEBUG
|
||||
printf("derived_secret:\n");
|
||||
for (i = 0; i < derivedSecret->len; i++)
|
||||
printf("%02x:", derivedSecret->data[i]);
|
||||
printf("\n");
|
||||
#endif
|
||||
|
||||
cleanup:
|
||||
mp_clear(&k);
|
||||
|
||||
if (pointQ.data) {
|
||||
PORT_ZFree(pointQ.data, 2*len + 1);
|
||||
}
|
||||
#else
|
||||
PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG);
|
||||
#endif /* NSS_ENABLE_ECC */
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
/* Computes the ECDSA signature (a concatenation of two values r and s)
|
||||
* on the digest using the given key and the random value kb (used in
|
||||
* computing s).
|
||||
*/
|
||||
SECStatus
|
||||
ECDSA_SignDigestWithSeed(ECPrivateKey *key, SECItem *signature,
|
||||
const SECItem *digest, const unsigned char *kb, const int kblen)
|
||||
{
|
||||
SECStatus rv = SECFailure;
|
||||
#ifdef NSS_ENABLE_ECC
|
||||
mp_int x1;
|
||||
mp_int d, k; /* private key, random integer */
|
||||
mp_int r, s; /* tuple (r, s) is the signature */
|
||||
mp_int n;
|
||||
mp_err err = MP_OKAY;
|
||||
ECParams *ecParams = NULL;
|
||||
SECItem kGpoint = { siBuffer, NULL, 0};
|
||||
int len = 0;
|
||||
|
||||
#if EC_DEBUG
|
||||
char mpstr[256];
|
||||
#endif
|
||||
|
||||
/* Check args */
|
||||
if (!key || !signature || !digest || !kb || (kblen < 0) ||
|
||||
(digest->len != SHA1_LENGTH)) {
|
||||
PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
ecParams = &(key->ecParams);
|
||||
len = (ecParams->fieldID.size + 7) >> 3;
|
||||
if (signature->len < 2*len) {
|
||||
PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Initialize MPI integers. */
|
||||
MP_DIGITS(&x1) = 0;
|
||||
MP_DIGITS(&d) = 0;
|
||||
MP_DIGITS(&k) = 0;
|
||||
MP_DIGITS(&r) = 0;
|
||||
MP_DIGITS(&s) = 0;
|
||||
MP_DIGITS(&n) = 0;
|
||||
CHECK_MPI_OK( mp_init(&x1) );
|
||||
CHECK_MPI_OK( mp_init(&d) );
|
||||
CHECK_MPI_OK( mp_init(&k) );
|
||||
CHECK_MPI_OK( mp_init(&r) );
|
||||
CHECK_MPI_OK( mp_init(&s) );
|
||||
CHECK_MPI_OK( mp_init(&n) );
|
||||
|
||||
SECITEM_TO_MPINT( ecParams->order, &n );
|
||||
SECITEM_TO_MPINT( key->privateValue, &d );
|
||||
CHECK_MPI_OK( mp_read_unsigned_octets(&k, kb, kblen) );
|
||||
/* Make sure k is in the interval [1, n-1] */
|
||||
if ((mp_cmp_z(&k) <= 0) || (mp_cmp(&k, &n) >= 0)) {
|
||||
PORT_SetError(SEC_ERROR_NEED_RANDOM);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/*
|
||||
** ANSI X9.62, Section 5.3.2, Step 2
|
||||
**
|
||||
** Compute kG
|
||||
*/
|
||||
kGpoint.len = 2*len + 1;
|
||||
kGpoint.data = PORT_Alloc(2*len + 1);
|
||||
if ((kGpoint.data == NULL) ||
|
||||
(ec_point_mul(ecParams, &k, &(ecParams->base), &kGpoint)
|
||||
!= SECSuccess))
|
||||
goto cleanup;
|
||||
|
||||
/*
|
||||
** ANSI X9.62, Section 5.3.3, Step 1
|
||||
**
|
||||
** Extract the x co-ordinate of kG into x1
|
||||
*/
|
||||
CHECK_MPI_OK( mp_read_unsigned_octets(&x1, kGpoint.data + 1,
|
||||
(mp_size) len) );
|
||||
|
||||
/*
|
||||
** ANSI X9.62, Section 5.3.3, Step 2
|
||||
**
|
||||
** r = x1 mod n NOTE: n is the order of the curve
|
||||
*/
|
||||
CHECK_MPI_OK( mp_mod(&x1, &n, &r) );
|
||||
|
||||
/*
|
||||
** ANSI X9.62, Section 5.3.3, Step 3
|
||||
**
|
||||
** verify r != 0
|
||||
*/
|
||||
if (mp_cmp_z(&r) == 0) {
|
||||
PORT_SetError(SEC_ERROR_NEED_RANDOM);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/*
|
||||
** ANSI X9.62, Section 5.3.3, Step 4
|
||||
**
|
||||
** s = (k**-1 * (SHA1(M) + d*r)) mod n
|
||||
*/
|
||||
SECITEM_TO_MPINT(*digest, &s); /* s = SHA1(M) */
|
||||
|
||||
#if EC_DEBUG
|
||||
mp_todecimal(&n, mpstr);
|
||||
printf("n : %s (dec)\n", mpstr);
|
||||
mp_todecimal(&d, mpstr);
|
||||
printf("d : %s (dec)\n", mpstr);
|
||||
mp_tohex(&x1, mpstr);
|
||||
printf("x1: %s\n", mpstr);
|
||||
mp_todecimal(&s, mpstr);
|
||||
printf("digest: %s (decimal)\n", mpstr);
|
||||
mp_todecimal(&r, mpstr);
|
||||
printf("r : %s (dec)\n", mpstr);
|
||||
#endif
|
||||
|
||||
CHECK_MPI_OK( mp_invmod(&k, &n, &k) ); /* k = k**-1 mod n */
|
||||
CHECK_MPI_OK( mp_mulmod(&d, &r, &n, &d) ); /* d = d * r mod n */
|
||||
CHECK_MPI_OK( mp_addmod(&s, &d, &n, &s) ); /* s = s + d mod n */
|
||||
CHECK_MPI_OK( mp_mulmod(&s, &k, &n, &s) ); /* s = s * k mod n */
|
||||
|
||||
#if EC_DEBUG
|
||||
mp_todecimal(&s, mpstr);
|
||||
printf("s : %s (dec)\n", mpstr);
|
||||
#endif
|
||||
|
||||
/*
|
||||
** ANSI X9.62, Section 5.3.3, Step 5
|
||||
**
|
||||
** verify s != 0
|
||||
*/
|
||||
if (mp_cmp_z(&s) == 0) {
|
||||
PORT_SetError(SEC_ERROR_NEED_RANDOM);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/*
|
||||
**
|
||||
** Signature is tuple (r, s)
|
||||
*/
|
||||
CHECK_MPI_OK( mp_to_fixlen_octets(&r, signature->data, len) );
|
||||
CHECK_MPI_OK( mp_to_fixlen_octets(&s, signature->data + len, len) );
|
||||
signature->len = 2*len;
|
||||
|
||||
rv = SECSuccess;
|
||||
err = MP_OKAY;
|
||||
cleanup:
|
||||
mp_clear(&x1);
|
||||
mp_clear(&d);
|
||||
mp_clear(&k);
|
||||
mp_clear(&r);
|
||||
mp_clear(&s);
|
||||
mp_clear(&n);
|
||||
|
||||
if (kGpoint.data) {
|
||||
PORT_ZFree(kGpoint.data, 2*len + 1);
|
||||
}
|
||||
|
||||
if (err) {
|
||||
MP_TO_SEC_ERROR(err);
|
||||
rv = SECFailure;
|
||||
}
|
||||
|
||||
#if EC_DEBUG
|
||||
printf("ECDSA signing with seed %s\n",
|
||||
(rv == SECSuccess) ? "succeeded" : "failed");
|
||||
#endif
|
||||
#else
|
||||
PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG);
|
||||
#endif /* NSS_ENABLE_ECC */
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
/*
|
||||
** Computes the ECDSA signature on the digest using the given key
|
||||
** and a random seed.
|
||||
*/
|
||||
SECStatus
|
||||
ECDSA_SignDigest(ECPrivateKey *key, SECItem *signature, const SECItem *digest)
|
||||
{
|
||||
SECStatus rv = SECFailure;
|
||||
#ifdef NSS_ENABLE_ECC
|
||||
int prerr = 0;
|
||||
int n = (key->ecParams.fieldID.size + 7) >> 3;
|
||||
unsigned char mask = bitmask[n * 8 - key->ecParams.fieldID.size];
|
||||
unsigned char *kseed = NULL;
|
||||
|
||||
/* Generate random seed of appropriate size as dictated
|
||||
* by field size.
|
||||
*/
|
||||
if ((kseed = PORT_Alloc(n)) == NULL) return SECFailure;
|
||||
|
||||
do {
|
||||
if (RNG_GenerateGlobalRandomBytes(kseed, n) != SECSuccess)
|
||||
goto cleanup;
|
||||
*kseed &= mask;
|
||||
rv = ECDSA_SignDigestWithSeed(key, signature, digest, kseed, n);
|
||||
if (rv) prerr = PORT_GetError();
|
||||
} while ((rv != SECSuccess) && (prerr == SEC_ERROR_NEED_RANDOM));
|
||||
|
||||
cleanup:
|
||||
if (kseed) PORT_ZFree(kseed, n);
|
||||
|
||||
#if EC_DEBUG
|
||||
printf("ECDSA signing %s\n",
|
||||
(rv == SECSuccess) ? "succeeded" : "failed");
|
||||
#endif
|
||||
#else
|
||||
PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG);
|
||||
#endif /* NSS_ENABLE_ECC */
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
/*
|
||||
** Checks the signature on the given digest using the key provided.
|
||||
*/
|
||||
SECStatus
|
||||
ECDSA_VerifyDigest(ECPublicKey *key, const SECItem *signature,
|
||||
const SECItem *digest)
|
||||
{
|
||||
SECStatus rv = SECFailure;
|
||||
#ifdef NSS_ENABLE_ECC
|
||||
mp_int r_, s_; /* tuple (r', s') is received signature) */
|
||||
mp_int c, u1, u2, v; /* intermediate values used in verification */
|
||||
mp_int x1, y1;
|
||||
mp_int x2, y2;
|
||||
mp_int n;
|
||||
mp_err err = MP_OKAY;
|
||||
PRArenaPool *arena = NULL;
|
||||
ECParams *ecParams = NULL;
|
||||
SECItem pointA = { siBuffer, NULL, 0 };
|
||||
SECItem pointB = { siBuffer, NULL, 0 };
|
||||
SECItem pointC = { siBuffer, NULL, 0 };
|
||||
int len;
|
||||
|
||||
#if EC_DEBUG
|
||||
char mpstr[256];
|
||||
printf("ECDSA verification called\n");
|
||||
#endif
|
||||
|
||||
/* Check args */
|
||||
if (!key || !signature || !digest ||
|
||||
(digest->len != SHA1_LENGTH)) {
|
||||
PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
ecParams = &(key->ecParams);
|
||||
len = (ecParams->fieldID.size + 7) >> 3;
|
||||
if (signature->len < 2*len) {
|
||||
PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Initialize an arena for pointA, pointB and pointC */
|
||||
if ((arena = PORT_NewArena(NSS_FREEBL_DEFAULT_CHUNKSIZE)) == NULL)
|
||||
goto cleanup;
|
||||
|
||||
SECITEM_AllocItem(arena, &pointA, 2*len + 1);
|
||||
SECITEM_AllocItem(arena, &pointB, 2*len + 1);
|
||||
SECITEM_AllocItem(arena, &pointC, 2*len + 1);
|
||||
if (pointA.data == NULL || pointB.data == NULL || pointC.data == NULL)
|
||||
goto cleanup;
|
||||
|
||||
/* Initialize MPI integers. */
|
||||
MP_DIGITS(&r_) = 0;
|
||||
MP_DIGITS(&s_) = 0;
|
||||
MP_DIGITS(&c) = 0;
|
||||
MP_DIGITS(&u1) = 0;
|
||||
MP_DIGITS(&u2) = 0;
|
||||
MP_DIGITS(&x1) = 0;
|
||||
MP_DIGITS(&y1) = 0;
|
||||
MP_DIGITS(&x2) = 0;
|
||||
MP_DIGITS(&y2) = 0;
|
||||
MP_DIGITS(&v) = 0;
|
||||
MP_DIGITS(&n) = 0;
|
||||
CHECK_MPI_OK( mp_init(&r_) );
|
||||
CHECK_MPI_OK( mp_init(&s_) );
|
||||
CHECK_MPI_OK( mp_init(&c) );
|
||||
CHECK_MPI_OK( mp_init(&u1) );
|
||||
CHECK_MPI_OK( mp_init(&u2) );
|
||||
CHECK_MPI_OK( mp_init(&x1) );
|
||||
CHECK_MPI_OK( mp_init(&y1) );
|
||||
CHECK_MPI_OK( mp_init(&x2) );
|
||||
CHECK_MPI_OK( mp_init(&y2) );
|
||||
CHECK_MPI_OK( mp_init(&v) );
|
||||
CHECK_MPI_OK( mp_init(&n) );
|
||||
|
||||
/*
|
||||
** Convert received signature (r', s') into MPI integers.
|
||||
*/
|
||||
CHECK_MPI_OK( mp_read_unsigned_octets(&r_, signature->data, len) );
|
||||
CHECK_MPI_OK( mp_read_unsigned_octets(&s_, signature->data + len, len) );
|
||||
|
||||
/*
|
||||
** ANSI X9.62, Section 5.4.2, Steps 1 and 2
|
||||
**
|
||||
** Verify that 0 < r' < n and 0 < s' < n
|
||||
*/
|
||||
SECITEM_TO_MPINT(ecParams->order, &n);
|
||||
if (mp_cmp_z(&r_) <= 0 || mp_cmp_z(&s_) <= 0 ||
|
||||
mp_cmp(&r_, &n) >= 0 || mp_cmp(&s_, &n) >= 0)
|
||||
goto cleanup; /* will return rv == SECFailure */
|
||||
|
||||
/*
|
||||
** ANSI X9.62, Section 5.4.2, Step 3
|
||||
**
|
||||
** c = (s')**-1 mod n
|
||||
*/
|
||||
CHECK_MPI_OK( mp_invmod(&s_, &n, &c) ); /* c = (s')**-1 mod n */
|
||||
|
||||
/*
|
||||
** ANSI X9.62, Section 5.4.2, Step 4
|
||||
**
|
||||
** u1 = ((SHA1(M')) * c) mod n
|
||||
*/
|
||||
SECITEM_TO_MPINT(*digest, &u1); /* u1 = SHA1(M') */
|
||||
|
||||
#if EC_DEBUG
|
||||
mp_todecimal(&r_, mpstr);
|
||||
printf("r_: %s (dec)\n", mpstr);
|
||||
mp_todecimal(&s_, mpstr);
|
||||
printf("s_: %s (dec)\n", mpstr);
|
||||
mp_todecimal(&c, mpstr);
|
||||
printf("c : %s (dec)\n", mpstr);
|
||||
mp_todecimal(&u1, mpstr);
|
||||
printf("digest: %s (dec)\n", mpstr);
|
||||
#endif
|
||||
|
||||
CHECK_MPI_OK( mp_mulmod(&u1, &c, &n, &u1) ); /* u1 = u1 * c mod n */
|
||||
|
||||
/*
|
||||
** ANSI X9.62, Section 5.4.2, Step 4
|
||||
**
|
||||
** u2 = ((r') * c) mod n
|
||||
*/
|
||||
CHECK_MPI_OK( mp_mulmod(&r_, &c, &n, &u2) );
|
||||
|
||||
/*
|
||||
** ANSI X9.62, Section 5.4.3, Step 1
|
||||
**
|
||||
** Compute u1*G + u2*Q
|
||||
** Here, A = u1.G B = u2.Q and C = A + B
|
||||
** If the result, C, is the point at infinity, reject the signature
|
||||
*/
|
||||
if ((ec_point_mul(ecParams, &u1, &ecParams->base, &pointA)
|
||||
== SECFailure) ||
|
||||
(ec_point_mul(ecParams, &u2, &key->publicValue, &pointB)
|
||||
== SECFailure) ||
|
||||
(ec_point_add(ecParams, &pointA, &pointB, &pointC) == SECFailure) ||
|
||||
ec_point_at_infinity(&pointC)) {
|
||||
rv = SECFailure;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
CHECK_MPI_OK( mp_read_unsigned_octets(&x1, pointC.data + 1, len) );
|
||||
|
||||
/*
|
||||
** ANSI X9.62, Section 5.4.4, Step 2
|
||||
**
|
||||
** v = x1 mod n
|
||||
*/
|
||||
CHECK_MPI_OK( mp_mod(&x1, &n, &v) );
|
||||
|
||||
/*
|
||||
** ANSI X9.62, Section 5.4.4, Step 3
|
||||
**
|
||||
** Verification: v == r'
|
||||
*/
|
||||
if (mp_cmp(&v, &r_)) {
|
||||
PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
|
||||
rv = SECFailure; /* Signature failed to verify. */
|
||||
} else {
|
||||
rv = SECSuccess; /* Signature verified. */
|
||||
}
|
||||
|
||||
#if EC_DEBUG
|
||||
mp_todecimal(&u1, mpstr);
|
||||
printf("u1: %s (dec)\n", mpstr);
|
||||
mp_todecimal(&u2, mpstr);
|
||||
printf("u2: %s (dec)\n", mpstr);
|
||||
mp_tohex(&x1, mpstr);
|
||||
printf("x1: %s\n", mpstr);
|
||||
mp_todecimal(&v, mpstr);
|
||||
printf("v : %s (dec)\n", mpstr);
|
||||
#endif
|
||||
|
||||
cleanup:
|
||||
mp_clear(&r_);
|
||||
mp_clear(&s_);
|
||||
mp_clear(&c);
|
||||
mp_clear(&u1);
|
||||
mp_clear(&u2);
|
||||
mp_clear(&x1);
|
||||
mp_clear(&y1);
|
||||
mp_clear(&x2);
|
||||
mp_clear(&y2);
|
||||
mp_clear(&v);
|
||||
mp_clear(&n);
|
||||
|
||||
if (arena) PORT_FreeArena(arena, PR_TRUE);
|
||||
if (err) {
|
||||
MP_TO_SEC_ERROR(err);
|
||||
rv = SECFailure;
|
||||
}
|
||||
|
||||
#if EC_DEBUG
|
||||
printf("ECDSA verification %s\n",
|
||||
(rv == SECSuccess) ? "succeeded" : "failed");
|
||||
#endif
|
||||
#else
|
||||
PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG);
|
||||
#endif /* NSS_ENABLE_ECC */
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
/*
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF 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 Elliptic Curve Cryptography library.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Sun Microsystems, Inc.
|
||||
* Portions created by Sun Microsystems, Inc. are Copyright (C) 2003
|
||||
* Sun Microsystems, Inc. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Dr Vipul Gupta <vipul.gupta@sun.com>, Sun Microsystems Laboratories
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __ec_h_
|
||||
#define __ec_h_
|
||||
|
||||
#define EC_DEBUG 0
|
||||
#define EC_POINT_FORM_COMPRESSED_Y0 0x02
|
||||
#define EC_POINT_FORM_COMPRESSED_Y1 0x03
|
||||
#define EC_POINT_FORM_UNCOMPRESSED 0x04
|
||||
#define EC_POINT_FORM_HYBRID_Y0 0x06
|
||||
#define EC_POINT_FORM_HYBRID_Y1 0x07
|
||||
|
||||
#define ANSI_X962_CURVE_OID_TOTAL_LEN 10
|
||||
#define SECG_CURVE_OID_TOTAL_LEN 7
|
||||
|
||||
#endif /* __ec_h_ */
|
||||
@@ -1,120 +0,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 the Netscape security libraries.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1994-2000 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the
|
||||
* terms of the GNU General Public License Version 2 or later (the
|
||||
* "GPL"), in which case the provisions of the GPL are applicable
|
||||
* instead of those above. If you wish to allow use of your
|
||||
* version of this file only under the terms of the GPL and not to
|
||||
* allow others to use your version of this file under the MPL,
|
||||
* indicate your decision by deleting the provisions above and
|
||||
* replace them with the notice and other provisions required by
|
||||
* the GPL. If you do not delete the provisions above, a recipient
|
||||
* may use your version of this file under either the MPL or the
|
||||
* GPL.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <plstr.h>
|
||||
#include "aglobal.h"
|
||||
#include "bsafe.h"
|
||||
#include "secport.h"
|
||||
|
||||
void CALL_CONV T_memset (p, c, count)
|
||||
POINTER p;
|
||||
int c;
|
||||
unsigned int count;
|
||||
{
|
||||
if (count >= 0)
|
||||
memset(p, c, count);
|
||||
}
|
||||
|
||||
void CALL_CONV T_memcpy (d, s, count)
|
||||
POINTER d, s;
|
||||
unsigned int count;
|
||||
{
|
||||
if (count >= 0)
|
||||
memcpy(d, s, count);
|
||||
}
|
||||
|
||||
void CALL_CONV T_memmove (d, s, count)
|
||||
POINTER d, s;
|
||||
unsigned int count;
|
||||
{
|
||||
if (count >= 0)
|
||||
PORT_Memmove(d, s, count);
|
||||
}
|
||||
|
||||
int CALL_CONV T_memcmp (s1, s2, count)
|
||||
POINTER s1, s2;
|
||||
unsigned int count;
|
||||
{
|
||||
if (count == 0)
|
||||
return (0);
|
||||
else
|
||||
return(memcmp(s1, s2, count));
|
||||
}
|
||||
|
||||
POINTER CALL_CONV T_malloc (size)
|
||||
unsigned int size;
|
||||
{
|
||||
return((POINTER)PORT_Alloc(size == 0 ? 1 : size));
|
||||
}
|
||||
|
||||
POINTER CALL_CONV T_realloc (p, size)
|
||||
POINTER p;
|
||||
unsigned int size;
|
||||
{
|
||||
POINTER result;
|
||||
|
||||
if (p == NULL_PTR)
|
||||
return (T_malloc(size));
|
||||
|
||||
if ((result = (POINTER)PORT_Realloc(p, size == 0 ? 1 : size)) == NULL_PTR)
|
||||
PORT_Free(p);
|
||||
return (result);
|
||||
}
|
||||
|
||||
void CALL_CONV T_free (p)
|
||||
POINTER p;
|
||||
{
|
||||
if (p != NULL_PTR)
|
||||
PORT_Free(p);
|
||||
}
|
||||
|
||||
unsigned int CALL_CONV T_strlen(p)
|
||||
char *p;
|
||||
{
|
||||
return PL_strlen(p);
|
||||
}
|
||||
|
||||
void CALL_CONV T_strcpy(dest, src)
|
||||
char *dest;
|
||||
char *src;
|
||||
{
|
||||
PL_strcpy(dest, src);
|
||||
}
|
||||
|
||||
int CALL_CONV T_strcmp (a, b)
|
||||
char *a, *b;
|
||||
{
|
||||
return (PL_strcmp (a, b));
|
||||
}
|
||||
@@ -1,196 +0,0 @@
|
||||
/*
|
||||
* ldvector.c - platform dependent DSO containing freebl implementation.
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF 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 Netscape security libraries.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 2000 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Portions created by Sun Microsystems, Inc. are Copyright (C) 2003
|
||||
* Sun Microsystems, Inc. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Dr Vipul Gupta <vipul.gupta@sun.com>, Sun Microsystems Laboratories
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the
|
||||
* terms of the GNU General Public License Version 2 or later (the
|
||||
* "GPL"), in which case the provisions of the GPL are applicable
|
||||
* instead of those above. If you wish to allow use of your
|
||||
* version of this file only under the terms of the GPL and not to
|
||||
* allow others to use your version of this file under the MPL,
|
||||
* indicate your decision by deleting the provisions above and
|
||||
* replace them with the notice and other provisions required by
|
||||
* the GPL. If you do not delete the provisions above, a recipient
|
||||
* may use your version of this file under either the MPL or the
|
||||
* GPL.
|
||||
*
|
||||
* $Id: ldvector.c,v 1.6 2003-02-27 01:31:13 nelsonb%netscape.com Exp $
|
||||
*/
|
||||
|
||||
#include "loader.h"
|
||||
|
||||
static const struct FREEBLVectorStr vector = {
|
||||
|
||||
sizeof vector,
|
||||
FREEBL_VERSION,
|
||||
|
||||
RSA_NewKey,
|
||||
RSA_PublicKeyOp,
|
||||
RSA_PrivateKeyOp,
|
||||
DSA_NewKey,
|
||||
DSA_SignDigest,
|
||||
DSA_VerifyDigest,
|
||||
DSA_NewKeyFromSeed,
|
||||
DSA_SignDigestWithSeed,
|
||||
DH_GenParam,
|
||||
DH_NewKey,
|
||||
DH_Derive,
|
||||
KEA_Derive,
|
||||
KEA_Verify,
|
||||
RC4_CreateContext,
|
||||
RC4_DestroyContext,
|
||||
RC4_Encrypt,
|
||||
RC4_Decrypt,
|
||||
RC2_CreateContext,
|
||||
RC2_DestroyContext,
|
||||
RC2_Encrypt,
|
||||
RC2_Decrypt,
|
||||
RC5_CreateContext,
|
||||
RC5_DestroyContext,
|
||||
RC5_Encrypt,
|
||||
RC5_Decrypt,
|
||||
DES_CreateContext,
|
||||
DES_DestroyContext,
|
||||
DES_Encrypt,
|
||||
DES_Decrypt,
|
||||
AES_CreateContext,
|
||||
AES_DestroyContext,
|
||||
AES_Encrypt,
|
||||
AES_Decrypt,
|
||||
MD5_Hash,
|
||||
MD5_HashBuf,
|
||||
MD5_NewContext,
|
||||
MD5_DestroyContext,
|
||||
MD5_Begin,
|
||||
MD5_Update,
|
||||
MD5_End,
|
||||
MD5_FlattenSize,
|
||||
MD5_Flatten,
|
||||
MD5_Resurrect,
|
||||
MD5_TraceState,
|
||||
MD2_Hash,
|
||||
MD2_NewContext,
|
||||
MD2_DestroyContext,
|
||||
MD2_Begin,
|
||||
MD2_Update,
|
||||
MD2_End,
|
||||
MD2_FlattenSize,
|
||||
MD2_Flatten,
|
||||
MD2_Resurrect,
|
||||
SHA1_Hash,
|
||||
SHA1_HashBuf,
|
||||
SHA1_NewContext,
|
||||
SHA1_DestroyContext,
|
||||
SHA1_Begin,
|
||||
SHA1_Update,
|
||||
SHA1_End,
|
||||
SHA1_TraceState,
|
||||
SHA1_FlattenSize,
|
||||
SHA1_Flatten,
|
||||
SHA1_Resurrect,
|
||||
RNG_RNGInit,
|
||||
RNG_RandomUpdate,
|
||||
RNG_GenerateGlobalRandomBytes,
|
||||
RNG_RNGShutdown,
|
||||
PQG_ParamGen,
|
||||
PQG_ParamGenSeedLen,
|
||||
PQG_VerifyParams,
|
||||
|
||||
/* End of Version 3.001. */
|
||||
|
||||
RSA_PrivateKeyOpDoubleChecked,
|
||||
RSA_PrivateKeyCheck,
|
||||
BL_Cleanup,
|
||||
|
||||
/* End of Version 3.002. */
|
||||
|
||||
SHA256_NewContext,
|
||||
SHA256_DestroyContext,
|
||||
SHA256_Begin,
|
||||
SHA256_Update,
|
||||
SHA256_End,
|
||||
SHA256_HashBuf,
|
||||
SHA256_Hash,
|
||||
SHA256_TraceState,
|
||||
SHA256_FlattenSize,
|
||||
SHA256_Flatten,
|
||||
SHA256_Resurrect,
|
||||
|
||||
SHA512_NewContext,
|
||||
SHA512_DestroyContext,
|
||||
SHA512_Begin,
|
||||
SHA512_Update,
|
||||
SHA512_End,
|
||||
SHA512_HashBuf,
|
||||
SHA512_Hash,
|
||||
SHA512_TraceState,
|
||||
SHA512_FlattenSize,
|
||||
SHA512_Flatten,
|
||||
SHA512_Resurrect,
|
||||
|
||||
SHA384_NewContext,
|
||||
SHA384_DestroyContext,
|
||||
SHA384_Begin,
|
||||
SHA384_Update,
|
||||
SHA384_End,
|
||||
SHA384_HashBuf,
|
||||
SHA384_Hash,
|
||||
SHA384_TraceState,
|
||||
SHA384_FlattenSize,
|
||||
SHA384_Flatten,
|
||||
SHA384_Resurrect,
|
||||
|
||||
/* End of Version 3.003. */
|
||||
|
||||
AESKeyWrap_CreateContext,
|
||||
AESKeyWrap_DestroyContext,
|
||||
AESKeyWrap_Encrypt,
|
||||
AESKeyWrap_Decrypt,
|
||||
|
||||
/* End of Version 3.004. */
|
||||
|
||||
BLAPI_SHVerify,
|
||||
BLAPI_VerifySelf,
|
||||
|
||||
/* End of Version 3.005. */
|
||||
|
||||
EC_NewKey,
|
||||
EC_NewKeyFromSeed,
|
||||
EC_ValidatePublicKey,
|
||||
ECDH_Derive,
|
||||
ECDSA_SignDigest,
|
||||
ECDSA_VerifyDigest,
|
||||
ECDSA_SignDigestWithSeed,
|
||||
|
||||
/* End of Version 3.006. */
|
||||
};
|
||||
|
||||
|
||||
const FREEBLVector *
|
||||
FREEBL_GetVector(void)
|
||||
{
|
||||
return &vector;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,386 +0,0 @@
|
||||
/*
|
||||
* loader.h - load platform dependent DSO containing freebl implementation.
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF 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 Netscape security libraries.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 2000 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Portions created by Sun Microsystems, Inc. are Copyright (C) 2003
|
||||
* Sun Microsystems, Inc. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Dr Vipul Gupta <vipul.gupta@sun.com>, Sun Microsystems Laboratories
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the
|
||||
* terms of the GNU General Public License Version 2 or later (the
|
||||
* "GPL"), in which case the provisions of the GPL are applicable
|
||||
* instead of those above. If you wish to allow use of your
|
||||
* version of this file only under the terms of the GPL and not to
|
||||
* allow others to use your version of this file under the MPL,
|
||||
* indicate your decision by deleting the provisions above and
|
||||
* replace them with the notice and other provisions required by
|
||||
* the GPL. If you do not delete the provisions above, a recipient
|
||||
* may use your version of this file under either the MPL or the
|
||||
* GPL.
|
||||
*
|
||||
* $Id: loader.h,v 1.9 2003-02-27 01:31:14 nelsonb%netscape.com Exp $
|
||||
*/
|
||||
|
||||
#ifndef _LOADER_H_
|
||||
#define _LOADER_H_ 1
|
||||
|
||||
#include "blapi.h"
|
||||
|
||||
#define FREEBL_VERSION 0x0306
|
||||
|
||||
struct FREEBLVectorStr {
|
||||
|
||||
unsigned short length; /* of this struct in bytes */
|
||||
unsigned short version; /* of this struct. */
|
||||
|
||||
RSAPrivateKey * (* p_RSA_NewKey)(int keySizeInBits,
|
||||
SECItem * publicExponent);
|
||||
|
||||
SECStatus (* p_RSA_PublicKeyOp) (RSAPublicKey * key,
|
||||
unsigned char * output,
|
||||
const unsigned char * input);
|
||||
|
||||
SECStatus (* p_RSA_PrivateKeyOp)(RSAPrivateKey * key,
|
||||
unsigned char * output,
|
||||
const unsigned char * input);
|
||||
|
||||
SECStatus (* p_DSA_NewKey)(const PQGParams * params,
|
||||
DSAPrivateKey ** privKey);
|
||||
|
||||
SECStatus (* p_DSA_SignDigest)(DSAPrivateKey * key,
|
||||
SECItem * signature,
|
||||
const SECItem * digest);
|
||||
|
||||
SECStatus (* p_DSA_VerifyDigest)(DSAPublicKey * key,
|
||||
const SECItem * signature,
|
||||
const SECItem * digest);
|
||||
|
||||
SECStatus (* p_DSA_NewKeyFromSeed)(const PQGParams *params,
|
||||
const unsigned char * seed,
|
||||
DSAPrivateKey **privKey);
|
||||
|
||||
SECStatus (* p_DSA_SignDigestWithSeed)(DSAPrivateKey * key,
|
||||
SECItem * signature,
|
||||
const SECItem * digest,
|
||||
const unsigned char * seed);
|
||||
|
||||
SECStatus (* p_DH_GenParam)(int primeLen, DHParams ** params);
|
||||
|
||||
SECStatus (* p_DH_NewKey)(DHParams * params,
|
||||
DHPrivateKey ** privKey);
|
||||
|
||||
SECStatus (* p_DH_Derive)(SECItem * publicValue,
|
||||
SECItem * prime,
|
||||
SECItem * privateValue,
|
||||
SECItem * derivedSecret,
|
||||
unsigned int maxOutBytes);
|
||||
|
||||
SECStatus (* p_KEA_Derive)(SECItem *prime,
|
||||
SECItem *public1,
|
||||
SECItem *public2,
|
||||
SECItem *private1,
|
||||
SECItem *private2,
|
||||
SECItem *derivedSecret);
|
||||
|
||||
PRBool (* p_KEA_Verify)(SECItem *Y, SECItem *prime, SECItem *subPrime);
|
||||
|
||||
RC4Context * (* p_RC4_CreateContext)(const unsigned char *key, int len);
|
||||
|
||||
void (* p_RC4_DestroyContext)(RC4Context *cx, PRBool freeit);
|
||||
|
||||
SECStatus (* p_RC4_Encrypt)(RC4Context *cx, unsigned char *output,
|
||||
unsigned int *outputLen, unsigned int maxOutputLen,
|
||||
const unsigned char *input, unsigned int inputLen);
|
||||
|
||||
SECStatus (* p_RC4_Decrypt)(RC4Context *cx, unsigned char *output,
|
||||
unsigned int *outputLen, unsigned int maxOutputLen,
|
||||
const unsigned char *input, unsigned int inputLen);
|
||||
|
||||
RC2Context * (* p_RC2_CreateContext)(const unsigned char *key,
|
||||
unsigned int len, const unsigned char *iv,
|
||||
int mode, unsigned effectiveKeyLen);
|
||||
|
||||
void (* p_RC2_DestroyContext)(RC2Context *cx, PRBool freeit);
|
||||
|
||||
SECStatus (* p_RC2_Encrypt)(RC2Context *cx, unsigned char *output,
|
||||
unsigned int *outputLen, unsigned int maxOutputLen,
|
||||
const unsigned char *input, unsigned int inputLen);
|
||||
|
||||
SECStatus (* p_RC2_Decrypt)(RC2Context *cx, unsigned char *output,
|
||||
unsigned int *outputLen, unsigned int maxOutputLen,
|
||||
const unsigned char *input, unsigned int inputLen);
|
||||
|
||||
RC5Context *(* p_RC5_CreateContext)(const SECItem *key, unsigned int rounds,
|
||||
unsigned int wordSize, const unsigned char *iv, int mode);
|
||||
|
||||
void (* p_RC5_DestroyContext)(RC5Context *cx, PRBool freeit);
|
||||
|
||||
SECStatus (* p_RC5_Encrypt)(RC5Context *cx, unsigned char *output,
|
||||
unsigned int *outputLen, unsigned int maxOutputLen,
|
||||
const unsigned char *input, unsigned int inputLen);
|
||||
|
||||
SECStatus (* p_RC5_Decrypt)(RC5Context *cx, unsigned char *output,
|
||||
unsigned int *outputLen, unsigned int maxOutputLen,
|
||||
const unsigned char *input, unsigned int inputLen);
|
||||
|
||||
DESContext *(* p_DES_CreateContext)(const unsigned char *key,
|
||||
const unsigned char *iv,
|
||||
int mode, PRBool encrypt);
|
||||
|
||||
void (* p_DES_DestroyContext)(DESContext *cx, PRBool freeit);
|
||||
|
||||
SECStatus (* p_DES_Encrypt)(DESContext *cx, unsigned char *output,
|
||||
unsigned int *outputLen, unsigned int maxOutputLen,
|
||||
const unsigned char *input, unsigned int inputLen);
|
||||
|
||||
SECStatus (* p_DES_Decrypt)(DESContext *cx, unsigned char *output,
|
||||
unsigned int *outputLen, unsigned int maxOutputLen,
|
||||
const unsigned char *input, unsigned int inputLen);
|
||||
|
||||
AESContext * (* p_AES_CreateContext)(const unsigned char *key,
|
||||
const unsigned char *iv,
|
||||
int mode, int encrypt, unsigned int keylen,
|
||||
unsigned int blocklen);
|
||||
|
||||
void (* p_AES_DestroyContext)(AESContext *cx, PRBool freeit);
|
||||
|
||||
SECStatus (* p_AES_Encrypt)(AESContext *cx, unsigned char *output,
|
||||
unsigned int *outputLen, unsigned int maxOutputLen,
|
||||
const unsigned char *input, unsigned int inputLen);
|
||||
|
||||
SECStatus (* p_AES_Decrypt)(AESContext *cx, unsigned char *output,
|
||||
unsigned int *outputLen, unsigned int maxOutputLen,
|
||||
const unsigned char *input, unsigned int inputLen);
|
||||
|
||||
SECStatus (* p_MD5_Hash)(unsigned char *dest, const char *src);
|
||||
|
||||
SECStatus (* p_MD5_HashBuf)(unsigned char *dest, const unsigned char *src,
|
||||
uint32 src_length);
|
||||
|
||||
MD5Context *(* p_MD5_NewContext)(void);
|
||||
|
||||
void (* p_MD5_DestroyContext)(MD5Context *cx, PRBool freeit);
|
||||
|
||||
void (* p_MD5_Begin)(MD5Context *cx);
|
||||
|
||||
void (* p_MD5_Update)(MD5Context *cx,
|
||||
const unsigned char *input, unsigned int inputLen);
|
||||
|
||||
void (* p_MD5_End)(MD5Context *cx, unsigned char *digest,
|
||||
unsigned int *digestLen, unsigned int maxDigestLen);
|
||||
|
||||
unsigned int (* p_MD5_FlattenSize)(MD5Context *cx);
|
||||
|
||||
SECStatus (* p_MD5_Flatten)(MD5Context *cx,unsigned char *space);
|
||||
|
||||
MD5Context * (* p_MD5_Resurrect)(unsigned char *space, void *arg);
|
||||
|
||||
void (* p_MD5_TraceState)(MD5Context *cx);
|
||||
|
||||
SECStatus (* p_MD2_Hash)(unsigned char *dest, const char *src);
|
||||
|
||||
MD2Context *(* p_MD2_NewContext)(void);
|
||||
|
||||
void (* p_MD2_DestroyContext)(MD2Context *cx, PRBool freeit);
|
||||
|
||||
void (* p_MD2_Begin)(MD2Context *cx);
|
||||
|
||||
void (* p_MD2_Update)(MD2Context *cx,
|
||||
const unsigned char *input, unsigned int inputLen);
|
||||
|
||||
void (* p_MD2_End)(MD2Context *cx, unsigned char *digest,
|
||||
unsigned int *digestLen, unsigned int maxDigestLen);
|
||||
|
||||
unsigned int (* p_MD2_FlattenSize)(MD2Context *cx);
|
||||
|
||||
SECStatus (* p_MD2_Flatten)(MD2Context *cx,unsigned char *space);
|
||||
|
||||
MD2Context * (* p_MD2_Resurrect)(unsigned char *space, void *arg);
|
||||
|
||||
SECStatus (* p_SHA1_Hash)(unsigned char *dest, const char *src);
|
||||
|
||||
SECStatus (* p_SHA1_HashBuf)(unsigned char *dest, const unsigned char *src,
|
||||
uint32 src_length);
|
||||
|
||||
SHA1Context *(* p_SHA1_NewContext)(void);
|
||||
|
||||
void (* p_SHA1_DestroyContext)(SHA1Context *cx, PRBool freeit);
|
||||
|
||||
void (* p_SHA1_Begin)(SHA1Context *cx);
|
||||
|
||||
void (* p_SHA1_Update)(SHA1Context *cx, const unsigned char *input,
|
||||
unsigned int inputLen);
|
||||
|
||||
void (* p_SHA1_End)(SHA1Context *cx, unsigned char *digest,
|
||||
unsigned int *digestLen, unsigned int maxDigestLen);
|
||||
|
||||
void (* p_SHA1_TraceState)(SHA1Context *cx);
|
||||
|
||||
unsigned int (* p_SHA1_FlattenSize)(SHA1Context *cx);
|
||||
|
||||
SECStatus (* p_SHA1_Flatten)(SHA1Context *cx,unsigned char *space);
|
||||
|
||||
SHA1Context * (* p_SHA1_Resurrect)(unsigned char *space, void *arg);
|
||||
|
||||
SECStatus (* p_RNG_RNGInit)(void);
|
||||
|
||||
SECStatus (* p_RNG_RandomUpdate)(const void *data, size_t bytes);
|
||||
|
||||
SECStatus (* p_RNG_GenerateGlobalRandomBytes)(void *dest, size_t len);
|
||||
|
||||
void (* p_RNG_RNGShutdown)(void);
|
||||
|
||||
SECStatus (* p_PQG_ParamGen)(unsigned int j, PQGParams **pParams,
|
||||
PQGVerify **pVfy);
|
||||
|
||||
SECStatus (* p_PQG_ParamGenSeedLen)( unsigned int j, unsigned int seedBytes,
|
||||
PQGParams **pParams, PQGVerify **pVfy);
|
||||
|
||||
SECStatus (* p_PQG_VerifyParams)(const PQGParams *params,
|
||||
const PQGVerify *vfy, SECStatus *result);
|
||||
|
||||
/* Version 3.001 came to here */
|
||||
|
||||
SECStatus (* p_RSA_PrivateKeyOpDoubleChecked)(RSAPrivateKey *key,
|
||||
unsigned char *output,
|
||||
const unsigned char *input);
|
||||
|
||||
SECStatus (* p_RSA_PrivateKeyCheck)(RSAPrivateKey *key);
|
||||
|
||||
void (* p_BL_Cleanup)(void);
|
||||
|
||||
/* Version 3.002 came to here */
|
||||
|
||||
SHA256Context *(* p_SHA256_NewContext)(void);
|
||||
void (* p_SHA256_DestroyContext)(SHA256Context *cx, PRBool freeit);
|
||||
void (* p_SHA256_Begin)(SHA256Context *cx);
|
||||
void (* p_SHA256_Update)(SHA256Context *cx, const unsigned char *input,
|
||||
unsigned int inputLen);
|
||||
void (* p_SHA256_End)(SHA256Context *cx, unsigned char *digest,
|
||||
unsigned int *digestLen, unsigned int maxDigestLen);
|
||||
SECStatus (* p_SHA256_HashBuf)(unsigned char *dest, const unsigned char *src,
|
||||
uint32 src_length);
|
||||
SECStatus (* p_SHA256_Hash)(unsigned char *dest, const char *src);
|
||||
void (* p_SHA256_TraceState)(SHA256Context *cx);
|
||||
unsigned int (* p_SHA256_FlattenSize)(SHA256Context *cx);
|
||||
SECStatus (* p_SHA256_Flatten)(SHA256Context *cx,unsigned char *space);
|
||||
SHA256Context * (* p_SHA256_Resurrect)(unsigned char *space, void *arg);
|
||||
|
||||
SHA512Context *(* p_SHA512_NewContext)(void);
|
||||
void (* p_SHA512_DestroyContext)(SHA512Context *cx, PRBool freeit);
|
||||
void (* p_SHA512_Begin)(SHA512Context *cx);
|
||||
void (* p_SHA512_Update)(SHA512Context *cx, const unsigned char *input,
|
||||
unsigned int inputLen);
|
||||
void (* p_SHA512_End)(SHA512Context *cx, unsigned char *digest,
|
||||
unsigned int *digestLen, unsigned int maxDigestLen);
|
||||
SECStatus (* p_SHA512_HashBuf)(unsigned char *dest, const unsigned char *src,
|
||||
uint32 src_length);
|
||||
SECStatus (* p_SHA512_Hash)(unsigned char *dest, const char *src);
|
||||
void (* p_SHA512_TraceState)(SHA512Context *cx);
|
||||
unsigned int (* p_SHA512_FlattenSize)(SHA512Context *cx);
|
||||
SECStatus (* p_SHA512_Flatten)(SHA512Context *cx,unsigned char *space);
|
||||
SHA512Context * (* p_SHA512_Resurrect)(unsigned char *space, void *arg);
|
||||
|
||||
SHA384Context *(* p_SHA384_NewContext)(void);
|
||||
void (* p_SHA384_DestroyContext)(SHA384Context *cx, PRBool freeit);
|
||||
void (* p_SHA384_Begin)(SHA384Context *cx);
|
||||
void (* p_SHA384_Update)(SHA384Context *cx, const unsigned char *input,
|
||||
unsigned int inputLen);
|
||||
void (* p_SHA384_End)(SHA384Context *cx, unsigned char *digest,
|
||||
unsigned int *digestLen, unsigned int maxDigestLen);
|
||||
SECStatus (* p_SHA384_HashBuf)(unsigned char *dest, const unsigned char *src,
|
||||
uint32 src_length);
|
||||
SECStatus (* p_SHA384_Hash)(unsigned char *dest, const char *src);
|
||||
void (* p_SHA384_TraceState)(SHA384Context *cx);
|
||||
unsigned int (* p_SHA384_FlattenSize)(SHA384Context *cx);
|
||||
SECStatus (* p_SHA384_Flatten)(SHA384Context *cx,unsigned char *space);
|
||||
SHA384Context * (* p_SHA384_Resurrect)(unsigned char *space, void *arg);
|
||||
|
||||
/* Version 3.003 came to here */
|
||||
|
||||
AESKeyWrapContext * (* p_AESKeyWrap_CreateContext)(const unsigned char *key,
|
||||
const unsigned char *iv, int encrypt, unsigned int keylen);
|
||||
|
||||
void (* p_AESKeyWrap_DestroyContext)(AESKeyWrapContext *cx, PRBool freeit);
|
||||
|
||||
SECStatus (* p_AESKeyWrap_Encrypt)(AESKeyWrapContext *cx,
|
||||
unsigned char *output,
|
||||
unsigned int *outputLen, unsigned int maxOutputLen,
|
||||
const unsigned char *input, unsigned int inputLen);
|
||||
|
||||
SECStatus (* p_AESKeyWrap_Decrypt)(AESKeyWrapContext *cx,
|
||||
unsigned char *output,
|
||||
unsigned int *outputLen, unsigned int maxOutputLen,
|
||||
const unsigned char *input, unsigned int inputLen);
|
||||
|
||||
/* Version 3.004 came to here */
|
||||
|
||||
PRBool (*p_BLAPI_SHVerify)(const char *name, PRFuncPtr addr);
|
||||
PRBool (*p_BLAPI_VerifySelf)(const char *name);
|
||||
|
||||
/* Version 3.005 came to here */
|
||||
|
||||
SECStatus (* p_EC_NewKey)(ECParams * params,
|
||||
ECPrivateKey ** privKey);
|
||||
|
||||
SECStatus (* p_EC_NewKeyFromSeed)(ECParams * params,
|
||||
ECPrivateKey ** privKey,
|
||||
const unsigned char * seed,
|
||||
int seedlen);
|
||||
|
||||
SECStatus (* p_EC_ValidatePublicKey)(ECParams * params,
|
||||
SECItem * publicValue);
|
||||
|
||||
SECStatus (* p_ECDH_Derive)(SECItem * publicValue,
|
||||
ECParams * params,
|
||||
SECItem * privateValue,
|
||||
PRBool withCofactor,
|
||||
SECItem * derivedSecret);
|
||||
|
||||
SECStatus (* p_ECDSA_SignDigest)(ECPrivateKey * key,
|
||||
SECItem * signature,
|
||||
const SECItem * digest);
|
||||
|
||||
SECStatus (* p_ECDSA_VerifyDigest)(ECPublicKey * key,
|
||||
const SECItem * signature,
|
||||
const SECItem * digest);
|
||||
|
||||
SECStatus (* p_ECDSA_SignDigestWithSeed)(ECPrivateKey * key,
|
||||
SECItem * signature,
|
||||
const SECItem * digest,
|
||||
const unsigned char * seed,
|
||||
const int seedlen);
|
||||
|
||||
/* Version 3.006 came to here */
|
||||
|
||||
};
|
||||
|
||||
typedef struct FREEBLVectorStr FREEBLVector;
|
||||
|
||||
SEC_BEGIN_PROTOS
|
||||
|
||||
typedef const FREEBLVector * FREEBLGetVectorFn(void);
|
||||
|
||||
extern FREEBLGetVectorFn FREEBL_GetVector;
|
||||
|
||||
SEC_END_PROTOS
|
||||
|
||||
#endif
|
||||
@@ -1,315 +0,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 the Netscape security libraries.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1994-2000 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the
|
||||
* terms of the GNU General Public License Version 2 or later (the
|
||||
* "GPL"), in which case the provisions of the GPL are applicable
|
||||
* instead of those above. If you wish to allow use of your
|
||||
* version of this file only under the terms of the GPL and not to
|
||||
* allow others to use your version of this file under the MPL,
|
||||
* indicate your decision by deleting the provisions above and
|
||||
* replace them with the notice and other provisions required by
|
||||
* the GPL. If you do not delete the provisions above, a recipient
|
||||
* may use your version of this file under either the MPL or the
|
||||
* GPL.
|
||||
*/
|
||||
|
||||
#ifdef notdef
|
||||
#include "xp_core.h"
|
||||
#include "xp_file.h"
|
||||
#endif
|
||||
#include "secrng.h"
|
||||
#include "mcom_db.h"
|
||||
#ifdef XP_MAC
|
||||
#include <Events.h>
|
||||
#include <OSUtils.h>
|
||||
#include <QDOffscreen.h>
|
||||
#include <PPCToolbox.h>
|
||||
#include <Processes.h>
|
||||
#include <LowMem.h>
|
||||
#include <Scrap.h>
|
||||
|
||||
/* Static prototypes */
|
||||
static size_t CopyLowBits(void *dst, size_t dstlen, void *src, size_t srclen);
|
||||
void FE_ReadScreen();
|
||||
|
||||
static size_t CopyLowBits(void *dst, size_t dstlen, void *src, size_t srclen)
|
||||
{
|
||||
union endianness {
|
||||
int32 i;
|
||||
char c[4];
|
||||
} u;
|
||||
|
||||
if (srclen <= dstlen) {
|
||||
memcpy(dst, src, srclen);
|
||||
return srclen;
|
||||
}
|
||||
u.i = 0x01020304;
|
||||
if (u.c[0] == 0x01) {
|
||||
/* big-endian case */
|
||||
memcpy(dst, (char*)src + (srclen - dstlen), dstlen);
|
||||
} else {
|
||||
/* little-endian case */
|
||||
memcpy(dst, src, dstlen);
|
||||
}
|
||||
return dstlen;
|
||||
}
|
||||
|
||||
size_t RNG_GetNoise(void *buf, size_t maxbytes)
|
||||
{
|
||||
UnsignedWide microTickCount;
|
||||
Microseconds(µTickCount);
|
||||
return CopyLowBits(buf, maxbytes, µTickCount, sizeof(microTickCount));
|
||||
}
|
||||
|
||||
void RNG_FileForRNG(const char *filename)
|
||||
{
|
||||
unsigned char buffer[BUFSIZ];
|
||||
size_t bytes;
|
||||
#ifdef notdef /*sigh*/
|
||||
XP_File file;
|
||||
unsigned long totalFileBytes = 0;
|
||||
|
||||
if (filename == NULL) /* For now, read in global history if filename is null */
|
||||
file = XP_FileOpen(NULL, xpGlobalHistory,XP_FILE_READ_BIN);
|
||||
else
|
||||
file = XP_FileOpen(NULL, xpURL,XP_FILE_READ_BIN);
|
||||
if (file != NULL) {
|
||||
for (;;) {
|
||||
bytes = XP_FileRead(buffer, sizeof(buffer), file);
|
||||
if (bytes == 0) break;
|
||||
RNG_RandomUpdate( buffer, bytes);
|
||||
totalFileBytes += bytes;
|
||||
if (totalFileBytes > 100*1024) break; /* No more than 100 K */
|
||||
}
|
||||
XP_FileClose(file);
|
||||
}
|
||||
#endif
|
||||
/*
|
||||
* Pass yet another snapshot of our highest resolution clock into
|
||||
* the hash function.
|
||||
*/
|
||||
bytes = RNG_GetNoise(buffer, sizeof(buffer));
|
||||
RNG_RandomUpdate(buffer, sizeof(buffer));
|
||||
}
|
||||
|
||||
void RNG_SystemInfoForRNG()
|
||||
{
|
||||
/* Time */
|
||||
{
|
||||
unsigned long sec;
|
||||
size_t bytes;
|
||||
GetDateTime(&sec); /* Current time since 1970 */
|
||||
RNG_RandomUpdate( &sec, sizeof(sec));
|
||||
bytes = RNG_GetNoise(&sec, sizeof(sec));
|
||||
RNG_RandomUpdate(&sec, bytes);
|
||||
}
|
||||
/* User specific variables */
|
||||
{
|
||||
MachineLocation loc;
|
||||
ReadLocation(&loc);
|
||||
RNG_RandomUpdate( &loc, sizeof(loc));
|
||||
}
|
||||
#if !TARGET_CARBON
|
||||
/* User name */
|
||||
{
|
||||
unsigned long userRef;
|
||||
Str32 userName;
|
||||
GetDefaultUser(&userRef, userName);
|
||||
RNG_RandomUpdate( &userRef, sizeof(userRef));
|
||||
RNG_RandomUpdate( userName, sizeof(userName));
|
||||
}
|
||||
#endif
|
||||
/* Mouse location */
|
||||
{
|
||||
Point mouseLoc;
|
||||
GetMouse(&mouseLoc);
|
||||
RNG_RandomUpdate( &mouseLoc, sizeof(mouseLoc));
|
||||
}
|
||||
/* Keyboard time threshold */
|
||||
{
|
||||
SInt16 keyTresh = LMGetKeyThresh();
|
||||
RNG_RandomUpdate( &keyTresh, sizeof(keyTresh));
|
||||
}
|
||||
/* Last key pressed */
|
||||
{
|
||||
SInt8 keyLast;
|
||||
keyLast = LMGetKbdLast();
|
||||
RNG_RandomUpdate( &keyLast, sizeof(keyLast));
|
||||
}
|
||||
/* Volume */
|
||||
{
|
||||
UInt8 volume = LMGetSdVolume();
|
||||
RNG_RandomUpdate( &volume, sizeof(volume));
|
||||
}
|
||||
#if !TARGET_CARBON
|
||||
/* Current directory */
|
||||
{
|
||||
SInt32 dir = LMGetCurDirStore();
|
||||
RNG_RandomUpdate( &dir, sizeof(dir));
|
||||
}
|
||||
#endif
|
||||
/* Process information about all the processes in the machine */
|
||||
{
|
||||
ProcessSerialNumber process;
|
||||
ProcessInfoRec pi;
|
||||
|
||||
process.highLongOfPSN = process.lowLongOfPSN = kNoProcess;
|
||||
|
||||
while (GetNextProcess(&process) == noErr)
|
||||
{
|
||||
FSSpec fileSpec;
|
||||
pi.processInfoLength = sizeof(ProcessInfoRec);
|
||||
pi.processName = NULL;
|
||||
pi.processAppSpec = &fileSpec;
|
||||
GetProcessInformation(&process, &pi);
|
||||
RNG_RandomUpdate( &pi, sizeof(pi));
|
||||
RNG_RandomUpdate( &fileSpec, sizeof(fileSpec));
|
||||
}
|
||||
}
|
||||
|
||||
#if !TARGET_CARBON
|
||||
/* Heap */
|
||||
{
|
||||
THz zone = LMGetTheZone();
|
||||
RNG_RandomUpdate( &zone, sizeof(zone));
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Screen */
|
||||
{
|
||||
GDHandle h = GetMainDevice(); /* GDHandle is **GDevice */
|
||||
RNG_RandomUpdate( *h, sizeof(GDevice));
|
||||
}
|
||||
|
||||
#if !TARGET_CARBON
|
||||
/* Scrap size */
|
||||
{
|
||||
SInt32 scrapSize = LMGetScrapSize();
|
||||
RNG_RandomUpdate( &scrapSize, sizeof(scrapSize));
|
||||
}
|
||||
/* Scrap count */
|
||||
{
|
||||
SInt16 scrapCount = LMGetScrapCount();
|
||||
RNG_RandomUpdate( &scrapCount, sizeof(scrapCount));
|
||||
}
|
||||
#else
|
||||
{
|
||||
ScrapRef scrap;
|
||||
if (GetCurrentScrap(&scrap) == noErr) {
|
||||
UInt32 flavorCount;
|
||||
if (GetScrapFlavorCount(scrap, &flavorCount) == noErr) {
|
||||
ScrapFlavorInfo* flavorInfo = (ScrapFlavorInfo*) malloc(flavorCount * sizeof(ScrapFlavorInfo));
|
||||
if (flavorInfo != NULL) {
|
||||
if (GetScrapFlavorInfoList(scrap, &flavorCount, flavorInfo) == noErr) {
|
||||
UInt32 i;
|
||||
RNG_RandomUpdate(&flavorCount, sizeof(flavorCount));
|
||||
for (i = 0; i < flavorCount; ++i) {
|
||||
Size flavorSize;
|
||||
if (GetScrapFlavorSize(scrap, flavorInfo[i].flavorType, &flavorSize) == noErr)
|
||||
RNG_RandomUpdate(&flavorSize, sizeof(flavorSize));
|
||||
}
|
||||
}
|
||||
free(flavorInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
/* File stuff, last modified, etc. */
|
||||
{
|
||||
HParamBlockRec pb;
|
||||
GetVolParmsInfoBuffer volInfo;
|
||||
pb.ioParam.ioVRefNum = 0;
|
||||
pb.ioParam.ioNamePtr = nil;
|
||||
pb.ioParam.ioBuffer = (Ptr) &volInfo;
|
||||
pb.ioParam.ioReqCount = sizeof(volInfo);
|
||||
PBHGetVolParmsSync(&pb);
|
||||
RNG_RandomUpdate( &volInfo, sizeof(volInfo));
|
||||
}
|
||||
#if !TARGET_CARBON
|
||||
/* Event queue */
|
||||
{
|
||||
EvQElPtr eventQ;
|
||||
for (eventQ = (EvQElPtr) LMGetEventQueue()->qHead;
|
||||
eventQ;
|
||||
eventQ = (EvQElPtr)eventQ->qLink)
|
||||
RNG_RandomUpdate( &eventQ->evtQWhat, sizeof(EventRecord));
|
||||
}
|
||||
#endif
|
||||
FE_ReadScreen();
|
||||
RNG_FileForRNG(NULL);
|
||||
}
|
||||
|
||||
void FE_ReadScreen()
|
||||
{
|
||||
UInt16 coords[4];
|
||||
PixMapHandle pmap;
|
||||
GDHandle gh;
|
||||
UInt16 screenHeight;
|
||||
UInt16 screenWidth; /* just what they say */
|
||||
UInt32 bytesToRead; /* number of bytes we're giving */
|
||||
UInt32 offset; /* offset into the graphics buffer */
|
||||
UInt16 rowBytes;
|
||||
UInt32 rowsToRead;
|
||||
float bytesPerPixel; /* dependent on buffer depth */
|
||||
Ptr p; /* temporary */
|
||||
UInt16 x, y, w, h;
|
||||
|
||||
gh = LMGetMainDevice();
|
||||
if ( !gh )
|
||||
return;
|
||||
pmap = (**gh).gdPMap;
|
||||
if ( !pmap )
|
||||
return;
|
||||
|
||||
RNG_GenerateGlobalRandomBytes( coords, sizeof( coords ) );
|
||||
|
||||
/* make x and y inside the screen rect */
|
||||
screenHeight = (**pmap).bounds.bottom - (**pmap).bounds.top;
|
||||
screenWidth = (**pmap).bounds.right - (**pmap).bounds.left;
|
||||
x = coords[0] % screenWidth;
|
||||
y = coords[1] % screenHeight;
|
||||
w = ( coords[2] & 0x7F ) | 0x40; /* Make sure that w is in the range 64..128 */
|
||||
h = ( coords[3] & 0x7F ) | 0x40; /* same for h */
|
||||
|
||||
bytesPerPixel = (**pmap).pixelSize / 8;
|
||||
rowBytes = (**pmap).rowBytes & 0x7FFF;
|
||||
|
||||
/* starting address */
|
||||
offset = ( rowBytes * y ) + (UInt32)( (float)x * bytesPerPixel );
|
||||
|
||||
/* don't read past the end of the pixmap's rowbytes */
|
||||
bytesToRead = PR_MIN( (UInt32)( w * bytesPerPixel ),
|
||||
(UInt32)( rowBytes - ( x * bytesPerPixel ) ) );
|
||||
|
||||
/* don't read past the end of the graphics device pixmap */
|
||||
rowsToRead = PR_MIN( h,
|
||||
( screenHeight - y ) );
|
||||
|
||||
p = GetPixBaseAddr( pmap ) + offset;
|
||||
|
||||
while ( rowsToRead-- )
|
||||
{
|
||||
RNG_RandomUpdate( p, bytesToRead );
|
||||
p += rowBytes;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -1,146 +0,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 the Netscape security libraries.
|
||||
#
|
||||
# The Initial Developer of the Original Code is Netscape
|
||||
# Communications Corporation. Portions created by Netscape are
|
||||
# Copyright (C) 1994-2000 Netscape Communications Corporation. All
|
||||
# Rights Reserved.
|
||||
#
|
||||
# Portions created by Sun Microsystems, Inc. are Copyright (C) 2003
|
||||
# Sun Microsystems, Inc. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
# Dr Vipul Gupta <vipul.gupta@sun.com>, Sun Microsystems Laboratories
|
||||
#
|
||||
# Alternatively, the contents of this file may be used under the
|
||||
# terms of the GNU General Public License Version 2 or later (the
|
||||
# "GPL"), in which case the provisions of the GPL are applicable
|
||||
# instead of those above. If you wish to allow use of your
|
||||
# version of this file only under the terms of the GPL and not to
|
||||
# allow others to use your version of this file under the MPL,
|
||||
# indicate your decision by deleting the provisions above and
|
||||
# replace them with the notice and other provisions required by
|
||||
# the GPL. If you do not delete the provisions above, a recipient
|
||||
# may use your version of this file under either the MPL or the
|
||||
# GPL.
|
||||
#
|
||||
CORE_DEPTH = ../../..
|
||||
|
||||
MODULE = nss
|
||||
|
||||
ifndef FREEBL_RECURSIVE_BUILD
|
||||
LIBRARY_NAME = freebl
|
||||
else
|
||||
ifdef USE_PURE_32
|
||||
CORE_DEPTH = ../../../..
|
||||
LIBRARY_NAME = freebl_pure32
|
||||
else
|
||||
LIBRARY_NAME = freebl_hybrid
|
||||
endif
|
||||
endif
|
||||
|
||||
# same version as rest of freebl
|
||||
LIBRARY_VERSION = _3
|
||||
|
||||
DEFINES += -DSHLIB_SUFFIX=\"$(DLL_SUFFIX)\" -DSHLIB_PREFIX=\"$(DLL_PREFIX)\"
|
||||
|
||||
REQUIRES =
|
||||
|
||||
EXPORTS = \
|
||||
blapi.h \
|
||||
blapit.h \
|
||||
secrng.h \
|
||||
shsign.h \
|
||||
$(NULL)
|
||||
|
||||
PRIVATE_EXPORTS = \
|
||||
secmpi.h \
|
||||
ec.h \
|
||||
$(NULL)
|
||||
|
||||
MPI_HDRS = mpi-config.h mpi.h mpi-priv.h mplogic.h mpprime.h logtab.h mp_gf2m.h
|
||||
MPI_SRCS = mpprime.c mpmontg.c mplogic.c mpi.c mp_gf2m.c
|
||||
|
||||
ifdef MOZILLA_BSAFE_BUILD
|
||||
CSRCS = \
|
||||
fblstdlib.c \
|
||||
sha_fast.c \
|
||||
md2.c \
|
||||
md5.c \
|
||||
blapi_bsf.c \
|
||||
$(MPI_SRCS) \
|
||||
dh.c \
|
||||
$(NULL)
|
||||
else
|
||||
CSRCS = \
|
||||
ldvector.c \
|
||||
prng_fips1861.c \
|
||||
sysrand.c \
|
||||
sha_fast.c \
|
||||
md2.c \
|
||||
md5.c \
|
||||
sha512.c \
|
||||
alg2268.c \
|
||||
arcfour.c \
|
||||
arcfive.c \
|
||||
desblapi.c \
|
||||
des.c \
|
||||
rijndael.c \
|
||||
aeskeywrap.c \
|
||||
dh.c \
|
||||
ec.c \
|
||||
GFp_ecl.c \
|
||||
GF2m_ecl.c \
|
||||
pqg.c \
|
||||
dsa.c \
|
||||
rsa.c \
|
||||
shvfy.c \
|
||||
$(MPI_SRCS) \
|
||||
$(NULL)
|
||||
endif
|
||||
|
||||
ALL_CSRCS := $(CSRCS)
|
||||
|
||||
ALL_HDRS = \
|
||||
blapi.h \
|
||||
blapit.h \
|
||||
des.h \
|
||||
ec.h \
|
||||
GFp_ecl.h \
|
||||
GF2m_ecl.h \
|
||||
loader.h \
|
||||
rijndael.h \
|
||||
secmpi.h \
|
||||
sha.h \
|
||||
sha_fast.h \
|
||||
shsign.h \
|
||||
vis_proto.h \
|
||||
$(NULL)
|
||||
|
||||
ifdef AES_GEN_TBL
|
||||
DEFINES += -DRIJNDAEL_GENERATE_TABLES
|
||||
else
|
||||
ifdef AES_GEN_TBL_M
|
||||
DEFINES += -DRIJNDAEL_GENERATE_TABLES_MACRO
|
||||
else
|
||||
ifdef AES_GEN_VAL
|
||||
DEFINES += -DRIJNDAEL_GENERATE_VALUES
|
||||
else
|
||||
ifdef AES_GEN_VAL_M
|
||||
DEFINES += -DRIJNDAEL_GENERATE_VALUES_MACRO
|
||||
else
|
||||
DEFINES += -DRIJNDAEL_INCLUDE_TABLES
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
@@ -1,39 +0,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 the Netscape security libraries.
|
||||
#
|
||||
# The Initial Developer of the Original Code is Netscape
|
||||
# Communications Corporation. Portions created by Netscape are
|
||||
# Copyright (C) 2000 Netscape Communications Corporation. All
|
||||
# Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
#
|
||||
# Alternatively, the contents of this file may be used under the
|
||||
# terms of the GNU General Public License Version 2 or later (the
|
||||
# "GPL"), in which case the provisions of the GPL are applicable
|
||||
# instead of those above. If you wish to allow use of your
|
||||
# version of this file only under the terms of the GPL and not to
|
||||
# allow others to use your version of this file under the MPL,
|
||||
# indicate your decision by deleting the provisions above and
|
||||
# replace them with the notice and other provisions required by
|
||||
# the GPL. If you do not delete the provisions above, a recipient
|
||||
# may use your version of this file under either the MPL or the
|
||||
# GPL.
|
||||
#
|
||||
|
||||
libfreebl_3.so {
|
||||
global:
|
||||
FREEBL_GetVector;
|
||||
local:
|
||||
*;
|
||||
};
|
||||
1857
mozilla/string/obsolete/nsString.cpp
Normal file
1857
mozilla/string/obsolete/nsString.cpp
Normal file
File diff suppressed because it is too large
Load Diff
226
mozilla/xpcom/base/nsError.h
Normal file
226
mozilla/xpcom/base/nsError.h
Normal file
@@ -0,0 +1,226 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/*
|
||||
* 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):
|
||||
*/
|
||||
|
||||
#ifndef nsError_h
|
||||
#define nsError_h
|
||||
|
||||
#ifndef prtypes_h___
|
||||
#include "prtypes.h"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Generic result data type
|
||||
*/
|
||||
|
||||
typedef PRUint32 nsresult;
|
||||
|
||||
/*
|
||||
* 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
|
||||
|
||||
/**
|
||||
* @name Standard Error Handling Macros
|
||||
*/
|
||||
|
||||
#define NS_FAILED(_nsresult) ((_nsresult) & 0x80000000)
|
||||
#define NS_SUCCEEDED(_nsresult) (!((_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
|
||||
|
||||
/* The backwards COM false */
|
||||
#define NS_COMFALSE 1
|
||||
|
||||
#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 unexpected error occurs */
|
||||
#define NS_ERROR_UNEXPECTED ((nsresult) 0x8000ffffL)
|
||||
|
||||
/* Returned when a memory allocation failes */
|
||||
#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)
|
||||
|
||||
|
||||
/* 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)
|
||||
|
||||
|
||||
/*@}*/
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifdef XP_PC
|
||||
#pragma warning(disable: 4251) // 'nsCOMPtr<class nsIInputStream>' 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
|
||||
|
||||
126
mozilla/xpcom/build/dlldeps.cpp
Normal file
126
mozilla/xpcom/build/dlldeps.cpp
Normal file
@@ -0,0 +1,126 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* 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):
|
||||
*/
|
||||
|
||||
// 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 "nsIAtom.h"
|
||||
#include "nsFileSpec.h"
|
||||
//#include "nsIBuffer.h"
|
||||
//#include "nsIByteBufferInputStream.h"
|
||||
#include "nsFileStream.h"
|
||||
#include "nsFileSpecStreaming.h"
|
||||
#include "nsSpecialSystemDirectory.h"
|
||||
#include "nsIThread.h"
|
||||
#include "nsDeque.h"
|
||||
#include "nsObserver.h"
|
||||
#include "nsTraceRefcnt.h"
|
||||
#include "nsXPIDLString.h"
|
||||
#include "nsIEnumerator.h"
|
||||
#include "nsEnumeratorUtils.h"
|
||||
#include "nsQuickSort.h"
|
||||
#include "nsString2.h"
|
||||
#include "nsProxyEventPrivate.h"
|
||||
#include "xpt_xdr.h"
|
||||
#include "nsInterfaceInfo.h"
|
||||
#include "xptcall.h"
|
||||
#include "nsIFileSpec.h"
|
||||
#include "nsIGenericFactory.h"
|
||||
#include "nsAVLTree.h"
|
||||
#include "nsHashtableEnumerator.h"
|
||||
#include "nsPipe2.h"
|
||||
#include "nsCWeakReference.h"
|
||||
#include "nsWeakReference.h"
|
||||
#include "nsISizeOfHandler.h"
|
||||
#include "nsTextFormater.h"
|
||||
#include "nsStorageStream.h"
|
||||
#include "nsIBinaryInputStream.h"
|
||||
#ifdef DEBUG
|
||||
#include "pure.h"
|
||||
#endif
|
||||
|
||||
class dummyComparitor: public nsAVLNodeComparitor {
|
||||
public:
|
||||
virtual PRInt32 operator()(void* anItem1,void* anItem2)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
#ifdef DEBUG
|
||||
extern NS_COM void
|
||||
TestSegmentedBuffer();
|
||||
#endif
|
||||
|
||||
void XXXNeverCalled()
|
||||
{
|
||||
nsTextFormater::snprintf(nsnull,0,nsnull);
|
||||
dummyComparitor dummy;
|
||||
nsVoidArray();
|
||||
nsAVLTree(dummy, nsnull);
|
||||
NS_GetNumberOfAtoms();
|
||||
nsFileURL(NULL);
|
||||
// NS_NewPipe(NULL, NULL, 0, 0, 0, NULL);
|
||||
NS_NewPipe(NULL, NULL, NULL, 0, 0);
|
||||
nsFileSpec s;
|
||||
NS_NewIOFileStream(NULL, s, 0, 0);
|
||||
nsInputFileStream(s, 0, 0);
|
||||
nsPersistentFileDescriptor d;
|
||||
ReadDescriptor(NULL, d);
|
||||
new nsSpecialSystemDirectory(nsSpecialSystemDirectory::OS_DriveDirectory);
|
||||
nsIThread::GetCurrent(NULL);
|
||||
nsDeque(NULL);
|
||||
NS_NewObserver(NULL, NULL);
|
||||
nsTraceRefcnt::DumpStatistics();
|
||||
nsXPIDLCString::Copy(NULL);
|
||||
NS_NewEmptyEnumerator(NULL);
|
||||
nsArrayEnumerator(NULL);
|
||||
NS_NewIntersectionEnumerator(NULL, NULL, NULL);
|
||||
NS_QuickSort(NULL, 0, 0, NULL, NULL);
|
||||
nsString2();
|
||||
nsProxyObject(NULL, 0, NULL);
|
||||
XPT_DoString(NULL, NULL);
|
||||
XPT_DoHeader(NULL, NULL);
|
||||
nsInterfaceInfo* info = NULL;
|
||||
info->GetName(NULL);
|
||||
#ifdef DEBUG
|
||||
info->print(NULL);
|
||||
PurePrintf(0);
|
||||
#endif
|
||||
XPTC_InvokeByIndex(NULL, 0, 0, NULL);
|
||||
NS_NewFileSpec(NULL);
|
||||
xptc_dummy();
|
||||
xptc_dummy2();
|
||||
XPTI_GetInterfaceInfoManager();
|
||||
NS_NewGenericFactory(NULL, NULL, NULL);
|
||||
NS_NewHashtableEnumerator(NULL, NULL, NULL, NULL);
|
||||
nsCWeakProxy(0, 0);
|
||||
nsCWeakReferent(0);
|
||||
NS_GetWeakReference(NULL);
|
||||
#ifdef DEBUG
|
||||
TestSegmentedBuffer();
|
||||
#endif
|
||||
NS_NewSizeOfHandler(0);
|
||||
nsStorageStream();
|
||||
NS_NewBinaryInputStream(0, 0);
|
||||
}
|
||||
170
mozilla/xpcom/components/nsIGenericFactory.h
Normal file
170
mozilla/xpcom/components/nsIGenericFactory.h
Normal file
@@ -0,0 +1,170 @@
|
||||
/* -*- Mode: C++; tab-width: 4; 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):
|
||||
*/
|
||||
|
||||
#ifndef nsIGenericFactory_h___
|
||||
#define nsIGenericFactory_h___
|
||||
|
||||
#include "nsIFactory.h"
|
||||
|
||||
// {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_PROGID "component:/netscape/generic-factory"
|
||||
#define NS_GENERICFACTORY_CLASSNAME "Generic Factory"
|
||||
/**
|
||||
* Provides a Generic nsIFactory implementation that can be used by
|
||||
* DLLs with very simple factory needs.
|
||||
*/
|
||||
class nsIGenericFactory : public nsIFactory {
|
||||
public:
|
||||
static const nsIID& GetIID() { static nsIID iid = NS_IGENERICFACTORY_IID; return iid; }
|
||||
|
||||
typedef NS_CALLBACK(ConstructorProcPtr) (nsISupports *aOuter, REFNSIID aIID, void **aResult);
|
||||
typedef NS_CALLBACK(DestructorProcPtr) (void);
|
||||
|
||||
/**
|
||||
* Establishes the generic factory's constructor function, which will be called
|
||||
* by CreateInstance.
|
||||
*/
|
||||
NS_IMETHOD SetConstructor(ConstructorProcPtr constructor) = 0;
|
||||
|
||||
/**
|
||||
* Establishes the generic factory's destructor function, which will be called
|
||||
* whe the generic factory is deleted. This is used to notify the DLL that
|
||||
* an instance of one of its generic factories is going away.
|
||||
*/
|
||||
NS_IMETHOD SetDestructor(DestructorProcPtr destructor) = 0;
|
||||
};
|
||||
|
||||
extern NS_COM nsresult
|
||||
NS_NewGenericFactory(nsIGenericFactory* *result,
|
||||
nsIGenericFactory::ConstructorProcPtr constructor,
|
||||
nsIGenericFactory::DestructorProcPtr destructor = NULL);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Generic Modules
|
||||
//
|
||||
// (See xpcom/sample/nsSampleModule.cpp to see how to use this.)
|
||||
|
||||
#include "nsIModule.h"
|
||||
|
||||
/**
|
||||
* Use this type to define a list of module component info to pass to
|
||||
* NS_NewGenericModule. E.g.:
|
||||
* static nsModuleComponentInfo components[] = { ... };
|
||||
* See xpcom/sample/nsSampleModule.cpp for more info.
|
||||
*/
|
||||
struct nsModuleComponentInfo {
|
||||
const char* mDescription;
|
||||
nsCID mCID;
|
||||
const char* mProgID;
|
||||
nsIGenericFactory::ConstructorProcPtr mConstructor;
|
||||
};
|
||||
|
||||
extern NS_COM nsresult
|
||||
NS_NewGenericModule(const char* moduleName,
|
||||
PRUint32 componentCount,
|
||||
nsModuleComponentInfo* components,
|
||||
nsIModule* *result);
|
||||
|
||||
#define NS_IMPL_NSGETMODULE(_name, _components) \
|
||||
extern "C" NS_EXPORT nsresult NSGetModule(nsIComponentManager *servMgr, \
|
||||
nsIFileSpec* location, \
|
||||
nsIModule** result) \
|
||||
{ \
|
||||
return NS_NewGenericModule((_name), \
|
||||
sizeof(_components) / sizeof(_components[0]), \
|
||||
(_components), result); \
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define NS_GENERIC_FACTORY_CONSTRUCTOR(_InstanceClass) \
|
||||
static NS_IMETHODIMP \
|
||||
_InstanceClass##Constructor(nsISupports *aOuter, REFNSIID aIID, void **aResult) \
|
||||
{ \
|
||||
nsresult rv; \
|
||||
\
|
||||
_InstanceClass * inst; \
|
||||
\
|
||||
if (NULL == aResult) { \
|
||||
rv = NS_ERROR_NULL_POINTER; \
|
||||
return rv; \
|
||||
} \
|
||||
*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; \
|
||||
\
|
||||
if (NULL == aResult) { \
|
||||
rv = NS_ERROR_NULL_POINTER; \
|
||||
return rv; \
|
||||
} \
|
||||
*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; \
|
||||
} \
|
||||
|
||||
#endif /* nsIGenericFactory_h___ */
|
||||
521
mozilla/xpcom/ds/nsHashtable.cpp
Normal file
521
mozilla/xpcom/ds/nsHashtable.cpp
Normal file
@@ -0,0 +1,521 @@
|
||||
/* -*- Mode: C++; tab-width: 4; 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):
|
||||
*/
|
||||
|
||||
#include "prmem.h"
|
||||
#include "prlog.h"
|
||||
#include "nsHashtable.h"
|
||||
|
||||
//
|
||||
// Key operations
|
||||
//
|
||||
|
||||
static PR_CALLBACK PLHashNumber _hashValue(const void *key)
|
||||
{
|
||||
return ((const nsHashKey *) key)->HashValue();
|
||||
}
|
||||
|
||||
static PR_CALLBACK PRIntn _hashKeyCompare(const void *key1, const void *key2) {
|
||||
return ((const nsHashKey *) key1)->Equals((const nsHashKey *) key2);
|
||||
}
|
||||
|
||||
static PR_CALLBACK PRIntn _hashValueCompare(const void *value1,
|
||||
const void *value2) {
|
||||
// We're not going to make any assumptions about value equality
|
||||
return 0;
|
||||
}
|
||||
|
||||
//
|
||||
// Memory callbacks
|
||||
//
|
||||
|
||||
static PR_CALLBACK void *_hashAllocTable(void *pool, PRSize size) {
|
||||
return PR_MALLOC(size);
|
||||
}
|
||||
|
||||
static PR_CALLBACK void _hashFreeTable(void *pool, void *item) {
|
||||
PR_DELETE(item);
|
||||
}
|
||||
|
||||
static PR_CALLBACK PLHashEntry *_hashAllocEntry(void *pool, const void *key) {
|
||||
return PR_NEW(PLHashEntry);
|
||||
}
|
||||
|
||||
static PR_CALLBACK void _hashFreeEntry(void *pool, PLHashEntry *entry,
|
||||
PRUintn flag) {
|
||||
if (flag == HT_FREE_ENTRY) {
|
||||
delete (nsHashKey *) (entry->key);
|
||||
PR_DELETE(entry);
|
||||
}
|
||||
}
|
||||
|
||||
static PLHashAllocOps _hashAllocOps = {
|
||||
_hashAllocTable, _hashFreeTable,
|
||||
_hashAllocEntry, _hashFreeEntry
|
||||
};
|
||||
|
||||
//
|
||||
// Enumerator callback
|
||||
//
|
||||
|
||||
struct _HashEnumerateArgs {
|
||||
nsHashtableEnumFunc fn;
|
||||
void* arg;
|
||||
};
|
||||
|
||||
static PR_CALLBACK PRIntn _hashEnumerate(PLHashEntry *he, PRIntn i, void *arg)
|
||||
{
|
||||
_HashEnumerateArgs* thunk = (_HashEnumerateArgs*)arg;
|
||||
return thunk->fn((nsHashKey *) he->key, he->value, thunk->arg)
|
||||
? HT_ENUMERATE_NEXT
|
||||
: HT_ENUMERATE_STOP;
|
||||
}
|
||||
|
||||
//
|
||||
// HashKey
|
||||
//
|
||||
nsHashKey::nsHashKey(void)
|
||||
{
|
||||
}
|
||||
|
||||
nsHashKey::~nsHashKey(void)
|
||||
{
|
||||
}
|
||||
|
||||
nsHashtable::nsHashtable(PRUint32 aInitSize, PRBool threadSafe)
|
||||
: mLock(NULL)
|
||||
{
|
||||
hashtable = PL_NewHashTable(aInitSize,
|
||||
_hashValue,
|
||||
_hashKeyCompare,
|
||||
_hashValueCompare,
|
||||
&_hashAllocOps,
|
||||
NULL);
|
||||
if (threadSafe == PR_TRUE)
|
||||
{
|
||||
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() {
|
||||
PL_HashTableDestroy(hashtable);
|
||||
if (mLock) PR_DestroyLock(mLock);
|
||||
}
|
||||
|
||||
PRBool nsHashtable::Exists(nsHashKey *aKey)
|
||||
{
|
||||
PLHashNumber hash = aKey->HashValue();
|
||||
|
||||
if (mLock) PR_Lock(mLock);
|
||||
|
||||
PLHashEntry **hep = PL_HashTableRawLookup(hashtable, hash, (void *) aKey);
|
||||
|
||||
if (mLock) PR_Unlock(mLock);
|
||||
|
||||
return *hep != NULL;
|
||||
}
|
||||
|
||||
void *nsHashtable::Put(nsHashKey *aKey, void *aData) {
|
||||
void *res = NULL;
|
||||
PLHashNumber hash = aKey->HashValue();
|
||||
PLHashEntry *he;
|
||||
|
||||
if (mLock) PR_Lock(mLock);
|
||||
|
||||
PLHashEntry **hep = PL_HashTableRawLookup(hashtable, hash, (void *) aKey);
|
||||
|
||||
if ((he = *hep) != NULL) {
|
||||
res = he->value;
|
||||
he->value = aData;
|
||||
} else {
|
||||
PL_HashTableRawAdd(hashtable, hep, hash,
|
||||
(void *) aKey->Clone(), aData);
|
||||
}
|
||||
|
||||
if (mLock) PR_Unlock(mLock);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void *nsHashtable::Get(nsHashKey *aKey) {
|
||||
|
||||
if (mLock) PR_Lock(mLock);
|
||||
|
||||
void *ret = PL_HashTableLookup(hashtable, (void *) aKey);
|
||||
|
||||
if (mLock) PR_Unlock(mLock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void *nsHashtable::Remove(nsHashKey *aKey) {
|
||||
PLHashNumber hash = aKey->HashValue();
|
||||
PLHashEntry *he;
|
||||
|
||||
if (mLock) PR_Lock(mLock);
|
||||
|
||||
PLHashEntry **hep = PL_HashTableRawLookup(hashtable, hash, (void *) aKey);
|
||||
void *res = NULL;
|
||||
|
||||
if ((he = *hep) != NULL) {
|
||||
res = he->value;
|
||||
PL_HashTableRawRemove(hashtable, hep, he);
|
||||
}
|
||||
|
||||
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.
|
||||
static PR_CALLBACK PRIntn _hashEnumerateShare(PLHashEntry *he, PRIntn i, void *arg)
|
||||
{
|
||||
nsHashtable *newHashtable = (nsHashtable *)arg;
|
||||
newHashtable->Put((nsHashKey *) he->key, he->value);
|
||||
return HT_ENUMERATE_NEXT;
|
||||
}
|
||||
|
||||
nsHashtable * nsHashtable::Clone() {
|
||||
PRBool threadSafe = PR_FALSE;
|
||||
if (mLock)
|
||||
threadSafe = PR_TRUE;
|
||||
nsHashtable *newHashTable = new nsHashtable(hashtable->nentries, threadSafe);
|
||||
|
||||
PL_HashTableEnumerateEntries(hashtable, _hashEnumerateShare, newHashTable);
|
||||
return newHashTable;
|
||||
}
|
||||
|
||||
void nsHashtable::Enumerate(nsHashtableEnumFunc aEnumFunc, void* closure) {
|
||||
_HashEnumerateArgs thunk;
|
||||
thunk.fn = aEnumFunc;
|
||||
thunk.arg = closure;
|
||||
PL_HashTableEnumerateEntries(hashtable, _hashEnumerate, &thunk);
|
||||
}
|
||||
|
||||
static PR_CALLBACK PRIntn _hashEnumerateRemove(PLHashEntry *he, PRIntn i, void *arg)
|
||||
{
|
||||
_HashEnumerateArgs* thunk = (_HashEnumerateArgs*)arg;
|
||||
if (thunk)
|
||||
return thunk->fn((nsHashKey *) he->key, he->value, thunk->arg)
|
||||
? HT_ENUMERATE_REMOVE
|
||||
: HT_ENUMERATE_STOP;
|
||||
else
|
||||
return HT_ENUMERATE_REMOVE;
|
||||
}
|
||||
|
||||
void nsHashtable::Reset() {
|
||||
Reset(NULL);
|
||||
}
|
||||
|
||||
void nsHashtable::Reset(nsHashtableEnumFunc destroyFunc, void* closure)
|
||||
{
|
||||
if (destroyFunc != NULL)
|
||||
{
|
||||
_HashEnumerateArgs thunk;
|
||||
thunk.fn = destroyFunc;
|
||||
thunk.arg = closure;
|
||||
PL_HashTableEnumerateEntries(hashtable, _hashEnumerateRemove, &thunk);
|
||||
}
|
||||
else
|
||||
PL_HashTableEnumerateEntries(hashtable, _hashEnumerateRemove, NULL);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
nsStringKey::nsStringKey(const char* str)
|
||||
{
|
||||
mStr.Assign(str);
|
||||
}
|
||||
|
||||
nsStringKey::nsStringKey(const PRUnichar* str)
|
||||
{
|
||||
mStr.Assign(str);
|
||||
}
|
||||
|
||||
nsStringKey::nsStringKey(const nsStr& str)
|
||||
{
|
||||
mStr.Assign(str);
|
||||
}
|
||||
|
||||
nsStringKey::~nsStringKey(void)
|
||||
{
|
||||
}
|
||||
|
||||
PRUint32 nsStringKey::HashValue(void) const
|
||||
{
|
||||
if(mStr.IsUnicode())
|
||||
{
|
||||
PRUint32 h;
|
||||
PRUint32 n;
|
||||
PRUint32 m;
|
||||
const PRUnichar* c;
|
||||
|
||||
h = 0;
|
||||
n = mStr.Length();
|
||||
c = mStr.GetUnicode();
|
||||
if(n < 16)
|
||||
{ /* Hash every char in a short string. */
|
||||
for(; n; c++, n--)
|
||||
h = (h >> 28) ^ (h << 4) ^ *c;
|
||||
}
|
||||
else
|
||||
{ /* Sample a la jave.lang.String.hash(). */
|
||||
for(m = n / 8; n >= m; c += m, n -= m)
|
||||
h = (h >> 28) ^ (h << 4) ^ *c;
|
||||
}
|
||||
return h;
|
||||
}
|
||||
return (PRUint32)PL_HashString((const void*) mStr.GetBuffer());
|
||||
}
|
||||
|
||||
PRBool nsStringKey::Equals(const nsHashKey* aKey) const
|
||||
{
|
||||
return ((nsStringKey*)aKey)->mStr == mStr;
|
||||
}
|
||||
|
||||
nsHashKey* nsStringKey::Clone() const
|
||||
{
|
||||
return new nsStringKey(mStr);
|
||||
}
|
||||
|
||||
const nsString& nsStringKey::GetString() const
|
||||
{
|
||||
return 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();
|
||||
}
|
||||
|
||||
PR_CALLBACK PRIntn
|
||||
nsObjectHashtable::CopyElement(PLHashEntry *he, PRIntn i, void *arg)
|
||||
{
|
||||
nsObjectHashtable *newHashtable = (nsObjectHashtable *)arg;
|
||||
void* newElement =
|
||||
newHashtable->mCloneElementFun((nsHashKey*)he->key, he->value,
|
||||
newHashtable->mCloneElementClosure);
|
||||
if (newElement == nsnull)
|
||||
return HT_ENUMERATE_STOP;
|
||||
newHashtable->Put((nsHashKey*)he->key, newElement);
|
||||
return HT_ENUMERATE_NEXT;
|
||||
}
|
||||
|
||||
nsHashtable*
|
||||
nsObjectHashtable::Clone()
|
||||
{
|
||||
PRBool threadSafe = PR_FALSE;
|
||||
if (mLock)
|
||||
threadSafe = PR_TRUE;
|
||||
nsObjectHashtable* newHashTable =
|
||||
new nsObjectHashtable(mCloneElementFun, mCloneElementClosure,
|
||||
mDestroyElementFun, mDestroyElementClosure,
|
||||
hashtable->nentries, threadSafe);
|
||||
|
||||
PL_HashTableEnumerateEntries(hashtable, 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);
|
||||
}
|
||||
else
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// nsSupportsHashtable: an nsHashtable where the elements are nsISupports*
|
||||
|
||||
static PR_CALLBACK PRBool
|
||||
_ReleaseElement(nsHashKey *aKey, void *aData, void* closure)
|
||||
{
|
||||
nsISupports* element = NS_STATIC_CAST(nsISupports*, aData);
|
||||
NS_IF_RELEASE(element);
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
nsSupportsHashtable::~nsSupportsHashtable()
|
||||
{
|
||||
Enumerate(_ReleaseElement, nsnull);
|
||||
}
|
||||
|
||||
void*
|
||||
nsSupportsHashtable::Put(nsHashKey *aKey, void *aData)
|
||||
{
|
||||
nsISupports* element = NS_STATIC_CAST(nsISupports*, aData);
|
||||
NS_IF_ADDREF(element);
|
||||
return nsHashtable::Put(aKey, aData);
|
||||
}
|
||||
|
||||
void*
|
||||
nsSupportsHashtable::Get(nsHashKey *aKey)
|
||||
{
|
||||
void* data = nsHashtable::Get(aKey);
|
||||
if (!data)
|
||||
return nsnull;
|
||||
nsISupports* element = NS_STATIC_CAST(nsISupports*, data);
|
||||
NS_IF_ADDREF(element);
|
||||
return data;
|
||||
}
|
||||
|
||||
void*
|
||||
nsSupportsHashtable::Remove(nsHashKey *aKey)
|
||||
{
|
||||
void* data = nsHashtable::Remove(aKey);
|
||||
if (!data)
|
||||
return nsnull;
|
||||
nsISupports* element = NS_STATIC_CAST(nsISupports*, data);
|
||||
NS_IF_RELEASE(element);
|
||||
return data;
|
||||
}
|
||||
|
||||
static PR_CALLBACK PRIntn
|
||||
_hashEnumerateCopy(PLHashEntry *he, PRIntn i, void *arg)
|
||||
{
|
||||
nsHashtable *newHashtable = (nsHashtable *)arg;
|
||||
nsISupports* element = NS_STATIC_CAST(nsISupports*, he->value);
|
||||
NS_IF_ADDREF(element);
|
||||
newHashtable->Put((nsHashKey*)he->key, he->value);
|
||||
return HT_ENUMERATE_NEXT;
|
||||
}
|
||||
|
||||
nsHashtable*
|
||||
nsSupportsHashtable::Clone()
|
||||
{
|
||||
PRBool threadSafe = PR_FALSE;
|
||||
if (mLock)
|
||||
threadSafe = PR_TRUE;
|
||||
nsSupportsHashtable* newHashTable =
|
||||
new nsSupportsHashtable(hashtable->nentries, threadSafe);
|
||||
|
||||
PL_HashTableEnumerateEntries(hashtable, _hashEnumerateCopy, newHashTable);
|
||||
return newHashTable;
|
||||
}
|
||||
|
||||
void
|
||||
nsSupportsHashtable::Reset()
|
||||
{
|
||||
Enumerate(_ReleaseElement, nsnull);
|
||||
nsHashtable::Reset();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// nsOpaqueKey: Where keys are opaque byte array blobs
|
||||
//
|
||||
|
||||
// Note opaque keys are not copied by this constructor. If you want a private
|
||||
// copy in each hash key, you must create one and pass it in to this function.
|
||||
nsOpaqueKey::nsOpaqueKey(const char *aOpaqueKey, PRUint32 aKeyLength)
|
||||
{
|
||||
mOpaqueKey = aOpaqueKey;
|
||||
mKeyLength = aKeyLength;
|
||||
}
|
||||
|
||||
nsOpaqueKey::~nsOpaqueKey(void)
|
||||
{
|
||||
}
|
||||
|
||||
PRUint32
|
||||
nsOpaqueKey::HashValue(void) const
|
||||
{
|
||||
PRUint32 h, i, k;
|
||||
|
||||
h = 0;
|
||||
|
||||
// Same hashing technique as for java.lang.String.hashCode()
|
||||
if (mKeyLength <= 15) {
|
||||
// A short key; Use a dense sampling to compute the hash code
|
||||
for (i = 0; i < mKeyLength; i++)
|
||||
h += 37 * mOpaqueKey[i];
|
||||
} else {
|
||||
// A long key; Use a sparse sampling to compute the hash code
|
||||
k = mKeyLength >> 3;
|
||||
for (i = 0; i < mKeyLength; i += k)
|
||||
h += 39 * mOpaqueKey[i];
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsOpaqueKey::Equals(const nsHashKey* aKey) const
|
||||
{
|
||||
nsOpaqueKey *otherKey = (nsOpaqueKey*)aKey;
|
||||
if (mKeyLength != otherKey->mKeyLength)
|
||||
return PR_FALSE;
|
||||
return !(PRBool)memcmp(otherKey->mOpaqueKey, mOpaqueKey, mKeyLength);
|
||||
}
|
||||
|
||||
nsHashKey*
|
||||
nsOpaqueKey::Clone() const
|
||||
{
|
||||
return new nsOpaqueKey(mOpaqueKey, mKeyLength);
|
||||
}
|
||||
|
||||
PRUint32
|
||||
nsOpaqueKey::GetKeyLength() const
|
||||
{
|
||||
return mKeyLength;
|
||||
}
|
||||
|
||||
const char*
|
||||
nsOpaqueKey::GetKey() const
|
||||
{
|
||||
return mOpaqueKey;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
248
mozilla/xpcom/ds/nsHashtable.h
Normal file
248
mozilla/xpcom/ds/nsHashtable.h
Normal file
@@ -0,0 +1,248 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/*
|
||||
* 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):
|
||||
*/
|
||||
|
||||
#ifndef nsHashtable_h__
|
||||
#define nsHashtable_h__
|
||||
|
||||
#include "plhash.h"
|
||||
#include "prlock.h"
|
||||
#include "nsCom.h"
|
||||
|
||||
class NS_COM nsHashKey {
|
||||
protected:
|
||||
nsHashKey(void);
|
||||
public:
|
||||
virtual ~nsHashKey(void);
|
||||
virtual PRUint32 HashValue(void) const = 0;
|
||||
virtual PRBool Equals(const nsHashKey *aKey) const = 0;
|
||||
virtual nsHashKey *Clone(void) const = 0;
|
||||
};
|
||||
|
||||
// Enumerator callback function. Use
|
||||
|
||||
typedef PRBool (*nsHashtableEnumFunc)(nsHashKey *aKey, void *aData, void* closure);
|
||||
|
||||
class NS_COM nsHashtable {
|
||||
protected:
|
||||
// members
|
||||
PLHashTable *hashtable;
|
||||
PRLock *mLock;
|
||||
|
||||
public:
|
||||
nsHashtable(PRUint32 aSize = 256, PRBool threadSafe = PR_FALSE);
|
||||
~nsHashtable();
|
||||
|
||||
PRInt32 Count(void) { return hashtable->nentries; }
|
||||
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* closure = NULL);
|
||||
void Reset();
|
||||
void Reset(nsHashtableEnumFunc destroyFunc, void* closure = NULL);
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// nsObjectHashtable: an nsHashtable where the elements are C++ objects to be
|
||||
// deleted
|
||||
|
||||
typedef void* (*nsHashtableCloneElementFunc)(nsHashKey *aKey, void *aData, void* closure);
|
||||
|
||||
class NS_COM nsObjectHashtable : public nsHashtable {
|
||||
public:
|
||||
nsObjectHashtable(nsHashtableCloneElementFunc cloneElementFun,
|
||||
void* cloneElementClosure,
|
||||
nsHashtableEnumFunc destroyElementFun,
|
||||
void* destroyElementClosure,
|
||||
PRUint32 aSize = 256, PRBool threadSafe = PR_FALSE);
|
||||
~nsObjectHashtable();
|
||||
|
||||
nsHashtable *Clone();
|
||||
void Reset();
|
||||
PRBool RemoveAndDelete(nsHashKey *aKey);
|
||||
|
||||
protected:
|
||||
static PR_CALLBACK PRIntn CopyElement(PLHashEntry *he, PRIntn i, void *arg);
|
||||
|
||||
nsHashtableCloneElementFunc mCloneElementFun;
|
||||
void* mCloneElementClosure;
|
||||
nsHashtableEnumFunc mDestroyElementFun;
|
||||
void* mDestroyElementClosure;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// nsSupportsHashtable: an nsHashtable where the elements are nsISupports*
|
||||
|
||||
class NS_COM nsSupportsHashtable : public nsHashtable {
|
||||
public:
|
||||
nsSupportsHashtable(PRUint32 aSize = 256, PRBool threadSafe = PR_FALSE)
|
||||
: nsHashtable(aSize, threadSafe) {}
|
||||
~nsSupportsHashtable();
|
||||
|
||||
void *Put(nsHashKey *aKey, void *aData);
|
||||
void *Get(nsHashKey *aKey);
|
||||
void *Remove(nsHashKey *aKey);
|
||||
nsHashtable *Clone();
|
||||
void Reset();
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// nsISupportsKey: Where keys are nsISupports objects that get refcounted.
|
||||
|
||||
#include "nsISupports.h"
|
||||
|
||||
class nsISupportsKey : public nsHashKey {
|
||||
protected:
|
||||
nsISupports* mKey;
|
||||
|
||||
public:
|
||||
nsISupportsKey(nsISupports* key) {
|
||||
mKey = key;
|
||||
NS_IF_ADDREF(mKey);
|
||||
}
|
||||
|
||||
~nsISupportsKey(void) {
|
||||
NS_IF_RELEASE(mKey);
|
||||
}
|
||||
|
||||
PRUint32 HashValue(void) const {
|
||||
return (PRUint32)mKey;
|
||||
}
|
||||
|
||||
PRBool Equals(const nsHashKey *aKey) const {
|
||||
return (mKey == ((nsISupportsKey *) aKey)->mKey);
|
||||
}
|
||||
|
||||
nsHashKey *Clone(void) const {
|
||||
return new nsISupportsKey(mKey);
|
||||
}
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// nsVoidKey: Where keys are void* objects that don't get refcounted.
|
||||
|
||||
class nsVoidKey : public nsHashKey {
|
||||
protected:
|
||||
const void* mKey;
|
||||
|
||||
public:
|
||||
nsVoidKey(const void* key) {
|
||||
mKey = key;
|
||||
}
|
||||
|
||||
PRUint32 HashValue(void) const {
|
||||
return (PRUint32)mKey;
|
||||
}
|
||||
|
||||
PRBool Equals(const nsHashKey *aKey) const {
|
||||
return (mKey == ((const nsVoidKey *) aKey)->mKey);
|
||||
}
|
||||
|
||||
nsHashKey *Clone(void) const {
|
||||
return new nsVoidKey(mKey);
|
||||
}
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// nsIDKey: Where keys are nsIDs (e.g. nsIID, nsCID).
|
||||
|
||||
#include "nsID.h"
|
||||
|
||||
class nsIDKey : public nsHashKey {
|
||||
protected:
|
||||
nsID mID;
|
||||
|
||||
public:
|
||||
nsIDKey(const nsID &aID) {
|
||||
mID = aID;
|
||||
}
|
||||
|
||||
PRUint32 HashValue(void) const {
|
||||
return mID.m0;
|
||||
}
|
||||
|
||||
PRBool Equals(const nsHashKey *aKey) const {
|
||||
return (mID.Equals(((const nsIDKey *) aKey)->mID));
|
||||
}
|
||||
|
||||
nsHashKey *Clone(void) const {
|
||||
return new nsIDKey(mID);
|
||||
}
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// nsStringKey: Where keys are PRUnichar* or char*
|
||||
// Some uses: hashing ProgIDs, filenames, URIs
|
||||
|
||||
#include "nsString.h"
|
||||
|
||||
class NS_COM nsStringKey : public nsHashKey {
|
||||
protected:
|
||||
nsAutoString mStr;
|
||||
|
||||
public:
|
||||
nsStringKey(const char* str);
|
||||
nsStringKey(const PRUnichar* str);
|
||||
nsStringKey(const nsStr& str);
|
||||
|
||||
~nsStringKey(void);
|
||||
|
||||
PRUint32 HashValue(void) const;
|
||||
|
||||
PRBool Equals(const nsHashKey* aKey) const;
|
||||
|
||||
nsHashKey* Clone() 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 nsString& GetString() const;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// nsOpaqueKey: Where keys are opaque byte-array blobs
|
||||
|
||||
#include "nsString.h"
|
||||
|
||||
class NS_COM nsOpaqueKey : public nsHashKey {
|
||||
protected:
|
||||
const char* mOpaqueKey; // Byte array of opaque data
|
||||
PRUint32 mKeyLength; // Length, in bytes, of mOpaqueKey
|
||||
|
||||
public:
|
||||
// Note opaque keys are not copied by this constructor. If you want a private
|
||||
// copy in each hash key, you must create one and pass it in to this function.
|
||||
nsOpaqueKey(const char* aOpaqueKey, PRUint32 aKeyLength);
|
||||
|
||||
~nsOpaqueKey(void);
|
||||
|
||||
PRUint32 HashValue(void) const;
|
||||
PRBool Equals(const nsHashKey* aKey) const;
|
||||
nsHashKey* Clone() const;
|
||||
|
||||
// For when the owner of the hashtable wants to peek at the actual
|
||||
// opaque array in the key. No copy is made, so be careful.
|
||||
const char* GetKey() const;
|
||||
PRUint32 GetKeyLength() const;
|
||||
};
|
||||
|
||||
#endif
|
||||
247
mozilla/xpcom/ds/nsHashtableEnumerator.cpp
Normal file
247
mozilla/xpcom/ds/nsHashtableEnumerator.cpp
Normal file
@@ -0,0 +1,247 @@
|
||||
/* -*- 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):
|
||||
*/
|
||||
|
||||
/*
|
||||
* Implementation of nsHashEnumerator.
|
||||
* Use it to expose nsIEnumerator interfaces around nsHashtable objects.
|
||||
* Contributed by Rob Ginda, rginda@ix.netcom.com
|
||||
*/
|
||||
|
||||
#include "nscore.h"
|
||||
#include "nsHashtableEnumerator.h"
|
||||
|
||||
class nsHashtableEnumerator : public nsIBidirectionalEnumerator
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIENUMERATOR
|
||||
NS_DECL_NSIBIDIRECTIONALENUMERATOR
|
||||
|
||||
public:
|
||||
virtual ~nsHashtableEnumerator ();
|
||||
nsHashtableEnumerator (nsHashtable *aHash,
|
||||
NS_HASH_ENUMERATOR_CONVERTER aConverter,
|
||||
void *aData);
|
||||
nsHashtableEnumerator (); /* no implementation */
|
||||
|
||||
private:
|
||||
NS_IMETHOD Reset(nsHashtable *aHash,
|
||||
NS_HASH_ENUMERATOR_CONVERTER aConverter,
|
||||
void *aData);
|
||||
NS_IMETHOD ReleaseElements();
|
||||
|
||||
nsISupports **mElements;
|
||||
PRInt16 mCount, mCurrent;
|
||||
PRBool mDoneFlag;
|
||||
|
||||
};
|
||||
|
||||
struct nsHashEnumClosure
|
||||
{
|
||||
NS_HASH_ENUMERATOR_CONVERTER Converter;
|
||||
nsISupports **Elements;
|
||||
PRInt16 Current;
|
||||
void *Data;
|
||||
};
|
||||
|
||||
extern "C" NS_COM nsresult
|
||||
NS_NewHashtableEnumerator (nsHashtable *aHash,
|
||||
NS_HASH_ENUMERATOR_CONVERTER aConverter,
|
||||
void *aData, nsIEnumerator **retval)
|
||||
{
|
||||
NS_PRECONDITION (retval, "null ptr");
|
||||
|
||||
*retval = nsnull;
|
||||
|
||||
nsHashtableEnumerator *hte = new nsHashtableEnumerator (aHash, aConverter,
|
||||
aData);
|
||||
if (!hte)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
return hte->QueryInterface (nsCOMTypeInfo<nsIEnumerator>::GetIID(),
|
||||
(void **)retval);
|
||||
}
|
||||
|
||||
nsHashtableEnumerator::nsHashtableEnumerator (nsHashtable *aHash,
|
||||
NS_HASH_ENUMERATOR_CONVERTER aConverter,
|
||||
void *aData)
|
||||
: mElements(nsnull), mCount(0), mDoneFlag(PR_TRUE)
|
||||
{
|
||||
NS_INIT_REFCNT();
|
||||
Reset (aHash, aConverter, aData);
|
||||
|
||||
}
|
||||
|
||||
PRBool
|
||||
hash_enumerator (nsHashKey *aKey, void *aObject, void *closure)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
nsHashEnumClosure *c = (nsHashEnumClosure *)closure;
|
||||
|
||||
rv = c->Converter (aKey, (void *)aObject, (void *)c->Data,
|
||||
&c->Elements[c->Current]);
|
||||
|
||||
if (!NS_FAILED(rv))
|
||||
c->Current++;
|
||||
|
||||
return PR_TRUE;
|
||||
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHashtableEnumerator::Reset (nsHashtable *aHash,
|
||||
NS_HASH_ENUMERATOR_CONVERTER aConverter,
|
||||
void *aData)
|
||||
{
|
||||
nsHashEnumClosure c;
|
||||
|
||||
ReleaseElements();
|
||||
|
||||
mCurrent = c.Current = 0;
|
||||
mCount = aHash->Count();
|
||||
if (mCount == 0)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
mElements = c.Elements = new nsISupports*[mCount];
|
||||
c.Data = aData;
|
||||
c.Converter = aConverter;
|
||||
aHash->Enumerate (&hash_enumerator, &c);
|
||||
|
||||
mCount = c.Current; /* some items may not have converted correctly */
|
||||
mDoneFlag = PR_FALSE;
|
||||
|
||||
return NS_OK;
|
||||
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHashtableEnumerator::ReleaseElements()
|
||||
{
|
||||
|
||||
for (; mCount > 0; mCount--)
|
||||
if (mElements[mCount - 1])
|
||||
NS_RELEASE(mElements[mCount - 1]);
|
||||
|
||||
delete[] mElements;
|
||||
mElements = nsnull;
|
||||
|
||||
return NS_OK;
|
||||
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS2(nsHashtableEnumerator, nsIBidirectionalEnumerator, nsIEnumerator)
|
||||
|
||||
nsHashtableEnumerator::~nsHashtableEnumerator()
|
||||
{
|
||||
ReleaseElements();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHashtableEnumerator::First ()
|
||||
{
|
||||
if (!mElements || (mCount == 0))
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
mCurrent = 0;
|
||||
mDoneFlag = PR_FALSE;
|
||||
|
||||
return NS_OK;
|
||||
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHashtableEnumerator::Last ()
|
||||
{
|
||||
if (!mElements || (mCount == 0))
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
mCurrent = mCount - 1;
|
||||
mDoneFlag = PR_FALSE;
|
||||
|
||||
return NS_OK;
|
||||
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHashtableEnumerator::Prev ()
|
||||
{
|
||||
if (!mElements || (mCount == 0) || (mCurrent == 0)) {
|
||||
mDoneFlag = PR_TRUE;
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
mCurrent--;
|
||||
mDoneFlag = PR_FALSE;
|
||||
|
||||
return NS_OK;
|
||||
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHashtableEnumerator::Next ()
|
||||
{
|
||||
if (!mElements || (mCount == 0) || (mCurrent == mCount - 1)) {
|
||||
mDoneFlag = PR_TRUE;
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
mCurrent++;
|
||||
mDoneFlag = PR_FALSE;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHashtableEnumerator::CurrentItem (nsISupports **retval)
|
||||
{
|
||||
NS_PRECONDITION (retval, "null ptr");
|
||||
NS_PRECONDITION (mElements, "invalid state");
|
||||
NS_ASSERTION (mCurrent >= 0, "mCurrent less than zero");
|
||||
|
||||
if (mCount == 0)
|
||||
{
|
||||
*retval = nsnull;
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_ASSERTION (mCurrent <= mCount - 1, "mCurrent too high");
|
||||
|
||||
*retval = mElements[mCurrent];
|
||||
|
||||
/* who says the item can't be null? */
|
||||
if (*retval)
|
||||
NS_ADDREF(*retval);
|
||||
|
||||
return NS_OK;
|
||||
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHashtableEnumerator::IsDone ()
|
||||
{
|
||||
|
||||
if ((!mElements) || (mCount == 0) || (mDoneFlag))
|
||||
return NS_OK;
|
||||
|
||||
return NS_COMFALSE;
|
||||
}
|
||||
47
mozilla/xpcom/ds/nsHashtableEnumerator.h
Normal file
47
mozilla/xpcom/ds/nsHashtableEnumerator.h
Normal file
@@ -0,0 +1,47 @@
|
||||
/* -*- 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):
|
||||
*/
|
||||
|
||||
/*
|
||||
* This class can be used to expose nsI(BiDirectional)Enumerator interfaces
|
||||
* around nsHashtable objects.
|
||||
* Contributed by Rob Ginda, rginda@ix.netcom.com
|
||||
*/
|
||||
|
||||
#ifndef nsHashtableEnumerator_h___
|
||||
#define nsHashtableEnumerator_h___
|
||||
|
||||
#include "nscore.h"
|
||||
#include "nsIEnumerator.h"
|
||||
#include "nsHashtable.h"
|
||||
|
||||
typedef NS_CALLBACK(NS_HASH_ENUMERATOR_CONVERTER) (nsHashKey *key, void *data,
|
||||
void *convert_data,
|
||||
nsISupports **retval);
|
||||
|
||||
extern "C" NS_COM nsresult
|
||||
NS_NewHashtableEnumerator (nsHashtable *aHash,
|
||||
NS_HASH_ENUMERATOR_CONVERTER aConverter,
|
||||
void *aData, nsIEnumerator **retval);
|
||||
|
||||
|
||||
#endif /* nsHashtableEnumerator_h___ */
|
||||
|
||||
1857
mozilla/xpcom/ds/nsString.cpp
Normal file
1857
mozilla/xpcom/ds/nsString.cpp
Normal file
File diff suppressed because it is too large
Load Diff
170
mozilla/xpcom/glue/nsIGenericFactory.h
Normal file
170
mozilla/xpcom/glue/nsIGenericFactory.h
Normal file
@@ -0,0 +1,170 @@
|
||||
/* -*- Mode: C++; tab-width: 4; 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):
|
||||
*/
|
||||
|
||||
#ifndef nsIGenericFactory_h___
|
||||
#define nsIGenericFactory_h___
|
||||
|
||||
#include "nsIFactory.h"
|
||||
|
||||
// {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_PROGID "component:/netscape/generic-factory"
|
||||
#define NS_GENERICFACTORY_CLASSNAME "Generic Factory"
|
||||
/**
|
||||
* Provides a Generic nsIFactory implementation that can be used by
|
||||
* DLLs with very simple factory needs.
|
||||
*/
|
||||
class nsIGenericFactory : public nsIFactory {
|
||||
public:
|
||||
static const nsIID& GetIID() { static nsIID iid = NS_IGENERICFACTORY_IID; return iid; }
|
||||
|
||||
typedef NS_CALLBACK(ConstructorProcPtr) (nsISupports *aOuter, REFNSIID aIID, void **aResult);
|
||||
typedef NS_CALLBACK(DestructorProcPtr) (void);
|
||||
|
||||
/**
|
||||
* Establishes the generic factory's constructor function, which will be called
|
||||
* by CreateInstance.
|
||||
*/
|
||||
NS_IMETHOD SetConstructor(ConstructorProcPtr constructor) = 0;
|
||||
|
||||
/**
|
||||
* Establishes the generic factory's destructor function, which will be called
|
||||
* whe the generic factory is deleted. This is used to notify the DLL that
|
||||
* an instance of one of its generic factories is going away.
|
||||
*/
|
||||
NS_IMETHOD SetDestructor(DestructorProcPtr destructor) = 0;
|
||||
};
|
||||
|
||||
extern NS_COM nsresult
|
||||
NS_NewGenericFactory(nsIGenericFactory* *result,
|
||||
nsIGenericFactory::ConstructorProcPtr constructor,
|
||||
nsIGenericFactory::DestructorProcPtr destructor = NULL);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Generic Modules
|
||||
//
|
||||
// (See xpcom/sample/nsSampleModule.cpp to see how to use this.)
|
||||
|
||||
#include "nsIModule.h"
|
||||
|
||||
/**
|
||||
* Use this type to define a list of module component info to pass to
|
||||
* NS_NewGenericModule. E.g.:
|
||||
* static nsModuleComponentInfo components[] = { ... };
|
||||
* See xpcom/sample/nsSampleModule.cpp for more info.
|
||||
*/
|
||||
struct nsModuleComponentInfo {
|
||||
const char* mDescription;
|
||||
nsCID mCID;
|
||||
const char* mProgID;
|
||||
nsIGenericFactory::ConstructorProcPtr mConstructor;
|
||||
};
|
||||
|
||||
extern NS_COM nsresult
|
||||
NS_NewGenericModule(const char* moduleName,
|
||||
PRUint32 componentCount,
|
||||
nsModuleComponentInfo* components,
|
||||
nsIModule* *result);
|
||||
|
||||
#define NS_IMPL_NSGETMODULE(_name, _components) \
|
||||
extern "C" NS_EXPORT nsresult NSGetModule(nsIComponentManager *servMgr, \
|
||||
nsIFileSpec* location, \
|
||||
nsIModule** result) \
|
||||
{ \
|
||||
return NS_NewGenericModule((_name), \
|
||||
sizeof(_components) / sizeof(_components[0]), \
|
||||
(_components), result); \
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define NS_GENERIC_FACTORY_CONSTRUCTOR(_InstanceClass) \
|
||||
static NS_IMETHODIMP \
|
||||
_InstanceClass##Constructor(nsISupports *aOuter, REFNSIID aIID, void **aResult) \
|
||||
{ \
|
||||
nsresult rv; \
|
||||
\
|
||||
_InstanceClass * inst; \
|
||||
\
|
||||
if (NULL == aResult) { \
|
||||
rv = NS_ERROR_NULL_POINTER; \
|
||||
return rv; \
|
||||
} \
|
||||
*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; \
|
||||
\
|
||||
if (NULL == aResult) { \
|
||||
rv = NS_ERROR_NULL_POINTER; \
|
||||
return rv; \
|
||||
} \
|
||||
*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; \
|
||||
} \
|
||||
|
||||
#endif /* nsIGenericFactory_h___ */
|
||||
84
mozilla/xpcom/io/Makefile.in
Normal file
84
mozilla/xpcom/io/Makefile.in
Normal file
@@ -0,0 +1,84 @@
|
||||
#
|
||||
# The contents of this file are subject to the Netscape Public License
|
||||
# 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) 1998 Netscape Communications Corporation. All Rights
|
||||
# Reserved.
|
||||
#
|
||||
|
||||
DEPTH = ../..
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
MODULE = xpcom
|
||||
XPIDL_MODULE = xpcom_io
|
||||
LIBRARY_NAME = xpcomio_s
|
||||
|
||||
REQUIRES = xpcom uconv unicharutil
|
||||
|
||||
CPPSRCS = \
|
||||
nsEscape.cpp \
|
||||
nsFileSpec.cpp \
|
||||
nsFileSpecStreaming.cpp \
|
||||
nsFileStream.cpp \
|
||||
nsFileSpecImpl.cpp \
|
||||
nsIFileStream.cpp \
|
||||
nsIStringStream.cpp \
|
||||
nsSegmentedBuffer.cpp \
|
||||
nsPipe2.cpp \
|
||||
nsSpecialSystemDirectory.cpp \
|
||||
nsUnicharInputStream.cpp \
|
||||
nsBinaryStream.cpp \
|
||||
nsStorageStream.cpp \
|
||||
$(NULL)
|
||||
|
||||
EXPORTS = \
|
||||
nsEscape.h \
|
||||
nsFileSpec.h \
|
||||
nsFileSpecStreaming.h \
|
||||
nsFileStream.h \
|
||||
nsIFileStream.h \
|
||||
nsIStringStream.h \
|
||||
nsIUnicharInputStream.h \
|
||||
nsSpecialSystemDirectory.h \
|
||||
$(NULL)
|
||||
|
||||
XPIDLSRCS = \
|
||||
nsIPipe.idl \
|
||||
nsIFileSpec.idl \
|
||||
nsIBaseStream.idl \
|
||||
nsIInputStream.idl \
|
||||
nsIOutputStream.idl \
|
||||
nsIBufferInputStream.idl \
|
||||
nsIBufferOutputStream.idl \
|
||||
nsIBinaryInputStream.idl \
|
||||
nsIBinaryOutputStream.idl \
|
||||
nsIStorageStream.idl \
|
||||
$(NULL)
|
||||
|
||||
EXPORTS := $(addprefix $(srcdir)/, $(EXPORTS))
|
||||
|
||||
# we don't want the shared lib, but we want to force the creation of a static lib.
|
||||
override NO_SHARED_LIB=1
|
||||
override NO_STATIC_LIB=
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
DEFINES += -D_IMPL_NS_COM -D_IMPL_NS_BASE
|
||||
|
||||
ifeq ($(OS_ARCH), Linux)
|
||||
DEFINES += -D_BSD_SOURCE
|
||||
endif
|
||||
|
||||
91
mozilla/xpcom/io/makefile.win
Normal file
91
mozilla/xpcom/io/makefile.win
Normal file
@@ -0,0 +1,91 @@
|
||||
#!nmake
|
||||
#
|
||||
# The contents of this file are subject to the Netscape Public License
|
||||
# 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) 1998 Netscape Communications Corporation. All Rights
|
||||
# Reserved.
|
||||
|
||||
|
||||
|
||||
DEPTH=..\..
|
||||
MODULE = xpcom
|
||||
|
||||
################################################################################
|
||||
## exports
|
||||
|
||||
EXPORTS = \
|
||||
nsEscape.h \
|
||||
nsFileSpec.h \
|
||||
nsFileSpecStreaming.h \
|
||||
nsFileStream.h \
|
||||
nsIFileStream.h \
|
||||
nsIStringStream.h \
|
||||
nsIUnicharInputStream.h \
|
||||
nsSpecialSystemDirectory.h \
|
||||
nsStorageStream.h \
|
||||
$(NULL)
|
||||
|
||||
NO_XPT_GEN=1
|
||||
XPIDL_MODULE = xpcom_io
|
||||
|
||||
XPIDLSRCS = \
|
||||
.\nsIPipe.idl \
|
||||
.\nsIFileSpec.idl \
|
||||
.\nsIBaseStream.idl \
|
||||
.\nsIBinaryInputStream.idl \
|
||||
.\nsIBinaryOutputStream.idl \
|
||||
.\nsIInputStream.idl \
|
||||
.\nsIOutputStream.idl \
|
||||
.\nsIBufferInputStream.idl \
|
||||
.\nsIBufferOutputStream.idl \
|
||||
.\nsIStorageStream.idl \
|
||||
$(NULL)
|
||||
|
||||
################################################################################
|
||||
## library
|
||||
|
||||
LIBRARY_NAME=xpcomio_s
|
||||
|
||||
LINCS = \
|
||||
-I$(PUBLIC)\xpcom \
|
||||
-I$(PUBLIC)\uconv \
|
||||
-I$(PUBLIC)\unicharutil \
|
||||
$(NULL)
|
||||
|
||||
LINCS = $(LINCS) -I$(PUBLIC)\raptor # until we sort out the filespec/widgets dependency
|
||||
|
||||
LCFLAGS = -D_IMPL_NS_COM -D_IMPL_NS_BASE -DWIN32_LEAN_AND_MEAN
|
||||
|
||||
CPP_OBJS = \
|
||||
.\$(OBJDIR)\nsBinaryStream.obj \
|
||||
.\$(OBJDIR)\nsEscape.obj \
|
||||
.\$(OBJDIR)\nsFileSpec.obj \
|
||||
.\$(OBJDIR)\nsFileSpecImpl.obj \
|
||||
.\$(OBJDIR)\nsFileSpecStreaming.obj \
|
||||
.\$(OBJDIR)\nsFileStream.obj \
|
||||
.\$(OBJDIR)\nsIFileStream.obj \
|
||||
.\$(OBJDIR)\nsIStringStream.obj \
|
||||
.\$(OBJDIR)\nsSegmentedBuffer.obj \
|
||||
.\$(OBJDIR)\nsPipe2.obj \
|
||||
.\$(OBJDIR)\nsSpecialSystemDirectory.obj \
|
||||
.\$(OBJDIR)\nsStorageStream.obj \
|
||||
.\$(OBJDIR)\nsUnicharInputStream.obj \
|
||||
$(NULL)
|
||||
|
||||
include <$(DEPTH)\config\rules.mak>
|
||||
|
||||
libs:: $(LIBRARY)
|
||||
$(MAKE_INSTALL) $(LIBRARY) $(DIST)\lib
|
||||
|
||||
clobber::
|
||||
rm -f $(DIST)\lib\$(LIBRARY_NAME).lib
|
||||
361
mozilla/xpcom/io/nsBinaryStream.cpp
Normal file
361
mozilla/xpcom/io/nsBinaryStream.cpp
Normal file
@@ -0,0 +1,361 @@
|
||||
/* -*- Mode: C++; tab-width: 4; 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 Communicator client code, released
|
||||
* March 31, 1998.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998-1999 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* 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 "nsBinaryStream.h"
|
||||
#include "nsIAllocator.h"
|
||||
|
||||
// Swap macros, used to convert to/from canonical (big-endian) format
|
||||
#ifdef IS_LITTLE_ENDIAN
|
||||
# define SWAP16(x) ((((x) & 0xff) << 8) | (((x) >> 8) & 0xff))
|
||||
# define SWAP32(x) ((SWAP16((x) & 0xffff) << 16) | (SWAP16((x) >> 16)))
|
||||
#else
|
||||
# ifndef IS_BIG_ENDIAN
|
||||
# error "Unknown endianness"
|
||||
# endif
|
||||
# define SWAP16(x) (x)
|
||||
# define SWAP32(x) (x)
|
||||
#endif
|
||||
|
||||
nsBinaryOutputStream::nsBinaryOutputStream(nsIOutputStream* aStream): mOutputStream(aStream)
|
||||
{
|
||||
NS_INIT_REFCNT();
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsBinaryOutputStream, NS_GET_IID(nsIBinaryOutputStream))
|
||||
|
||||
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::SetOutputStream(nsIOutputStream *aOutputStream)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aOutputStream);
|
||||
mOutputStream = aOutputStream;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBinaryOutputStream::WriteBoolean(PRBool aBoolean)
|
||||
{
|
||||
return Write8(aBoolean);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBinaryOutputStream::Write8(PRUint8 aByte)
|
||||
{
|
||||
nsresult rv;
|
||||
PRUint32 bytesWritten;
|
||||
|
||||
rv = Write((const char*)&aByte, sizeof aByte, &bytesWritten);
|
||||
if (bytesWritten != sizeof aByte)
|
||||
return NS_ERROR_FAILURE;
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBinaryOutputStream::Write16(PRUint16 a16)
|
||||
{
|
||||
nsresult rv;
|
||||
PRUint32 bytesWritten;
|
||||
|
||||
a16 = SWAP16(a16);
|
||||
rv = Write((const char*)&a16, sizeof a16, &bytesWritten);
|
||||
if (bytesWritten != sizeof a16)
|
||||
return NS_ERROR_FAILURE;
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBinaryOutputStream::Write32(PRUint32 a32)
|
||||
{
|
||||
nsresult rv;
|
||||
PRUint32 bytesWritten;
|
||||
|
||||
a32 = SWAP32(a32);
|
||||
rv = Write((const char*)&a32, sizeof a32, &bytesWritten);
|
||||
if (bytesWritten != sizeof a32)
|
||||
return NS_ERROR_FAILURE;
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBinaryOutputStream::Write64(PRUint64 a64)
|
||||
{
|
||||
nsresult rv;
|
||||
PRUint32* raw32 = (PRUint32*)&a64;
|
||||
|
||||
#ifdef IS_BIG_ENDIAN
|
||||
rv = Write32(raw32[0]);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
return Write32(raw32[1]);
|
||||
#else
|
||||
rv = Write32(raw32[1]);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
return Write32(raw32[0]);
|
||||
#endif
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBinaryOutputStream::WriteWStringZ(const PRUnichar* aString)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBinaryOutputStream::WriteUtf8Z(const PRUnichar* aString)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBinaryOutputStream::WriteBytes(const char *aString, PRUint32 aLength)
|
||||
{
|
||||
nsresult rv;
|
||||
PRUint32 bytesWritten;
|
||||
|
||||
rv = Write(aString, aLength, &bytesWritten);
|
||||
if (bytesWritten != aLength)
|
||||
return NS_ERROR_FAILURE;
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBinaryOutputStream::WriteString(nsString* aString)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
nsBinaryInputStream::nsBinaryInputStream(nsIInputStream* aStream): mInputStream(aStream) { NS_INIT_REFCNT(); }
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsBinaryInputStream, NS_GET_IID(nsIBinaryInputStream))
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBinaryInputStream::Close() { return mInputStream->Close(); }
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBinaryInputStream::SetInputStream(nsIInputStream *aInputStream)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aInputStream);
|
||||
mInputStream = 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((char*)aByte, sizeof(*aByte), &bytesRead);
|
||||
if (bytesRead != sizeof (*aByte))
|
||||
return NS_ERROR_FAILURE;
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBinaryInputStream::Read16(PRUint16* a16)
|
||||
{
|
||||
nsresult rv;
|
||||
PRUint32 bytesRead;
|
||||
|
||||
rv = Read((char*)a16, sizeof *a16, &bytesRead);
|
||||
if (bytesRead != sizeof *a16)
|
||||
return NS_ERROR_FAILURE;
|
||||
*a16 = SWAP16(*a16);
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBinaryInputStream::Read32(PRUint32* a32)
|
||||
{
|
||||
nsresult rv;
|
||||
PRUint32 bytesRead;
|
||||
|
||||
rv = Read((char*)a32, sizeof *a32, &bytesRead);
|
||||
if (bytesRead != sizeof *a32)
|
||||
return NS_ERROR_FAILURE;
|
||||
*a32 = SWAP32(*a32);
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBinaryInputStream::Read64(PRUint64* a64)
|
||||
{
|
||||
nsresult rv;
|
||||
PRUint32* raw32 = (PRUint32*)a64;
|
||||
|
||||
#ifdef IS_BIG_ENDIAN
|
||||
rv = Read32(&raw32[0]);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
return Read32(&raw32[1]);
|
||||
#else
|
||||
rv = Read32(&raw32[1]);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
return Read32(&raw32[0]);
|
||||
#endif
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBinaryInputStream::ReadStringZ(char* *aString)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBinaryInputStream::ReadWStringZ(PRUnichar* *aString)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBinaryInputStream::ReadUtf8Z(PRUnichar* *aString)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBinaryInputStream::ReadBytes(char* *aString, PRUint32 aLength)
|
||||
{
|
||||
nsresult rv;
|
||||
PRUint32 bytesRead;
|
||||
char* s;
|
||||
|
||||
s = (char*)nsAllocator::Alloc(aLength);
|
||||
if (!s)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
rv = Read(s, aLength, &bytesRead);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
if (bytesRead != aLength)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
*aString = s;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBinaryInputStream::ReadString(nsString* *aString)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_COM nsresult
|
||||
NS_NewBinaryOutputStream(nsIBinaryOutputStream* *aResult, nsIOutputStream* aDestStream)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aResult);
|
||||
nsIBinaryOutputStream *stream = new nsBinaryOutputStream(aDestStream);
|
||||
if (!stream)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
NS_ADDREF(stream);
|
||||
*aResult = stream;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_COM nsresult
|
||||
NS_NewBinaryInputStream(nsIBinaryInputStream* *aResult, nsIInputStream* aSrcStream)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aResult);
|
||||
nsIBinaryInputStream *stream = new nsBinaryInputStream(aSrcStream);
|
||||
if (!stream)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
NS_ADDREF(stream);
|
||||
*aResult = stream;
|
||||
return NS_OK;
|
||||
}
|
||||
72
mozilla/xpcom/io/nsBinaryStream.h
Normal file
72
mozilla/xpcom/io/nsBinaryStream.h
Normal file
@@ -0,0 +1,72 @@
|
||||
/* -*- Mode: C++; tab-width: 4; 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 Communicator client code, released
|
||||
* March 31, 1998.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998-1999 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "nsIBinaryInputStream.h"
|
||||
#include "nsIBinaryOutputStream.h"
|
||||
#include "nsCOMPtr.h"
|
||||
|
||||
class nsBinaryOutputStream : public nsIBinaryOutputStream
|
||||
{
|
||||
public:
|
||||
nsBinaryOutputStream(nsIOutputStream *aStream);
|
||||
virtual ~nsBinaryOutputStream() {};
|
||||
|
||||
private:
|
||||
|
||||
// nsISupports methods
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
// nsIBaseStream methods
|
||||
NS_DECL_NSIBASESTREAM
|
||||
|
||||
// nsIOutputStream methods
|
||||
NS_DECL_NSIOUTPUTSTREAM
|
||||
|
||||
// nsIBinaryOutputStream methods
|
||||
NS_DECL_NSIBINARYOUTPUTSTREAM
|
||||
|
||||
protected:
|
||||
nsCOMPtr<nsIOutputStream> mOutputStream;
|
||||
};
|
||||
|
||||
class nsBinaryInputStream : public nsIBinaryInputStream
|
||||
{
|
||||
public:
|
||||
nsBinaryInputStream(nsIInputStream *aStream);
|
||||
virtual ~nsBinaryInputStream() {};
|
||||
|
||||
private:
|
||||
// nsISupports methods
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
// nsIBaseStream methods
|
||||
NS_DECL_NSIBASESTREAM
|
||||
|
||||
// nsIInputStream methods
|
||||
NS_DECL_NSIINPUTSTREAM
|
||||
|
||||
// nsIBinaryInputStream methods
|
||||
NS_DECL_NSIBINARYINPUTSTREAM
|
||||
|
||||
protected:
|
||||
nsCOMPtr<nsIInputStream> mInputStream;
|
||||
};
|
||||
|
||||
806
mozilla/xpcom/io/nsFileSpec.h
Normal file
806
mozilla/xpcom/io/nsFileSpec.h
Normal file
@@ -0,0 +1,806 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* 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) 1998 Netscape Communications Corporation. All Rights
|
||||
* Reserved.
|
||||
*/
|
||||
|
||||
// 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. Oh, and a convenience class nsAutoCString.
|
||||
//
|
||||
// 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 "nscore.h"
|
||||
#include "nsError.h"
|
||||
#include "nsString.h"
|
||||
#include "nsCRT.h"
|
||||
#include "prtypes.h"
|
||||
|
||||
//========================================================================================
|
||||
// Compiler-specific macros, as needed
|
||||
//========================================================================================
|
||||
#if !defined(NS_USING_NAMESPACE) && (defined(__MWERKS__) || defined(XP_PC))
|
||||
#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 ===============================
|
||||
|
||||
#ifdef XP_MAC
|
||||
#include <Files.h>
|
||||
#elif defined(XP_UNIX) || defined (XP_OS2) || defined(XP_BEOS)
|
||||
#include <dirent.h>
|
||||
#elif defined(XP_PC)
|
||||
|
||||
// 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"
|
||||
#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 nsString;
|
||||
|
||||
//========================================================================================
|
||||
// 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 NS_COM nsAutoCString
|
||||
//
|
||||
// This should be in nsString.h, but the owner would not reply to my proposal. After four
|
||||
// weeks, I decided to put it in here.
|
||||
//
|
||||
// This is a quiet little class that acts as a sort of autoptr for
|
||||
// a const char*. If you used to call nsString::ToNewCString(), just
|
||||
// to pass the result a parameter list, it was a nuisance having to
|
||||
// call delete [] on the result after the call. Now you can say
|
||||
// nsString myStr;
|
||||
// ...
|
||||
// f(nsAutoCString(myStr));
|
||||
// where f is declared as void f(const char*); This call will
|
||||
// make a temporary char* pointer on the stack and delete[] it
|
||||
// when the function returns.
|
||||
//========================================================================================
|
||||
{
|
||||
public:
|
||||
NS_EXPLICIT nsAutoCString(const nsString& other) : mCString(other.ToNewCString()) {}
|
||||
virtual ~nsAutoCString();
|
||||
operator const char*() const { return mCString; }
|
||||
|
||||
// operator const char*() { return mCString; }
|
||||
// don't need this, since |operator const char*() const| can
|
||||
// serve for both |const| and non-|const| callers
|
||||
protected:
|
||||
const char* mCString;
|
||||
}; // class nsAutoCString
|
||||
|
||||
//========================================================================================
|
||||
class NS_COM 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 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);
|
||||
NS_EXPLICIT nsFileSpec(const nsPersistentFileDescriptor& inURL);
|
||||
nsFileSpec(const nsFileSpec& inPath);
|
||||
virtual ~nsFileSpec();
|
||||
|
||||
// These two operands take *native* file paths.
|
||||
void operator = (const char* inNativePath);
|
||||
void operator = (const nsString& inNativePath)
|
||||
{
|
||||
const nsAutoCString path(inNativePath);
|
||||
*this = path;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
#ifdef 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
|
||||
{
|
||||
#ifndef 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().
|
||||
|
||||
#if 0
|
||||
// needs implementing
|
||||
// copy the leaf name into the supplied buffer, thus
|
||||
// getting a copy without allocation. Buffer should be
|
||||
// 64 chars big.
|
||||
void GetLeafNameCopy(char* destBuffer, PRInt32 bufferSize) const;
|
||||
#endif
|
||||
// inLeafName can be a relative path, so this allows
|
||||
// one kind of concatenation of "paths".
|
||||
void SetLeafName(const char* inLeafName);
|
||||
void SetLeafName(const nsString& inLeafName)
|
||||
{
|
||||
const nsAutoCString leafName(inLeafName);
|
||||
SetLeafName(leafName);
|
||||
}
|
||||
|
||||
// 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;
|
||||
nsFileSpec operator + (const nsString& inRelativeUnixPath) const
|
||||
{
|
||||
const nsAutoCString
|
||||
relativePath(inRelativeUnixPath);
|
||||
return *this + relativePath;
|
||||
}
|
||||
|
||||
// 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 operator += (const nsString& inRelativeUnixPath)
|
||||
{
|
||||
const nsAutoCString relativePath(inRelativeUnixPath);
|
||||
*this += relativePath;
|
||||
}
|
||||
|
||||
void MakeUnique();
|
||||
void MakeUnique(const char* inSuggestedLeafName);
|
||||
void MakeUnique(const nsString& inSuggestedLeafName)
|
||||
{
|
||||
const nsAutoCString suggestedLeafName(inSuggestedLeafName);
|
||||
MakeUnique(suggestedLeafName);
|
||||
}
|
||||
|
||||
|
||||
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 = 0700 /* for unix */);
|
||||
void CreateDir(int mode = 0700) { CreateDirectory(mode); }
|
||||
// workaround for yet another VC++ bug with long identifiers.
|
||||
void Delete(PRBool inRecursive) const;
|
||||
void RecursiveCopy(nsFileSpec newDir) const;
|
||||
|
||||
nsresult Truncate(const PRInt32 offset) const;
|
||||
nsresult Rename(const char* inNewName); // not const: gets updated
|
||||
nsresult Rename(const nsString& inNewName)
|
||||
{
|
||||
const nsAutoCString newName(inNewName);
|
||||
return Rename(newName);
|
||||
}
|
||||
nsresult CopyToDir(const nsFileSpec& inNewParentDirectory) const;
|
||||
nsresult MoveToDir(const nsFileSpec& inNewParentDirectory);
|
||||
nsresult Execute(const char* args) const;
|
||||
nsresult Execute(const nsString& args) const
|
||||
{
|
||||
const nsAutoCString argsString(args);
|
||||
return Execute(argsString);
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// Data
|
||||
//--------------------------------------------------
|
||||
|
||||
protected:
|
||||
|
||||
// Clear the nsFileSpec contents, resetting it
|
||||
// to the uninitialized state;
|
||||
void Clear();
|
||||
|
||||
friend class nsFilePath;
|
||||
friend class nsFileURL;
|
||||
friend class nsDirectoryIterator;
|
||||
#ifdef XP_MAC
|
||||
FSSpec mSpec;
|
||||
#endif
|
||||
nsSimpleCharString mPath;
|
||||
nsresult mError;
|
||||
|
||||
}; // class nsFileSpec
|
||||
|
||||
// FOR HISTORICAL REASONS:
|
||||
|
||||
typedef nsFileSpec nsNativeFileSpec;
|
||||
|
||||
//========================================================================================
|
||||
class NS_COM 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)
|
||||
{
|
||||
const nsAutoCString string(inURLString);
|
||||
*this = string;
|
||||
}
|
||||
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.
|
||||
|
||||
#ifdef 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;
|
||||
|
||||
#ifdef 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 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)
|
||||
{
|
||||
const nsAutoCString string(inUnixPathString);
|
||||
*this = string;
|
||||
}
|
||||
void operator = (const nsFileURL& inURL);
|
||||
void operator = (const nsFileSpec& inOther);
|
||||
|
||||
void operator +=(const char* inRelativeUnixPath);
|
||||
nsFilePath operator +(const char* inRelativeUnixPath) const;
|
||||
|
||||
#ifdef XP_MAC
|
||||
public:
|
||||
// Accessor to allow quick assignment to a mFileSpec
|
||||
const nsFileSpec& GetFileSpec() const { return mFileSpec; }
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------
|
||||
// Data
|
||||
//--------------------------------------------------
|
||||
|
||||
private:
|
||||
|
||||
nsSimpleCharString mPath;
|
||||
#ifdef 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 NS_COM 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 nsInputStream& operator >> (nsInputStream&, nsPersistentFileDescriptor&);
|
||||
// reads the data from a file
|
||||
friend NS_COM nsOutputStream& operator << (nsOutputStream&, const nsPersistentFileDescriptor&);
|
||||
// writes the data to a file
|
||||
friend class nsFileSpec;
|
||||
|
||||
void GetData(nsSimpleCharString& outData) const;
|
||||
void SetData(const nsSimpleCharString& inData);
|
||||
void GetData(nsSimpleCharString& outData, PRInt32& outSize) const;
|
||||
void SetData(const nsSimpleCharString& inData, PRInt32 inSize);
|
||||
void SetData(const char* inData, PRInt32 inSize);
|
||||
|
||||
//--------------------------------------------------
|
||||
// Data
|
||||
//--------------------------------------------------
|
||||
|
||||
protected:
|
||||
|
||||
nsSimpleCharString mDescriptorString;
|
||||
|
||||
}; // class nsPersistentFileDescriptor
|
||||
|
||||
//========================================================================================
|
||||
class NS_COM 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);
|
||||
#ifndef 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_PC)
|
||||
nsFileSpec mStarting;
|
||||
#endif
|
||||
|
||||
#if defined(XP_UNIX) || defined(XP_BEOS)
|
||||
DIR* mDir;
|
||||
#elif defined(XP_PC)
|
||||
PRDir* mDir; // XXX why not use PRDir for Unix too?
|
||||
#elif defined(XP_MAC)
|
||||
short mVRefNum;
|
||||
long mParID;
|
||||
short mIndex;
|
||||
short mMaxIndex;
|
||||
#endif
|
||||
}; // class nsDirectoryIterator
|
||||
|
||||
//========================================================================================
|
||||
class NS_COM 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_PC
|
||||
}; // class nsNSPRPath
|
||||
|
||||
#endif // _FILESPEC_H_
|
||||
781
mozilla/xpcom/io/nsFileSpecImpl.cpp
Normal file
781
mozilla/xpcom/io/nsFileSpecImpl.cpp
Normal file
@@ -0,0 +1,781 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* 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) 1998 Netscape Communications Corporation. All Rights
|
||||
* Reserved.
|
||||
*/
|
||||
|
||||
#include "nsFileSpecImpl.h"// Always first, to ensure that it compiles alone.
|
||||
|
||||
#include "nsIFileStream.h"
|
||||
#include "nsFileStream.h"
|
||||
|
||||
#include "prmem.h"
|
||||
|
||||
NS_IMPL_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_INIT_ISUPPORTS();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------
|
||||
nsFileSpecImpl::nsFileSpecImpl(const nsFileSpec& inSpec)
|
||||
//----------------------------------------------------------------------------------------
|
||||
: mFileSpec(inSpec)
|
||||
, mInputStream(nsnull)
|
||||
, mOutputStream(nsnull)
|
||||
{
|
||||
NS_INIT_ISUPPORTS();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------
|
||||
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(nsIFileSpec::GetIID(), (void **) result);
|
||||
} // nsFileSpecImpl::MakeInterface
|
||||
|
||||
#define FILESPEC(ifilespec) ((nsFileSpecImpl*)ifilespec)->mFileSpec
|
||||
|
||||
//----------------------------------------------------------------------------------------
|
||||
NS_IMETHODIMP nsFileSpecImpl::FromFileSpec(const nsIFileSpec *original)
|
||||
//----------------------------------------------------------------------------------------
|
||||
{
|
||||
mFileSpec = FILESPEC(original);
|
||||
return mFileSpec.Error();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------
|
||||
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);
|
||||
nsSimpleCharString data;
|
||||
desc.GetData(data);
|
||||
*aPersistentDescriptorString = nsCRT::strdup((const char*) data);
|
||||
if (!*aPersistentDescriptorString)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------
|
||||
NS_IMETHODIMP nsFileSpecImpl::SetPersistentDescriptorString(const char * aPersistentDescriptorString)
|
||||
//----------------------------------------------------------------------------------------
|
||||
{
|
||||
nsPersistentFileDescriptor desc(mFileSpec);
|
||||
desc.SetData(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 = OpenStreamForReadingAndWriting();
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
rv = CloseStream();
|
||||
return rv;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------
|
||||
NS_IMETHODIMP nsFileSpecImpl::CreateDir()
|
||||
//----------------------------------------------------------------------------------------
|
||||
{
|
||||
mFileSpec.CreateDir();
|
||||
return mFileSpec.Error();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------
|
||||
NS_IMETHODIMP nsFileSpecImpl::Truncate(const PRInt32 offset)
|
||||
//----------------------------------------------------------------------------------------
|
||||
{
|
||||
return mFileSpec.Truncate(offset);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------
|
||||
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::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)
|
||||
{
|
||||
NS_INIT_ISUPPORTS();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------
|
||||
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_METHOD 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_METHOD 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, nsIFileSpec::GetIID(), (void**)result);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------
|
||||
nsresult NS_NewDirectoryIterator(nsIDirectoryIterator** result)
|
||||
//----------------------------------------------------------------------------------------
|
||||
{
|
||||
return nsDirectoryIteratorImpl::Create(nsnull, nsIDirectoryIterator::GetIID(), (void**)result);
|
||||
}
|
||||
|
||||
603
mozilla/xpcom/io/nsFileSpecUnix.cpp
Normal file
603
mozilla/xpcom/io/nsFileSpecUnix.cpp
Normal file
@@ -0,0 +1,603 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* 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) 1998 Netscape Communications Corporation. All Rights
|
||||
* Reserved.
|
||||
*/
|
||||
|
||||
// This file is included by nsFileSpec.cpp, and includes the Unix-specific
|
||||
// implementations.
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <sys/param.h>
|
||||
#include <errno.h>
|
||||
#include <dirent.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <limits.h>
|
||||
#include "nsError.h"
|
||||
#include "prio.h" /* for PR_Rename */
|
||||
|
||||
#if defined(_SCO_DS)
|
||||
#define _SVID3 /* for statvfs.h */
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_STATVFS_H
|
||||
#include <sys/statvfs.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_VFS_H
|
||||
#include <sys/vfs.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_STATFS_H
|
||||
#include <sys/statfs.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_MOUNT_H
|
||||
#include <sys/mount.h>
|
||||
#ifdef __bsdi__
|
||||
#undef Free
|
||||
#endif
|
||||
#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 <unix.h> /* for realpath */
|
||||
#define f_bavail f_bfree
|
||||
#endif
|
||||
|
||||
#if defined(SUNOS4)
|
||||
extern "C" int statfs(char *, struct statfs *);
|
||||
#endif
|
||||
|
||||
#if defined(OSF1)
|
||||
extern "C" int statvfs(const char *, struct statvfs *);
|
||||
#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
|
||||
//----------------------------------------------------------------------------------------
|
||||
{
|
||||
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_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(const PRInt32 offset) const
|
||||
//----------------------------------------------------------------------------------------
|
||||
{
|
||||
char* Path = nsCRT::strdup(mPath);
|
||||
|
||||
PRInt32 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
|
||||
|
||||
LL_I2L( bytes, (fs_buf.f_bsize * (fs_buf.f_bavail - 1) ) );
|
||||
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;
|
||||
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 --
|
||||
726
mozilla/xpcom/io/nsFileSpecWin.cpp
Normal file
726
mozilla/xpcom/io/nsFileSpecWin.cpp
Normal file
@@ -0,0 +1,726 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* 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) 1998 Netscape Communications Corporation. All Rights
|
||||
* Reserved.
|
||||
*/
|
||||
|
||||
// This file is included by nsFileSpec.cp, and includes the Windows-specific
|
||||
// implementations.
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <direct.h>
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
#include "prio.h"
|
||||
#include "nsError.h"
|
||||
|
||||
#include "windows.h"
|
||||
|
||||
#if (_MSC_VER == 1100)
|
||||
#define INITGUID
|
||||
#include "objbase.h"
|
||||
DEFINE_OLEGUID(IID_IPersistFile, 0x0000010BL, 0, 0);
|
||||
#endif
|
||||
|
||||
#include "shlobj.h"
|
||||
#include "shellapi.h"
|
||||
#include "shlguid.h"
|
||||
|
||||
#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 = 0700;
|
||||
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);
|
||||
|
||||
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 == '/')
|
||||
{
|
||||
// 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;
|
||||
|
||||
// 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++)
|
||||
{
|
||||
if (*cp == '\\')
|
||||
*cp = '/';
|
||||
}
|
||||
// Add the slash in front.
|
||||
temp += ioPath;
|
||||
ioPath = temp;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------
|
||||
nsFileSpec::nsFileSpec(const nsFilePath& inPath)
|
||||
//----------------------------------------------------------------------------------------
|
||||
{
|
||||
*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))
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------------------
|
||||
nsresult nsFileSpec::ResolveSymlink(PRBool& wasSymlink)
|
||||
//----------------------------------------------------------------------------------------
|
||||
{
|
||||
wasSymlink = PR_FALSE; // assume failure
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
// 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
|
||||
|
||||
// We have to implement this since there's no truncate() in system.
|
||||
//----------------------------------------------------------------------------------------
|
||||
nsresutl nsFileSpec::Truncate(const PRInt32 offset) const
|
||||
{
|
||||
char* oldPath = nsCRT::strdup(mPath);
|
||||
|
||||
nsFileSpec newFile = *this ;
|
||||
newFile.MakeUnique() ;
|
||||
|
||||
nsInputFileStream inStream(*this) ;
|
||||
nsOutputFileStream outStream(newFile) ;
|
||||
|
||||
PRUint32 buffer_size = 1024, len ;
|
||||
char buffer[buffer_size] ;
|
||||
PRUint32 bytes_read=0, bytes_written=0, size_left = offset ;
|
||||
|
||||
do {
|
||||
if(size_left > buffer_size)
|
||||
len = buffer_size ;
|
||||
else
|
||||
len = size_left ;
|
||||
|
||||
bytes_read = inStream.read((void*)buffer, len) ;
|
||||
|
||||
bytes_written = outStream.write(buffer, bytes_read) ;
|
||||
if(bytes_written != bytes_read)
|
||||
return NS_ERROR_FAILURE ;
|
||||
|
||||
size_left -= bytes_read ;
|
||||
} while(!set_left) ;
|
||||
|
||||
outStream.flush() ;
|
||||
outStream.close() ;
|
||||
inStream.close() ;
|
||||
|
||||
// remove the original file
|
||||
Delete(PR_TRUE) ;
|
||||
|
||||
// rename the new file
|
||||
rv = newFile.Rename(oldPath) ;
|
||||
|
||||
return rv ;
|
||||
|
||||
} // 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 = 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 --
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user