pcx2gba.c (4233B)
1 /* 2 * GBAconv 1.00 3 * Copyright (c) 2002-2019, Frederic Cambus 4 * https://github.com/fcambus/gbaconv 5 * 6 * PCX to GBA Converter 7 * 8 * Created: 2002-12-09 9 * Last Updated: 2019-07-28 10 * 11 * GBAconv is released under the BSD 2-Clause license. 12 * See LICENSE file for details. 13 */ 14 15 #include <fcntl.h> 16 #include <stdio.h> 17 #include <stdint.h> 18 #include <stdlib.h> 19 #include <string.h> 20 #include <unistd.h> 21 #include <sys/mman.h> 22 #include <sys/stat.h> 23 24 #define PCX_HEADER_LENGTH 128 25 #define PCX_PALETTE_LENGTH 768 26 27 unsigned char *input_file_buffer; 28 29 struct pcx_header { 30 uint8_t ID; 31 uint8_t version; 32 uint8_t encoding; 33 uint8_t bits_per_pixel; 34 uint16_t x_min; 35 uint16_t y_min; 36 uint16_t x_max; 37 uint16_t y_max; 38 uint16_t x_resolution; 39 uint16_t y_resolution; 40 uint8_t palette[48]; 41 uint8_t reserved; 42 uint8_t number_of_bit_planes; 43 uint16_t bytes_per_line; 44 uint16_t palette_type; 45 uint16_t x_screen_size; 46 uint16_t y_screen_size; 47 uint8_t filler[54]; 48 } __attribute__((packed)) pcx_header; 49 50 unsigned char pcx_image_palette[PCX_PALETTE_LENGTH]; 51 unsigned char *pcx_buffer; 52 size_t pcx_buffer_size; 53 54 size_t loop; 55 56 int current_byte; 57 int offset; 58 int run_count; 59 int run_position; 60 61 int main(int argc, char *argv[]) 62 { 63 int fd; 64 struct stat st; 65 66 if (argc != 3) { 67 printf("USAGE: pcx2gba input.pcx array_name (Input File must be 8-bpp PCX)\n\n"); 68 return EXIT_SUCCESS; 69 } 70 71 fd = open(argv[1], O_RDONLY); 72 if (fd == -1) 73 return EXIT_FAILURE; 74 75 if (fstat(fd, &st) == -1) { 76 close(fd); 77 return EXIT_FAILURE; 78 } 79 80 if (st.st_size < PCX_HEADER_LENGTH + PCX_PALETTE_LENGTH) { 81 printf("ERROR: Input File is not a PCX file\n\n"); 82 return EXIT_FAILURE; 83 } 84 85 /* mmap input file into memory */ 86 input_file_buffer = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0); 87 if (input_file_buffer == MAP_FAILED) { 88 close(fd); 89 return EXIT_FAILURE; 90 } 91 92 memcpy(&pcx_header, input_file_buffer, PCX_HEADER_LENGTH); 93 94 /* Check that the file is a valid PCX file */ 95 if (pcx_header.ID != 10) { 96 printf("ERROR: Input File is not a PCX file\n\n"); 97 return EXIT_FAILURE; 98 } 99 100 /* Check that the file is a 8-bpp PCX */ 101 if (pcx_header.bits_per_pixel != 8) { 102 printf("ERROR: Input File is not 8-bpp\n\n"); 103 return EXIT_FAILURE; 104 } 105 106 pcx_header.x_max++; 107 pcx_header.y_max++; 108 109 if ((pcx_header.x_max) > 4096 || (pcx_header.y_max) > 4096) { 110 printf("ERROR: Input File height or width is larger than 4096\n\n"); 111 return EXIT_FAILURE; 112 } 113 114 /* Uncompress RLE encoded PCX Input File */ 115 pcx_buffer_size = pcx_header.x_max * pcx_header.y_max; 116 pcx_buffer = malloc(pcx_buffer_size); 117 118 if (!pcx_buffer) { 119 printf("ERROR: Cannot allocate memory for the PCX buffer\n\n"); 120 return EXIT_FAILURE; 121 } 122 123 loop = PCX_HEADER_LENGTH; 124 125 while (loop < st.st_size - PCX_PALETTE_LENGTH) { 126 current_byte = input_file_buffer[loop]; 127 128 if (current_byte > 192) { 129 run_count = current_byte-192; 130 131 for (run_position = 0; run_position < run_count; run_position++) { 132 if (offset + run_position < pcx_buffer_size) { 133 pcx_buffer[offset + run_position] = input_file_buffer[loop +1]; 134 } else { 135 printf("ERROR: Input File is corrupt\n\n"); 136 return EXIT_FAILURE; 137 } 138 } 139 offset += run_count; 140 loop += 2; 141 } else { 142 if (offset < pcx_buffer_size) 143 pcx_buffer[offset] = current_byte; 144 145 offset++; 146 loop++; 147 } 148 } 149 150 for (loop = 0; loop < PCX_PALETTE_LENGTH; loop++) { 151 pcx_image_palette[loop] = input_file_buffer[st.st_size - PCX_PALETTE_LENGTH + loop] / 8; 152 } 153 154 fprintf(stderr, "INPUT FILE: %s (%ix%ix%i-bpp)\n", argv[1], pcx_header.x_max, pcx_header.y_max, pcx_header.bits_per_pixel); 155 156 fprintf(stdout, "const u16 %s_palette[] = {", argv[2]); 157 158 for (loop = 0; loop < 256; loop++) { 159 if (loop % 10 == 0) 160 fprintf(stdout, "\n\t"); 161 162 fprintf(stdout, "0x%x,", pcx_image_palette[loop*3] | pcx_image_palette[(loop*3)+1]<<5 | pcx_image_palette[(loop*3)+2]<<10); 163 } 164 165 fprintf(stdout, "\n};\n\n"); 166 167 fprintf(stdout, "const u16 %s[] = {", argv[2]); 168 169 for (loop = 0; loop < pcx_buffer_size/2; loop++) { 170 if (loop % 10 == 0) 171 fprintf(stdout, "\n\t"); 172 173 fprintf(stdout, "0x%x,", pcx_buffer[loop*2] | pcx_buffer[(loop*2)+1]<<8); 174 } 175 176 fprintf(stdout, "\n};\n"); 177 178 /* Terminate Program */ 179 munmap(input_file_buffer, st.st_size); 180 close(fd); 181 182 return EXIT_SUCCESS; 183 }