1 (edited by reentrant 2025-03-18 20:31:00)

Hi,
New version of CDArchive is out with following new features:
- Automatic sector merging - no need to specify extrsectdir anymore (if specified, sectors will be dumped to the directory anyway)
- Automatic sector checking and repairing (both in the input image as well as those read by the drive) using ECC codes (RSPC). If a specific sector can be repaired (in the image) it is not read from the device.

List of removed dependencies:
- CDmage
- EccEdc

List of added dependencies:
- Python 3.12 - RS library - no C++ code available anywhere

Example command line:
CDArchive.exe --mode=ext --extrdrive=e --extrstart=100 --extrend=200 --extroverread=0 --extrskip=3 --extrdirection=f --extrdiscmode=cd --extrrefcue="d:\Storage\Sin\Sin.cue"

Example output:

Initialized C2 module
Extracting error range forward: 100 - 200
Repaired sector with C2: 150
Repaired sector with C2: 151
Repaired sector with C2: 152
Repaired sector with C2: 153
Repaired sector with C2: 154
Repaired sector with C2: 155
Repaired sector with C2: 156
Range direction result: 0 1

Extracted all sectors

Configuration:
- Install Python 3.12 (exactly this major version)
- Adjust PYTHONHOME variable in config file: Plugins\C2Corrector\C2Corrector.ini
- Copy python312.dll from Python installation directory to Plugins\C2Corrector directory

And that's it - no more tedious merging, fixing, checking...

Post's attachments

CDArchive.7z 350.04 kb, 3 downloads since 2025-03-18 

You don't have the permssions to download the attachments of this post.

2 (edited by reentrant 2025-03-18 21:23:59)

C2Corrector API (Plugins/C2Corrector/C2Corrector.DLL):

#pragma pack(push, 1)
typedef struct _C2_CORRECTOR_INIT {
    PVOID pythonEccP;
    PVOID pythonEccQ;
} C2_CORRECTOR_INIT, *PC2_CORRECTOR_INIT;
#pragma pack(pop)

// InitC2
typedef DWORD (WINAPI *pInitC2)(PC2_CORRECTOR_INIT c2InitBlock);

#pragma pack(push, 1)
typedef struct _C2_CORRECTOR_HANDLE {
    PVOID pythonEccP; // C2_CORRECTOR_INIT.pythonEccP
    PVOID pythonEccQ; // C2_CORRECTOR_INIT.pythonEccQ
    PUCHAR sectorData; // Length: 2352 bytes
    PUCHAR c2Pointers; // Length: 2352 / 8 bytes
    PUCHAR c2Repaired; // Length: 2352 / 8 bytes
} C2_CORRECTOR_HANDLE, *PC2_CORRECTOR_HANDLE;
#pragma pack(pop)

// HandleC2
typedef DWORD (WINAPI *pHandleC2)(PC2_CORRECTOR_HANDLE c2HandleBlock);

Steps:
1) Call InitC2 once in main
2) Call HandleC2 multiple times on each re-read

How it works:
ECC (ECCP / ECCQ) code inside data sector (mode 1 / mode 2) is in fact a Reed-Solomon code.
ECCP = RS(26,24) - difference = 2. It means 1 error can be corrected for a row of 26 bytes (or 2 positions without correcting).
ECCQ = RS(45,43) - difference = 2. It means 1 error can be a corrected for a row of 45 bytes (or 2 positions without correcting).

When you combine the RS algorithm with C2 pointers from the device and use the pointers as erasures it's possible to increase algorithm strength twice (2 errors can be corrected).

C2Corrector does just that - it uses C2 pointers as erasures (positions of invalid bytes) and tries to repair the data. Bytes that were repaired are recorded in c2Repaired buffer. This buffer should be combined with C2 buffer received from the device + appropriate repaired bytes should be replaced with data from sectorData buffer.

That's also how drives work internally. Depending on the manufacturer number of iterations varies (re-read + repair). Some are worse, some are better...

Hi reentrant, is this an alternative to DIC?

4 (edited by reentrant 2025-03-21 20:03:23)

Hi ssjkakaroto, no, it's just a brute-force tool to improve DIC's output...

