I know there's a DBI Stream. It's not parsing correctly or something

=== PDB File Information ===
Page Size: 4096
Number of Pages: 223165
Root Stream Size: 918732
Total Streams: 6859

=== Project/File Directory ===
Failed to parse DBI stream: failed to fill whole buffer

=== Types and Structures ===

use std::collections::HashMap;
use std::fs::File;
use std::io::{self, BufReader, Cursor, Read, Seek, SeekFrom};
use std::path::{Path, PathBuf};
use std::thread::sleep;
use std::time::Duration;

use byteorder::{LittleEndian, ReadBytesExt};

fn main() -> io::Result<()> {
    // Entry point of the PDB parsing program
    let args: Vec<String> = std::env::args().collect();
    if args.len() != 2 {
        eprintln!("Usage: {} <path_to_pdb_file>", args[0]);
        std::process::exit(1);
    }

    let pdb_path = &args[1];

    println!("Parsing PDB file: {}", pdb_path);

    // Open the PDB file
    let file = match File::open(pdb_path) {
        Ok(f) => f,
        Err(e) => {
            eprintln!("Failed to open file {}: {}", pdb_path, e);
            std::process::exit(1);
        }
    };
    let mut reader = BufReader::new(file);

    // Parse the PDB file
    let pdb = match PdbFile::parse(&mut reader) {
        Ok(pdb) => pdb,
        Err(e) => {
            eprintln!("Failed to parse PDB file: {}", e);
            std::process::exit(1);
        }
    };

    // Output the parsed information
    pdb.print_info();

    Ok(())
}

/// Represents a PDB file
struct PdbFile {
    page_size: u32,
    fpm_page: u32,
    num_pages: u32,
    root_stream_size: u32,
    root_stream_pages: Vec<u32>,
    streams: Vec<PdbStream>,
}

/// Represents a stream within the PDB file
struct PdbStream {
    size: u32,
    pages: Vec<u32>,
    data: Vec<u8>,
}

impl PdbFile {
    /// Parses the PDB file from the given reader
    fn parse(reader: &mut BufReader<File>) -> io::Result<Self> {
        // Read and parse the SuperBlock (first 64 bytes)
        let mut superblock = [0u8; 64];
        reader.read_exact(&mut superblock)?;

        // Verify the PDB signature
        let signature = &superblock[0..32];
        let expected_signature = b"Microsoft C/C++ MSF 7.00";
        if &signature[0..expected_signature.len()] != expected_signature {
            return Err(io::Error::new(
                io::ErrorKind::InvalidData,
                "Invalid PDB signature.",
            ));
        }

        // Parse SuperBlock fields
        let mut cursor = Cursor::new(&superblock);

        // Skip the signature (32 bytes)
        cursor.seek(SeekFrom::Start(32))?;

        // Read PDB header fields
        let page_size = cursor.read_u32::<LittleEndian>()?;
        let fpm_page = cursor.read_u32::<LittleEndian>()?;
        let num_pages = cursor.read_u32::<LittleEndian>()?;
        let root_stream_size = cursor.read_u32::<LittleEndian>()?;
        let _reserved = cursor.read_u32::<LittleEndian>()?;

        // Read Root Directory Index entries from SuperBlock
        let mut rdi_entries = Vec::new();
        while cursor.position() < 64 {
            let page_number = cursor.read_u32::<LittleEndian>()?;
            rdi_entries.push(page_number);
        }

        // Calculate the number of pages the directory stream spans
        let directory_size = root_stream_size;
        let directory_pages = Self::calculate_page_count(directory_size, page_size);

        // Calculate the number of entries needed in the Root Directory Index
        let entries_per_page = page_size / 4; // Number of u32s per page
        let num_rdi_entries = Self::calculate_page_count(directory_pages * 4, page_size);

        // Read the full Root Directory Index
        let root_dir_index_pages = if num_rdi_entries <= rdi_entries.len() as u32 {
            // Root Directory Index entries fit in SuperBlock
            rdi_entries[0..num_rdi_entries as usize].to_vec()
        } else {
            // Root Directory Index spans multiple levels
            Self::read_page_number_array(reader, page_size, &rdi_entries, num_rdi_entries)?
        };

        // Read the directory pages list from the Root Directory Index Pages
        let directory_pages_list = Self::read_page_number_array(
            reader,
            page_size,
            &root_dir_index_pages,
            directory_pages,
        )?;

        // Read the root directory stream data
        let root_stream_data =
            Self::read_stream(reader, page_size, &directory_pages_list, root_stream_size)?;

        // Parse the root directory stream
        let (streams, _stream_pages) =
            Self::parse_root_stream(&root_stream_data, page_size, reader)?;

        // Load the data for each stream
        let mut pdb_streams = Vec::new();
        for (i, (size, pages)) in streams.into_iter().enumerate() {
            if size == u32::MAX {
                // Stream does not exist
                pdb_streams.push(PdbStream {
                    size,
                    pages,
                    data: Vec::new(),
                });
                continue;
            }

            let data = Self::read_stream(reader, page_size, &pages, size)?;
            pdb_streams.push(PdbStream { size, pages, data });
        }

        Ok(PdbFile {
            page_size,
            fpm_page,
            num_pages,
            root_stream_size,
            root_stream_pages: directory_pages_list,
            streams: pdb_streams,
        })
    }

