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 _MORKBLOB_
15 #  include "morkBlob.h"
16 #endif
17 
18 #ifndef _MORKATOM_
19 #  include "morkAtom.h"
20 #endif
21 
22 #ifndef _MORKENV_
23 #  include "morkEnv.h"
24 #endif
25 
26 #ifndef _MORKATOMSPACE_
27 #  include "morkAtomSpace.h"
28 #endif
29 
30 // 456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
31 
32 /* static */
GetYarn(const morkAtom * atom,mdbYarn * outYarn)33 mork_bool morkAtom::GetYarn(const morkAtom* atom, mdbYarn* outYarn) {
34   const void* source = 0;
35   mdb_fill fill = 0;
36   mdb_cscode form = 0;
37   outYarn->mYarn_More = 0;
38 
39   if (atom) {
40     if (atom->IsWeeBook()) {
41       morkWeeBookAtom* weeBook = (morkWeeBookAtom*)atom;
42       source = weeBook->mWeeBookAtom_Body;
43       fill = weeBook->mAtom_Size;
44     } else if (atom->IsBigBook()) {
45       morkBigBookAtom* bigBook = (morkBigBookAtom*)atom;
46       source = bigBook->mBigBookAtom_Body;
47       fill = bigBook->mBigBookAtom_Size;
48       form = bigBook->mBigBookAtom_Form;
49     } else if (atom->IsWeeAnon()) {
50       morkWeeAnonAtom* weeAnon = (morkWeeAnonAtom*)atom;
51       source = weeAnon->mWeeAnonAtom_Body;
52       fill = weeAnon->mAtom_Size;
53     } else if (atom->IsBigAnon()) {
54       morkBigAnonAtom* bigAnon = (morkBigAnonAtom*)atom;
55       source = bigAnon->mBigAnonAtom_Body;
56       fill = bigAnon->mBigAnonAtom_Size;
57       form = bigAnon->mBigAnonAtom_Form;
58     }
59   }
60 
61   if (source && fill)  // have an atom with nonempty content?
62   {
63     // if we have too many bytes, and yarn seems growable:
64     if (fill > outYarn->mYarn_Size && outYarn->mYarn_Grow)  // try grow?
65       (*outYarn->mYarn_Grow)(outYarn, (mdb_size)fill);      // request bigger
66 
67     mdb_size size = outYarn->mYarn_Size;  // max dest size
68     if (fill > size)                      // too much atom content?
69     {
70       outYarn->mYarn_More = fill - size;  // extra atom bytes omitted
71       fill = size;  // copy no more bytes than size of yarn buffer
72     }
73     void* dest = outYarn->mYarn_Buf;  // where bytes are going
74     if (!dest)                        // nil destination address buffer?
75       fill = 0;                       // we can't write any content at all
76 
77     if (fill)                           // anything to copy?
78       MORK_MEMCPY(dest, source, fill);  // copy fill bytes to yarn
79 
80     outYarn->mYarn_Fill = fill;  // tell yarn size of copied content
81   } else                         // no content to put into the yarn
82   {
83     outYarn->mYarn_Fill = 0;  // tell yarn that atom has no bytes
84   }
85   outYarn->mYarn_Form = form;  // always update the form slot
86 
87   return (source != 0);
88 }
89 
90 /* static */
AliasYarn(const morkAtom * atom,mdbYarn * outYarn)91 mork_bool morkAtom::AliasYarn(const morkAtom* atom, mdbYarn* outYarn) {
92   outYarn->mYarn_More = 0;
93   outYarn->mYarn_Form = 0;
94 
95   if (atom) {
96     if (atom->IsWeeBook()) {
97       morkWeeBookAtom* weeBook = (morkWeeBookAtom*)atom;
98       outYarn->mYarn_Buf = weeBook->mWeeBookAtom_Body;
99       outYarn->mYarn_Fill = weeBook->mAtom_Size;
100       outYarn->mYarn_Size = weeBook->mAtom_Size;
101     } else if (atom->IsBigBook()) {
102       morkBigBookAtom* bigBook = (morkBigBookAtom*)atom;
103       outYarn->mYarn_Buf = bigBook->mBigBookAtom_Body;
104       outYarn->mYarn_Fill = bigBook->mBigBookAtom_Size;
105       outYarn->mYarn_Size = bigBook->mBigBookAtom_Size;
106       outYarn->mYarn_Form = bigBook->mBigBookAtom_Form;
107     } else if (atom->IsWeeAnon()) {
108       morkWeeAnonAtom* weeAnon = (morkWeeAnonAtom*)atom;
109       outYarn->mYarn_Buf = weeAnon->mWeeAnonAtom_Body;
110       outYarn->mYarn_Fill = weeAnon->mAtom_Size;
111       outYarn->mYarn_Size = weeAnon->mAtom_Size;
112     } else if (atom->IsBigAnon()) {
113       morkBigAnonAtom* bigAnon = (morkBigAnonAtom*)atom;
114       outYarn->mYarn_Buf = bigAnon->mBigAnonAtom_Body;
115       outYarn->mYarn_Fill = bigAnon->mBigAnonAtom_Size;
116       outYarn->mYarn_Size = bigAnon->mBigAnonAtom_Size;
117       outYarn->mYarn_Form = bigAnon->mBigAnonAtom_Form;
118     } else
119       atom = 0;  // show desire to put empty content in yarn
120   }
121 
122   if (!atom)  // empty content for yarn?
123   {
124     outYarn->mYarn_Buf = 0;
125     outYarn->mYarn_Fill = 0;
126     outYarn->mYarn_Size = 0;
127     // outYarn->mYarn_Grow = 0; // please don't modify the Grow slot
128   }
129   return (atom != 0);
130 }
131 
GetBookAtomAid() const132 mork_aid morkAtom::GetBookAtomAid() const  // zero or book atom's ID
133 {
134   return (this->IsBook()) ? ((morkBookAtom*)this)->mBookAtom_Id : 0;
135 }
136 
GetBookAtomSpaceScope(morkEnv * ev) const137 mork_scope morkAtom::GetBookAtomSpaceScope(
138     morkEnv* ev) const  // zero or book's space's scope
139 {
140   mork_scope outScope = 0;
141   if (this->IsBook()) {
142     const morkBookAtom* bookAtom = (const morkBookAtom*)this;
143     morkAtomSpace* space = bookAtom->mBookAtom_Space;
144     if (space->IsAtomSpace())
145       outScope = space->SpaceScope();
146     else
147       space->NonAtomSpaceTypeError(ev);
148   }
149 
150   return outScope;
151 }
152 
MakeCellUseForever(morkEnv * ev)153 void morkAtom::MakeCellUseForever(morkEnv* ev) {
154   MORK_USED_1(ev);
155   mAtom_CellUses = morkAtom_kForeverCellUses;
156 }
157 
AddCellUse(morkEnv * ev)158 mork_u1 morkAtom::AddCellUse(morkEnv* ev) {
159   MORK_USED_1(ev);
160   if (mAtom_CellUses < morkAtom_kMaxCellUses)  // not already maxed out?
161     ++mAtom_CellUses;
162 
163   return mAtom_CellUses;
164 }
165 
CutCellUse(morkEnv * ev)166 mork_u1 morkAtom::CutCellUse(morkEnv* ev) {
167   if (mAtom_CellUses)  // any outstanding uses to cut?
168   {
169     if (mAtom_CellUses < morkAtom_kMaxCellUses)  // not frozen at max?
170       --mAtom_CellUses;
171   } else
172     this->CellUsesUnderflowWarning(ev);
173 
174   return mAtom_CellUses;
175 }
176 
CellUsesUnderflowWarning(morkEnv * ev)177 /*static*/ void morkAtom::CellUsesUnderflowWarning(morkEnv* ev) {
178   ev->NewWarning("mAtom_CellUses underflow");
179 }
180 
BadAtomKindError(morkEnv * ev)181 /*static*/ void morkAtom::BadAtomKindError(morkEnv* ev) {
182   ev->NewError("bad mAtom_Kind");
183 }
184 
ZeroAidError(morkEnv * ev)185 /*static*/ void morkAtom::ZeroAidError(morkEnv* ev) {
186   ev->NewError("zero atom ID");
187 }
188 
AtomSizeOverflowError(morkEnv * ev)189 /*static*/ void morkAtom::AtomSizeOverflowError(morkEnv* ev) {
190   ev->NewError("atom mAtom_Size overflow");
191 }
192 
InitRowOidAtom(morkEnv * ev,const mdbOid & inOid)193 void morkOidAtom::InitRowOidAtom(morkEnv* ev, const mdbOid& inOid) {
194   MORK_USED_1(ev);
195   mAtom_CellUses = 0;
196   mAtom_Kind = morkAtom_kKindRowOid;
197   mAtom_Change = morkChange_kNil;
198   mAtom_Size = 0;
199   mOidAtom_Oid = inOid;  // bitwise copy
200 }
201 
InitTableOidAtom(morkEnv * ev,const mdbOid & inOid)202 void morkOidAtom::InitTableOidAtom(morkEnv* ev, const mdbOid& inOid) {
203   MORK_USED_1(ev);
204   mAtom_CellUses = 0;
205   mAtom_Kind = morkAtom_kKindTableOid;
206   mAtom_Change = morkChange_kNil;
207   mAtom_Size = 0;
208   mOidAtom_Oid = inOid;  // bitwise copy
209 }
210 
InitWeeAnonAtom(morkEnv * ev,const morkBuf & inBuf)211 void morkWeeAnonAtom::InitWeeAnonAtom(morkEnv* ev, const morkBuf& inBuf) {
212   mAtom_Kind = 0;
213   mAtom_Change = morkChange_kNil;
214   if (inBuf.mBuf_Fill <= morkAtom_kMaxByteSize) {
215     mAtom_CellUses = 0;
216     mAtom_Kind = morkAtom_kKindWeeAnon;
217     mork_size size = inBuf.mBuf_Fill;
218     mAtom_Size = (mork_u1)size;
219     if (size && inBuf.mBuf_Body)
220       MORK_MEMCPY(mWeeAnonAtom_Body, inBuf.mBuf_Body, size);
221 
222     mWeeAnonAtom_Body[size] = 0;
223   } else
224     this->AtomSizeOverflowError(ev);
225 }
226 
InitBigAnonAtom(morkEnv * ev,const morkBuf & inBuf,mork_cscode inForm)227 void morkBigAnonAtom::InitBigAnonAtom(morkEnv* ev, const morkBuf& inBuf,
228                                       mork_cscode inForm) {
229   MORK_USED_1(ev);
230   mAtom_CellUses = 0;
231   mAtom_Kind = morkAtom_kKindBigAnon;
232   mAtom_Change = morkChange_kNil;
233   mAtom_Size = 0;
234   mBigAnonAtom_Form = inForm;
235   mork_size size = inBuf.mBuf_Fill;
236   mBigAnonAtom_Size = size;
237   if (size && inBuf.mBuf_Body)
238     MORK_MEMCPY(mBigAnonAtom_Body, inBuf.mBuf_Body, size);
239 
240   mBigAnonAtom_Body[size] = 0;
241 }
242 
NonBookAtomTypeError(morkEnv * ev)243 /*static*/ void morkBookAtom::NonBookAtomTypeError(morkEnv* ev) {
244   ev->NewError("non morkBookAtom");
245 }
246 
HashFormAndBody(morkEnv * ev) const247 mork_u4 morkBookAtom::HashFormAndBody(morkEnv* ev) const {
248   // This hash is obviously a variation of the dragon book string hash.
249   // (I won't bother to explain or rationalize this usage for you.)
250 
251   mork_u4 outHash = 0;  // hash value returned
252   unsigned char c;      // next character
253   const mork_u1* body;  // body of bytes to hash
254   mork_size size = 0;   // the number of bytes to hash
255 
256   if (this->IsWeeBook()) {
257     size = mAtom_Size;
258     body = ((const morkWeeBookAtom*)this)->mWeeBookAtom_Body;
259   } else if (this->IsBigBook()) {
260     size = ((const morkBigBookAtom*)this)->mBigBookAtom_Size;
261     body = ((const morkBigBookAtom*)this)->mBigBookAtom_Body;
262   } else if (this->IsFarBook()) {
263     size = ((const morkFarBookAtom*)this)->mFarBookAtom_Size;
264     body = ((const morkFarBookAtom*)this)->mFarBookAtom_Body;
265   } else {
266     this->NonBookAtomTypeError(ev);
267     return 0;
268   }
269 
270   const mork_u1* end = body + size;
271   while (body < end) {
272     c = *body++;
273     outHash <<= 4;
274     outHash += c;
275     mork_u4 top = outHash & 0xF0000000L;  // top four bits
276     if (top)                              // any of high four bits equal to one?
277     {
278       outHash ^= (top >> 24);  // fold down high bits
279       outHash ^= top;          // zero top four bits
280     }
281   }
282 
283   return outHash;
284 }
285 
EqualFormAndBody(morkEnv * ev,const morkBookAtom * inAtom) const286 mork_bool morkBookAtom::EqualFormAndBody(morkEnv* ev,
287                                          const morkBookAtom* inAtom) const {
288   mork_bool outEqual = morkBool_kFalse;
289 
290   const mork_u1* body = 0;  // body of inAtom bytes to compare
291   mork_size size;           // the number of inAtom bytes to compare
292   mork_cscode form;         // nominal charset for ioAtom
293 
294   if (inAtom->IsWeeBook()) {
295     size = inAtom->mAtom_Size;
296     body = ((const morkWeeBookAtom*)inAtom)->mWeeBookAtom_Body;
297     form = 0;
298   } else if (inAtom->IsBigBook()) {
299     size = ((const morkBigBookAtom*)inAtom)->mBigBookAtom_Size;
300     body = ((const morkBigBookAtom*)inAtom)->mBigBookAtom_Body;
301     form = ((const morkBigBookAtom*)inAtom)->mBigBookAtom_Form;
302   } else if (inAtom->IsFarBook()) {
303     size = ((const morkFarBookAtom*)inAtom)->mFarBookAtom_Size;
304     body = ((const morkFarBookAtom*)inAtom)->mFarBookAtom_Body;
305     form = ((const morkFarBookAtom*)inAtom)->mFarBookAtom_Form;
306   } else {
307     inAtom->NonBookAtomTypeError(ev);
308     return morkBool_kFalse;
309   }
310 
311   const mork_u1* thisBody = 0;  // body of bytes in this to compare
312   mork_size thisSize;           // the number of bytes in this to compare
313   mork_cscode thisForm;         // nominal charset for this atom
314 
315   if (this->IsWeeBook()) {
316     thisSize = mAtom_Size;
317     thisBody = ((const morkWeeBookAtom*)this)->mWeeBookAtom_Body;
318     thisForm = 0;
319   } else if (this->IsBigBook()) {
320     thisSize = ((const morkBigBookAtom*)this)->mBigBookAtom_Size;
321     thisBody = ((const morkBigBookAtom*)this)->mBigBookAtom_Body;
322     thisForm = ((const morkBigBookAtom*)this)->mBigBookAtom_Form;
323   } else if (this->IsFarBook()) {
324     thisSize = ((const morkFarBookAtom*)this)->mFarBookAtom_Size;
325     thisBody = ((const morkFarBookAtom*)this)->mFarBookAtom_Body;
326     thisForm = ((const morkFarBookAtom*)this)->mFarBookAtom_Form;
327   } else {
328     this->NonBookAtomTypeError(ev);
329     return morkBool_kFalse;
330   }
331 
332   // if atoms are empty, form is irrelevant
333   if (body && thisBody && size == thisSize && (!size || form == thisForm))
334     outEqual = (MORK_MEMCMP(body, thisBody, size) == 0);
335 
336   return outEqual;
337 }
338 
CutBookAtomFromSpace(morkEnv * ev)339 void morkBookAtom::CutBookAtomFromSpace(morkEnv* ev) {
340   morkAtomSpace* space = mBookAtom_Space;
341   if (space) {
342     mBookAtom_Space = 0;
343     space->mAtomSpace_AtomBodies.CutAtom(ev, this);
344     space->mAtomSpace_AtomAids.CutAtom(ev, this);
345   } else
346     ev->NilPointerError();
347 }
348 
morkWeeBookAtom(mork_aid inAid)349 morkWeeBookAtom::morkWeeBookAtom(mork_aid inAid) {
350   mAtom_Kind = morkAtom_kKindWeeBook;
351   mAtom_CellUses = 0;
352   mAtom_Change = morkChange_kNil;
353   mAtom_Size = 0;
354 
355   mBookAtom_Space = 0;
356   mBookAtom_Id = inAid;
357 
358   mWeeBookAtom_Body[0] = 0;
359 }
360 
InitWeeBookAtom(morkEnv * ev,const morkBuf & inBuf,morkAtomSpace * ioSpace,mork_aid inAid)361 void morkWeeBookAtom::InitWeeBookAtom(morkEnv* ev, const morkBuf& inBuf,
362                                       morkAtomSpace* ioSpace, mork_aid inAid) {
363   mAtom_Kind = 0;
364   mAtom_Change = morkChange_kNil;
365   if (ioSpace) {
366     if (inAid) {
367       if (inBuf.mBuf_Fill <= morkAtom_kMaxByteSize) {
368         mAtom_CellUses = 0;
369         mAtom_Kind = morkAtom_kKindWeeBook;
370         mBookAtom_Space = ioSpace;
371         mBookAtom_Id = inAid;
372         mork_size size = inBuf.mBuf_Fill;
373         mAtom_Size = (mork_u1)size;
374         if (size && inBuf.mBuf_Body)
375           MORK_MEMCPY(mWeeBookAtom_Body, inBuf.mBuf_Body, size);
376 
377         mWeeBookAtom_Body[size] = 0;
378       } else
379         this->AtomSizeOverflowError(ev);
380     } else
381       this->ZeroAidError(ev);
382   } else
383     ev->NilPointerError();
384 }
385 
InitBigBookAtom(morkEnv * ev,const morkBuf & inBuf,mork_cscode inForm,morkAtomSpace * ioSpace,mork_aid inAid)386 void morkBigBookAtom::InitBigBookAtom(morkEnv* ev, const morkBuf& inBuf,
387                                       mork_cscode inForm,
388                                       morkAtomSpace* ioSpace, mork_aid inAid) {
389   mAtom_Kind = 0;
390   mAtom_Change = morkChange_kNil;
391   if (ioSpace) {
392     if (inAid) {
393       mAtom_CellUses = 0;
394       mAtom_Kind = morkAtom_kKindBigBook;
395       mAtom_Size = 0;
396       mBookAtom_Space = ioSpace;
397       mBookAtom_Id = inAid;
398       mBigBookAtom_Form = inForm;
399       mork_size size = inBuf.mBuf_Fill;
400       mBigBookAtom_Size = size;
401       if (size && inBuf.mBuf_Body)
402         MORK_MEMCPY(mBigBookAtom_Body, inBuf.mBuf_Body, size);
403 
404       mBigBookAtom_Body[size] = 0;
405     } else
406       this->ZeroAidError(ev);
407   } else
408     ev->NilPointerError();
409 }
410 
InitFarBookAtom(morkEnv * ev,const morkBuf & inBuf,mork_cscode inForm,morkAtomSpace * ioSpace,mork_aid inAid)411 void morkFarBookAtom::InitFarBookAtom(morkEnv* ev, const morkBuf& inBuf,
412                                       mork_cscode inForm,
413                                       morkAtomSpace* ioSpace, mork_aid inAid) {
414   mAtom_Kind = 0;
415   mAtom_Change = morkChange_kNil;
416   if (ioSpace) {
417     if (inAid) {
418       mAtom_CellUses = 0;
419       mAtom_Kind = morkAtom_kKindFarBook;
420       mAtom_Size = 0;
421       mBookAtom_Space = ioSpace;
422       mBookAtom_Id = inAid;
423       mFarBookAtom_Form = inForm;
424       mFarBookAtom_Size = inBuf.mBuf_Fill;
425       mFarBookAtom_Body = (mork_u1*)inBuf.mBuf_Body;
426     } else
427       this->ZeroAidError(ev);
428   } else
429     ev->NilPointerError();
430 }
431 
432 // 456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
433