While potentially useful having CDarchive  repair sectors as it extracts them sounds risky.

reentrant wrote:

Steps:
1) Call InitC2 once in main
2) Call HandleC2 multiple times on each re-read

If possible, please show me the sample code to call these func.

7 (edited by reentrant 2025-03-23 13:51:25)

Morlit wrote:

While potentially useful having CDarchive  repair sectors as it extracts them sounds risky.

Potentially yes, I only use it for hardcore cases like fetching more sectors from the rings...

sarami wrote:
reentrant wrote:

Steps:
1) Call InitC2 once in main
2) Call HandleC2 multiple times on each re-read

If possible, please show me the sample code to call these func.

DWORD C2Handler::corruptSectorForP(PC2_CORRECTOR_HANDLE c2HandleBlock, DWORD vectorNo, DWORD errorCount, BOOL enablePointers) {
    if(vectorNo >= 43)
        return ERROR_INVALID_PARAMETER;

    PUCHAR dataBuffer = c2HandleBlock->sectorData;
    
    errorCount = min(errorCount, 26);

    for(DWORD i = 0; i < errorCount; ++i) {
        DWORD dataIndex = userDataOffset + 2 * (43 * i + vectorNo) + 1;

        DEBUGPRINTWO(L"Corrupting P vector: 0x%03X: 0x%02X -> 0x%02X\n", dataIndex, dataBuffer[dataIndex], dataBuffer[dataIndex] + 1);

        ++dataBuffer[dataIndex];

        if(enablePointers && c2HandleBlock->c2Pointers) {
            PUCHAR c2Pointer = &c2HandleBlock->c2Pointers[dataIndex >> 3];
            *c2Pointer |= (0x1 << (dataIndex & 0x7));
        }
    }

    return 0;
}

DWORD C2Handler::corruptSectorForQ(PC2_CORRECTOR_HANDLE c2HandleBlock, DWORD vectorNo, DWORD errorCount, BOOL enablePointers) {
    if(vectorNo >= 26)
        return ERROR_INVALID_PARAMETER;

    PUCHAR dataBuffer = c2HandleBlock->sectorData;
    
    errorCount = min(errorCount, 43);

    for(DWORD i = 0; i < errorCount; ++i) {
        DWORD dataIndex = userDataOffset + 2 * ((43 * vectorNo + 44 * i) % 1118);

        DEBUGPRINTWO(L"Corrupting Q vector: 0x%03X: 0x%02X -> 0x%02X\n", dataIndex, dataBuffer[dataIndex], dataBuffer[dataIndex] + 1);

        ++dataBuffer[dataIndex];

        if(enablePointers && c2HandleBlock->c2Pointers) {
            PUCHAR c2Pointer = &c2HandleBlock->c2Pointers[dataIndex >> 3];
            *c2Pointer |= (0x1 << (dataIndex & 0x7));
        }
    }

    return 0;
}

#include "C2Handler.hpp"

#include <FileOps/FileOps.hpp>

DWORD WINAPI InitC2(PC2_CORRECTOR_INIT c2InitBlock) {
    return C2Handler::initC2(c2InitBlock);
}

DWORD WINAPI HandleC2(PC2_CORRECTOR_HANDLE c2HandleBlock) {
    return C2Handler::handleC2(c2HandleBlock);
}
#ifdef _DEBUG
int main() {
    C2_CORRECTOR_INIT c2InitBlock = {};

    DWORD retVal = InitC2(&c2InitBlock);
    if(!retVal) {
        UCHAR sectorData[2352];
        UCHAR c2Pointers[2352 / 8] = {};
        UCHAR c2Repaired[2352 / 8] = {};

        if(!(retVal = FileOps::readData(L"sector.data.in", sectorData, sizeof(sectorData)))) {
            C2_CORRECTOR_HANDLE c2HandleBlock = {};
            c2HandleBlock.pythonEccP = c2InitBlock.pythonEccP;
            c2HandleBlock.pythonEccQ = c2InitBlock.pythonEccQ;
            c2HandleBlock.sectorData = sectorData;
            c2HandleBlock.c2Pointers = c2Pointers;
            c2HandleBlock.c2Repaired = c2Repaired;

            //C2Handler::corruptSectorForP(&c2HandleBlock, 0, 2, FALSE);
            //retVal = HandleC2(&c2HandleBlock);

            //C2Handler::corruptSectorForP(&c2HandleBlock, 0, 3, TRUE);
            //retVal = HandleC2(&c2HandleBlock);

            C2Handler::corruptSectorForQ(&c2HandleBlock, 0, 2, TRUE);
            retVal = HandleC2(&c2HandleBlock);

            FileOps::writeData(L"sector.data.out", c2HandleBlock.sectorData, sizeof(sectorData));
            FileOps::writeData(L"sector.c2pre.out", c2HandleBlock.c2Pointers, sizeof(c2Pointers));
            FileOps::writeData(L"sector.c2post.out", c2HandleBlock.c2Repaired, sizeof(c2Repaired));
        }
    }

    return retVal ? EXIT_FAILURE : EXIT_SUCCESS;
}
#else
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) {
    return TRUE;
}
#endif

