xref: /haiku/src/kits/media/MediaAddOn.cpp (revision 610f99c838cb661ff85377789ffd3ad4ff672a08)
1 /*
2  * Copyright (c) 2002, 2003, 2008 Marcus Overhagen <Marcus@Overhagen.de>
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining
5  * a copy of this software and associated documentation files or portions
6  * thereof (the "Software"), to deal in the Software without restriction,
7  * including without limitation the rights to use, copy, modify, merge,
8  * publish, distribute, sublicense, and/or sell copies of the Software,
9  * and to permit persons to whom the Software is furnished to do so, subject
10  * to the following conditions:
11  *
12  *  * Redistributions of source code must retain the above copyright notice,
13  *    this list of conditions and the following disclaimer.
14  *
15  *  * Redistributions in binary form must reproduce the above copyright notice
16  *    in the  binary, as well as this list of conditions and the following
17  *    disclaimer in the documentation and/or other materials provided with
18  *    the distribution.
19  *
20  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26  * THE SOFTWARE.
27  *
28  */
29 
30 
31 #include <MediaAddOn.h>
32 #include <string.h>
33 #include <stdlib.h>
34 #include <new>
35 #include "MediaDebug.h"
36 #include "DataExchange.h"
37 
38 
39 #define MAX_FLAVOR_IN_FORMAT_COUNT	300
40 #define MAX_FLAVOR_OUT_FORMAT_COUNT	300
41 
42 #define FLATTEN_MAGIC 		'CODE'
43 #define FLATTEN_TYPECODE	'DFIT'
44 
45 
46 static char *
47 _newstrdup(const char *str)
48 {
49 	if (str == NULL)
50 		return NULL;
51 	int len = strlen(str) + 1;
52 	char *p = new(std::nothrow) char[len];
53 	if (p)
54 		memcpy(p, str, len);
55 	return p;
56 }
57 
58 
59 // #pragma mark - dormant_node_info
60 
61 
62 dormant_node_info::dormant_node_info()
63 	:
64 	addon(-1),
65 	flavor_id(-1)
66 {
67 	name[0] = '\0';
68 }
69 
70 
71 dormant_node_info::~dormant_node_info()
72 {
73 }
74 
75 
76 // #pragma mark - flavor_info
77 
78 
79 /* DO NOT IMPLEMENT */
80 /*
81 flavor_info &flavor_info::operator=(const flavor_info &other)
82 */
83 
84 
85 // #pragma mark - dormant_flavor_info
86 
87 
88 dormant_flavor_info::dormant_flavor_info()
89 {
90 	name = NULL;
91 	info = NULL;
92 	kinds = 0;
93 	flavor_flags = 0;
94 	internal_id = 0;
95 	possible_count = 0;
96 	in_format_count = 0;
97 	in_format_flags = 0;
98 	in_formats = NULL;
99 	out_format_count = 0;
100 	out_format_flags = 0;
101 	out_formats = NULL;
102 }
103 
104 
105 dormant_flavor_info::~dormant_flavor_info()
106 {
107 	delete[] name;
108 	delete[] info;
109 	delete[] in_formats;
110 	delete[] out_formats;
111 }
112 
113 
114 dormant_flavor_info::dormant_flavor_info(const dormant_flavor_info &clone)
115 {
116 	name = NULL;
117 	info = NULL;
118 	in_formats = NULL;
119 	out_formats = NULL;
120 
121 	*this = clone;
122 }
123 
124 
125 dormant_flavor_info &
126 dormant_flavor_info::operator=(const dormant_flavor_info &clone)
127 {
128 	// call operator=(const flavor_info &clone) to copy the flavor_info base class
129 	*this = static_cast<const flavor_info>(clone);
130 	// copy the dormant_node_info member variable
131 	node_info = clone.node_info;
132 	return *this;
133 }
134 
135 
136 dormant_flavor_info &
137 dormant_flavor_info::operator=(const flavor_info &clone)
138 {
139 	kinds = clone.kinds;
140 	flavor_flags = clone.flavor_flags;
141 	internal_id = clone.internal_id;
142 	possible_count = clone.possible_count;
143 
144 	delete [] info;
145 	info = _newstrdup(clone.info);
146 
147 	delete [] name;
148 	name = _newstrdup(clone.name);
149 
150 	delete [] in_formats;
151 	in_formats = NULL;
152 	in_format_count = 0;
153 	in_format_flags = clone.in_format_flags;
154 	if ((kinds & B_BUFFER_CONSUMER) != 0) {
155 		if (clone.in_format_count >= 0
156 			&& clone.in_format_count <= MAX_FLAVOR_IN_FORMAT_COUNT) {
157 			in_formats = new(std::nothrow) media_format[clone.in_format_count];
158 			if (in_formats != NULL && clone.in_formats != NULL) {
159 				in_format_count = clone.in_format_count;
160 				for (int i = 0; i < in_format_count; i++) {
161 					const_cast<media_format &>(in_formats[i])
162 						= clone.in_formats[i];
163 				}
164 			}
165 		} else {
166 			fprintf(stderr, "error: dormant_flavor_info::operator= clone.in_"
167 				"format_count is invalid\n");
168 		}
169 	} else if (clone.in_format_count) {
170 		fprintf(stderr, "warning: dormant_flavor_info::operator= not "
171 			"B_BUFFER_CONSUMER and clone.in_format_count is != 0\n");
172 	}
173 
174 	delete [] out_formats;
175 	out_formats = NULL;
176 	out_format_count = 0;
177 	out_format_flags = clone.out_format_flags;
178 	if (kinds & B_BUFFER_PRODUCER) {
179 		if (clone.out_format_count >= 0
180 			&& clone.out_format_count <= MAX_FLAVOR_OUT_FORMAT_COUNT) {
181 			out_formats = new(std::nothrow) media_format[clone.out_format_count];
182 			if (out_formats != NULL && clone.out_formats != NULL) {
183 				out_format_count = clone.out_format_count;
184 				for (int i = 0; i < out_format_count; i++) {
185 					const_cast<media_format &>(out_formats[i])
186 						= clone.out_formats[i];
187 				}
188 			}
189 		} else {
190 			fprintf(stderr, "error dormant_flavor_info::operator= clone.out_"
191 				"format_count is invalid\n");
192 		}
193 	} else if (clone.out_format_count) {
194 		fprintf(stderr, "warning: dormant_flavor_info::operator= not "
195 			"B_BUFFER_PRODUCER and clone.out_format_count is != 0\n");
196 	}
197 
198 	// initialize node_info with default values
199 	dormant_node_info defaultValues;
200 	node_info = defaultValues;
201 
202 	return *this;
203 }
204 
205 
206 void
207 dormant_flavor_info::set_name(const char *newName)
208 {
209 	delete[] name;
210 	name = _newstrdup(newName);
211 }
212 
213 
214 void
215 dormant_flavor_info::set_info(const char *newInfo)
216 {
217 	delete[] info;
218 	info = _newstrdup(newInfo);
219 }
220 
221 
222 void
223 dormant_flavor_info::add_in_format(const media_format &in_format)
224 {
225 	media_format *p = new(std::nothrow) media_format[in_format_count + 1];
226 	if (p) {
227 		for (int i = 0; i < in_format_count; i++)
228 			p[i] = in_formats[i];
229 		p[in_format_count] = in_format;
230 		delete [] in_formats;
231 		in_formats = p;
232 		in_format_count += 1;
233 	}
234 }
235 
236 
237 void
238 dormant_flavor_info::add_out_format(const media_format &out_format)
239 {
240 	media_format *p = new(std::nothrow) media_format[out_format_count + 1];
241 	if (p) {
242 		for (int i = 0; i < out_format_count; i++)
243 			p[i] = out_formats[i];
244 		p[out_format_count] = out_format;
245 		delete [] out_formats;
246 		out_formats = p;
247 		out_format_count += 1;
248 	}
249 }
250 
251 
252 bool
253 dormant_flavor_info::IsFixedSize() const
254 {
255 	return false;
256 }
257 
258 
259 type_code
260 dormant_flavor_info::TypeCode() const
261 {
262 	return FLATTEN_TYPECODE;
263 }
264 
265 
266 ssize_t
267 dormant_flavor_info::FlattenedSize() const
268 {
269 	ssize_t size = 0;
270 	// magic
271 	size += sizeof(int32);
272 	// size
273 	size += sizeof(int32);
274 	// struct flavor_info
275 	size += sizeof(int32) + strlen(name);
276 	size += sizeof(int32) + strlen(info);
277 	size += sizeof(kinds);
278 	size += sizeof(flavor_flags);
279 	size += sizeof(internal_id);
280 	size += sizeof(possible_count);
281 	size += sizeof(in_format_count);
282 	size += sizeof(in_format_flags);
283 	if (in_format_count > 0 && in_format_count <= MAX_FLAVOR_IN_FORMAT_COUNT
284 		&& in_formats != NULL)
285 		size += in_format_count * sizeof(media_format);
286 	size += sizeof(out_format_count);
287 	size += sizeof(out_format_flags);
288 	if (out_format_count > 0 && out_format_count <= MAX_FLAVOR_OUT_FORMAT_COUNT
289 		&& out_formats != NULL)
290 		size += out_format_count * sizeof(media_format);
291 	// struct dormant_node_info	node_info
292 	size += sizeof(node_info);
293 
294 	return size;
295 }
296 
297 
298 status_t
299 dormant_flavor_info::Flatten(void *buffer, ssize_t size) const
300 {
301 	if (size < FlattenedSize())
302 		return B_ERROR;
303 
304 	char *buf = (char *)buffer;
305 	int32 nameLength = name ? (int32)strlen(name) : -1;
306 	int32 infoLength = info ? (int32)strlen(info) : -1;
307 	int32 inFormatCount = 0;
308 	size_t inFormatSize = 0;
309 	int32 outFormatCount = 0;
310 	size_t outFormatSize = 0;
311 
312 	if ((kinds & B_BUFFER_CONSUMER) != 0 && in_format_count > 0
313 		&& in_formats != NULL) {
314 		if (in_format_count <= MAX_FLAVOR_IN_FORMAT_COUNT) {
315 			inFormatCount = in_format_count;
316 			inFormatSize = in_format_count * sizeof(media_format);
317 		} else {
318 			fprintf(stderr, "error dormant_flavor_info::Flatten: "
319 				"in_format_count is too large\n");
320 			return B_ERROR;
321 		}
322 	}
323 
324 	if ((kinds & B_BUFFER_PRODUCER) != 0 && out_format_count > 0
325 		&& out_formats != NULL) {
326 		if (out_format_count <= MAX_FLAVOR_OUT_FORMAT_COUNT) {
327 			outFormatCount = out_format_count;
328 			outFormatSize = out_format_count * sizeof(media_format);
329 		} else {
330 			fprintf(stderr, "error dormant_flavor_info::Flatten: "
331 				"out_format_count is too large\n");
332 			return B_ERROR;
333 		}
334 	}
335 
336 	// magic
337 	*(int32*)buf = FLATTEN_MAGIC; buf += sizeof(int32);
338 
339 	// size
340 	*(int32*)buf = FlattenedSize(); buf += sizeof(int32);
341 
342 	// struct flavor_info
343 	*(int32*)buf = nameLength; buf += sizeof(int32);
344 	if (nameLength > 0) {
345 		memcpy(buf, name, nameLength);
346 		buf += nameLength;
347 	}
348 	*(int32*)buf = infoLength; buf += sizeof(int32);
349 	if (infoLength > 0) {
350 		memcpy(buf, info, infoLength);
351 		buf += infoLength;
352 	}
353 
354 	*(uint64*)buf = kinds; buf += sizeof(uint64);
355 	*(uint32*)buf = flavor_flags; buf += sizeof(uint32);
356 	*(int32*)buf = internal_id; buf += sizeof(int32);
357 	*(int32*)buf = possible_count; buf += sizeof(int32);
358 	*(int32*)buf = inFormatCount; buf += sizeof(int32);
359 	*(uint32*)buf = in_format_flags; buf += sizeof(uint32);
360 
361 	// XXX FIXME! we should not!!! make flat copies	of media_format
362 	memcpy(buf, in_formats, inFormatSize); buf += inFormatSize;
363 
364 	*(int32*)buf = outFormatCount; buf += sizeof(int32);
365 	*(uint32*)buf = out_format_flags; buf += sizeof(uint32);
366 
367 	// XXX FIXME! we should not!!! make flat copies	of media_format
368 	memcpy(buf, out_formats, outFormatSize); buf += outFormatSize;
369 
370 	*(dormant_node_info*)buf = node_info; buf += sizeof(dormant_node_info);
371 
372 	return B_OK;
373 }
374 
375 
376 status_t
377 dormant_flavor_info::Unflatten(type_code c, const void *buffer, ssize_t size)
378 {
379 	if (c != FLATTEN_TYPECODE)
380 		return B_ERROR;
381 	if (size < 8)
382 		return B_ERROR;
383 
384 	const char *buf = (const char *)buffer;
385 	int32 nameLength;
386 	int32 infoLength;
387 
388 	// check magic
389 	if (*(int32*)buf != FLATTEN_MAGIC)
390 		return B_ERROR;
391 	buf += sizeof(int32);
392 
393 	// check size
394 	if (*(uint32*)buf > (uint32)size)
395 		return B_ERROR;
396 	buf += sizeof(int32);
397 
398 	delete[] name;
399 	name = NULL;
400 	delete[] info;
401 	info = NULL;
402 	delete[] in_formats;
403 	in_formats = NULL;
404 	in_format_count = 0;
405 	delete[] out_formats;
406 	out_formats = NULL;
407 	out_format_count = 0;
408 
409 	// struct flavor_info
410 	nameLength = *(int32*)buf; buf += sizeof(int32);
411 	if (nameLength >= 0) { // if nameLength is -1, we leave name = 0
412 		char* nameStorage = new(std::nothrow) char [nameLength + 1];
413 		name = nameStorage;
414 		if (nameStorage) {
415 			memcpy(nameStorage, buf, nameLength);
416 			nameStorage[nameLength] = 0;
417 			buf += nameLength; // XXX not save
418 		}
419 	}
420 
421 	infoLength = *(int32*)buf; buf += sizeof(int32);
422 	if (infoLength >= 0) { // if infoLength is -1, we leave info = 0
423 		char* infoStorage = new(std::nothrow) char [infoLength + 1];
424 		info = infoStorage;
425 		if (infoStorage) {
426 			memcpy(infoStorage, buf, infoLength);
427 			infoStorage[infoLength] = 0;
428 			buf += infoLength; // XXX not save
429 		}
430 	}
431 
432 	int32 count;
433 
434 	kinds = *(uint64*)buf; buf += sizeof(uint64);
435 	flavor_flags = *(uint32*)buf; buf += sizeof(uint32);
436 	internal_id = *(int32*)buf; buf += sizeof(int32);
437 	possible_count = *(int32*)buf; buf += sizeof(int32);
438 	count = *(int32*)buf; buf += sizeof(int32);
439 	in_format_flags = *(uint32*)buf; buf += sizeof(uint32);
440 
441 	if (count > 0) {
442 		if (count <= MAX_FLAVOR_IN_FORMAT_COUNT) {
443 			in_formats = new(std::nothrow) media_format[count];
444 			if (!in_formats)
445 				return B_NO_MEMORY;
446 			// TODO: we should not!!! make flat copies of media_format
447 			for (int32 i = 0; i < count; i++) {
448 				const_cast<media_format*>
449 					(&in_formats[i])->Unflatten(buf);
450 				buf += sizeof(media_format); // TODO: not save
451 			}
452 			in_format_count = count;
453 		}
454 	}
455 
456 	count = *(int32*)buf; buf += sizeof(int32);
457 	out_format_flags = *(uint32*)buf; buf += sizeof(uint32);
458 
459 	if (count > 0) {
460 		if (count <= MAX_FLAVOR_OUT_FORMAT_COUNT) {
461 			out_formats = new(std::nothrow) media_format[count];
462 			if (!out_formats)
463 				return B_NO_MEMORY;
464 			// TODO: we should not!!! make flat copies of media_format
465 			for (int32 i = 0; i < count; i++) {
466 				const_cast<media_format*>
467 					(&out_formats[i])->Unflatten(buf);
468 				buf += sizeof(media_format); // TODO: not save
469 			}
470 			out_format_count = count;
471 		}
472 	}
473 
474 	node_info = *(dormant_node_info*)buf; buf += sizeof(dormant_node_info);
475 
476 	return B_OK;
477 }
478 
479 
480 // #pragma mark - BMediaAddOn
481 
482 
483 BMediaAddOn::BMediaAddOn(image_id image)
484 	:
485 	fImage(image),
486 	fAddon(0)
487 {
488 	CALLED();
489 }
490 
491 
492 BMediaAddOn::~BMediaAddOn()
493 {
494 	CALLED();
495 }
496 
497 
498 status_t
499 BMediaAddOn::InitCheck(const char **_failureText)
500 {
501 	CALLED();
502 	// only to be implemented by derived classes
503 	*_failureText = "no error";
504 	return B_OK;
505 }
506 
507 
508 int32
509 BMediaAddOn::CountFlavors()
510 {
511 	CALLED();
512 	// only to be implemented by derived classes
513 	return 0;
514 }
515 
516 
517 status_t
518 BMediaAddOn::GetFlavorAt(int32 n, const flavor_info **_info)
519 {
520 	CALLED();
521 	// only to be implemented by derived classes
522 	return B_ERROR;
523 }
524 
525 
526 BMediaNode*
527 BMediaAddOn::InstantiateNodeFor(const flavor_info *info, BMessage *config,
528 	status_t *_error)
529 {
530 	CALLED();
531 	// only to be implemented by derived classes
532 	return NULL;
533 }
534 
535 
536 status_t
537 BMediaAddOn::GetConfigurationFor(BMediaNode *node, BMessage *toMessage)
538 {
539 	CALLED();
540 	// only to be implemented by derived classes
541 	return B_ERROR;
542 }
543 
544 
545 bool
546 BMediaAddOn::WantsAutoStart()
547 {
548 	CALLED();
549 	// only to be implemented by derived classes
550 	return false;
551 }
552 
553 
554 status_t
555 BMediaAddOn::AutoStart(int count, BMediaNode **_node, int32 *_internalID,
556 	bool *_hasMore)
557 {
558 	CALLED();
559 	// only to be implemented by derived classes
560 	return B_ERROR;
561 }
562 
563 
564 status_t
565 BMediaAddOn::SniffRef(const entry_ref &file, BMimeType *mimeType,
566 	float *_quality, int32 *_internalID)
567 {
568 	CALLED();
569 	// only to be implemented by BFileInterface derived classes
570 	return B_ERROR;
571 }
572 
573 
574 status_t
575 BMediaAddOn::SniffType(const BMimeType &type, float *_quality,
576 	int32 *_internalID)
577 {
578 	CALLED();
579 	// only to be implemented by BFileInterface derived classes
580 	return B_ERROR;
581 }
582 
583 
584 status_t
585 BMediaAddOn::GetFileFormatList(int32 flavorID,
586 	media_file_format *writableFormats, int32 maxWriteItems, int32 *_writeItems,
587 	media_file_format *readableFormats, int32 maxReadItems, int32 *_readItems,
588 	void *_reserved)
589 {
590 	CALLED();
591 	// only to be implemented by BFileInterface derived classes
592 	return B_ERROR;
593 }
594 
595 
596 status_t
597 BMediaAddOn::SniffTypeKind(const BMimeType &type, uint64 kinds, float *_quality,
598 	int32 *_internalID, void *_reserved)
599 {
600 	CALLED();
601 	// only to be implemented by BFileInterface derived classes
602 	return B_ERROR;
603 }
604 
605 
606 image_id
607 BMediaAddOn::ImageID()
608 {
609 	return fImage;
610 }
611 
612 
613 media_addon_id
614 BMediaAddOn::AddonID()
615 {
616 	return fAddon;
617 }
618 
619 
620 // #pragma mark - protected BMediaAddOn
621 
622 
623 status_t
624 BMediaAddOn::NotifyFlavorChange()
625 {
626 	CALLED();
627 	if (fAddon == 0)
628 		return B_ERROR;
629 
630 	add_on_server_rescan_flavors_command command;
631 	command.add_on_id = fAddon;
632 	return SendToAddOnServer(ADD_ON_SERVER_RESCAN_ADD_ON_FLAVORS, &command,
633 		sizeof(command));
634 }
635 
636 
637 // #pragma mark - private BMediaAddOn
638 
639 
640 /*
641 unimplemented:
642 BMediaAddOn::BMediaAddOn()
643 BMediaAddOn::BMediaAddOn(const BMediaAddOn &clone)
644 BMediaAddOn & BMediaAddOn::operator=(const BMediaAddOn &clone)
645 */
646 
647 
648 extern "C" {
649 	// declared here to remove them from the class header file
650 	status_t _Reserved_MediaAddOn_0__11BMediaAddOnPv(void *, void *); /* now used for BMediaAddOn::GetFileFormatList */
651 	status_t _Reserved_MediaAddOn_1__11BMediaAddOnPv(void *, void *); /* now used for BMediaAddOn::SniffTypeKind */
652 	status_t _Reserved_MediaAddOn_0__11BMediaAddOnPv(void *, void *) { return B_ERROR; }
653 	status_t _Reserved_MediaAddOn_1__11BMediaAddOnPv(void *, void *) { return B_ERROR; }
654 };
655 
656 status_t BMediaAddOn::_Reserved_MediaAddOn_2(void *) { return B_ERROR; }
657 status_t BMediaAddOn::_Reserved_MediaAddOn_3(void *) { return B_ERROR; }
658 status_t BMediaAddOn::_Reserved_MediaAddOn_4(void *) { return B_ERROR; }
659 status_t BMediaAddOn::_Reserved_MediaAddOn_5(void *) { return B_ERROR; }
660 status_t BMediaAddOn::_Reserved_MediaAddOn_6(void *) { return B_ERROR; }
661 status_t BMediaAddOn::_Reserved_MediaAddOn_7(void *) { return B_ERROR; }
662 
663