    /// Prints information about the PDB file
    fn print_info(&self) {
        use console::*;

        println!("Parsing PDB file completed.");

        println!();
        set_console_text_color(FOREGROUND_YELLOW | FOREGROUND_INTENSITY).unwrap();
        println!("=== PDB File Information ===");
        reset_console_text_color().unwrap();
        println!("Page Size: {}", self.page_size);
        println!("Number of Pages: {}", self.num_pages);
        println!("Root Stream Size: {}", self.root_stream_size);
        println!("Total Streams: {}", self.streams.len());
        println!();

        // Parse and print the project/file directory
        if let Some(stream) = self.streams.get(3) {
            set_console_text_color(FOREGROUND_GREEN | FOREGROUND_INTENSITY).unwrap();
            println!("=== Project/File Directory ===");
            reset_console_text_color().unwrap();
            self.parse_dbi_stream(stream).unwrap_or_else(|e| {
                eprintln!("Failed to parse DBI stream: {}", e);
            });
            println!();
        } else {
            println!("DBI Stream (Stream 3) not found.");
        }

        // Parse and print the types, structures, and classes
        if let Some(stream) = self.streams.get(2) {
            set_console_text_color(FOREGROUND_CYAN | FOREGROUND_INTENSITY).unwrap();
            println!("=== Types and Structures ===");
            reset_console_text_color().unwrap();
            self.parse_tpi_stream(stream).unwrap_or_else(|e| {
                eprintln!("Failed to parse TPI stream: {}", e);
            });
            println!();
        } else {
            println!("TPI Stream (Stream 2) not found.");
        }
    }