Keep in mind, when you pass c2Pointers bitmap, ECC algorithm will only repair bytes which are marked as 1 in C2 bitmap. If the repair is successful bits in c2Repaired bitmap will be set and it's up to you to merge c2Repaired bitmap + write appropriate bytes from sectorData into the image file...

reentrant wrote:

Configuration:
- Install Python 3.12 (exactly this major version)
- Adjust PYTHONHOME variable in config file: Plugins\C2Corrector\C2Corrector.ini
- Copy python312.dll from Python installation directory to Plugins\C2Corrector directory

Is python312.dll 64-bit only? Or does it work in 32bit dll? Are C2Corrector.dll and boost_python312-vc143-mt-x64-1_87.dll also 64bit only? It fails to load using LoadLibrary.

Python 3.12 x86: https://www.python.org/ftp/python/3.12. … 3.12.9.exe

32bit DLL in attachment.

Post's attachments

32.7z 67.56 kb, 1 downloads since 2025-03-26 

You don't have the permssions to download the attachments of this post.

reentrant wrote:

32bit DLL in attachment.

Thanks. I implemented it but error occurs.

Could not find platform independent libraries <prefix>
Need to reread sector:  13164LBA: 13164, C2 error count; 0
Need to reread sector:  13201Exception ignored in garbage collection:
Traceback (most recent call last):
  File "E:\source\repos\DiscImageCreator\Release_ANSI\Plugins\C2Corrector\reedsolo.py", line 984, in decode
    total_chunks = int(math.ceil(float(len(data)) / float(chunk_size)))  # need to convert to floats first to get an accurate floating division, or else we assume implicit conversion and it will cause an error on Python 2
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
SystemError: <class 'int'> returned a result with an exception set
LBA: 13201, C2 error count; 0
Need to reread sector:  13211Exception ignored in garbage collection:
Traceback (most recent call last):
  File "E:\source\repos\DiscImageCreator\Release_ANSI\Plugins\C2Corrector\reedsolo.py", line 984, in decode
    total_chunks = int(math.ceil(float(len(data)) / float(chunk_size)))  # need to convert to floats first to get an accurate floating division, or else we assume implicit conversion and it will cause an error on Python 2
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
SystemError: <class 'int'> returned a result with an exception set
LBA: 13211, C2 error count; 0
Need to reread sector:  13248LBA: 13248, C2 error count; 0
Need to reread sector:  13257Exception ignored in garbage collection:
Traceback (most recent call last):
  File "E:\source\repos\DiscImageCreator\Release_ANSI\Plugins\C2Corrector\reedsolo.py", line 984, in decode
    total_chunks = int(math.ceil(float(len(data)) / float(chunk_size)))  # need to convert to floats first to get an accurate floating division, or else we assume implicit conversion and it will cause an error on Python 2
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
SystemError: <class 'int'> returned a result with an exception set
LBA: 13257, C2 error count; 0
Need to reread sector:  13266Exception ignored in garbage collection:
Traceback (most recent call last):
  File "E:\source\repos\DiscImageCreator\Release_ANSI\Plugins\C2Corrector\reedsolo.py", line 984, in decode
    total_chunks = int(math.ceil(float(len(data)) / float(chunk_size)))  # need to convert to floats first to get an accurate floating division, or else we assume implicit conversion and it will cause an error on Python 2
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
SystemError: <class 'int'> returned a result with an exception set
LBA: 13266, C2 error count; 0
Need to reread sector:  13267LBA: 13267, C2 error count; 0
Need to reread sector:  13285Exception ignored in garbage collection:
Traceback (most recent call last):
  File "E:\source\repos\DiscImageCreator\Release_ANSI\Plugins\C2Corrector\reedsolo.py", line 984, in decode
    total_chunks = int(math.ceil(float(len(data)) / float(chunk_size)))  # need to convert to floats first to get an accurate floating division, or else we assume implicit conversion and it will cause an error on Python 2
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
SystemError: <class 'int'> returned a result with an exception set
LBA: 13285, C2 error count; 0
Need to reread sector:  13294Exception ignored in garbage collection:
Traceback (most recent call last):
  File "E:\source\repos\DiscImageCreator\Release_ANSI\Plugins\C2Corrector\reedsolo.py", line 984, in decode
    total_chunks = int(math.ceil(float(len(data)) / float(chunk_size)))  # need to convert to floats first to get an accurate floating division, or else we assume implicit conversion and it will cause an error on Python 2
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
SystemError: <class 'int'> returned a result with an exception set
LBA: 13294, C2 error count; 0
Need to reread sector:  13295Exception ignored in garbage collection:
Traceback (most recent call last):
  File "E:\source\repos\DiscImageCreator\Release_ANSI\Plugins\C2Corrector\reedsolo.py", line 984, in decode
    total_chunks = int(math.ceil(float(len(data)) / float(chunk_size)))  # need to convert to floats first to get an accurate floating division, or else we assume implicit conversion and it will cause an error on Python 2
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
SystemError: <class 'int'> returned a result with an exception set
LBA: 13295, C2 error count; 0
Need to reread sector:  13322LBA: 13322, C2 error count; 0
Need to reread sector:  99879Exception ignored in garbage collection:
Traceback (most recent call last):
  File "E:\source\repos\DiscImageCreator\Release_ANSI\Plugins\C2Corrector\reedsolo.py", line 984, in decode
    total_chunks = int(math.ceil(float(len(data)) / float(chunk_size)))  # need to convert to floats first to get an accurate floating division, or else we assume implicit conversion and it will cause an error on Python 2
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
SystemError: <class 'int'> returned a result with an exception set
LBA: 99879, C2 error count; 0
Need to reread sector:  99880Exception ignored in garbage collection:
Traceback (most recent call last):
  File "E:\source\repos\DiscImageCreator\Release_ANSI\Plugins\C2Corrector\reedsolo.py", line 984, in decode
    total_chunks = int(math.ceil(float(len(data)) / float(chunk_size)))  # need to convert to floats first to get an accurate floating division, or else we assume implicit conversion and it will cause an error on Python 2
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
SystemError: <class 'int'> returned a result with an exception set
LBA: 99880, C2 error count; 0
Need to reread sector:  99892LBA: 99892, C2 error count; 0
Need to reread sector:  99893Exception ignored in garbage collection:
Traceback (most recent call last):
  File "E:\source\repos\DiscImageCreator\Release_ANSI\Plugins\C2Corrector\reedsolo.py", line 984, in decode
    total_chunks = int(math.ceil(float(len(data)) / float(chunk_size)))  # need to convert to floats first to get an accurate floating division, or else we assume implicit conversion and it will cause an error on Python 2
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
SystemError: <class 'int'> returned a result with an exception set
LBA: 99893, C2 error count; 0
Need to reread sector: 100108Exception ignored in garbage collection:
Traceback (most recent call last):
  File "E:\source\repos\DiscImageCreator\Release_ANSI\Plugins\C2Corrector\reedsolo.py", line 984, in decode
    total_chunks = int(math.ceil(float(len(data)) / float(chunk_size)))  # need to convert to floats first to get an accurate floating division, or else we assume implicit conversion and it will cause an error on Python 2
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
SystemError: <class 'int'> returned a result with an exception set
LBA: 100108, C2 error count; 0
Need to reread sector: 100162LBA: 100162, C2 error count; 0
Need to reread sector: 100163Exception ignored in garbage collection:
Traceback (most recent call last):
  File "E:\source\repos\DiscImageCreator\Release_ANSI\Plugins\C2Corrector\reedsolo.py", line 984, in decode
    total_chunks = int(math.ceil(float(len(data)) / float(chunk_size)))  # need to convert to floats first to get an accurate floating division, or else we assume implicit conversion and it will cause an error on Python 2
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
SystemError: <class 'int'> returned a result with an exception set
LBA: 100163, C2 error count; 0
Need to reread sector: 100175Exception ignored in garbage collection:
Traceback (most recent call last):
  File "E:\source\repos\DiscImageCreator\Release_ANSI\Plugins\C2Corrector\reedsolo.py", line 984, in decode
    total_chunks = int(math.ceil(float(len(data)) / float(chunk_size)))  # need to convert to floats first to get an accurate floating division, or else we assume implicit conversion and it will cause an error on Python 2
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
SystemError: <class 'int'> returned a result with an exception set
LBA: 100175, C2 error count; 0
Need to reread sector: 100176LBA: 100176, C2 error count; 0
Need to reread sector: 100189Exception ignored in garbage collection:
Traceback (most recent call last):
  File "E:\source\repos\DiscImageCreator\Release_ANSI\Plugins\C2Corrector\reedsolo.py", line 984, in decode
    total_chunks = int(math.ceil(float(len(data)) / float(chunk_size)))  # need to convert to floats first to get an accurate floating division, or else we assume implicit conversion and it will cause an error on Python 2
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
SystemError: <class 'int'> returned a result with an exception set
LBA: 100189, C2 error count; 0
Need to reread sector: 100215Exception ignored in garbage collection:
Traceback (most recent call last):
  File "E:\source\repos\DiscImageCreator\Release_ANSI\Plugins\C2Corrector\reedsolo.py", line 984, in decode
    total_chunks = int(math.ceil(float(len(data)) / float(chunk_size)))  # need to convert to floats first to get an accurate floating division, or else we assume implicit conversion and it will cause an error on Python 2
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
SystemError: <class 'int'> returned a result with an exception set
LBA: 100215, C2 error count; 0
Need to reread sector: 100216LBA: 100216, C2 error count; 0

