xref: /haiku/src/kits/translation/TranslatorRoster.cpp (revision 484a5f0ec2a2657494fdb86a2a5d96f3d01f9973)
1 /*****************************************************************************/
2 //               File: TranslatorRoster.cpp
3 //              Class: BTranslatorRoster
4 //   Reimplemented by: Michael Wilber, Translation Kit Team
5 //   Reimplementation: 2002-06-11
6 //
7 // Description: This class is the guts of the translation kit, it makes the
8 //              whole thing happen. It bridges the applications using this
9 //              object with the translators that the apps need to access.
10 //
11 //
12 // Copyright (c) 2002 OpenBeOS Project
13 //
14 // Original Version: Copyright 1998, Be Incorporated, All Rights Reserved.
15 //                   Copyright 1995-1997, Jon Watte
16 //
17 // Permission is hereby granted, free of charge, to any person obtaining a
18 // copy of this software and associated documentation files (the "Software"),
19 // to deal in the Software without restriction, including without limitation
20 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
21 // and/or sell copies of the Software, and to permit persons to whom the
22 // Software is furnished to do so, subject to the following conditions:
23 //
24 // The above copyright notice and this permission notice shall be included
25 // in all copies or substantial portions of the Software.
26 //
27 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
28 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
29 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
30 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
31 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
32 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
33 // DEALINGS IN THE SOFTWARE.
34 /*****************************************************************************/
35 
36 #include <TranslatorRoster.h>
37 
38 // Initialize static member variable
39 BTranslatorRoster *BTranslatorRoster::fspDefaultTranslators = NULL;
40 
41 // Extensions used in the extension BMessage, defined in TranslatorFormats.h
42 char B_TRANSLATOR_EXT_HEADER_ONLY[]			= "/headerOnly";
43 char B_TRANSLATOR_EXT_DATA_ONLY[]			= "/dataOnly";
44 char B_TRANSLATOR_EXT_COMMENT[]				= "/comment";
45 char B_TRANSLATOR_EXT_TIME[]				= "/time";
46 char B_TRANSLATOR_EXT_FRAME[]				= "/frame";
47 char B_TRANSLATOR_EXT_BITMAP_RECT[]			= "bits/Rect";
48 char B_TRANSLATOR_EXT_BITMAP_COLOR_SPACE[]	= "bits/space";
49 char B_TRANSLATOR_EXT_BITMAP_PALETTE[]		= "bits/palette";
50 char B_TRANSLATOR_EXT_SOUND_CHANNEL[]		= "nois/channel";
51 char B_TRANSLATOR_EXT_SOUND_MONO[]			= "nois/mono";
52 char B_TRANSLATOR_EXT_SOUND_MARKER[]		= "nois/marker";
53 char B_TRANSLATOR_EXT_SOUND_LOOP[]			= "nois/loop";
54 
55 // ---------------------------------------------------------------
56 // Constructor
57 //
58 // Private, unimplimented constructor that no one should use.
59 // I don't think there would be much of a need for this function.
60 //
61 // Preconditions:
62 //
63 // Parameters: tr, not used
64 //
65 // Postconditions:
66 //
67 // Returns:
68 // ---------------------------------------------------------------
69 BTranslatorRoster::BTranslatorRoster(const BTranslatorRoster &tr)
70 	: BArchivable()
71 {
72 	Initialize();
73 }
74 
75 // ---------------------------------------------------------------
76 // operator=
77 //
78 // Private, unimplimented function that no one should use.
79 // I don't know that there is a need for this function anyway.
80 //
81 // Preconditions:
82 //
83 // Parameters: tr, not used
84 //
85 // Postconditions:
86 //
87 // Returns: refernce to this object
88 // ---------------------------------------------------------------
89 BTranslatorRoster &
90 BTranslatorRoster::operator=(const BTranslatorRoster &tr)
91 {
92 	return *this;
93 }
94 
95 // ---------------------------------------------------------------
96 // Constructor
97 //
98 // Initilizes the BTranslatorRoster to the empty state, it loads
99 // no translators.
100 //
101 // Preconditions:
102 //
103 // Parameters:
104 //
105 // Postconditions:
106 //
107 // Returns:
108 // ---------------------------------------------------------------
109 BTranslatorRoster::BTranslatorRoster() : BArchivable()
110 {
111 	Initialize();
112 }
113 
114 // ---------------------------------------------------------------
115 // Constructor
116 //
117 // This constructor initilizes the BTranslatorRoster, then
118 // loads all of the translators specified in the
119 // "be:translator_path" field of the supplied BMessage.
120 //
121 // Preconditions:
122 //
123 // Parameters: model, the BMessage where the translator paths are
124 //                    found.
125 //
126 // Postconditions:
127 //
128 // Returns:
129 // ---------------------------------------------------------------
130 BTranslatorRoster::BTranslatorRoster(BMessage *model) : BArchivable()
131 {
132 	Initialize();
133 
134 	if (model) {
135 		BString bstr;
136 		for (int32 i = 0;
137 			model->FindString("be:translator_path", i, &bstr) == B_OK; i++) {
138 			AddTranslators(bstr.String());
139 			bstr = "";
140 		}
141 	}
142 }
143 
144 // ---------------------------------------------------------------
145 // Initialize()
146 //
147 // This function initializes this object to the empty state. It
148 // is used by all constructors.
149 //
150 // Preconditions: Object must be in initial uninitialized state
151 //
152 // Parameters:
153 //
154 // Postconditions:
155 //
156 // Returns:
157 // ---------------------------------------------------------------
158 void BTranslatorRoster::Initialize()
159 {
160 	fpTranslators = fpLastTranslator = NULL;
161 	fSem = create_sem(1, "BTranslatorRoster Lock");
162 }
163 
164 // ---------------------------------------------------------------
165 // Destructor
166 //
167 // Unloads any translators that were loaded and frees all memory
168 // allocated by the BTranslatorRoster, except for the static
169 // member data.
170 //
171 // Preconditions:
172 //
173 // Parameters:
174 //
175 // Postconditions:
176 //
177 // Returns:
178 // ---------------------------------------------------------------
179 BTranslatorRoster::~BTranslatorRoster()
180 {
181 	if (fSem > 0 && acquire_sem(fSem) == B_NO_ERROR) {
182 
183 		// If the default BTranslatorRoster is being
184 		// deleted, set the pointer to the default
185 		// BTranslatorRoster to NULL
186 		if (fspDefaultTranslators == this)
187 			fspDefaultTranslators = NULL;
188 
189 		// FIRST PASS: release BTranslator objects
190 		translator_node *pTranNode = fpTranslators;
191 		while (pTranNode) {
192 			translator_node *pRelTranNode = pTranNode;
193 			pTranNode = pTranNode->next;
194 			pRelTranNode->translator->Release();
195 		}
196 
197 		// SECOND PASS: unload images and delete nodes
198 		// (I can't delete a BTranslator if I've deleted
199 		// the code for it)
200 		pTranNode = fpTranslators;
201 		while (pTranNode) {
202 			translator_node *pDelTranNode = pTranNode;
203 			pTranNode = pTranNode->next;
204 
205 			// only try to unload actual images
206 			if (pDelTranNode->image >= 0)
207 				unload_add_on(pDelTranNode->image);
208 					// I may end up trying to unload the same image
209 					// more than once, but I don't think
210 					// that should be a problem
211 			delete[] pDelTranNode->path;
212 			delete pDelTranNode;
213 		}
214 
215 		fpTranslators = fpLastTranslator = NULL;
216 	}
217 
218 	delete_sem(fSem);
219 }
220 
221 // ---------------------------------------------------------------
222 // Archive
223 //
224 // Archives the BTranslatorRoster by recording its loaded add-ons
225 // in the BMessage into. The deep variable appeared to have no
226 // impact in Be's version of this function, so I went the same
227 // route.
228 //
229 // Preconditions:
230 //
231 // Parameters: into, the BMessage that this object is written to
232 //             deep, if true, more data is written, if false,
233 //                   less data is written
234 //
235 // Postconditions:
236 //
237 // Returns: B_OK, if everything went well
238 //          B_BAD_VALUE, if into is NULL
239 //          B_NOT_INITIALIZED, if the constructor couldn't create
240 //                             a semaphore
241 //          other errors that BMessage::AddString() and
242 //          BArchivable::Archive() return
243 // ---------------------------------------------------------------
244 status_t
245 BTranslatorRoster::Archive(BMessage *into, bool deep) const
246 {
247 	if (!into)
248 		return B_BAD_VALUE;
249 
250 	status_t result = B_NOT_INITIALIZED;
251 
252 	if (fSem > 0 && acquire_sem(fSem) == B_OK) {
253 		result = BArchivable::Archive(into, deep);
254 		if (result == B_OK) {
255 			result = into->AddString("class", "BTranslatorRoster");
256 
257 			translator_node *pTranNode = NULL;
258 			for (pTranNode = fpTranslators; result == B_OK && pTranNode;
259 				pTranNode = pTranNode->next) {
260 				if (pTranNode->path[0])
261 					result = into->AddString("be:translator_path",
262 						pTranNode->path);
263 			}
264 		}
265 		release_sem(fSem);
266 	}
267 
268 	return result;
269 }
270 
271 // ---------------------------------------------------------------
272 // Instantiate
273 //
274 // This static member function returns a new BTranslatorRosters
275 // object, allocated by new and created with the version of the
276 // constructor that takes a BMessage archive. However if the
277 // archive doesn't contain data for a BTranslatorRoster object,
278 // Instantiate() returns NULL.
279 //
280 // Preconditions:
281 //
282 // Parameters: from, the BMessage to create the new object from
283 //
284 // Postconditions:
285 //
286 // Returns: returns NULL if the BMessage was no good
287 //          returns a BArchivable * to a BTranslatorRoster
288 // ---------------------------------------------------------------
289 BArchivable *
290 BTranslatorRoster::Instantiate(BMessage *from)
291 {
292 	if (!from || !validate_instantiation(from, "BTranslatorRoster"))
293 		return NULL;
294 	else
295 		return new BTranslatorRoster(from);
296 }
297 
298 // ---------------------------------------------------------------
299 // Version
300 //
301 // Sets outCurVersion to the Translation Kit protocol version
302 // number and outMinVersion to the minimum  protocol version number
303 // supported. Returns a string containing verbose version
304 // information.  Currently, inAppVersion must be
305 // B_TRANSLATION_CURRENT_VERSION, but as far as I can tell, its
306 // completely ignored.
307 //
308 // Preconditions:
309 //
310 // Parameters: outCurVersion, the current version is stored here
311 //             outMinVersion, the minimum supported version is
312 //                            stored here
313 //             inAppVersion, is ignored as far as I know
314 //
315 // Postconditions:
316 //
317 // Returns: string of verbose translation kit version
318 //          information or an empty string if either of the
319 //          out variables is NULL.
320 // ---------------------------------------------------------------
321 const char *
322 BTranslatorRoster::Version(int32 *outCurVersion, int32 *outMinVersion,
323 	int32 inAppVersion)
324 {
325 	if (!outCurVersion || !outMinVersion)
326 		return "";
327 
328 	static char vString[50];
329 	static char vDate[] = __DATE__;
330 	if (!vString[0]) {
331 		sprintf(vString, "Translation Kit v%d.%d.%d %s\n",
332 			static_cast<int>(B_TRANSLATION_MAJOR_VER(B_TRANSLATION_CURRENT_VERSION)),
333 			static_cast<int>(B_TRANSLATION_MINOR_VER(B_TRANSLATION_CURRENT_VERSION)),
334 			static_cast<int>(B_TRANSLATION_REVSN_VER(B_TRANSLATION_CURRENT_VERSION)),
335 			vDate);
336 	}
337 	*outCurVersion = B_TRANSLATION_CURRENT_VERSION;
338 	*outMinVersion = B_TRANSLATION_MIN_VERSION;
339 	return vString;
340 }
341 
342 // ---------------------------------------------------------------
343 // Default
344 //
345 // This static member function returns a pointer to the default
346 // BTranslatorRoster that has the default translators stored in
347 // it. The paths for the default translators are loaded from
348 // the TRANSLATORS environment variable. If it does not exist,
349 // the paths used are /boot/home/config/add-ons/Translators,
350 // /boot/home/config/add-ons/Datatypes, and
351 // /system/add-ons/Translators. The BTranslatorRoster returned
352 // by this function is global to the application and should
353 // not be deleted.
354 //
355 // This code probably isn't thread safe (yet).
356 //
357 // Preconditions:
358 //
359 // Parameters:
360 //
361 // Postconditions:
362 //
363 // Returns: pointer to the default BTranslatorRoster
364 // ---------------------------------------------------------------
365 BTranslatorRoster *
366 BTranslatorRoster::Default()
367 {
368 	// If the default translators have not been loaded,
369 	// create a new BTranslatorRoster for them, and load them.
370 	if (!fspDefaultTranslators) {
371 		fspDefaultTranslators = new BTranslatorRoster();
372 		fspDefaultTranslators->AddTranslators(NULL);
373 	}
374 
375 	return fspDefaultTranslators;
376 }
377 
378 // ---------------------------------------------------------------
379 // AddTranslators
380 //
381 // This function takes a string of colon delimited paths,
382 // (folders or specific files) and adds the translators from
383 // those paths to this BTranslatorRoster.
384 //
385 // If load_path is NULL, it parses the environment variable
386 // TRANSLATORS. If that does not exist, it uses the paths:
387 // /boot/home/config/add-ons/Translators,
388 // /boot/home/config/add-ons/Datatypes and
389 // /system/add-ons/Translators.
390 //
391 // Preconditions:
392 //
393 // Parameters: load_path, colon delimited list of paths
394 //                        to load translators from
395 //
396 // Postconditions:
397 //
398 // Returns: B_OK on success,
399 //          B_BAD_VALUE if there was something wrong with
400 //                      load_path
401 //          other errors for problems with loading add-ons
402 // ---------------------------------------------------------------
403 status_t
404 BTranslatorRoster::AddTranslators(const char *load_path)
405 {
406 	if (fSem <= 0)
407 		return fSem;
408 
409 	status_t loadErr = B_ERROR;
410 	int32 nLoaded = 0;
411 
412 	if (acquire_sem(fSem) == B_OK) {
413 		if (load_path == NULL)
414 			load_path = getenv("TRANSLATORS");
415 		if (load_path == NULL)
416 			load_path = kgDefaultTranslatorPath;
417 
418 		char pathbuf[PATH_MAX];
419 		const char *ptr = load_path;
420 		const char *end = ptr;
421 		struct stat stbuf;
422 		while (*ptr != 0) {
423 			//	find segments specified by colons
424 			end = strchr(ptr, ':');
425 			if (end == NULL)
426 				end = ptr + strlen(ptr);
427 			if (end-ptr > PATH_MAX - 1)
428 				loadErr = B_BAD_VALUE;
429 			else {
430 				//	copy this segment of the path into a path, and load it
431 				memcpy(pathbuf, ptr, end - ptr);
432 				pathbuf[end - ptr] = 0;
433 
434 				if (!stat(pathbuf, &stbuf)) {
435 					//	files are loaded as translators
436 					if (S_ISREG(stbuf.st_mode)) {
437 						status_t err = LoadTranslator(pathbuf);
438 						if (err != B_OK)
439 							loadErr = err;
440 						else
441 							nLoaded++;
442 					} else
443 						//	directories are scanned
444 						LoadDir(pathbuf, loadErr, nLoaded);
445 				}
446 			}
447 			ptr = end + 1;
448 			if (*end == 0)
449 				break;
450 		} // while (*ptr != 0)
451 
452 		release_sem(fSem);
453 
454 	} // if (acquire_sem(fSem) == B_OK)
455 
456 	//	if anything loaded, it's not too bad
457 	if (nLoaded)
458 		loadErr = B_OK;
459 
460 	return loadErr;
461 }
462 
463 // ---------------------------------------------------------------
464 // AddTranslator
465 //
466 // Adds a BTranslator based object to the BTranslatorRoster.
467 // When you add a BTranslator roster, it is Acquire()'d by
468 // BTranslatorRoster; it is Release()'d when the
469 // BTranslatorRoster is deleted.
470 //
471 // Preconditions:
472 //
473 // Parameters: translator, the translator to be added to the
474 //                         BTranslatorRoster
475 //
476 // Postconditions:
477 //
478 // Returns: B_BAD_VALUE, if translator is NULL,
479 //          B_NOT_INITIALIZED, if the constructor couldn't
480 //                             create a semaphore
481 //          B_OK if all went well
482 // ---------------------------------------------------------------
483 status_t
484 BTranslatorRoster::AddTranslator(BTranslator *translator)
485 {
486 	if (!translator)
487 		return B_BAD_VALUE;
488 
489 	status_t result = B_NOT_INITIALIZED;
490 
491 	if (fSem > 0 && acquire_sem(fSem) == B_NO_ERROR) {
492 		// Add the translator to the list even if
493 		// it is already in the list
494 		result = AddTranslatorToList(translator);
495 		release_sem(fSem);
496 	}
497 
498 	return result;
499 }
500 
501 // ---------------------------------------------------------------
502 // Identify
503 //
504 // This function determines which translator is best suited
505 // to convert the data from inSource.
506 //
507 // Preconditions:
508 //
509 // Parameters: inSource, the data to be translated,
510 //             ioExtension, the configuration data for the
511 //                          translator
512 //             outInfo, the information about the chosen
513 //                      translator is put here
514 //             inHintType, a hint about the type of data
515 //                         that is in inSource, can be
516 //                         zero if type is not known
517 //             inHintMIME, a hint about the MIME type of
518 //                         data that is in inSource,
519 //                         can be NULL
520 //             inWantType, the desired output type for
521 //                         inSource, if zero, any type
522 //                         is ok.
523 //
524 // Postconditions:
525 //
526 // Returns: B_OK, identification of inSource was successful,
527 //          B_NO_TRANSLATOR, no appropriate translator found
528 //          B_NOT_INITIALIZED, the constructor failed to
529 //                             create a semaphore
530 //          B_BAD_VALUE, inSource or outInfo is NULL
531 //          other values, error using inSource
532 // ---------------------------------------------------------------
533 status_t
534 BTranslatorRoster::Identify(BPositionIO *inSource,
535 	BMessage *ioExtension, translator_info *outInfo,
536 	uint32 inHintType, const char *inHintMIME,
537 	uint32 inWantType)
538 {
539 	if (!inSource || !outInfo)
540 		return B_BAD_VALUE;
541 
542 	status_t result = B_NOT_INITIALIZED;
543 	bool bFoundMatch = false;
544 
545 	if (fSem > 0 && acquire_sem(fSem) == B_OK) {
546 
547 		translator_node *pTranNode = fpTranslators;
548 		float bestWeight = 0.0;
549 		for (; pTranNode; pTranNode = pTranNode->next) {
550 
551 			const translation_format *format = NULL;
552 			translator_info tmpInfo;
553 			float weight = 0.0;
554 			bool addmatch = false;
555 				// eliminates need for a goto
556 
557 			result = inSource->Seek(0, SEEK_SET);
558 			if (result == B_OK) {
559 
560 				int32 inputFormatsCount = 0;
561 				const translation_format *inputFormats =
562 					pTranNode->translator->InputFormats(&inputFormatsCount);
563 
564 				if (CheckFormats(inputFormats, inputFormatsCount, inHintType,
565 					 inHintMIME, &format)) {
566 
567 					// after checking the formats for hints, we still need to make
568 					// sure the translator recognizes the data and can output the
569 					// desired format, so we call its' Identify() function.
570 					if (format && !pTranNode->translator->Identify(inSource,
571 						format, ioExtension, &tmpInfo, inWantType))
572 						addmatch = true;
573 
574 				} else if (!pTranNode->translator->Identify(inSource, NULL,
575 					ioExtension, &tmpInfo, inWantType))
576 					addmatch = true;
577 
578 				if (addmatch) {
579 					weight = tmpInfo.quality * tmpInfo.capability;
580 					if (weight > bestWeight) {
581 						bFoundMatch = true;
582 						bestWeight = weight;
583 
584 						tmpInfo.translator = pTranNode->id;
585 						outInfo->type = tmpInfo.type;
586 						outInfo->translator = tmpInfo.translator;
587 						outInfo->group = tmpInfo.group;
588 						outInfo->quality = tmpInfo.quality;
589 						outInfo->capability = tmpInfo.capability;
590 						strcpy(outInfo->name, tmpInfo.name);
591 						strcpy(outInfo->MIME, tmpInfo.MIME);
592 					}
593 				}
594 			} // if (result == B_OK)
595 		} // for (; pTranNode; pTranNode = pTranNode->next)
596 
597 		if (bFoundMatch)
598 			result = B_NO_ERROR;
599 		else if (result == B_OK)
600 			result = B_NO_TRANSLATOR;
601 
602 		release_sem(fSem);
603 	} // if (acquire_sem(fSem) == B_OK)
604 
605 	return result;
606 }
607 
608 // ---------------------------------------------------------------
609 // compare_data
610 //
611 // This function is not a member of BTranslatorRoster, but it is
612 // used by the GetTranslators() member function as the function
613 // passed to qsort to sort the translators from best to worst.
614 //
615 // Preconditions:
616 //
617 // Parameters: a, pointer to translator_info structure to be
618 //                compared to b
619 //             b, pointer to translator_info structure to be
620 //                compared to a
621 //
622 // Postconditions:
623 //
624 // Returns:
625 //          NOTE: Since qsort sorts lowest to highest, and I want
626 //          the highest quality/capability first, I must do things
627 //          "backwards."
628 //
629 //          0   if A and B are equally capable
630 //          -1  if A is more capable than B
631 //          1   if A is less capable than B
632 // ---------------------------------------------------------------
633 static int
634 compare_data(const void *a, const void *b)
635 {
636 	register const translator_info *ai =
637 		reinterpret_cast<const translator_info *> (a);
638 
639 	register const translator_info *bi =
640 		reinterpret_cast<const translator_info *> (b);
641 
642 	float acmp, bcmp;
643 	acmp = ai->quality * ai->capability;
644 	bcmp = bi->quality * bi->capability;
645 	if (acmp == bcmp)
646 		return 0;
647 	else if (acmp > bcmp)
648 		return -1;
649 	else
650 		return 1;
651 }
652 
653 // ---------------------------------------------------------------
654 // GetTranslators
655 //
656 // Finds all translators capable of handling the data in inSource
657 // and puts them into the outInfo array (which you must delete
658 // yourself when you are done with it). Specifying a value for
659 // inHintType, inHintMIME and/or inWantType causes only the
660 // translators that satisfy them to be included in the outInfo.
661 //
662 // Preconditions:
663 //
664 // Parameters: inSource, the data that wants to be translated
665 //             ioExtension, configuration data for the translator
666 //             outInfo, the array of acceptable translators is
667 //                      stored here if the function succeeds
668 //             outNumInfo, number of entries in outInfo
669 //             inHintType, hint for the type of data in
670 //                         inSource, can be zero if the
671 //                         type is not known
672 //             inHintMIME, hint MIME type of the data
673 //                         in inSource, can be NULL if
674 //                         the MIME type is not known
675 //             inWantType, the desired output type for
676 //                         the data in inSource, can be zero
677 //                         for any type.
678 //
679 // Postconditions:
680 //
681 // Returns: B_OK, successfully indentified the data in inSource
682 //          B_NO_TRANSLATOR, no translator could handle inSource
683 //          B_NOT_INITIALIZED, the constructore failed to create
684 //                              a semaphore
685 //          B_BAD_VALUE, inSource, outInfo, or outNumInfo is NULL
686 //          other errors, problems using inSource
687 // ---------------------------------------------------------------
688 status_t
689 BTranslatorRoster::GetTranslators(BPositionIO *inSource,
690 	BMessage *ioExtension, translator_info **outInfo,
691 	int32 *outNumInfo, uint32 inHintType,
692 	const char *inHintMIME, uint32 inWantType)
693 {
694 	if (!inSource || !outInfo || !outNumInfo)
695 		return B_BAD_VALUE;
696 
697 	status_t result = B_NOT_INITIALIZED;
698 
699 	*outInfo = NULL;
700 	*outNumInfo = 0;
701 
702 	if (fSem > 0 && acquire_sem(fSem) == B_OK) {
703 
704 		int32 physCnt = 10;
705 		*outInfo = new translator_info[physCnt];
706 		*outNumInfo = 0;
707 
708 		translator_node *pTranNode = fpTranslators;
709 		for (; pTranNode; pTranNode = pTranNode->next) {
710 
711 			const translation_format *format = NULL;
712 			translator_info tmpInfo;
713 			bool addmatch = false;
714 				// avoid the need for a goto
715 
716 			result = inSource->Seek(0, SEEK_SET);
717 			if (result < B_OK) {
718 				// break out of the loop if error reading from source
719 				delete *outInfo;
720 				*outInfo = NULL;
721 				break;
722 			} else {
723 				int32 inputFormatsCount = 0;
724 				const translation_format *inputFormats =
725 					pTranNode->translator->InputFormats(&inputFormatsCount);
726 
727 				if (CheckFormats(inputFormats, inputFormatsCount, inHintType,
728 					inHintMIME, &format)) {
729 					if (format && !pTranNode->translator->Identify(inSource,
730 						format, ioExtension, &tmpInfo, inWantType))
731 						addmatch = true;
732 
733 				} else if (!pTranNode->translator->Identify(inSource, NULL,
734 					ioExtension, &tmpInfo, inWantType))
735 					addmatch = true;
736 
737 				if (addmatch) {
738 					//	dynamically resize output list
739 					//
740 					if (physCnt <= *outNumInfo) {
741 						physCnt += 10;
742 						translator_info *nOut = new translator_info[physCnt];
743 						for (int ix = 0; ix < *outNumInfo; ix++)
744 							nOut[ix] = (*outInfo)[ix];
745 
746 						delete[] *outInfo;
747 						*outInfo = nOut;
748 					}
749 
750 					 // XOR to discourage taking advantage of undocumented
751 					 // features
752 					tmpInfo.translator = pTranNode->id;
753 					(*outInfo)[(*outNumInfo)++] = tmpInfo;
754 				}
755 			}
756 		} // for (; pTranNode; pTranNode = pTranNode->next)
757 
758 		// if exited loop WITHOUT errors
759 		if (!pTranNode) {
760 
761 			if (*outNumInfo > 1)
762 				qsort(*outInfo, *outNumInfo, sizeof(**outInfo), compare_data);
763 
764 			if (*outNumInfo > 0)
765 				result = B_NO_ERROR;
766 			else
767 				result = B_NO_TRANSLATOR;
768 		}
769 
770 		release_sem(fSem);
771 
772 	} // if (acquire_sem(fSem) == B_OK)
773 
774 	return result;
775 }
776 
777 // ---------------------------------------------------------------
778 // GetAllTranslators
779 //
780 // Returns a list of all of the translators stored by this object.
781 // You must delete the list, outList, yourself when you are done
782 // with it.
783 //
784 // Preconditions:
785 //
786 // Parameters: outList, where the list is stored,
787 //                      (you must delete the list yourself)
788 //             outCount, where the count of the items in
789 //                       the list is stored
790 //
791 // Postconditions:
792 //
793 // Returns: B_BAD_VALUE, if outList or outCount is NULL
794 //          B_NOT_INITIALIZED, if the constructor couldn't
795 //                             create a semaphore
796 //          B_NO_ERROR, if successful
797 // ---------------------------------------------------------------
798 status_t
799 BTranslatorRoster::GetAllTranslators(
800 	translator_id **outList, int32 *outCount)
801 {
802 	if (!outList || !outCount)
803 		return B_BAD_VALUE;
804 
805 	status_t result = B_NOT_INITIALIZED;
806 
807 	*outList = NULL;
808 	*outCount = 0;
809 
810 	if (fSem > 0 && acquire_sem(fSem) == B_OK) {
811 		// count translators
812 		translator_node *pTranNode = NULL;
813 		for (pTranNode = fpTranslators; pTranNode; pTranNode = pTranNode->next)
814 			(*outCount)++;
815 		// populate the outList
816 		*outList = new translator_id[*outCount];
817 		int32 i = 0;
818 		for (pTranNode = fpTranslators; pTranNode; pTranNode = pTranNode->next)
819 			(*outList)[i++] = pTranNode->id;
820 
821 		result = B_NO_ERROR;
822 		release_sem(fSem);
823 	}
824 
825 	return result;
826 }
827 
828 // ---------------------------------------------------------------
829 // GetTranslatorInfo
830 //
831 // Returns information about the translator with translator_id
832 // forTranslator. outName is the short name of the translator,
833 // outInfo is the verbose name / description of the translator,
834 // and outVersion is the integer representation of the translator
835 // version.
836 //
837 // Preconditions:
838 //
839 // Parameters: forTranslator, identifies which translator
840 //                            you want info for
841 //             outName, the translator name is put here
842 //             outInfo, the translator info is put here
843 //             outVersion, the translation version is put here
844 //
845 // Postconditions:
846 //
847 // Returns: B_NO_ERROR, if successful,
848 //          B_BAD_VALUE, if any parameter is NULL
849 //          B_NOT_INITIALIZED, if the constructor couldn't
850 //                             create a semaphore
851 //          B_NO_TRANSLATOR, if forTranslator is not a valid
852 //                           translator id
853 // ---------------------------------------------------------------
854 status_t
855 BTranslatorRoster::GetTranslatorInfo(
856 	translator_id forTranslator, const char **outName,
857 	const char **outInfo, int32 *outVersion)
858 {
859 	if (!outName || !outInfo || !outVersion)
860 		return B_BAD_VALUE;
861 
862 	status_t result = B_NOT_INITIALIZED;
863 
864 	if (fSem > 0 && acquire_sem(fSem) == B_OK) {
865 		// find the translator we've requested
866 		translator_node *pTranNode = FindTranslatorNode(forTranslator);
867 		if (!pTranNode)
868 			result = B_NO_TRANSLATOR;
869 		else {
870 			*outName = pTranNode->translator->TranslatorName();
871 			*outInfo = pTranNode->translator->TranslatorInfo();
872 			*outVersion = pTranNode->translator->TranslatorVersion();
873 
874 			result = B_NO_ERROR;
875 		}
876 		release_sem(fSem);
877 	}
878 
879 	return result;
880 }
881 
882 // ---------------------------------------------------------------
883 // GetInputFormats
884 //
885 // Returns all of the input formats for the translator
886 // forTranslator. Not all translators publish the input formats
887 // that they accept.
888 //
889 // Preconditions:
890 //
891 // Parameters: forTranslator, identifies which translator
892 //                            you want info for
893 //              outFormats, array of input formats
894 //              outNumFormats, number of items in outFormats
895 //
896 // Postconditions:
897 //
898 // Returns: B_NO_ERROR, if successful
899 //          B_BAD_VALUE, if either pointer is NULL
900 //          B_NOT_INITIALIZED, if the constructor couldn't
901 //                             create a semaphore
902 //          B_NO_TRANSLATOR, if forTranslator is a bad id
903 // ---------------------------------------------------------------
904 status_t
905 BTranslatorRoster::GetInputFormats(translator_id forTranslator,
906 	const translation_format **outFormats, int32 *outNumFormats)
907 {
908 	if (!outFormats || !outNumFormats)
909 		return B_BAD_VALUE;
910 
911 	status_t result = B_NOT_INITIALIZED;
912 
913 	*outFormats = NULL;
914 	*outNumFormats = 0;
915 
916 	if (fSem > 0 && acquire_sem(fSem) == B_OK) {
917 		//	find the translator we've requested
918 		translator_node *pTranNode = FindTranslatorNode(forTranslator);
919 		if (!pTranNode)
920 			result = B_NO_TRANSLATOR;
921 		else {
922 			*outFormats = pTranNode->translator->InputFormats(outNumFormats);
923 			result = B_NO_ERROR;
924 		}
925 		release_sem(fSem);
926 	}
927 
928 	return result;
929 }
930 
931 // ---------------------------------------------------------------
932 // GetOutputFormats
933 //
934 // Returns all of the output formats for the translator
935 // forTranslator. Not all translators publish the output formats
936 // that they accept.
937 //
938 // Preconditions:
939 //
940 // Parameters: forTranslator, identifies which translator
941 //                            you want info for
942 //              outFormats, array of output formats
943 //              outNumFormats, number of items in outFormats
944 //
945 // Postconditions:
946 //
947 // Returns: B_NO_ERROR, if successful
948 //          B_BAD_VALUE, if either pointer is NULL
949 //          B_NOT_INITIALIZED, if the constructor couldn't
950 //                             create a semaphore
951 //          B_NO_TRANSLATOR, if forTranslator is a bad id
952 // ---------------------------------------------------------------
953 status_t
954 BTranslatorRoster::GetOutputFormats(translator_id forTranslator,
955 	const translation_format **outFormats, int32 *outNumFormats)
956 {
957 	if (!outFormats || !outNumFormats)
958 		return B_BAD_VALUE;
959 
960 	status_t result = B_NOT_INITIALIZED;
961 
962 	*outFormats = NULL;
963 	*outNumFormats = 0;
964 
965 	if (fSem > 0 && acquire_sem(fSem) == B_OK) {
966 		// find the translator we've requested
967 		translator_node *pTranNode = FindTranslatorNode(forTranslator);
968 		if (!pTranNode)
969 			result = B_NO_TRANSLATOR;
970 		else {
971 			*outFormats = pTranNode->translator->OutputFormats(outNumFormats);
972 			result = B_NO_ERROR;
973 		}
974 		release_sem(fSem);
975 	}
976 
977 	return result;
978 }
979 
980 // ---------------------------------------------------------------
981 // Translate
982 //
983 // This function is the whole point of the Translation Kit.
984 // This is for translating the data in inSource to outDestination
985 // using the format inWantOutType.
986 //
987 // Preconditions:
988 //
989 // Parameters: inSource, the data that wants to be translated
990 //             ioExtension, configuration data for the translator
991 //             inInfo, identifies the translator to use, can be
992 //                     NULL, calls Identify() if NULL
993 //             inHintType, hint for the type of data in
994 //                         inSource, can be zero if the
995 //                         type is not known
996 //             inHintMIME, hint MIME type of the data
997 //                         in inSource, can be NULL if
998 //                         the MIME type is not known
999 //             inWantOutType, the desired output type for
1000 //                            the data in inSource.
1001 //             outDestination,  where inSource is translated to
1002 //
1003 // Postconditions:
1004 //
1005 // Returns: B_OK, translation successful,
1006 //          B_NO_TRANSLATOR, no appropriate translator found
1007 //          B_NOT_INITIALIZED, the constructor failed to
1008 //                             create a semaphore
1009 //          B_BAD_VALUE, inSource or outDestination is NULL
1010 //          other values, error using inSource
1011 // ---------------------------------------------------------------
1012 status_t
1013 BTranslatorRoster::Translate(BPositionIO *inSource,
1014 	const translator_info *inInfo, BMessage *ioExtension,
1015 	BPositionIO *outDestination, uint32 inWantOutType,
1016 	uint32 inHintType, const char *inHintMIME)
1017 {
1018 	if (!inSource || !outDestination)
1019 		return B_BAD_VALUE;
1020 
1021 	if (fSem <= 0)
1022 		return B_NOT_INITIALIZED;
1023 
1024 	status_t result = B_OK;
1025 	translator_info stat_info;
1026 
1027 	if (!inInfo) {
1028 		//	go look for a suitable translator
1029 		inInfo = &stat_info;
1030 
1031 		result = Identify(inSource, ioExtension, &stat_info,
1032 				inHintType, inHintMIME, inWantOutType);
1033 			// Identify is a locked function, so it cannot be
1034 			// called from code that is already locked
1035 	}
1036 
1037 	if (result >= B_OK && acquire_sem(fSem) == B_OK) {
1038 		translator_node *pTranNode = FindTranslatorNode(inInfo->translator);
1039 		if (!pTranNode) {
1040 			result = B_NO_TRANSLATOR;
1041 		}
1042 		else {
1043 			result = inSource->Seek(0, SEEK_SET);
1044 			if (result == B_OK)
1045 				result = pTranNode->translator->Translate(inSource, inInfo,
1046 					ioExtension, inWantOutType, outDestination);
1047 		}
1048 		release_sem(fSem);
1049 	}
1050 
1051 	return result;
1052 }
1053 
1054 // ---------------------------------------------------------------
1055 // Translate
1056 //
1057 // This function is the whole point of the Translation Kit.
1058 // This is for translating the data in inSource to outDestination
1059 // using the format inWantOutType.
1060 //
1061 // Preconditions:
1062 //
1063 // Parameters: inSource, the data that wants to be translated
1064 //             ioExtension, configuration data for the translator
1065 //             inTranslator, the translator to use for the
1066 //                           translation
1067 //             inWantOutType, the desired output type for
1068 //                            the data in inSource.
1069 //             outDestination,  where inSource is translated to
1070 //
1071 // Postconditions:
1072 //
1073 // Returns: B_OK, translation successful,
1074 //          B_NO_TRANSLATOR, inTranslator is an invalid id
1075 //          B_NOT_INITIALIZED, the constructor failed to
1076 //                             create a semaphore
1077 //          B_BAD_VALUE, inSource or outDestination is NULL
1078 //          other values, error using inSource
1079 // ---------------------------------------------------------------
1080 status_t
1081 BTranslatorRoster::Translate(translator_id inTranslator,
1082 	BPositionIO *inSource, BMessage *ioExtension,
1083 	BPositionIO *outDestination, uint32 inWantOutType)
1084 {
1085 	if (!inSource || !outDestination)
1086 		return B_BAD_VALUE;
1087 
1088 	status_t result = B_NOT_INITIALIZED;
1089 
1090 	if (fSem > 0 && acquire_sem(fSem) == B_OK) {
1091 		translator_node *pTranNode = FindTranslatorNode(inTranslator);
1092 		if (!pTranNode)
1093 			result = B_NO_TRANSLATOR;
1094 		else {
1095 			result = inSource->Seek(0, SEEK_SET);
1096 			if (result == B_OK) {
1097 				translator_info traninfo;
1098 				result = pTranNode->translator->Identify(inSource, NULL,
1099 					ioExtension, &traninfo, inWantOutType);
1100 				if (result == B_OK) {
1101 					result = inSource->Seek(0, SEEK_SET);
1102 					if (result == B_OK) {
1103 						result = pTranNode->translator->Translate(inSource,
1104 							&traninfo, ioExtension, inWantOutType,
1105 							outDestination);
1106 					}
1107 				}
1108 			}
1109 		}
1110 		release_sem(fSem);
1111 	}
1112 
1113 	return result;
1114 }
1115 
1116 // ---------------------------------------------------------------
1117 // MakeConfigurationView
1118 //
1119 // Returns outView, a BView for configuring the translator
1120 // forTranslator. Not all translators support this.
1121 //
1122 // Preconditions:
1123 //
1124 // Parameters: forTranslator, the translator the view is for
1125 //             ioExtension, the configuration data for
1126 //                          the translator
1127 //             outView, the view for configuring the
1128 //                      translator
1129 //             outExtent, the bounds for the view, the view
1130 //                        can be resized
1131 //
1132 // Postconditions:
1133 //
1134 // Returns: B_OK, success,
1135 //          B_NO_TRANSLATOR, inTranslator is an invalid id
1136 //          B_NOT_INITIALIZED, the constructor failed to
1137 //                             create a semaphore
1138 //          B_BAD_VALUE, inSource or outDestination is NULL
1139 //          other values, error using inSource
1140 // ---------------------------------------------------------------
1141 status_t
1142 BTranslatorRoster::MakeConfigurationView(
1143 	translator_id forTranslator, BMessage *ioExtension,
1144 	BView **outView, BRect *outExtent)
1145 {
1146 	if (!outView || !outExtent)
1147 		return B_BAD_VALUE;
1148 
1149 	status_t result = B_NOT_INITIALIZED;
1150 
1151 	if (fSem > 0 && acquire_sem(fSem) == B_OK) {
1152 		translator_node *pTranNode = FindTranslatorNode(forTranslator);
1153 		if (!pTranNode)
1154 			result = B_NO_TRANSLATOR;
1155 		else
1156 			result = pTranNode->translator->MakeConfigurationView(ioExtension,
1157 				outView, outExtent);
1158 
1159 		release_sem(fSem);
1160 	}
1161 
1162 	return result;
1163 }
1164 
1165 // ---------------------------------------------------------------
1166 // GetConfigurationMessage
1167 //
1168 // Gets the configuration setttings for the translator
1169 // forTranslator and puts the settings into ioExtension.
1170 //
1171 // Preconditions:
1172 //
1173 // Parameters: forTranslator, the translator the info
1174 //                            is for
1175 //             ioExtension, the configuration data for
1176 //                          the translator is stored here
1177 //
1178 // Postconditions:
1179 //
1180 // Returns: B_OK, success,
1181 //          B_NO_TRANSLATOR, inTranslator is an invalid id
1182 //          B_NOT_INITIALIZED, the constructor failed to
1183 //                             create a semaphore
1184 //          B_BAD_VALUE, inSource or outDestination is NULL
1185 //          other values, error using inSource
1186 // ---------------------------------------------------------------
1187 status_t
1188 BTranslatorRoster::GetConfigurationMessage(
1189 	translator_id forTranslator, BMessage *ioExtension)
1190 {
1191 	if (!ioExtension)
1192 		return B_BAD_VALUE;
1193 
1194 	status_t result = B_NOT_INITIALIZED;
1195 
1196 	if (fSem > 0 && acquire_sem(fSem) == B_OK) {
1197 		translator_node *pTranNode = FindTranslatorNode(forTranslator);
1198 		if (!pTranNode)
1199 			result = B_NO_TRANSLATOR;
1200 		else
1201 			result =
1202 				pTranNode->translator->GetConfigurationMessage(ioExtension);
1203 
1204 		release_sem(fSem);
1205 	}
1206 
1207 	return result;
1208 }
1209 
1210 // ---------------------------------------------------------------
1211 // GetRefFor
1212 //
1213 // Gets the entry_ref for the given translator.
1214 //
1215 // Preconditions:
1216 //
1217 // Parameters: forTranslator, the translator the info
1218 //                            is for
1219 //             entry_ref, where the entry ref is stored
1220 //
1221 // Postconditions:
1222 //
1223 // Returns: B_OK, success,
1224 //          B_NO_TRANSLATOR, translator is an invalid id
1225 //          B_NOT_INITIALIZED, the constructor failed to
1226 //                             create a semaphore
1227 //          B_BAD_VALUE, inSource or outDestination is NULL
1228 //          other values, error using inSource
1229 // ---------------------------------------------------------------
1230 status_t
1231 BTranslatorRoster::GetRefFor(translator_id translator,
1232 	entry_ref *out_ref)
1233 {
1234 	if (!out_ref)
1235 		return B_BAD_VALUE;
1236 
1237 	status_t result = B_NOT_INITIALIZED;
1238 
1239 	if (fSem > 0 && acquire_sem(fSem) == B_OK) {
1240 		translator_node *pTranNode = FindTranslatorNode(translator);
1241 		if (!pTranNode)
1242 			result = B_NO_TRANSLATOR;
1243 		else {
1244 			if (pTranNode->path[0] == '\0')
1245 				result = B_ERROR;
1246 			else
1247 				result = get_ref_for_path(pTranNode->path, out_ref);
1248 		}
1249 		release_sem(fSem);
1250 	}
1251 
1252 	return result;
1253 }
1254 
1255 
1256 // ---------------------------------------------------------------
1257 // FindTranslatorNode
1258 //
1259 // Finds the translator_node that holds the translator with
1260 // the translator_id id.
1261 //
1262 // Preconditions:
1263 //
1264 // Parameters: id, the translator you want a translator_node for
1265 //
1266 // Postconditions:
1267 //
1268 // Returns: NULL if id is not a valid translator_id,
1269 //          pointer to the translator_node that holds the
1270 //          translator id
1271 // ---------------------------------------------------------------
1272 translator_node *
1273 BTranslatorRoster::FindTranslatorNode(translator_id id)
1274 {
1275 	translator_node *pTranNode = NULL;
1276 	for (pTranNode = fpTranslators; pTranNode; pTranNode = pTranNode->next)
1277 		if (pTranNode->id == id)
1278 			break;
1279 
1280 	return pTranNode;
1281 }
1282 
1283 const char *
1284 get_file_name(const char *path)
1285 {
1286 	const char *file_name = strrchr(path, '/');
1287 	if (file_name)
1288 		file_name++;
1289 	else
1290 		file_name = path;
1291 
1292 	return file_name;
1293 }
1294 
1295 // ---------------------------------------------------------------
1296 // LoadTranslator
1297 //
1298 // Loads the translator from path into memory and adds it to
1299 // the BTranslatorRoster.
1300 //
1301 // Preconditions: This should only be called inside of locked
1302 //                code.
1303 //
1304 // Parameters: path, the path for the translator to be loaded
1305 //
1306 // Postconditions:
1307 //
1308 // Returns: B_BAD_VALUE, if path is NULL,
1309 //          B_NO_ERROR, if all is well,
1310 //          other values if error loading add ons
1311 // ---------------------------------------------------------------
1312 status_t
1313 BTranslatorRoster::LoadTranslator(const char *path)
1314 {
1315 	if (!path)
1316 		return B_BAD_VALUE;
1317 
1318 	//	check that this ref is not already loaded
1319 	const char *file_name = get_file_name(path);
1320 
1321 	// If a translator with the same filename has already
1322 	// been loaded, do not load the current translator and
1323 	// return no error. This code is not fool proof, however.
1324 	for (translator_node *i = fpTranslators; i; i = i->next)
1325 		if (!strcmp(file_name, get_file_name(i->path)))
1326 			return B_NO_ERROR;
1327 
1328 	image_id image = load_add_on(path);
1329 		// Load the data and code for the Translator into memory
1330 	if (image < 0)
1331 		return image;
1332 
1333 	// Function pointer used to create post R4.5 style translators
1334 	BTranslator *(*pMakeNthTranslator)(int32 n, image_id you, uint32 flags, ...);
1335 
1336 	status_t err = get_image_symbol(image, "make_nth_translator",
1337 		B_SYMBOL_TYPE_TEXT, reinterpret_cast<void **> (&pMakeNthTranslator));
1338 	if (!err) {
1339 		// If the translator add-on supports the post R4.5
1340 		// translator creation mechanism, keep loading translators
1341 		// until MakeNthTranslator stops returning them.
1342 		BTranslator *ptran = NULL;
1343 		for (int32 n = 0; (ptran = pMakeNthTranslator(n, image, 0)); n++)
1344 			AddTranslatorToList(ptran, path, image, false);
1345 
1346 		return B_NO_ERROR;
1347 
1348 	} else {
1349 		// If the translator add-on is in the R4.0 / R4.5 format
1350 		translator_data trand;
1351 		trand.translatorName = NULL;
1352 		trand.translatorInfo = NULL;
1353 		trand.translatorVersion = 0;
1354 		trand.inputFormats = NULL;
1355 		trand.outputFormats = NULL;
1356 		trand.Identify = NULL;
1357 		trand.Translate = NULL;
1358 		trand.MakeConfig = NULL;
1359 		trand.GetConfigMessage = NULL;
1360 
1361 		char *name = NULL, *info = NULL;
1362 		translation_format *ins = NULL, *outs = NULL;
1363 
1364 		//	find all the symbols
1365 		err = get_image_symbol(image, "translatorName", B_SYMBOL_TYPE_DATA,
1366 			reinterpret_cast<void **> (&name));
1367 		if (err)
1368 			name = NULL;
1369 		else if (!err && get_image_symbol(image, "translatorInfo",
1370 			B_SYMBOL_TYPE_DATA, reinterpret_cast<void **> (&info)))
1371 			info = NULL;
1372 
1373 		int32 *pn = NULL;
1374 		if (!err) {
1375 			err = get_image_symbol(image, "translatorVersion",
1376 				B_SYMBOL_TYPE_DATA, reinterpret_cast<void **> (&pn));
1377 			if (!err && (pn != NULL))
1378 				trand.translatorVersion = *pn;
1379 		}
1380 
1381 		if (!err && get_image_symbol(image, "inputFormats",
1382 			B_SYMBOL_TYPE_DATA,
1383 			reinterpret_cast<void **> (&ins)))
1384 			ins = NULL;
1385 
1386 		if (!err && get_image_symbol(image, "outputFormats",
1387 			B_SYMBOL_TYPE_DATA,
1388 			reinterpret_cast<void **> (&outs)))
1389 			outs = NULL;
1390 
1391 		if (!err)
1392 			err = get_image_symbol(image, "Identify",
1393 				B_SYMBOL_TYPE_TEXT,
1394 				reinterpret_cast<void **> (&trand.Identify));
1395 
1396 		if (!err)
1397 			err = get_image_symbol(image, "Translate",
1398 				B_SYMBOL_TYPE_TEXT,
1399 				reinterpret_cast<void **> (&trand.Translate));
1400 
1401 		if (!err && get_image_symbol(image, "MakeConfig",
1402 			B_SYMBOL_TYPE_TEXT,
1403 			reinterpret_cast<void **> (&trand.MakeConfig)))
1404 			trand.MakeConfig = NULL;
1405 
1406 		if (!err && get_image_symbol(image, "GetConfigMessage",
1407 			B_SYMBOL_TYPE_TEXT,
1408 			reinterpret_cast<void **> (&trand.GetConfigMessage)))
1409 			trand.GetConfigMessage = NULL;
1410 
1411 		trand.translatorName = name;
1412 		trand.translatorInfo = info;
1413 		trand.inputFormats = ins;
1414 		trand.outputFormats = outs;
1415 
1416 		// if add-on is not in the correct format, return with error
1417 		if (err)
1418 			return err;
1419 
1420 		// add this translator to the list
1421 		BFuncTranslator *pFuncTran = new BFuncTranslator(&trand);
1422 		AddTranslatorToList(pFuncTran, path, image, false);
1423 			// do not call Acquire() on ptran because I want it to be
1424 			// deleted the first time Release() is called on it.
1425 
1426 		return B_NO_ERROR;
1427 	}
1428 }
1429 
1430 // ---------------------------------------------------------------
1431 // LoadDir
1432 //
1433 // Loads all of the translators in the directory path
1434 //
1435 // Preconditions: should only be called inside locked code
1436 //
1437 // Parameters: path, the directory of translators to load
1438 //             loadErr, the return code
1439 //             nLoaded, number of translators loaded
1440 //
1441 // Postconditions:
1442 //
1443 // Returns: B_FILE_NOT_FOUND, if the path is NULL or invalid
1444 //          other errors if LoadTranslator failed
1445 // ---------------------------------------------------------------
1446 void
1447 BTranslatorRoster::LoadDir(const char *path, int32 &loadErr, int32 &nLoaded)
1448 {
1449 	if (!path) {
1450 		loadErr = B_FILE_NOT_FOUND;
1451 		return;
1452 	}
1453 
1454 	loadErr = B_OK;
1455 	DIR *dir = opendir(path);
1456 	if (!dir) {
1457 		loadErr = B_FILE_NOT_FOUND;
1458 		return;
1459 	}
1460 	struct dirent *dent;
1461 	struct stat stbuf;
1462 	char cwd[PATH_MAX] = "";
1463 	while (NULL != (dent = readdir(dir))) {
1464 		strcpy(cwd, path);
1465 		strcat(cwd, "/");
1466 		strcat(cwd, dent->d_name);
1467 		status_t err = stat(cwd, &stbuf);
1468 
1469 		if (!err && S_ISREG(stbuf.st_mode) &&
1470 			strcmp(dent->d_name, ".") && strcmp(dent->d_name, "..")) {
1471 
1472 			err = LoadTranslator(cwd);
1473 			if (err == B_OK)
1474 				nLoaded++;
1475 			else
1476 				loadErr = err;
1477 		}
1478 	}
1479 	closedir(dir);
1480 }
1481 
1482 // ---------------------------------------------------------------
1483 // CheckFormats
1484 //
1485 // Function used to determine if hintType and hintMIME can be
1486 // used to find the desired translation_format.
1487 //
1488 // Preconditions: Should only be called from inside locked code
1489 //
1490 // Parameters: inputFormats, the formats check against the hints
1491 //             inputFormatsCount, number of items in inputFormats
1492 //             hintType, the type this function is looking for
1493 //             hintMIME, the MIME type this function is looking
1494 //                       for
1495 //             outFormat, NULL if no suitable translation_format
1496 //                        from inputFormats was found, not NULL
1497 //                        if a translation_format matching the
1498 //                        hints was found
1499 //
1500 //
1501 // Postconditions:
1502 //
1503 // Returns: true, if a determination could be made
1504 //          false, if indentification must be done
1505 // ---------------------------------------------------------------
1506 bool
1507 BTranslatorRoster::CheckFormats(const translation_format *inputFormats,
1508 	int32 inputFormatsCount, uint32 hintType, const char *hintMIME,
1509 	const translation_format **outFormat)
1510 {
1511 	if (!inputFormats || inputFormatsCount <= 0 || !outFormat)
1512 		return false;
1513 
1514 	*outFormat = NULL;
1515 
1516 	// return false if we can't use hints for this module
1517 	if (!hintType && !hintMIME)
1518 		return false;
1519 
1520 	// check for the length of the MIME string, since it may be just a prefix
1521 	// so we use strncmp().
1522 	int mlen = 0;
1523 	if (hintMIME)
1524 		mlen = strlen(hintMIME);
1525 
1526 	// scan for suitable format
1527 	const translation_format *fmt = inputFormats;
1528 	for (int32 i = 0; i < inputFormatsCount && fmt->type; i++, fmt++) {
1529 		if ((fmt->type == hintType) ||
1530 			(hintMIME && mlen && !strncmp(fmt->MIME, hintMIME, mlen))) {
1531 			*outFormat = fmt;
1532 			return true;
1533 		}
1534 	}
1535 	// the module did export formats, but none matched.
1536 	// we return true (uses formats) but set outFormat to NULL
1537 	return true;
1538 }
1539 
1540 // ---------------------------------------------------------------
1541 // AddTranslatorToList
1542 //
1543 // Adds a BTranslator based object to the list of translators
1544 // stored by the BTranslatorRoster.
1545 //
1546 // Preconditions: Should only be called inside locked code
1547 //
1548 // Parameters: translator, the translator to add to this object
1549 //
1550 // Postconditions:
1551 //
1552 // Returns: B_BAD_VALUE, if translator is NULL
1553 //          B_OK, if not
1554 // ---------------------------------------------------------------
1555 status_t
1556 BTranslatorRoster::AddTranslatorToList(BTranslator *translator)
1557 {
1558 	return AddTranslatorToList(translator, "", -1, true);
1559 		// add translator to list with no add-on image to unload,
1560 		// and call Acquire() on it
1561 }
1562 
1563 // ---------------------------------------------------------------
1564 // AddTranslatorToList
1565 //
1566 // Adds a BTranslator based object to the list of translators
1567 // stored by the BTranslatorRoster.
1568 //
1569 // Preconditions: Should only be called inside locked code
1570 //
1571 // Parameters: translator, the translator to add to this object
1572 //             path, the path the translator was loaded from
1573 //             image, the image the translator was loaded from
1574 //             acquire, if true Acquire() is called on the
1575 //                      translator
1576 //
1577 // Postconditions:
1578 //
1579 // Returns: B_BAD_VALUE, if translator is NULL
1580 //          B_OK, if not
1581 // ---------------------------------------------------------------
1582 status_t
1583 BTranslatorRoster::AddTranslatorToList(BTranslator *translator,
1584 	const char *path, image_id image, bool acquire)
1585 {
1586 	if (!translator || !path)
1587 		return B_BAD_VALUE;
1588 
1589 	translator_node *pTranNode = new translator_node;
1590 
1591 	if (acquire)
1592 		pTranNode->translator = translator->Acquire();
1593 	else
1594 		pTranNode->translator = translator;
1595 
1596 	if (fpTranslators)
1597 		pTranNode->id = fpLastTranslator->id + 1;
1598 	else
1599 		pTranNode->id = 1;
1600 
1601 	pTranNode->path = new char[strlen(path) + 1];
1602 	strcpy(pTranNode->path, path);
1603 	pTranNode->image = image;
1604 	pTranNode->next = NULL;
1605 	if (!fpTranslators)
1606 		fpTranslators = fpLastTranslator = pTranNode;
1607 	else {
1608 		fpLastTranslator->next = pTranNode;
1609 		fpLastTranslator = pTranNode;
1610 	}
1611 
1612 	return B_OK;
1613 }
1614 
1615 // ---------------------------------------------------------------
1616 // ReservedTranslatorRoster1
1617 //
1618 // It does nothing! :) Its here only for past/future binary
1619 // compatibility.
1620 //
1621 // Preconditions:
1622 //
1623 // Parameters:
1624 //
1625 // Postconditions:
1626 //
1627 // Returns:
1628 // ---------------------------------------------------------------
1629 void
1630 BTranslatorRoster::ReservedTranslatorRoster1()
1631 {
1632 }
1633 
1634 // ---------------------------------------------------------------
1635 // ReservedTranslatorRoster2
1636 //
1637 // It does nothing! :) Its here only for past/future binary
1638 // compatibility.
1639 //
1640 // Preconditions:
1641 //
1642 // Parameters:
1643 //
1644 // Postconditions:
1645 //
1646 // Returns:
1647 // ---------------------------------------------------------------
1648 void
1649 BTranslatorRoster::ReservedTranslatorRoster2()
1650 {
1651 }
1652 
1653 // ---------------------------------------------------------------
1654 // ReservedTranslatorRoster3
1655 //
1656 // It does nothing! :) Its here only for past/future binary
1657 // compatibility.
1658 //
1659 // Preconditions:
1660 //
1661 // Parameters:
1662 //
1663 // Postconditions:
1664 //
1665 // Returns:
1666 // ---------------------------------------------------------------
1667 void
1668 BTranslatorRoster::ReservedTranslatorRoster3()
1669 {
1670 }
1671 
1672 // ---------------------------------------------------------------
1673 // ReservedTranslatorRoster4
1674 //
1675 // It does nothing! :) Its here only for past/future binary
1676 // compatibility.
1677 //
1678 // Preconditions:
1679 //
1680 // Parameters:
1681 //
1682 // Postconditions:
1683 //
1684 // Returns:
1685 // ---------------------------------------------------------------
1686 void
1687 BTranslatorRoster::ReservedTranslatorRoster4()
1688 {
1689 }
1690 
1691 // ---------------------------------------------------------------
1692 // ReservedTranslatorRoster5
1693 //
1694 // It does nothing! :) Its here only for past/future binary
1695 // compatibility.
1696 //
1697 // Preconditions:
1698 //
1699 // Parameters:
1700 //
1701 // Postconditions:
1702 //
1703 // Returns:
1704 // ---------------------------------------------------------------
1705 void
1706 BTranslatorRoster::ReservedTranslatorRoster5()
1707 {
1708 }
1709 
1710 // ---------------------------------------------------------------
1711 // ReservedTranslatorRoster6
1712 //
1713 // It does nothing! :) Its here only for past/future binary
1714 // compatibility.
1715 //
1716 // Preconditions:
1717 //
1718 // Parameters:
1719 //
1720 // Postconditions:
1721 //
1722 // Returns:
1723 // ---------------------------------------------------------------
1724 void
1725 BTranslatorRoster::ReservedTranslatorRoster6()
1726 {
1727 }
1728 
1729