@@ -2,7 +2,7 @@ use zlib_rs::c_api::*;
2
2
3
3
use libz_rs_sys:: {
4
4
gzFile_s, gzbuffer, gzclearerr, gzclose, gzclose_r, gzclose_w, gzdirect, gzdopen, gzerror,
5
- gzflush, gzoffset, gzopen, gzread, gztell, gzwrite,
5
+ gzflush, gzoffset, gzopen, gzputc , gzputs , gzread, gztell, gzwrite,
6
6
} ;
7
7
8
8
use std:: ffi:: { c_char, c_int, c_uint, c_void, CString } ;
@@ -878,6 +878,150 @@ fn gzoffset_gztell_error() {
878
878
}
879
879
}
880
880
881
+ #[ test]
882
+ fn gzputc_basic ( ) {
883
+ // Create a temporary directory that will be automatically removed when
884
+ // temp_dir goes out of scope.
885
+ let temp_dir_path = temp_base ( ) ;
886
+ let temp_dir = tempfile:: TempDir :: new_in ( temp_dir_path) . unwrap ( ) ;
887
+ let temp_path = temp_dir. path ( ) ;
888
+ let file_name = path ( temp_path, "output" ) ;
889
+
890
+ // Open a new gzip file for writing. Use direct (uncompressed) mode to make validation easier.
891
+ let file = unsafe {
892
+ gzopen (
893
+ CString :: new ( file_name. as_str ( ) ) . unwrap ( ) . as_ptr ( ) ,
894
+ CString :: new ( "wT" ) . unwrap ( ) . as_ptr ( ) ,
895
+ )
896
+ } ;
897
+ assert ! ( !file. is_null( ) ) ;
898
+ // Set a small buffer size to exercise more internal code paths.
899
+ assert_eq ! ( unsafe { gzbuffer( file, 8 ) } , 0 ) ;
900
+
901
+ // Write to the file one byte at a time, using gzputc.
902
+ const CONTENT : & [ u8 ] = b"sample text to test gzputc implementation" ;
903
+ for c in CONTENT {
904
+ assert_eq ! ( unsafe { gzputc( file, * c as _) } , * c as _) ;
905
+ }
906
+
907
+ // Close the file to flush any buffered writes.
908
+ assert_eq ! ( unsafe { gzclose( file) } , Z_OK ) ;
909
+
910
+ // Validate that the file contains the expected bytes.
911
+ let mut mode = 0 ;
912
+ #[ cfg( target_os = "windows" ) ]
913
+ {
914
+ mode |= libc:: O_BINARY ;
915
+ }
916
+ mode |= libc:: O_RDONLY ;
917
+ let fd = unsafe { libc:: open ( CString :: new ( file_name. as_str ( ) ) . unwrap ( ) . as_ptr ( ) , mode) } ;
918
+ assert_ne ! ( fd, -1 ) ;
919
+ // Try to read more than the expected amount of data, to ensure we get everything.
920
+ let mut buf = [ 0u8 ; CONTENT . len ( ) + 1 ] ;
921
+ let bytes_read = unsafe { libc:: read ( fd, buf. as_mut_ptr ( ) as * mut c_void , buf. len ( ) as _ ) } ;
922
+ assert_ne ! ( bytes_read, -1 ) ;
923
+ assert_eq ! ( & buf[ ..bytes_read as usize ] , CONTENT ) ;
924
+ assert_eq ! ( unsafe { libc:: close( fd) } , 0 ) ;
925
+ }
926
+
927
+ #[ test]
928
+ fn gzputc_error ( ) {
929
+ // gzputc on a null file handle should return -1.
930
+ assert_eq ! ( unsafe { gzputc( ptr:: null_mut( ) , 1 ) } , -1 ) ;
931
+
932
+ // gzputc on a read-only file handle should return -1.
933
+ let file = unsafe { gzdopen ( -2 , CString :: new ( "r" ) . unwrap ( ) . as_ptr ( ) ) } ;
934
+ assert ! ( !file. is_null( ) ) ;
935
+ assert_eq ! ( unsafe { gzputc( ptr:: null_mut( ) , 1 ) } , -1 ) ;
936
+ assert_eq ! ( unsafe { gzclose( file) } , Z_ERRNO ) ;
937
+
938
+ // Open an invalid file descriptor as a gzip write stream, with a small buffer,
939
+ // and use gzputc to write enough bytes to overflow the buffer and cause file I/O.
940
+ // The last gzputc call should return -1.
941
+ let file = unsafe { gzdopen ( -2 , CString :: new ( "wT" ) . unwrap ( ) . as_ptr ( ) ) } ;
942
+ const BUF_SIZE : usize = 10 ;
943
+ assert_eq ! ( unsafe { gzbuffer( file, BUF_SIZE as _) } , 0 ) ;
944
+ // In write mode, the internal input buffer is 2x the size specified via gzbuffer.
945
+ for _ in 0 ..BUF_SIZE * 2 {
946
+ assert_eq ! ( unsafe { gzputc( file, 1 ) } , 1 ) ;
947
+ }
948
+ assert_eq ! ( unsafe { gzputc( file, 1 ) } , -1 ) ;
949
+ assert_eq ! ( unsafe { gzclose( file) } , Z_ERRNO ) ;
950
+ }
951
+
952
+ #[ test]
953
+ fn gzputs_basic ( ) {
954
+ // Create a temporary directory that will be automatically removed when
955
+ // temp_dir goes out of scope.
956
+ let temp_dir_path = temp_base ( ) ;
957
+ let temp_dir = tempfile:: TempDir :: new_in ( temp_dir_path) . unwrap ( ) ;
958
+ let temp_path = temp_dir. path ( ) ;
959
+ let file_name = path ( temp_path, "output" ) ;
960
+
961
+ // Open a new gzip file for writing. Use direct (uncompressed) mode to make validation easier.
962
+ let file = unsafe {
963
+ gzopen (
964
+ CString :: new ( file_name. as_str ( ) ) . unwrap ( ) . as_ptr ( ) ,
965
+ CString :: new ( "wT" ) . unwrap ( ) . as_ptr ( ) ,
966
+ )
967
+ } ;
968
+ assert ! ( !file. is_null( ) ) ;
969
+ // Set a small buffer size to exercise more internal code paths.
970
+ assert_eq ! ( unsafe { gzbuffer( file, 8 ) } , 0 ) ;
971
+
972
+ // gzputs of a null string should return -1 rather than crashing.
973
+ assert_eq ! ( unsafe { gzputs( file, ptr:: null( ) ) } , -1 ) ;
974
+
975
+ // Write some data to the file using gzputs.
976
+ const CONTENT : [ & str ; 3 ] = [ "zlib " , "" , "string larger than the buffer size" ] ;
977
+ for s in CONTENT {
978
+ assert_eq ! (
979
+ unsafe { gzputs( file, CString :: new( s) . unwrap( ) . as_ptr( ) ) } ,
980
+ s. len( ) as _
981
+ ) ;
982
+ }
983
+
984
+ // Close the file to flush any buffered writes.
985
+ assert_eq ! ( unsafe { gzclose( file) } , Z_OK ) ;
986
+
987
+ // Validate that the file contains the expected bytes.
988
+ const EXPECTED : & str = "zlib string larger than the buffer size" ;
989
+ let mut mode = 0 ;
990
+ #[ cfg( target_os = "windows" ) ]
991
+ {
992
+ mode |= libc:: O_BINARY ;
993
+ }
994
+ mode |= libc:: O_RDONLY ;
995
+ let fd = unsafe { libc:: open ( CString :: new ( file_name. as_str ( ) ) . unwrap ( ) . as_ptr ( ) , mode) } ;
996
+ assert_ne ! ( fd, -1 ) ;
997
+ // Try to read more than the expected amount of data, to ensure we get everything.
998
+ let mut buf = [ 0u8 ; EXPECTED . len ( ) + 1 ] ;
999
+ let bytes_read = unsafe { libc:: read ( fd, buf. as_mut_ptr ( ) as * mut c_void , buf. len ( ) as _ ) } ;
1000
+ assert_ne ! ( bytes_read, -1 ) ;
1001
+ assert_eq ! ( & buf[ ..bytes_read as usize ] , EXPECTED . as_bytes( ) ) ;
1002
+ assert_eq ! ( unsafe { libc:: close( fd) } , 0 ) ;
1003
+ }
1004
+
1005
+ #[ test]
1006
+ fn gzputs_error ( ) {
1007
+ const CONTENT : & [ u8 ] = b"example\0 " ;
1008
+
1009
+ // gzputs on a null file handle should return -1.
1010
+ assert_eq ! (
1011
+ unsafe { gzputs( ptr:: null_mut( ) , CONTENT . as_ptr( ) . cast:: <c_char>( ) ) } ,
1012
+ -1
1013
+ ) ;
1014
+
1015
+ // gzputs on a read-only file handle should return -1.
1016
+ let file = unsafe { gzdopen ( -2 , CString :: new ( "r" ) . unwrap ( ) . as_ptr ( ) ) } ;
1017
+ assert ! ( !file. is_null( ) ) ;
1018
+ assert_eq ! (
1019
+ unsafe { gzputs( ptr:: null_mut( ) , CONTENT . as_ptr( ) . cast:: <c_char>( ) ) } ,
1020
+ -1
1021
+ ) ;
1022
+ assert_eq ! ( unsafe { gzclose( file) } , Z_ERRNO ) ;
1023
+ }
1024
+
881
1025
// Get the size in bytes of a file.
882
1026
//
883
1027
// # Returns
0 commit comments