    /// Parses the DBI (Debug Information) Stream (Stream 3)
    fn parse_dbi_stream(&self, stream: &PdbStream) -> io::Result<()> {
        let mut cursor = Cursor::new(&stream.data);

        // Read DBI Stream Header
        let _signature = cursor.read_u32::<LittleEndian>()?;
        let _version = cursor.read_u32::<LittleEndian>()?;
        let _age = cursor.read_u32::<LittleEndian>()?;
        let _global_stream_index = cursor.read_u16::<LittleEndian>()?;
        let _build_number = cursor.read_u16::<LittleEndian>()?;
        let _public_stream_index = cursor.read_u16::<LittleEndian>()?;
        let _pdb_dll_version = cursor.read_u16::<LittleEndian>()?;
        let _sym_record_stream = cursor.read_u16::<LittleEndian>()?;
        let _pdb_dll_rbld = cursor.read_u16::<LittleEndian>()?;

        let module_info_size = cursor.read_i32::<LittleEndian>()?;
        let _section_contribution_size = cursor.read_i32::<LittleEndian>()?;
        let _section_map_size = cursor.read_i32::<LittleEndian>()?;
        let file_info_size = cursor.read_i32::<LittleEndian>()?;
        let _type_server_map_size = cursor.read_i32::<LittleEndian>()?;
        let _mfc_type_server_index = cursor.read_u32::<LittleEndian>()?;
        let _optional_dbg_header_size = cursor.read_i32::<LittleEndian>()?;
        let _ec_substream_size = cursor.read_i32::<LittleEndian>()?;
        let _flags = cursor.read_u16::<LittleEndian>()?;
        let _machine = cursor.read_u16::<LittleEndian>()?;
        let _reserved = cursor.read_u32::<LittleEndian>()?;

        // Read Module Info Substream
        let module_info_offset = cursor.position();
        let module_info_data = &stream.data
            [module_info_offset as usize..(module_info_offset + module_info_size as u64) as usize];
        let module_infos = self.parse_module_info_substream(module_info_data)?;

        // Move cursor past module_info
        cursor.seek(SeekFrom::Current(module_info_size as i64))?;

        // Skip Section Contribution, Section Map, and Type Server Map Substreams
        cursor.seek(SeekFrom::Current(
            _section_contribution_size as i64
                + _section_map_size as i64
                + _type_server_map_size as i64,
        ))?;

        // Read File Info Substream
        let file_info_offset = cursor.position();
        let file_info_data = &stream.data
            [file_info_offset as usize..(file_info_offset + file_info_size as u64) as usize];
        let file_info = self.parse_file_info_substream(file_info_data)?;

        // Build the directory tree
        let mut root = DirNode::new("".to_string());
        for module_file_info in &file_info.module_file_infos {
            let start = module_file_info.start_file_index as usize;
            let end = start + module_file_info.num_files as usize;
            if end > file_info.file_names.len() {
                return Err(io::Error::new(
                    io::ErrorKind::InvalidData,
                    "File index out of bounds",
                ));
            }
            for file_name in &file_info.file_names[start..end] {
                let path = Path::new(file_name);
                let components: Vec<&str> = path
                    .components()
                    .map(|comp| comp.as_os_str().to_str().unwrap_or(""))
                    .collect();
                root.add_path(&components);
            }
        }

        // Print the directory tree
        root.print("", true);

        Ok(())
    }

    /// Parses the Module Info Substream
    fn parse_module_info_substream(&self, data: &[u8]) -> io::Result<Vec<ModuleInfo>> {
        let mut cursor = Cursor::new(data);
        let mut module_infos = Vec::new();

        while (cursor.position() as usize) < data.len() {
            // Read the ModInfo structure
            let _unused = cursor.read_u32::<LittleEndian>()?;
            let _section = cursor.read_u16::<LittleEndian>()?;
            let _padding = cursor.read_u16::<LittleEndian>()?;
            let _flags = cursor.read_u16::<LittleEndian>()?;
            let _module_sym_stream = cursor.read_u16::<LittleEndian>()?;
            let _sym_bytes = cursor.read_u32::<LittleEndian>()?;
            let _c11_bytes = cursor.read_u32::<LittleEndian>()?;
            let _c13_bytes = cursor.read_u32::<LittleEndian>()?;
            let num_files = cursor.read_u16::<LittleEndian>()?;
            let _pdb_name_index = cursor.read_u16::<LittleEndian>()?;

            // Read null-terminated module name
            let module_name = read_null_terminated_string_from_cursor(&mut cursor)?;

            // Read null-terminated object file name
            let obj_file_name = read_null_terminated_string_from_cursor(&mut cursor)?;

            // Align cursor to next 4-byte boundary
            let pos = cursor.position();
            let aligned_pos = (pos + 3) & !3;
            if aligned_pos > pos {
                cursor.seek(SeekFrom::Start(aligned_pos))?;
            }

            module_infos.push(ModuleInfo {
                module_name,
                obj_file_name,
                num_files,
            });
        }

        Ok(module_infos)
    }

    /// Parses the File Info Substream
    fn parse_file_info_substream(&self, data: &[u8]) -> io::Result<FileInfo> {
        let mut cursor = Cursor::new(data);

        let num_modules = cursor.read_u16::<LittleEndian>()?;
        let num_source_files = cursor.read_u16::<LittleEndian>()?;

        // Read Module File Info entries
        let mut module_file_infos: Vec<ModuleFileInfo> = Vec::with_capacity(num_modules as usize);
        for _ in 0..num_modules {
            let num_files = cursor.read_u16::<LittleEndian>()?;
            let start_file_index = cursor.read_u16::<LittleEndian>()?;
            module_file_infos.push(ModuleFileInfo {
                num_files,
                start_file_index,
            });
        }

        // Read File Name Offsets
        let mut file_name_offsets: Vec<u32> = Vec::with_capacity(num_source_files as usize);
        for _ in 0..num_source_files {
            let offset = cursor.read_u32::<LittleEndian>()?;
            file_name_offsets.push(offset);
        }

        // The rest is the names buffer
        let name_buffer_offset = cursor.position() as usize;
        let name_buffer = &data[name_buffer_offset..];

        // Build a Vec of file names
        let mut file_names = Vec::with_capacity(num_source_files as usize);

        for &offset in &file_name_offsets {
            let name_offset = offset as usize;
            if name_offset >= name_buffer.len() {
                return Err(io::Error::new(
                    io::ErrorKind::InvalidData,
                    "File name offset out of bounds",
                ));
            }
            let name = read_null_terminated_string(&name_buffer[name_offset..])?;
            file_names.push(name);
        }

        Ok(FileInfo {
            module_file_infos,
            file_names,
        })
    }

