/* * This file is part of the Aaru Data Preservation Suite. * Copyright (c) 2019-2025 Natalia Portillo. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include bool check_cd_sector_channel(CdEccContext *context, const uint8_t *sector, bool *unknown, bool *has_edc, bool *edc_correct, bool *has_ecc_p, bool *ecc_p_correct, bool *has_ecc_q, bool *ecc_q_correct) { uint32_t storedEdc = 0, edc = 0, calculatedEdc = 0; int size = 0, pos = 0; uint8_t zeroaddress[4]; *has_edc = false; *has_ecc_p = false; *has_ecc_q = false; *edc_correct = false; *ecc_p_correct = false; *ecc_q_correct = false; *unknown = false; if(sector[0x000] != 0x00 || sector[0x001] != 0xFF || sector[0x002] != 0xFF || sector[0x003] != 0xFF || sector[0x004] != 0xFF || sector[0x005] != 0xFF || sector[0x006] != 0xFF || sector[0x007] != 0xFF || sector[0x008] != 0xFF || sector[0x009] != 0xFF || sector[0x00A] != 0xFF || sector[0x00B] != 0x00) { *unknown = true; return false; } if((sector[0x00F] & 0x03) == 0x00) // Mode 0 { for(int i = 0x010; i < 0x930; i++) if(sector[i] != 0x00) { fprintf(stderr, "Mode 0 sector with error at address: %2X:%2X:%2X.\n", sector[0x00C], sector[0x00D], sector[0x00E]); return false; } return true; } if((sector[0x00F] & 0x03) == 0x01) // Mode 1 { if(sector[0x814] != 0x00 || // reserved (8 bytes) sector[0x815] != 0x00 || sector[0x816] != 0x00 || sector[0x817] != 0x00 || sector[0x818] != 0x00 || sector[0x819] != 0x00 || sector[0x81A] != 0x00 || sector[0x81B] != 0x00) { fprintf(stderr, "Mode 1 with data in reserved bytes at address: %2X:%2X:%2X.\n", sector[0x00C], sector[0x00D], sector[0x00E]); return false; } *has_edc = true; *has_ecc_p = true; *has_ecc_q = true; *ecc_p_correct = aaruf_ecc_cd_check(context, sector, sector, 86, 24, 2, 86, sector, 0xC, 0x10, 0x81C); *ecc_q_correct = aaruf_ecc_cd_check(context, sector, sector, 52, 43, 86, 88, sector, 0xC, 0x10, 0x81C + 0xAC); storedEdc = (sector[0x813] << 24) + (sector[0x812] << 16) + (sector[0x811] << 8) + sector[0x810]; // TODO: Check casting edc = 0; size = 0x810; pos = 0; for(; size > 0; size--) edc = edc >> 8 ^ context->edc_table[(edc ^ sector[pos++]) & 0xFF]; calculatedEdc = edc; *edc_correct = calculatedEdc == storedEdc; if(!*edc_correct) { fprintf(stderr, "Mode 1 sector at address: %2X:%2X:%2X, got CRC 0x%8X expected 0x%8X\n", sector[0x00C], sector[0x00D], sector[0x00E], calculatedEdc, storedEdc); } if(!*ecc_p_correct) { fprintf(stderr, "Mode 1 sector at address: %2X:%2X:%2X, fails ECC P check.\n", sector[0x00C], sector[0x00D], sector[0x00E]); } if(!*ecc_q_correct) { fprintf(stderr, "Mode 1 sector at address: %2X:%2X:%2X, fails ECC Q check.\n", sector[0x00C], sector[0x00D], sector[0x00E]); } return *edc_correct && *ecc_p_correct && *ecc_q_correct; } if((sector[0x00F] & 0x03) == 0x02) // Mode 2 { if((sector[0x012] & 0x20) == 0x20) // mode 2 form 2 { if(sector[0x010] != sector[0x014] || sector[0x011] != sector[0x015] || sector[0x012] != sector[0x016] || sector[0x013] != sector[0x017]) fprintf(stderr, "Subheader copies differ in mode 2 form 2 sector at address: %2X:%2X:%2X", sector[0x00C], sector[0x00D], sector[0x00E]); storedEdc = sector[0x91C]; if(storedEdc == 0) return true; *has_edc = true; storedEdc = (sector[0x81B] << 24) + (sector[0x81A] << 16) + (sector[0x819] << 8) + sector[0x818]; edc = 0; size = 0x808; pos = 0x10; for(; size > 0; size--) edc = edc >> 8 ^ context->edc_table[(edc ^ sector[pos++]) & 0xFF]; calculatedEdc = edc; *edc_correct = calculatedEdc == storedEdc; if(!*edc_correct) { fprintf(stderr, "Mode 2 sector at address: %2X:%2X:%2X, got CRC 0x%8X expected 0x%8X\n", sector[0x00C], sector[0x00D], sector[0x00E], calculatedEdc, storedEdc); } return *edc_correct; } *ecc_p_correct = aaruf_ecc_cd_check(context, zeroaddress, sector, 86, 24, 2, 86, sector, 0, 0x10, 0x81C); *ecc_q_correct = aaruf_ecc_cd_check(context, zeroaddress, sector, 52, 43, 86, 88, sector, 0, 0x10, 0x81C + 0xAC); storedEdc = sector[0x818]; // TODO: Check cast edc = 0; size = 0x808; pos = 0x10; for(; size > 0; size--) edc = edc >> 8 ^ context->edc_table[(edc ^ sector[pos++]) & 0xFF]; calculatedEdc = edc; *edc_correct = calculatedEdc == storedEdc; if(!*edc_correct) { fprintf(stderr, "Mode 2 sector at address: %2X:%2X:%2X, got CRC 0x%8X expected 0x%8X\n", sector[0x00C], sector[0x00D], sector[0x00E], calculatedEdc, storedEdc); } if(!*ecc_p_correct) { fprintf(stderr, "Mode 2 sector at address: %2X:%2X:%2X, fails ECC P check.\n", sector[0x00C], sector[0x00D], sector[0x00E]); } if(!*ecc_q_correct) { fprintf(stderr, "Mode 2 sector at address: %2X:%2X:%2X, fails ECC Q check.\n", sector[0x00C], sector[0x00D], sector[0x00E]); } return *edc_correct && *ecc_p_correct && *ecc_q_correct; } fprintf(stderr, "Unknown mode %d sector at address: %2X:%2X:%2X", sector[0x00F], sector[0x00C], sector[0x00D], sector[0x00E]); return false; }