@@ -438,74 +438,66 @@ func decompressRemainingBits(remainingBits uint32, remainingBitsLen uint8, numOf
438438 return nil
439439}
440440
441- // Zip compresses data using Huffman coding and writes the compressed data to the output stream.
442- // Zip compresses multiple files and writes the compressed data to the provided output writer.
443- // It first generates compression codes for the files, writes the number of files, and then processes each file individually.
444- // For each file, it compresses and writes the file name, writes a placeholder for the compressed size, compresses the file data,
445- // and then updates the placeholder with the actual compressed size.
446- //
447- // Parameters:
448- // - files: A slice of utils.FileData representing the files to be compressed.
449- // - output: An io.Writer where the compressed data will be written.
450- // - progressCallback: A callback function to report progress.
451- //
452- // Returns:
453- // - error: An error if any step in the compression process fails.
454- func Zip (files []utils.FileData , output io.Writer , progressCallback utils.ProgressCallback ) error {
455- codes , err := generateCodes (& files , output )
456- if err != nil {
457- return fmt .Errorf ("error preparing codes: %w" , err )
441+ // processFile handles the compression of a single file
442+ func processFileCompression (file utils.FileData , output io.Writer , codes map [rune ]string , progressCallback utils.ProgressCallback ) error {
443+ // Report progress for current file
444+ if progressCallback != nil {
445+ utils .UpdateProgress (utils.ProgressInfo {
446+ TotalFiles : 1 ,
447+ CurrentFile : 1 ,
448+ CurrentFileSize : file .Size ,
449+ Message : fmt .Sprintf ("Compressing file: %s" , filepath .Base (file .Name )),
450+ }, progressCallback )
451+ }
452+
453+ // Compress and write the file name
454+ if err := writeFileName (file .Name , output , codes ); err != nil {
455+ return fmt .Errorf (constants .FILE_WRITE_ERROR , err )
458456 }
459457
460- // Write the number of files
461- if err := writeNumOfFiles ( uint64 (len ( files )), output ); err != nil {
458+ // Write placeholder for compressed size
459+ if err := binary . Write ( output , binary . LittleEndian , uint64 (0 ) ); err != nil {
462460 return fmt .Errorf (constants .FILE_WRITE_ERROR , err )
463461 }
464462
465- for i , file := range files {
466- reader := file .Reader
463+ // Compress and write the data
464+ compressedLen , err := compressData (file .Reader , output , codes )
465+ if err != nil {
466+ return fmt .Errorf (constants .ERROR_COMPRESS , err )
467+ }
467468
468- // Report progress for current file
469- if progressCallback != nil {
470- utils .UpdateProgress (utils.ProgressInfo {
471- TotalFiles : len (files ),
472- CurrentFile : i + 1 ,
473- CurrentFileSize : file .Size ,
474- Message : fmt .Sprintf ("Compressing file: %s" , filepath .Base (file .Name )),
475- }, progressCallback )
476- }
469+ // Seek back to write the actual compressed size
470+ if _ , err := output .(io.Seeker ).Seek (- int64 (compressedLen + 8 ), io .SeekCurrent ); err != nil {
471+ return fmt .Errorf ("error seeking back to write the compressed size: %w" , err )
472+ }
477473
478- //Compress and write the file name
479- if err := writeFileName (file .Name , output , codes ); err != nil {
480- return fmt .Errorf (constants .FILE_WRITE_ERROR , err )
481- }
474+ if err := binary .Write (output , binary .LittleEndian , compressedLen ); err != nil {
475+ return fmt .Errorf (constants .FILE_WRITE_ERROR , err )
476+ }
482477
483- //write 64 bit 0 for the compressed size
484- if err := binary . Write ( output , binary . LittleEndian , uint64 ( 0 ) ); err != nil {
485- return fmt .Errorf (constants . FILE_WRITE_ERROR , err )
486- }
478+ // Seek back to the end
479+ if _ , err := output .(io. Seeker ). Seek ( 0 , io . SeekEnd ); err != nil {
480+ return fmt .Errorf ("error seeking to the end of the file: %w" , err )
481+ }
487482
488- //Compress and write the data
489- compressedLen , err := compressData (reader , output , codes )
490- if err != nil {
491- return fmt .Errorf (constants .ERROR_COMPRESS , err )
492- }
483+ return nil
484+ }
493485
494- //seek back to compressedLen bytes and write the compressed size
495- if _ , err := output .(io.Seeker ).Seek (- int64 (compressedLen + 8 ), io .SeekCurrent ); err != nil {
496- return fmt .Errorf ("error seeking back to write the compressed size: %w" , err )
497- }
486+ func Zip (files []utils.FileData , output io.Writer , progressCallback utils.ProgressCallback ) error {
487+ codes , err := generateCodes (& files , output )
488+ if err != nil {
489+ return fmt .Errorf ("error preparing codes: %w" , err )
490+ }
498491
499- if err := binary . Write ( output , binary . LittleEndian , compressedLen ); err != nil {
500- return fmt .Errorf (constants .FILE_WRITE_ERROR , err )
501- }
492+ if err := writeNumOfFiles ( uint64 ( len ( files )), output ); err != nil {
493+ return fmt .Errorf (constants .FILE_WRITE_ERROR , err )
494+ }
502495
503- //seek back to the end of the file
504- if _ , err := output .(io. Seeker ). Seek ( 0 , io . SeekEnd ); err != nil {
505- return fmt . Errorf ( "error seeking to the end of the file: %w" , err )
496+ for i , file := range files {
497+ if err := processFileCompression ( file , output , codes , progressCallback ); err != nil {
498+ return err
506499 }
507500
508- // Report progress after file is compressed
509501 if progressCallback != nil {
510502 utils .UpdateProgress (utils.ProgressInfo {
511503 TotalFiles : len (files ),
@@ -631,10 +623,36 @@ func readFileName(input io.Reader, codes map[rune]string) (string, error) {
631623 return name , nil
632624}
633625
634- // Unzip decompresses data from the provided io.Reader and writes the decompressed files to the specified output path.
626+ // processFile handles the decompression of a single file
627+ func processFile (input io.Reader , outputPath string , fileName string , codes map [rune ]string , progressCallback utils.ProgressCallback ) (string , error ) {
628+ fileName = filepath .Join (outputPath , fileName )
629+ dir := filepath .Dir (fileName )
630+
631+ if err := utils .MakeOutputDir (dir ); err != nil {
632+ return "" , fmt .Errorf (constants .ERROR_CREATE_DIR , err )
633+ }
634+
635+ outputFile , err := os .Create (fileName )
636+ if err != nil {
637+ return "" , fmt .Errorf (constants .FILE_CREATE_ERROR , err )
638+ }
639+ defer outputFile .Close ()
640+
641+ var compressedSize uint64
642+ if err := binary .Read (input , binary .LittleEndian , & compressedSize ); err != nil {
643+ return "" , fmt .Errorf (constants .FILE_READ_ERROR , err )
644+ }
645+
646+ if err := decompressData (input , outputFile , codes , compressedSize ); err != nil {
647+ return "" , fmt .Errorf (constants .ERROR_DECOMPRESS , err )
648+ }
649+
650+ return fileName , nil
651+ }
652+
635653func Unzip (input io.Reader , outputPath string , progressCallback utils.ProgressCallback ) ([]string , error ) {
636654 if outputPath == "" {
637- outputPath = "." // Use the current directory if no output path is provided
655+ outputPath = "."
638656 }
639657
640658 codes , err := ReadHuffmanCodes (input )
@@ -651,24 +669,14 @@ func Unzip(input io.Reader, outputPath string, progressCallback utils.ProgressCa
651669 return nil , errors .New ("no files to decompress" )
652670 }
653671
654- filePaths := []string {}
672+ filePaths := make ( []string , 0 , numOfFiles )
655673
656674 for i := uint64 (0 ); i < numOfFiles ; i ++ {
657- // get the file name
658675 fileName , err := readFileName (input , codes )
659676 if err != nil {
660677 return nil , err
661678 }
662679
663- fileName = filepath .Join (outputPath , fileName )
664-
665- dir := filepath .Dir (fileName )
666-
667- if err := utils .MakeOutputDir (dir ); err != nil {
668- return nil , fmt .Errorf (constants .ERROR_CREATE_DIR , err )
669- }
670-
671- // Report progress for current file
672680 if progressCallback != nil {
673681 utils .UpdateProgress (utils.ProgressInfo {
674682 TotalFiles : int (numOfFiles ),
@@ -677,28 +685,13 @@ func Unzip(input io.Reader, outputPath string, progressCallback utils.ProgressCa
677685 }, progressCallback )
678686 }
679687
680- // writer
681- outputFile , err := os .Create (fileName )
688+ filePath , err := processFile (input , outputPath , fileName , codes , progressCallback )
682689 if err != nil {
683- return nil , fmt .Errorf (constants .FILE_CREATE_ERROR , err )
684- }
685-
686- // read the compressed size
687- var compressedSize uint64
688- if err := binary .Read (input , binary .LittleEndian , & compressedSize ); err != nil {
689- return nil , fmt .Errorf (constants .FILE_READ_ERROR , err )
690- }
691-
692- err = decompressData (input , outputFile , codes , compressedSize )
693- if err != nil {
694- return nil , fmt .Errorf (constants .ERROR_DECOMPRESS , err )
690+ return nil , err
695691 }
696692
697- outputFile .Close ()
698-
699- filePaths = append (filePaths , fileName )
693+ filePaths = append (filePaths , filePath )
700694
701- // Report progress after file is decompressed
702695 if progressCallback != nil {
703696 utils .UpdateProgress (utils.ProgressInfo {
704697 TotalFiles : int (numOfFiles ),
0 commit comments