128 lines
3.1 KiB
C
128 lines
3.1 KiB
C
/* Calcite, src/user-libs/silver/pam.c
|
|
* Copyright 2025 Benji Dial
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
* for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along
|
|
* with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include <calcite/file-streams.h>
|
|
#include <silver/pam.h>
|
|
|
|
static int starts_with(const char *big_string, const char *little_string) {
|
|
while (*little_string) {
|
|
if (*big_string != *little_string)
|
|
return 0;
|
|
++big_string;
|
|
++little_string;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int strequ(const char *str1, const char *str2) {
|
|
while (1) {
|
|
if (!*str1 && !*str2)
|
|
return 1;
|
|
if (*str1 != *str2)
|
|
return 0;
|
|
++str1;
|
|
++str2;
|
|
}
|
|
}
|
|
|
|
static int parse_uint(const char *str) {
|
|
int i = 0;
|
|
while (*str)
|
|
i = i * 10 + *(str++) - '0';
|
|
return i;
|
|
}
|
|
|
|
enum pam_tupltype {
|
|
PTT_RGB_ALPHA
|
|
};
|
|
|
|
#define MAX_LINE_LENGTH 1023
|
|
|
|
int load_pam(const char *path, struct image **image_out) {
|
|
|
|
struct file_stream *stream;
|
|
if (open_file_stream(path, &stream) != FAR_SUCCESS)
|
|
return 0;
|
|
|
|
if (read_file_stream_byte(stream) != 'P' ||
|
|
read_file_stream_byte(stream) != '7' ||
|
|
read_file_stream_byte(stream) != '\n') {
|
|
close_file_stream(stream);
|
|
return 0;
|
|
}
|
|
|
|
int width = -1, height = -1, depth = -1, maxval = -1, tupltype = -1;
|
|
|
|
while (1) {
|
|
|
|
char line[MAX_LINE_LENGTH + 1];
|
|
int line_length = 0;
|
|
while (1) {
|
|
int c = read_file_stream_byte(stream);
|
|
if (c == -1) {
|
|
close_file_stream(stream);
|
|
return 0;
|
|
}
|
|
if (c == '\n') {
|
|
line[line_length] = 0;
|
|
break;
|
|
}
|
|
if (line_length == MAX_LINE_LENGTH) {
|
|
close_file_stream(stream);
|
|
return 0;
|
|
}
|
|
line[line_length++] = c;
|
|
}
|
|
|
|
if (line[0] == '#')
|
|
continue;
|
|
|
|
if (starts_with(line, "WIDTH "))
|
|
width = parse_uint(&line[6]);
|
|
else if (starts_with(line, "HEIGHT "))
|
|
height = parse_uint(&line[7]);
|
|
else if (starts_with(line, "DEPTH "))
|
|
depth = parse_uint(&line[6]);
|
|
else if (starts_with(line, "MAXVAL "))
|
|
maxval = parse_uint(&line[7]);
|
|
else if (strequ(line, "TUPLTYPE RGB_ALPHA"))
|
|
tupltype = PTT_RGB_ALPHA;
|
|
else if (strequ(line, "ENDHDR"))
|
|
break;
|
|
|
|
}
|
|
|
|
if (width == -1 || height == -1 || depth != 4 || maxval != 255 || tupltype != PTT_RGB_ALPHA) {
|
|
close_file_stream(stream);
|
|
return 0;
|
|
}
|
|
|
|
create_image(width, height, image_out);
|
|
|
|
if (read_file_stream(
|
|
stream,
|
|
(*image_out)->pixels,
|
|
width * height * 4) != FAR_SUCCESS) {
|
|
close_file_stream(stream);
|
|
destroy_image(*image_out);
|
|
return 0;
|
|
}
|
|
|
|
close_file_stream(stream);
|
|
return 1;
|
|
|
|
}
|