From 557299d350bdcbb88c04a9d204ef525a20dad065 Mon Sep 17 00:00:00 2001 From: Thomas Schmitt Date: Fri, 4 Sep 2009 20:21:55 +0000 Subject: [PATCH] New API calls burn_get_media_product_id() and burn_guess_manufacturer() --- cdrskin/cdrskin_timestamp.h | 2 +- libburn/drive.c | 16 ++ libburn/libburn.h | 56 ++++++- libburn/mmc.c | 284 +++++++++++++++++++++++++++++++++++- libburn/mmc.h | 8 + libburn/spc.c | 4 + libburn/util.c | 117 ++++++++++++++- 7 files changed, 476 insertions(+), 11 deletions(-) diff --git a/cdrskin/cdrskin_timestamp.h b/cdrskin/cdrskin_timestamp.h index 1fae3c2..dfe8d2c 100644 --- a/cdrskin/cdrskin_timestamp.h +++ b/cdrskin/cdrskin_timestamp.h @@ -1 +1 @@ -#define Cdrskin_timestamP "2009.09.02.133307" +#define Cdrskin_timestamP "2009.09.04.202255" diff --git a/libburn/drive.c b/libburn/drive.c index 98634d8..acbea46 100644 --- a/libburn/drive.c +++ b/libburn/drive.c @@ -2625,3 +2625,19 @@ int burn_get_read_capacity(struct burn_drive *d, int *capacity, int flag) return (d->media_read_capacity != 0x7fffffff); } + +/* ts A90903 : API */ +int burn_get_media_product_id(struct burn_drive *d, + char **product_id, char **media_code1, char **media_code2, + char **book_type, int flag) +{ + int ret; + + *product_id = *media_code1 = *media_code2 = *book_type = NULL; + if (burn_drive_get_drive_role(d) != 1) + return 0; + ret = mmc_get_media_product_id(d, + product_id, media_code1, media_code2, book_type, 0); + return ret; +} + diff --git a/libburn/libburn.h b/libburn/libburn.h index ba55fdb..c50fa8c 100644 --- a/libburn/libburn.h +++ b/libburn/libburn.h @@ -1138,9 +1138,9 @@ int burn_drive_get_start_end_lba(struct burn_drive *drive, /* ts A90902 */ -/** Guess the manufacturer name from the ATIP addresses of lead-in and - lead-out. (Currently only lead-in is interpreted. Lead-out may in future - be used to identify the media type in more detail.) +/** Guess the manufacturer name of CD media from the ATIP addresses of lead-in + and lead-out. (Currently only lead-in is interpreted. Lead-out may in + future be used to identify the media type in more detail.) The parameters of this call should be obtained by burn_disc_read_atip(d), burn_drive_get_start_end_lba(d, &start_lba, &end_lba, 0), burn_lba_to_msf(start_lba, &m_li, &s_li, &f_li) and @@ -1156,7 +1156,7 @@ int burn_drive_get_start_end_lba(struct burn_drive *drive, vendor names are known. @return Printable text or NULL on memory shortage. Dispose by free() when no longer needed. - @since 0.7.2 + @since 0.7.2 */ char *burn_guess_cd_manufacturer(int m_li, int s_li, int f_li, int m_lo, int s_lo, int f_lo, int flag); @@ -1237,6 +1237,54 @@ off_t burn_disc_available_space(struct burn_drive *d, */ int burn_disc_get_profile(struct burn_drive *d, int *pno, char name[80]); + +/* ts A90903 : API */ +/** Obtain product id and standards defined media codes. + The product id is a printable string which is supposed to be the same + for identical media but should vary with non-identical media. Some media + do not allow to obtain such an id at all. + The pair (profile_number, product_id) should be the best id to identify + media with identical product specifications. + The reply parameters media_code1 and media_code2 can be used with + burn_guess_manufacturer() + The reply parameters have to be disposed by free() when no longer needed. + @param d The drive where the media is inserted. + @param product_id Reply: Printable text depicting manufacturer and + eventually media id. + @param media_code1 Reply: The eventual manufacturer identification as read + from DVD/BD media or a text "XXmYYsZZf" from CD media + ATIP lead-in. + @param media_code2 The eventual media id as read from DVD+/BD media or a + text "XXmYYsZZf" from CD ATIP lead-out. + @param book_type Book type text for DVD and BD. + Caution: is NULL with CD, even if return value says ok. + @param flag Bitfield for control purposes, submit 0 + @return 1= ok, product_id and media codes are valid, + 0= no product id_available, reply parameters are NULL + <0= error +*/ +int burn_get_media_product_id(struct burn_drive *d, + char **product_id, char **media_code1, char **media_code2, + char **book_type, int flag); + + +/* ts A90904 */ +/** Guess the name of a manufacturer by profile number, manufacturer code + and media code. The profile number can be obtained by + burn_disc_get_profile(), the other two parameters can be obtained as + media_code1 and media_code2 by burn_get_media_product_id(). + @param profile_no Profile number (submit -1 if not known) + @param manuf_code Manufacturer code from media (e.g. "RICOHJPN") + @param media_code Media ID code from media (e.g. "W11") + @param flag Bitfield for control purposes, submit 0 + @return Printable text or NULL on memory shortage. + Dispose by free() when no longer needed. + @since 0.7.2 +*/ +char *burn_guess_manufacturer(int profile_no, + char *manuf_code, char *media_code, int flag); + + /** Tells whether a disc can be erased or not @param d The drive to inquire. @return Non-zero means erasable diff --git a/libburn/mmc.c b/libburn/mmc.c index 8f54a66..cda058e 100644 --- a/libburn/mmc.c +++ b/libburn/mmc.c @@ -9,6 +9,8 @@ #include #include #include +#include + #include "error.h" #include "sector.h" #include "libburn.h" @@ -214,6 +216,10 @@ static unsigned char MMC_READ_10[] = static unsigned char MMC_READ_CAPACITY[] = { 0x25, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +/* ts A90903 : Obtain media type specific information. E.g. manufacturer. +*/ +static unsigned char MMC_READ_DISC_STRUCTURE[] = + { 0xAD, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; static int mmc_function_spy_do_tell = 0; @@ -3850,6 +3856,283 @@ int mmc_read_capacity(struct burn_drive *d) } +/* ts A90903 */ +/* mmc5r03c.pdf 6.23 ADh READ DISC STRUCTURE obtains media specific information +*/ +static int mmc_read_disc_structure_al(struct burn_drive *d, int *alloc_len, + int media_type, int layer_number, int format, + int min_len, char **reply, int *reply_len, + int flag) +{ + struct buffer buf; + int old_alloc_len, len; + struct command c; + unsigned char *dpt; + + *reply = NULL; + *reply_len = 0; + + if (*alloc_len < 4) + return 0; + + scsi_init_command(&c, MMC_READ_DISC_STRUCTURE, + sizeof(MMC_READ_DISC_STRUCTURE)); + c.dxfer_len = *alloc_len; + c.retry = 1; + c.opcode[1]= media_type; + c.opcode[7]= format; + c.opcode[8]= (c.dxfer_len >> 8) & 0xff; + c.opcode[9]= c.dxfer_len & 0xff; + c.page = &buf; + c.page->sectors = 0; + c.page->bytes = 0; + c.dir = FROM_DRIVE; + + d->issue_command(d, &c); + if (c.error) + return 0; + + len = (c.page->data[0] << 8) | (c.page->data[1]); + old_alloc_len = *alloc_len; + *alloc_len = len + 2; + if (old_alloc_len <= 4) + return 1; + if (len + 2 > old_alloc_len) + len = old_alloc_len - 2; + if (len < 4) + return 0; + + dpt = c.page->data + 4; + if (len - 2 < min_len) + return 0; + *reply = calloc(len - 2, 1); + if (*reply == NULL) + return 0; + *reply_len = len - 2; + memcpy(*reply, dpt, len - 2); + return 1; +} + + +int mmc_read_disc_structure(struct burn_drive *d, + int media_type, int layer_number, int format, int min_len, + char **reply, int *reply_len, int flag) +{ + int alloc_len = 4, ret; + + if (mmc_function_spy(d, "mmc_read_disc_structure") <= 0) + return 0; + + ret = mmc_read_disc_structure_al(d, &alloc_len, + media_type, layer_number, format, min_len, + reply, reply_len, 0); +/* + fprintf(stderr,"LIBBURN_DEBUG: ADh alloc_len = %d , ret = %d\n", + alloc_len, ret); +*/ + if (alloc_len >= 12 && ret > 0) + ret = mmc_read_disc_structure_al(d, &alloc_len, + media_type, layer_number, format, min_len, + reply, reply_len, 0); + return ret; +} + +/* ts A90903 */ +static int mmc_set_product_id(char *reply, + int manuf_idx, int type_idx, int rev_idx, + char **product_id, char **media_code1, char **media_code2, int flag) +{ + *product_id = calloc(17, 1); + *media_code1 = calloc(9, 1); + *media_code2 = calloc(8, 1); + if (*product_id == NULL || + *media_code1 == NULL || *media_code2 == NULL) + return -1; + sprintf(*media_code1, "%.8s", reply + manuf_idx); + sprintf(*media_code2, "%.3s/%d", reply + type_idx, + (int) ((unsigned char *) reply)[rev_idx]); + sprintf(*product_id, "%s/%s", *media_code1, *media_code2); + return 1; +} + + +/* ts A90903 */ +/* MMC backend of API call burn_get_media_product_id() + See also doc/mediainfo.txt + @param flag Bitfield for control purposes +*/ +int mmc_get_media_product_id(struct burn_drive *d, + char **product_id, char **media_code1, char **media_code2, + char **book_type, int flag) +{ + int prf, ret, reply_len, i, has_11h = -1, bt, start_lba, end_lba; + int min, sec, fr, media_type = 0; + char *reply = NULL, *wpt; + static char *books[16] = { + "DVD-ROM", "DVD-RAM", "DVD-R", "DVD-RW", + "HD DVD-ROM", "HD DVD-RAM", "HD DVD-R", "unknown", + "unknown", "DVD+RW", "DVD+R", "unknown", + "unknown", "DVD+RW DL" "DVD+R DL", "unknown"}; + + *product_id = *media_code1 = *media_code2 = *book_type = NULL; + prf = d->current_profile; + if (prf == 0x09 || prf == 0x0A) { + + *product_id = calloc(20, 1); + *media_code1 = calloc(10, 1); + *media_code2 = calloc(10, 1); + if (*product_id == NULL || + *media_code1 == NULL || *media_code2 == NULL) { + ret = -1; + goto ex; + } + ret = burn_disc_read_atip(d); + if (ret <= 0) + goto ex; + ret = burn_drive_get_start_end_lba(d, &start_lba, &end_lba, 0); + if (ret <= 0) + goto ex; + burn_lba_to_msf(start_lba, &min, &sec, &fr); + sprintf(*media_code1, "%2.2dm%2.2ds%2.2df", min, sec, fr); + burn_lba_to_msf(end_lba, &min, &sec, &fr); + sprintf(*media_code2, "%2.2dm%2.2ds%2.2df", min, sec, fr); + sprintf(*product_id, "%s/%s", *media_code1, *media_code2); + ret = 1; + goto ex; /* No booktype with CD media */ + + } else if (prf == 0x11 || prf == 0x13 || prf == 0x14 || prf == 0x15) { + /* DVD-R */ + + ret = mmc_read_disc_structure(d, 0, 0, 0x0E, 31, &reply, + &reply_len, 0); + if (ret <= 0) + goto ex; + if (reply[16] != 3 || reply[24] != 4 || + (reply_len > 38 && reply[32] != 5)) { + ret = 0; + goto ex; + } + *product_id = calloc(19, 1); + *media_code1 = calloc(19, 1); + *media_code2 = strdup(""); + if (*product_id == NULL || + *media_code1 == NULL || *media_code2 == NULL) { + ret = -1; + goto ex; + } + memcpy(*product_id, reply + 17, 6); + memcpy(*product_id + 6, reply + 25, 6); + if (reply_len > 38) + memcpy(*product_id + 12, reply + 33, 6); + /* Clean out 0 bytes */ + wpt = *product_id; + for (i = 0; i < 18; i++) + if ((*product_id)[i]) + *(wpt++) = (*product_id)[i]; + *wpt = 0; + strcpy(*media_code1, *product_id); + + } else if (prf == 0x1a || prf == 0x1b || prf == 0x2b) { /* DVD+R[W] */ + + /* Check whether the drive supports format 11h */ + has_11h = 0; + ret = mmc_read_disc_structure(d, 0, 0, 4, 0xff, &reply, + &reply_len, 0); + if (ret > 0) { + for (i = 0; i < reply_len; i += 4) { + if (reply[i] == 0x11 && (reply[i + 1] & 64)) + has_11h = 1; + } + } + if (reply != NULL) + free(reply); + reply = NULL; + ret = mmc_read_disc_structure(d, 0, 0, 0x11, 29, &reply, + &reply_len, 0); + if (ret <= 0) { + /* Hope for format 00h */ + has_11h = 0; + } else { + /* Dig out manufacturer, media type and revision */ + ret = mmc_set_product_id(reply, 19, 27, 28, + product_id, media_code1, media_code2, 0); + if (ret <= 0) + goto ex; + } + } else if (prf == 0x41 || prf == 0x43 || prf == 0x40 || prf == 0x42) { + /* BD */ + media_type = 1; + ret = mmc_read_disc_structure(d, 1, 0, 0x00, 112, &reply, + &reply_len, 0); + if (ret <= 0) + goto ex; + if (reply[0] != 'D' || reply[1] != 'I') { + ret = 0; + goto ex; + } + /* Dig out manufacturer, media type and revision */ + ret = mmc_set_product_id(reply, 100, 106, 111, + product_id, media_code1, media_code2, 0); + if (ret <= 0) + goto ex; + + } else { + + /* Source of DVD-RAM manufacturer and media id not found yet */ + ret = 0; + goto ex; + } + + if (reply != NULL) + free(reply); + reply = NULL; + ret = mmc_read_disc_structure(d, media_type, 0, 0x00, 1, + &reply, &reply_len, 0); + if (ret <= 0) + goto ex; + bt = (reply[0] >> 4) & 0xf; + *book_type = calloc(80 + strlen(books[bt]), 1); + if (*book_type == NULL) { + ret = -1; + goto ex; + } + sprintf(*book_type, "%2.2Xh, %s book [revision %d]", + bt, books[bt], reply[0] & 0xf); + + if (has_11h == 0 && *product_id == NULL && reply_len > 28) { + /* DVD+ with no format 11h */ + /* Get manufacturer and media type from bytes 19 and 27 */ + ret = mmc_set_product_id(reply, 19, 27, 28, product_id, + media_code1, media_code2, 0); + if (*product_id == NULL) { + ret = 0; + goto ex; + } + } + + ret = 1; +ex:; + if (reply != NULL) + free(reply); + if (ret <= 0) { + if (*product_id != NULL) + free(*product_id); + if (*media_code1 != NULL) + free(*media_code1); + if (*media_code2 != NULL) + free(*media_code2); + if (*book_type != NULL) + free(*book_type); + *product_id = *media_code1 = *media_code2 = *book_type = NULL; + } else if(*product_id != NULL) { + for (i = 0; (*product_id)[i]; i++) + if (isspace((*product_id)[i])) + (*product_id)[i] = '_'; + } + return ret; +} + + /* ts A61021 : the mmc specific part of sg.c:enumerate_common() */ int mmc_setup_drive(struct burn_drive *d) @@ -3924,4 +4207,3 @@ int mmc_setup_drive(struct burn_drive *d) return 1; } - diff --git a/libburn/mmc.h b/libburn/mmc.h index 28858b3..645750f 100644 --- a/libburn/mmc.h +++ b/libburn/mmc.h @@ -82,4 +82,12 @@ char *mmc_obtain_profile_name(int profile_number); /* mmc5r03c.pdf 4.3.4.4.1 d) "The maximum number of RZones is 2 302." */ #define BURN_MMC_FAKE_TOC_MAX_SIZE 2302 + +/* ts A90903 */ +/* MMC backend of API call burn_get_media_product_id() +*/ +int mmc_get_media_product_id(struct burn_drive *d, + char **product_id, char **media_code1, char **media_code2, + char **book_type, int flag); + #endif /*__MMC*/ diff --git a/libburn/spc.c b/libburn/spc.c index 3eb9fac..73d8bb6 100644 --- a/libburn/spc.c +++ b/libburn/spc.c @@ -1233,6 +1233,8 @@ static char *scsi_command_name(unsigned int c, int flag) return "PREVENT/ALLOW MEDIA REMOVAL"; case 0x23: return "READ FORMAT CAPACITIES"; + case 0x25: + return "READ CAPACITY"; case 0x28: return "READ(10)"; case 0x2a: @@ -1269,6 +1271,8 @@ static char *scsi_command_name(unsigned int c, int flag) return "WRITE(12)"; case 0xac: return "GET PERFORMANCE"; + case 0xad: + return "READ DISC STRUCTURE"; case 0xb6: return "SET STREAMING"; case 0xbb: diff --git a/libburn/util.c b/libburn/util.c index a8c9efa..a04365a 100644 --- a/libburn/util.c +++ b/libburn/util.c @@ -59,7 +59,7 @@ void burn_version(int *major, int *minor, int *micro) } -struct mid_record { +struct cd_mid_record { char *manufacturer; int m_li; int s_li; @@ -69,7 +69,7 @@ struct mid_record { int f_lo; char *other_brands; }; -typedef struct mid_record mid_record_t; +typedef struct cd_mid_record cd_mid_record_t; /* ts A90902 */ @@ -80,7 +80,7 @@ typedef struct mid_record mid_record_t; char *burn_guess_cd_manufacturer(int m_li, int s_li, int f_li, int m_lo, int s_lo, int f_lo, int flag) { - static mid_record_t mid_list[]= { + static cd_mid_record_t mid_list[]= { {"SKC", 96, 40, 0, 0, 0, 0, ""}, {"Ritek Corp" , 96, 43, 30, 0, 0, 0, ""}, {"TDK / Ritek" , 97, 10, 0, 0, 0, 0, "TRAXDATA"}, @@ -99,7 +99,7 @@ char *burn_guess_cd_manufacturer(int m_li, int s_li, int f_li, {"Sony Corporation" , 97, 24, 10, 0, 0, 0, "LeadData, Imation"}, {"Computer Support Italcard s.r.l" , 97, 24, 20, 0, 0, 0, ""}, {"Unitech Japan Inc." , 97, 24, 30, 0, 0, 0, ""}, - {"MPO, France" , 97, 25, 0, 0, 0, 0, ""}, + {"MPO, France" , 97, 25, 0, 0, 0, 0, "TDK"}, {"Hitachi Maxell Ltd." , 97, 25, 20, 0, 0, 0, ""}, {"Infodisc Technology Co,Ltd." , 97, 25, 30, 0, 0, 0, "MEMOREX, SPEEDA, Lead data"}, {"Xcitec" , 97, 25, 60, 0, 0, 0, ""}, @@ -123,6 +123,8 @@ char *burn_guess_cd_manufacturer(int m_li, int s_li, int f_li, {"TDK Corporation" , 97, 32, 00, 0, 0, 0, ""}, {"Prodisc Technology Inc." , 97, 32, 10, 0, 0, 0, "Smartbuy, Mitsubishi, Digmaster, LG, Media Market"}, {"Mitsubishi Chemical Corporation" , 97, 34, 20, 0, 0, 0, "YAMAHA, Verbatim"}, + {"Mitsui Chemicals Inc." , 97, 48, 50, 0, 0, 0, ""}, + {"TDK Corporation" , 97, 49, 0, 0, 0, 0, ""}, {"", 0, 0, 0, 0, 0, 0, ""} }; @@ -138,7 +140,7 @@ char *burn_guess_cd_manufacturer(int m_li, int s_li, int f_li, break; } if (mid_list[i].manufacturer[0] == 0) { - sprintf(buf, "Unknown CD manufacturer. Please report code '%2.2dm%2.2ds%2.2df-%2.2dm%2.2ds%2.2df', human readable brand, size, and speed to scdbackup@gmx.net.", m_li, s_li, f_li, m_lo, s_lo, f_lo); + sprintf(buf, "Unknown CD manufacturer. Please report code '%2.2dm%2.2ds%2.2df/%2.2dm%2.2ds%2.2df', the human readable brand, size, and speed to scdbackup@gmx.net.", m_li, s_li, f_li, m_lo, s_lo, f_lo); result = strdup(buf); return result; } @@ -153,3 +155,108 @@ char *burn_guess_cd_manufacturer(int m_li, int s_li, int f_li, return result; } + +/* ts A90904 */ +struct dvd_mid_record { + char *mc1; + char *mc2; + int mc1_sig_len; + char *manufacturer; +}; +typedef struct dvd_mid_record dvd_mid_record_t; + +/* ts A90904 */ +char *burn_guess_manufacturer(int prf, + char *media_code1, char *media_code2, int flag) +{ + int i, l = 0, m_li, s_li, f_li, m_lo, s_lo, f_lo; + char buf[1024]; + char *result = NULL, *cpt; + + static dvd_mid_record_t mid_list[]= { + {"AML", "", 8, "UML"}, + {"BeAll", "", 5, "BeAll Developers, Inc."}, + {"CMC", "", 3, "CMC Magnetics Corporation"}, + {"DAXON", "", 5, "Daxon Technology Inc. / Acer"}, + {"Daxon", "", 5, "Daxon Technology Inc. / Acer"}, + {"FUJI", "", 4, "Fujifilm Holdings Corporation"}, + {"INFODISC", "", 8, "New Star Digital Co., Ltd."}, + {"INFOME", "", 6, "InfoMedia Inc."}, + {"ISMMBD", "", 6, "Info Source Multi Media Ltd."}, + {"JVC", "", 3, "JVC Limited"}, + {"KIC01RG", "", 7, "AMC"}, + {"LD", "", 8, "Lead Data Inc."}, + {"LGE", "", 3, "LG Electronics"}, + {"MAM", "", 8, "Mitsui Advanced Media, Inc. Europe"}, + {"MAXELL", "", 6, "Hitachi Maxell Ltd."}, + {"MBI", "", 3, "Moser Baer India Limited"}, + {"MCC", "", 8, "Mitsubishi Chemical Corporation"}, + {"MCI", "", 8, "Mitsui Chemicals Inc."}, + {"MEI", "", 3, "Panasonic Corporation"}, + {"MKM", "", 3, "Mitsubishi Kagaku Media Co."}, + {"MMC", "", 8, "Mitsubishi Kagaku Media Co."}, + {"MXL", "", 8, "Hitachi Maxell Ltd."}, + {"NANYA", "", 5, "Nan-Ya Plastics Corporation"}, + {"NSD", "", 8, "NESA International Inc."}, + {"OPTODISC", "", 8, "Optodisc Technology Corporation"}, + {"OTCBDR", "", 8, "Optodisc Technology Corporation"}, + {"PHILIP", "", 8, "Moser Baer India Limited"}, + {"PHILIPS", "", 8, "Philips"}, + {"PRINCO", "", 6, "Princo Corporation"}, + {"PRODISC", "", 7, "Prodisc Technology Inc."}, + {"Prodisc", "", 7, "Prodisc Technology Inc."}, + {"PVC", "", 3, "Pioneer"}, + {"RICOHJPN", "", 8, "Ricoh Company Limited"}, + {"RITEK", "", 5, "Ritek Corp"}, + {"SONY", "", 4, "Sony Corporation"}, + {"TDK", "", 3, "TDK Corporation"}, + {"TT", "", 8, "TDK Corporation"}, + {"TY", "", 8, "Taiyo Yuden Company Limited"}, + {"TYG", "", 3, "Taiyo Yuden Company Limited"}, + {"UTJR001", "", 7, "Unifino Inc."}, + {"VERBAT", "", 5, "Mitsubishi Kagaku Media Co."}, + {"YUDEN", "", 5, "Taiyo Yuden Company Limited"}, + {"", "", 0, ""} + }; + + if (media_code2 != NULL && + (prf == -1 || prf == 0x09 || prf == 0x0A)) { + if (strlen(media_code2) == 9 && media_code2[0] == '9' && + media_code2[2] == 'm' && media_code2[5] == 's' && + media_code2[8] == 'f') { + sscanf(media_code1, "%dm%ds%df", &m_li, &s_li, &f_li); + sscanf(media_code2, "%dm%ds%df", &m_lo, &s_lo, &f_lo); + if (m_li >= 96 && m_li <= 97 && m_lo > 0) { + result = burn_guess_cd_manufacturer( + m_li, s_li, f_li, m_lo, s_lo, f_lo, 0); + return result; + } + } + } + + /* DVD-R do not keep manufacturer id apart from media id. + Some manufacturers use a blank as separator. + */ + cpt = strchr(media_code1, ' '); + if (cpt != NULL && (prf == -1 || prf == 0x11 || prf == 0x13 || + prf == 0x14 || prf == 0x15)) + l = cpt - media_code1; + + for (i = 0; mid_list[i].mc1[0]; i++) { + if (strncmp(mid_list[i].mc1, media_code1, + mid_list[i].mc1_sig_len) == 0) + break; + if (l > 0) + if (strncmp(mid_list[i].mc1, media_code1, l) == 0) + break; + } + if (mid_list[i].mc1[0] == 0) { + sprintf(buf, "Unknown DVD/BD manufacturer. Please report code '%s/%s', the human readable brand, size, and speed to scdbackup@gmx.net.", + media_code1, media_code2); + result = strdup(buf); + return result; + } + result = strdup(mid_list[i].manufacturer); + return result; +} +