1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
/* ***** BEGIN LICENSE BLOCK *****
3
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
5
* The contents of this file are subject to the Netscape Public License
6
* Version 1.1 (the "License"); you may not use this file except in
7
* compliance with the License. You may obtain a copy of the License at
8
* http://www.mozilla.org/NPL/
10
* Software distributed under the License is distributed on an "AS IS" basis,
11
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12
* for the specific language governing rights and limitations under the
15
* The Original Code is mozilla.org code.
17
* The Initial Developer of the Original Code is
18
* Netscape Communications Corporation.
19
* Portions created by the Initial Developer are Copyright (C) 1999
20
* the Initial Developer. All Rights Reserved.
25
* Alternatively, the contents of this file may be used under the terms of
26
* either the GNU General Public License Version 2 or later (the "GPL"), or
27
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28
* in which case the provisions of the GPL or the LGPL are applicable instead
29
* of those above. If you wish to allow use of your version of this file only
30
* under the terms of either the GPL or the LGPL, and not to allow others to
31
* use your version of this file under the terms of the NPL, indicate your
32
* decision by deleting the provisions above and replace them with the notice
33
* and other provisions required by the GPL or the LGPL. If you do not delete
34
* the provisions above, a recipient may use your version of this file under
35
* the terms of any one of the NPL, the GPL or the LGPL.
37
* ***** END LICENSE BLOCK ***** */
52
#include "morkHandle.h"
60
#include "morkFactory.h"
63
#ifndef _ORKINFACTORY_
64
#include "orkinFactory.h"
84
#include "morkWriter.h"
88
#include "morkStore.h"
92
#include "orkinStore.h"
96
#include "orkinThumb.h"
100
#include "morkThumb.h"
104
#include "orkinHeap.h"
107
#ifndef _ORKINCOMPARE_
108
#include "orkinCompare.h"
111
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
114
orkinFactory:: ~orkinFactory() // morkHandle destructor does everything
118
/*protected non-poly construction*/
119
orkinFactory::orkinFactory(morkEnv* ev, // morkUsage is morkUsage_kPool
120
morkHandleFace* ioFace, // must not be nil, cookie for this handle
121
morkFactory* ioObject) // must not be nil, object for this handle
122
: morkHandle(ev, ioFace, ioObject, morkMagic_kFactory)
124
// do not modify mNode_Derived; leave it equal to morkDerived_kHandle
127
extern "C" nsIMdbFactory* MakeMdbFactory()
129
return orkinFactory::MakeGlobalFactory();
132
/*static */ orkinFactory*
133
orkinFactory::MakeGlobalFactory()
134
// instantiate objects using almost no context information.
136
morkFactory* factory = new morkFactory(new orkinHeap());
137
MORK_ASSERT(factory);
139
return orkinFactory::MakeFactory(&factory->mFactory_Env, factory);
141
return (orkinFactory*) 0;
144
/*static */ orkinFactory*
145
orkinFactory::MakeFactory(morkEnv* ev, morkFactory* ioObject)
147
mork_bool isEnv = ev->IsEnv();
151
morkHandleFace* face = ev->NewHandle(sizeof(orkinFactory));
154
orkinFactory* f = new(face) orkinFactory(ev, face, ioObject);
156
f->mNode_Refs += morkFactory_kWeakRefCountBonus;
160
ev->OutOfMemoryError();
163
return (orkinFactory*) 0;
167
orkinFactory::CanUseFactory(nsIMdbEnv* mev, mork_bool inMutable,
168
mdb_err* outErr) const
171
morkEnv* ev = morkEnv::FromMdbEnv(mev);
174
morkFactory* factory = (morkFactory*)
175
this->GetGoodHandleObject(ev, inMutable, morkMagic_kFactory,
176
/*inClosedOkay*/ morkBool_kFalse);
179
if ( factory->IsFactory() )
182
factory->NonFactoryTypeError(ev);
184
*outErr = ev->AsErr();
190
morkEnv* orkinFactory::GetInternalFactoryEnv(mdb_err* outErr)
193
morkFactory* f = (morkFactory*) this->mHandle_Object;
194
if ( f && f->IsNode() && f->IsOpenNode() && f->IsFactory() )
196
morkEnv* fenv = &f->mFactory_Env;
197
if ( fenv && fenv->IsNode() && fenv->IsOpenNode() && fenv->IsEnv() )
199
fenv->ClearMorkErrorsAndWarnings(); // drop any earlier errors
203
*outErr = morkEnv_kBadFactoryEnvError;
206
*outErr = morkEnv_kBadFactoryError;
211
// { ===== begin nsIMdbISupports methods =====
212
NS_IMPL_QUERY_INTERFACE0(orkinFactory)
215
orkinFactory::AddRef() // add strong ref with no
217
morkEnv* ev = mHandle_Env;
218
if ( ev && ev->IsEnv() )
219
return this->Handle_AddStrongRef(ev->AsMdbEnv());
221
return morkEnv_kNonEnvTypeError;
225
orkinFactory::Release() // cut strong ref
227
morkEnv* ev = mHandle_Env;
228
if ( ev && ev->IsEnv() )
229
return this->Handle_CutStrongRef(ev->AsMdbEnv());
231
return morkEnv_kNonEnvTypeError;
233
// } ===== end nsIMdbObject methods =====
236
// { ===== begin nsIMdbObject methods =====
238
// { ----- begin attribute methods -----
240
orkinFactory::IsFrozenMdbObject(nsIMdbEnv* mev, mdb_bool* outIsReadonly)
242
return this->Handle_IsFrozenMdbObject(mev, outIsReadonly);
244
// same as nsIMdbPort::GetIsPortReadonly() when this object is inside a port.
245
// } ----- end attribute methods -----
247
// { ----- begin factory methods -----
249
orkinFactory::GetMdbFactory(nsIMdbEnv* mev, nsIMdbFactory** acqFactory)
251
return this->Handle_GetMdbFactory(mev, acqFactory);
253
// } ----- end factory methods -----
255
// { ----- begin ref counting for well-behaved cyclic graphs -----
257
orkinFactory::GetWeakRefCount(nsIMdbEnv* mev, // weak refs
260
return this->Handle_GetWeakRefCount(mev, outCount);
263
orkinFactory::GetStrongRefCount(nsIMdbEnv* mev, // strong refs
266
return this->Handle_GetStrongRefCount(mev, outCount);
270
orkinFactory::AddWeakRef(nsIMdbEnv* mev)
272
return this->Handle_AddWeakRef(mev);
275
orkinFactory::AddStrongRef(nsIMdbEnv* mev)
277
return this->Handle_AddStrongRef(mev);
281
orkinFactory::CutWeakRef(nsIMdbEnv* mev)
283
return this->Handle_CutWeakRef(mev);
286
orkinFactory::CutStrongRef(nsIMdbEnv* mev)
288
return this->Handle_CutStrongRef(mev);
292
orkinFactory::CloseMdbObject(nsIMdbEnv* mev)
294
return this->Handle_CloseMdbObject(mev);
298
orkinFactory::IsOpenMdbObject(nsIMdbEnv* mev, mdb_bool* outOpen)
300
return this->Handle_IsOpenMdbObject(mev, outOpen);
302
// } ----- end ref counting -----
304
// } ===== end nsIMdbObject methods =====
306
// { ===== begin nsIMdbFactory methods =====
308
// { ----- begin file methods -----
310
orkinFactory::OpenOldFile(nsIMdbEnv* mev, nsIMdbHeap* ioHeap,
311
const char* inFilePath,
312
mork_bool inFrozen, nsIMdbFile** acqFile)
313
// Choose some subclass of nsIMdbFile to instantiate, in order to read
314
// (and write if not frozen) the file known by inFilePath. The file
315
// returned should be open and ready for use, and presumably positioned
316
// at the first byte position of the file. The exact manner in which
317
// files must be opened is considered a subclass specific detail, and
318
// other portions or Mork source code don't want to know how it's done.
321
nsIMdbFile* outFile = 0;
322
morkEnv* ev = this->CanUseFactory(mev,
323
/*inMutable*/ morkBool_kFalse, &outErr);
324
morkFile* file = nsnull;
327
morkFactory* factory = (morkFactory*) this->mHandle_Object;
329
ioHeap = &factory->mFactory_Heap;
331
file = morkFile::OpenOldFile(ev, ioHeap, inFilePath, inFrozen);
332
NS_IF_ADDREF( file );
334
outErr = ev->AsErr();
343
orkinFactory::CreateNewFile(nsIMdbEnv* mev, nsIMdbHeap* ioHeap,
344
const char* inFilePath, nsIMdbFile** acqFile)
345
// Choose some subclass of nsIMdbFile to instantiate, in order to read
346
// (and write if not frozen) the file known by inFilePath. The file
347
// returned should be created and ready for use, and presumably positioned
348
// at the first byte position of the file. The exact manner in which
349
// files must be opened is considered a subclass specific detail, and
350
// other portions or Mork source code don't want to know how it's done.
353
nsIMdbFile* outFile = 0;
354
morkEnv* ev = this->CanUseFactory(mev,
355
/*inMutable*/ morkBool_kFalse, &outErr);
356
morkFile* file = nsnull;
359
morkFactory* factory = (morkFactory*) this->mHandle_Object;
361
ioHeap = &factory->mFactory_Heap;
363
file = morkFile::CreateNewFile(ev, ioHeap, inFilePath);
367
outErr = ev->AsErr();
374
// } ----- end file methods -----
376
// { ----- begin env methods -----
378
orkinFactory::MakeEnv(nsIMdbHeap* ioHeap, nsIMdbEnv** acqEnv)
379
// ioHeap can be nil, causing a MakeHeap() style heap instance to be used
382
nsIMdbEnv* outEnv = 0;
383
mork_bool ownsHeap = (ioHeap == 0);
385
ioHeap = new orkinHeap();
387
if ( acqEnv && ioHeap )
389
morkEnv* fenv = this->GetInternalFactoryEnv(&outErr);
392
morkFactory* factory = (morkFactory*) this->mHandle_Object;
393
morkEnv* newEnv = new(*ioHeap, fenv)
394
morkEnv(morkUsage::kHeap, ioHeap, factory, ioHeap);
398
newEnv->mEnv_OwnsHeap = ownsHeap;
399
newEnv->mNode_Refs += morkEnv_kWeakRefCountEnvBonus;
401
newEnv->mEnv_SelfAsMdbEnv = newEnv;
405
outErr = morkEnv_kOutOfMemoryError;
411
outErr = morkEnv_kNilPointerError;
415
// } ----- end env methods -----
417
// { ----- begin heap methods -----
419
orkinFactory::MakeHeap(nsIMdbEnv* mev, nsIMdbHeap** acqHeap)
422
nsIMdbHeap* outHeap = 0;
423
morkEnv* ev = this->CanUseFactory(mev,
424
/*inMutable*/ morkBool_kFalse, &outErr);
427
outHeap = new orkinHeap();
429
ev->OutOfMemoryError();
431
MORK_ASSERT(acqHeap);
436
// } ----- end heap methods -----
438
// { ----- begin compare methods -----
440
orkinFactory::MakeCompare(nsIMdbEnv* mev, nsIMdbCompare** acqCompare)
443
nsIMdbCompare* outCompare = 0;
444
morkEnv* ev = this->CanUseFactory(mev,
445
/*inMutable*/ morkBool_kFalse, &outErr);
448
NS_ASSERTION(PR_FALSE, "not implemented");
449
outErr = NS_ERROR_NOT_IMPLEMENTED;
450
// outCompare = new orkinCompare();
452
ev->OutOfMemoryError();
455
*acqCompare = outCompare;
458
// } ----- end compare methods -----
460
// { ----- begin row methods -----
462
orkinFactory::MakeRow(nsIMdbEnv* mev, nsIMdbHeap* ioHeap,
467
nsIMdbRow* outRow = 0;
468
morkEnv* ev = this->CanUseFactory(mev,
469
/*inMutable*/ morkBool_kFalse, &outErr);
472
ev->StubMethodOnlyError();
473
outErr = ev->AsErr();
480
// ioHeap can be nil, causing the heap associated with ev to be used
481
// } ----- end row methods -----
483
// { ----- begin port methods -----
485
orkinFactory::CanOpenFilePort(
486
nsIMdbEnv* mev, // context
487
// const char* inFilePath, // the file to investigate
488
// const mdbYarn* inFirst512Bytes,
489
nsIMdbFile* ioFile, // db abstract file interface
490
mdb_bool* outCanOpen, // whether OpenFilePort() might succeed
491
mdbYarn* outFormatVersion)
494
if ( outFormatVersion )
496
outFormatVersion->mYarn_Fill = 0;
498
mdb_bool canOpenAsPort = morkBool_kFalse;
499
morkEnv* ev = this->CanUseFactory(mev,
500
/*inMutable*/ morkBool_kFalse, &outErr);
503
if ( ioFile && outCanOpen )
505
canOpenAsPort = this->CanOpenMorkTextFile(ev, ioFile);
508
ev->NilPointerError();
510
outErr = ev->AsErr();
514
*outCanOpen = canOpenAsPort;
520
orkinFactory::OpenFilePort(
521
nsIMdbEnv* mev, // context
522
nsIMdbHeap* ioHeap, // can be nil to cause ev's heap attribute to be used
523
// const char* inFilePath, // the file to open for readonly import
524
nsIMdbFile* ioFile, // db abstract file interface
525
const mdbOpenPolicy* inOpenPolicy, // runtime policies for using db
526
nsIMdbThumb** acqThumb)
530
nsIMdbThumb* outThumb = 0;
531
morkEnv* ev = this->CanUseFactory(mev,
532
/*inMutable*/ morkBool_kFalse, &outErr);
535
if ( ioFile && inOpenPolicy && acqThumb )
539
ev->NilPointerError();
541
outErr = ev->AsErr();
544
*acqThumb = outThumb;
547
// Call nsIMdbThumb::DoMore() until done, or until the thumb is broken, and
548
// then call nsIMdbFactory::ThumbToOpenPort() to get the port instance.
551
orkinFactory::ThumbToOpenPort( // redeeming a completed thumb from OpenFilePort()
552
nsIMdbEnv* mev, // context
553
nsIMdbThumb* ioThumb, // thumb from OpenFilePort() with done status
554
nsIMdbPort** acqPort)
557
nsIMdbPort* outPort = 0;
558
morkEnv* ev = this->CanUseFactory(mev,
559
/*inMutable*/ morkBool_kFalse, &outErr);
562
if ( ioThumb && acqPort )
564
morkThumb* thumb = (morkThumb*) ioThumb;
565
morkStore* store = thumb->ThumbToOpenStore(ev);
568
store->mStore_CanAutoAssignAtomIdentity = morkBool_kTrue;
569
store->mStore_CanDirty = morkBool_kTrue;
570
store->SetStoreAndAllSpacesCanDirty(ev, morkBool_kTrue);
577
ev->NilPointerError();
579
outErr = ev->AsErr();
585
// } ----- end port methods -----
588
orkinFactory::CanOpenMorkTextFile(morkEnv* ev,
589
// const mdbYarn* inFirst512Bytes,
593
mork_bool outBool = morkBool_kFalse;
594
mork_size headSize = MORK_STRLEN(morkWriter_kFileHeader);
596
char localBuf[ 256 + 4 ]; // for extra for sloppy safety
598
mdbYarn* y = &localYarn;
599
y->mYarn_Buf = localBuf; // space to hold content
600
y->mYarn_Fill = 0; // no logical content yet
601
y->mYarn_Size = 256; // physical capacity is 256 bytes
608
nsIMdbEnv* menv = ev->AsMdbEnv();
609
mdb_size actualSize = 0;
610
ioFile->Get(menv, y->mYarn_Buf, y->mYarn_Size, /*pos*/ 0, &actualSize);
611
y->mYarn_Fill = actualSize;
613
if ( y->mYarn_Buf && actualSize >= headSize && ev->Good() )
615
mork_u1* buf = (mork_u1*) y->mYarn_Buf;
616
outBool = ( MORK_MEMCMP(morkWriter_kFileHeader, buf, headSize) == 0 );
620
ev->NilPointerError();
625
// { ----- begin store methods -----
627
orkinFactory::CanOpenFileStore(
628
nsIMdbEnv* mev, // context
629
// const char* inFilePath, // the file to investigate
630
// const mdbYarn* inFirst512Bytes,
631
nsIMdbFile* ioFile, // db abstract file interface
632
mdb_bool* outCanOpenAsStore, // whether OpenFileStore() might succeed
633
mdb_bool* outCanOpenAsPort, // whether OpenFilePort() might succeed
634
mdbYarn* outFormatVersion)
636
mdb_bool canOpenAsStore = morkBool_kFalse;
637
mdb_bool canOpenAsPort = morkBool_kFalse;
638
if ( outFormatVersion )
640
outFormatVersion->mYarn_Fill = 0;
643
morkEnv* ev = this->CanUseFactory(mev,
644
/*inMutable*/ morkBool_kFalse, &outErr);
647
if ( ioFile && outCanOpenAsStore )
649
// right now always say true; later we should look for magic patterns
650
canOpenAsStore = this->CanOpenMorkTextFile(ev, ioFile);
651
canOpenAsPort = canOpenAsStore;
654
ev->NilPointerError();
656
outErr = ev->AsErr();
658
if ( outCanOpenAsStore )
659
*outCanOpenAsStore = canOpenAsStore;
661
if ( outCanOpenAsPort )
662
*outCanOpenAsPort = canOpenAsPort;
668
orkinFactory::OpenFileStore( // open an existing database
669
nsIMdbEnv* mev, // context
670
nsIMdbHeap* ioHeap, // can be nil to cause ev's heap attribute to be used
671
// const char* inFilePath, // the file to open for general db usage
672
nsIMdbFile* ioFile, // db abstract file interface
673
const mdbOpenPolicy* inOpenPolicy, // runtime policies for using db
674
nsIMdbThumb** acqThumb)
677
nsIMdbThumb* outThumb = 0;
678
morkEnv* ev = this->CanUseFactory(mev,
679
/*inMutable*/ morkBool_kFalse, &outErr);
682
if ( !ioHeap ) // need to use heap from env?
683
ioHeap = ev->mEnv_Heap;
685
if ( ioFile && inOpenPolicy && acqThumb )
687
morkFactory* factory = (morkFactory*) this->mHandle_Object;
688
morkStore* store = new(*ioHeap, ev)
689
morkStore(ev, morkUsage::kHeap, ioHeap, factory, ioHeap);
693
mork_bool frozen = morkBool_kFalse; // open store mutable access
694
if ( store->OpenStoreFile(ev, frozen, ioFile, inOpenPolicy) )
696
morkThumb* thumb = morkThumb::Make_OpenFileStore(ev, ioHeap, store);
703
// store->CutStrongRef(mev); // always cut ref (handle has its own ref)
707
ev->NilPointerError();
709
outErr = ev->AsErr();
712
*acqThumb = outThumb;
715
// Call nsIMdbThumb::DoMore() until done, or until the thumb is broken, and
716
// then call nsIMdbFactory::ThumbToOpenStore() to get the store instance.
719
orkinFactory::ThumbToOpenStore( // redeem completed thumb from OpenFileStore()
720
nsIMdbEnv* mev, // context
721
nsIMdbThumb* ioThumb, // thumb from OpenFileStore() with done status
722
nsIMdbStore** acqStore)
725
nsIMdbStore* outStore = 0;
726
morkEnv* ev = this->CanUseFactory(mev,
727
/*inMutable*/ morkBool_kFalse, &outErr);
730
if ( ioThumb && acqStore )
732
morkThumb* thumb = (morkThumb*) ioThumb;
733
morkStore* store = thumb->ThumbToOpenStore(ev);
736
store->mStore_CanAutoAssignAtomIdentity = morkBool_kTrue;
737
store->mStore_CanDirty = morkBool_kTrue;
738
store->SetStoreAndAllSpacesCanDirty(ev, morkBool_kTrue);
745
ev->NilPointerError();
747
outErr = ev->AsErr();
750
*acqStore = outStore;
755
orkinFactory::CreateNewFileStore( // create a new db with minimal content
756
nsIMdbEnv* mev, // context
757
nsIMdbHeap* ioHeap, // can be nil to cause ev's heap attribute to be used
758
// const char* inFilePath, // name of file which should not yet exist
759
nsIMdbFile* ioFile, // db abstract file interface
760
const mdbOpenPolicy* inOpenPolicy, // runtime policies for using db
761
nsIMdbStore** acqStore)
764
nsIMdbStore* outStore = 0;
765
morkEnv* ev = this->CanUseFactory(mev,
766
/*inMutable*/ morkBool_kFalse, &outErr);
769
if ( !ioHeap ) // need to use heap from env?
770
ioHeap = ev->mEnv_Heap;
772
if ( ioFile && inOpenPolicy && acqStore && ioHeap )
774
morkFactory* factory = (morkFactory*) this->mHandle_Object;
775
morkStore* store = new(*ioHeap, ev)
776
morkStore(ev, morkUsage::kHeap, ioHeap, factory, ioHeap);
780
store->mStore_CanAutoAssignAtomIdentity = morkBool_kTrue;
781
store->mStore_CanDirty = morkBool_kTrue;
782
store->SetStoreAndAllSpacesCanDirty(ev, morkBool_kTrue);
784
if ( store->CreateStoreFile(ev, ioFile, inOpenPolicy) )
790
ev->NilPointerError();
792
outErr = ev->AsErr();
795
*acqStore = outStore;
798
// } ----- end store methods -----
800
// } ===== end nsIMdbFactory methods =====
803
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789