static int do_compress(struct deflate_compressor *compressor, struct file_stream *in, struct file_stream *out) { const void *uncompressed_data = in->mmap_mem; size_t uncompressed_size = in->mmap_size; void *compressed_data; size_t actual_compressed_size; size_t max_compressed_size; int ret; max_compressed_size = gzip_compress_bound(compressor, uncompressed_size); compressed_data = xmalloc(max_compressed_size); if (compressed_data == NULL) { msg("%"TS": file is probably too large to be processed by this " "program", in->name); ret = -1; goto out; } actual_compressed_size = gzip_compress(compressor, uncompressed_data, uncompressed_size, compressed_data, max_compressed_size); if (actual_compressed_size == 0) { msg("Bug in gzip_compress_bound()!"); ret = -1; goto out; } ret = full_write(out, compressed_data, actual_compressed_size); out: free(compressed_data); return ret; }
int compress_buffer(ssh_session session, ssh_buffer buf) { ssh_buffer dest = NULL; dest = gzip_compress(session, buf, session->compressionlevel); if (dest == NULL) { return -1; } if (buffer_reinit(buf) < 0) { ssh_buffer_free(dest); return -1; } if (buffer_add_data(buf, buffer_get_rest(dest), buffer_get_rest_len(dest)) < 0) { ssh_buffer_free(dest); return -1; } ssh_buffer_free(dest); return 0; }
int mc_compress_cb(char** buf_p, void* param, int type, int* olen) { int rc; int len; int algo; int flags; int compress_len=0; int uncompress_len=0; int hdr_compress_len=0; str msg_start; char *buf=*buf_p; char *end=buf+strlen(buf); unsigned long temp; struct mc_comp_args *args=(struct mc_comp_args*)param; struct hdr_field *hf; struct hdr_field *mnd_hdrs=NULL; struct hdr_field *non_mnd_hdrs=NULL; struct hdr_field *mnd_hdrs_head=NULL; struct hdr_field *non_mnd_hdrs_head=NULL; mc_param_p wh_param; mc_whitelist_p hdr2compress_list; wh_param = args->wh_param; hdr2compress_list = args->hdr2compress_list; algo = args->algo; flags = args->flags; mc_parse_first_line(&msg_start, &buf); uncompress_len = msg_start.len; /* Parse the message until the body is found Build two lists one of mandatory headers and one of non mandatory headers */ while (1) { hf = pkg_malloc(sizeof(struct hdr_field)); if (hf == NULL) { LM_ERR("no more pkg mem\n"); goto free_mem_full; } memset(hf, 0, sizeof(struct hdr_field)); hf->type=HDR_ERROR_T; buf=get_hdr_field(buf, end, hf); if (hf->type == HDR_ERROR_T) { goto free_mem_full; } if (hf->type == HDR_EOH_T) { compress_len += strlen(buf); compress_len = compress_len > CRLF_LEN ? compress_len : 0; pkg_free(hf); break; } /*if Content-Length=0 then header must remain*/ if (hf->type == HDR_CONTENTLENGTH_T && hf->body.s[0] == '0') { goto set_mandatory; } if (mc_is_in_whitelist(hf, hdr2compress_list)) { if (!non_mnd_hdrs) { non_mnd_hdrs_head = non_mnd_hdrs = hf; } else { non_mnd_hdrs->next = hf; non_mnd_hdrs = non_mnd_hdrs->next; } /* in case will have a separate compressed header */ if ((flags&SEPARATE_COMP_FLG && flags&BODY_COMP_FLG && flags&HDR_COMP_FLG) || (flags&HDR_COMP_FLG && !(flags&BODY_COMP_FLG))) hdr_compress_len += hf->len; else compress_len += hf->len; } else { set_mandatory: if (!mnd_hdrs) { mnd_hdrs_head = mnd_hdrs = hf; } else { mnd_hdrs->next = hf; mnd_hdrs = mnd_hdrs->next; } uncompress_len += hf->len; } hf = 0; } str buf2compress={NULL, 0}; str hdr_buf2compress={NULL, 0}; /* Copy headers only if they exist and only if were asked*/ non_mnd_hdrs = non_mnd_hdrs_head; if (!non_mnd_hdrs || !(flags&HDR_COMP_FLG)) goto only_body; /* If body compression and header compression flags are set and they have to be together in the body */ if ((flags&BODY_COMP_FLG && flags&HDR_COMP_FLG && !(flags&SEPARATE_COMP_FLG)) || (flags&BODY_COMP_FLG && !(flags&HDR_COMP_FLG))){ if (wrap_realloc(&body_in, compress_len)) goto free_mem_full; buf2compress.s = body_in.s; buf2compress.len = 0; for (hf = non_mnd_hdrs; hf; hf = hf->next) { wrap_copy_and_update( &buf2compress.s, hf->name.s, hf->len, &buf2compress.len); } /* body compression and header compression but separately or only header compression */ } else if ((flags&BODY_COMP_FLG && flags&HDR_COMP_FLG && flags&SEPARATE_COMP_FLG) || (!(flags&BODY_COMP_FLG) && flags&HDR_COMP_FLG)) { if (wrap_realloc(&hdr_in, hdr_compress_len)) goto free_mem_full; hdr_buf2compress.s = hdr_in.s; for (hf = non_mnd_hdrs; hf; hf = hf->next) { wrap_copy_and_update( &hdr_buf2compress.s, hf->name.s, hf->len, &hdr_buf2compress.len); } } only_body: /* Copy the body of the message only if body compression is asked */ if (flags&BODY_COMP_FLG && compress_len) { if (!buf2compress.s) { if (wrap_realloc(&body_in, compress_len)) goto free_mem_full; buf2compress.s = body_in.s; } wrap_copy_and_update( &buf2compress.s, buf, strlen(buf), &buf2compress.len); } if (!buf2compress.s && !hdr_buf2compress.s) { LM_WARN("Nothing to compress. Specified headers not found\n"); goto free_mem_full; } /* Compress the message */ str bufcompressed={NULL, 0}; str hdr_bufcompressed={NULL, 0}; switch (algo) { case 0: /* deflate */ if (buf2compress.s) { bufcompressed.len = compressBound((unsigned long)buf2compress.len); if (wrap_realloc(&body_out, bufcompressed.len)) goto free_mem_full; bufcompressed.s = body_out.s; temp = (unsigned long)bufcompressed.len; rc = compress2((unsigned char*)bufcompressed.s, &temp, (unsigned char*)buf2compress.s, (unsigned long)buf2compress.len, mc_level); bufcompressed.len = (int)temp; if (check_zlib_rc(rc)) { LM_ERR("Body compression failed\n"); goto free_mem_full; } } if ((flags&HDR_COMP_FLG) && hdr_buf2compress.s) { hdr_bufcompressed.len = compressBound((unsigned long)hdr_buf2compress.len); if (wrap_realloc(&hdr_out, hdr_bufcompressed.len)) goto free_mem_full; hdr_bufcompressed.s = hdr_out.s; temp = (unsigned long)hdr_bufcompressed.len; rc = compress2((unsigned char*)hdr_bufcompressed.s, &temp, (unsigned char*)hdr_buf2compress.s, (unsigned long)hdr_buf2compress.len, mc_level); hdr_bufcompressed.len = temp; if (check_zlib_rc(rc)) { LM_ERR("Header compression failed\n"); goto free_mem_full; } } break; case 1: /* gzip */ if (buf2compress.s) { rc = gzip_compress( (unsigned char*)buf2compress.s, (unsigned long)buf2compress.len, &body_out, &temp, mc_level); if (check_zlib_rc(rc)) { LM_ERR("Body compression failed\n"); goto free_mem_full; } bufcompressed.s = body_out.s; bufcompressed.len = (int)temp; } if ((flags&HDR_COMP_FLG) && hdr_buf2compress.s) { rc = gzip_compress( (unsigned char*)hdr_buf2compress.s, (unsigned long)hdr_buf2compress.len, &hdr_out, &temp, mc_level); if (check_zlib_rc(rc)) { LM_ERR("Header compression failed\n"); goto free_mem_full; } hdr_bufcompressed.s = hdr_out.s; hdr_bufcompressed.len = temp; } break; default: LM_WARN("Invalind algo! no compression made\n"); goto free_mem_full; } str bufencoded={NULL, 0}; str hdr_bufencoded={NULL, 0}; if ((flags&B64_ENCODED_FLG) && bufcompressed.s) { bufencoded.len = calc_base64_encode_len(bufcompressed.len); if (wrap_realloc( &body_in, 2*CRLF_LEN + bufencoded.len)) goto free_mem_full; bufencoded.s = body_in.s; memcpy(bufencoded.s, CRLF, CRLF_LEN); base64encode((unsigned char*)(bufencoded.s + CRLF_LEN), (unsigned char*)bufcompressed.s, bufcompressed.len); } else if (bufcompressed.s) { if (wrap_realloc(&body_in, bufcompressed.len + 2*CRLF_LEN)) goto free_mem_full; /* !!! shift buf2compressed CRLF_LEN to the right !!! */ memcpy(body_in.s+CRLF_LEN, bufcompressed.s, bufcompressed.len); memcpy(body_in.s, CRLF, CRLF_LEN); bufencoded.len = bufcompressed.len; bufencoded.s = body_in.s; } if (hdr_bufcompressed.s) { hdr_bufencoded.len = calc_base64_encode_len(hdr_bufcompressed.len); if (wrap_realloc( &hdr_in, hdr_bufencoded.len + CRLF_LEN)) goto free_mem_full; hdr_bufencoded.s = hdr_in.s; base64encode((unsigned char*)hdr_bufencoded.s, (unsigned char*)hdr_bufcompressed.s, hdr_bufcompressed.len); wrap_copy_and_update(&hdr_bufencoded.s, CRLF, CRLF_LEN, &hdr_bufencoded.len); } /* Allocate the new buffer */ int alloc_size; str buf2send={NULL, 0}; alloc_size = msg_start.len + uncompress_len + CRLF_LEN/*the one before all headers*/; if (hdr_bufencoded.s) { alloc_size += COMP_HDRS_LEN + hdr_bufencoded.len; alloc_size += sizeof(HDRS_ENCODING) - 1; } /* if body compressed new content length and content encoding * plus if required more space for base64 in content encoding header*/ if (bufencoded.s) { alloc_size += CL_NAME_LEN + mc_ndigits(bufencoded.len) + CRLF_LEN; alloc_size += CE_NAME_LEN + CRLF_LEN; if (flags&B64_ENCODED_FLG) { alloc_size += ATTR_DELIM_LEN + (sizeof(BASE64_ALGO)-1); } } switch (algo) { case 0: /* deflate*/ if (bufencoded.s) alloc_size += DEFLATE_CE_LEN; if (hdr_bufencoded.s) alloc_size += sizeof(DEFLATE_ALGO) - 1; break; case 1: /* gzip */ if (bufencoded.s) alloc_size += GZIP_CE_LEN; if (hdr_bufencoded.s) alloc_size += sizeof(GZIP_ALGO) - 1; break; default: LM_ERR("compression algo not impelemented\n"); goto free_mem_full; } if (bufencoded.s) alloc_size += bufencoded.len + CRLF_LEN; else alloc_size += strlen(buf); if (wrap_realloc(&buf_out, alloc_size)) goto free_mem_full; buf2send.s = buf_out.s; /* Copy message start */ wrap_copy_and_update( &buf2send.s, msg_start.s, msg_start.len, &buf2send.len); /* Copy mandatory headers */ for (mnd_hdrs = mnd_hdrs_head; mnd_hdrs; mnd_hdrs = mnd_hdrs->next) { wrap_copy_and_update( &buf2send.s, mnd_hdrs->name.s, mnd_hdrs->len, &buf2send.len); } if ((flags&BODY_COMP_FLG) && bufencoded.s) { wrap_copy_and_update( &buf2send.s, CL_NAME, CL_NAME_LEN, &buf2send.len); wrap_copy_and_update( &buf2send.s, int2str(bufencoded.len, &len), mc_ndigits(bufencoded.len), &buf2send.len); wrap_copy_and_update( &buf2send.s, CRLF, CRLF_LEN, &buf2send.len); } if (hdr_bufencoded.s) { wrap_copy_and_update( &buf2send.s, COMP_HDRS, COMP_HDRS_LEN, &buf2send.len); wrap_copy_and_update( &buf2send.s, hdr_bufencoded.s, hdr_bufencoded.len, &buf2send.len); } switch (algo) { case 0: /* deflate */ if (hdr_bufencoded.s) { str hdr_name = str_init(HDRS_ENCODING), hdr_value = str_init(DEFLATE_ALGO); wrap_copy_and_update(&buf2send.s, hdr_name.s, hdr_name.len, &buf2send.len); if (flags & B64_ENCODED_FLG) { wrap_copy_and_update(&buf2send.s, BASE64_ALGO, sizeof(BASE64_ALGO)-1, &buf2send.len); wrap_copy_and_update(&buf2send.s, ATTR_DELIM, ATTR_DELIM_LEN, &buf2send.len); } wrap_copy_and_update(&buf2send.s, hdr_value.s, hdr_value.len, &buf2send.len); wrap_copy_and_update(&buf2send.s, CRLF, CRLF_LEN, &buf2send.len); } if (bufencoded.s) { wrap_copy_and_update(&buf2send.s, CE_NAME, CE_NAME_LEN, &buf2send.len); if (flags & B64_ENCODED_FLG) { wrap_copy_and_update(&buf2send.s, BASE64_ALGO, sizeof(BASE64_ALGO)-1, &buf2send.len); wrap_copy_and_update(&buf2send.s, ATTR_DELIM, ATTR_DELIM_LEN, &buf2send.len); } wrap_copy_and_update(&buf2send.s, DEFLATE_ALGO, sizeof(DEFLATE_ALGO)-1, &buf2send.len); wrap_copy_and_update(&buf2send.s, CRLF, CRLF_LEN, &buf2send.len); } break; case 1: /* gzip */ if (hdr_bufencoded.s) { str hdr_name = str_init(HDRS_ENCODING), hdr_value = str_init(GZIP_ALGO); if (flags & B64_ENCODED_FLG) { wrap_copy_and_update(&buf2send.s, BASE64_ALGO, sizeof(BASE64_ALGO)-1, &buf2send.len); wrap_copy_and_update(&buf2send.s, ATTR_DELIM, ATTR_DELIM_LEN, &buf2send.len); } wrap_copy_and_update(&buf2send.s, hdr_name.s, hdr_name.len, &buf2send.len); wrap_copy_and_update(&buf2send.s, hdr_value.s, hdr_value.len, &buf2send.len); wrap_copy_and_update(&buf2send.s, CRLF, CRLF_LEN, &buf2send.len); } if (bufencoded.s) { wrap_copy_and_update(&buf2send.s, CE_NAME, CE_NAME_LEN, &buf2send.len); if (flags & B64_ENCODED_FLG) { wrap_copy_and_update(&buf2send.s, BASE64_ALGO, sizeof(BASE64_ALGO)-1, &buf2send.len); wrap_copy_and_update(&buf2send.s, ATTR_DELIM, ATTR_DELIM_LEN, &buf2send.len); } wrap_copy_and_update(&buf2send.s, GZIP_ALGO, sizeof(GZIP_ALGO)-1, &buf2send.len); wrap_copy_and_update(&buf2send.s, CRLF, CRLF_LEN, &buf2send.len); } break; default: LM_ERR("compression algo not impelemented\n"); goto free_mem_full; } /* Copy message body */ if (bufencoded.s) { wrap_copy_and_update( &buf2send.s, bufencoded.s, bufencoded.len+CRLF_LEN, &buf2send.len); wrap_copy_and_update( &buf2send.s, CRLF, CRLF_LEN, &buf2send.len); } else { wrap_copy_and_update( &buf2send.s, buf, strlen(buf), &buf2send.len); } switch (type) { case TM_CB: shm_free(*buf_p); *buf_p = shm_malloc(buf2send.len+1); if (*buf_p == NULL) { LM_ERR("no more sh mem\n"); goto free_mem_full; } break; case PROCESSING_CB: *buf_p = pkg_malloc(buf2send.len+1); if (*buf_p == NULL) { LM_ERR("no more pkg mem\n"); goto free_mem_full; } break; default: LM_ERR("invalid type\n"); goto free_mem_full; } memcpy(*buf_p, buf2send.s, buf2send.len); (*buf_p)[buf2send.len] = '\0'; *olen = buf2send.len; free_hdr_list(&mnd_hdrs_head); free_hdr_list(&non_mnd_hdrs_head); if (wh_param && wh_param->type == WH_TYPE_PVS) free_whitelist(&hdr2compress_list); return 0; free_mem_full: free_hdr_list(&mnd_hdrs_head); free_hdr_list(&non_mnd_hdrs_head); if (wh_param && wh_param->type == WH_TYPE_PVS) free_whitelist(&hdr2compress_list); return -1; }
int main(int argc, char **argv) { header_keys keys; u8 rawkheaderBk[0x90]; if(argc < 2) { printf("USAGE: PrxEncrypter [prx]\n"); return 0; } memset(in_buffer, 0, sizeof(in_buffer)); memset(out_buffer, 0, sizeof(out_buffer)); memset(kirk_raw, 0, sizeof(kirk_raw)); memset(kirk_enc, 0, sizeof(kirk_enc)); memset(elf, 0, sizeof(elf)); kirk_init(); int elfSize = load_elf(argv[1]); if(elfSize < 0) { printf("Cannot open %s\n", argv[1]); return 0; } Header_List *target_header = get_header_list( elfSize ); if( target_header == NULL ) { printf("PRX SIGNER: Elf is to big\n"); return 0; } u8 *kirkHeader = target_header->kirkHeader; u8 *pspHeader = target_header->pspHeader; int krawSize = get_kirk_size(kirkHeader); if (is_compressed(pspHeader)) { elfSize = get_elf_size(pspHeader); gzip_compress(elf, elf, elfSize); } memcpy(kirk_raw, kirkHeader, 0x110); memcpy(rawkheaderBk, kirk_raw, sizeof(rawkheaderBk)); kirk_decrypt_keys((u8*)&keys, kirk_raw); memcpy(kirk_raw, &keys, sizeof(header_keys)); memcpy(kirk_raw+0x110, elf, elfSize); if(kirk_CMD0(kirk_enc, kirk_raw, sizeof(kirk_enc), 0) != 0) { printf("PRX SIGNER: Could not encrypt elf\n"); return 0; } memcpy(kirk_enc, rawkheaderBk, sizeof(rawkheaderBk)); if(kirk_forge(kirk_enc, sizeof(kirk_enc)) != 0) { printf("PRX SIGNER: Could not forge cmac block\n"); return 0; } memcpy(out_buffer, pspHeader, 0x150); memcpy(out_buffer+0x150, kirk_enc+0x110, krawSize-0x110); return dumpFile("./data.psp", out_buffer, (krawSize-0x110)+0x150); }
/** * This handles requests that are daap-related. For example, * /server-info, /login, etc. This should really be split up * into multiple functions, and perhaps moved into daap.c * * \param pwsc Webserver connection info, passed from the webserver * * \todo Decomplexify this! */ void daap_handler(WS_CONNINFO *pwsc) { int close; DAAP_BLOCK *root; int clientrev; /* for the /databases URI */ char *uri; unsigned long int db_index; unsigned long int playlist_index; unsigned long int item=0; char *first, *last; char* index = 0; int streaming=0; int compress =0; int start_time; int end_time; int bytes_written; MP3FILE *pmp3; int file_fd; int session_id=0; int img_fd; struct stat sb; long img_size; off_t offset=0; off_t real_len; off_t file_len; int bytes_copied=0; GZIP_STREAM *gz; close=pwsc->close; pwsc->close=1; /* in case we have any errors */ root=NULL; ws_addresponseheader(pwsc,"Accept-Ranges","bytes"); ws_addresponseheader(pwsc,"DAAP-Server","mt-daapd/%s",VERSION); ws_addresponseheader(pwsc,"Content-Type","application/x-dmap-tagged"); if(ws_getvar(pwsc,"session-id")) { session_id=atoi(ws_getvar(pwsc,"session-id")); } if(!strcasecmp(pwsc->uri,"/server-info")) { config_set_status(pwsc,session_id,"Sending server info"); root=daap_response_server_info(config.servername, ws_getrequestheader(pwsc,"Client-DAAP-Version")); } else if (!strcasecmp(pwsc->uri,"/content-codes")) { config_set_status(pwsc,session_id,"Sending content codes"); root=daap_response_content_codes(); } else if (!strcasecmp(pwsc->uri,"/login")) { config_set_status(pwsc,session_id,"Logging in"); root=daap_response_login(pwsc->hostname); } else if (!strcasecmp(pwsc->uri,"/update")) { if(!ws_getvar(pwsc,"delta")) { /* first check */ clientrev=db_version() - 1; config_set_status(pwsc,session_id,"Sending database"); } else { clientrev=atoi(ws_getvar(pwsc,"delta")); config_set_status(pwsc,session_id,"Waiting for DB updates"); } root=daap_response_update(pwsc->fd,clientrev); if((ws_getvar(pwsc,"delta")) && (root==NULL)) { DPRINTF(E_LOG,L_WS,"Client %s disconnected\n",pwsc->hostname); config_set_status(pwsc,session_id,NULL); pwsc->close=1; return; } } else if (!strcasecmp(pwsc->uri,"/logout")) { config_set_status(pwsc,session_id,NULL); ws_returnerror(pwsc,204,"Logout Successful"); return; } else if(strcmp(pwsc->uri,"/databases")==0) { config_set_status(pwsc,session_id,"Sending database info"); root=daap_response_dbinfo(config.servername); if(0 != (index = ws_getvar(pwsc, "index"))) daap_handle_index(root, index); } else if(strncmp(pwsc->uri,"/databases/",11) == 0) { /* the /databases/ uri will either be: * * /databases/id/items, which returns items in a db * /databases/id/containers, which returns a container * /databases/id/containers/id/items, which returns playlist elements * /databases/id/items/id.mp3, to spool an mp3 * /databases/id/browse/category */ uri = strdup(pwsc->uri); first=(char*)&uri[11]; last=first; while((*last) && (*last != '/')) { last++; } if(*last) { *last='\0'; db_index=atoll(first); last++; if(strncasecmp(last,"items/",6)==0) { /* streaming */ first=last+6; while((*last) && (*last != '.')) last++; if(*last == '.') { *last='\0'; item=atoll(first); streaming=1; DPRINTF(E_DBG,L_DAAP|L_WS,"Streaming request for id %lu\n",item); } free(uri); } else if (strncasecmp(last,"items",5)==0) { /* songlist */ free(uri); // pass the meta field request for processing // pass the query request for processing root=daap_response_songlist(ws_getvar(pwsc,"meta"), ws_getvar(pwsc,"query")); config_set_status(pwsc,session_id,"Sending songlist"); } else if (strncasecmp(last,"containers/",11)==0) { /* playlist elements */ first=last + 11; last=first; while((*last) && (*last != '/')) { last++; } if(*last) { *last='\0'; playlist_index=atoll(first); // pass the meta list info for processing root=daap_response_playlist_items(playlist_index, ws_getvar(pwsc,"meta"), ws_getvar(pwsc,"query")); } free(uri); config_set_status(pwsc,session_id,"Sending playlist info"); } else if (strncasecmp(last,"containers",10)==0) { /* list of playlists */ free(uri); root=daap_response_playlists(config.servername); config_set_status(pwsc,session_id,"Sending playlist info"); } else if (strncasecmp(last,"browse/",7)==0) { config_set_status(pwsc,session_id,"Compiling browse info"); root = daap_response_browse(last + 7, ws_getvar(pwsc, "filter")); config_set_status(pwsc,session_id,"Sending browse info"); free(uri); } } // prune the full list if an index range was specified if(0 != (index = ws_getvar(pwsc, "index"))) daap_handle_index(root, index); } if((!root)&&(!streaming)) { DPRINTF(E_DBG,L_WS|L_DAAP,"Bad request -- root=%x, streaming=%d\n",root,streaming); ws_returnerror(pwsc,400,"Invalid Request"); config_set_status(pwsc,session_id,NULL); return; } pwsc->close=close; if(!streaming) { DPRINTF(E_DBG,L_WS,"Satisfying request\n"); if((config.compress) && ws_testrequestheader(pwsc,"Accept-Encoding","gzip") && root->reported_size >= 1000) { compress=1; } DPRINTF(E_DBG,L_WS|L_DAAP,"Serializing\n"); start_time = time(NULL); if (compress) { DPRINTF(E_DBG,L_WS|L_DAAP,"Using compression: %s\n", pwsc->uri); gz = gzip_alloc(); daap_serialize(root,pwsc->fd,gz); gzip_compress(gz); bytes_written = gz->bytes_out; ws_writefd(pwsc,"HTTP/1.1 200 OK\r\n"); ws_addresponseheader(pwsc,"Content-Length","%d",bytes_written); ws_addresponseheader(pwsc,"Content-Encoding","gzip"); DPRINTF(E_DBG,L_WS,"Emitting headers\n"); ws_emitheaders(pwsc); if (gzip_close(gz,pwsc->fd) != bytes_written) { DPRINTF(E_LOG,L_WS|L_DAAP,"Error compressing data\n"); } DPRINTF(E_DBG,L_WS|L_DAAP,"Compression ratio: %f\n",((double) bytes_written)/(8.0 + root->reported_size)) } else {