xref: /haiku/src/kits/app/Message.cpp (revision 95bac3fda53a4cb21880712d7b43f8c21db32a2e)
1 //------------------------------------------------------------------------------
2 //	Copyright (c) 2001-2005, OpenBeOS
3 //
4 //	Permission is hereby granted, free of charge, to any person obtaining a
5 //	copy of this software and associated documentation files (the "Software"),
6 //	to deal in the Software without restriction, including without limitation
7 //	the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 //	and/or sell copies of the Software, and to permit persons to whom the
9 //	Software is furnished to do so, subject to the following conditions:
10 //
11 //	The above copyright notice and this permission notice shall be included in
12 //	all copies or substantial portions of the Software.
13 //
14 //	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 //	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 //	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 //	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 //	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 //	FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20 //	DEALINGS IN THE SOFTWARE.
21 //
22 //	File Name:		Message.h
23 //	Author(s):		Erik Jaesler (erik@cgsoftware.com)
24 //					DarkWyrm <bpmagic@columbus.rr.com>
25 //					Ingo Weinhold <bonefish@users.sf.net>
26 //	Description:	BMessage class creates objects that store data and that
27 //					can be processed in a message loop.  BMessage objects
28 //					are also used as data containers by the archiving and
29 //					the scripting mechanisms.
30 //------------------------------------------------------------------------------
31 
32 // debugging
33 //#define DBG(x) x
34 #define DBG(x)	;
35 #define PRINT(x)	DBG({ printf("[%6ld] ", find_thread(NULL)); printf x; })
36 
37 // Standard Includes -----------------------------------------------------------
38 #include <stdio.h>
39 
40 // System Includes -------------------------------------------------------------
41 #include <Application.h>
42 #include <BlockCache.h>
43 #include <ByteOrder.h>
44 #include <Errors.h>
45 #include <Message.h>
46 #include <Messenger.h>
47 #include <MessengerPrivate.h>
48 #include <String.h>
49 
50 //#include <CRTDBG.H>
51 
52 // Project Includes ------------------------------------------------------------
53 #include <AppMisc.h>
54 #include <DataBuffer.h>
55 #include <KMessage.h>
56 #include <MessageBody.h>
57 #include <MessageUtils.h>
58 #include <TokenSpace.h>
59 
60 // Local Includes --------------------------------------------------------------
61 
62 // Local Defines ---------------------------------------------------------------
63 #define	MSG_FIELD_VERSION		'FOB1'
64 
65 // flags for the overall message (the bitfield is 1 byte)
66 #define MSG_FLAG_BIG_ENDIAN		0x01
67 #define MSG_FLAG_INCL_TARGET	0x02
68 #define MSG_FLAG_INCL_REPLY		0x04
69 #define MSG_FLAG_SCRIPT_MSG		0x08
70 // These are for future improvement
71 #if 0
72 #define MSG_FLAG_USE_PREFERRED	0x10
73 #define MSG_FLAG_REPLY_WANTED	0x20
74 #define MSG_FLAG_REPLY_DONE		0x40
75 #define MSG_FLAG_IS_REPLY		0x80
76 
77 #define MSG_FLAG_HDR_MASK		0xF0
78 #endif
79 
80 #define MSG_HEADER_MAX_SIZE		38
81 #define MSG_NAME_MAX_SIZE		256
82 
83 // Globals ---------------------------------------------------------------------
84 
85 using namespace BPrivate;
86 
87 const char* B_SPECIFIER_ENTRY = "specifiers";
88 const char* B_PROPERTY_ENTRY = "property";
89 const char* B_PROPERTY_NAME_ENTRY = "name";
90 
91 BBlockCache* BMessage::sMsgCache = NULL;
92 port_id BMessage::sReplyPorts[sNumReplyPorts];
93 long BMessage::sReplyPortInUse[sNumReplyPorts];
94 
95 
96 static status_t handle_reply(port_id   reply_port,
97                              int32*    pCode,
98                              bigtime_t timeout,
99                              BMessage* reply);
100 
101 static status_t convert_message(const KMessage *fromMessage,
102 	BMessage *toMessage);
103 
104 static ssize_t min_hdr_size();
105 
106 
107 // #pragma mark -
108 
109 class BMessage::Header {
110 public:
111 	Header() {}
112 	Header(const BMessage &message) { ReadFrom(message); }
113 
114 	status_t ReadFrom(BDataIO &stream);
115 	void ReadFrom(const BMessage &message);
116 	status_t WriteTo(BDataIO &stream, bool calculateCheckSum = true) const;
117 	void WriteTo(BMessage &message) const;
118 
119 	uint32	CalculateCheckSum() const;
120 	uint32	CalculateHeaderSize() const;
121 
122 	bool IsSwapped() const { return fSwapped; }
123 
124 	bool HasTarget() const { return (fFlags & MSG_FLAG_INCL_TARGET); }
125 	void SetTarget(int32 token, bool preferred);
126 
127 	void Dump() const;
128 
129 private:
130 	int32	fMagic;
131 	int32	fBodySize;
132 	uint32	fWhat;
133 	uint8	fFlags;
134 	int32	fTargetToken;
135 	port_id	fReplyPort;
136 	int32	fReplyToken;
137 	team_id	fReplyTeam;
138 	bool	fPreferredTarget;
139 	bool	fReplyRequired;
140 	bool	fReplyDone;
141 	bool	fIsReply;
142 	bool	fSwapped;
143 };
144 
145 // ReadFrom
146 status_t
147 BMessage::Header::ReadFrom(BDataIO &stream)
148 {
149 	int32 checkSum;
150 	uchar csBuffer[MSG_HEADER_MAX_SIZE];
151 
152 	TReadHelper read_helper(&stream);
153 	TChecksumHelper checksum_helper(csBuffer);
154 	int32 flattenedSize;
155 
156 	try {
157 		// Get the message version
158 		read_helper(fMagic);
159 
160 		fSwapped = false;
161 		if (fMagic == '1BOF') {
162 			fSwapped = true;
163 		} else if (fMagic == 'FOB1') {
164 			fSwapped = false;
165 		} else {
166 			// This is *not* a message
167 			return B_NOT_A_MESSAGE;
168 		}
169 
170 		read_helper.SetSwap(fSwapped);
171 
172 		// get the checksum
173 		read_helper(checkSum);
174 		// get the size
175 		read_helper(flattenedSize);
176 		checksum_helper.Cache(flattenedSize);
177 		// Get the what
178 		read_helper(fWhat);
179 		checksum_helper.Cache(fWhat);
180 		// Get the flags
181 		read_helper(fFlags);
182 		checksum_helper.Cache(fFlags);
183 
184 		if (fFlags & MSG_FLAG_BIG_ENDIAN) {
185 			// TODO: ???
186 			// Isn't this already indicated by the byte order of the message version?
187 		}
188 		if (fFlags & MSG_FLAG_INCL_TARGET) {
189 			// Get the target data
190 			read_helper(fTargetToken);
191 			checksum_helper.Cache(fTargetToken);
192 		}
193 		if (fFlags & MSG_FLAG_INCL_REPLY) {
194 			// Get the reply port
195 			read_helper(fReplyPort);
196 			read_helper(fReplyToken);
197 			read_helper(fReplyTeam);
198 			checksum_helper.Cache(fReplyPort);
199 			checksum_helper.Cache(fReplyToken);
200 			checksum_helper.Cache(fReplyTeam);
201 
202 			// Get the "big flags"
203 			uint8 bigFlags;
204 			// Get the preferred flag
205 			read_helper(bigFlags);
206 			checksum_helper.Cache(bigFlags);
207 			fPreferredTarget = bigFlags;
208 
209 			// Get the reply requirement flag
210 			read_helper(bigFlags);
211 			checksum_helper.Cache(bigFlags);
212 			fReplyRequired = bigFlags;
213 
214 			// Get the reply done flag
215 			read_helper(bigFlags);
216 			checksum_helper.Cache(bigFlags);
217 			fReplyDone = bigFlags;
218 
219 			// Get the "is reply" flag
220 			read_helper(bigFlags);
221 			checksum_helper.Cache(bigFlags);
222 			fIsReply = bigFlags;
223 		}
224 	} catch (status_t& e) {
225 		return e;
226 	}
227 
228 	fBodySize = flattenedSize - CalculateHeaderSize();
229 
230 	if (checkSum != checksum_helper.CheckSum())
231 		return B_NOT_A_MESSAGE;
232 
233 	return B_OK;
234 }
235 
236 // ReadFrom
237 void
238 BMessage::Header::ReadFrom(const BMessage &message)
239 {
240 	fMagic = MSG_FIELD_VERSION;
241 
242 	fBodySize = message.fBody->FlattenedSize();
243 	fWhat = message.what;
244 	fFlags = 0;
245 #ifdef B_HOST_IS_BENDIAN
246 	fFlags |= MSG_FLAG_BIG_ENDIAN;
247 #endif
248 	if (message.HasSpecifiers())
249 		fFlags |= MSG_FLAG_SCRIPT_MSG;
250 	if (message.fTarget != B_NULL_TOKEN)
251 		fFlags |= MSG_FLAG_INCL_TARGET;
252 	if (message.fReplyTo.port >= 0 &&
253 		message.fReplyTo.target != B_NULL_TOKEN &&
254 		message.fReplyTo.team >= 0) {
255 		fFlags |= MSG_FLAG_INCL_REPLY;
256 	}
257 	fTargetToken = message.fTarget;
258 	fReplyPort = message.fReplyTo.port;
259 	fReplyToken = message.fReplyTo.target;
260 	fReplyTeam = message.fReplyTo.team;
261 	fPreferredTarget = message.fPreferred;
262 	fReplyRequired = message.fReplyRequired;
263 	fReplyDone = message.fReplyDone;
264 	fIsReply = message.fIsReply;
265 }
266 
267 // WriteTo
268 status_t
269 BMessage::Header::WriteTo(BDataIO &stream, bool calculateCheckSum) const
270 {
271 	status_t err = B_OK;
272 	int32 data;
273 
274 	// Write the version of the binary data format
275 	data = fMagic;
276 	write_helper(&stream, (const void*)&data, sizeof (data), err);
277 	if (!err) {
278 		// compute checksum
279 		data = (calculateCheckSum ? CalculateCheckSum() : 0);
280 		write_helper(&stream, (const void*)&data, sizeof (data), err);
281 	}
282 	if (!err) {
283 		// Write the flattened size of the entire message
284 		data = CalculateHeaderSize() + fBodySize;
285 		write_helper(&stream, (const void*)&data, sizeof (data), err);
286 	}
287 	if (!err) {
288 		// Write the 'what' member
289 		write_helper(&stream, (const void*)&fWhat, sizeof (fWhat), err);
290 	}
291 	if (!err) {
292 		// Write the header flags
293 		write_helper(&stream, (const void*)&fFlags, sizeof (fFlags), err);
294 	}
295 
296 	// Write targeting info if necessary
297 	if (!err && (fFlags & MSG_FLAG_INCL_TARGET)) {
298 		data = fPreferredTarget ? B_PREFERRED_TOKEN : fTargetToken;
299 		write_helper(&stream, (const void*)&data, sizeof (data), err);
300 	}
301 
302 	// Write reply info if necessary
303 	if (!err && (fFlags & MSG_FLAG_INCL_REPLY)) {
304 		write_helper(&stream, (const void*)&fReplyPort, sizeof(fReplyPort),
305 			err);
306 		if (!err) {
307 			write_helper(&stream, (const void*)&fReplyToken,
308 						 sizeof(fReplyToken), err);
309 		}
310 		if (!err) {
311 			write_helper(&stream, (const void*)&fReplyTeam,
312 						 sizeof(fReplyTeam), err);
313 		}
314 
315 		uint8 bigFlags;
316 		if (!err) {
317 			bigFlags = fPreferredTarget ? 1 : 0;
318 			write_helper(&stream, (const void*)&bigFlags, sizeof(bigFlags),
319 				err);
320 		}
321 		if (!err)
322 		{
323 			bigFlags = fReplyRequired ? 1 : 0;
324 			write_helper(&stream, (const void*)&bigFlags, sizeof(bigFlags),
325 				err);
326 		}
327 		if (!err)
328 		{
329 			bigFlags = fReplyDone ? 1 : 0;
330 			write_helper(&stream, (const void*)&bigFlags, sizeof(bigFlags),
331 				err);
332 		}
333 		if (!err)
334 		{
335 			bigFlags = fIsReply ? 1 : 0;
336 			write_helper(&stream, (const void*)&bigFlags, sizeof(bigFlags),
337 				err);
338 		}
339 	}
340 
341 	return err;
342 }
343 
344 // WriteTo
345 void
346 BMessage::Header::WriteTo(BMessage &message) const
347 {
348 	// Make way for the new data
349 	message.MakeEmpty();
350 
351 	message.what = fWhat;
352 
353 	message.fHasSpecifiers = fFlags & MSG_FLAG_SCRIPT_MSG;
354 
355 	if (fFlags & MSG_FLAG_INCL_TARGET) {
356 		// Get the target data
357 		message.fTarget = fTargetToken;
358 	}
359 	if (fFlags & MSG_FLAG_INCL_REPLY) {
360 		// Get the reply port
361 		message.fReplyTo.port = fReplyPort;
362 		message.fReplyTo.target = fReplyToken;
363 		message.fReplyTo.team = fReplyTeam;
364 
365 		message.fWasDelivered = true;
366 
367 		message.fPreferred = fPreferredTarget;
368 		if (fPreferredTarget)
369 			message.fTarget = B_PREFERRED_TOKEN;
370 
371 		message.fReplyRequired = fReplyRequired;
372 		message.fReplyDone = fReplyDone;
373 		message.fIsReply = fIsReply;
374 	}
375 }
376 
377 // CalculateCheckSum
378 uint32
379 BMessage::Header::CalculateCheckSum() const
380 {
381 	uchar buffer[MSG_HEADER_MAX_SIZE];
382 	BMemoryIO stream(buffer, sizeof(buffer));
383 	WriteTo(stream, false);
384 	int32 size = stream.Position();
385 	return _checksum_(buffer + 8, size - 8);
386 }
387 
388 // CalculateHeaderSize
389 uint32
390 BMessage::Header::CalculateHeaderSize() const
391 {
392 	ssize_t size = min_hdr_size();
393 
394 	if (fTargetToken != B_NULL_TOKEN)
395 		size += sizeof (fTargetToken);
396 
397 	if (fReplyPort >= 0 && fReplyToken != B_NULL_TOKEN && fReplyTeam >= 0) {
398 		size += sizeof (fReplyPort);
399 		size += sizeof (fReplyToken);
400 		size += sizeof (fReplyTeam);
401 
402 		size += 4;	// For the "big" flags
403 	}
404 
405 	return size;
406 }
407 
408 // SetTarget
409 void
410 BMessage::Header::SetTarget(int32 token, bool preferred)
411 {
412 	fTargetToken = token;
413 	if (fTargetToken == B_NULL_TOKEN)
414 		fFlags &= ~MSG_FLAG_INCL_TARGET;
415 	else
416 		fFlags |= MSG_FLAG_INCL_TARGET;
417 
418 	fPreferredTarget = preferred;
419 }
420 
421 // Dump
422 void
423 BMessage::Header::Dump() const
424 {
425 	printf("BMessage::Header:\n");
426 	printf("  magic:            %lx\n", fMagic);
427 	printf("  body size:        %ld\n", fBodySize);
428 	printf("  what:             %lx\n", fWhat);
429 	printf("  flags:            %x\n", fFlags);
430 	printf("  target token:     %ld\n", fTargetToken);
431 	printf("  reply port:       %ld\n", fReplyPort);
432 	printf("  reply token:      %ld\n", fReplyToken);
433 	printf("  reply team:       %ld\n", fReplyTeam);
434 	printf("  preferred target: %d\n", fPreferredTarget);
435 	printf("  reply required:   %d\n", fReplyRequired);
436 	printf("  reply done:       %d\n", fReplyDone);
437 	printf("  is reply:         %d\n", fIsReply);
438 	printf("  swapped:          %d\n", fSwapped);
439 }
440 
441 // #pragma mark -
442 
443 void BMessage::_ReservedMessage1() {}
444 void BMessage::_ReservedMessage2() {}
445 void BMessage::_ReservedMessage3() {}
446 
447 //------------------------------------------------------------------------------
448 BMessage::BMessage()
449 	:	what(0), fBody(NULL)
450 {
451 	init_data();
452 }
453 //------------------------------------------------------------------------------
454 BMessage::BMessage(uint32 w)
455 	:	fBody(NULL)
456 {
457 	init_data();
458 	what = w;
459 }
460 //------------------------------------------------------------------------------
461 BMessage::BMessage(const BMessage& a_message)
462 	:	fBody(NULL)
463 {
464 	init_data();
465 	*this = a_message;
466 }
467 //------------------------------------------------------------------------------
468 BMessage::BMessage(BMessage *a_message)
469 	:	fBody(NULL)
470 {
471 	init_data();
472 	*this = *a_message;
473 }
474 //------------------------------------------------------------------------------
475 BMessage::~BMessage()
476 {
477 	if (IsSourceWaiting())
478 	{
479 		SendReply(B_NO_REPLY);
480 	}
481 	delete fBody;
482 }
483 //------------------------------------------------------------------------------
484 BMessage& BMessage::operator=(const BMessage& msg)
485 {
486 	what = msg.what;
487 
488 	link = msg.link;
489 	fTarget = msg.fTarget;
490 	fOriginal = msg.fOriginal;
491 	fChangeCount = msg.fChangeCount;
492 	fCurSpecifier = msg.fCurSpecifier;
493 	fPtrOffset = msg.fPtrOffset;
494 
495 	fEntries = msg.fEntries;
496 
497 	fReplyTo.port = msg.fReplyTo.port;
498 	fReplyTo.target = msg.fReplyTo.target;
499 	fReplyTo.team = msg.fReplyTo.team;
500 	fReplyTo.preferred = msg.fReplyTo.preferred;
501 
502 	fPreferred = msg.fPreferred;
503 	fReplyRequired = msg.fReplyRequired;
504 	fReplyDone = msg.fReplyDone;
505 	fIsReply = msg.fIsReply;
506 	fWasDelivered = msg.fWasDelivered;
507 	fReadOnly = msg.fReadOnly;
508 	fHasSpecifiers = msg.fHasSpecifiers;
509 
510 	*fBody = *(msg.fBody);
511 	return *this;
512 }
513 //------------------------------------------------------------------------------
514 void BMessage::init_data()
515 {
516 	what = 0;
517 
518 	link = NULL;
519 	fTarget = B_NULL_TOKEN;
520 	fOriginal = NULL;
521 	fChangeCount = 0;
522 	fCurSpecifier = -1;
523 	fPtrOffset = 0;
524 
525 	fEntries = NULL;
526 
527 	fReplyTo.port = -1;
528 	fReplyTo.target = B_NULL_TOKEN;
529 	fReplyTo.team = -1;
530 	fReplyTo.preferred = false;
531 
532 	fPreferred = false;
533 	fReplyRequired = false;
534 	fReplyDone = false;
535 	fIsReply = false;
536 	fWasDelivered = false;
537 	fReadOnly = false;
538 	fHasSpecifiers = false;
539 
540 	if (fBody)
541 	{
542 		fBody->MakeEmpty();
543 	}
544 	else
545 	{
546 		fBody = new BPrivate::BMessageBody;
547 	}
548 }
549 //------------------------------------------------------------------------------
550 status_t BMessage::GetInfo(type_code typeRequested, int32 which, char** name,
551 						   type_code* typeReturned, int32* count) const
552 {
553 	return fBody->GetInfo(typeRequested, which, name, typeReturned, count);
554 }
555 //------------------------------------------------------------------------------
556 status_t BMessage::GetInfo(const char* name, type_code* type, int32* c) const
557 {
558 	return fBody->GetInfo(name, type, c);
559 }
560 //------------------------------------------------------------------------------
561 status_t BMessage::GetInfo(const char* name, type_code* type,
562 						   bool* fixed_size) const
563 {
564 	return fBody->GetInfo(name, type, fixed_size);
565 }
566 //------------------------------------------------------------------------------
567 int32 BMessage::CountNames(type_code type) const
568 {
569 	return fBody->CountNames(type);
570 }
571 //------------------------------------------------------------------------------
572 bool BMessage::IsEmpty() const
573 {
574 	return fBody->IsEmpty();
575 }
576 //------------------------------------------------------------------------------
577 bool BMessage::IsSystem() const
578 {
579 	char a = char(what >> 24);
580 	char b = char(what >> 16);
581 	char c = char(what >> 8);
582 	char d = char(what);
583 
584 	// The BeBook says:
585 	//		... we've adopted a strict convention for assigning values to all
586 	//		Be-defined constants.  The value assigned will always be formed by
587 	//		combining four characters into a multicharacter constant, with the
588 	//		characters limited to uppercase letters and the underbar
589 	// Between that and what's in AppDefs.h, this algo seems like a safe bet:
590 	if (a == '_' && isupper(b) && isupper(c) && isupper(d))
591 	{
592 		return true;
593 	}
594 
595 	return false;
596 }
597 //------------------------------------------------------------------------------
598 bool BMessage::IsReply() const
599 {
600 	return fIsReply;
601 }
602 //------------------------------------------------------------------------------
603 void BMessage::PrintToStream() const
604 {
605 	printf("\nBMessage: what =  (0x%lX or %ld)\n", what, what);
606 	fBody->PrintToStream();
607 }
608 //------------------------------------------------------------------------------
609 status_t BMessage::Rename(const char* old_entry, const char* new_entry)
610 {
611 	return fBody->Rename(old_entry, new_entry);
612 }
613 //------------------------------------------------------------------------------
614 bool BMessage::WasDelivered() const
615 {
616 	return fWasDelivered;
617 }
618 //------------------------------------------------------------------------------
619 bool BMessage::IsSourceWaiting() const
620 {
621 	return fReplyRequired && !fReplyDone;
622 }
623 //------------------------------------------------------------------------------
624 bool BMessage::IsSourceRemote() const
625 {
626 	return WasDelivered() && fReplyTo.team != BPrivate::current_team();
627 }
628 //------------------------------------------------------------------------------
629 BMessenger BMessage::ReturnAddress() const
630 {
631 	if (WasDelivered())
632 	{
633 		BMessenger messenger;
634 		BMessenger::Private(messenger).SetTo(fReplyTo.team, fReplyTo.port,
635 			fReplyTo.target, fReplyTo.preferred);
636 		return messenger;
637 	}
638 
639 	return BMessenger();
640 }
641 //------------------------------------------------------------------------------
642 const BMessage* BMessage::Previous() const
643 {
644 	// TODO: test
645 	// In particular, look to see if the "_previous_" field is used in R5
646 	if (!fOriginal)
647 	{
648 		BMessage* fOriginal = new BMessage;
649 		if (FindMessage("_previous_", fOriginal) != B_OK)
650 		{
651 			delete fOriginal;
652 			fOriginal = NULL;
653 		}
654 	}
655 
656 	return fOriginal;
657 }
658 //------------------------------------------------------------------------------
659 bool BMessage::WasDropped() const
660 {
661 	return fReadOnly;
662 }
663 //------------------------------------------------------------------------------
664 BPoint BMessage::DropPoint(BPoint* offset) const
665 {
666 	// TODO: Where do we get this stuff???
667 	if (offset)
668 	{
669 		*offset = FindPoint("_drop_offset_");
670 	}
671 	return FindPoint("_drop_point_");
672 }
673 //------------------------------------------------------------------------------
674 status_t BMessage::SendReply(uint32 command, BHandler* reply_to)
675 {
676 	BMessage msg(command);
677 	return SendReply(&msg, reply_to);
678 }
679 //------------------------------------------------------------------------------
680 status_t BMessage::SendReply(BMessage* the_reply, BHandler* reply_to,
681 							 bigtime_t timeout)
682 {
683 	BMessenger messenger(reply_to);
684 	return SendReply(the_reply, messenger, timeout);
685 }
686 //------------------------------------------------------------------------------
687 #if 0
688 template<class Sender>
689 status_t SendReplyHelper(BMessage* the_message, BMessage* the_reply,
690 						 Sender& the_sender)
691 {
692 	BMessenger messenger(the_message->fReplyTo.team, the_message->fReplyTo.port,
693 						 the_message->fReplyTo.target,
694 						 the_message->fReplyTo.preferred);
695 	if (the_message->fReplyRequired)
696 	{
697 		if (the_message->fReplyDone)
698 		{
699 			return B_DUPLICATE_REPLY;
700 		}
701 		the_message->fReplyDone = true;
702 		the_reply->fIsReply = true;
703 		status_t err = the_sender.Send(messenger, the_reply);
704 		the_reply->fIsReply = false;
705 		if (err)
706 		{
707 			if (set_port_owner(messenger.fPort, messenger.fTeam) == B_BAD_TEAM_ID)
708 			{
709 				delete_port(messenger.fPort);
710 			}
711 		}
712 		return err;
713 	}
714 	// no reply required
715 	if (!the_message->fWasDelivered)
716 	{
717 		return B_BAD_REPLY;
718 	}
719 
720 #if 0
721 	char tmp[0x800];
722 	ssize_t size;
723 	char* p = stack_flatten(tmp, sizeof(tmp), true /* include reply */, &size);
724 	the_reply->AddData("_previous_", B_RAW_TYPE, p ? p : tmp, &size);
725 	if (p)
726 	{
727 		free(p);
728 	}
729 #endif
730 	the_reply->AddMessage("_previous_", the_message);
731 	the_reply->fIsReply = true;
732 	status_t err = the_sender.Send(messenger, the_reply);
733 	the_reply->fIsReply = false;
734 	the_reply->RemoveName("_previous_");
735 	return err;
736 };
737 #endif
738 //------------------------------------------------------------------------------
739 #if 0
740 struct Sender1
741 {
742 	BMessenger& reply_to;
743 	bigtime_t timeout;
744 
745 	Sender1(BMessenger& m, bigtime_t t) : reply_to(m), timeout(t) {;}
746 
747 	status_t Send(BMessenger& messenger, BMessage* the_reply)
748 	{
749 		return messenger.SendMessage(the_reply, reply_to, timeout);
750 	}
751 };
752 status_t BMessage::SendReply(BMessage* the_reply, BMessenger reply_to,
753 							 bigtime_t timeout)
754 {
755 	Sender1 mySender(reply_to, timeout);
756 	return SendReplyHelper(this, the_reply, mySender);
757 }
758 #endif
759 status_t BMessage::SendReply(BMessage* the_reply, BMessenger reply_to,
760 							 bigtime_t timeout)
761 {
762 	// TODO: test
763 	BMessenger messenger;
764 
765 	BMessenger::Private messengerPrivate(messenger);
766 	messengerPrivate.SetTo(fReplyTo.team, fReplyTo.port, fReplyTo.target,
767 		fReplyTo.preferred);
768 	if (fReplyRequired)
769 	{
770 		if (fReplyDone)
771 		{
772 			return B_DUPLICATE_REPLY;
773 		}
774 		fReplyDone = true;
775 		the_reply->fIsReply = true;
776 		status_t err = messenger.SendMessage(the_reply, reply_to, timeout);
777 		the_reply->fIsReply = false;
778 		if (err)
779 		{
780 			if (set_port_owner(messengerPrivate.Port(),
781 				messengerPrivate.Team()) == B_BAD_TEAM_ID) {
782 				delete_port(messengerPrivate.Port());
783 			}
784 		}
785 		return err;
786 	}
787 	// no reply required
788 	if (!fWasDelivered)
789 	{
790 		return B_BAD_REPLY;
791 	}
792 
793 	the_reply->AddMessage("_previous_", this);
794 	the_reply->fIsReply = true;
795 	status_t err = messenger.SendMessage(the_reply, reply_to, timeout);
796 	the_reply->fIsReply = false;
797 	the_reply->RemoveName("_previous_");
798 	return err;
799 }
800 //------------------------------------------------------------------------------
801 status_t BMessage::SendReply(uint32 command, BMessage* reply_to_reply)
802 {
803 	BMessage msg(command);
804 	return SendReply(&msg, reply_to_reply);
805 }
806 //------------------------------------------------------------------------------
807 #if 0
808 struct Sender2
809 {
810 	BMessage* reply_to_reply;
811 	bigtime_t send_timeout;
812 	bigtime_t reply_timeout;
813 
814 	Sender2(BMessage* m, bigtime_t t1, bigtime_t t2)
815 		:	reply_to_reply(m), send_timeout(t1), reply_timeout(t2) {;}
816 
817 	status_t Send(BMessenger& messenger, BMessage* the_reply)
818 	{
819 		return messenger.SendMessage(the_reply, reply_to_reply,
820 									 send_timeout, reply_timeout);
821 	}
822 };
823 status_t BMessage::SendReply(BMessage* the_reply, BMessage* reply_to_reply,
824 							 bigtime_t send_timeout, bigtime_t reply_timeout)
825 {
826 	Sender2 mySender(reply_to_reply, send_timeout, reply_timeout);
827 	return SendReplyHelper(this, the_reply, mySender);
828 }
829 #endif
830 status_t BMessage::SendReply(BMessage* the_reply, BMessage* reply_to_reply,
831 							 bigtime_t send_timeout, bigtime_t reply_timeout)
832 {
833 	// TODO: test
834 	BMessenger messenger;
835 	BMessenger::Private messengerPrivate(messenger);
836 	messengerPrivate.SetTo(fReplyTo.team, fReplyTo.port, fReplyTo.target,
837 		fReplyTo.preferred);
838 	if (fReplyRequired)
839 	{
840 		if (fReplyDone)
841 		{
842 			return B_DUPLICATE_REPLY;
843 		}
844 		fReplyDone = true;
845 		the_reply->fIsReply = true;
846 		status_t err = messenger.SendMessage(the_reply, reply_to_reply,
847 											 send_timeout, reply_timeout);
848 		the_reply->fIsReply = false;
849 		if (err)
850 		{
851 			if (set_port_owner(messengerPrivate.Port(),
852 				messengerPrivate.Team()) == B_BAD_TEAM_ID) {
853 				delete_port(messengerPrivate.Port());
854 			}
855 		}
856 		return err;
857 	}
858 	// no reply required
859 	if (!fWasDelivered)
860 	{
861 		return B_BAD_REPLY;
862 	}
863 
864 	the_reply->AddMessage("_previous_", this);
865 	the_reply->fIsReply = true;
866 	status_t err = messenger.SendMessage(the_reply, reply_to_reply,
867 										 send_timeout, reply_timeout);
868 	the_reply->fIsReply = false;
869 	the_reply->RemoveName("_previous_");
870 	return err;
871 }
872 //------------------------------------------------------------------------------
873 ssize_t BMessage::FlattenedSize() const
874 {
875 	return calc_hdr_size(0) + fBody->FlattenedSize();
876 }
877 //------------------------------------------------------------------------------
878 status_t BMessage::Flatten(char* buffer, ssize_t size) const
879 {
880 	return real_flatten(buffer, size);
881 }
882 //------------------------------------------------------------------------------
883 status_t BMessage::Flatten(BDataIO* stream, ssize_t* size) const
884 {
885 	status_t err = B_OK;
886 	ssize_t len = FlattenedSize();
887 	char* buffer = new(nothrow) char[len];
888 	if (buffer)
889 	{
890 		err = Flatten(buffer, len);
891 		if (!err)
892 		{
893 			// size is an optional parameter, don't crash on NULL
894 			if (size != NULL)
895 			{
896 				*size = len;
897 			}
898 			err = stream->Write(buffer, len);
899 			if (err > B_OK)
900 				err = B_OK;
901 		}
902 
903 		delete[] buffer;
904 	}
905 	else
906 	{
907 		err = B_NO_MEMORY;
908 	}
909 
910 	return err;
911 }
912 //------------------------------------------------------------------------------
913 status_t BMessage::Unflatten(const char* flat_buffer)
914 {
915 	if (!flat_buffer)
916 		return B_BAD_VALUE;
917 
918 	// check whether this is a KMessage
919 	if (((KMessage::Header*)flat_buffer)->magic
920 		== KMessage::kMessageHeaderMagic) {
921 		return _UnflattenKMessage(flat_buffer);
922 	}
923 
924 	// assume it's a normal flattened BMessage
925 	uint32 size = ((uint32*)flat_buffer)[2];
926 
927 	BMemoryIO MemIO(flat_buffer, size);
928 	return Unflatten(&MemIO);
929 }
930 //------------------------------------------------------------------------------
931 status_t BMessage::Unflatten(BDataIO* stream)
932 {
933 	Header header;
934 	status_t err = header.ReadFrom(*stream);
935 
936 if (err) {
937 	printf("BMessage::Unflatten(): Reading the header failed: %lx\n", err);
938 }
939 
940 	if (!err)
941 	{
942 		header.WriteTo(*this);
943 		bool swap = header.IsSwapped();
944 
945 		TReadHelper reader(stream, swap);
946 		int8 flags;
947 		type_code type;
948 		uint32 count;
949 		uint32 dataLen;
950 		uint8 nameLen;
951 		char name[MSG_NAME_MAX_SIZE];
952 		unsigned char* databuffer = NULL;
953 
954 		try
955 		{
956 			reader(flags);
957 			while (flags != MSG_LAST_ENTRY)
958 			{
959 				reader(type);
960 				// Is there more than one data item? (!flags & MSG_FLAG_SINGLE_ITEM)
961 				if (flags & MSG_FLAG_SINGLE_ITEM)
962 				{
963 					count = 1;
964 					if (flags & MSG_FLAG_MINI_DATA)
965 					{
966 						uint8 littleLen;
967 						reader(littleLen);
968 						dataLen = littleLen;
969 					}
970 					else
971 					{
972 						reader(dataLen);
973 					}
974 				}
975 				else
976 				{
977 					// Is there a little data? (flags & MSG_FLAG_MINI_DATA)
978 					if (flags & MSG_FLAG_MINI_DATA)
979 					{
980 						// Get item count (1 byte)
981 						uint8 littleCount;
982 						reader(littleCount);
983 						count = littleCount;
984 
985 						// Get data length (1 byte)
986 						uint8 littleLen;
987 						reader(littleLen);
988 						dataLen = littleLen;
989 					}
990 					else
991 					{
992 					// Is there a lot of data? (!flags & MSG_FLAG_MINI_DATA)
993 						// Get item count (4 bytes)
994 						reader(count);
995 						// Get data length (4 bytes)
996 						reader(dataLen);
997 					}
998 				}
999 
1000 				// Get the name length (1 byte)
1001 				reader(nameLen);
1002 				// Get the name (name length bytes)
1003 				reader(name, nameLen);
1004 				name[nameLen] = '\0';
1005 
1006 				// Copy the data into a new buffer to byte align it
1007 				databuffer = (unsigned char*)realloc(databuffer, dataLen);
1008 				if (!databuffer)
1009 					throw B_NO_MEMORY;
1010 				// Get the data
1011 				reader(databuffer, dataLen);
1012 
1013 				// Is the data fixed size? (flags & MSG_FLAG_FIXED_SIZE)
1014 				if (flags & MSG_FLAG_FIXED_SIZE && swap)
1015 				{
1016 					// Make sure to swap the data
1017 					err = swap_data(type, (void*)databuffer, dataLen,
1018 									B_SWAP_ALWAYS);
1019 					if (err)
1020 						throw err;
1021 				}
1022 				// Is the data variable size? (!flags & MSG_FLAG_FIXED_SIZE)
1023 				else if (swap && type == B_REF_TYPE)
1024 				{
1025 					// Apparently, entry_refs are the only variable-length data
1026 					// 	  explicitely swapped -- the dev_t and ino_t
1027 					//    specifically
1028 					byte_swap(*(entry_ref*)databuffer);
1029 				}
1030 
1031 				// Add each data field to the message
1032 				uint32 itemSize = 0;
1033 				if (flags & MSG_FLAG_FIXED_SIZE)
1034 				{
1035 					itemSize = dataLen / count;
1036 				}
1037 				unsigned char* dataPtr = databuffer;
1038 				for (uint32 i = 0; i < count; ++i)
1039 				{
1040 					// Line up for the next item
1041 					if (i)
1042 					{
1043 						if (flags & MSG_FLAG_FIXED_SIZE)
1044 						{
1045 							dataPtr += itemSize;
1046 						}
1047 						else
1048 						{
1049 							// Have to account for 8-byte boundary padding
1050 							// We add 4 because padding as calculated during
1051 							// flattening includes the four-byte size header
1052 							dataPtr += itemSize + calc_padding(itemSize + 4, 8);
1053 						}
1054 					}
1055 
1056 					if ((flags & MSG_FLAG_FIXED_SIZE) == 0)
1057 					{
1058 						itemSize = *(uint32*)dataPtr;
1059 						dataPtr += sizeof (uint32);
1060 					}
1061 
1062 					err = AddData(name, type, dataPtr, itemSize,
1063 								  flags & MSG_FLAG_FIXED_SIZE);
1064 					if (err)
1065 						throw err;
1066 				}
1067 
1068 				reader(flags);
1069 			}
1070 		}
1071 		catch (status_t& e)
1072 		{
1073 			err = e;
1074 		}
1075 	}
1076 
1077 	return err;
1078 }
1079 //------------------------------------------------------------------------------
1080 status_t BMessage::AddSpecifier(const char* property)
1081 {
1082 	BMessage message(B_DIRECT_SPECIFIER);
1083 	status_t err = message.AddString(B_PROPERTY_ENTRY, property);
1084 	if (err)
1085 		return err;
1086 
1087 	return AddSpecifier(&message);
1088 }
1089 //------------------------------------------------------------------------------
1090 status_t BMessage::AddSpecifier(const char* property, int32 index)
1091 {
1092 	BMessage message(B_INDEX_SPECIFIER);
1093 	status_t err = message.AddString(B_PROPERTY_ENTRY, property);
1094 	if (err)
1095 		return err;
1096 
1097 	err = message.AddInt32("index", index);
1098 	if (err)
1099 		return err;
1100 
1101 	return AddSpecifier(&message);
1102 }
1103 //------------------------------------------------------------------------------
1104 status_t BMessage::AddSpecifier(const char* property, int32 index, int32 range)
1105 {
1106 	if (range < 0)
1107 		return B_BAD_VALUE;
1108 
1109 	BMessage message(B_RANGE_SPECIFIER);
1110 	status_t err = message.AddString(B_PROPERTY_ENTRY, property);
1111 	if (err)
1112 		return err;
1113 
1114 	err = message.AddInt32("index", index);
1115 	if (err)
1116 		return err;
1117 
1118 	err = message.AddInt32("range", range);
1119 	if (err)
1120 		return err;
1121 
1122 	return AddSpecifier(&message);
1123 }
1124 //------------------------------------------------------------------------------
1125 status_t BMessage::AddSpecifier(const char* property, const char* name)
1126 {
1127 	BMessage message(B_NAME_SPECIFIER);
1128 	status_t err = message.AddString(B_PROPERTY_ENTRY, property);
1129 	if (err)
1130 		return err;
1131 
1132 	err = message.AddString(B_PROPERTY_NAME_ENTRY, name);
1133 	if (err)
1134 		return err;
1135 
1136 	return AddSpecifier(&message);
1137 }
1138 //------------------------------------------------------------------------------
1139 status_t BMessage::AddSpecifier(const BMessage* specifier)
1140 {
1141 	status_t err = AddMessage(B_SPECIFIER_ENTRY, specifier);
1142 	if (!err)
1143 	{
1144 		++fCurSpecifier;
1145 		fHasSpecifiers = true;
1146 	}
1147 	return err;
1148 }
1149 //------------------------------------------------------------------------------
1150 status_t BMessage::SetCurrentSpecifier(int32 index)
1151 {
1152 	type_code	type;
1153 	int32		count;
1154 	status_t	err = GetInfo(B_SPECIFIER_ENTRY, &type, &count);
1155 	if (err)
1156 		return err;
1157 
1158 	if (index < 0 || index >= count)
1159 		return B_BAD_INDEX;
1160 
1161 	fCurSpecifier = index;
1162 
1163 	return B_OK;
1164 }
1165 //------------------------------------------------------------------------------
1166 status_t BMessage::GetCurrentSpecifier(int32* index, BMessage* specifier,
1167 									   int32* what, const char** property) const
1168 {
1169 	if (fCurSpecifier == -1 || !WasDelivered())
1170 		return B_BAD_SCRIPT_SYNTAX;
1171 
1172 	if (index)
1173 		*index = fCurSpecifier;
1174 
1175 	if (specifier)
1176 	{
1177 		if (FindMessage(B_SPECIFIER_ENTRY, fCurSpecifier, specifier))
1178 			return B_BAD_SCRIPT_SYNTAX;
1179 
1180 		if (what)
1181 			*what = specifier->what;
1182 
1183 		if (property)
1184 		{
1185 			if (specifier->FindString(B_PROPERTY_ENTRY, property))
1186 				return B_BAD_SCRIPT_SYNTAX;
1187 		}
1188 	}
1189 
1190 	return B_OK;
1191 }
1192 //------------------------------------------------------------------------------
1193 bool BMessage::HasSpecifiers() const
1194 {
1195 	return fHasSpecifiers;
1196 }
1197 //------------------------------------------------------------------------------
1198 status_t BMessage::PopSpecifier()
1199 {
1200 	if (fCurSpecifier < 0 || !WasDelivered())
1201 	{
1202 		return B_BAD_VALUE;
1203 	}
1204 
1205 	--fCurSpecifier;
1206 	return B_OK;
1207 }
1208 //------------------------------------------------------------------------------
1209 //	return fBody->AddData<TYPE>(name, val, TYPESPEC);
1210 //	return fBody->FindData<TYPE>(name, index, val, TYPESPEC);
1211 //	return fBody->ReplaceData<TYPE>(name, index, val, TYPESPEC);
1212 //	return fBody->HasData(name, TYPESPEC, n);
1213 
1214 #define DEFINE_FUNCTIONS(TYPE, fnName, TYPESPEC)									\
1215 	status_t BMessage::Add ## fnName(const char* name, TYPE val)					\
1216 	{ return fBody->AddData<TYPE>(name, val, TYPESPEC); }							\
1217 	status_t BMessage::Find ## fnName(const char* name, TYPE* p) const				\
1218 	{ return Find ## fnName(name, 0, p); }											\
1219 	status_t BMessage::Find ## fnName(const char* name, int32 index, TYPE* p) const	\
1220 	{																				\
1221 		*p = TYPE();																\
1222 		return fBody->FindData<TYPE>(name, index, p, TYPESPEC);						\
1223 	}																				\
1224 	status_t BMessage::Replace ## fnName(const char* name, TYPE val)				\
1225 	{ return Replace ## fnName(name, 0, val); }										\
1226 	status_t BMessage::Replace ## fnName(const char *name, int32 index, TYPE val)	\
1227 	{  return fBody->ReplaceData<TYPE>(name, index, val, TYPESPEC); }				\
1228 	bool BMessage::Has ## fnName(const char* name, int32 n) const					\
1229 	{ return fBody->HasData(name, TYPESPEC, n); }
1230 
1231 DEFINE_FUNCTIONS(int8  , Int8  , B_INT8_TYPE)
1232 DEFINE_FUNCTIONS(int16 , Int16 , B_INT16_TYPE)
1233 DEFINE_FUNCTIONS(int32 , Int32 , B_INT32_TYPE)
1234 DEFINE_FUNCTIONS(int64 , Int64 , B_INT64_TYPE)
1235 DEFINE_FUNCTIONS(BPoint, Point , B_POINT_TYPE)
1236 DEFINE_FUNCTIONS(BRect , Rect  , B_RECT_TYPE)
1237 DEFINE_FUNCTIONS(float , Float , B_FLOAT_TYPE)
1238 DEFINE_FUNCTIONS(double, Double, B_DOUBLE_TYPE)
1239 DEFINE_FUNCTIONS(bool  , Bool  , B_BOOL_TYPE)
1240 
1241 #undef DEFINE_FUNCTIONS
1242 
1243 
1244 #define DEFINE_HAS_FUNCTION(fnName, TYPESPEC)						\
1245 	bool BMessage::Has ## fnName(const char* name, int32 n) const	\
1246 	{ return HasData(name, TYPESPEC, n); }
1247 
1248 DEFINE_HAS_FUNCTION(Message  , B_MESSAGE_TYPE)
1249 DEFINE_HAS_FUNCTION(String   , B_STRING_TYPE)
1250 DEFINE_HAS_FUNCTION(Pointer  , B_POINTER_TYPE)
1251 DEFINE_HAS_FUNCTION(Messenger, B_MESSENGER_TYPE)
1252 DEFINE_HAS_FUNCTION(Ref      , B_REF_TYPE)
1253 
1254 #undef DEFINE_HAS_FUNCTION
1255 
1256 #define DEFINE_LAZY_FIND_FUNCTION(TYPE, fnName)						\
1257 	TYPE BMessage::Find ## fnName(const char* name, int32 n) const	\
1258 	{																\
1259 		TYPE i = 0;													\
1260 		Find ## fnName(name, n, &i);								\
1261 		return i;													\
1262 	}
1263 
1264 DEFINE_LAZY_FIND_FUNCTION(int8			, Int8)
1265 DEFINE_LAZY_FIND_FUNCTION(int16			, Int16)
1266 DEFINE_LAZY_FIND_FUNCTION(int32			, Int32)
1267 DEFINE_LAZY_FIND_FUNCTION(int64			, Int64)
1268 DEFINE_LAZY_FIND_FUNCTION(float			, Float)
1269 DEFINE_LAZY_FIND_FUNCTION(double		, Double)
1270 DEFINE_LAZY_FIND_FUNCTION(bool			, Bool)
1271 DEFINE_LAZY_FIND_FUNCTION(const char*	, String)
1272 
1273 #undef DEFINE_LAZY_FIND_FUNCTION
1274 
1275 //------------------------------------------------------------------------------
1276 status_t BMessage::AddString(const char* name, const char* a_string)
1277 {
1278 	return fBody->AddData<BString>(name, a_string, B_STRING_TYPE);
1279 }
1280 //------------------------------------------------------------------------------
1281 status_t BMessage::AddString(const char* name, const BString& a_string)
1282 {
1283 	return AddString(name, a_string.String());
1284 }
1285 //------------------------------------------------------------------------------
1286 status_t BMessage::AddPointer(const char* name, const void* ptr)
1287 {
1288 	return fBody->AddData<void*>(name, (void*)ptr, B_POINTER_TYPE);
1289 }
1290 //------------------------------------------------------------------------------
1291 status_t BMessage::AddMessenger(const char* name, BMessenger messenger)
1292 {
1293 	return fBody->AddData<BMessenger>(name, messenger, B_MESSENGER_TYPE);
1294 }
1295 //------------------------------------------------------------------------------
1296 status_t BMessage::AddRef(const char* name, const entry_ref* ref)
1297 {
1298 	char* buffer = new(nothrow) char[sizeof (entry_ref) + B_PATH_NAME_LENGTH];
1299 	size_t size;
1300 	status_t err = entry_ref_flatten(buffer, &size, ref);
1301 	if (!err)
1302 	{
1303 		BDataBuffer DB((void*)buffer, size);
1304 		err = fBody->AddData<BDataBuffer>(name, DB, B_REF_TYPE);
1305 	}
1306 
1307 	return err;
1308 }
1309 //------------------------------------------------------------------------------
1310 status_t BMessage::AddMessage(const char* name, const BMessage* msg)
1311 {
1312 	status_t err = B_OK;
1313 	ssize_t size = msg->FlattenedSize();
1314 	char* buffer = new(nothrow) char[size];
1315 	if (buffer)
1316 	{
1317 		err = msg->Flatten(buffer, size);
1318 		if (!err)
1319 		{
1320 			BDataBuffer DB((void*)buffer, size);
1321 			err = fBody->AddData<BDataBuffer>(name, DB, B_MESSAGE_TYPE);
1322 		}
1323 	}
1324 	else
1325 	{
1326 		err = B_NO_MEMORY;
1327 	}
1328 
1329 	return err;
1330 }
1331 //------------------------------------------------------------------------------
1332 status_t BMessage::AddFlat(const char* name, BFlattenable* obj, int32 count)
1333 {
1334 	status_t err = B_OK;
1335 	ssize_t size = obj->FlattenedSize();
1336 	char* buffer = new(nothrow) char[size];
1337 	if (buffer)
1338 	{
1339 		err = obj->Flatten((void*)buffer, size);
1340 		if (!err)
1341 		{
1342 			err = AddData(name, obj->TypeCode(), (void*)buffer, size,
1343 						  obj->IsFixedSize(), count);
1344 		}
1345 		delete[] buffer;
1346 	}
1347 	else
1348 	{
1349 		err = B_NO_MEMORY;
1350 	}
1351 
1352 	return err;
1353 }
1354 //------------------------------------------------------------------------------
1355 status_t BMessage::AddData(const char* name, type_code type, const void* data,
1356 						   ssize_t numBytes, bool is_fixed_size, int32 /*count*/)
1357 {
1358 /**
1359 	@note	Because we're using vectors for our item storage, the count param
1360 			is no longer useful to us:  dynamically adding more items is not
1361 			really a performance issue, so pre-allocating space for objects
1362 			gives us no real advantage.
1363  */
1364 
1365 	// TODO: test
1366 	// In particular, we want to see what happens if is_fixed_size == true and
1367 	// the user attempts to add something bigger or smaller.  We may need to
1368 	// enforce the size thing.
1369 	//--------------------------------------------------------------------------
1370 	// voidref suggests creating a BDataBuffer type which we can use here to
1371 	// avoid having to specialize BMessageBody::AddData().
1372 	//--------------------------------------------------------------------------
1373 
1374 	// TODO: Fix this horrible hack
1375 	status_t err = B_OK;
1376 	switch (type)
1377 	{
1378 		case B_BOOL_TYPE:
1379 			err = AddBool(name, *(bool*)data);
1380 			break;
1381 		case B_INT8_TYPE:
1382 		case B_UINT8_TYPE:
1383 			err = AddInt8(name, *(int8*)data);
1384 			break;
1385 		case B_INT16_TYPE:
1386 		case B_UINT16_TYPE:
1387 			err = AddInt16(name, *(int16*)data);
1388 			break;
1389 		case B_INT32_TYPE:
1390 		case B_UINT32_TYPE:
1391 			err = AddInt32(name, *(int32*)data);
1392 			break;
1393 		case B_INT64_TYPE:
1394 		case B_UINT64_TYPE:
1395 			err = AddInt64(name, *(int64*)data);
1396 			break;
1397 		case B_FLOAT_TYPE:
1398 			err = AddFloat(name, *(float*)data);
1399 			break;
1400 		case B_DOUBLE_TYPE:
1401 			err = AddDouble(name, *(double*)data);
1402 			break;
1403 		case B_POINT_TYPE:
1404 			err = AddPoint(name, *(BPoint*)data);
1405 			break;
1406 		case B_RECT_TYPE:
1407 			err = AddRect(name, *(BRect*)data);
1408 			break;
1409 		case B_REF_TYPE:
1410 		{
1411 			BDataBuffer DB((void*)data, numBytes, true);
1412 			err = fBody->AddData<BDataBuffer>(name, DB, type);
1413 			break;
1414 		}
1415 		case B_MESSAGE_TYPE:
1416 		{
1417 			BDataBuffer DB((void*)data, numBytes, true);
1418 			err = fBody->AddData<BDataBuffer>(name, DB, type);
1419 			break;
1420 		}
1421 		case B_MESSENGER_TYPE:
1422 			err = AddMessenger(name, *(BMessenger*)data);
1423 			break;
1424 		case B_POINTER_TYPE:
1425 			err = AddPointer(name, *(void**)data);
1426 			break;
1427 		case B_STRING_TYPE:
1428 			err = AddString(name, (const char*)data);
1429 			break;
1430 		default:
1431 			// TODO: test
1432 			// Using the mythical BDataBuffer
1433 			BDataBuffer DB((void*)data, numBytes, true);
1434 			err = fBody->AddData<BDataBuffer>(name, DB, type);
1435 			break;
1436 	}
1437 
1438 	return err;
1439 }
1440 //------------------------------------------------------------------------------
1441 status_t BMessage::RemoveData(const char* name, int32 index)
1442 {
1443 	return fReadOnly ? B_ERROR : fBody->RemoveData(name, index);
1444 }
1445 //------------------------------------------------------------------------------
1446 status_t BMessage::RemoveName(const char* name)
1447 {
1448 	return fReadOnly ? B_ERROR : fBody->RemoveName(name);
1449 }
1450 //------------------------------------------------------------------------------
1451 status_t BMessage::MakeEmpty()
1452 {
1453 	return fReadOnly ? B_ERROR : fBody->MakeEmpty();
1454 }
1455 //------------------------------------------------------------------------------
1456 status_t BMessage::FindString(const char* name, const char** str) const
1457 {
1458 	return FindString(name, 0, str);
1459 }
1460 //------------------------------------------------------------------------------
1461 status_t BMessage::FindString(const char* name, int32 index,
1462 							  const char** str) const
1463 {
1464 	ssize_t bytes;
1465 	return FindData(name, B_STRING_TYPE, index,
1466 					(const void**)str, &bytes);
1467 }
1468 //------------------------------------------------------------------------------
1469 status_t BMessage::FindString(const char* name, BString* str) const
1470 {
1471 	return FindString(name, 0, str);
1472 }
1473 //------------------------------------------------------------------------------
1474 status_t BMessage::FindString(const char* name, int32 index, BString* str) const
1475 {
1476 	const char* cstr;
1477 	status_t err = FindString(name, index, &cstr);
1478 	if (!err)
1479 	{
1480 		*str = cstr;
1481 	}
1482 
1483 	return err;
1484 }
1485 //------------------------------------------------------------------------------
1486 status_t BMessage::FindPointer(const char* name, void** ptr) const
1487 {
1488 	return FindPointer(name, 0, ptr);
1489 }
1490 //------------------------------------------------------------------------------
1491 status_t BMessage::FindPointer(const char* name, int32 index, void** ptr) const
1492 {
1493 	*ptr = NULL;
1494 	return fBody->FindData<void*>(name, index, ptr, B_POINTER_TYPE);
1495 }
1496 //------------------------------------------------------------------------------
1497 status_t BMessage::FindMessenger(const char* name, BMessenger* m) const
1498 {
1499 	return FindMessenger(name, 0, m);
1500 }
1501 //------------------------------------------------------------------------------
1502 status_t BMessage::FindMessenger(const char* name, int32 index, BMessenger* m) const
1503 {
1504 	return fBody->FindData<BMessenger>(name, index, m, B_MESSENGER_TYPE);
1505 }
1506 //------------------------------------------------------------------------------
1507 status_t BMessage::FindRef(const char* name, entry_ref* ref) const
1508 {
1509 	return FindRef(name, 0, ref);
1510 }
1511 //------------------------------------------------------------------------------
1512 status_t BMessage::FindRef(const char* name, int32 index, entry_ref* ref) const
1513 {
1514 	void* data = NULL;
1515 	ssize_t size = 0;
1516 	status_t err = FindData(name, B_REF_TYPE, index, (const void**)&data, &size);
1517 	if (!err)
1518 	{
1519 		err = entry_ref_unflatten(ref, (char*)data, size);
1520 	}
1521 
1522 	return err;
1523 }
1524 //------------------------------------------------------------------------------
1525 status_t BMessage::FindMessage(const char* name, BMessage* msg) const
1526 {
1527 	return FindMessage(name, 0, msg);
1528 }
1529 //------------------------------------------------------------------------------
1530 status_t BMessage::FindMessage(const char* name, int32 index, BMessage* msg) const
1531 {
1532 	void* data = NULL;
1533 	ssize_t size = 0;
1534 	status_t err = FindData(name, B_MESSAGE_TYPE, index,
1535 							(const void**)&data, &size);
1536 	if (!err)
1537 	{
1538 		err = msg->Unflatten((const char*)data);
1539 	}
1540 
1541 	return err;
1542 }
1543 //------------------------------------------------------------------------------
1544 status_t BMessage::FindFlat(const char* name, BFlattenable* obj) const
1545 {
1546 	return FindFlat(name, 0, obj);
1547 }
1548 //------------------------------------------------------------------------------
1549 status_t BMessage::FindFlat(const char* name, int32 index,
1550 							BFlattenable* obj) const
1551 {
1552 	const void* data;
1553 	ssize_t numBytes;
1554 	status_t err = FindData(name, obj->TypeCode(), index, &data, &numBytes);
1555 	if (!err)
1556 	{
1557 		err = obj->Unflatten(obj->TypeCode(), data, numBytes);
1558 	}
1559 
1560 	return err;
1561 }
1562 //------------------------------------------------------------------------------
1563 status_t BMessage::FindData(const char* name, type_code type, const void** data,
1564 							ssize_t* numBytes) const
1565 {
1566 	return FindData(name, type, 0, data, numBytes);
1567 }
1568 //------------------------------------------------------------------------------
1569 status_t BMessage::FindData(const char* name, type_code type, int32 index,
1570 							const void** data, ssize_t* numBytes) const
1571 {
1572 	status_t err = B_OK;
1573 	// Oh, the humanity!
1574 	err = fBody->FindData(name, type, index, data, numBytes);
1575 
1576 	return err;
1577 }
1578 //------------------------------------------------------------------------------
1579 status_t BMessage::ReplaceString(const char* name, const char* string)
1580 {
1581 	return ReplaceString(name, 0, string);
1582 }
1583 //------------------------------------------------------------------------------
1584 status_t BMessage::ReplaceString(const char* name, int32 index,
1585 								 const char* string)
1586 {
1587 	return fBody->ReplaceData<BString>(name, index, string, B_STRING_TYPE);
1588 }
1589 //------------------------------------------------------------------------------
1590 status_t BMessage::ReplaceString(const char* name, const BString& string)
1591 {
1592 	return ReplaceString(name, 0, string);
1593 }
1594 //------------------------------------------------------------------------------
1595 status_t BMessage::ReplaceString(const char* name, int32 index, const BString& string)
1596 {
1597 	return fBody->ReplaceData<BString>(name, index, string, B_STRING_TYPE);
1598 }
1599 //------------------------------------------------------------------------------
1600 status_t BMessage::ReplacePointer(const char* name, const void* ptr)
1601 {
1602 	return ReplacePointer(name, 0, ptr);
1603 }
1604 //------------------------------------------------------------------------------
1605 status_t BMessage::ReplacePointer(const char* name, int32 index,
1606 								  const void* ptr)
1607 {
1608 	return fBody->ReplaceData<void*>(name, index, (void*)ptr, B_POINTER_TYPE);
1609 }
1610 //------------------------------------------------------------------------------
1611 status_t BMessage::ReplaceMessenger(const char* name, BMessenger messenger)
1612 {
1613 	// Don't want to copy the BMessenger
1614 	return fBody->ReplaceData<BMessenger>(name, 0, messenger, B_MESSENGER_TYPE);
1615 }
1616 //------------------------------------------------------------------------------
1617 status_t BMessage::ReplaceMessenger(const char* name, int32 index,
1618 									BMessenger msngr)
1619 {
1620 	return fBody->ReplaceData<BMessenger>(name, index, msngr, B_MESSENGER_TYPE);
1621 }
1622 //------------------------------------------------------------------------------
1623 status_t BMessage::ReplaceRef(const char* name, const entry_ref* ref)
1624 {
1625 	return ReplaceRef(name, 0, ref);
1626 }
1627 //------------------------------------------------------------------------------
1628 status_t BMessage::ReplaceRef(const char* name, int32 index, const entry_ref* ref)
1629 {
1630 	// TODO: test
1631 	// Use voidref's theoretical BDataBuffer
1632 	char* buffer = new(nothrow) char[sizeof (entry_ref) + B_PATH_NAME_LENGTH];
1633 	size_t size;
1634 	status_t err = entry_ref_flatten(buffer, &size, ref);
1635 	if (!err)
1636 	{
1637 		BDataBuffer DB((void*)buffer, size);
1638 		err = fBody->ReplaceData<BDataBuffer>(name, index, DB, B_REF_TYPE);
1639 	}
1640 
1641 	return err;
1642 }
1643 //------------------------------------------------------------------------------
1644 status_t BMessage::ReplaceMessage(const char* name, const BMessage* msg)
1645 {
1646 	return ReplaceMessage(name, 0, msg);
1647 }
1648 //------------------------------------------------------------------------------
1649 status_t BMessage::ReplaceMessage(const char* name, int32 index,
1650 								  const BMessage* msg)
1651 {
1652 	status_t err = B_OK;
1653 	ssize_t size = msg->FlattenedSize();
1654 	char* buffer = new(nothrow) char[size];
1655 	if (buffer)
1656 	{
1657 		err = msg->Flatten(buffer, size);
1658 		if (!err)
1659 		{
1660 			BDataBuffer DB((void*)buffer, size);
1661 			err = fBody->ReplaceData<BDataBuffer>(name, index, DB,
1662 												  B_MESSAGE_TYPE);
1663 		}
1664 	}
1665 	else
1666 	{
1667 		err = B_NO_MEMORY;
1668 	}
1669 
1670 	return err;
1671 }
1672 //------------------------------------------------------------------------------
1673 status_t BMessage::ReplaceFlat(const char* name, BFlattenable* obj)
1674 {
1675 	return ReplaceFlat(name, 0, obj);
1676 }
1677 //------------------------------------------------------------------------------
1678 status_t BMessage::ReplaceFlat(const char* name, int32 index, BFlattenable* obj)
1679 {
1680 	// TODO: test
1681 	status_t err = B_OK;
1682 	ssize_t size = obj->FlattenedSize();
1683 	char* buffer = new(nothrow) char[size];
1684 	if (buffer)
1685 	{
1686 		err = obj->Flatten(buffer, size);
1687 		if (!err)
1688 		{
1689 			err = ReplaceData(name, obj->TypeCode(), index, (void*)buffer, size);
1690 		}
1691 		delete[] buffer;
1692 	}
1693 
1694 	return err;
1695 }
1696 //------------------------------------------------------------------------------
1697 status_t BMessage::ReplaceData(const char* name, type_code type,
1698 							   const void* data, ssize_t data_size)
1699 {
1700 	return ReplaceData(name, type, 0, data, data_size);
1701 }
1702 //------------------------------------------------------------------------------
1703 status_t BMessage::ReplaceData(const char* name, type_code type, int32 index,
1704 							   const void* data, ssize_t data_size)
1705 {
1706 	// TODO: Fix this horrible hack
1707 	status_t err = B_OK;
1708 	switch (type)
1709 	{
1710 		case B_BOOL_TYPE:
1711 			err = ReplaceBool(name, index, *(bool*)data);
1712 			break;
1713 		case B_INT8_TYPE:
1714 		case B_UINT8_TYPE:
1715 			err = ReplaceInt8(name, index, *(int8*)data);
1716 			break;
1717 		case B_INT16_TYPE:
1718 		case B_UINT16_TYPE:
1719 			err = ReplaceInt16(name, index, *(int16*)data);
1720 			break;
1721 		case B_INT32_TYPE:
1722 		case B_UINT32_TYPE:
1723 			err = ReplaceInt32(name, index, *(int32*)data);
1724 			break;
1725 		case B_INT64_TYPE:
1726 		case B_UINT64_TYPE:
1727 			err = ReplaceInt64(name, index, *(int64*)data);
1728 			break;
1729 		case B_FLOAT_TYPE:
1730 			err = ReplaceFloat(name, index, *(float*)data);
1731 			break;
1732 		case B_DOUBLE_TYPE:
1733 			err = ReplaceDouble(name, index, *(double*)data);
1734 			break;
1735 		case B_POINT_TYPE:
1736 			err = ReplacePoint(name, index, *(BPoint*)data);
1737 			break;
1738 		case B_RECT_TYPE:
1739 			err = ReplaceRect(name, index, *(BRect*)data);
1740 			break;
1741 		case B_REF_TYPE:
1742 			err = ReplaceRef(name, index, (entry_ref*)data);
1743 			break;
1744 		case B_MESSAGE_TYPE:
1745 			err = ReplaceMessage(name, index, (BMessage*)data);
1746 			break;
1747 		case B_MESSENGER_TYPE:
1748 			err = ReplaceMessenger(name, index, *(BMessenger*)data);
1749 			break;
1750 		case B_POINTER_TYPE:
1751 			err = ReplacePointer(name, index, (void**)data);
1752 			break;
1753 		default:
1754 			// TODO: test
1755 			// Using the mythical BDataBuffer
1756 			BDataBuffer DB((void*)data, data_size, true);
1757 			err = fBody->ReplaceData<BDataBuffer>(name, index, DB, type);
1758 			break;
1759 	}
1760 
1761 	return err;
1762 }
1763 //------------------------------------------------------------------------------
1764 void* BMessage::operator new(size_t size)
1765 {
1766 	if (!sMsgCache)
1767 	{
1768 		sMsgCache = new BBlockCache(10, size, B_OBJECT_CACHE);
1769 	}
1770 	return sMsgCache->Get(size);
1771 }
1772 //------------------------------------------------------------------------------
1773 void* BMessage::operator new(size_t, void* p)
1774 {
1775 	return p;
1776 }
1777 //------------------------------------------------------------------------------
1778 void BMessage::operator delete(void* ptr, size_t size)
1779 {
1780 	sMsgCache->Save(ptr, size);
1781 }
1782 //------------------------------------------------------------------------------
1783 bool BMessage::HasFlat(const char* name, const BFlattenable* flat) const
1784 {
1785 	return HasFlat(name, 0, flat);
1786 }
1787 //------------------------------------------------------------------------------
1788 bool BMessage::HasFlat(const char* name, int32 n, const BFlattenable* flat) const
1789 {
1790 	return fBody->HasData(name, flat->TypeCode(), n);
1791 }
1792 //------------------------------------------------------------------------------
1793 bool BMessage::HasData(const char* name, type_code t, int32 n) const
1794 {
1795 	return fBody->HasData(name, t, n);
1796 }
1797 //------------------------------------------------------------------------------
1798 BRect BMessage::FindRect(const char* name, int32 n) const
1799 {
1800 	BRect r(0, 0, -1, -1);
1801 	FindRect(name, n, &r);
1802 	return r;
1803 }
1804 //------------------------------------------------------------------------------
1805 BPoint BMessage::FindPoint(const char* name, int32 n) const
1806 {
1807 	BPoint p(0, 0);
1808 	FindPoint(name, n, &p);
1809 	return p;
1810 }
1811 
1812 
1813 status_t
1814 BMessage::real_flatten(char* result, ssize_t size) const
1815 {
1816 	BMemoryIO stream((void*)result, size);
1817 	return real_flatten(&stream);
1818 
1819 }
1820 //------------------------------------------------------------------------------
1821 status_t BMessage::real_flatten(BDataIO* stream) const
1822 {
1823 	Header header(*this);
1824 
1825 	status_t err = header.WriteTo(*stream);
1826 
1827 	if (!err)
1828 		err = fBody->Flatten(stream);
1829 
1830 	return err;
1831 }
1832 //------------------------------------------------------------------------------
1833 char* BMessage::stack_flatten(char* stack_ptr, ssize_t stack_size,
1834 							  bool /*incl_reply*/, ssize_t* size) const
1835 {
1836 	const ssize_t calcd_size = calc_hdr_size(0) + fBody->FlattenedSize();
1837 	char* new_ptr = NULL;
1838 	if (calcd_size > stack_size)
1839 	{
1840 		stack_ptr = new char[calcd_size];
1841 		new_ptr = stack_ptr;
1842 	}
1843 	real_flatten(stack_ptr, calcd_size);
1844 	if (size)
1845 	{
1846 		*size = calcd_size;
1847 	}
1848 	return new_ptr;
1849 }
1850 
1851 
1852 status_t
1853 BMessage::_UnflattenKMessage(const char *buffer)
1854 {
1855 	// init a real KMessage
1856 	KMessage message;
1857 	status_t error = message.SetTo(buffer, ((KMessage::Header*)buffer)->size);
1858 	if (error != B_OK)
1859 		return error;
1860 
1861 	// let convert_message() do the real job
1862 	return convert_message(&message, this);
1863 }
1864 
1865 
1866 ssize_t
1867 BMessage::calc_hdr_size(uchar flags) const
1868 {
1869 	ssize_t size = min_hdr_size();
1870 
1871 	if (fTarget != B_NULL_TOKEN)
1872 	{
1873 		size += sizeof (fTarget);
1874 	}
1875 
1876 	if (fReplyTo.port >= 0 &&
1877 		fReplyTo.target != B_NULL_TOKEN &&
1878 		fReplyTo.team >= 0)
1879 	{
1880 		size += sizeof (fReplyTo.port);
1881 		size += sizeof (fReplyTo.target);
1882 		size += sizeof (fReplyTo.team);
1883 
1884 		size += 4;	// For the "big" flags
1885 	}
1886 
1887 	return size;
1888 }
1889 //------------------------------------------------------------------------------
1890 status_t BMessage::_send_(port_id port, int32 token, bool preferred,
1891 						  bigtime_t timeout, bool reply_required,
1892 						  BMessenger& reply_to) const
1893 {
1894 PRINT(("BMessage::_send_(port: %ld, token: %ld, preferred: %d): "
1895 "what: %lx (%.4s)\n", port, token, preferred, what, (char*)&what));
1896 	BMessage tmp_msg;
1897 	tmp_msg.fPreferred     = fPreferred;
1898 	tmp_msg.fTarget        = fTarget;
1899 	tmp_msg.fReplyRequired = fReplyRequired;
1900 	tmp_msg.fReplyTo       = fReplyTo;
1901 
1902 	BMessage* self = const_cast<BMessage*>(this);
1903 	BMessenger::Private replyToPrivate(reply_to);
1904 	self->fPreferred         = preferred;
1905 	self->fTarget            = token;
1906 	self->fReplyRequired     = reply_required;
1907 	self->fReplyTo.team      = replyToPrivate.Team();
1908 	self->fReplyTo.port      = replyToPrivate.Port();
1909 	self->fReplyTo.target    = (replyToPrivate.IsPreferredTarget()
1910 								? B_PREFERRED_TOKEN : replyToPrivate.Token());
1911 	self->fReplyTo.preferred = replyToPrivate.IsPreferredTarget();
1912 
1913 	char tmp[0x800];
1914 	ssize_t size;
1915 	char* p = stack_flatten(tmp, sizeof(tmp), true /* include reply */, &size);
1916 	char* pMem = p ? p : tmp;
1917 	status_t err;
1918 	do
1919 	{
1920 		err = write_port_etc(port, 'pjpp', pMem, size, B_RELATIVE_TIMEOUT, timeout);
1921 	} while (err == B_INTERRUPTED);
1922 	if (p)
1923 	{
1924 		delete[] p;
1925 	}
1926 	self->fPreferred     = tmp_msg.fPreferred;
1927 	self->fTarget        = tmp_msg.fTarget;
1928 	self->fReplyRequired = tmp_msg.fReplyRequired;
1929 	self->fReplyTo       = tmp_msg.fReplyTo;
1930 	tmp_msg.init_data();
1931 PRINT(("BMessage::_send_() done: %lx\n", err));
1932 	return err;
1933 }
1934 //------------------------------------------------------------------------------
1935 status_t BMessage::send_message(port_id port, team_id port_owner, int32 token,
1936 								bool preferred, BMessage* reply,
1937 								bigtime_t send_timeout,
1938 								bigtime_t reply_timeout) const
1939 {
1940 	const int32 cached_reply_port = sGetCachedReplyPort();
1941 	port_id reply_port;
1942 	status_t err;
1943 	if (cached_reply_port == -1)
1944 	{
1945 		// All the cached reply ports are in use; create a new one
1946 		reply_port = create_port(1 /* for one message */, "tmp_reply_port");
1947 		if (reply_port < 0)
1948 		{
1949 			return reply_port;
1950 		}
1951 	}
1952 	else
1953 	{
1954 		assert(cached_reply_port < sNumReplyPorts);
1955 		reply_port = sReplyPorts[cached_reply_port];
1956 	}
1957 
1958 	team_id team = B_BAD_TEAM_ID;
1959 	if (be_app != NULL)
1960 		team = be_app->Team();
1961 	else {
1962 		port_info pi;
1963 		err = get_port_info(reply_port, &pi);
1964 		if (err)
1965 			goto error;
1966 
1967 		team = pi.team;
1968 	}
1969 
1970 	err = set_port_owner(reply_port, port_owner);
1971 	if (err)
1972 		goto error;
1973 
1974 	{
1975 		BMessenger messenger;
1976 		BMessenger::Private(messenger).SetTo(team, reply_port,
1977 			B_PREFERRED_TOKEN, false);
1978 		err = _send_(port, token, preferred, send_timeout, true, messenger);
1979 	}
1980 	if (err)
1981 	{
1982 		goto error;
1983 	}
1984 	int32 code;
1985 	err = handle_reply(reply_port, &code, reply_timeout, reply);
1986 	if (err && cached_reply_port >= 0)
1987 	{
1988 		delete_port(reply_port);
1989 		sReplyPorts[cached_reply_port] = create_port(1, "tmp_rport");
1990 	}
1991 
1992 error:
1993 	if (cached_reply_port >= 0)
1994 	{
1995 		// Reclaim ownership of cached port
1996 		set_port_owner(reply_port, team);
1997 		// Flag as available
1998 		atomic_add(&sReplyPortInUse[cached_reply_port], -1);
1999 		return err;
2000 	}
2001 	delete_port(reply_port);
2002 	return err;
2003 }
2004 
2005 
2006 // Note, that in case of a flattened BMessage setting the target token will
2007 // change the header size, if no token was set when the message was flattened.
2008 // Hence the message would need to unflattened and flattened again before it
2009 // can be sent.
2010 status_t
2011 BMessage::_SendFlattenedMessage(void *data, int32 size, port_id port,
2012 	int32 token, bool preferred, bigtime_t timeout)
2013 {
2014 	if (!data)
2015 		return B_BAD_VALUE;
2016 
2017 	// prepare flattened fields
2018 	if (((KMessage::Header*)data)->magic == KMessage::kMessageHeaderMagic) {
2019 		// a KMessage
2020 		KMessage::Header *header = (KMessage::Header*)data;
2021 		header->targetToken = (preferred ? B_PREFERRED_TOKEN : token);
2022 	} else if (*(int32*)data == '1BOF' || *(int32*)data == 'FOB1') {
2023 		// get the header
2024 		BMemoryIO stream(data, size);
2025 		Header header;
2026 		status_t error = header.ReadFrom(stream);
2027 		if (error != B_OK)
2028 			return error;
2029 
2030 		if (!header.HasTarget()) {
2031 			// fallback implementation -- the header size would change by
2032 			// setting the token
2033 
2034 			// unflatten the message
2035 			BMessage message;
2036 			error = message.Unflatten((const char*)data);
2037 			if (error != B_OK)
2038 				return error;
2039 
2040 			// send the message
2041 			BMessenger messenger;
2042 			return message._send_(port, token, preferred, timeout, false,
2043 				messenger);
2044 		}
2045 
2046 		// set the target token and replace the header
2047 		header.SetTarget(token, preferred);
2048 		stream.Seek(0LL, SEEK_SET);
2049 		error = header.WriteTo(stream);
2050 		if (error != B_OK)
2051 			return error;
2052 	} else {
2053 		return B_NOT_A_MESSAGE;
2054 	}
2055 
2056 	// send the message
2057 	status_t error;
2058 	do {
2059 		error = write_port_etc(port, 'pjpp', data, size, B_RELATIVE_TIMEOUT,
2060 			timeout);
2061 	} while (error == B_INTERRUPTED);
2062 
2063 	return error;
2064 }
2065 
2066 
2067 void
2068 BMessage::_StaticCacheCleanup()
2069 {
2070 	delete sMsgCache;
2071 	sMsgCache = NULL;
2072 }
2073 
2074 
2075 void
2076 BMessage::_StaticInit()
2077 {
2078 	sReplyPorts[0] = create_port(1, "tmp_rport0");
2079 	sReplyPorts[1] = create_port(1, "tmp_rport1");
2080 	sReplyPorts[2] = create_port(1, "tmp_rport2");
2081 
2082 	sReplyPortInUse[0] = 0;
2083 	sReplyPortInUse[1] = 0;
2084 	sReplyPortInUse[2] = 0;
2085 }
2086 
2087 
2088 void
2089 BMessage::_StaticCleanup()
2090 {
2091 	delete_port(sReplyPorts[0]);
2092 	sReplyPorts[0] = -1;
2093 	delete_port(sReplyPorts[1]);
2094 	sReplyPorts[1] = -1;
2095 	delete_port(sReplyPorts[2]);
2096 	sReplyPorts[2] = -1;
2097 }
2098 
2099 
2100 int32
2101 BMessage::sGetCachedReplyPort()
2102 {
2103 	int index = -1;
2104 	for (int32 i = 0; i < sNumReplyPorts; i++)
2105 	{
2106 		int32 old = atomic_add(&(sReplyPortInUse[i]), 1);
2107 		if (old == 0)
2108 		{
2109 			// This entry is free
2110 			index = i;
2111 			break;
2112 		}
2113 		else
2114 		{
2115 			// This entry is being used.
2116 			atomic_add(&(sReplyPortInUse[i]), -1);
2117 		}
2118 	}
2119 
2120 	return index;
2121 }
2122 //------------------------------------------------------------------------------
2123 static status_t handle_reply(port_id   reply_port,
2124                              int32*    pCode,
2125                              bigtime_t timeout,
2126                              BMessage* reply)
2127 {
2128 PRINT(("handle_reply(port: %ld)\n", reply_port));
2129 	status_t err;
2130 	do
2131 	{
2132 		err = port_buffer_size_etc(reply_port, 8, timeout);
2133 	} while (err == B_INTERRUPTED);
2134 	if (err < 0)
2135 	{
2136 		PRINT(("handle_reply() error 1: %lx\n", err));
2137 		return err;
2138 	}
2139 	// The API lied. It really isn't an error code, but the message size...
2140 	char* pAllocd = NULL;
2141 	char* pMem    = NULL;
2142 	char tmp[0x800];
2143 	if (err < 0x800)
2144 	{
2145 		pMem = tmp;
2146 	}
2147 	else
2148 	{
2149 		pAllocd = new char[err];
2150 		pMem = pAllocd;
2151 	}
2152 	do
2153 	{
2154 		err = read_port(reply_port, pCode, pMem, err);
2155 	} while (err == B_INTERRUPTED);
2156 
2157 	if (err < 0)
2158 	{
2159 		PRINT(("handle_reply() error 2: %lx\n", err));
2160 		return err;
2161 	}
2162 
2163 	if (*pCode == 'PUSH')
2164 	{
2165 		PRINT(("handle_reply() error 3: %x\n", B_ERROR));
2166 		return B_ERROR;
2167 	}
2168 	if (*pCode != 'pjpp')
2169 	{
2170 		PRINT(("handle_reply() error 4: port message code not 'pjpp' but "
2171 			"'%lx'\n", *pCode));
2172 		return B_ERROR;
2173 	}
2174 
2175 	err = reply->Unflatten(pMem);
2176 
2177 	// There seems to be a bug in the original Be implementation.
2178 	// It never free'd pAllocd !
2179 	if (pAllocd)
2180 	{
2181 		delete[] pAllocd;
2182 	}
2183 PRINT(("handle_reply() done: %lx\n", err));
2184 	return err;
2185 }
2186 
2187 // convert_message
2188 static
2189 status_t
2190 convert_message(const KMessage *fromMessage, BMessage *toMessage)
2191 {
2192 	if (!fromMessage || !toMessage)
2193 		return B_BAD_VALUE;
2194 
2195 	// make empty and init what of the target message
2196 	toMessage->MakeEmpty();
2197 	toMessage->what = fromMessage->What();
2198 
2199 	// iterate through the fields and import them in the target message
2200 	KMessageField field;
2201 	while (fromMessage->GetNextField(&field) == B_OK) {
2202 		int32 elementCount = field.CountElements();
2203 		if (elementCount > 0) {
2204 			for (int32 i = 0; i < elementCount; i++) {
2205 				int32 size;
2206 				const void *data = field.ElementAt(i, &size);
2207 				status_t error;
2208 				if (field.TypeCode() == B_MESSAGE_TYPE) {
2209 					// message type: if it's a KMessage, convert it
2210 					KMessage message;
2211 					if (message.SetTo(data, size) == B_OK) {
2212 						BMessage bMessage;
2213 						error = convert_message(&message, &bMessage);
2214 						if (error != B_OK)
2215 							return error;
2216 						error = toMessage->AddMessage(field.Name(), &bMessage);
2217 					} else {
2218 						// just add it
2219 						error = toMessage->AddData(field.Name(),
2220 							field.TypeCode(), data, size,
2221 							field.HasFixedElementSize(), 1);
2222 					}
2223 				} else {
2224 					error = toMessage->AddData(field.Name(), field.TypeCode(),
2225 						data, size, field.HasFixedElementSize(), 1);
2226 				}
2227 
2228 				if (error != B_OK)
2229 					return error;
2230 			}
2231 		}
2232 	}
2233 	return B_OK;
2234 }
2235 
2236 static
2237 ssize_t
2238 min_hdr_size()
2239 {
2240 	ssize_t size = 0;
2241 
2242 	size += 4;	// version
2243 	size += 4;	// checksum
2244 	size += 4;	// flattened size
2245 	size += 4;	// 'what'
2246 	size += 1;	// flags
2247 
2248 	return size;
2249 }
2250