| 1 | #include <stdio.h> |
| 2 | #include <stdlib.h> |
| 3 | #include <string.h> |
| 4 | #include <zlib.h> |
| 5 | |
| 6 | #define CD_FRAMESIZE_RAW 2352 |
| 7 | |
| 8 | struct ztab_entry { |
| 9 | unsigned int offset; |
| 10 | unsigned short size; |
| 11 | } __attribute__((packed)); |
| 12 | |
| 13 | int main(int argc, char *argv[]) |
| 14 | { |
| 15 | unsigned char outbuf[CD_FRAMESIZE_RAW * 2]; |
| 16 | unsigned char inbuf[CD_FRAMESIZE_RAW]; |
| 17 | struct ztab_entry *ztable; |
| 18 | char *out_basename, *out_fname, *out_tfname; |
| 19 | FILE *fin, *fout; |
| 20 | long in_bytes, out_bytes; |
| 21 | long s, total_sectors; |
| 22 | int ret, len; |
| 23 | |
| 24 | if (argc < 2) { |
| 25 | fprintf(stderr, "usage:\n%s <cd_img> [out_basename]\n", argv[0]); |
| 26 | return 1; |
| 27 | } |
| 28 | |
| 29 | fin = fopen(argv[1], "rb"); |
| 30 | if (fin == NULL) { |
| 31 | fprintf(stderr, "fopen %s: ", argv[1]); |
| 32 | perror(NULL); |
| 33 | return 1; |
| 34 | } |
| 35 | |
| 36 | if (argv[2] != NULL) |
| 37 | out_basename = argv[2]; |
| 38 | else |
| 39 | out_basename = argv[1]; |
| 40 | |
| 41 | len = strlen(out_basename) + 3; |
| 42 | out_fname = malloc(len); |
| 43 | if (out_fname == NULL) { |
| 44 | fprintf(stderr, "OOM\n"); |
| 45 | return 1; |
| 46 | } |
| 47 | snprintf(out_fname, len, "%s.Z", out_basename); |
| 48 | |
| 49 | fout = fopen(out_fname, "wb"); |
| 50 | if (fout == NULL) { |
| 51 | fprintf(stderr, "fopen %s: ", out_fname); |
| 52 | perror(NULL); |
| 53 | return 1; |
| 54 | } |
| 55 | |
| 56 | if (fseek(fin, 0, SEEK_END) != 0) { |
| 57 | fprintf(stderr, "fseek failed: "); |
| 58 | perror(NULL); |
| 59 | return 1; |
| 60 | } |
| 61 | |
| 62 | in_bytes = ftell(fin); |
| 63 | if (in_bytes % CD_FRAMESIZE_RAW) { |
| 64 | fprintf(stderr, "warning: input size %ld is not " |
| 65 | "multiple of sector size\n", in_bytes); |
| 66 | } |
| 67 | total_sectors = in_bytes / CD_FRAMESIZE_RAW; |
| 68 | fseek(fin, 0, SEEK_SET); |
| 69 | |
| 70 | ztable = calloc(total_sectors, sizeof(ztable[0])); |
| 71 | if (ztable == NULL) { |
| 72 | fprintf(stderr, "OOM\n"); |
| 73 | return 1; |
| 74 | } |
| 75 | |
| 76 | out_bytes = 0; |
| 77 | for (s = 0; s < total_sectors; s++) { |
| 78 | uLongf dest_len = sizeof(outbuf); |
| 79 | |
| 80 | ret = fread(inbuf, 1, sizeof(inbuf), fin); |
| 81 | if (ret != sizeof(inbuf)) { |
| 82 | printf("\n"); |
| 83 | fprintf(stderr, "fread returned %d\n", ret); |
| 84 | return 1; |
| 85 | } |
| 86 | |
| 87 | ret = compress2(outbuf, &dest_len, inbuf, sizeof(inbuf), 9); |
| 88 | if (ret != Z_OK) { |
| 89 | printf("\n"); |
| 90 | fprintf(stderr, "compress2 failed: %d\n", ret); |
| 91 | return 1; |
| 92 | } |
| 93 | |
| 94 | ret = fwrite(outbuf, 1, dest_len, fout); |
| 95 | if (ret != dest_len) { |
| 96 | printf("\n"); |
| 97 | fprintf(stderr, "fwrite returned %d\n", ret); |
| 98 | return 1; |
| 99 | } |
| 100 | |
| 101 | ztable[s].offset = out_bytes; |
| 102 | ztable[s].size = dest_len; |
| 103 | out_bytes += dest_len; |
| 104 | |
| 105 | // print progress |
| 106 | if ((s & 0x1ff) == 0) { |
| 107 | printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); |
| 108 | printf("%3ld%% %ld/%ld", s * 100 / total_sectors, s, total_sectors); |
| 109 | fflush(stdout); |
| 110 | } |
| 111 | } |
| 112 | |
| 113 | fclose(fin); |
| 114 | fclose(fout); |
| 115 | |
| 116 | // write .table |
| 117 | len = strlen(out_fname) + 7; |
| 118 | out_tfname = malloc(len); |
| 119 | if (out_tfname == NULL) { |
| 120 | printf("\n"); |
| 121 | fprintf(stderr, "OOM\n"); |
| 122 | return 1; |
| 123 | } |
| 124 | snprintf(out_tfname, len, "%s.table", out_fname); |
| 125 | |
| 126 | fout = fopen(out_tfname, "wb"); |
| 127 | if (fout == NULL) { |
| 128 | fprintf(stderr, "fopen %s: ", out_tfname); |
| 129 | perror(NULL); |
| 130 | return 1; |
| 131 | } |
| 132 | |
| 133 | ret = fwrite(ztable, sizeof(ztable[0]), total_sectors, fout); |
| 134 | if (ret != total_sectors) { |
| 135 | printf("\n"); |
| 136 | fprintf(stderr, "fwrite returned %d\n", ret); |
| 137 | return 1; |
| 138 | } |
| 139 | fclose(fout); |
| 140 | |
| 141 | printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); |
| 142 | printf("%3ld%% %ld/%ld\n", s * 100 / total_sectors, s, total_sectors); |
| 143 | printf("%ld bytes from %ld (%.1f%%)\n", out_bytes, in_bytes, |
| 144 | (double)out_bytes * 100.0 / in_bytes); |
| 145 | |
| 146 | return 0; |
| 147 | } |