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
46static 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
62dormant_node_info::dormant_node_info()
63	:
64	addon(-1),
65	flavor_id(-1)
66{
67	name[0] = '\0';
68}
69
70
71dormant_node_info::~dormant_node_info()
72{
73}
74
75
76// #pragma mark - flavor_info
77
78
79/* DO NOT IMPLEMENT */
80/*
81flavor_info &flavor_info::operator=(const flavor_info &other)
82*/
83
84
85// #pragma mark - dormant_flavor_info
86
87
88dormant_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
105dormant_flavor_info::~dormant_flavor_info()
106{
107	delete[] name;
108	delete[] info;
109	delete[] in_formats;
110	delete[] out_formats;
111}
112
113
114dormant_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
125dormant_flavor_info &
126dormant_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
136dormant_flavor_info &
137dormant_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
206void
207dormant_flavor_info::set_name(const char *newName)
208{
209	delete[] name;
210	name = _newstrdup(newName);
211}
212
213
214void
215dormant_flavor_info::set_info(const char *newInfo)
216{
217	delete[] info;
218	info = _newstrdup(newInfo);
219}
220
221
222void
223dormant_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
237void
238dormant_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
252bool
253dormant_flavor_info::IsFixedSize() const
254{
255	return false;
256}
257
258
259type_code
260dormant_flavor_info::TypeCode() const
261{
262	return FLATTEN_TYPECODE;
263}
264
265
266ssize_t
267dormant_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
298status_t
299dormant_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
376status_t
377dormant_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
483BMediaAddOn::BMediaAddOn(image_id image)
484	:
485	fImage(image),
486	fAddon(0)
487{
488	CALLED();
489}
490
491
492BMediaAddOn::~BMediaAddOn()
493{
494	CALLED();
495}
496
497
498status_t
499BMediaAddOn::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
508int32
509BMediaAddOn::CountFlavors()
510{
511	CALLED();
512	// only to be implemented by derived classes
513	return 0;
514}
515
516
517status_t
518BMediaAddOn::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
526BMediaNode*
527BMediaAddOn::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
536status_t
537BMediaAddOn::GetConfigurationFor(BMediaNode *node, BMessage *toMessage)
538{
539	CALLED();
540	// only to be implemented by derived classes
541	return B_ERROR;
542}
543
544
545bool
546BMediaAddOn::WantsAutoStart()
547{
548	CALLED();
549	// only to be implemented by derived classes
550	return false;
551}
552
553
554status_t
555BMediaAddOn::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
564status_t
565BMediaAddOn::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
574status_t
575BMediaAddOn::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
584status_t
585BMediaAddOn::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
596status_t
597BMediaAddOn::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
606image_id
607BMediaAddOn::ImageID()
608{
609	return fImage;
610}
611
612
613media_addon_id
614BMediaAddOn::AddonID()
615{
616	return fAddon;
617}
618
619
620// #pragma mark - protected BMediaAddOn
621
622
623status_t
624BMediaAddOn::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/*
641unimplemented:
642BMediaAddOn::BMediaAddOn()
643BMediaAddOn::BMediaAddOn(const BMediaAddOn &clone)
644BMediaAddOn & BMediaAddOn::operator=(const BMediaAddOn &clone)
645*/
646
647
648extern "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
656status_t BMediaAddOn::_Reserved_MediaAddOn_2(void *) { return B_ERROR; }
657status_t BMediaAddOn::_Reserved_MediaAddOn_3(void *) { return B_ERROR; }
658status_t BMediaAddOn::_Reserved_MediaAddOn_4(void *) { return B_ERROR; }
659status_t BMediaAddOn::_Reserved_MediaAddOn_5(void *) { return B_ERROR; }
660status_t BMediaAddOn::_Reserved_MediaAddOn_6(void *) { return B_ERROR; }
661status_t BMediaAddOn::_Reserved_MediaAddOn_7(void *) { return B_ERROR; }
662
663