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