    /// Parses the TPI (Type Information) Stream (Stream 2)
    fn parse_tpi_stream(&self, stream: &PdbStream) -> io::Result<()> {
        let mut cursor = Cursor::new(&stream.data);

        // Read TPI Stream Header
        let version = cursor.read_u32::<LittleEndian>()?;
        let _header_size = cursor.read_u32::<LittleEndian>()?;
        let type_index_begin = cursor.read_u32::<LittleEndian>()?;
        let type_index_end = cursor.read_u32::<LittleEndian>()?;
        let type_record_bytes = cursor.read_u32::<LittleEndian>()?;
        let _hash_stream_index = cursor.read_u16::<LittleEndian>()?;
        let _hash_aux_stream_index = cursor.read_u16::<LittleEndian>()?;
        let _hash_key_size = cursor.read_u32::<LittleEndian>()?;
        let _num_hash_buckets = cursor.read_u32::<LittleEndian>()?;
        let _hash_value_buffer_offset = cursor.read_u32::<LittleEndian>()?;
        let _hash_value_buffer_length = cursor.read_u32::<LittleEndian>()?;
        let _index_offset_buffer_offset = cursor.read_u32::<LittleEndian>()?;
        let _index_offset_buffer_length = cursor.read_u32::<LittleEndian>()?;
        let _hash_adj_buffer_offset = cursor.read_u32::<LittleEndian>()?;
        let _hash_adj_buffer_length = cursor.read_u32::<LittleEndian>()?;

        println!("Total Type Records: {}", type_index_end - type_index_begin);

        // Read Type Records
        let mut type_records = Vec::new();
        let type_records_start = cursor.position() as usize;
        let type_records_end = type_records_start + type_record_bytes as usize;
        let type_records_data = &stream.data[type_records_start..type_records_end];
        let mut type_cursor = Cursor::new(type_records_data);

        while (type_cursor.position() as usize) < type_records_data.len() {
            let record_start = type_cursor.position();
            let record_length = type_cursor.read_u16::<LittleEndian>()?;
            let kind = type_cursor.read_u16::<LittleEndian>()?;

            let record_data = if record_length >= 2 {
                let data_length = (record_length - 2) as usize;
                let mut data = vec![0u8; data_length];
                type_cursor.read_exact(&mut data)?;
                data
            } else {
                Vec::new()
            };

            type_records.push(TypeRecord {
                kind,
                data: record_data,
            });

            // Handle special type records if needed

            // Align to even boundary
            let pos = type_cursor.position();
            if pos % 4 != 0 {
                let aligned_pos = ((pos + 3) / 4) * 4;
                if aligned_pos > pos {
                    type_cursor.seek(SeekFrom::Start(aligned_pos))?;
                }
            }
        }

        // Print types
        for record in &type_records {
            // For demonstration, print the type kind
            sleep(Duration::from_secs(1));
            println!("Type Kind: 0x{:04X}", record.kind);
            // Additional parsing can be implemented here to interpret type records
        }

        Ok(())
    }

