ref: b5f1e3844af4613148ef2a3132022a170e0c803f
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; }