xref: /haiku/src/kits/translation/TranslatorRoster.cpp (revision 7120e97489acbf17d86d3f33e3b2e68974fd4b23)
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 = 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 = 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 			B_TRANSLATION_CURRENT_VERSION/100,
333 			(B_TRANSLATION_CURRENT_VERSION/10)%10,
334 			B_TRANSLATION_CURRENT_VERSION%10,
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 		// Determine if translator is already in the list
493 		translator_node *pNode = fpTranslators;
494 		while (pNode) {
495 			// If translator is in the list, don't add it
496 			if (!strcmp(pNode->translator->TranslatorName(),
497 				translator->TranslatorName())) {
498 				result = B_OK;
499 				break;
500 			}
501 			pNode = pNode->next;
502 		}
503 
504 		// if translator is NOT in the list, add it
505 		if (!pNode)
506 			result = AddTranslatorToList(translator);
507 
508 		release_sem(fSem);
509 	}
510 
511 	return result;
512 }
513 
514 // ---------------------------------------------------------------
515 // Identify
516 //
517 // This function determines which translator is best suited
518 // to convert the data from inSource.
519 //
520 // Preconditions:
521 //
522 // Parameters: inSource, the data to be translated,
523 //             ioExtension, the configuration data for the
524 //                          translator
525 //             outInfo, the information about the chosen
526 //                      translator is put here
527 //             inHintType, a hint about the type of data
528 //                         that is in inSource, can be
529 //                         zero if type is not known
530 //             inHintMIME, a hint about the MIME type of
531 //                         data that is in inSource,
532 //                         can be NULL
533 //             inWantType, the desired output type for
534 //                         inSource, if zero, any type
535 //                         is ok.
536 //
537 // Postconditions:
538 //
539 // Returns: B_OK, identification of inSource was successful,
540 //          B_NO_TRANSLATOR, no appropriate translator found
541 //          B_NOT_INITIALIZED, the constructor failed to
542 //                             create a semaphore
543 //          B_BAD_VALUE, inSource or outInfo is NULL
544 //          other values, error using inSource
545 // ---------------------------------------------------------------
546 status_t
547 BTranslatorRoster::Identify(BPositionIO *inSource,
548 	BMessage *ioExtension, translator_info *outInfo,
549 	uint32 inHintType, const char *inHintMIME,
550 	uint32 inWantType)
551 {
552 	if (!inSource || !outInfo)
553 		return B_BAD_VALUE;
554 
555 	status_t result = B_NOT_INITIALIZED;
556 	bool bFoundMatch = false;
557 
558 	if (fSem > 0 && acquire_sem(fSem) == B_OK) {
559 
560 		translator_node *pTranNode = fpTranslators;
561 		float bestWeight = 0.0;
562 		for (; pTranNode; pTranNode = pTranNode->next) {
563 
564 			const translation_format *format = NULL;
565 			translator_info tmpInfo;
566 			float weight = 0.0;
567 			bool addmatch = false;
568 				// eliminates need for a goto
569 
570 			result = inSource->Seek(0, SEEK_SET);
571 			if (result == B_OK) {
572 
573 				int32 inputFormatsCount = 0;
574 				const translation_format *inputFormats =
575 					pTranNode->translator->InputFormats(&inputFormatsCount);
576 
577 				if (CheckFormats(inputFormats, inputFormatsCount, inHintType,
578 					 inHintMIME, &format)) {
579 
580 					// after checking the formats for hints, we still need to make
581 					// sure the translator recognizes the data and can output the
582 					// desired format, so we call its' Identify() function.
583 					if (format && !pTranNode->translator->Identify(inSource,
584 						format, ioExtension, &tmpInfo, inWantType))
585 						addmatch = true;
586 
587 				} else if (!pTranNode->translator->Identify(inSource, NULL,
588 					ioExtension, &tmpInfo, inWantType))
589 					addmatch = true;
590 
591 				if (addmatch) {
592 					weight = tmpInfo.quality * tmpInfo.capability;
593 
594 					// Since many kinds of data can look like text,
595 					// don't choose the text format if it has been identified
596 					// as belonging to a different group.
597 					if (bFoundMatch && outInfo->group == B_TRANSLATOR_TEXT &&
598 						tmpInfo.group != B_TRANSLATOR_TEXT)
599 						bestWeight = 0.0;
600 					else if (bFoundMatch && tmpInfo.group == B_TRANSLATOR_TEXT &&
601 						outInfo->group != B_TRANSLATOR_TEXT)
602 						weight = 0.0;
603 
604 					if (weight > bestWeight) {
605 						bFoundMatch = true;
606 						bestWeight = weight;
607 
608 						tmpInfo.translator = pTranNode->id;
609 						outInfo->type = tmpInfo.type;
610 						outInfo->translator = tmpInfo.translator;
611 						outInfo->group = tmpInfo.group;
612 						outInfo->quality = tmpInfo.quality;
613 						outInfo->capability = tmpInfo.capability;
614 						strcpy(outInfo->name, tmpInfo.name);
615 						strcpy(outInfo->MIME, tmpInfo.MIME);
616 					}
617 				}
618 			} // if (result == B_OK)
619 		} // for (; pTranNode; pTranNode = pTranNode->next)
620 
621 		if (bFoundMatch)
622 			result = B_NO_ERROR;
623 		else if (result == B_OK)
624 			result = B_NO_TRANSLATOR;
625 
626 		release_sem(fSem);
627 	} // if (acquire_sem(fSem) == B_OK)
628 
629 	return result;
630 }
631 
632 // ---------------------------------------------------------------
633 // compare_data
634 //
635 // This function is not a member of BTranslatorRoster, but it is
636 // used by the GetTranslators() member function as the function
637 // passed to qsort to sort the translators from best to worst.
638 //
639 // Preconditions:
640 //
641 // Parameters: a, pointer to translator_info structure to be
642 //                compared to b
643 //             b, pointer to translator_info structure to be
644 //                compared to a
645 //
646 // Postconditions:
647 //
648 // Returns: < 0 if a is less desirable than b,
649 //          0 if a as good as b,
650 //          > 0 if a is more desirable than b
651 // ---------------------------------------------------------------
652 static int
653 compare_data(const void *a, const void *b)
654 {
655 	register const translator_info *ai =
656 		reinterpret_cast<const translator_info *> (a);
657 
658 	register const translator_info *bi =
659 		reinterpret_cast<const translator_info *> (b);
660 
661 	return static_cast<int> (- ai->quality * ai->capability +
662 		bi->quality * bi->capability);
663 }
664 
665 // ---------------------------------------------------------------
666 // GetTranslators
667 //
668 // Finds all translators capable of handling the data in inSource
669 // and puts them into the outInfo array (which you must delete
670 // yourself when you are done with it). Specifying a value for
671 // inHintType, inHintMIME and/or inWantType causes only the
672 // translators that satisfy them to be included in the outInfo.
673 //
674 // Preconditions:
675 //
676 // Parameters: inSource, the data that wants to be translated
677 //             ioExtension, configuration data for the translator
678 //             outInfo, the array of acceptable translators is
679 //                      stored here if the function succeeds
680 //             outNumInfo, number of entries in outInfo
681 //             inHintType, hint for the type of data in
682 //                         inSource, can be zero if the
683 //                         type is not known
684 //             inHintMIME, hint MIME type of the data
685 //                         in inSource, can be NULL if
686 //                         the MIME type is not known
687 //             inWantType, the desired output type for
688 //                         the data in inSource, can be zero
689 //                         for any type.
690 //
691 // Postconditions:
692 //
693 // Returns: B_OK, successfully indentified the data in inSource
694 //          B_NO_TRANSLATOR, no translator could handle inSource
695 //          B_NOT_INITIALIZED, the constructore failed to create
696 //                              a semaphore
697 //          B_BAD_VALUE, inSource, outInfo, or outNumInfo is NULL
698 //          other errors, problems using inSource
699 // ---------------------------------------------------------------
700 status_t
701 BTranslatorRoster::GetTranslators(BPositionIO *inSource,
702 	BMessage *ioExtension, translator_info **outInfo,
703 	int32 *outNumInfo, uint32 inHintType,
704 	const char *inHintMIME, uint32 inWantType)
705 {
706 	if (!inSource || !outInfo || !outNumInfo)
707 		return B_BAD_VALUE;
708 
709 	status_t result = B_NOT_INITIALIZED;
710 
711 	*outInfo = NULL;
712 	*outNumInfo = 0;
713 
714 	if (fSem > 0 && acquire_sem(fSem) == B_OK) {
715 
716 		int32 physCnt = 10;
717 		*outInfo = new translator_info[physCnt];
718 		*outNumInfo = 0;
719 
720 		translator_node *pTranNode = fpTranslators;
721 		for (; pTranNode; pTranNode = pTranNode->next) {
722 
723 			const translation_format *format = NULL;
724 			translator_info tmpInfo;
725 			bool addmatch = false;
726 				// avoid the need for a goto
727 
728 			result = inSource->Seek(0, SEEK_SET);
729 			if (result < B_OK) {
730 				// break out of the loop if error reading from source
731 				delete *outInfo;
732 				*outInfo = NULL;
733 				break;
734 			} else {
735 				int32 inputFormatsCount = 0;
736 				const translation_format *inputFormats =
737 					pTranNode->translator->InputFormats(&inputFormatsCount);
738 
739 				if (CheckFormats(inputFormats, inputFormatsCount, inHintType,
740 					inHintMIME, &format)) {
741 					if (format && !pTranNode->translator->Identify(inSource,
742 						format, ioExtension, &tmpInfo, inWantType))
743 						addmatch = true;
744 
745 				} else if (!pTranNode->translator->Identify(inSource, NULL,
746 					ioExtension, &tmpInfo, inWantType))
747 					addmatch = true;
748 
749 				if (addmatch) {
750 					//	dynamically resize output list
751 					//
752 					if (physCnt <= *outNumInfo) {
753 						physCnt += 10;
754 						translator_info *nOut = new translator_info[physCnt];
755 						for (int ix = 0; ix < *outNumInfo; ix++)
756 							nOut[ix] = (*outInfo)[ix];
757 
758 						delete[] *outInfo;
759 						*outInfo = nOut;
760 					}
761 
762 					 // XOR to discourage taking advantage of undocumented
763 					 // features
764 					tmpInfo.translator = pTranNode->id;
765 					(*outInfo)[(*outNumInfo)++] = tmpInfo;
766 				}
767 			}
768 		} // for (; pTranNode; pTranNode = pTranNode->next)
769 
770 		// if exited loop WITHOUT errors
771 		if (!pTranNode) {
772 
773 			if (*outNumInfo > 1)
774 				qsort(*outInfo, *outNumInfo, sizeof(**outInfo), compare_data);
775 
776 			if (*outNumInfo > 0)
777 				result = B_NO_ERROR;
778 			else
779 				result = B_NO_TRANSLATOR;
780 		}
781 
782 		release_sem(fSem);
783 
784 	} // if (acquire_sem(fSem) == B_OK)
785 
786 	return result;
787 }
788 
789 // ---------------------------------------------------------------
790 // GetAllTranslators
791 //
792 // Returns a list of all of the translators stored by this object.
793 // You must delete the list, outList, yourself when you are done
794 // with it.
795 //
796 // Preconditions:
797 //
798 // Parameters: outList, where the list is stored,
799 //                      (you must delete the list yourself)
800 //             outCount, where the count of the items in
801 //                       the list is stored
802 //
803 // Postconditions:
804 //
805 // Returns: B_BAD_VALUE, if outList or outCount is NULL
806 //          B_NOT_INITIALIZED, if the constructor couldn't
807 //                             create a semaphore
808 //          B_NO_ERROR, if successful
809 // ---------------------------------------------------------------
810 status_t
811 BTranslatorRoster::GetAllTranslators(
812 	translator_id **outList, int32 *outCount)
813 {
814 	if (!outList || !outCount)
815 		return B_BAD_VALUE;
816 
817 	status_t result = B_NOT_INITIALIZED;
818 
819 	*outList = NULL;
820 	*outCount = 0;
821 
822 	if (fSem > 0 && acquire_sem(fSem) == B_OK) {
823 		// count handlers
824 		translator_node *pTranNode = NULL;
825 		for (pTranNode = fpTranslators; pTranNode; pTranNode = pTranNode->next)
826 			(*outCount)++;
827 		*outList = new translator_id[*outCount];
828 		*outCount = 0;
829 		for (pTranNode = fpTranslators; pTranNode; pTranNode = pTranNode->next)
830 			(*outList)[(*outCount)++] = pTranNode->id;
831 
832 		result = B_NO_ERROR;
833 		release_sem(fSem);
834 	}
835 
836 	return result;
837 }
838 
839 // ---------------------------------------------------------------
840 // GetTranslatorInfo
841 //
842 // Returns information about the translator with translator_id
843 // forTranslator. outName is the short name of the translator,
844 // outInfo is the verbose name / description of the translator,
845 // and outVersion is the integer representation of the translator
846 // version.
847 //
848 // Preconditions:
849 //
850 // Parameters: forTranslator, identifies which translator
851 //                            you want info for
852 //             outName, the translator name is put here
853 //             outInfo, the translator info is put here
854 //             outVersion, the translation version is put here
855 //
856 // Postconditions:
857 //
858 // Returns: B_NO_ERROR, if successful,
859 //          B_BAD_VALUE, if any parameter is NULL
860 //          B_NOT_INITIALIZED, if the constructor couldn't
861 //                             create a semaphore
862 //          B_NO_TRANSLATOR, if forTranslator is not a valid
863 //                           translator id
864 // ---------------------------------------------------------------
865 status_t
866 BTranslatorRoster::GetTranslatorInfo(
867 	translator_id forTranslator, const char **outName,
868 	const char **outInfo, int32 *outVersion)
869 {
870 	if (!outName || !outInfo || !outVersion)
871 		return B_BAD_VALUE;
872 
873 	status_t result = B_NOT_INITIALIZED;
874 
875 	if (fSem > 0 && acquire_sem(fSem) == B_OK) {
876 		// find the translator we've requested
877 		translator_node *pTranNode = FindTranslatorNode(forTranslator);
878 		if (!pTranNode)
879 			result = B_NO_TRANSLATOR;
880 		else {
881 			*outName = pTranNode->translator->TranslatorName();
882 			*outInfo = pTranNode->translator->TranslatorInfo();
883 			*outVersion = pTranNode->translator->TranslatorVersion();
884 
885 			result = B_NO_ERROR;
886 		}
887 		release_sem(fSem);
888 	}
889 
890 	return result;
891 }
892 
893 // ---------------------------------------------------------------
894 // GetInputFormats
895 //
896 // Returns all of the input formats for the translator
897 // forTranslator. Not all translators publish the input formats
898 // that they accept.
899 //
900 // Preconditions:
901 //
902 // Parameters: forTranslator, identifies which translator
903 //                            you want info for
904 //              outFormats, array of input formats
905 //              outNumFormats, number of items in outFormats
906 //
907 // Postconditions:
908 //
909 // Returns: B_NO_ERROR, if successful
910 //          B_BAD_VALUE, if either pointer is NULL
911 //          B_NOT_INITIALIZED, if the constructor couldn't
912 //                             create a semaphore
913 //          B_NO_TRANSLATOR, if forTranslator is a bad id
914 // ---------------------------------------------------------------
915 status_t
916 BTranslatorRoster::GetInputFormats(translator_id forTranslator,
917 	const translation_format **outFormats, int32 *outNumFormats)
918 {
919 	if (!outFormats || !outNumFormats)
920 		return B_BAD_VALUE;
921 
922 	status_t result = B_NOT_INITIALIZED;
923 
924 	*outFormats = NULL;
925 	*outNumFormats = 0;
926 
927 	if (fSem > 0 && acquire_sem(fSem) == B_OK) {
928 		//	find the translator we've requested
929 		translator_node *pTranNode = FindTranslatorNode(forTranslator);
930 		if (!pTranNode)
931 			result = B_NO_TRANSLATOR;
932 		else {
933 			*outFormats = pTranNode->translator->InputFormats(outNumFormats);
934 			result = B_NO_ERROR;
935 		}
936 		release_sem(fSem);
937 	}
938 
939 	return result;
940 }
941 
942 // ---------------------------------------------------------------
943 // GetOutputFormats
944 //
945 // Returns all of the output formats for the translator
946 // forTranslator. Not all translators publish the output formats
947 // that they accept.
948 //
949 // Preconditions:
950 //
951 // Parameters: forTranslator, identifies which translator
952 //                            you want info for
953 //              outFormats, array of output formats
954 //              outNumFormats, number of items in outFormats
955 //
956 // Postconditions:
957 //
958 // Returns: B_NO_ERROR, if successful
959 //          B_BAD_VALUE, if either pointer is NULL
960 //          B_NOT_INITIALIZED, if the constructor couldn't
961 //                             create a semaphore
962 //          B_NO_TRANSLATOR, if forTranslator is a bad id
963 // ---------------------------------------------------------------
964 status_t
965 BTranslatorRoster::GetOutputFormats(translator_id forTranslator,
966 	const translation_format **outFormats, int32 *outNumFormats)
967 {
968 	if (!outFormats || !outNumFormats)
969 		return B_BAD_VALUE;
970 
971 	status_t result = B_NOT_INITIALIZED;
972 
973 	*outFormats = NULL;
974 	*outNumFormats = 0;
975 
976 	if (fSem > 0 && acquire_sem(fSem) == B_OK) {
977 		// find the translator we've requested
978 		translator_node *pTranNode = FindTranslatorNode(forTranslator);
979 		if (!pTranNode)
980 			result = B_NO_TRANSLATOR;
981 		else {
982 			*outFormats = pTranNode->translator->OutputFormats(outNumFormats);
983 			result = B_NO_ERROR;
984 		}
985 		release_sem(fSem);
986 	}
987 
988 	return result;
989 }
990 
991 // ---------------------------------------------------------------
992 // Translate
993 //
994 // This function is the whole point of the Translation Kit.
995 // This is for translating the data in inSource to outDestination
996 // using the format inWantOutType.
997 //
998 // Preconditions:
999 //
1000 // Parameters: inSource, the data that wants to be translated
1001 //             ioExtension, configuration data for the translator
1002 //             inInfo, identifies the translator to use, can be
1003 //                     NULL, calls Identify() if NULL
1004 //             inHintType, hint for the type of data in
1005 //                         inSource, can be zero if the
1006 //                         type is not known
1007 //             inHintMIME, hint MIME type of the data
1008 //                         in inSource, can be NULL if
1009 //                         the MIME type is not known
1010 //             inWantOutType, the desired output type for
1011 //                            the data in inSource.
1012 //             outDestination,  where inSource is translated to
1013 //
1014 // Postconditions:
1015 //
1016 // Returns: B_OK, translation successful,
1017 //          B_NO_TRANSLATOR, no appropriate translator found
1018 //          B_NOT_INITIALIZED, the constructor failed to
1019 //                             create a semaphore
1020 //          B_BAD_VALUE, inSource or outDestination is NULL
1021 //          other values, error using inSource
1022 // ---------------------------------------------------------------
1023 status_t
1024 BTranslatorRoster::Translate(BPositionIO *inSource,
1025 	const translator_info *inInfo, BMessage *ioExtension,
1026 	BPositionIO *outDestination, uint32 inWantOutType,
1027 	uint32 inHintType, const char *inHintMIME)
1028 {
1029 	if (!inSource || !outDestination)
1030 		return B_BAD_VALUE;
1031 
1032 	if (fSem <= 0)
1033 		return B_NOT_INITIALIZED;
1034 
1035 	status_t result = B_OK;
1036 	translator_info stat_info;
1037 
1038 	if (!inInfo) {
1039 		//	go look for a suitable translator
1040 		inInfo = &stat_info;
1041 
1042 		result = Identify(inSource, ioExtension, &stat_info,
1043 				inHintType, inHintMIME, inWantOutType);
1044 			// Identify is a locked function, so it cannot be
1045 			// called from code that is already locked
1046 	}
1047 
1048 	if (result >= B_OK && acquire_sem(fSem) == B_OK) {
1049 		translator_node *pTranNode = FindTranslatorNode(inInfo->translator);
1050 		if (!pTranNode) {
1051 			result = B_NO_TRANSLATOR;
1052 		}
1053 		else {
1054 			result = inSource->Seek(0, SEEK_SET);
1055 			if (result == B_OK)
1056 				result = pTranNode->translator->Translate(inSource, inInfo,
1057 					ioExtension, inWantOutType, outDestination);
1058 		}
1059 		release_sem(fSem);
1060 	}
1061 
1062 	return result;
1063 }
1064 
1065 // ---------------------------------------------------------------
1066 // Translate
1067 //
1068 // This function is the whole point of the Translation Kit.
1069 // This is for translating the data in inSource to outDestination
1070 // using the format inWantOutType.
1071 //
1072 // Preconditions:
1073 //
1074 // Parameters: inSource, the data that wants to be translated
1075 //             ioExtension, configuration data for the translator
1076 //             inTranslator, the translator to use for the
1077 //                           translation
1078 //             inWantOutType, the desired output type for
1079 //                            the data in inSource.
1080 //             outDestination,  where inSource is translated to
1081 //
1082 // Postconditions:
1083 //
1084 // Returns: B_OK, translation successful,
1085 //          B_NO_TRANSLATOR, inTranslator is an invalid id
1086 //          B_NOT_INITIALIZED, the constructor failed to
1087 //                             create a semaphore
1088 //          B_BAD_VALUE, inSource or outDestination is NULL
1089 //          other values, error using inSource
1090 // ---------------------------------------------------------------
1091 status_t
1092 BTranslatorRoster::Translate(translator_id inTranslator,
1093 	BPositionIO *inSource, BMessage *ioExtension,
1094 	BPositionIO *outDestination, uint32 inWantOutType)
1095 {
1096 	if (!inSource || !outDestination)
1097 		return B_BAD_VALUE;
1098 
1099 	status_t result = B_NOT_INITIALIZED;
1100 
1101 	if (fSem > 0 && acquire_sem(fSem) == B_OK) {
1102 		translator_node *pTranNode = FindTranslatorNode(inTranslator);
1103 		if (!pTranNode)
1104 			result = B_NO_TRANSLATOR;
1105 		else {
1106 			result = inSource->Seek(0, SEEK_SET);
1107 			if (result == B_OK) {
1108 				translator_info traninfo;
1109 				result = pTranNode->translator->Identify(inSource, NULL,
1110 					ioExtension, &traninfo, inWantOutType);
1111 				if (result == B_OK) {
1112 					result = inSource->Seek(0, SEEK_SET);
1113 					if (result == B_OK) {
1114 						result = pTranNode->translator->Translate(inSource,
1115 							&traninfo, ioExtension, inWantOutType,
1116 							outDestination);
1117 					}
1118 				}
1119 			}
1120 		}
1121 		release_sem(fSem);
1122 	}
1123 
1124 	return result;
1125 }
1126 
1127 // ---------------------------------------------------------------
1128 // MakeConfigurationView
1129 //
1130 // Returns outView, a BView for configuring the translator
1131 // forTranslator. Not all translators support this.
1132 //
1133 // Preconditions:
1134 //
1135 // Parameters: forTranslator, the translator the view is for
1136 //             ioExtension, the configuration data for
1137 //                          the translator
1138 //             outView, the view for configuring the
1139 //                      translator
1140 //             outExtent, the bounds for the view, the view
1141 //                        can be resized
1142 //
1143 // Postconditions:
1144 //
1145 // Returns: B_OK, success,
1146 //          B_NO_TRANSLATOR, inTranslator is an invalid id
1147 //          B_NOT_INITIALIZED, the constructor failed to
1148 //                             create a semaphore
1149 //          B_BAD_VALUE, inSource or outDestination is NULL
1150 //          other values, error using inSource
1151 // ---------------------------------------------------------------
1152 status_t
1153 BTranslatorRoster::MakeConfigurationView(
1154 	translator_id forTranslator, BMessage *ioExtension,
1155 	BView **outView, BRect *outExtent)
1156 {
1157 	if (!outView || !outExtent)
1158 		return B_BAD_VALUE;
1159 
1160 	status_t result = B_NOT_INITIALIZED;
1161 
1162 	if (fSem > 0 && acquire_sem(fSem) == B_OK) {
1163 		translator_node *pTranNode = FindTranslatorNode(forTranslator);
1164 		if (!pTranNode)
1165 			result = B_NO_TRANSLATOR;
1166 		else
1167 			result = pTranNode->translator->MakeConfigurationView(ioExtension,
1168 				outView, outExtent);
1169 
1170 		release_sem(fSem);
1171 	}
1172 
1173 	return result;
1174 }
1175 
1176 // ---------------------------------------------------------------
1177 // GetConfigurationMessage
1178 //
1179 // Gets the configuration setttings for the translator
1180 // forTranslator and puts the settings into ioExtension.
1181 //
1182 // Preconditions:
1183 //
1184 // Parameters: forTranslator, the translator the info
1185 //                            is for
1186 //             ioExtension, the configuration data for
1187 //                          the translator is stored here
1188 //
1189 // Postconditions:
1190 //
1191 // Returns: B_OK, success,
1192 //          B_NO_TRANSLATOR, inTranslator is an invalid id
1193 //          B_NOT_INITIALIZED, the constructor failed to
1194 //                             create a semaphore
1195 //          B_BAD_VALUE, inSource or outDestination is NULL
1196 //          other values, error using inSource
1197 // ---------------------------------------------------------------
1198 status_t
1199 BTranslatorRoster::GetConfigurationMessage(
1200 	translator_id forTranslator, BMessage *ioExtension)
1201 {
1202 	if (!ioExtension)
1203 		return B_BAD_VALUE;
1204 
1205 	status_t result = B_NOT_INITIALIZED;
1206 
1207 	if (fSem > 0 && acquire_sem(fSem) == B_OK) {
1208 		translator_node *pTranNode = FindTranslatorNode(forTranslator);
1209 		if (!pTranNode)
1210 			result = B_NO_TRANSLATOR;
1211 		else
1212 			result =
1213 				pTranNode->translator->GetConfigurationMessage(ioExtension);
1214 
1215 		release_sem(fSem);
1216 	}
1217 
1218 	return result;
1219 }
1220 
1221 // ---------------------------------------------------------------
1222 // GetRefFor
1223 //
1224 // Gets the entry_ref for the given translator.
1225 //
1226 // Preconditions:
1227 //
1228 // Parameters: forTranslator, the translator the info
1229 //                            is for
1230 //             entry_ref, where the entry ref is stored
1231 //
1232 // Postconditions:
1233 //
1234 // Returns: B_OK, success,
1235 //          B_NO_TRANSLATOR, translator is an invalid id
1236 //          B_NOT_INITIALIZED, the constructor failed to
1237 //                             create a semaphore
1238 //          B_BAD_VALUE, inSource or outDestination is NULL
1239 //          other values, error using inSource
1240 // ---------------------------------------------------------------
1241 status_t
1242 BTranslatorRoster::GetRefFor(translator_id translator,
1243 	entry_ref *out_ref)
1244 {
1245 	if (!out_ref)
1246 		return B_BAD_VALUE;
1247 
1248 	status_t result = B_NOT_INITIALIZED;
1249 
1250 	if (fSem > 0 && acquire_sem(fSem) == B_OK) {
1251 		translator_node *pTranNode = FindTranslatorNode(translator);
1252 		if (!pTranNode)
1253 			result = B_NO_TRANSLATOR;
1254 		else {
1255 			if (pTranNode->path[0] == '\0')
1256 				result = B_ERROR;
1257 			else
1258 				result = get_ref_for_path(pTranNode->path, out_ref);
1259 		}
1260 		release_sem(fSem);
1261 	}
1262 
1263 	return result;
1264 }
1265 
1266 
1267 // ---------------------------------------------------------------
1268 // FindTranslatorNode
1269 //
1270 // Finds the translator_node that holds the translator with
1271 // the translator_id id.
1272 //
1273 // Preconditions:
1274 //
1275 // Parameters: id, the translator you want a translator_node for
1276 //
1277 // Postconditions:
1278 //
1279 // Returns: NULL if id is not a valid translator_id,
1280 //          pointer to the translator_node that holds the
1281 //          translator id
1282 // ---------------------------------------------------------------
1283 translator_node *
1284 BTranslatorRoster::FindTranslatorNode(translator_id id)
1285 {
1286 	translator_node *pTranNode = NULL;
1287 	for (pTranNode = fpTranslators; pTranNode; pTranNode = pTranNode->next)
1288 		if (pTranNode->id == id)
1289 			break;
1290 
1291 	return pTranNode;
1292 }
1293 
1294 // ---------------------------------------------------------------
1295 // LoadTranslator
1296 //
1297 // Loads the translator from path into memory and adds it to
1298 // the BTranslatorRoster.
1299 //
1300 // Preconditions: This should only be called inside of locked
1301 //                code.
1302 //
1303 // Parameters: path, the path for the translator to be loaded
1304 //
1305 // Postconditions:
1306 //
1307 // Returns: B_BAD_VALUE, if path is NULL,
1308 //          B_NO_ERROR, if all is well,
1309 //          other values if error loading add ons
1310 // ---------------------------------------------------------------
1311 status_t
1312 BTranslatorRoster::LoadTranslator(const char *path)
1313 {
1314 	if (!path)
1315 		return B_BAD_VALUE;
1316 
1317 	//	check that this ref is not already loaded
1318 	const char *name = strrchr(path, '/');
1319 	if (name)
1320 		name++;
1321 	else
1322 		name = path;
1323 	for (translator_node *i = fpTranslators; i; i = i->next)
1324 		if (!strcmp(name, i->translator->TranslatorName()))
1325 			return B_NO_ERROR;
1326 			//	we use name for determining whether it's loaded
1327 			//	that is not entirely foolproof, but making SURE will be
1328 			//	a very slow process that I don't much care for.
1329 
1330 	image_id image = load_add_on(path);
1331 		// Load the data and code for the Translator into memory
1332 	if (image < 0)
1333 		return image;
1334 
1335 	// Function pointer used to create post R4.5 style translators
1336 	BTranslator *(*pMakeNthTranslator)(int32 n, image_id you, uint32 flags, ...);
1337 
1338 	status_t err = get_image_symbol(image, "make_nth_translator",
1339 		B_SYMBOL_TYPE_TEXT, reinterpret_cast<void **> (&pMakeNthTranslator));
1340 	if (!err) {
1341 		// If the translator add-on supports the post R4.5
1342 		// translator creation mechanism
1343 
1344 		BTranslator *ptran = NULL;
1345 		// WARNING: This code assumes that the ref count on the
1346 		// BTranslators from MakeNth... begin at 1!!!
1347 		// I NEED TO WRITE CODE TO TEST WHAT THE REF COUNT FOR
1348 		// THESE BTRANSLATORS START AS!!!!
1349 		for (int32 n = 0; (ptran = pMakeNthTranslator(n, image, 0)); n++)
1350 			AddTranslatorToList(ptran, path, image, false);
1351 
1352 		return B_NO_ERROR;
1353 
1354 	} else {
1355 		// If the translator add-on is in the R4.0 / R4.5 format
1356 		translator_data trand;
1357 		trand.translatorName = NULL;
1358 		trand.translatorInfo = NULL;
1359 		trand.translatorVersion = 0;
1360 		trand.inputFormats = NULL;
1361 		trand.outputFormats = NULL;
1362 		trand.Identify = NULL;
1363 		trand.Translate = NULL;
1364 		trand.MakeConfig = NULL;
1365 		trand.GetConfigMessage = NULL;
1366 
1367 		char *name = NULL, *info = NULL;
1368 		translation_format *ins = NULL, *outs = NULL;
1369 
1370 		//	find all the symbols
1371 		err = get_image_symbol(image, "translatorName", B_SYMBOL_TYPE_DATA,
1372 			reinterpret_cast<void **> (&name));
1373 		if (err)
1374 			name = NULL;
1375 		else if (!err && get_image_symbol(image, "translatorInfo",
1376 			B_SYMBOL_TYPE_DATA, reinterpret_cast<void **> (&info)))
1377 			info = NULL;
1378 
1379 		int32 *pn = NULL;
1380 		if (!err) {
1381 			err = get_image_symbol(image, "translatorVersion",
1382 				B_SYMBOL_TYPE_DATA, reinterpret_cast<void **> (&pn));
1383 			if (!err && (pn != NULL))
1384 				trand.translatorVersion = *pn;
1385 		}
1386 
1387 		if (!err && get_image_symbol(image, "inputFormats",
1388 			B_SYMBOL_TYPE_DATA,
1389 			reinterpret_cast<void **> (&ins)))
1390 			ins = NULL;
1391 
1392 		if (!err && get_image_symbol(image, "outputFormats",
1393 			B_SYMBOL_TYPE_DATA,
1394 			reinterpret_cast<void **> (&outs)))
1395 			outs = NULL;
1396 
1397 		if (!err)
1398 			err = get_image_symbol(image, "Identify",
1399 				B_SYMBOL_TYPE_TEXT,
1400 				reinterpret_cast<void **> (&trand.Identify));
1401 
1402 		if (!err)
1403 			err = get_image_symbol(image, "Translate",
1404 				B_SYMBOL_TYPE_TEXT,
1405 				reinterpret_cast<void **> (&trand.Translate));
1406 
1407 		if (!err && get_image_symbol(image, "MakeConfig",
1408 			B_SYMBOL_TYPE_TEXT,
1409 			reinterpret_cast<void **> (&trand.MakeConfig)))
1410 			trand.MakeConfig = NULL;
1411 
1412 		if (!err && get_image_symbol(image, "GetConfigMessage",
1413 			B_SYMBOL_TYPE_TEXT,
1414 			reinterpret_cast<void **> (&trand.GetConfigMessage)))
1415 			trand.GetConfigMessage = NULL;
1416 
1417 		trand.translatorName = name;
1418 		trand.translatorInfo = info;
1419 		trand.inputFormats = ins;
1420 		trand.outputFormats = outs;
1421 
1422 		// if add-on is not in the correct format, return with error
1423 		if (err)
1424 			return err;
1425 
1426 		// add this translator to the list
1427 		BR4xTranslator *pR4xTran = new BR4xTranslator(&trand);
1428 		AddTranslatorToList(pR4xTran, path, image, false);
1429 			// do not call Acquire() on ptran because I want it to be
1430 			// deleted the first time Release() is called on it.
1431 
1432 		return B_NO_ERROR;
1433 	}
1434 }
1435 
1436 // ---------------------------------------------------------------
1437 // LoadDir
1438 //
1439 // Loads all of the translators in the directory path
1440 //
1441 // Preconditions: should only be called inside locked code
1442 //
1443 // Parameters: path, the directory of translators to load
1444 //             loadErr, the return code
1445 //             nLoaded, number of translators loaded
1446 //
1447 // Postconditions:
1448 //
1449 // Returns: B_FILE_NOT_FOUND, if the path is NULL or invalid
1450 //          other errors if LoadTranslator failed
1451 // ---------------------------------------------------------------
1452 void
1453 BTranslatorRoster::LoadDir(const char *path, int32 &loadErr, int32 &nLoaded)
1454 {
1455 	if (!path) {
1456 		loadErr = B_FILE_NOT_FOUND;
1457 		return;
1458 	}
1459 
1460 	loadErr = B_OK;
1461 	DIR *dir = opendir(path);
1462 	if (!dir) {
1463 		loadErr = B_FILE_NOT_FOUND;
1464 		return;
1465 	}
1466 	struct dirent *dent;
1467 	struct stat stbuf;
1468 	char cwd[PATH_MAX] = "";
1469 	while (NULL != (dent = readdir(dir))) {
1470 		strcpy(cwd, path);
1471 		strcat(cwd, "/");
1472 		strcat(cwd, dent->d_name);
1473 		status_t err = stat(cwd, &stbuf);
1474 
1475 		if (!err && S_ISREG(stbuf.st_mode) &&
1476 			strcmp(dent->d_name, ".") && strcmp(dent->d_name, "..")) {
1477 
1478 			err = LoadTranslator(cwd);
1479 			if (err == B_OK)
1480 				nLoaded++;
1481 			else
1482 				loadErr = err;
1483 		}
1484 	}
1485 	closedir(dir);
1486 }
1487 
1488 // ---------------------------------------------------------------
1489 // CheckFormats
1490 //
1491 // Function used to determine if hintType and hintMIME can be
1492 // used to find the desired translation_format.
1493 //
1494 // Preconditions: Should only be called from inside locked code
1495 //
1496 // Parameters: inputFormats, the formats check against the hints
1497 //             inputFormatsCount, number of items in inputFormats
1498 //             hintType, the type this function is looking for
1499 //             hintMIME, the MIME type this function is looking
1500 //                       for
1501 //             outFormat, NULL if no suitable translation_format
1502 //                        from inputFormats was found, not NULL
1503 //                        if a translation_format matching the
1504 //                        hints was found
1505 //
1506 //
1507 // Postconditions:
1508 //
1509 // Returns: true, if a determination could be made
1510 //          false, if indentification must be done
1511 // ---------------------------------------------------------------
1512 bool
1513 BTranslatorRoster::CheckFormats(const translation_format *inputFormats,
1514 	int32 inputFormatsCount, uint32 hintType, const char *hintMIME,
1515 	const translation_format **outFormat)
1516 {
1517 	if (!inputFormats || inputFormatsCount <= 0 || !outFormat)
1518 		return false;
1519 
1520 	*outFormat = NULL;
1521 
1522 	// return false if we can't use hints for this module
1523 	if (!hintType && !hintMIME)
1524 		return false;
1525 
1526 	// check for the length of the MIME string, since it may be just a prefix
1527 	// so we use strncmp().
1528 	int mlen = 0;
1529 	if (hintMIME)
1530 		mlen = strlen(hintMIME);
1531 
1532 	// scan for suitable format
1533 	const translation_format *fmt = inputFormats;
1534 	for (int32 i = 0; i < inputFormatsCount && fmt->type; i++, fmt++) {
1535 		if ((fmt->type == hintType) ||
1536 			(hintMIME && mlen && !strncmp(fmt->MIME, hintMIME, mlen))) {
1537 			*outFormat = fmt;
1538 			return true;
1539 		}
1540 	}
1541 	// the module did export formats, but none matched.
1542 	// we return true (uses formats) but set outFormat to NULL
1543 	return true;
1544 }
1545 
1546 // ---------------------------------------------------------------
1547 // AddTranslatorToList
1548 //
1549 // Adds a BTranslator based object to the list of translators
1550 // stored by the BTranslatorRoster.
1551 //
1552 // Preconditions: Should only be called inside locked code
1553 //
1554 // Parameters: translator, the translator to add to this object
1555 //
1556 // Postconditions:
1557 //
1558 // Returns: B_BAD_VALUE, if translator is NULL
1559 //          B_OK, if not
1560 // ---------------------------------------------------------------
1561 status_t
1562 BTranslatorRoster::AddTranslatorToList(BTranslator *translator)
1563 {
1564 	return AddTranslatorToList(translator, "", -1, true);
1565 		// add translator to list with no add-on image to unload,
1566 		// and call Acquire() on it
1567 }
1568 
1569 // ---------------------------------------------------------------
1570 // AddTranslatorToList
1571 //
1572 // Adds a BTranslator based object to the list of translators
1573 // stored by the BTranslatorRoster.
1574 //
1575 // Preconditions: Should only be called inside locked code
1576 //
1577 // Parameters: translator, the translator to add to this object
1578 //             path, the path the translator was loaded from
1579 //             image, the image the translator was loaded from
1580 //             acquire, if true Acquire() is called on the
1581 //                      translator
1582 //
1583 // Postconditions:
1584 //
1585 // Returns: B_BAD_VALUE, if translator is NULL
1586 //          B_OK, if not
1587 // ---------------------------------------------------------------
1588 status_t
1589 BTranslatorRoster::AddTranslatorToList(BTranslator *translator,
1590 	const char *path, image_id image, bool acquire)
1591 {
1592 	if (!translator || !path)
1593 		return B_BAD_VALUE;
1594 
1595 	translator_node *pTranNode = new translator_node;
1596 
1597 	if (acquire)
1598 		pTranNode->translator = translator->Acquire();
1599 	else
1600 		pTranNode->translator = translator;
1601 
1602 	if (fpTranslators)
1603 		pTranNode->id = fpTranslators->id + 1;
1604 	else
1605 		pTranNode->id = 1;
1606 
1607 	pTranNode->path = new char[strlen(path) + 1];
1608 	strcpy(pTranNode->path, path);
1609 	pTranNode->image = image;
1610 	pTranNode->next = fpTranslators;
1611 	fpTranslators = pTranNode;
1612 
1613 	return B_OK;
1614 }
1615 
1616 // ---------------------------------------------------------------
1617 // ReservedTranslatorRoster1
1618 //
1619 // It does nothing! :) Its here only for past/future binary
1620 // compatibility.
1621 //
1622 // Preconditions:
1623 //
1624 // Parameters:
1625 //
1626 // Postconditions:
1627 //
1628 // Returns:
1629 // ---------------------------------------------------------------
1630 void
1631 BTranslatorRoster::ReservedTranslatorRoster1()
1632 {
1633 }
1634 
1635 // ---------------------------------------------------------------
1636 // ReservedTranslatorRoster2
1637 //
1638 // It does nothing! :) Its here only for past/future binary
1639 // compatibility.
1640 //
1641 // Preconditions:
1642 //
1643 // Parameters:
1644 //
1645 // Postconditions:
1646 //
1647 // Returns:
1648 // ---------------------------------------------------------------
1649 void
1650 BTranslatorRoster::ReservedTranslatorRoster2()
1651 {
1652 }
1653 
1654 // ---------------------------------------------------------------
1655 // ReservedTranslatorRoster3
1656 //
1657 // It does nothing! :) Its here only for past/future binary
1658 // compatibility.
1659 //
1660 // Preconditions:
1661 //
1662 // Parameters:
1663 //
1664 // Postconditions:
1665 //
1666 // Returns:
1667 // ---------------------------------------------------------------
1668 void
1669 BTranslatorRoster::ReservedTranslatorRoster3()
1670 {
1671 }
1672 
1673 // ---------------------------------------------------------------
1674 // ReservedTranslatorRoster4
1675 //
1676 // It does nothing! :) Its here only for past/future binary
1677 // compatibility.
1678 //
1679 // Preconditions:
1680 //
1681 // Parameters:
1682 //
1683 // Postconditions:
1684 //
1685 // Returns:
1686 // ---------------------------------------------------------------
1687 void
1688 BTranslatorRoster::ReservedTranslatorRoster4()
1689 {
1690 }
1691 
1692 // ---------------------------------------------------------------
1693 // ReservedTranslatorRoster5
1694 //
1695 // It does nothing! :) Its here only for past/future binary
1696 // compatibility.
1697 //
1698 // Preconditions:
1699 //
1700 // Parameters:
1701 //
1702 // Postconditions:
1703 //
1704 // Returns:
1705 // ---------------------------------------------------------------
1706 void
1707 BTranslatorRoster::ReservedTranslatorRoster5()
1708 {
1709 }
1710 
1711 // ---------------------------------------------------------------
1712 // ReservedTranslatorRoster6
1713 //
1714 // It does nothing! :) Its here only for past/future binary
1715 // compatibility.
1716 //
1717 // Preconditions:
1718 //
1719 // Parameters:
1720 //
1721 // Postconditions:
1722 //
1723 // Returns:
1724 // ---------------------------------------------------------------
1725 void
1726 BTranslatorRoster::ReservedTranslatorRoster6()
1727 {
1728 }
1729 
1730