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