diff --git a/main.c b/main.c index 09c7ca6..7729695 100644 --- a/main.c +++ b/main.c @@ -241,6 +241,57 @@ static void get_sm_version(char *buf, size_t buflen) { } /* Generic SM API proxy - returns malloc'd body or NULL */ +/* base64-encode binary data; out must be at least ceil(in_len/3)*4+1 bytes */ +static void b64enc(const unsigned char *in, size_t len, char *out) { + static const char t[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + size_t i=0,j=0; + for(;i+2>2];out[j++]=t[((in[i]&3)<<4)|(in[i+1]>>4)]; + out[j++]=t[((in[i+1]&15)<<2)|(in[i+2]>>6)];out[j++]=t[in[i+2]&63]; + } + if(i>2]; + if(i+1>4)];out[j++]=t[(in[i+1]&15)<<2];out[j++]='=';} + else{out[j++]=t[(in[i]&3)<<4];out[j++]='=';out[j++]='=';} + } + out[j]=0; +} + +/* read icon file and return malloc'd base64 string, or NULL */ +static char *icon_b64(const char *tid) { + static const char *ptpl[]={ + "/data/SMPlusGui/icon-cache/%s.png", + "/user/appmeta/%s/icon0.png", + "/data/homebrew/%s/sce_sys/icon0.png", + NULL + }; + char src[256]; FILE *f=NULL; + for(int i=0;ptpl[i]&&!f;i++){snprintf(src,sizeof(src),ptpl[i],tid);f=fopen(src,"rb");} + /* scan /mnt/shadowmnt/ */ + if(!f){DIR *sd=opendir("/mnt/shadowmnt");if(sd){struct dirent *de;size_t tl=strlen(tid); + while(!f&&(de=readdir(sd))!=NULL)if(strncmp(de->d_name,tid,tl)==0&&de->d_name[tl]=='_') + {snprintf(src,sizeof(src),"/mnt/shadowmnt/%s/sce_sys/icon0.png",de->d_name);f=fopen(src,"rb");} + closedir(sd);} + } + if(!f) return NULL; + fseek(f,0,SEEK_END);long sz=ftell(f);fseek(f,0,SEEK_SET); + if(sz<=0||sz>524288){fclose(f);return NULL;} + unsigned char *buf=malloc(sz); + if(!buf){fclose(f);return NULL;} + if((long)fread(buf,1,sz,f)!=sz){free(buf);fclose(f);return NULL;} + fclose(f); + /* also write to cache if we found it elsewhere */ + {char cp[256];snprintf(cp,sizeof(cp),"/data/SMPlusGui/icon-cache/%s.png",tid); + struct stat cs; if(stat(cp,&cs)!=0){mkdir("/data/SMPlusGui",0777);mkdir("/data/SMPlusGui/icon-cache",0777); + FILE *cf=fopen(cp,"wb");if(cf){fwrite(buf,1,sz,cf);fclose(cf);}}} + size_t b64sz=((sz+2)/3)*4+1; + char *out=malloc(b64sz); + if(!out){free(buf);return NULL;} + b64enc(buf,sz,out); + free(buf); + return out; +} + static char* sm_api_req(const char *method, const char *path, const char *body) { int sock = socket(AF_INET, SOCK_STREAM, 0); if (sock < 0) return NULL; @@ -2901,9 +2952,9 @@ static void fn(struct mg_connection *c, int ev, void *ev_data) { /* images always available; enrich with title_name from games API when mounted */ char *img_json=sm_api_req("POST","/api/v1/images","{}"); char *gam_json=sm_api_req("POST","/api/v1/games","{}"); - char *out=malloc(131072); if(!out){if(img_json)free(img_json);if(gam_json)free(gam_json);mg_http_reply(c,500,"","");return;} + char *out=malloc(1048576); if(!out){if(img_json)free(img_json);if(gam_json)free(gam_json);mg_http_reply(c,500,"","");return;} int pos=0; - #define GL(fmt,...) pos+=snprintf(out+pos,131071-pos,fmt,##__VA_ARGS__) + #define GL(fmt,...) pos+=snprintf(out+pos,1048575-pos,fmt,##__VA_ARGS__) if(!img_json){ GL("

SM API nicht erreichbar

"); } else { @@ -2912,7 +2963,7 @@ static void fn(struct mg_connection *c, int ev, void *ev_data) { else { int n=0; const char *cur=istart; - while((cur=strstr(cur,"{\"path\""))!=NULL&&pos<120000){ + while((cur=strstr(cur,"{\"path\""))!=NULL&&pos<900000){ char imgpath[512]={0},mp[256]={0}; long long sz=0; int mounted=0; /* extract path, mount_point, size, mounted from images API */ @@ -2956,9 +3007,12 @@ static void fn(struct mg_connection *c, int ev, void *ev_data) { const char *bs_um="background:transparent;border:1px solid #f87171;border-radius:4px;color:#f87171;padding:3px 10px;cursor:pointer;font-size:.75rem;"; const char *bs_mt="background:transparent;border:1px solid var(--accent);border-radius:4px;color:var(--accent);padding:3px 10px;cursor:pointer;font-size:.75rem;white-space:nowrap;"; GL("
"); - GL("
" - "" - "%.4s
",tid,tid[0]?tid:"?"); + /* inline base64 icon — no separate HTTP request, works on all devices */ + {char *b64=tid[0]?icon_b64(tid):NULL; + if(b64){GL("
" + "
",b64);free(b64);} + else GL("
%.4s
",tid[0]?tid:"?");} GL("
" "
%s
" "
%s — %s
",