1 /*
2 * Copyright 2001-2012 Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 * Rene Gollent (rene@gollent.com)
7 * Erik Jaesler (erik@cgsoftware.com)
8 * Alex Wilson (yourpalal2@gmail.com)
9 */
10
11 /*! BArchivable mix-in class defines the archiving protocol.
12 Also some global archiving functions.
13 */
14
15
16 #include <ctype.h>
17 #include <errno.h>
18 #include <stdlib.h>
19 #include <stdio.h>
20 #include <string>
21 #include <syslog.h>
22 #include <typeinfo>
23 #include <vector>
24
25 #include <AppFileInfo.h>
26 #include <Archivable.h>
27 #include <Entry.h>
28 #include <List.h>
29 #include <OS.h>
30 #include <Path.h>
31 #include <Roster.h>
32 #include <String.h>
33
34 #include <binary_compatibility/Support.h>
35
36 #include "ArchivingManagers.h"
37
38
39 using std::string;
40 using std::vector;
41
42 using namespace BPrivate::Archiving;
43
44 const char* B_CLASS_FIELD = "class";
45 const char* B_ADD_ON_FIELD = "add_on";
46 const int32 FUNC_NAME_LEN = 1024;
47
48 // TODO: consider moving these to a separate module, and making them more
49 // full-featured (e.g., taking NS::ClassName::Function(Param p) instead
50 // of just NS::ClassName)
51
52
53 static status_t
demangle_class_name(const char * name,BString & out)54 demangle_class_name(const char* name, BString& out)
55 {
56 // TODO: add support for template classes
57 // _find__t12basic_string3ZcZt18string_char_traits1ZcZt24__default_alloc_template2b0i0PCccUlUl
58
59 out = "";
60
61 #if __GNUC__ >= 4
62 if (name[0] == 'N')
63 name++;
64 int nameLen;
65 bool first = true;
66 while ((nameLen = strtoul(name, (char**)&name, 10))) {
67 if (!first)
68 out += "::";
69 else
70 first = false;
71 out.Append(name, nameLen);
72 name += nameLen;
73 }
74 if (first)
75 return B_BAD_VALUE;
76
77 #else
78 if (name[0] == 'Q') {
79 // The name is in a namespace
80 int namespaceCount = 0;
81 name++;
82 if (name[0] == '_') {
83 // more than 10 namespaces deep
84 if (!isdigit(*++name))
85 return B_BAD_VALUE;
86
87 namespaceCount = strtoul(name, (char**)&name, 10);
88 if (name[0] != '_')
89 return B_BAD_VALUE;
90 } else
91 namespaceCount = name[0] - '0';
92
93 name++;
94
95 for (int i = 0; i < namespaceCount - 1; i++) {
96 if (!isdigit(name[0]))
97 return B_BAD_VALUE;
98
99 int nameLength = strtoul(name, (char**)&name, 10);
100 out.Append(name, nameLength);
101 out += "::";
102 name += nameLength;
103 }
104 }
105
106 int nameLength = strtoul(name, (char**)&name, 10);
107 out.Append(name, nameLength);
108 #endif
109
110 return B_OK;
111 }
112
113
114 static void
mangle_class_name(const char * name,BString & out)115 mangle_class_name(const char* name, BString& out)
116 {
117 // TODO: add support for template classes
118 // _find__t12basic_string3ZcZt18string_char_traits1ZcZt24__default_alloc_template2b0i0PCccUlUl
119
120 // Chop this:
121 // testthree::testfour::Testthree::Testfour
122 // up into little bite-sized pieces
123 int count = 0;
124 string origName(name);
125 vector<string> spacenames;
126
127 string::size_type pos = 0;
128 string::size_type oldpos = 0;
129 while (pos != string::npos) {
130 pos = origName.find_first_of("::", oldpos);
131 spacenames.push_back(string(origName, oldpos, pos - oldpos));
132 pos = origName.find_first_not_of("::", pos);
133 oldpos = pos;
134 ++count;
135 }
136
137 // Now mangle it into this:
138 // 9testthree8testfour9Testthree8Testfour
139 // (for __GNUC__ > 2)
140 // this isn't always the proper mangled class name, it should
141 // actually have an 'N' prefix and 'E' suffix if the name is
142 // in > 0 namespaces, but these would have to be removed in
143 // build_function_name() (the only place this function is called)
144 // so we don't add them.
145 // or this:
146 // Q49testthree8testfour9Testthree8Testfour
147 // (for __GNUC__ == 2)
148
149 out = "";
150 #if __GNUC__ == 2
151 if (count > 1) {
152 out += 'Q';
153 if (count > 10)
154 out += '_';
155 out << count;
156 if (count > 10)
157 out += '_';
158 }
159 #endif
160
161 for (unsigned int i = 0; i < spacenames.size(); ++i) {
162 out << (int)spacenames[i].length();
163 out += spacenames[i].c_str();
164 }
165 }
166
167
168 static void
build_function_name(const BString & className,BString & funcName)169 build_function_name(const BString& className, BString& funcName)
170 {
171 funcName = "";
172
173 // This is what we're after:
174 // Instantiate__Q28OpenBeOS11BArchivableP8BMessage
175 mangle_class_name(className.String(), funcName);
176 #if __GNUC__ >= 4
177 funcName.Prepend("_ZN");
178 funcName.Append("11InstantiateE");
179 #else
180 funcName.Prepend("Instantiate__");
181 #endif
182 funcName.Append("P8BMessage");
183 }
184
185
186 static bool
add_private_namespace(BString & name)187 add_private_namespace(BString& name)
188 {
189 if (name.Compare("_", 1) != 0)
190 return false;
191
192 name.Prepend("BPrivate::");
193 return true;
194 }
195
196
197 static instantiation_func
find_function_in_image(BString & funcName,image_id id,status_t & err)198 find_function_in_image(BString& funcName, image_id id, status_t& err)
199 {
200 instantiation_func instantiationFunc = NULL;
201 err = get_image_symbol(id, funcName.String(), B_SYMBOL_TYPE_TEXT,
202 (void**)&instantiationFunc);
203 if (err != B_OK)
204 return NULL;
205
206 return instantiationFunc;
207 }
208
209
210 static status_t
check_signature(const char * signature,image_info & info)211 check_signature(const char* signature, image_info& info)
212 {
213 if (signature == NULL) {
214 // If it wasn't specified, anything "matches"
215 return B_OK;
216 }
217
218 // Get image signature
219 BFile file(info.name, B_READ_ONLY);
220 status_t err = file.InitCheck();
221 if (err != B_OK)
222 return err;
223
224 char imageSignature[B_MIME_TYPE_LENGTH];
225 BAppFileInfo appFileInfo(&file);
226 err = appFileInfo.GetSignature(imageSignature);
227 if (err != B_OK) {
228 syslog(LOG_ERR, "instantiate_object - couldn't get mime sig for %s",
229 info.name);
230 return err;
231 }
232
233 if (strcmp(signature, imageSignature) != 0)
234 return B_MISMATCHED_VALUES;
235
236 return B_OK;
237 }
238
239
240 namespace BPrivate {
241
242 instantiation_func
find_instantiation_func(const char * className,const char * signature,image_id * id)243 find_instantiation_func(const char* className, const char* signature,
244 image_id* id)
245 {
246 if (className == NULL) {
247 errno = B_BAD_VALUE;
248 return NULL;
249 }
250
251 thread_info threadInfo;
252 status_t err = get_thread_info(find_thread(NULL), &threadInfo);
253 if (err != B_OK) {
254 errno = err;
255 return NULL;
256 }
257
258 instantiation_func instantiationFunc = NULL;
259 image_info imageInfo;
260
261 BString name = className;
262 for (int32 pass = 0; pass < 2; pass++) {
263 BString funcName;
264 build_function_name(name, funcName);
265
266 // for each image_id in team_id
267 int32 cookie = 0;
268 while (instantiationFunc == NULL
269 && get_next_image_info(threadInfo.team, &cookie, &imageInfo)
270 == B_OK) {
271 instantiationFunc = find_function_in_image(funcName, imageInfo.id,
272 err);
273 }
274 if (instantiationFunc != NULL) {
275 // if requested, save the image id in
276 // which the function was found
277 if (id != NULL)
278 *id = imageInfo.id;
279 break;
280 }
281
282 // Check if we have a private class, and add the BPrivate namespace
283 // (for backwards compatibility)
284 if (!add_private_namespace(name))
285 break;
286 }
287
288 if (instantiationFunc != NULL
289 && check_signature(signature, imageInfo) != B_OK)
290 return NULL;
291
292 return instantiationFunc;
293 }
294
295 } // namespace BPrivate
296
297
298 // #pragma mark - BArchivable
299
300
BArchivable()301 BArchivable::BArchivable()
302 :
303 fArchivingToken(NULL_TOKEN)
304 {
305 }
306
307
BArchivable(BMessage * from)308 BArchivable::BArchivable(BMessage* from)
309 :
310 fArchivingToken(NULL_TOKEN)
311 {
312 if (BUnarchiver::IsArchiveManaged(from)) {
313 BUnarchiver::PrepareArchive(from);
314 BUnarchiver(from).RegisterArchivable(this);
315 }
316 }
317
318
~BArchivable()319 BArchivable::~BArchivable()
320 {
321 }
322
323
324 status_t
Archive(BMessage * into,bool deep) const325 BArchivable::Archive(BMessage* into, bool deep) const
326 {
327 if (!into) {
328 // TODO: logging/other error reporting?
329 return B_BAD_VALUE;
330 }
331
332 if (BManagerBase::ArchiveManager(into))
333 BArchiver(into).RegisterArchivable(this);
334
335 BString name;
336 status_t status = demangle_class_name(typeid(*this).name(), name);
337 if (status != B_OK)
338 return status;
339
340 return into->AddString(B_CLASS_FIELD, name);
341 }
342
343
344 BArchivable*
Instantiate(BMessage * from)345 BArchivable::Instantiate(BMessage* from)
346 {
347 debugger("Can't create a plain BArchivable object");
348 return NULL;
349 }
350
351
352 status_t
Perform(perform_code d,void * arg)353 BArchivable::Perform(perform_code d, void* arg)
354 {
355 switch (d) {
356 case PERFORM_CODE_ALL_UNARCHIVED:
357 {
358 perform_data_all_unarchived* data =
359 (perform_data_all_unarchived*)arg;
360
361 data->return_value = BArchivable::AllUnarchived(data->archive);
362 return B_OK;
363 }
364
365 case PERFORM_CODE_ALL_ARCHIVED:
366 {
367 perform_data_all_archived* data =
368 (perform_data_all_archived*)arg;
369
370 data->return_value = BArchivable::AllArchived(data->archive);
371 return B_OK;
372 }
373 }
374
375 return B_NAME_NOT_FOUND;
376 }
377
378
379 status_t
AllUnarchived(const BMessage * archive)380 BArchivable::AllUnarchived(const BMessage* archive)
381 {
382 return B_OK;
383 }
384
385
386 status_t
AllArchived(BMessage * archive) const387 BArchivable::AllArchived(BMessage* archive) const
388 {
389 return B_OK;
390 }
391
392
393 // #pragma mark - BArchiver
394
395
BArchiver(BMessage * archive)396 BArchiver::BArchiver(BMessage* archive)
397 :
398 fManager(BManagerBase::ArchiveManager(archive)),
399 fArchive(archive),
400 fFinished(false)
401 {
402 if (fManager == NULL)
403 fManager = new BArchiveManager(this);
404 }
405
406
~BArchiver()407 BArchiver::~BArchiver()
408 {
409 if (!fFinished)
410 fManager->ArchiverLeaving(this, B_OK);
411 }
412
413
414 status_t
AddArchivable(const char * name,BArchivable * archivable,bool deep)415 BArchiver::AddArchivable(const char* name, BArchivable* archivable, bool deep)
416 {
417 int32 token;
418 status_t err = GetTokenForArchivable(archivable, deep, token);
419
420 if (err != B_OK)
421 return err;
422
423 return fArchive->AddInt32(name, token);
424 }
425
426
427 status_t
GetTokenForArchivable(BArchivable * archivable,bool deep,int32 & _token)428 BArchiver::GetTokenForArchivable(BArchivable* archivable,
429 bool deep, int32& _token)
430 {
431 return fManager->ArchiveObject(archivable, deep, _token);
432 }
433
434
435 bool
IsArchived(BArchivable * archivable)436 BArchiver::IsArchived(BArchivable* archivable)
437 {
438 return fManager->IsArchived(archivable);
439 }
440
441
442 status_t
Finish(status_t err)443 BArchiver::Finish(status_t err)
444 {
445 if (fFinished)
446 debugger("Finish() called multiple times on same BArchiver.");
447
448 fFinished = true;
449
450 return fManager->ArchiverLeaving(this, err);
451 }
452
453
454 BMessage*
ArchiveMessage() const455 BArchiver::ArchiveMessage() const
456 {
457 return fArchive;
458 }
459
460
461 void
RegisterArchivable(const BArchivable * archivable)462 BArchiver::RegisterArchivable(const BArchivable* archivable)
463 {
464 fManager->RegisterArchivable(archivable);
465 }
466
467
468 // #pragma mark - BUnarchiver
469
470
BUnarchiver(const BMessage * archive)471 BUnarchiver::BUnarchiver(const BMessage* archive)
472 :
473 fManager(BManagerBase::UnarchiveManager(archive)),
474 fArchive(archive),
475 fFinished(false)
476 {
477 }
478
479
~BUnarchiver()480 BUnarchiver::~BUnarchiver()
481 {
482 if (!fFinished && fManager)
483 fManager->UnarchiverLeaving(this, B_OK);
484 }
485
486
487 template<>
488 status_t
GetObject(int32 token,ownership_policy owning,BArchivable * & object)489 BUnarchiver::GetObject<BArchivable>(int32 token,
490 ownership_policy owning, BArchivable*& object)
491 {
492 _CallDebuggerIfManagerNull();
493 return fManager->GetArchivableForToken(token, owning, object);
494 }
495
496
497 template<>
498 status_t
FindObject(const char * name,int32 index,ownership_policy owning,BArchivable * & archivable)499 BUnarchiver::FindObject<BArchivable>(const char* name,
500 int32 index, ownership_policy owning, BArchivable*& archivable)
501 {
502 archivable = NULL;
503 int32 token;
504 status_t err = fArchive->FindInt32(name, index, &token);
505 if (err != B_OK)
506 return err;
507
508 return GetObject(token, owning, archivable);
509 }
510
511
512 bool
IsInstantiated(int32 token)513 BUnarchiver::IsInstantiated(int32 token)
514 {
515 _CallDebuggerIfManagerNull();
516 return fManager->IsInstantiated(token);
517 }
518
519
520 bool
IsInstantiated(const char * field,int32 index)521 BUnarchiver::IsInstantiated(const char* field, int32 index)
522 {
523 int32 token;
524 if (fArchive->FindInt32(field, index, &token) == B_OK)
525 return IsInstantiated(token);
526
527 return false;
528 }
529
530
531 status_t
Finish(status_t err)532 BUnarchiver::Finish(status_t err)
533 {
534 if (fFinished)
535 debugger("Finish() called multiple times on same BArchiver.");
536
537 fFinished = true;
538 if (fManager)
539 return fManager->UnarchiverLeaving(this, err);
540 else
541 return B_OK;
542 }
543
544
545 const BMessage*
ArchiveMessage() const546 BUnarchiver::ArchiveMessage() const
547 {
548 return fArchive;
549 }
550
551
552 void
AssumeOwnership(BArchivable * archivable)553 BUnarchiver::AssumeOwnership(BArchivable* archivable)
554 {
555 _CallDebuggerIfManagerNull();
556 fManager->AssumeOwnership(archivable);
557 }
558
559
560 void
RelinquishOwnership(BArchivable * archivable)561 BUnarchiver::RelinquishOwnership(BArchivable* archivable)
562 {
563 _CallDebuggerIfManagerNull();
564 fManager->RelinquishOwnership(archivable);
565 }
566
567
568 bool
IsArchiveManaged(const BMessage * archive)569 BUnarchiver::IsArchiveManaged(const BMessage* archive)
570 {
571 // managed child archives will return here
572 if (BManagerBase::ManagerPointer(archive))
573 return true;
574
575 if (archive == NULL)
576 return false;
577
578 // managed top level archives return here
579 bool dummy;
580 if (archive->FindBool(kManagedField, &dummy) == B_OK)
581 return true;
582
583 return false;
584 }
585
586
587 template<>
588 status_t
InstantiateObject(BMessage * from,BArchivable * & object)589 BUnarchiver::InstantiateObject<BArchivable>(BMessage* from,
590 BArchivable* &object)
591 {
592 BUnarchiver unarchiver(BUnarchiver::PrepareArchive(from));
593 object = instantiate_object(from);
594 return unarchiver.Finish();
595 }
596
597
598 BMessage*
PrepareArchive(BMessage * & archive)599 BUnarchiver::PrepareArchive(BMessage* &archive)
600 {
601 // this check allows PrepareArchive to be
602 // called on new or old-style archives
603 if (BUnarchiver::IsArchiveManaged(archive)) {
604 BUnarchiveManager* manager = BManagerBase::UnarchiveManager(archive);
605 if (!manager)
606 manager = new BUnarchiveManager(archive);
607
608 manager->Acquire();
609 }
610
611 return archive;
612 }
613
614
615 void
RegisterArchivable(BArchivable * archivable)616 BUnarchiver::RegisterArchivable(BArchivable* archivable)
617 {
618 _CallDebuggerIfManagerNull();
619 fManager->RegisterArchivable(archivable);
620 }
621
622
623 void
_CallDebuggerIfManagerNull()624 BUnarchiver::_CallDebuggerIfManagerNull()
625 {
626 if (!fManager)
627 debugger("BUnarchiver used with legacy or unprepared archive.");
628 }
629
630
631 // #pragma mark -
632
633
634 BArchivable*
instantiate_object(BMessage * archive,image_id * _id)635 instantiate_object(BMessage* archive, image_id* _id)
636 {
637 status_t statusBuffer;
638 status_t* status = &statusBuffer;
639 if (_id != NULL)
640 status = _id;
641
642 // Check our params
643 if (archive == NULL) {
644 syslog(LOG_ERR, "instantiate_object failed: NULL BMessage argument");
645 *status = B_BAD_VALUE;
646 return NULL;
647 }
648
649 // Get class name from archive
650 const char* className = NULL;
651 status_t err = archive->FindString(B_CLASS_FIELD, &className);
652 if (err) {
653 syslog(LOG_ERR, "instantiate_object failed: Failed to find an entry "
654 "defining the class name (%s).", strerror(err));
655 *status = B_BAD_VALUE;
656 return NULL;
657 }
658
659 // Get sig from archive
660 const char* signature = NULL;
661 bool hasSignature = archive->FindString(B_ADD_ON_FIELD, &signature) == B_OK;
662
663 instantiation_func instantiationFunc = BPrivate::find_instantiation_func(
664 className, signature, _id);
665
666 // if find_instantiation_func() can't locate Class::Instantiate()
667 // and a signature was specified
668 if (!instantiationFunc && hasSignature) {
669 // use BRoster::FindApp() to locate an app or add-on with the symbol
670 BRoster Roster;
671 entry_ref ref;
672 err = Roster.FindApp(signature, &ref);
673
674 // if an entry_ref is obtained
675 BEntry entry;
676 if (err == B_OK)
677 err = entry.SetTo(&ref);
678
679 BPath path;
680 if (err == B_OK)
681 err = entry.GetPath(&path);
682
683 if (err != B_OK) {
684 syslog(LOG_ERR, "instantiate_object failed: Error finding app "
685 "with signature \"%s\" (%s)", signature, strerror(err));
686 *status = err;
687 return NULL;
688 }
689
690 // load the app/add-on
691 image_id addOn = load_add_on(path.Path());
692 if (addOn < B_OK) {
693 syslog(LOG_ERR, "instantiate_object failed: Could not load "
694 "add-on %s: %s.", path.Path(), strerror(addOn));
695 *status = addOn;
696 return NULL;
697 }
698
699 // Save the image_id
700 if (_id != NULL)
701 *_id = addOn;
702
703 BString name = className;
704 for (int32 pass = 0; pass < 2; pass++) {
705 BString funcName;
706 build_function_name(name, funcName);
707
708 instantiationFunc = find_function_in_image(funcName, addOn, err);
709 if (instantiationFunc != NULL)
710 break;
711
712 // Check if we have a private class, and add the BPrivate namespace
713 // (for backwards compatibility)
714 if (!add_private_namespace(name))
715 break;
716 }
717
718 if (instantiationFunc == NULL) {
719 syslog(LOG_ERR, "instantiate_object failed: Failed to find exported "
720 "Instantiate static function for class %s.", className);
721 *status = B_NAME_NOT_FOUND;
722 return NULL;
723 }
724 } else if (instantiationFunc == NULL) {
725 syslog(LOG_ERR, "instantiate_object failed: No signature specified "
726 "in archive, looking for class \"%s\".", className);
727 *status = B_NAME_NOT_FOUND;
728 return NULL;
729 }
730
731 // if Class::Instantiate(BMessage*) was found
732 if (instantiationFunc != NULL) {
733 // use to create and return an object instance
734 return instantiationFunc(archive);
735 }
736
737 return NULL;
738 }
739
740
741 BArchivable*
instantiate_object(BMessage * from)742 instantiate_object(BMessage* from)
743 {
744 return instantiate_object(from, NULL);
745 }
746
747
748 // #pragma mark - support_globals
749
750
751 bool
validate_instantiation(BMessage * from,const char * className)752 validate_instantiation(BMessage* from, const char* className)
753 {
754 // Make sure our params are kosher -- original skimped here =P
755 if (!from) {
756 errno = B_BAD_VALUE;
757 return false;
758 }
759
760 BString name = className;
761 for (int32 pass = 0; pass < 2; pass++) {
762 const char* archiveClassName;
763 for (int32 index = 0; from->FindString(B_CLASS_FIELD, index,
764 &archiveClassName) == B_OK; ++index) {
765 if (name == archiveClassName) {
766 errno = B_OK;
767 return true;
768 }
769 }
770
771 if (!add_private_namespace(name))
772 break;
773 }
774
775 errno = B_MISMATCHED_VALUES;
776 syslog(LOG_ERR, "validate_instantiation failed on class %s.", className);
777
778 return false;
779 }
780
781
782 instantiation_func
find_instantiation_func(const char * className,const char * signature)783 find_instantiation_func(const char* className, const char* signature)
784 {
785 return BPrivate::find_instantiation_func(className, signature, NULL);
786 }
787
788
789 instantiation_func
find_instantiation_func(const char * className)790 find_instantiation_func(const char* className)
791 {
792 return find_instantiation_func(className, NULL);
793 }
794
795
796 instantiation_func
find_instantiation_func(BMessage * archive)797 find_instantiation_func(BMessage* archive)
798 {
799 if (archive == NULL) {
800 errno = B_BAD_VALUE;
801 return NULL;
802 }
803
804 const char* name = NULL;
805 const char* signature = NULL;
806 if (archive->FindString(B_CLASS_FIELD, &name) != B_OK
807 || archive->FindString(B_ADD_ON_FIELD, &signature)) {
808 errno = B_BAD_VALUE;
809 return NULL;
810 }
811
812 return find_instantiation_func(name, signature);
813 }
814
815
816 // #pragma mark - BArchivable binary compatibility
817
818
819 #if __GNUC__ == 2
820
821 extern "C" status_t
_ReservedArchivable1__11BArchivable(BArchivable * archivable,const BMessage * archive)822 _ReservedArchivable1__11BArchivable(BArchivable* archivable,
823 const BMessage* archive)
824 {
825 // AllUnarchived
826 perform_data_all_unarchived performData;
827 performData.archive = archive;
828
829 archivable->Perform(PERFORM_CODE_ALL_UNARCHIVED, &performData);
830 return performData.return_value;
831 }
832
833
834 extern "C" status_t
_ReservedArchivable2__11BArchivable(BArchivable * archivable,BMessage * archive)835 _ReservedArchivable2__11BArchivable(BArchivable* archivable,
836 BMessage* archive)
837 {
838 // AllArchived
839 perform_data_all_archived performData;
840 performData.archive = archive;
841
842 archivable->Perform(PERFORM_CODE_ALL_ARCHIVED, &performData);
843 return performData.return_value;
844 }
845
846
847 #elif __GNUC__ > 2
848
849 extern "C" status_t
_ZN11BArchivable20_ReservedArchivable1Ev(BArchivable * archivable,const BMessage * archive)850 _ZN11BArchivable20_ReservedArchivable1Ev(BArchivable* archivable,
851 const BMessage* archive)
852 {
853 // AllUnarchived
854 perform_data_all_unarchived performData;
855 performData.archive = archive;
856
857 archivable->Perform(PERFORM_CODE_ALL_UNARCHIVED, &performData);
858 return performData.return_value;
859 }
860
861
862 extern "C" status_t
_ZN11BArchivable20_ReservedArchivable2Ev(BArchivable * archivable,BMessage * archive)863 _ZN11BArchivable20_ReservedArchivable2Ev(BArchivable* archivable,
864 BMessage* archive)
865 {
866 // AllArchived
867 perform_data_all_archived performData;
868 performData.archive = archive;
869
870 archivable->Perform(PERFORM_CODE_ALL_ARCHIVED, &performData);
871 return performData.return_value;
872 }
873
874 #endif // _GNUC__ > 2
875
876
_ReservedArchivable3()877 void BArchivable::_ReservedArchivable3() {}
878