common.odin 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. package compress
  2. import "core:io"
  3. import "core:image"
  4. // Error helper, e.g. is_kind(err, General_Error.OK);
  5. is_kind :: proc(u: $U, x: $V) -> bool {
  6. v, ok := u.(V);
  7. return ok && v == x;
  8. }
  9. Error :: union {
  10. General_Error,
  11. Deflate_Error,
  12. ZLIB_Error,
  13. GZIP_Error,
  14. ZIP_Error,
  15. /*
  16. This is here because png.load will return a this type of error union,
  17. as it may involve an I/O error, a Deflate error, etc.
  18. */
  19. image.PNG_Error,
  20. }
  21. General_Error :: enum {
  22. OK = 0,
  23. File_Not_Found,
  24. Cannot_Open_File,
  25. File_Too_Short,
  26. Stream_Too_Short,
  27. Output_Too_Short,
  28. Unknown_Compression_Method,
  29. Checksum_Failed,
  30. Incompatible_Options,
  31. Unimplemented,
  32. }
  33. GZIP_Error :: enum {
  34. Invalid_GZIP_Signature,
  35. Reserved_Flag_Set,
  36. Invalid_Extra_Data,
  37. Original_Name_Too_Long,
  38. Comment_Too_Long,
  39. Payload_Length_Invalid,
  40. Payload_CRC_Invalid,
  41. }
  42. ZIP_Error :: enum {
  43. Invalid_ZIP_File_Signature,
  44. Unexpected_Signature,
  45. Insert_Next_Disk,
  46. Expected_End_of_Central_Directory_Record,
  47. }
  48. ZLIB_Error :: enum {
  49. Unsupported_Window_Size,
  50. FDICT_Unsupported,
  51. Unsupported_Compression_Level,
  52. Code_Buffer_Malformed,
  53. }
  54. Deflate_Error :: enum {
  55. Huffman_Bad_Sizes,
  56. Huffman_Bad_Code_Lengths,
  57. Inflate_Error,
  58. Bad_Distance,
  59. Bad_Huffman_Code,
  60. Len_Nlen_Mismatch,
  61. BType_3,
  62. }
  63. // General context for ZLIB, LZW, etc.
  64. Context :: struct {
  65. code_buffer: u32,
  66. num_bits: i8,
  67. /*
  68. num_bits will be set to -100 if the buffer is malformed
  69. */
  70. eof: b8,
  71. input: io.Stream,
  72. output: io.Stream,
  73. bytes_written: i64,
  74. // Used to update hash as we write instead of all at once
  75. rolling_hash: u32,
  76. // Sliding window buffer. Size must be a power of two.
  77. window_size: i64,
  78. last: ^[dynamic]byte,
  79. }
  80. // Stream helpers
  81. /*
  82. TODO: These need to be optimized.
  83. Streams should really only check if a certain method is available once, perhaps even during setup.
  84. Bit and byte readers may be merged so that reading bytes will grab them from the bit buffer first.
  85. This simplifies end-of-stream handling where bits may be left in the bit buffer.
  86. */
  87. read_data :: #force_inline proc(c: ^Context, $T: typeid) -> (res: T, err: io.Error) {
  88. b := make([]u8, size_of(T), context.temp_allocator);
  89. r, e1 := io.to_reader(c.input);
  90. _, e2 := io.read(r, b);
  91. if !e1 || e2 != .None {
  92. return T{}, e2;
  93. }
  94. res = (^T)(raw_data(b))^;
  95. return res, .None;
  96. }
  97. read_u8 :: #force_inline proc(z: ^Context) -> (res: u8, err: io.Error) {
  98. return read_data(z, u8);
  99. }
  100. peek_data :: #force_inline proc(c: ^Context, $T: typeid) -> (res: T, err: io.Error) {
  101. // Get current position to read from.
  102. curr, e1 := c.input->impl_seek(0, .Current);
  103. if e1 != .None {
  104. return T{}, e1;
  105. }
  106. r, e2 := io.to_reader_at(c.input);
  107. if !e2 {
  108. return T{}, .Empty;
  109. }
  110. b := make([]u8, size_of(T), context.temp_allocator);
  111. _, e3 := io.read_at(r, b, curr);
  112. if e3 != .None {
  113. return T{}, .Empty;
  114. }
  115. res = (^T)(raw_data(b))^;
  116. return res, .None;
  117. }
  118. // Sliding window read back
  119. peek_back_byte :: proc(c: ^Context, offset: i64) -> (res: u8, err: io.Error) {
  120. // Look back into the sliding window.
  121. return c.last[offset % c.window_size], .None;
  122. }
  123. // Generalized bit reader LSB
  124. refill_lsb :: proc(z: ^Context, width := i8(24)) {
  125. for {
  126. if z.num_bits > width {
  127. break;
  128. }
  129. if z.code_buffer == 0 && z.num_bits == -1 {
  130. z.num_bits = 0;
  131. }
  132. if z.code_buffer >= 1 << uint(z.num_bits) {
  133. // Code buffer is malformed.
  134. z.num_bits = -100;
  135. return;
  136. }
  137. c, err := read_u8(z);
  138. if err != .None {
  139. // This is fine at the end of the file.
  140. z.num_bits = -42;
  141. z.eof = true;
  142. return;
  143. }
  144. z.code_buffer |= (u32(c) << u8(z.num_bits));
  145. z.num_bits += 8;
  146. }
  147. }
  148. consume_bits_lsb :: #force_inline proc(z: ^Context, width: u8) {
  149. z.code_buffer >>= width;
  150. z.num_bits -= i8(width);
  151. }
  152. peek_bits_lsb :: #force_inline proc(z: ^Context, width: u8) -> u32 {
  153. if z.num_bits < i8(width) {
  154. refill_lsb(z);
  155. }
  156. // assert(z.num_bits >= i8(width));
  157. return z.code_buffer & ~(~u32(0) << width);
  158. }
  159. peek_bits_no_refill_lsb :: #force_inline proc(z: ^Context, width: u8) -> u32 {
  160. assert(z.num_bits >= i8(width));
  161. return z.code_buffer & ~(~u32(0) << width);
  162. }
  163. read_bits_lsb :: #force_inline proc(z: ^Context, width: u8) -> u32 {
  164. k := peek_bits_lsb(z, width);
  165. consume_bits_lsb(z, width);
  166. return k;
  167. }
  168. read_bits_no_refill_lsb :: #force_inline proc(z: ^Context, width: u8) -> u32 {
  169. k := peek_bits_no_refill_lsb(z, width);
  170. consume_bits_lsb(z, width);
  171. return k;
  172. }
  173. discard_to_next_byte_lsb :: proc(z: ^Context) {
  174. discard := u8(z.num_bits & 7);
  175. consume_bits_lsb(z, discard);
  176. }