1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-  */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3  * License, v. 2.0. If a copy of the MPL was not distributed with this
4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 
6 #ifndef _MDB_
7 #  include "mdb.h"
8 #endif
9 
10 #ifndef _MORK_
11 #  include "mork.h"
12 #endif
13 
14 #ifndef _MORKNODE_
15 #  include "morkNode.h"
16 #endif
17 
18 #ifndef _MORKROWOBJECT_
19 #  include "morkRowObject.h"
20 #endif
21 
22 #ifndef _MORKENV_
23 #  include "morkEnv.h"
24 #endif
25 
26 #ifndef _MORKSTORE_
27 #  include "morkStore.h"
28 #endif
29 
30 #ifndef _MORKROWCELLCURSOR_
31 #  include "morkRowCellCursor.h"
32 #endif
33 
34 #ifndef _MORKCELLOBJECT_
35 #  include "morkCellObject.h"
36 #endif
37 
38 #ifndef _MORKROW_
39 #  include "morkRow.h"
40 #endif
41 
42 // 456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
43 
44 // ````` ````` ````` ````` `````
45 // { ===== begin morkNode interface =====
46 
CloseMorkNode(morkEnv * ev)47 /*public virtual*/ void morkRowObject::CloseMorkNode(
48     morkEnv* ev)  // CloseRowObject() only if open
49 {
50   if (this->IsOpenNode()) {
51     this->MarkClosing();
52     this->CloseRowObject(ev);
53     this->MarkShut();
54   }
55 }
56 
57 /*public virtual*/
~morkRowObject()58 morkRowObject::~morkRowObject()  // assert CloseRowObject() executed earlier
59 {
60   CloseMorkNode(mMorkEnv);
61   MORK_ASSERT(this->IsShutNode());
62 }
63 
64 /*public non-poly*/
morkRowObject(morkEnv * ev,const morkUsage & inUsage,nsIMdbHeap * ioHeap,morkRow * ioRow,morkStore * ioStore)65 morkRowObject::morkRowObject(morkEnv* ev, const morkUsage& inUsage,
66                              nsIMdbHeap* ioHeap, morkRow* ioRow,
67                              morkStore* ioStore)
68     : morkObject(ev, inUsage, ioHeap, morkColor_kNone, (morkHandle*)0),
69       mRowObject_Row(0),
70       mRowObject_Store(0) {
71   if (ev->Good()) {
72     if (ioRow && ioStore) {
73       mRowObject_Row = ioRow;
74       mRowObject_Store =
75           ioStore;  // morkRowObjects don't ref-cnt the owning store.
76 
77       if (ev->Good()) mNode_Derived = morkDerived_kRowObject;
78     } else
79       ev->NilPointerError();
80   }
81 }
82 
NS_IMPL_ISUPPORTS_INHERITED(morkRowObject,morkObject,nsIMdbRow)83 NS_IMPL_ISUPPORTS_INHERITED(morkRowObject, morkObject, nsIMdbRow)
84 // { ===== begin nsIMdbCollection methods =====
85 
86 // { ----- begin attribute methods -----
87 NS_IMETHODIMP
88 morkRowObject::GetSeed(nsIMdbEnv* mev, mdb_seed* outSeed) {
89   nsresult outErr = NS_OK;
90   morkEnv* ev = morkEnv::FromMdbEnv(mev);
91   if (ev) {
92     *outSeed = (mdb_seed)mRowObject_Row->mRow_Seed;
93     outErr = ev->AsErr();
94   }
95   return outErr;
96 }
97 NS_IMETHODIMP
GetCount(nsIMdbEnv * mev,mdb_count * outCount)98 morkRowObject::GetCount(nsIMdbEnv* mev, mdb_count* outCount) {
99   nsresult outErr = NS_OK;
100   morkEnv* ev = morkEnv::FromMdbEnv(mev);
101   if (ev) {
102     *outCount = (mdb_count)mRowObject_Row->mRow_Length;
103     outErr = ev->AsErr();
104   }
105   return outErr;
106 }
107 
108 NS_IMETHODIMP
GetPort(nsIMdbEnv * mev,nsIMdbPort ** acqPort)109 morkRowObject::GetPort(nsIMdbEnv* mev, nsIMdbPort** acqPort) {
110   nsresult outErr = NS_OK;
111   nsIMdbPort* outPort = 0;
112   morkEnv* ev = morkEnv::FromMdbEnv(mev);
113   if (ev) {
114     morkRowSpace* rowSpace = mRowObject_Row->mRow_Space;
115     if (rowSpace && rowSpace->mSpace_Store) {
116       morkStore* store = mRowObject_Row->GetRowSpaceStore(ev);
117       if (store) outPort = store->AcquireStoreHandle(ev);
118     } else
119       ev->NilPointerError();
120 
121     outErr = ev->AsErr();
122   }
123   if (acqPort) *acqPort = outPort;
124 
125   return outErr;
126 }
127 // } ----- end attribute methods -----
128 
129 // { ----- begin cursor methods -----
130 NS_IMETHODIMP
GetCursor(nsIMdbEnv * mev,mdb_pos inMemberPos,nsIMdbCursor ** acqCursor)131 morkRowObject::GetCursor(  // make a cursor starting iter at inMemberPos
132     nsIMdbEnv* mev,        // context
133     mdb_pos inMemberPos,   // zero-based ordinal pos of member in collection
134     nsIMdbCursor** acqCursor) {
135   return this->GetRowCellCursor(mev, inMemberPos,
136                                 (nsIMdbRowCellCursor**)acqCursor);
137 }
138 // } ----- end cursor methods -----
139 
140 // { ----- begin ID methods -----
141 NS_IMETHODIMP
GetOid(nsIMdbEnv * mev,mdbOid * outOid)142 morkRowObject::GetOid(nsIMdbEnv* mev, mdbOid* outOid) {
143   *outOid = mRowObject_Row->mRow_Oid;
144   morkEnv* ev = morkEnv::FromMdbEnv(mev);
145   return (ev) ? ev->AsErr() : NS_ERROR_FAILURE;
146 }
147 
148 NS_IMETHODIMP
BecomeContent(nsIMdbEnv * mev,const mdbOid * inOid)149 morkRowObject::BecomeContent(nsIMdbEnv* mev, const mdbOid* inOid) {
150   NS_ASSERTION(false, "not implemented");
151   return NS_ERROR_NOT_IMPLEMENTED;
152   // remember row->MaybeDirtySpaceStoreAndRow();
153 }
154 // } ----- end ID methods -----
155 
156 // { ----- begin activity dropping methods -----
157 NS_IMETHODIMP
DropActivity(nsIMdbEnv * mev)158 morkRowObject::DropActivity(  // tell collection usage no longer expected
159     nsIMdbEnv* mev) {
160   NS_ASSERTION(false, "not implemented");
161   return NS_ERROR_NOT_IMPLEMENTED;
162 }
163 // } ----- end activity dropping methods -----
164 
165 // } ===== end nsIMdbCollection methods =====
166 
167 // { ===== begin nsIMdbRow methods =====
168 
169 // { ----- begin cursor methods -----
170 NS_IMETHODIMP
GetRowCellCursor(nsIMdbEnv * mev,mdb_pos inPos,nsIMdbRowCellCursor ** acqCursor)171 morkRowObject::GetRowCellCursor(  // make a cursor starting iteration at
172                                   // inCellPos
173     nsIMdbEnv* mev,               // context
174     mdb_pos inPos,                // zero-based ordinal position of cell in row
175     nsIMdbRowCellCursor** acqCursor) {
176   nsresult outErr = NS_OK;
177   morkEnv* ev = morkEnv::FromMdbEnv(mev);
178   nsIMdbRowCellCursor* outCursor = 0;
179   if (ev) {
180     morkRowCellCursor* cursor = mRowObject_Row->NewRowCellCursor(ev, inPos);
181     if (cursor) {
182       if (ev->Good()) {
183         cursor->mCursor_Seed = (mork_seed)inPos;
184         outCursor = cursor;
185         NS_ADDREF(cursor);
186       }
187     }
188     outErr = ev->AsErr();
189   }
190   if (acqCursor) *acqCursor = outCursor;
191   return outErr;
192 }
193 // } ----- end cursor methods -----
194 
195 // { ----- begin column methods -----
196 NS_IMETHODIMP
AddColumn(nsIMdbEnv * mev,mdb_column inColumn,const mdbYarn * inYarn)197 morkRowObject::AddColumn(  // make sure a particular column is inside row
198     nsIMdbEnv* mev,        // context
199     mdb_column inColumn,   // column to add
200     const mdbYarn* inYarn) {
201   nsresult outErr = NS_ERROR_FAILURE;
202   morkEnv* ev = morkEnv::FromMdbEnv(mev);
203   if (ev) {
204     if (mRowObject_Store && mRowObject_Row)
205       mRowObject_Row->AddColumn(ev, inColumn, inYarn, mRowObject_Store);
206 
207     outErr = ev->AsErr();
208   }
209   return outErr;
210 }
211 
212 NS_IMETHODIMP
CutColumn(nsIMdbEnv * mev,mdb_column inColumn)213 morkRowObject::CutColumn(  // make sure a column is absent from the row
214     nsIMdbEnv* mev,        // context
215     mdb_column inColumn) {
216   nsresult outErr = NS_ERROR_FAILURE;
217   morkEnv* ev = morkEnv::FromMdbEnv(mev);
218   if (ev) {
219     mRowObject_Row->CutColumn(ev, inColumn);
220     outErr = ev->AsErr();
221   }
222   return outErr;
223 }
224 
225 NS_IMETHODIMP
CutAllColumns(nsIMdbEnv * mev)226 morkRowObject::CutAllColumns(  // remove all columns from the row
227     nsIMdbEnv* mev) {
228   nsresult outErr = NS_OK;
229   morkEnv* ev = morkEnv::FromMdbEnv(mev);
230   if (ev) {
231     mRowObject_Row->CutAllColumns(ev);
232     outErr = ev->AsErr();
233   }
234   return outErr;
235 }
236 // } ----- end column methods -----
237 
238 // { ----- begin cell methods -----
239 NS_IMETHODIMP
NewCell(nsIMdbEnv * mev,mdb_column inColumn,nsIMdbCell ** acqCell)240 morkRowObject::NewCell(   // get cell for specified column, or add new one
241     nsIMdbEnv* mev,       // context
242     mdb_column inColumn,  // column to add
243     nsIMdbCell** acqCell) {
244   nsresult outErr = NS_OK;
245   morkEnv* ev = morkEnv::FromMdbEnv(mev);
246   if (ev) {
247     GetCell(mev, inColumn, acqCell);
248     if (!*acqCell) {
249       if (mRowObject_Store) {
250         mdbYarn yarn;  // to pass empty yarn into morkRowObject::AddColumn()
251         yarn.mYarn_Buf = 0;
252         yarn.mYarn_Fill = 0;
253         yarn.mYarn_Size = 0;
254         yarn.mYarn_More = 0;
255         yarn.mYarn_Form = 0;
256         yarn.mYarn_Grow = 0;
257         AddColumn(ev, inColumn, &yarn);
258         GetCell(mev, inColumn, acqCell);
259       }
260     }
261 
262     outErr = ev->AsErr();
263   }
264   return outErr;
265 }
266 
267 NS_IMETHODIMP
AddCell(nsIMdbEnv * mev,const nsIMdbCell * inCell)268 morkRowObject::AddCell(  // copy a cell from another row to this row
269     nsIMdbEnv* mev,      // context
270     const nsIMdbCell* inCell) {
271   nsresult outErr = NS_OK;
272   morkEnv* ev = morkEnv::FromMdbEnv(mev);
273   if (ev) {
274     morkCell* cell = 0;
275     morkCellObject* cellObj = (morkCellObject*)inCell;
276     if (cellObj->CanUseCell(mev, morkBool_kFalse, &outErr, &cell)) {
277       morkRow* cellRow = cellObj->mCellObject_Row;
278       if (cellRow) {
279         if (mRowObject_Row != cellRow) {
280           morkStore* store = mRowObject_Row->GetRowSpaceStore(ev);
281           morkStore* cellStore = cellRow->GetRowSpaceStore(ev);
282           if (store && cellStore) {
283             mork_column col = cell->GetColumn();
284             morkAtom* atom = cell->mCell_Atom;
285             mdbYarn yarn;
286             morkAtom::AliasYarn(atom, &yarn);  // works even when atom is nil
287 
288             if (store != cellStore) col = store->CopyToken(ev, col, cellStore);
289             if (ev->Good()) AddColumn(ev, col, &yarn);
290           } else
291             ev->NilPointerError();
292         }
293       } else
294         ev->NilPointerError();
295     }
296 
297     outErr = ev->AsErr();
298   }
299   return outErr;
300 }
301 
302 NS_IMETHODIMP
GetCell(nsIMdbEnv * mev,mdb_column inColumn,nsIMdbCell ** acqCell)303 morkRowObject::GetCell(   // find a cell in this row
304     nsIMdbEnv* mev,       // context
305     mdb_column inColumn,  // column to find
306     nsIMdbCell** acqCell) {
307   nsresult outErr = NS_OK;
308   nsIMdbCell* outCell = 0;
309   morkEnv* ev = morkEnv::FromMdbEnv(mev);
310 
311   if (ev) {
312     if (inColumn) {
313       mork_pos pos = 0;
314       morkCell* cell = mRowObject_Row->GetCell(ev, inColumn, &pos);
315       if (cell) {
316         outCell = mRowObject_Row->AcquireCellHandle(ev, cell, inColumn, pos);
317       }
318     } else
319       mRowObject_Row->ZeroColumnError(ev);
320 
321     outErr = ev->AsErr();
322   }
323   if (acqCell) *acqCell = outCell;
324   return outErr;
325 }
326 
327 NS_IMETHODIMP
EmptyAllCells(nsIMdbEnv * mev)328 morkRowObject::EmptyAllCells(  // make all cells in row empty of content
329     nsIMdbEnv* mev) {
330   nsresult outErr = NS_OK;
331   morkEnv* ev = morkEnv::FromMdbEnv(mev);
332   if (ev) {
333     EmptyAllCells(ev);
334     outErr = ev->AsErr();
335   }
336   return outErr;
337 }
338 // } ----- end cell methods -----
339 
340 // { ----- begin row methods -----
341 NS_IMETHODIMP
AddRow(nsIMdbEnv * mev,nsIMdbRow * ioSourceRow)342 morkRowObject::AddRow(  // add all cells in another row to this one
343     nsIMdbEnv* mev,     // context
344     nsIMdbRow* ioSourceRow) {
345   nsresult outErr = NS_OK;
346   morkEnv* ev = morkEnv::FromMdbEnv(mev);
347   if (ev) {
348     morkRow* unsafeSource = (morkRow*)ioSourceRow;  // unsafe cast
349     //    if ( unsafeSource->CanUseRow(mev, morkBool_kFalse, &outErr, &source) )
350     { mRowObject_Row->AddRow(ev, unsafeSource); }
351     outErr = ev->AsErr();
352   }
353   return outErr;
354 }
355 
356 NS_IMETHODIMP
SetRow(nsIMdbEnv * mev,nsIMdbRow * ioSourceRow)357 morkRowObject::SetRow(  // make exact duplicate of another row
358     nsIMdbEnv* mev,     // context
359     nsIMdbRow* ioSourceRow) {
360   nsresult outErr = NS_OK;
361   morkEnv* ev = morkEnv::FromMdbEnv(mev);
362   if (ev) {
363     morkRowObject* sourceObject = (morkRowObject*)ioSourceRow;  // unsafe cast
364     morkRow* unsafeSource = sourceObject->mRowObject_Row;
365     //    if ( unsafeSource->CanUseRow(mev, morkBool_kFalse, &outErr, &source) )
366     { mRowObject_Row->SetRow(ev, unsafeSource); }
367     outErr = ev->AsErr();
368   }
369   return outErr;
370 }
371 // } ----- end row methods -----
372 
373 // { ----- begin blob methods -----
374 NS_IMETHODIMP
SetCellYarn(nsIMdbEnv * mev,mdb_column inColumn,const mdbYarn * inYarn)375 morkRowObject::SetCellYarn(  // synonym for AddColumn()
376     nsIMdbEnv* mev,          // context
377     mdb_column inColumn,     // column to add
378     const mdbYarn* inYarn) {
379   nsresult outErr = NS_OK;
380   morkEnv* ev = morkEnv::FromMdbEnv(mev);
381   if (ev) {
382     if (mRowObject_Store) AddColumn(ev, inColumn, inYarn);
383 
384     outErr = ev->AsErr();
385   }
386   return outErr;
387 }
388 NS_IMETHODIMP
GetCellYarn(nsIMdbEnv * mev,mdb_column inColumn,mdbYarn * outYarn)389 morkRowObject::GetCellYarn(nsIMdbEnv* mev,       // context
390                            mdb_column inColumn,  // column to read
391                            mdbYarn* outYarn)     // writes some yarn slots
392 // copy content into the yarn buffer, and update mYarn_Fill and mYarn_Form
393 {
394   nsresult outErr = NS_OK;
395   morkEnv* ev = morkEnv::FromMdbEnv(mev);
396   if (ev) {
397     if (mRowObject_Store && mRowObject_Row) {
398       morkAtom* atom = mRowObject_Row->GetColumnAtom(ev, inColumn);
399       morkAtom::GetYarn(atom, outYarn);
400     }
401 
402     outErr = ev->AsErr();
403   }
404   return outErr;
405 }
406 
407 NS_IMETHODIMP
AliasCellYarn(nsIMdbEnv * mev,mdb_column inColumn,mdbYarn * outYarn)408 morkRowObject::AliasCellYarn(nsIMdbEnv* mev,       // context
409                              mdb_column inColumn,  // column to alias
410                              mdbYarn* outYarn)     // writes ALL yarn slots
411 {
412   nsresult outErr = NS_OK;
413   morkEnv* ev = morkEnv::FromMdbEnv(mev);
414   if (ev) {
415     if (mRowObject_Store && mRowObject_Row) {
416       morkAtom* atom = mRowObject_Row->GetColumnAtom(ev, inColumn);
417       morkAtom::AliasYarn(atom, outYarn);
418       // note nil atom works and sets yarn correctly
419     }
420     outErr = ev->AsErr();
421   }
422   return outErr;
423 }
424 
425 NS_IMETHODIMP
NextCellYarn(nsIMdbEnv * mev,mdb_column * ioColumn,mdbYarn * outYarn)426 morkRowObject::NextCellYarn(
427     nsIMdbEnv* mev,        // iterative version of GetCellYarn()
428     mdb_column* ioColumn,  // next column to read
429     mdbYarn* outYarn)      // writes some yarn slots
430 // copy content into the yarn buffer, and update mYarn_Fill and mYarn_Form
431 //
432 // The ioColumn argument is an inout parameter which initially contains the
433 // last column accessed and returns the next column corresponding to the
434 // content read into the yarn.  Callers should start with a zero column
435 // value to say 'no previous column', which causes the first column to be
436 // read.  Then the value returned in ioColumn is perfect for the next call
437 // to NextCellYarn(), since it will then be the previous column accessed.
438 // Callers need only examine the column token returned to see which cell
439 // in the row is being read into the yarn.  When no more columns remain,
440 // and the iteration has ended, ioColumn will return a zero token again.
441 // So iterating over cells starts and ends with a zero column token.
442 {
443   nsresult outErr = NS_OK;
444   morkEnv* ev = morkEnv::FromMdbEnv(mev);
445   if (ev) {
446     if (mRowObject_Store && mRowObject_Row)
447       mRowObject_Row->NextColumn(ev, ioColumn, outYarn);
448 
449     outErr = ev->AsErr();
450   }
451   return outErr;
452 }
453 
454 NS_IMETHODIMP
SeekCellYarn(nsIMdbEnv * mev,mdb_pos inPos,mdb_column * outColumn,mdbYarn * outYarn)455 morkRowObject::SeekCellYarn(  // resembles nsIMdbRowCellCursor::SeekCell()
456     nsIMdbEnv* mev,           // context
457     mdb_pos inPos,            // position of cell in row sequence
458     mdb_column* outColumn,    // column for this particular cell
459     mdbYarn* outYarn)         // writes some yarn slots
460 // copy content into the yarn buffer, and update mYarn_Fill and mYarn_Form
461 // Callers can pass nil for outYarn to indicate no interest in content, so
462 // only the outColumn value is returned.  NOTE to subclasses: you must be
463 // able to ignore outYarn when the pointer is nil; please do not crash.
464 
465 {
466   nsresult outErr = NS_OK;
467   morkEnv* ev = morkEnv::FromMdbEnv(mev);
468   if (ev) {
469     if (mRowObject_Store && mRowObject_Row)
470       mRowObject_Row->SeekColumn(ev, inPos, outColumn, outYarn);
471 
472     outErr = ev->AsErr();
473   }
474   return outErr;
475 }
476 
477 // } ----- end blob methods -----
478 
479 // } ===== end nsIMdbRow methods =====
480 
CloseRowObject(morkEnv * ev)481 /*public non-poly*/ void morkRowObject::CloseRowObject(
482     morkEnv* ev)  // called by CloseMorkNode();
483 {
484   if (this->IsNode()) {
485     morkRow* row = mRowObject_Row;
486     mRowObject_Row = 0;
487     this->CloseObject(ev);
488     this->MarkShut();
489 
490     if (row) {
491       MORK_ASSERT(row->mRow_Object == this);
492       if (row->mRow_Object == this) {
493         row->mRow_Object = 0;  // just nil this slot -- cut ref down below
494 
495         mRowObject_Store = 0;  // morkRowObjects don't ref-cnt the owning store.
496 
497         this->CutWeakRef(
498             ev->AsMdbEnv());  // do last, because it might self destroy
499       }
500     }
501   } else
502     this->NonNodeError(ev);
503 }
504 
505 // } ===== end morkNode methods =====
506 // ````` ````` ````` ````` `````
507 
NonRowObjectTypeError(morkEnv * ev)508 /*static*/ void morkRowObject::NonRowObjectTypeError(morkEnv* ev) {
509   ev->NewError("non morkRowObject");
510 }
511 
NilRowError(morkEnv * ev)512 /*static*/ void morkRowObject::NilRowError(morkEnv* ev) {
513   ev->NewError("nil mRowObject_Row");
514 }
515 
NilStoreError(morkEnv * ev)516 /*static*/ void morkRowObject::NilStoreError(morkEnv* ev) {
517   ev->NewError("nil mRowObject_Store");
518 }
519 
RowObjectRowNotSelfError(morkEnv * ev)520 /*static*/ void morkRowObject::RowObjectRowNotSelfError(morkEnv* ev) {
521   ev->NewError("mRowObject_Row->mRow_Object != self");
522 }
523 
AcquireRowHandle(morkEnv * ev)524 nsIMdbRow* morkRowObject::AcquireRowHandle(morkEnv* ev)  // mObject_Handle
525 {
526   AddRef();
527   return this;
528 }
529 
530 // 456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
531