    /// Reads an array of page numbers from the given pages
    fn read_page_number_array(
        reader: &mut BufReader<File>,
        page_size: u32,
        pages: &[u32],
        num_items: u32,
    ) -> io::Result<Vec<u32>> {
        let mut result = Vec::new();
        let mut items_to_read = num_items;
        let entries_per_page = page_size / 4;
        for &page in pages {
            let page_offset = page as u64 * page_size as u64;
            reader.seek(SeekFrom::Start(page_offset))?;

            // Read the entire page
            let mut buffer = vec![0u8; page_size as usize];
            reader.read_exact(&mut buffer)?;

            let mut cursor = Cursor::new(buffer);

            for _ in 0..entries_per_page {
                if items_to_read == 0 {
                    break;
                }
                let page_number = cursor.read_u32::<LittleEndian>()?;
                result.push(page_number);
                items_to_read -= 1;
            }

            if items_to_read == 0 {
                break;
            }
        }

        if items_to_read > 0 {
            return Err(io::Error::new(
                io::ErrorKind::UnexpectedEof,
                "Not enough data to read all page number entries.",
            ));
        }

        Ok(result)
    }

    /// Reads a stream from the file
    fn read_stream(
        reader: &mut BufReader<File>,
        page_size: u32,
        pages: &[u32],
        stream_size: u32,
    ) -> io::Result<Vec<u8>> {
        let mut stream_data = Vec::with_capacity(stream_size as usize);
        let mut remaining = stream_size as usize;

        for &page in pages {
            let page_offset = page as u64 * page_size as u64;
            reader.seek(SeekFrom::Start(page_offset))?;

            let bytes_to_read = std::cmp::min(page_size as usize, remaining);
            let mut buffer = vec![0u8; bytes_to_read];
            reader.read_exact(&mut buffer)?;
            stream_data.extend_from_slice(&buffer);
            remaining -= bytes_to_read;

            if remaining == 0 {
                break;
            }
        }

        Ok(stream_data)
    }

    /// Calculates the number of pages needed to store the given size
    fn calculate_page_count(size: u32, page_size: u32) -> u32 {
        (size + page_size - 1) / page_size
    }

    /// Parses the Root Stream Directory
    fn parse_root_stream(
        _root_stream_data: &[u8],
        _page_size: u32,
        _reader: &mut BufReader<File>,
    ) -> io::Result<(Vec<(u32, Vec<u32>)>, Vec<Vec<u32>>)> {
        let mut cursor = Cursor::new(_root_stream_data);

        // Read the number of streams
        let num_streams = cursor.read_u32::<LittleEndian>()?;

        // Read the sizes of each stream
        let mut stream_sizes = Vec::new();
        for _ in 0..num_streams {
            let size = cursor.read_u32::<LittleEndian>()?;
            stream_sizes.push(size);
        }

        // Read the page lists for each stream
        let mut stream_pages: Vec<Vec<u32>> = Vec::new();
        for &size in &stream_sizes {
            if size == u32::MAX {
                // Stream does not exist
                stream_pages.push(Vec::new());
                continue;
            }

            // Calculate the number of pages for this stream
            let num_pages = Self::calculate_page_count(size, _page_size);

            let mut pages = Vec::new();
            for _ in 0..num_pages {
                let page_number = cursor.read_u32::<LittleEndian>()?;
                pages.push(page_number);
            }
            stream_pages.push(pages);
        }

        // Pair sizes with their pages
        let streams: Vec<(u32, Vec<u32>)> =
            stream_sizes.into_iter().zip(stream_pages.clone()).collect();

        Ok((streams, stream_pages))
    }
}

/// Represents information about a module in the PDB
struct ModuleInfo {
    module_name: String,
    obj_file_name: String,
    num_files: u16,
}

/// Represents parsed file information from the File Info Substream
struct FileInfo {
    module_file_infos: Vec<ModuleFileInfo>,
    file_names: Vec<String>,
}

/// Represents module file information entry
struct ModuleFileInfo {
    num_files: u16,
    start_file_index: u16,
}

/// Represents a directory node in the directory tree
#[derive(Debug)]
struct DirNode {
    name: String,
    subdirs: HashMap<String, DirNode>,
    files: Vec<String>,
}

impl DirNode {
    fn new(name: String) -> Self {
        DirNode {
            name,
            subdirs: HashMap::new(),
            files: Vec::new(),
        }
    }

    fn add_path(&mut self, components: &[&str]) {
        if components.is_empty() {
            return;
        }
        if components.len() == 1 {
            self.files.push(components[0].to_string());
        } else {
            let subdir_name = components[0].to_string();
            let subdir = self
                .subdirs
                .entry(subdir_name.clone())
                .or_insert_with(|| DirNode::new(subdir_name));
            subdir.add_path(&components[1..]);
        }
    }

