From 4d5caebc86940eb7032e8de21ddeda9c5bb96381 Mon Sep 17 00:00:00 2001 From: John Doe Date: Fri, 14 Feb 2020 00:00:00 +0000 Subject: [PATCH] Use cached conversion tables Tables will be loaded from "\convtab\*.bin". --- src/libbdplus/bdplus.c | 78 +++++++++++++++++++++++++++-------- src/libbdplus/bdplus_data.h | 1 + src/libbdplus/bdsvm/segment.c | 57 +++++++++++++++++++++++++ src/libbdplus/bdsvm/segment.h | 28 +++++++------ src/libbdplus/internal.c | 62 +++++++++++++++++++++++++--- src/libbdplus/internal.h | 2 +- 6 files changed, 191 insertions(+), 37 deletions(-) diff --git a/src/libbdplus/bdplus.c b/src/libbdplus/bdplus.c index d9b677e..8c597df 100644 --- a/src/libbdplus/bdplus.c +++ b/src/libbdplus/bdplus.c @@ -37,6 +37,7 @@ #include "util/strutl.h" #include "file/configfile.h" #include "file/file.h" +#include "file/dirs.h" #include #include @@ -120,6 +121,33 @@ static void _save_slots(bdplus_t *plus) } } +static void _load_cached_table(bdplus_t *plus) +{ + /* try to load a cached conversion table file */ + char *file = bdplus_disc_cache_file(plus); + FILE *fp = NULL; + + bdplus_run_init(plus->vm); + + if (file) { + BD_DEBUG(DBG_BDPLUS | DBG_CRIT, "[bdplus] Opening cached CONVERSION TABLE from %s ...\n", file); + fp = fopen(file, "rb"); + if (fp) { + conv_table_t *ct = NULL; + if(segment_load(&ct, fp) == 1) { + bdplus_setConvTable(plus, ct); + segment_activateTable(&plus->conv_tab); + } + + fclose(fp); + } else { + BD_DEBUG(DBG_BDPLUS | DBG_CRIT, "[bdplus] File open failed\n"); + } + + X_FREE(file); + } +} + bdplus_t *bdplus_init(const char *path, const char *config_path, const uint8_t *vid) { bdplus_t *plus = NULL; @@ -254,15 +282,18 @@ void bdplus_free(bdplus_t *plus) // FIXME if (plus->conv_tab) { - char *file = bdplus_disc_cache_file(plus, "convtab.bin"); - FILE *fp = NULL; - if (file) { - fp = fopen(file, "wb"); - X_FREE(file); - } - if (fp) { - segment_save(plus->conv_tab, fp); - fclose(fp); + // don't save conversion table when we're already using cached table + if (!plus->using_cached_table) { + char *file = bdplus_disc_cache_file(plus); + FILE *fp = NULL; + if (file) { + fp = fopen(file, "wb"); + X_FREE(file); + } + if (fp) { + segment_save(plus->conv_tab, fp); + fclose(fp); + } } segment_freeTable(&plus->conv_tab); } @@ -289,9 +320,16 @@ bdplus_st_t *bdplus_m2ts(bdplus_t *plus, uint32_t m2ts) bd_mutex_lock(plus->mutex); if (!plus->conv_tab) { - BD_DEBUG(DBG_BDPLUS | DBG_CRIT, "[bdplus] bdplus_m2ts(%05u.m2ts): no conversion table\n", m2ts); - bd_mutex_unlock(plus->mutex); - return NULL; + /* try to load a cached conversion table file */ + _load_cached_table(plus); + + if(plus->conv_tab) { + BD_DEBUG(DBG_BDPLUS | DBG_CRIT, "[bdplus] bdplus_m2ts(%05u.m2ts): using cached CONVERSION TABLE file\n", m2ts); + } else { + BD_DEBUG(DBG_BDPLUS | DBG_CRIT, "[bdplus] bdplus_m2ts(%05u.m2ts): no conversion table\n", m2ts); + bd_mutex_unlock(plus->mutex); + return NULL; + } } bdplus_run_m2ts(plus, m2ts); @@ -379,13 +417,19 @@ static int32_t _bdplus_event(bdplus_t *plus, uint32_t event, uint32_t param1, ui if (event == BDPLUS_RUN_CONVTAB) { /* this event is used when disc is played without menus. */ - /* try to emulate player to get converson table. */ - BD_DEBUG(DBG_BDPLUS, "[bdplus] received CONVERSION TABLE event\n"); + /* try to load a cached file or emulate player to get the conversion table. */ + BD_DEBUG(DBG_BDPLUS | DBG_CRIT, "[bdplus] received CONVERSION TABLE event\n"); unsigned int num_titles = param2; - bdplus_run_init(plus->vm); - return bdplus_run_convtab(plus, num_titles); + _load_cached_table(plus); + + if(plus->conv_tab) { + BD_DEBUG(DBG_BDPLUS | DBG_CRIT, "[bdplus] using cached CONVERSION TABLE file\n"); + return 1; + } else { + return bdplus_run_convtab(plus, num_titles); + } } @@ -394,7 +438,7 @@ static int32_t _bdplus_event(bdplus_t *plus, uint32_t event, uint32_t param1, ui } if (event == BDPLUS_EVENT_TITLE) { - if (plus->conv_tab && param1 == 0xffff) { + if (plus->conv_tab && param1 == 0xffff) { BD_DEBUG(DBG_BDPLUS, "[bdplus] ignoring FirstPlay title event (conversion table exists)\n"); return 0; } diff --git a/src/libbdplus/bdplus_data.h b/src/libbdplus/bdplus_data.h index 7521f4b..33a164e 100644 --- a/src/libbdplus/bdplus_data.h +++ b/src/libbdplus/bdplus_data.h @@ -59,6 +59,7 @@ struct bdplus_s { uint8_t loaded; uint8_t started; + uint8_t using_cached_table; /* BD+ content code version */ int gen; diff --git a/src/libbdplus/bdsvm/segment.c b/src/libbdplus/bdsvm/segment.c index 7e5df94..c0da08b 100644 --- a/src/libbdplus/bdsvm/segment.c +++ b/src/libbdplus/bdsvm/segment.c @@ -567,7 +567,40 @@ uint32_t segment_mergeTables(conv_table_t *set1, conv_table_t *set2) } +// +// Activates a table. This is usefull if a cached convtab.bin file is being used. +// Sets all segements as decrypted and all entries as active +int32_t segment_activateTable(conv_table_t **conv_tab) +{ + uint32_t table, currseg, currentry; + conv_table_t *ct = NULL; + subtable_t *subtable = NULL; + segment_t *segment = NULL; + entry_t *entry = NULL; + + BD_DEBUG(DBG_BDPLUS | DBG_CRIT,"[segment] activating conv_tab.bin\n"); + + ct = *conv_tab; + + for (table = 0; table < ct->numTables; table++) { + // Assign pointer so we don't need to keep dereferencing + subtable = &ct->Tables[ table ]; + + //set all segments as decrypted + for (currseg = 0; currseg < subtable->numSegments; currseg++) { + segment = &subtable->Segments[ currseg ]; + segment->encrypted = 0; + + //set all entries as active + for (currentry = 0; currentry < segment->numEntries; currentry++) { + entry = &segment->Entries[ currentry ]; + entry->active = 1; + } + } + } + return 0; +} // @@ -746,6 +779,30 @@ static int segment_sortby_tableid(const void *a1, const void *a2) } +int32_t segment_load(conv_table_t **conv_tab, FILE *fd) +{ + uint32_t fileLen; + uint32_t len; + uint8_t *buffer = NULL; + + BD_DEBUG(DBG_BDPLUS | DBG_CRIT,"[segment] loading cached convTable file\n"); + fseek(fd, 0L, SEEK_END); + fileLen=ftell(fd); + rewind(fd); + buffer=(uint8_t *)malloc(fileLen+1); + len=fread(buffer, fileLen, 1, fd); + + // Save the table to VM + if (len) { + // Decode the table into C structures. + segment_setTable(conv_tab, buffer, fileLen); + X_FREE(buffer); + + if(conv_tab) return 1; + } + return 0; +} + int32_t segment_save(conv_table_t *ct, FILE *fd) { diff --git a/src/libbdplus/bdsvm/segment.h b/src/libbdplus/bdsvm/segment.h index 082f222..2b69005 100644 --- a/src/libbdplus/bdsvm/segment.h +++ b/src/libbdplus/bdsvm/segment.h @@ -33,23 +33,25 @@ typedef struct conv_table_s conv_table_t; typedef struct bdplus_st_s bdplus_st_t; #endif -BD_PRIVATE uint32_t segment_numTables ( conv_table_t * ); -BD_PRIVATE uint32_t segment_numEntries ( conv_table_t * ); +BD_PRIVATE uint32_t segment_numTables ( conv_table_t * ); +BD_PRIVATE uint32_t segment_numEntries ( conv_table_t * ); -BD_PRIVATE int32_t segment_setTable ( conv_table_t **, uint8_t *, uint32_t ); -BD_PRIVATE int32_t segment_freeTable ( conv_table_t ** ); -BD_PRIVATE uint32_t segment_mergeTables ( conv_table_t *, conv_table_t * ); +BD_PRIVATE int32_t segment_setTable ( conv_table_t **, uint8_t *, uint32_t ); +BD_PRIVATE int32_t segment_freeTable ( conv_table_t ** ); +BD_PRIVATE uint32_t segment_mergeTables ( conv_table_t *, conv_table_t * ); +BD_PRIVATE int32_t segment_activateTable( conv_table_t ** ); -BD_PRIVATE int32_t segment_nextSegment ( conv_table_t *, uint32_t *, uint32_t * ); -BD_PRIVATE int32_t segment_setSegment ( conv_table_t *, uint32_t, uint32_t ); -BD_PRIVATE int32_t segment_decrypt ( conv_table_t *, uint8_t *, uint8_t * ); +BD_PRIVATE int32_t segment_nextSegment ( conv_table_t *, uint32_t *, uint32_t * ); +BD_PRIVATE int32_t segment_setSegment ( conv_table_t *, uint32_t, uint32_t ); +BD_PRIVATE int32_t segment_decrypt ( conv_table_t *, uint8_t *, uint8_t * ); -BD_PRIVATE int32_t segment_save ( conv_table_t *, FILE * ); +BD_PRIVATE int32_t segment_save ( conv_table_t *, FILE * ); +BD_PRIVATE int32_t segment_load ( conv_table_t **,FILE * ); -BD_PRIVATE bdplus_st_t *segment_set_m2ts ( conv_table_t *, uint32_t ); -BD_PRIVATE int32_t segment_patchfile ( conv_table_t *, uint32_t , FILE * ); -BD_PRIVATE int32_t segment_patchseek ( bdplus_st_t *, uint64_t ); -BD_PRIVATE int32_t segment_patch ( bdplus_st_t *, int32_t, uint8_t * ); +BD_PRIVATE bdplus_st_t *segment_set_m2ts ( conv_table_t *, uint32_t ); +BD_PRIVATE int32_t segment_patchfile ( conv_table_t *, uint32_t , FILE * ); +BD_PRIVATE int32_t segment_patchseek ( bdplus_st_t *, uint64_t ); +BD_PRIVATE int32_t segment_patch ( bdplus_st_t *, int32_t, uint8_t * ); #endif diff --git a/src/libbdplus/internal.c b/src/libbdplus/internal.c index 480efb6..a300015 100644 --- a/src/libbdplus/internal.c +++ b/src/libbdplus/internal.c @@ -29,6 +29,7 @@ #include "file/configfile.h" #include "file/file.h" +#include "file/dirs.h" #include "util/logging.h" #include "util/macro.h" #include "util/strutl.h" @@ -37,6 +38,8 @@ #include #include #include +#include +#include #ifdef HAVE_PTHREAD_H #include #endif @@ -66,13 +69,60 @@ int crypto_init() return crypto_init_check; } -char *bdplus_disc_cache_file(bdplus_t *plus, const char *file) +char *bdplus_disc_cache_file(bdplus_t *plus) { - char *base = file_get_cache_dir(); - char vid_str[33]; - char *result; - str_print_hex(vid_str, plus->volumeID, 16); - result = str_printf("%s/%s/%s", base ? base : "/tmp/", vid_str, file); + char *base = file_get_cache_dir(); + char mk[33]; + char *result = NULL; + DIR *dir; + struct dirent *ent; + + str_print_hex(mk, plus->mediaKey, 16); + + /* try opening from cache dir (user profile) */ + BD_DEBUG(DBG_BDPLUS | DBG_CRIT, "[bdplus] Trying to open CONVERSION TABLE from %s ...\n", base); + if ((dir = opendir(str_printf("%s%s", base ? base : "/tmp/", "convtab"))) != NULL) { + while ((ent = readdir (dir)) != NULL) { + char *tmp = malloc(strlen(ent->d_name) + 1); + strcpy(tmp, ent->d_name); + for (long unsigned int i = 0; i < strlen(tmp); i++) { + tmp[i] = tolower(tmp[i]); + } + if(!memcmp(tmp, mk, 32) && !memcmp(tmp+strlen(tmp)-4, ".bin", 4)) { + result = str_printf("%s%s%s%s", base ? base : "/tmp/", "convtab", DIR_SEP, ent->d_name); + plus->using_cached_table = 1; + } + X_FREE(tmp); + } + closedir (dir); + } + if (!result) { + /* no cached conversion table in cache dir (user profile) */ + const char *sysdir = NULL; + const char *sysbase = file_get_config_system(sysdir); + + /* try opening from system wide config dir */ + BD_DEBUG(DBG_BDPLUS | DBG_CRIT, "[bdplus] Trying to open CONVERSION TABLE from %s%s%s ...\n", sysbase, DIR_SEP, "bdplus"); + if ((dir = opendir(str_printf("%s%s%s%s%s", sysbase ? sysbase : "/tmp", DIR_SEP, "bdplus", DIR_SEP, "convtab"))) != NULL) { + while ((ent = readdir (dir)) != NULL) { + char *tmp = malloc(strlen(ent->d_name) + 1); + strcpy(tmp, ent->d_name); + for (long unsigned int i = 0; i < strlen(tmp); i++) { + tmp[i] = tolower(tmp[i]); + } + if(!memcmp(tmp, mk, 32) && !memcmp(tmp+strlen(tmp)-4, ".bin", 4)) { + result = str_printf("%s%s%s%s%s%s%s", sysbase ? sysbase : "/tmp", DIR_SEP, "bdplus", DIR_SEP, "convtab", DIR_SEP, ent->d_name); + plus->using_cached_table = 1; + } + X_FREE(tmp); + } + closedir (dir); + } else { + /* could not open conversion table */ + BD_DEBUG(DBG_BDPLUS | DBG_CRIT, "[bdplus] File open failed\n"); + } + } + X_FREE(base); file_mkdirs(result); return result; diff --git a/src/libbdplus/internal.h b/src/libbdplus/internal.h index b3950ac..a95f5d5 100644 --- a/src/libbdplus/internal.h +++ b/src/libbdplus/internal.h @@ -42,7 +42,7 @@ BD_PRIVATE uint8_t *bdplus_getMediaKey( bdplus_t *plus ); BD_PRIVATE void bdplus_setConvTable( bdplus_t *plus, struct conv_table_s * ); BD_PRIVATE struct conv_table_s *bdplus_getConvTable ( bdplus_t *plus ); BD_PRIVATE struct bdplus_config_s *bdplus_getConfig ( bdplus_t *plus ); -BD_PRIVATE char *bdplus_disc_cache_file( bdplus_t *plus, const char *file ); +BD_PRIVATE char *bdplus_disc_cache_file( bdplus_t *plus); BD_PRIVATE void bdplus_getSlot ( bdplus_t *plus, uint32_t slot, struct slot_s *dst ); BD_PRIVATE void bdplus_getAttachStatus ( bdplus_t *plus, uint8_t *dst ); -- 2.28.0.rc2