| // Назначим пропавшим секторам данных их наиболее вероятные позиции в исходном файле
// (для того, чтобы скопировать в восстановленный файл эти, предположительно лишь частично повреждённые сектора,
// в тех случаях, когда точное содержание сектора не может быть восстановлено с помощью ECC)
void Decoder::GuessPositionsOfLostSectors()
{
// Проверка, что расстояние между секторами first и last осталось таким же, как в исходном файле
// (что позволяет надеяться, что сектора между ними и вокруг них смещены аналогично)
auto matching = [&] (size_t first, size_t last) {
return data_sector_pos[last] - data_sector_pos[first] == G.data_sector_pos(last) - G.data_sector_pos(first);
};
size_t size = data_sector_pos.size(), first = 0, last = 0;
size_t first_first = size, latest_last = size-1; // эти значения будут задействованы, если нет ни одного сектора с известной позицией
if (size==0) return;
ui.Progress (ui.DECODER_GUESSING, 0, size, sizeof(data_sector_pos[0]));
// Найдём первый сектор, позиция которого в файле известна
while (data_sector_pos[first] == SECTOR_NOT_FOUND)
if (++first >= size)
goto done;
first_first = first;
// Цикл по всем сегментам массива, ограниченным с обоих сторон секторами с известной позицией
for(;;)
{
// Конец предыдущего сегмента становится началом следующего
latest_last = last = first;
// Найдём следующий сектор, позиция которого в файле известна
do {
if (++last >= size)
goto done;
} while (data_sector_pos[last] == SECTOR_NOT_FOUND);
// Оптимизация - пропустим вычисление pos, если между first и last всё равно нет других секторов
if (last==first+1) {first++; continue;}
// Если между first и last то же расстояние, что и в исходном файле, то позиции промежуточных секторов расставляются между ними,
// иначе - исходя из предположения, что данные остались на исходном месте (умнее всё равно ничего не придумаешь)
auto pos = matching(first,last)? data_sector_pos[first] : G.data_sector_pos(first);
while (++first!=last)
data_sector_pos[first] = (pos += SECTOR_SIZE);
}
// Теперь займёмся секторами до первого сектора с известной позицией и после последнего такого
done: first = first_first, last = latest_last;
// До первого first - если позиции трёх секторов first..first+2 консистентны, то мы берём их за базу
auto pos = (first+2 < size && matching(first,first+1) && matching(first,first+2))? data_sector_pos[first] : G.data_sector_pos(first);
while (first-- > 0)
data_sector_pos[first] = (pos>=SECTOR_SIZE? (pos -= SECTOR_SIZE) : G.data_sector_pos(first));
// После последнего last - если позиции трёх секторов last-2..last консистентны, то мы берём их за базу
pos = (last >= 2 && matching(last-1,last) && matching(last-2,last))? data_sector_pos[last] : G.data_sector_pos(last);
while (++last < size)
data_sector_pos[last] = (pos += SECTOR_SIZE);
}
|