int himd_blockstream_open(struct himd * himd, unsigned int firstfrag, unsigned int frags_per_block, struct himd_blockstream * stream, struct himderrinfo * status) { struct fraginfo frag; unsigned int fragcount, fragnum, blockcount; g_return_val_if_fail(himd != NULL, -1); g_return_val_if_fail(firstfrag >= HIMD_FIRST_FRAGMENT, -1); g_return_val_if_fail(firstfrag <= HIMD_LAST_FRAGMENT, -1); g_return_val_if_fail(stream != NULL, -1); stream->himd = himd; for(fragcount = 0, blockcount = 0, fragnum = firstfrag; fragnum != 0; fragcount++) { if(himd_get_fragment_info(himd, fragnum, &frag, status) < 0) return -1; fragnum = frag.nextfrag; if(fragcount > HIMD_LAST_FRAGMENT) { set_status_printf(status, HIMD_ERROR_FRAGMENT_CHAIN_BROKEN, _("Fragment chain starting at %d loops"), firstfrag); return -1; } blockcount += frag.lastblock - frag.firstblock + 1; } stream->frags = malloc(fragcount * sizeof stream->frags[0]); if(!stream->frags) { set_status_printf(status, HIMD_ERROR_OUT_OF_MEMORY, _("Can't allocate %d fragments for chain starting at %d"), fragcount, firstfrag); return -1; } stream->fragcount = fragcount; stream->blockcount = blockcount; stream->curfragno = 0; for(fragcount = 0, fragnum = firstfrag; fragnum != 0; fragcount++) { if(himd_get_fragment_info(himd, fragnum, &stream->frags[fragcount], status) < 0) return -1; fragnum = stream->frags[fragcount].nextfrag; } stream->atdata = himd_open_file(himd, "ATDATA", HIMD_READ_ONLY); if(!stream->atdata) { set_status_printf(status, HIMD_ERROR_CANT_OPEN_AUDIO, _("Can't open audio data: %s"), g_strerror(errno)); free(stream->frags); return -1; } stream->curblockno = stream->frags[0].firstblock; stream->frames_per_block = frags_per_block; return 0; }
int himd_nonmp3stream_open(struct himd * himd, unsigned int trackno, struct himd_nonmp3stream * stream, struct himderrinfo * status) { struct trackinfo trkinfo; g_return_val_if_fail(himd != NULL, -1); g_return_val_if_fail(trackno >= HIMD_FIRST_TRACK, -1); g_return_val_if_fail(trackno <= HIMD_LAST_TRACK, -1); g_return_val_if_fail(stream != NULL, -1); if(himd_get_track_info(himd, trackno, &trkinfo, status) < 0) return -1; if((trkinfo.codec_id != CODEC_LPCM) && (trkinfo.codec_id != CODEC_ATRAC3) && (trkinfo.codec_id != CODEC_ATRAC3PLUS_OR_MPEG || (trkinfo.codecinfo[0] & 3) != 0)) { set_status_printf(status, HIMD_ERROR_BAD_AUDIO_CODEC, _("Track %d does not contain PCM, ATRAC3 or ATRAC3+ data"), trackno); return -1; } if(himd_blockstream_open(himd, trkinfo.firstfrag, himd_trackinfo_framesperblock(&trkinfo), &stream->stream, status) < 0) return -1; if(descrypt_open(&stream->cryptinfo, trkinfo.key, trkinfo.ekbnum, status) < 0) { himd_blockstream_close(&stream->stream); return -1; } stream->framesize = himd_trackinfo_framesize(&trkinfo); stream->framesleft = 0; return 0; }
int himd_mp3stream_open(struct himd * himd, unsigned int trackno, struct himd_mp3stream * stream, struct himderrinfo * status) { struct trackinfo trkinfo; g_return_val_if_fail(himd != NULL, -1); g_return_val_if_fail(trackno >= HIMD_FIRST_TRACK, -1); g_return_val_if_fail(trackno <= HIMD_LAST_TRACK, -1); g_return_val_if_fail(stream != NULL, -1); if(himd_get_track_info(himd, trackno, &trkinfo, status) < 0) return -1; if(trkinfo.codec_id != CODEC_ATRAC3PLUS_OR_MPEG || (trkinfo.codecinfo[0] & 3) != 3) { set_status_printf(status, HIMD_ERROR_BAD_AUDIO_CODEC, _("Track %d does not contain MPEG data"), trackno); return -1; } if(himd_obtain_mp3key(himd, trackno, &stream->key, status) < 0) return -1; if(himd_blockstream_open(himd, trkinfo.firstfrag, TRACK_IS_MPEG, &stream->stream, status) < 0) return -1; stream->frames = 0; stream->curframe = 0; stream->frameptrs = NULL; return 0; }
unsigned int himd_get_trackslot(struct himd * himd, unsigned int idx, struct himderrinfo * status) { if(idx >= himd_track_count(himd)) { set_status_printf(status, HIMD_ERROR_NO_SUCH_TRACK, _("Track %d of %d requested")); return 0; } return beword16(himd->tifdata + 0x102 + 2*idx); }
char* himd_get_string_utf8(struct himd * himd, unsigned int idx, int*type, struct himderrinfo * status) { int length; char * out; char * srcencoding; char * rawstr; GError * err = NULL; g_return_val_if_fail(himd != NULL, NULL); g_return_val_if_fail(idx >= 1, NULL); g_return_val_if_fail(idx < 4096, NULL); rawstr = himd_get_string_raw(himd, idx, type, &length, status); if(!rawstr) return NULL; switch((unsigned char)rawstr[0]) { case HIMD_ENCODING_LATIN1: srcencoding = "ISO-8859-1"; break; case HIMD_ENCODING_UTF16BE: srcencoding = "UTF-16BE"; break; case HIMD_ENCODING_SHIFT_JIS: srcencoding = "SHIFT_JIS"; break; default: set_status_printf(status, HIMD_ERROR_UNKNOWN_ENCODING, "string %d has unknown encoding with ID %d", idx, rawstr[0]); himd_free(rawstr); return NULL; } out = g_convert(rawstr+1,length-1,"UTF-8",srcencoding,NULL,NULL,&err); himd_free(rawstr); if(err) { set_status_printf(status, HIMD_ERROR_STRING_ENCODING_ERROR, "convert string %d from %s to UTF-8: %s", idx, srcencoding, err->message); return NULL; } return out; }
static void on_socket_client_event (GSocketClient *client, GSocketClientEvent event, GSocketConnectable *connectable, GIOStream *connection, gpointer user_data) { HotSshTab *self = HOTSSH_TAB (user_data); HotSshTabPrivate *priv = hotssh_tab_get_instance_private (self); switch (event) { case G_SOCKET_CLIENT_RESOLVING: set_status_printf (self, _("Resolving '%s'…"), priv->hostname); break; case G_SOCKET_CLIENT_CONNECTING: { GSocketConnection *socketconn = G_SOCKET_CONNECTION (connection); gs_unref_object GSocketAddress *remote_address = g_socket_connection_get_remote_address (socketconn, NULL); g_debug ("socket connecting remote=%p", remote_address); if (remote_address && G_IS_INET_SOCKET_ADDRESS (remote_address)) { GInetAddress *inetaddr = g_inet_socket_address_get_address ((GInetSocketAddress*)remote_address); gs_free char *inet_str = g_inet_address_to_string (inetaddr); set_status_printf (self, _("Connecting to '%s'…"), inet_str); } break; } default: break; } }
int descrypt_decrypt(void * dataptr, unsigned char * block, size_t cryptlen, const unsigned char * fragkey, struct himderrinfo * status) { unsigned char finalfragkey[8]; unsigned char mainkey[8]; struct descrypt_data * data = dataptr; int err; xor_keys(finalfragkey, data->masterkey, fragkey); if((err = cached_cipher_prepare(&data->master, finalfragkey, NULL)) < 0) { set_status_printf(status, HIMD_ERROR_ENCRYPTION_FAILURE, _("Can't setup track key: %s"), mcrypt_strerror(err)); return -1; } memcpy(mainkey, block+16, 8); if((err = mcrypt_generic(data->master.cipher, mainkey, 8)) < 0) { set_status_printf(status, HIMD_ERROR_ENCRYPTION_FAILURE, _("Can't calc block key: %s"), mcrypt_strerror(err)); return -1; } if((err = cached_cipher_prepare(&data->block, mainkey, block + 24)) < 0) { set_status_printf(status, HIMD_ERROR_ENCRYPTION_FAILURE, _("Can't setup block key: %s"), mcrypt_strerror(err)); return -1; } if((err = mdecrypt_generic(data->block.cipher, block+32, cryptlen)) < 0) { set_status_printf(status, HIMD_ERROR_ENCRYPTION_FAILURE, _("Can't decrypt: %s"), mcrypt_strerror(err)); return -1; } return 0; }
int himd_get_track_info(struct himd * himd, unsigned int idx, struct trackinfo * t, struct himderrinfo * status) { unsigned char * trackbuffer; unsigned int firstpart; g_return_val_if_fail(himd != NULL, -1); g_return_val_if_fail(idx >= HIMD_FIRST_TRACK, -1); g_return_val_if_fail(idx <= HIMD_LAST_TRACK, -1); g_return_val_if_fail(t != NULL, -1); trackbuffer = get_track(himd, idx); firstpart = beword16(trackbuffer+36); if(firstpart == 0) { set_status_printf(status, HIMD_ERROR_NO_SUCH_TRACK, _("Track %d is not present on disc"), idx); return -1; } get_dostime(&t->recordingtime,trackbuffer+0); t->ekbnum = beword32(trackbuffer+4); t->title = beword16(trackbuffer+8); t->artist = beword16(trackbuffer+10); t->album = beword16(trackbuffer+12); t->trackinalbum = trackbuffer[14]; memcpy(t->key, trackbuffer+16,8); memcpy(t->mac, trackbuffer+24,8); t->codec_id = trackbuffer[32]; memcpy(t->codecinfo,trackbuffer+33,3); memcpy(t->codecinfo+3,trackbuffer+44,2); t->firstfrag = firstpart; t->tracknum = beword16(trackbuffer+38); t->seconds = beword16(trackbuffer+40); memcpy(t->contentid,trackbuffer+48,20); get_dostime(&t->starttime,trackbuffer+68); get_dostime(&t->endtime,trackbuffer+72); return 0; }
int himd_add_string(struct himd * himd, char *string, int type, struct himderrinfo * status) { int curidx, curtype, i, nextidx; int nslots; int idx_firstslot; gsize length; gchar * convertedstring; unsigned char * curchunk; unsigned char strencoding; g_return_val_if_fail(himd != NULL, -1); g_return_val_if_fail(string != NULL, -1); /* try to use Latin-1 or Shift-JIS. If that fails, use Unicode. */ if((convertedstring = g_convert(string,-1,"ISO-8859-1","UTF8", NULL,&length,NULL)) != NULL) strencoding = HIMD_ENCODING_LATIN1; else if((convertedstring = g_convert(string,-1,"SHIFT_JIS","UTF8", NULL,&length,NULL)) != NULL) strencoding = HIMD_ENCODING_SHIFT_JIS; else if((convertedstring = g_convert(string,-1,"UTF-16BE","UTF8", NULL,&length,NULL)) != NULL) strencoding = HIMD_ENCODING_UTF16BE; else { /* should never happen, as utf-16 can encode anything */ set_status_printf(status, HIMD_ERROR_UNKNOWN_ENCODING, "can't encode the string '%s' into anything usable", string); return -1; } /* how many number of slots to store string in? */ nslots = (length+14)/14; /* +13 for rounding up, +1 for the encoding byte */ /* check that there are enough free slots. Start at slot 0 which is the head of the free list. */ curidx = 0; for(i = 0; i < nslots; i--) { curtype = strtype(get_strchunk(himd, curidx)); curidx = strlink(get_strchunk(himd, curidx)); if(!curidx) { g_free(convertedstring); set_status_printf(status, HIMD_ERROR_OUT_OF_STRINGS, "Not enough string space to allocate %d string slots\n", nslots); return -1; } if(curtype != STRING_TYPE_UNUSED) { g_free(convertedstring); set_status_printf(status, HIMD_ERROR_STRING_CHAIN_BROKEN, "String slot %d in free list has type %d\n", curidx, curtype); return -1; } } idx_firstslot = strlink(get_strchunk(himd, 0)); curidx = idx_firstslot; for(i = 0; i < nslots; i++) { /* reserve space for the encoding byte in the first slot */ gsize slotlen = (i != 0) ? 14 : 13; gsize stroffset = i*14 - 1; /* limit length to what is remaining of the string */ if(slotlen > length - stroffset) slotlen = length - stroffset; curchunk = get_strchunk(himd, curidx); nextidx = strlink(curchunk); if(i == 0) { curchunk[0] = strencoding; memcpy(curchunk + 1, convertedstring, slotlen); set_strtype(curchunk, type); } else { memcpy(curchunk, convertedstring + stroffset, slotlen); set_strtype(curchunk, STRING_TYPE_CONTINUATION); } if(i == nslots-1) set_strlink(curchunk, 0); curidx = nextidx; } /* adjust free list head pointer */ set_strlink(get_strchunk(himd, 0), curidx); g_free(convertedstring); return idx_firstslot; }
char* himd_get_string_raw(struct himd * himd, unsigned int idx, int*type, int* length, struct himderrinfo * status) { int curidx; int len; char * rawstr; int actualtype; g_return_val_if_fail(himd != NULL, NULL); g_return_val_if_fail(idx >= 1, NULL); g_return_val_if_fail(idx < 4096, NULL); actualtype = strtype(get_strchunk(himd,idx)); /* Not the head of a string */ if(actualtype < 8) { set_status_printf(status, HIMD_ERROR_NOT_STRING_HEAD, _("String table entry %d is not a head: Type %d"), idx,actualtype); return NULL; } if(type != NULL) *type = actualtype; /* Get length of string */ len = 1; for(curidx = strlink(get_strchunk(himd,idx)); curidx != 0; curidx = strlink(get_strchunk(himd,curidx))) { if(strtype(get_strchunk(himd,curidx)) != STRING_TYPE_CONTINUATION) { set_status_printf(status, HIMD_ERROR_STRING_CHAIN_BROKEN, _("%dth entry in string chain starting at %d has type %d"), len+1,idx,strtype(get_strchunk(himd,curidx))); return NULL; } len++; if(len >= 4096) { set_status_printf(status, HIMD_ERROR_STRING_CHAIN_BROKEN, _("string chain starting at %d loops"),idx); return NULL; } } /* collect fragments */ rawstr = g_malloc(len*14); if(!rawstr) { set_status_printf(status, HIMD_ERROR_OUT_OF_MEMORY, _("Can't allocate %d bytes for raw string (string idx %d)"), len, idx); return NULL; } len = 0; for(curidx = idx; curidx != 0; curidx = strlink(get_strchunk(himd,curidx))) { memcpy(rawstr+len*14,get_strchunk(himd,curidx),14); len++; } *length = 14*len; return rawstr; }
int himd_blockstream_read(struct himd_blockstream * stream, unsigned char * block, unsigned int * firstframe, unsigned int * lastframe, unsigned char * fragkey, struct himderrinfo * status) { struct fraginfo * curfrag; g_return_val_if_fail(stream != NULL, -1); g_return_val_if_fail(block != NULL, -1); if(stream->curfragno == stream->fragcount) { set_status_const(status, HIMD_STATUS_AUDIO_EOF, _("EOF of audio stream reached")); return -1; } curfrag = &stream->frags[stream->curfragno]; if(stream->curblockno == curfrag->firstblock) { if(firstframe) *firstframe = curfrag->firstframe; if(fseek(stream->atdata, stream->curblockno*16384L, SEEK_SET) < 0) { set_status_printf(status, HIMD_ERROR_CANT_SEEK_AUDIO, _("Can't seek in audio data: %s"), g_strerror(errno)); return -1; } } else if(firstframe) *firstframe = 0; if(fread(block, 16384, 1, stream->atdata) != 1) { if(feof(stream->atdata)) set_status_printf(status, HIMD_ERROR_CANT_READ_AUDIO, _("Unexpected EOF while reading audio block %d"),stream->curblockno); else set_status_printf(status, HIMD_ERROR_CANT_READ_AUDIO, _("Read error on block audio %d: %s"), stream->curblockno, g_strerror(errno)); return -1; } if(fragkey) memcpy(fragkey, curfrag->key, sizeof curfrag->key); if(stream->curblockno == curfrag->lastblock) { if(lastframe) { if(is_mpeg(stream)) *lastframe = curfrag->lastframe - 1; else *lastframe = curfrag->lastframe; } stream->curfragno++; curfrag++; if(stream->curfragno < stream->fragcount) stream->curblockno = curfrag->firstblock; } else { if(lastframe) { if(is_mpeg(stream)) *lastframe = beword16(block+4) - 1; else *lastframe = stream->frames_per_block - 1; } stream->curblockno++; } return 0; }
int himd_mp3stream_read_block(struct himd_mp3stream * stream, const unsigned char ** frameout, unsigned int * lenout, unsigned int * framecount, struct himderrinfo * status) { unsigned int i; unsigned int firstframe, lastframe; unsigned int dataframes, databytes; /* partial block remaining, return all remaining frames */ if(stream->curframe < stream->frames) { if(frameout) *frameout = stream->frameptrs[stream->curframe]; if(lenout) *lenout = stream->frameptrs[stream->frames] - stream->frameptrs[stream->curframe]; if(framecount) *framecount = stream->frames - stream->curframe; stream->curframe = stream->frames; return 0; } /* need to read next block */ if(himd_blockstream_read(&stream->stream, stream->blockbuf, &firstframe, &lastframe, NULL, status) < 0) return -1; free(stream->frameptrs); stream->frameptrs = NULL; if(firstframe > lastframe) { set_status_printf(status, HIMD_ERROR_BAD_FRAME_NUMBERS, _("Last frame %u before first frame %u"), lastframe, firstframe); return -1; } dataframes = beword16(stream->blockbuf+4); databytes = beword16(stream->blockbuf+8); if(databytes > 0x3FC0) { set_status_printf(status, HIMD_ERROR_BAD_DATA_FORMAT, _("Block contains %u MPEG data bytes, which is too much"), databytes); return -1; } if(lastframe >= dataframes) { set_status_printf(status, HIMD_ERROR_BAD_FRAME_NUMBERS, _("Last requested frame %u past number of frames %u"), lastframe, dataframes); return -1; } /* Decrypt block */ for(i = 0;i < (databytes & ~7U);i++) stream->blockbuf[i+0x20] ^= stream->key[i & 3]; /* Indicate completely consumed block be sure to set this *before* writing to *framecont, it might alias stream->frames! */ stream->frames = 0; stream->curframe = 0; /* The common case - all frames belong to the stream to read. If compiled without MAD, always put all frames into the block */ #ifndef CONFIG_WITH_MAD if(firstframe == 0 && lastframe == dataframes - 1) #endif { if(frameout) *frameout = stream->blockbuf + 0x20; if(lenout) *lenout = databytes; if(framecount) *framecount = dataframes; return 0; } #ifdef CONFIG_WITH_MAD if(himd_mp3stream_split_frames(stream, databytes, firstframe, lastframe, status) < 0) return -1; if(*framecount) *framecount = lastframe - firstframe + 1; #endif return 0; }
static int himd_mp3stream_split_frames(struct himd_mp3stream * stream, unsigned int databytes, unsigned int firstframe, unsigned int lastframe, struct himderrinfo * status) { int gotdata = 1; unsigned int i; struct mad_stream madstream; struct mad_header madheader; /* stream->frameptrs is NULL if the current frame has not been splitted yet */ g_warn_if_fail(stream->frameptrs == NULL); stream->frameptrs = malloc((lastframe - firstframe + 2) * sizeof stream->frameptrs[0]); if(!stream->frameptrs) { set_status_printf(status, HIMD_ERROR_OUT_OF_MEMORY, _("Can't allocate memory for %u frame pointers"), lastframe-firstframe+2); return -1; } /* parse block */ mad_stream_init(&madstream); mad_header_init(&madheader); mad_stream_buffer(&madstream, &stream->blockbuf[0x20], databytes+MAD_BUFFER_GUARD); /* drop unneeded frames in front */ while(firstframe > 0) { if(mad_header_decode(&madheader, &madstream) < 0) { set_status_printf(status, HIMD_ERROR_BAD_DATA_FORMAT, _("Still %u frames to skip: %s"), firstframe, mad_stream_errorstr(&madstream)); gotdata = 0; goto cleanup_decoder; } firstframe--; lastframe--; } /* store needed frames */ for(i = 0;i <= lastframe;i++) { if(mad_header_decode(&madheader, &madstream) < 0 && (madstream.error != MAD_ERROR_LOSTSYNC || i != lastframe)) { set_status_printf(status, HIMD_ERROR_BAD_DATA_FORMAT, _("Frame %u of %u to store: %s"), i+1, lastframe, mad_stream_errorstr(&madstream)); gotdata = 0; goto cleanup_decoder; } stream->frameptrs[i] = madstream.this_frame; } stream->frameptrs[i] = madstream.next_frame; stream->frames = lastframe+1; stream->curframe = 0; cleanup_decoder: mad_header_finish(&madheader); mad_stream_finish(&madstream); if(!gotdata) return -1; return 0; }