/// <summary> /// ibatrak очистка полей с количеством ссылок в заголовке записи /// </summary> public static void ClearItems(Stream stream, long offset) { //в заголовке проставляем 0 записей, сами ссылки не трогаем //ирбис так делает, проверено var ifpRecord = ReadLeader(stream, offset); //в записи со спец блоком зануляется только TotalLinkCount и оба поля во вложенных записях var special = ifpRecord.Special; if (!special) { ifpRecord.BlockLinkCount = 0; } ifpRecord.TotalLinkCount = 0; WriteLeader(stream, ifpRecord, offset); if (special) { //начитаем первую запись из спец блока, в ней ссылка на первую запись обыкновенного формата //остальные записи спец блока здесь не нужны var specBlock = new SpecialPostingBlockEntry[ifpRecord.Capacity]; var specBlockBuffer = new byte[ifpRecord.Capacity * SpecialPostingBlockEntry.RecordSize]; var fileOffset = stream.Position; if (stream.Read(specBlockBuffer, 0, specBlockBuffer.Length) != specBlockBuffer.Length) { throw new IOException(); } for (int i = 0; i < ifpRecord.Capacity; i++) { var entry = SpecialPostingBlockEntry.Read(specBlockBuffer, i * SpecialPostingBlockEntry.RecordSize); entry.FileOffset = fileOffset + i + SpecialPostingBlockEntry.RecordSize; specBlock[i] = entry; } var nonEmptyEntries = specBlock.Where(e => e.Offset > 0).Count(); if (nonEmptyEntries != ifpRecord.BlockLinkCount) { throw new InvalidOperationException("Ошибка чтения ifp offset=" + offset); } var nestedRecords = new IfpRecord[ifpRecord.BlockLinkCount]; for (int i = 0; i < ifpRecord.BlockLinkCount; i++) { if (specBlock[i].Offset <= 0 || (i > 0 && nestedRecords[i - 1].FullOffset != specBlock[i].Offset)) { throw new InvalidOperationException("Ошибка чтения ifp offset=" + offset); } var nestedRecord = ReadLeader(stream, specBlock[i].Offset); nestedRecord.BlockLinkCount = 0; nestedRecord.TotalLinkCount = 0; nestedRecords[i] = nestedRecord; WriteLeader(stream, ifpRecord, specBlock[i].Offset); } } }
public static IfpRecord Read ( Stream stream, long offset ) { //new ObjectDumper() // .DumpStream(stream, offset, 100); //ibatrak чтение лидера вынесено отдельно //stream.Position = offset; //IfpRecord result = new IfpRecord // { // LowOffset = stream.ReadInt32Network(), // HighOffset = stream.ReadInt32Network(), // TotalLinkCount = stream.ReadInt32Network(), // BlockLinkCount = stream.ReadInt32Network(), // Capacity = stream.ReadInt32Network(), // _FileOffset = offset // }; IfpRecord result = ReadLeader(stream, offset); //ibatrak чтение вложенных записей в спец блоке //Специальный формат записи .ifp //В этом случае первой записью является специальный блок, //который представляет собой заголовок (обыкновенного формата), в котором смещения имеют специальные значения = -1001, и набор вхождений следующего формата: //Число бит Параметр Описание //32 POSTING 1-я ссылка из записи обыкновенного формата //32 LOW младшее слово смещения на следующую запись (если нет 0) //32 HIGH старшее слово смещения на следующую запись (если нет 0) //Число вхождений кратно 4. Записи, на которые ссылается специальный блок связаны между собой как описано выше. //Общее количество ссылок для данного термина сохраняется только в специальном блоке. if (result.Special) { //irbis64.dll делает так //читает первые 24 байта блока спец ссылок //берет первую запись, адрес из нее в файле и читает записей IFP //по количеству result.BlockLinkCount //записи спец блока идут по количеству Capacity //каждая указывает на запись обычного формата //также в каждой записи обычного формата FullOffset указывает на следующую запись (кроме последней) //это должно соответствовать var specBlock = new SpecialPostingBlockEntry[result.Capacity]; var specBlockBuffer = new byte[result.Capacity * SpecialPostingBlockEntry.RecordSize]; var fileOffset = stream.Position; if (stream.Read(specBlockBuffer, 0, specBlockBuffer.Length) != specBlockBuffer.Length) { throw new IOException(); } for (int i = 0; i < result.Capacity; i++) { var entry = SpecialPostingBlockEntry.Read(specBlockBuffer, i * SpecialPostingBlockEntry.RecordSize); entry.FileOffset = fileOffset + i + SpecialPostingBlockEntry.RecordSize; specBlock[i] = entry; } //запомнить для редактирования result._SpecialBlock = specBlock; var nonEmptyEntries = specBlock.Where(e => e.Offset > 0).Count(); if (nonEmptyEntries != result.BlockLinkCount) { throw new InvalidOperationException("Ошибка чтения ifp offset=" + offset); } var nestedRecords = new IfpRecord[result.BlockLinkCount]; for (int i = 0; i < result.BlockLinkCount; i++) { if (specBlock[i].Offset <= 0 || (i > 0 && nestedRecords[i - 1].FullOffset != specBlock[i].Offset)) { throw new InvalidOperationException("Ошибка чтения ifp offset=" + offset); } var nestedRecord = Read(stream, specBlock[i].Offset); nestedRecords[i] = nestedRecord; } var links = nestedRecords.SelectMany(r => r.Links).ToArray(); if (links.Length != result.TotalLinkCount) { throw new InvalidOperationException("Ошибка чтения ifp offset=" + offset); } result.Links.AddRange(links); result._NestedRecordLeaders = nestedRecords.ToArray(); foreach (var r in nestedRecords) { r._links.Clear(); } return(result); } //ibatrak до сюда //ibatrak читаем ссылки за раз, так быстрее var linkBuffer = new byte[result.BlockLinkCount * TermLink.RecordSize]; if (stream.Read(linkBuffer, 0, linkBuffer.Length) != linkBuffer.Length) { throw new IOException(); } for (int i = 0; i < result.BlockLinkCount; i++) { TermLink link = TermLink.Read(linkBuffer, i * TermLink.RecordSize); result.Links.Add(link); } //for (int i = 0; i < result.BlockLinkCount; i++) //{ // TermLink link = TermLink.Read(stream); // result.Links.Add(link); //} return(result); }