code is here. What am I wrong?

    C2_CORRECTOR_INIT c2InitBlock = {};

    DWORD retVal = pDisc->C2.InitC2(&c2InitBlock);
    if (!retVal) {
        C2_CORRECTOR_HANDLE c2HandleBlock = {};
        c2HandleBlock.pythonEccP = c2InitBlock.pythonEccP;
        c2HandleBlock.pythonEccQ = c2InitBlock.pythonEccQ;
        c2HandleBlock.sectorData = pDiscPerSector->data.current;
        c2HandleBlock.c2Pointers = pDiscPerSector->data.next + CD_RAW_READ_C2_294_SIZE;
        c2HandleBlock.c2Repaired = c2Repaired;
        for (UINT h = 0; h < pExtArg->uiMaxRereadNum; h++) {
            nErrCnt = 0;
            retVal = pDisc->C2.HandleC2(&c2HandleBlock);
            for (INT i = 0; i < CD_RAW_READ_C2_294_SIZE; i++) {
                if (c2HandleBlock.c2Repaired[i] != 0) {
                    INT nBit = 0x80;
                    for (INT n = 0; n < CHAR_BIT; n++) {
                        if (c2HandleBlock.c2Repaired[i] & nBit) {
                            nErrCnt++;
                        }
                        nBit >>= 1;
                    }
                }
            }
            OutputLog(standardError | fileC2Error, "LBA: %d, C2 error count; %d\n", nLBA, nErrCnt);
            if (!nErrCnt) {
                break;
            }
        }
    }

> Could not find platform independent libraries <prefix>

This is critical problem - I'll test it over the weekend but in the meantime, did you adjust the path in C2Corrector.ini?

reentrant wrote:

did you adjust the path in C2Corrector.ini?

I set it.

PYTHONHOME = C:\Users\xxx\AppData\Local\Programs\Python\Python312-32