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