deaacs/main.c

172 lines
3.6 KiB
C

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ftw.h>
#include <sys/stat.h>
#include <libbluray/bluray.h>
#include <libaacs/aacs.h>
#ifndef BUFFER_SIZE
#define BUFFER_SIZE 1024
#endif
const char* aacs_error_string(int error_code)
{
switch(error_code)
{
case AACS_ERROR_CORRUPTED_DISC:
return "disc corrupted";
break;
case AACS_ERROR_NO_CONFIG:
return "AACS config file not found";
break;
case AACS_ERROR_NO_PK:
return "no processing key found for this disc";
break;
case AACS_ERROR_NO_CERT:
return "no valid AACS certificate found";
break;
case AACS_ERROR_CERT_REVOKED:
return "AACS certificate revoked";
break;
case AACS_ERROR_MMC_OPEN:
return "MMC open failed";
break;
case AACS_ERROR_MMC_FAILURE:
return "MMC failed";
break;
case AACS_ERROR_NO_DK:
return "no matching device key";
break;
default:
return "unknown AACS error";
break;
}
}
const char* disc_path;
const char* output_path;
BLURAY* bd;
AACS* aacs;
int fn(const char* fpath, const struct stat* sb, int typeflag)
{
const char* path = fpath + strlen(disc_path);
if(!strncmp(path, "AACS", 4))
{
return 0;
}
char output_entry[255];
sprintf(output_entry, "%s/%s", output_path, path);
if(typeflag == FTW_D)
{
mkdir(output_entry, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
}
else
{
const char* extension = ".m2ts";
if(strlen(path) >= strlen(extension) && !strncmp(path + strlen(path) - strlen(extension), extension, strlen(extension)))
{
void* data = NULL;
int64_t size;
if(!bd_read_file(bd, path, &data, &size))
{
fprintf(stderr, "Error reading file from Blu-Ray!]\n");
return EXIT_FAILURE;
}
FILE* file = fopen(output_entry, "wb");
uint8_t unit[6144];
size_t unit_count = (size + sizeof(unit) - 1) / sizeof(unit);
for(int i = 0; i < unit_count; i++)
{
size_t unit_size = ((i + 1) * sizeof(unit) <= size) ? sizeof(unit) : size - i * sizeof(unit);
memcpy(unit, data + i * sizeof(unit), unit_size);
aacs_decrypt_unit(aacs, data + i * sizeof(unit));
fwrite(data + i * sizeof(unit), unit_size, 1, file);
}
fclose(file);
free(data);
}
else
{
//TODO: Error checking
uint8_t buffer[BUFFER_SIZE];
FILE* from = fopen(fpath, "rb");
FILE* to = fopen(output_entry, "wb");
size_t bytes_read = 0;
while((bytes_read = fread(buffer, 1, BUFFER_SIZE, from)) > 0)
{
fwrite(buffer, 1, bytes_read, to);
}
fclose(to);
fclose(from);
}
}
return 0;
}
int main(int argc, char* argv[])
{
if(argc < 3)
{
fprintf(stderr, "usage: %s <BD root> <output path> [key file]\n", argv[0]);
return EXIT_FAILURE;
}
disc_path = argv[1];
output_path = argv[2];
const char* keyfile_path = argc >= 4 ? argv[3] : NULL;
bd = bd_open(disc_path, keyfile_path);
if(!bd)
{
fprintf(stderr, "Error opening %s!\n", disc_path);
return EXIT_FAILURE;
}
const BLURAY_DISC_INFO* disc_info = bd_get_disc_info(bd);
if(!disc_info)
{
fprintf(stderr, "Error getting disc info!\n");
return EXIT_FAILURE;
}
if(!disc_info->aacs_detected)
{
fprintf(stderr, "Disc is not encrypted with AACS.\n");
return EXIT_SUCCESS;
}
if(!disc_info->libaacs_detected)
{
fprintf(stderr, "libaacs is not available!\n");
return EXIT_FAILURE;
}
int error_code;
aacs = aacs_open2(disc_path, keyfile_path, &error_code);
if(error_code != AACS_SUCCESS)
{
fprintf(stderr, "AACS handling failed: %s.\n", aacs_error_string(error_code));
return EXIT_FAILURE;
}
aacs_select_title(aacs, 0xffff);
ftw(disc_path, &fn, 16);
aacs_close(aacs);
bd_close(bd);
return EXIT_SUCCESS;
}