2 SuperCollider real time audio synthesis system
3 Copyright (c) 2002 James McCartney. All rights reserved.
4 http://www.audiosynth.com
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 An object archiving system for SuperCollider.
30 #include "PyrObject.h"
31 #include "SC_AllocPool.h"
33 #include "PyrKernel.h"
34 #include "PyrPrimitive.h"
35 #include "PyrSymbol.h"
36 #include "VMGlobals.h"
38 #include "ReadWriteMacros.h"
41 const int32 kArchHdrSize
= 12;
42 const int32 kObjectArrayInitialCapacity
= 32;
48 PyrArchiver(VMGlobals
*inG
)
49 : g(inG
), mObjectArray(mInitialObjectArray
), mNumObjects(0),
50 mObjectArrayCapacity( kObjectArrayInitialCapacity
),
51 mReadArchiveVersion(0)
57 if (mObjectArray
!= mInitialObjectArray
) {
58 g
->allocPool
->Free(mObjectArray
);
62 void setStream(S s
) { mStream
.SetStream(s
); }
64 int32
calcArchiveSize()
67 int32 size
= kArchHdrSize
;
68 if (mNumObjects
== 0) {
69 size
+= sizeOfElem(&mTopSlot
) + 1;
72 for (int i
=0; i
<mNumObjects
; ++i
) {
73 PyrObject
* obj
= mObjectArray
[i
];
74 size
+= slotRawSymbol(&obj
->classptr
->name
)->length
+ 1; // class name symbol
75 size
+= sizeof(int32
); // size
76 if (obj
->obj_format
<= obj_slot
) {
77 size
+= obj
->size
; // tags
79 for (int j
=0; j
<obj
->size
; ++j
, ++slot
) {
80 size
+= sizeOfElem(slot
);
82 } else if (obj
->obj_format
== obj_symbol
) {
83 PyrSymbol
**symbol
= ((PyrSymbolArray
*)obj
)->symbols
;
84 for (int j
=0; j
<obj
->size
; ++j
, ++symbol
) {
85 size
+= (**symbol
).length
+ 1;
88 size
+= obj
->size
* gFormatElemSize
[obj
->obj_format
];
95 long prepareToWriteArchive(PyrSlot
*objectSlot
)
100 slotCopy(&mTopSlot
, objectSlot
);
101 if (IsObj(objectSlot
)) constructObjectArray(slotRawObject(objectSlot
));
102 } catch (std::exception
&ex
) {
114 writeArchiveHeader();
116 if (mNumObjects
== 0) {
117 writeSlot(&mTopSlot
);
119 for (int i
=0; i
<mNumObjects
; ++i
) {
120 writeObjectHeader(mObjectArray
[i
]);
122 for (int i
=0; i
<mNumObjects
; ++i
) {
123 writeSlots(mObjectArray
[i
]);
126 } catch (std::exception
&ex
) {
133 long readArchive(PyrSlot
*objectSlot
)
135 //postfl("->readArchive\n");
143 //postfl("readObjectHeaders %d\n", mNumObjects);
144 if (mNumObjects
== 0) {
145 readSlot(objectSlot
);
147 for (int i
=0; i
<mNumObjects
; ++i
) {
148 mObjectArray
[i
] = readObjectHeader();
150 //postfl("readSlots\n");
151 for (int i
=0; i
<mNumObjects
; ++i
) {
152 readSlots(mObjectArray
[i
]);
154 //postfl("done reading\n");
155 //postfl("SetObject\n");
156 SetObject(objectSlot
, mObjectArray
[0]);
158 } catch (std::exception
&ex
) {
164 //postfl("<-readArchive\n");
170 void writeArchiveHeader()
172 mStream
.writeInt32_be(('!'<<24)|('S'<<16)|('C'<<8)|'a' /*'!SCa'*/);
173 mStream
.writeInt32_be(2); // file version
174 mStream
.writeInt32_be(mNumObjects
);
177 void readArchiveHeader()
179 int32 magicNumber
= mStream
.readInt32_be();
180 if (magicNumber
!= (('!'<<24)|('S'<<16)|('C'<<8)|'a' /*'!SCa'*/)) {
181 throw std::runtime_error("not an SC archive.\n");
183 mReadArchiveVersion
= mStream
.readInt32_be(); // file version
184 mNumObjects
= mStream
.readInt32_be();
185 //post("readArchiveHeader %d %d\n", mReadArchiveVersion, mNumObjects);
187 if (mNumObjects
> kObjectArrayInitialCapacity
) {
188 mObjectArray
= (PyrObject
**)g
->allocPool
->Alloc(mNumObjects
* sizeof(PyrObject
*));
189 mObjectArrayCapacity
= mNumObjects
;
194 void recurse(PyrObject
*obj
, int n
)
196 PyrSlot
*slot
= obj
->slots
;
197 for (int i
=0; i
<n
; ++i
, ++slot
) {
198 if (IsObj(slot
)) constructObjectArray(slotRawObject(slot
));
202 void growObjectArray()
204 int32 newObjectArrayCapacity
= mObjectArrayCapacity
<< 1;
206 int32 newSize
= newObjectArrayCapacity
* sizeof(PyrObject
*);
207 PyrObject
** newArray
= (PyrObject
**)g
->allocPool
->Alloc(newSize
);
208 memcpy(newArray
, mObjectArray
, mNumObjects
* sizeof(PyrObject
*));
209 if (mObjectArray
!= mInitialObjectArray
) {
210 g
->allocPool
->Free(mObjectArray
);
212 mObjectArrayCapacity
= newObjectArrayCapacity
;
213 mObjectArray
= newArray
;
216 void putObject(PyrObject
*obj
)
219 obj
->scratch1
= mNumObjects
;
221 // expand array if needed
222 if (mNumObjects
>= mObjectArrayCapacity
) growObjectArray();
225 mObjectArray
[mNumObjects
++] = obj
;
228 void constructObjectArray(PyrObject
*obj
)
230 if (!obj
->IsMarked()) {
231 if (isKindOf(obj
, class_class
)) {
232 } else if (isKindOf(obj
, class_process
)) {
233 } else if (isKindOf(obj
, s_interpreter
->u
.classobj
)) {
234 } else if (isKindOf(obj
, class_method
)) {
235 throw std::runtime_error("cannot archive Methods.\n");
236 } else if (isKindOf(obj
, class_thread
)) {
237 throw std::runtime_error("cannot archive Threads.\n");
238 } else if (isKindOf(obj
, class_frame
)) {
239 throw std::runtime_error("cannot archive Frames.\n");
240 } else if (isKindOf(obj
, class_func
)) {
241 //if (NotNil(&((PyrClosure*)obj)->block.uoblk->context)) {
242 // throw std::runtime_error("open Function can not be archived.\n");
245 recurse(obj
, obj
->size
);
247 if (isKindOf(obj
, class_rawarray
)) {
249 } else if (isKindOf(obj
, class_array
)) {
251 recurse(obj
, obj
->size
);
255 recurse(obj
, obj
->size
);
261 int32
sizeOfElem(PyrSlot
*slot
)
263 //postfl("writeSlot %08X\n", GetTag(slot));
264 switch (GetTag(slot
)) {
266 if (isKindOf(slotRawObject(slot
), class_class
)) {
267 return slotRawSymbol(&slotRawClass(slot
)->name
)->length
+ 1;
268 } else if (isKindOf(slotRawObject(slot
), class_process
)) {
270 } else if (isKindOf(slotRawObject(slot
), class_frame
)) {
272 } else if (isKindOf(slotRawObject(slot
), s_interpreter
->u
.classobj
)) {
275 return sizeof(int32
);
279 return sizeof(int32
);
281 return slotRawSymbol(slot
)->length
+ 1;
283 return sizeof(int32
);
291 throw std::runtime_error("cannot archive RawPointers.");
294 return sizeof(double);
298 PyrSymbol
* readSymbolID()
301 mStream
.readSymbol(str
);
306 PyrObject
* readObjectID()
308 int32 objID
= mStream
.readInt32_be();
309 //postfl("readObjectID %d\n", objID);
310 return mObjectArray
[objID
];
313 void writeObjectHeader(PyrObject
*obj
)
317 //postfl("writeObjectHeader %s\n", slotRawSymbol(&obj->classptr->name)->name);
318 mStream
.writeSymbol(slotRawSymbol(&obj
->classptr
->name
)->name
);
320 mStream
.writeInt32_be(obj
->size
);
323 PyrObject
* readObjectHeader()
325 PyrSymbol
* classname
= readSymbolID();
326 //post("readObjectHeader %s\n", classname->name);
328 int32 size
= mStream
.readInt32_be();
329 if (slotRawInt(&classname
->u
.classobj
->classFlags
) & classHasIndexableInstances
) {
330 obj
= instantiateObject(g
->gc
, classname
->u
.classobj
, size
, false, false);
333 obj
= instantiateObject(g
->gc
, classname
->u
.classobj
, 0, false, false);
338 void writeSlots(PyrObject
*obj
)
340 //postfl(" writeSlots %s\n", slotRawSymbol(&obj->classptr->name)->name);
341 if (isKindOf(obj
, class_rawarray
)) {
343 } else if (isKindOf(obj
, class_func
)) {
344 PyrClosure
* closure
= (PyrClosure
*)obj
;
345 if (NotNil(&slotRawBlock(&closure
->block
)->contextDef
)) {
346 writeSlot(&closure
->block
);
347 writeSlot(&closure
->context
);
349 writeSlot(&closure
->block
);
353 for (int i
=0; i
<obj
->size
; ++i
) {
354 writeSlot(obj
->slots
+ i
);
359 void readSlots(PyrObject
*obj
)
361 //postfl("readSlots\n");
362 if (isKindOf(obj
, class_rawarray
)) {
364 } else if (isKindOf(obj
, class_func
)) {
365 PyrClosure
* closure
= (PyrClosure
*)obj
;
366 readSlot(&closure
->block
);
367 readSlot(&closure
->context
);
368 if (IsNil(&closure
->context
)) {
369 slotCopy(&closure
->context
, &slotRawInterpreter(&g
->process
->interpreter
)->context
);
372 for (int i
=0; i
<obj
->size
; ++i
) {
373 readSlot(obj
->slots
+ i
);
378 void writeSlot(PyrSlot
*slot
)
381 //postfl(" writeSlot %08X\n", GetTag(slot));
382 switch (GetTag(slot
)) {
384 obj
= slotRawObject(slot
);
385 if (isKindOf(obj
, class_class
)) {
386 mStream
.writeInt8('C');
387 mStream
.writeSymbol(slotRawSymbol(&slotRawClass(slot
)->name
)->name
);
388 } else if (isKindOf(obj
, class_process
)) {
389 mStream
.writeInt8('P');
390 } else if (isKindOf(obj
, s_interpreter
->u
.classobj
)) {
391 mStream
.writeInt8('R');
393 mStream
.writeInt8('o');
394 mStream
.writeInt32_be(obj
->scratch1
);
398 mStream
.writeInt8('i');
399 mStream
.writeInt32_be(slotRawInt(slot
));
402 mStream
.writeInt8('s');
403 mStream
.writeSymbol(slotRawSymbol(slot
)->name
);
406 mStream
.writeInt8('c');
407 mStream
.writeInt32_be(slotRawInt(slot
));
410 mStream
.writeInt8('N');
413 mStream
.writeInt8('F');
416 mStream
.writeInt8('T');
419 mStream
.writeInt8('N');
422 mStream
.writeInt8('f');
423 mStream
.writeDouble_be(slotRawFloat(slot
));
428 void readSlot(PyrSlot
*slot
)
430 char tag
= mStream
.readInt8();
433 SetObject(slot
, readObjectID());
436 SetObject(slot
, (PyrObject
*)(size_t)mStream
.readInt32_be()); // FIXME: fix 64bit safety
439 SetObject(slot
, (PyrObject
*)readSymbolID()->u
.classobj
);
442 SetObject(slot
, (PyrObject
*)g
->process
);
445 SetObject(slot
, slotRawObject(&g
->process
->interpreter
));
448 SetInt(slot
, mStream
.readInt32_be());
451 SetSymbol(slot
, readSymbolID());
454 SetChar(slot
, mStream
.readInt32_be());
457 SetFloat(slot
, mStream
.readDouble_be());
472 void writeRawArray(PyrObject
*obj
)
474 int32 size
= obj
->size
;
475 //postfl("writeRawArray %d\n", size);
476 switch (obj
->obj_format
) {
479 char *data
= (char*)obj
->slots
;
480 mStream
.writeData(data
, size
);
483 int16
*data
= (int16
*)obj
->slots
;
484 for (int i
=0; i
<size
; ++i
) {
485 mStream
.writeInt16_be(data
[i
]);
490 int32
*data
= (int32
*)obj
->slots
;
491 for (int i
=0; i
<size
; ++i
) {
492 mStream
.writeInt32_be(data
[i
]);
496 double *data
= (double*)obj
->slots
;
497 for (int i
=0; i
<size
; ++i
) {
498 mStream
.writeDouble_be(data
[i
]);
502 PyrSymbol
**data
= (PyrSymbol
**)obj
->slots
;
503 for (int i
=0; i
<size
; ++i
) {
504 mStream
.writeSymbol(data
[i
]->name
);
510 void readRawArray(PyrObject
*obj
)
512 //postfl("readRawArray\n");
513 int32 size
= obj
->size
;
514 switch (obj
->obj_format
) {
517 int8
*data
= (int8
*)obj
->slots
;
518 for (int i
=0; i
<size
; ++i
) {
519 data
[i
] = mStream
.readInt8();
523 int16
*data
= (int16
*)obj
->slots
;
524 for (int i
=0; i
<size
; ++i
) {
525 data
[i
] = mStream
.readInt16_be();
530 int32
*data
= (int32
*)obj
->slots
;
531 for (int i
=0; i
<size
; ++i
) {
532 data
[i
] = mStream
.readInt32_be();
536 double *data
= (double*)obj
->slots
;
537 for (int i
=0; i
<size
; ++i
) {
538 data
[i
] = mStream
.readDouble_be();
542 PyrSymbol
**data
= (PyrSymbol
**)obj
->slots
;
543 for (int i
=0; i
<size
; ++i
) {
544 data
[i
] = readSymbolID();
553 PyrObject
**mObjectArray
;
555 int32 mObjectArrayCapacity
;
558 SC_IOStream
<S
> mStream
;
559 int32 mReadArchiveVersion
;
561 PyrObject
*mInitialObjectArray
[kObjectArrayInitialCapacity
];