    fn print(&self, prefix: &str, is_last: bool) {
        if !self.name.is_empty() {
            let connector = if is_last { "└── " } else { "├── " };
            println!("{}{}{}", prefix, connector, self.name);
        }
        let new_prefix = if is_last {
            format!("{}    ", prefix)
        } else {
            format!("{}│   ", prefix)
        };

        let mut entries: Vec<&String> = self.subdirs.keys().collect();
        entries.sort();

        let total = entries.len() + self.files.len();
        let mut index = 0;

        for name in &entries {
            index += 1;
            let is_last = index == total;
            self.subdirs[*name].print(&new_prefix, is_last);
        }

        for (i, file) in self.files.iter().enumerate() {
            let is_last = index + i + 1 == total;
            let connector = if is_last { "└── " } else { "├── " };
            println!("{}{}{}", new_prefix, connector, file);
        }
    }
}

/// Represents a type record in the TPI stream
struct TypeRecord {
    kind: u16,
    data: Vec<u8>,
}

/// Reads a null-terminated string from a cursor
fn read_null_terminated_string_from_cursor(cursor: &mut Cursor<&[u8]>) -> io::Result<String> {
    let mut buf = Vec::new();
    loop {
        if cursor.position() >= cursor.get_ref().len() as u64 {
            return Err(io::Error::new(
                io::ErrorKind::UnexpectedEof,
                "Unexpected end of data while reading string",
            ));
        }
        let byte = cursor.read_u8()?;
        if byte == 0 {
            break;
        }
        buf.push(byte);
    }
    Ok(String::from_utf8_lossy(&buf).to_string())
}

/// Reads a null-terminated string from a byte slice
fn read_null_terminated_string(data: &[u8]) -> io::Result<String> {
    if let Some(pos) = data.iter().position(|&c| c == 0) {
        let s = String::from_utf8_lossy(&data[0..pos]).to_string();
        Ok(s)
    } else {
        Err(io::Error::new(
            io::ErrorKind::InvalidData,
            "String not null terminated",
        ))
    }
}

#[cfg(windows)]
mod console {
    use std::io;
    use std::ptr;
    use std::os::windows::io::RawHandle;

    pub const STD_OUTPUT_HANDLE: u32 = -11i32 as u32;

    // Console text attribute constants
    pub const FOREGROUND_BLACK: u16 = 0x0000;
    pub const FOREGROUND_BLUE: u16 = 0x0001;
    pub const FOREGROUND_GREEN: u16 = 0x0002;
    pub const FOREGROUND_CYAN: u16 = 0x0003;
    pub const FOREGROUND_RED: u16 = 0x0004;
    pub const FOREGROUND_MAGENTA: u16 = 0x0005;
    pub const FOREGROUND_YELLOW: u16 = 0x0006;
    pub const FOREGROUND_WHITE: u16 = 0x0007;
    pub const FOREGROUND_INTENSITY: u16 = 0x0008;

    #[link(name = "Kernel32")]
    extern "system" {
        fn GetStdHandle(nStdHandle: u32) -> RawHandle;
        fn SetConsoleTextAttribute(hConsoleHandle: RawHandle, wAttributes: u16) -> i32;
    }

    pub fn set_console_text_color(color: u16) -> io::Result<()> {
        unsafe {
            let handle = GetStdHandle(STD_OUTPUT_HANDLE);
            if handle == ptr::null_mut() {
                return Err(io::Error::new(
                    io::ErrorKind::Other,
                    "Failed to get standard output handle",
                ));
            }

            if SetConsoleTextAttribute(handle, color) == 0 {
                return Err(io::Error::new(
                    io::ErrorKind::Other,
                    "Failed to set console text attribute",
                ));
            }
        }
        Ok(())
    }

    pub fn reset_console_text_color() -> io::Result<()> {
        // Default console color is light gray (7)
        set_console_text_color(FOREGROUND_WHITE)
    }
}

#[cfg(not(windows))]
mod console {
    use std::io;

    pub fn set_console_text_color(_color: u16) -> io::Result<()> {
        Ok(())
    }

    pub fn reset_console_text_color() -> io::Result<()> {
        Ok(())
    }
}

` no using the pdb crate `