ref: 765e2086b63cf705bfddb85af870dec02ee71860
dir: /qoirecv.c/
#define _DEFAULT_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <SDL.h>
#include "parg.h"
enum {
Opind = 0x00,
Opdif = 0x40,
Oplum = 0x80,
Oprun = 0xc0,
Oprgb = 0xfe,
};
typedef struct Pix Pix;
struct Pix {
uint8_t r, g, b, a;
};
int
main(int argc, char **argv)
{
int port, c, ls, s, n, w, h, m, ow, oh;
uint8_t hdr[14], t[8], *o, *b;
Pix p[64], prevpix, pix;
struct sockaddr_in addr;
struct parg_state ps;
SDL_Renderer *rend;
SDL_Texture *tex;
SDL_Window *win;
socklen_t alen;
SDL_Event e;
FILE *f;
parg_init(&ps);
port = 12345;
while((c = parg_getopt(&ps, argc, argv, "hp:")) >= 0){
switch(c){
case 'p':
port = atoi(ps.optarg);
break;
default:
case 'h':
fprintf(stderr, "usage: qoirecv [-p PORT]\n");
return 0;
break;
case '?':
fprintf(stderr, "unknown option -%c\n", ps.optopt);
return 1;
break;
}
}
if((ls = socket(AF_INET, SOCK_STREAM, 0)) < 0){
perror("socket");
return 1;
}
setsockopt(ls, SOL_SOCKET, SO_REUSEADDR, &(int){1}, sizeof(int));
setsockopt(ls, SOL_SOCKET, SO_REUSEPORT, &(int){1}, sizeof(int));
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = INADDR_ANY;
addr.sin_port = htons(port);
if(bind(ls, (struct sockaddr*)&addr, sizeof(addr)) < 0){
perror("bind");
return 1;
}
if(listen(ls, 0) < 0){
perror("listen");
return 1;
}
if(SDL_Init(SDL_INIT_VIDEO) < 0){
fprintf(stderr, "SDL_Init: %s\n", SDL_GetError());
return 1;
}
win = SDL_CreateWindow("qoirecv", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 256, 256, SDL_WINDOW_HIDDEN | SDL_WINDOW_ALLOW_HIGHDPI);
if(win == NULL){
fprintf(stderr, "SDL_CreateWindow: %s\n", SDL_GetError());
return 1;
}
if((rend = SDL_CreateRenderer(win, -1, 0)) == NULL){
fprintf(stderr, "SDL_CreateRenderer: %s\n", SDL_GetError());
return 1;
}
SDL_SetRenderDrawColor(rend, 0, 0, 0, 255);
tex = NULL;
b = NULL;
ow = oh = 0;
for(;;){
alen = sizeof(addr);
if((s = accept(ls, (struct sockaddr*)&addr, &alen)) < 0){
perror("accept");
return 1;
}
if((f = fdopen(s, "rb")) == NULL){
perror("fdopen");
goto err;
}
for(;;){
while(SDL_PollEvent(&e) > 0){
if(e.type == SDL_QUIT){
close(s);
close(ls);
SDL_Quit();
return 0;
}
}
if(fread(hdr, 1, sizeof(hdr), f) != sizeof(hdr)){
perror("header");
goto err;
}
if(memcmp(hdr, "qoif", 4) != 0 || hdr[12] != 3 || hdr[13] != 0){
fprintf(stderr, "invalid image format (magic=%c%c%c%c channels=%d colorspace=%d)\n",
hdr[0], hdr[1], hdr[2], hdr[3], hdr[12], hdr[13]
);
goto err;
}
w = hdr[4]<<24 | hdr[5]<<16 | hdr[6]<<8 | hdr[7];
h = hdr[8]<<24 | hdr[9]<<16 | hdr[10]<<8 | hdr[11];
if(w < 1 || h < 1 || w > 16384 || h > 16384){
fprintf(stderr, "sketchy image dimensions (%dx%d)\n", w, h);
goto err;
}
if(tex == NULL || ow != w || oh != h){
if((o = realloc(b, w*h*3)) == NULL){
perror("memory");
goto err;
}
b = o;
if(tex != NULL)
SDL_DestroyTexture(tex);
tex = SDL_CreateTexture(rend, SDL_PIXELFORMAT_RGB24, SDL_TEXTUREACCESS_STATIC, w, h);
if(tex == NULL){
fprintf(stderr, "SDL_CreateTexture: %s\n", SDL_GetError());
goto err;
}
SDL_SetTextureBlendMode(tex, SDL_BLENDMODE_NONE);
SDL_RenderSetLogicalSize(rend, w, h);
SDL_RenderClear(rend);
SDL_RenderPresent(rend);
SDL_SetWindowSize(win, w, h);
SDL_SetWindowPosition(win, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
SDL_ShowWindow(win);
ow = w;
oh = h;
}
memset(p, 0, sizeof(p));
prevpix.r = 0;
prevpix.g = 0;
prevpix.b = 0;
prevpix.a = 255;
pix.a = 255;
o = b;
for(m = w*h; m > 0;){
if((c = fgetc(f)) == EOF){
fprintf(stderr, "unexpected EOF\n");
goto err;
}
if(c == Oprgb){
if(fread(t, 1, 3, f) != 3){
perror("Oprgb");
goto err;
}
pix.r = t[0];
pix.g = t[1];
pix.b = t[2];
}else if((c & 0xc0) == Oplum){
if((t[0] = fgetc(f)) == EOF){
perror("Oplum");
goto err;
}
pix.g = -32 + (c & 0x3f);
pix.r = pix.g - 8 + (t[0] >> 4) + prevpix.r;
pix.b = pix.g - 8 + (t[0] & 0x0f) + prevpix.b;
pix.g += prevpix.g;
}else if((c & 0xc0) == Opdif){
pix.b = prevpix.b - 2 + ((c>>0) & 3);
pix.g = prevpix.g - 2 + ((c>>2) & 3);
pix.r = prevpix.r - 2 + ((c>>4) & 3);
}else if((c & 0xc0) == Opind){
pix = p[c];
}else if(c == 0xff){ /* rgba */
fprintf(stderr, "unexpected Oprgba\n");
goto err;
}else{ /* run */
if((n = (c&0x3f)+1) > m){
fprintf(stderr, "run out of bounds: %d > %d", n, m);
goto err;
}
do{
*o++ = pix.r;
*o++ = pix.g;
*o++ = pix.b;
m--;
}while(--n > 0);
continue;
}
prevpix = pix;
p[(pix.r*3 + pix.g*5 + pix.b*7 + 255*11) & 63] = pix;
*o++ = pix.r;
*o++ = pix.g;
*o++ = pix.b;
m--;
}
if(fread(t, 1, 8, f) != 8){
perror("padding");
goto err;
}
if(memcmp(t, "\0\0\0\0\0\0\0\1", 7) != 0){
fprintf(stderr, "invalid padding: %02x%02x%02x%02x%02x%02x%02x%02x\n",
t[0], t[1], t[2], t[3], t[4], t[5], t[6], t[7]
);
goto err;
}
if(SDL_UpdateTexture(tex, NULL, b, w*3) != 0){
fprintf(stderr, "SDL_UpdateTexture: %s\n", SDL_GetError());
goto err;
}
SDL_RenderCopy(rend, tex, NULL, NULL);
SDL_RenderPresent(rend);
continue;
err:
close(s);
break;
}
}
return 0;
}