public static IEnumerable <byte[]> Blocks(MYDBinaryReader br) { while (br.Position < br.Length) { MYDBlock root_block = MYDBlock.Read(br); //root_block.DumpStats(); long post_block_processing_return_offset = br.Position; // Only follow blocks that are a 'starting block' if (!root_block.is_block_first) { continue; } // Concatenate all blocks byte[] record_data = new byte[root_block.rec_len]; { MYDBlock block = root_block; int record_data_i = 0; while (true) { Array.Copy(block.data, 0, record_data, record_data_i, block.data_len); record_data_i += block.data_len; if (block.is_block_last) { break; } if (0 == block.next_filepos) { throw new GenericException("Expecting a file offset if we have more blocks!"); } br.Seek(block.next_filepos); //Logging.Info("Appending additional data from block at {0}", block.next_filepos); block = MYDBlock.Read(br); //block.DumpStats("\t"); } if (record_data_i != root_block.rec_len) { throw new GenericException("Block building length {0} is different to expected length of {1}!", record_data_i, root_block.rec_len); } } br.Seek(post_block_processing_return_offset); yield return(record_data); } }
internal static MYDBlock Read(MYDBinaryReader br) { MYDBlock block = new MYDBlock(); // Debugging purposes block.start_position = br.Position; // Start of header block.header = br.ReadByte(); block.rec_len = 0; block.data_len = 0; block.block_len = 0; block.next_filepos = 0; // See http://dev.mysql.com/doc/internals/en/layout-record-storage-frame.html // Or bottom of this code switch (block.header) { case 0: block.block_len = br.Read3(); block.block_len -= 4; // Deleted blocks include the header in their total length...sigh. block.is_block_deleted = true; break; case 1: block.rec_len = block.data_len = block.block_len = br.Read2(); block.is_block_first = block.is_block_last = true; break; case 2: block.rec_len = block.data_len = block.block_len = br.Read3(); block.is_block_first = block.is_block_last = true; break; case 13: block.rec_len = br.Read4(); block.data_len = block.block_len = br.Read3(); block.next_filepos = br.Read8(); block.is_block_first = true; break; case 3: block.rec_len = block.data_len = br.Read2(); block.block_len = block.rec_len + br.Read1(); block.is_block_first = block.is_block_last = true; break; case 4: block.rec_len = block.data_len = br.Read3(); block.block_len = block.rec_len + br.Read1(); block.is_block_first = block.is_block_last = true; break; case 5: block.rec_len = br.Read2(); block.data_len = block.block_len = br.Read2(); block.next_filepos = br.Read8(); block.is_block_first = true; break; case 6: block.rec_len = br.Read3(); block.data_len = block.block_len = br.Read3(); block.next_filepos = br.Read8(); block.is_block_first = true; break; case 7: block.data_len = block.block_len = br.Read2(); block.is_block_last = true; break; case 8: block.data_len = block.block_len = br.Read3(); block.is_block_last = true; break; case 9: block.data_len = br.Read2(); block.block_len = block.data_len + br.Read1(); block.is_block_last = true; break; case 10: block.data_len = br.Read3(); block.block_len = block.rec_len + br.Read1(); block.is_block_last = true; break; case 11: block.data_len = block.block_len = br.Read2(); block.next_filepos = br.Read8(); break; case 12: block.data_len = block.block_len = br.Read3(); block.next_filepos = br.Read8(); break; default: break; } block.data = br.ReadBytes(block.block_len); return(block); }