@@ -14,46 +14,35 @@ const (
1414 maxHeaderSize = 50 * 1024 * 1024 // 50MB for large tokenizer vocabularies
1515)
1616
17- // readHeader reads only the GGUF header (metadata) without reading tensor data
18- // This is much more efficient than reading the entire file
19- // The reader should be wrapped with io.LimitedReader to prevent OOM issues
20- func readHeader ( r io.Reader ) ([] byte , error ) {
21- // Read initial chunk to determine header size
17+ // copyHeader copies the GGUF header from the reader to the writer.
18+ // It validates the magic number first, then copies the rest of the data.
19+ // The reader should be wrapped with io.LimitedReader to prevent OOM issues.
20+ func copyHeader ( w io. Writer , r io.Reader ) error {
21+ // Read initial chunk to validate magic number
2222 // GGUF format: magic(4) + version(4) + tensor_count(8) + metadata_kv_count(8) + metadata_kvs + tensors_info
2323 initialBuf := make ([]byte , 24 ) // Enough for magic, version, tensor count, and kv count
2424 if _ , err := io .ReadFull (r , initialBuf ); err != nil {
25- return nil , fmt .Errorf ("failed to read GGUF header prefix: %w" , err )
25+ return fmt .Errorf ("failed to read GGUF header prefix: %w" , err )
2626 }
2727
2828 // Verify magic number
2929 magic := binary .LittleEndian .Uint32 (initialBuf [0 :4 ])
3030 if magic != ggufMagicNumber {
31- return nil , fmt .Errorf ("invalid GGUF magic number: 0x%08X" , magic )
31+ return fmt .Errorf ("invalid GGUF magic number: 0x%08X" , magic )
3232 }
3333
34- // We need to read the metadata KV pairs to know the full header size
35- // The io.LimitedReader wrapping this reader ensures we don't read more than maxHeaderSize
36- headerData := make ([] byte , 0 , 1024 * 1024 ) // Start with 1MB capacity
37- headerData = append ( headerData , initialBuf ... )
34+ // Write the initial buffer to the writer
35+ if _ , err := w . Write ( initialBuf ); err != nil {
36+ return fmt . Errorf ( "failed to write GGUF header prefix: %w" , err )
37+ }
3838
39- // Read the rest of the header in larger chunks for efficiency
39+ // Copy the rest of the header from reader to writer
4040 // The LimitedReader will return EOF once maxHeaderSize is reached
41- buf := make ([]byte , 64 * 1024 ) // 64KB chunks
42- for {
43- n , err := r .Read (buf )
44- if n > 0 {
45- headerData = append (headerData , buf [:n ]... )
46- }
47- if err == io .EOF {
48- // Reached end of file or limit, we have all available data
49- break
50- }
51- if err != nil {
52- return nil , fmt .Errorf ("failed to read GGUF header: %w" , err )
53- }
41+ if _ , err := io .Copy (w , r ); err != nil {
42+ return fmt .Errorf ("failed to copy GGUF header: %w" , err )
5443 }
5544
56- return headerData , nil
45+ return nil
5746}
5847
5948// Helper to convert gguf_parser metadata to simpler types
0 commit comments