Beispiel #1
0
/**
  Testuje wczytywanie drzewa.
  @param state Środowisko testowe.
  */
static void trie_load_test(void** state)
{
    Trie *trie = NULL;

    IO *io = io_new(stdin, stdout, stderr);

    push_word_to_io_mock(L"");
    trie = trie_load(io);
    assert_non_null(trie);
    trie_done(trie);

    // Poprawny zapis
    push_word_to_io_mock(L"ciupagą*^^^^^^^\n");
    trie = trie_load(io);
    pop_remaining_chars(io);
    assert_true(trie_has_word(trie, L"ciupagą"));
    assert_false(trie_has_word(trie, L"ciupaga"));
    assert_false(trie_has_word(trie, L"ciupag"));
    assert_false(trie_has_word(trie, L"ciupagąą"));
    trie_done(trie);

    // Próba dojścia wyżej niż korzeń
    push_word_to_io_mock(L"a*^^\n");
    trie = trie_load(io);
    pop_remaining_chars(io);
    assert_null(trie);

    // Znaki spoza alfabetu
    push_word_to_io_mock(L"&*^\n");
    trie = trie_load(io);
    pop_remaining_chars();
    assert_null(trie);

    io_done(io);
}
Beispiel #2
0
struct hfp_gw *hfp_gw_new(int fd)
{
	struct hfp_gw *hfp;

	if (fd < 0)
		return NULL;

	hfp = new0(struct hfp_gw, 1);
	if (!hfp)
		return NULL;

	hfp->fd = fd;
	hfp->close_on_unref = false;

	hfp->read_buf = ringbuf_new(4096);
	if (!hfp->read_buf) {
		free(hfp);
		return NULL;
	}

	hfp->write_buf = ringbuf_new(4096);
	if (!hfp->write_buf) {
		ringbuf_free(hfp->read_buf);
		free(hfp);
		return NULL;
	}

	hfp->io = io_new(fd);
	if (!hfp->io) {
		ringbuf_free(hfp->write_buf);
		ringbuf_free(hfp->read_buf);
		free(hfp);
		return NULL;
	}

	hfp->cmd_handlers = queue_new();
	if (!hfp->cmd_handlers) {
		io_destroy(hfp->io);
		ringbuf_free(hfp->write_buf);
		ringbuf_free(hfp->read_buf);
		free(hfp);
		return NULL;
	}

	if (!io_set_read_handler(hfp->io, can_read_data, hfp,
							read_watch_destroy)) {
		queue_destroy(hfp->cmd_handlers, destroy_cmd_handler);
		io_destroy(hfp->io);
		ringbuf_free(hfp->write_buf);
		ringbuf_free(hfp->read_buf);
		free(hfp);
		return NULL;
	}

	hfp->writer_active = false;
	hfp->result_pending = false;

	return hfp_gw_ref(hfp);
}
static struct bt_hci *create_hci(int fd)
{
	struct bt_hci *hci;

	if (fd < 0)
		return NULL;

	hci = new0(struct bt_hci, 1);
	if (!hci)
		return NULL;

	hci->io = io_new(fd);
	if (!hci->io) {
		free(hci);
		return NULL;
	}

	hci->is_stream = true;
	hci->writer_active = false;
	hci->num_cmds = 1;
	hci->next_cmd_id = 1;
	hci->next_evt_id = 1;

	hci->cmd_queue = queue_new();
	if (!hci->cmd_queue) {
		io_destroy(hci->io);
		free(hci);
		return NULL;
	}

	hci->rsp_queue = queue_new();
	if (!hci->rsp_queue) {
		queue_destroy(hci->cmd_queue, NULL);
		io_destroy(hci->io);
		free(hci);
		return NULL;
	}

	hci->evt_list = queue_new();
	if (!hci->evt_list) {
		queue_destroy(hci->rsp_queue, NULL);
		queue_destroy(hci->cmd_queue, NULL);
		io_destroy(hci->io);
		free(hci);
		return NULL;
	}

	if (!io_set_read_handler(hci->io, io_read_callback, hci, NULL)) {
		queue_destroy(hci->evt_list, NULL);
		queue_destroy(hci->rsp_queue, NULL);
		queue_destroy(hci->cmd_queue, NULL);
		io_destroy(hci->io);
		free(hci);
		return NULL;
	}

	return bt_hci_ref(hci);
}
Beispiel #4
0
struct bt_att *bt_att_new(int fd)
{
	struct bt_att *att;

	if (fd < 0)
		return NULL;

	att = new0(struct bt_att, 1);
	if (!att)
		return NULL;

	att->fd = fd;

	att->mtu = ATT_DEFAULT_LE_MTU;
	att->buf = malloc(att->mtu);
	if (!att->buf)
		goto fail;

	att->io = io_new(fd);
	if (!att->io)
		goto fail;

	att->req_queue = queue_new();
	if (!att->req_queue)
		goto fail;

	att->ind_queue = queue_new();
	if (!att->ind_queue)
		goto fail;

	att->write_queue = queue_new();
	if (!att->write_queue)
		goto fail;

	att->notify_list = queue_new();
	if (!att->notify_list)
		goto fail;

	if (!io_set_read_handler(att->io, can_read_data, att, NULL))
		goto fail;

	return bt_att_ref(att);

fail:
	queue_destroy(att->req_queue, NULL);
	queue_destroy(att->ind_queue, NULL);
	queue_destroy(att->write_queue, NULL);
	io_destroy(att->io);
	free(att->buf);
	free(att);

	return NULL;
}
Beispiel #5
0
/* ------------------------------------------------------------------------ *
 * Open a file.                                                             *
 * ------------------------------------------------------------------------ */
int io_open(const char *path, int mode, ...)
{
  int         fd;
  int         flags = 0;
  int         ret;
  struct stat st;
  va_list     args;

#ifdef O_BINARY
  flags |= O_BINARY;
#endif

  switch(mode & IO_OPEN_RDWR)
  {
    case IO_OPEN_READ: flags |= O_RDONLY; break;
    case IO_OPEN_WRITE: flags |= O_WRONLY; break;
    case IO_OPEN_RDWR: flags |= O_RDWR; break;
  }

  if(mode & IO_OPEN_CREATE) flags |= O_CREAT;
  if(mode & IO_OPEN_APPEND) flags |= O_APPEND;
  if(mode & IO_OPEN_TRUNCATE) flags |= O_TRUNC;

  if(!(flags & O_CREAT) && (stat(path, &st) == -1))
    return -1;

  va_start(args, mode);

  fd = syscall_open(path, flags, va_arg(args, long));

  va_end(args);

  if(fd == -1)
    return -1;

  if(fd >= IO_MAX_FDS)
  {
    syscall_close(fd);
    return -1;
  }

  io_list[fd].stat = st;

  ret = io_new(fd, FD_FILE);

  if(ret >= 0)
  {
    io_note(fd, "%s", path);
  }

  return ret;
}
Beispiel #6
0
Datei: nastd.c Projekt: bjc/nastd
static int
do_client_connect(int sock)
{
	struct sockaddr_un saremote;
	socklen_t addrlen;
	int s;

	addrlen = sizeof(saremote);
	s = accept(sock, (struct sockaddr *)&saremote, &addrlen);
	if (s == -1) {
		log_err("Couldn't accept new connection: %s.",
			strerror(errno));
		return -1;
	}
	io_new(s);

	return 0;
}
Beispiel #7
0
struct bt_uhid *bt_uhid_new(int fd)
{
	struct bt_uhid *uhid;

	uhid = new0(struct bt_uhid, 1);
	uhid->io = io_new(fd);
	if (!uhid->io)
		goto failed;

	uhid->notify_list = queue_new();

	if (!io_set_read_handler(uhid->io, uhid_read_handler, uhid, NULL))
		goto failed;

	return bt_uhid_ref(uhid);

failed:
	uhid_free(uhid);
	return NULL;
}
Beispiel #8
0
void sploit_init(void)
{
  log(sploit_log, L_startup, "%s v%s sploit",
      PACKAGE_NAME, PACKAGE_VERSION, PACKAGE_RELEASE);
  
  log_init(STDOUT_FILENO, LOG_ALL, L_status);
  io_init_except(STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO);
  
  sploit_stdin = io_new(STDIN_FILENO, FD_PIPE);
  
  mem_init();
  timer_init();
  connect_init();                 
  queue_init();
  dlink_init();
  str_init();
  net_init();
  ssl_init();
  
  sploit_log = log_source_register("sploit");
}
Beispiel #9
0
/**
  Testuje zapisywanie drzewa.
  @param state Środowisko testowe.
  */
static void trie_save_test(void** state)
{
    Trie *trie = trie_new();

    FILE *stream;
    wchar_t *buf = NULL;
    size_t len;

    stream = open_wmemstream(&buf, &len);
    if (stream == NULL)
    {
        fprintf(stderr, "Failed to open memory stream\n");
        exit(EXIT_FAILURE);
    }

    IO *io = io_new(stdin, stream, stderr);

    assert_true(trie_save(trie, io) == 0);
    fflush(stream);
    assert_true(wcscmp(L"\n", buf) == 0);
    fseek(stream, 0, SEEK_SET);

    trie_insert_word(trie, L"ciupaga");
    assert_true(trie_save(trie, io) == 0);
    fflush(stream);
    assert_true(wcscmp(L"ciupaga*^^^^^^^\n", buf) == 0);
    fseek(stream, 0, SEEK_SET);

    trie_delete_word(trie, L"ciupaga");
    assert_true(trie_save(trie, io) == 0);
    fflush(stream);
    assert_true(wcscmp(L"\n", buf) == 0);

    fclose(stream);
    io_done(io);
#   undef free
    free(buf);
#   define free(ptr) _test_free(ptr, __FILE__, __LINE__)
    trie_done(trie);
}
Beispiel #10
0
int err_setlogfile(char *file) {
    char *mode;
    int result=TRUE;

/*
    if(strcmp(file,err_filename) == 0)
        return TRUE;
*/

    if(err_file) {
        io_close(err_file);
    } else {
        err_file = io_new();
        if(!err_file) {
            err_logdest &= ~LOGDEST_LOGFILE;
            if(!err_syslog_open)
                os_opensyslog();
            os_syslog(1,"Error initializing logfile");
        }
    }

    mode = "a";
    if(err_truncate) mode = "w";

    strncpy(err_filename,file,sizeof(err_filename)-1);

    if(!io_open(err_file,"file://%U?mode=%s&ascii=1",err_filename,mode)) {
        fprintf(stderr,"Error opening logfile: %s",io_errstr(err_file));
        err_logdest &= ~LOGDEST_LOGFILE;

        if(!err_syslog_open)
            os_opensyslog();
        os_syslog(1,"Error opening logfile");

        result=FALSE;
    }

    return result;
}
Beispiel #11
0
/* -------------------------------------------------------------------------- *
 * Program entry.                                                             *
 * -------------------------------------------------------------------------- */
int main(int argc, char *argv[])
{
  int i, j;
  int recvfd = 0, sendfd = 1;
  net_addr_t localhost = net_addr_loopback;

  /* get control connection */
  if(argc >= 2)
    recvfd = str_tol(argv[1], NULL, 10);

  if(argc >= 3)
    sendfd = str_tol(argv[2], NULL, 10);

  io_init_except(recvfd, sendfd, -1);

  if(recvfd == sendfd)
  {
    /* socketpair() */
    io_new(recvfd, FD_SOCKET);
  }
  else
  {
    /* 2x pipe() */
    io_new(recvfd, FD_PIPE);
    io_new(sendfd, FD_PIPE);
  }

  /* initialize library */
  servauth_init();

  /* Make sure we are running under hybrid.. */
/*  if(str_ncmp(argv[0], "-sauth", 6))
    sauth_usage();*/

  /* clear argv */
  for(i = 1; i < argc; i++)
    for(j = 0; argv[i][j]; j++)
      argv[i][j] = '\0';

  /* set file descriptor to nonblocking mode */
/*  io_nonblocking(recvfd);
  io_nonblocking(sendfd);*/

  /* initialize dns client */
  dns_init();
  dns_updatedb();

  /* initialize caches */
  cache_auth_new(&servauth_authcache, CACHE_AUTH_SIZE);
  cache_dns_new(&servauth_dnscache, CACHE_DNS_SIZE);
  cache_proxy_new(&servauth_proxycache, CACHE_PROXY_SIZE);

  cache_dns_put(&servauth_dnscache, CACHE_DNS_REVERSE, localhost, "localhost", (uint64_t)-1LL);

  /* initialize control connection */
  control_init(&servauth_control, recvfd, sendfd);

  /* clear query structs */
  memset(servauth_queries, 0, sizeof(servauth_queries));

  /* enter io loop */
  servauth_loop();

  /* NOTREACHED */
  return(0);
}
Beispiel #12
0
struct bt_att *bt_att_new(int fd, bool ext_signed)
{
	struct bt_att *att;

	if (fd < 0)
		return NULL;

	att = new0(struct bt_att, 1);
	if (!att)
		return NULL;

	att->fd = fd;
	att->mtu = BT_ATT_DEFAULT_LE_MTU;
	att->buf = malloc(att->mtu);
	if (!att->buf)
		goto fail;

	att->io = io_new(fd);
	if (!att->io)
		goto fail;

	/* crypto is optional, if not available leave it NULL */
	if (!ext_signed)
		att->crypto = bt_crypto_new();

	att->req_queue = queue_new();
	if (!att->req_queue)
		goto fail;

	att->ind_queue = queue_new();
	if (!att->ind_queue)
		goto fail;

	att->write_queue = queue_new();
	if (!att->write_queue)
		goto fail;

	att->notify_list = queue_new();
	if (!att->notify_list)
		goto fail;

	att->disconn_list = queue_new();
	if (!att->disconn_list)
		goto fail;

	if (!io_set_read_handler(att->io, can_read_data, att, NULL))
		goto fail;

	if (!io_set_disconnect_handler(att->io, disconnect_cb, att, NULL))
		goto fail;

	att->io_on_l2cap = is_io_l2cap_based(att->fd);
	if (!att->io_on_l2cap)
		att->io_sec_level = BT_SECURITY_LOW;

	return bt_att_ref(att);

fail:
	bt_att_free(att);

	return NULL;
}
struct mgmt *mgmt_new(int fd)
{
	struct mgmt *mgmt;

	if (fd < 0)
		return NULL;

	mgmt = new0(struct mgmt, 1);
	if (!mgmt)
		return NULL;

	mgmt->fd = fd;
	mgmt->close_on_unref = false;

	mgmt->len = 512;
	mgmt->buf = malloc(mgmt->len);
	if (!mgmt->buf) {
		free(mgmt);
		return NULL;
	}

	mgmt->io = io_new(fd);
	if (!mgmt->io) {
		free(mgmt->buf);
		free(mgmt);
		return NULL;
	}

	mgmt->request_queue = queue_new();
	if (!mgmt->request_queue) {
		io_destroy(mgmt->io);
		free(mgmt->buf);
		free(mgmt);
		return NULL;
	}

	mgmt->reply_queue = queue_new();
	if (!mgmt->reply_queue) {
		queue_destroy(mgmt->request_queue, NULL);
		io_destroy(mgmt->io);
		free(mgmt->buf);
		free(mgmt);
		return NULL;
	}

	mgmt->pending_list = queue_new();
	if (!mgmt->pending_list) {
		queue_destroy(mgmt->reply_queue, NULL);
		queue_destroy(mgmt->request_queue, NULL);
		io_destroy(mgmt->io);
		free(mgmt->buf);
		free(mgmt);
		return NULL;
	}

	mgmt->notify_list = queue_new();
	if (!mgmt->notify_list) {
		queue_destroy(mgmt->pending_list, NULL);
		queue_destroy(mgmt->reply_queue, NULL);
		queue_destroy(mgmt->request_queue, NULL);
		io_destroy(mgmt->io);
		free(mgmt->buf);
		free(mgmt);
		return NULL;
	}

	if (!io_set_read_handler(mgmt->io, can_read_data, mgmt,
						read_watch_destroy)) {
		queue_destroy(mgmt->notify_list, NULL);
		queue_destroy(mgmt->pending_list, NULL);
		queue_destroy(mgmt->reply_queue, NULL);
		queue_destroy(mgmt->request_queue, NULL);
		io_destroy(mgmt->io);
		free(mgmt->buf);
		free(mgmt);
		return NULL;
	}

	mgmt->writer_active = false;

	return mgmt_ref(mgmt);
}
/**
 * Get info from a "url" file -- a media stream file.
 * This should really get more metainfo, but I'll leave that
 * to later.
 *
 * @param filename .url file to process
 * @param pmp3 MP3FILE structure that must be filled
 * @returns TRUE if file should be added to db, FALSE otherwise
 */
int scan_get_urlinfo(char *filename, MP3FILE *pmp3) {
    IOHANDLE hfile;
    char *head, *tail;
    char linebuffer[256];
    uint32_t len;

    DPRINTF(E_DBG,L_SCAN,"Getting URL file info\n");

    if(!(hfile = io_new())) {
        DPRINTF(E_LOG,L_SCAN,"Can't create file handle\n");
        return FALSE;
    }
    
    if(!io_open(hfile,"file://%U?ascii=1",filename)) {
        DPRINTF(E_WARN,L_SCAN,"Could not open %s for reading: %s\n",filename,
            io_errstr(hfile));
        io_dispose(hfile);
        return FALSE;
    }

    io_buffer(hfile);
    len = sizeof(linebuffer);
    if(!io_readline(hfile,(unsigned char *)linebuffer,&len)) {
        DPRINTF(E_WARN,L_SCAN,"Error reading from file %s: %s",filename,io_errstr(hfile));
        io_close(hfile);
        io_dispose(hfile);
        return FALSE;
    }

    while((linebuffer[strlen(linebuffer)-1] == '\n') ||
          (linebuffer[strlen(linebuffer)-1] == '\r')) {
        linebuffer[strlen(linebuffer)-1] = '\0';
    }

    head=linebuffer;
    tail=strchr(head,',');
    if(!tail) {
        DPRINTF(E_LOG,L_SCAN,"Badly formatted .url file - must be bitrate,descr,url\n");
        io_close(hfile);
        io_dispose(hfile);
        return FALSE;
    }

    pmp3->bitrate=atoi(head);
    head=++tail;
    tail=strchr(head,',');
    if(!tail) {
        DPRINTF(E_LOG,L_SCAN,"Badly formatted .url file - must be bitrate,descr,url\n");
        io_close(hfile);
        io_dispose(hfile);
        return FALSE;
    }

    *tail++='\0';

    pmp3->title=strdup(head);
    pmp3->url=strdup(tail);
    
    io_close(hfile);
    io_dispose(hfile);

    DPRINTF(E_DBG,L_SCAN,"  Title:    %s\n",pmp3->title);
    DPRINTF(E_DBG,L_SCAN,"  Bitrate:  %d\n",pmp3->bitrate);
    DPRINTF(E_DBG,L_SCAN,"  URL:      %s\n",pmp3->url);

    return TRUE;
}
Beispiel #15
0
struct hfp_hf *hfp_hf_new(int fd)
{
	struct hfp_hf *hfp;

	if (fd < 0)
		return NULL;

	hfp = new0(struct hfp_hf, 1);
	if (!hfp)
		return NULL;

	hfp->fd = fd;
	hfp->close_on_unref = false;

	hfp->read_buf = ringbuf_new(4096);
	if (!hfp->read_buf) {
		free(hfp);
		return NULL;
	}

	hfp->write_buf = ringbuf_new(4096);
	if (!hfp->write_buf) {
		ringbuf_free(hfp->read_buf);
		free(hfp);
		return NULL;
	}

	hfp->io = io_new(fd);
	if (!hfp->io) {
		ringbuf_free(hfp->write_buf);
		ringbuf_free(hfp->read_buf);
		free(hfp);
		return NULL;
	}

	hfp->event_handlers = queue_new();
	if (!hfp->event_handlers) {
		io_destroy(hfp->io);
		ringbuf_free(hfp->write_buf);
		ringbuf_free(hfp->read_buf);
		free(hfp);
		return NULL;
	}

	hfp->cmd_queue = queue_new();
	if (!hfp->cmd_queue) {
		io_destroy(hfp->io);
		ringbuf_free(hfp->write_buf);
		ringbuf_free(hfp->read_buf);
		queue_destroy(hfp->event_handlers, NULL);
		free(hfp);
		return NULL;
	}

	hfp->writer_active = false;

	if (!io_set_read_handler(hfp->io, hf_can_read_data, hfp,
							read_watch_destroy)) {
		queue_destroy(hfp->event_handlers,
						destroy_event_handler);
		io_destroy(hfp->io);
		ringbuf_free(hfp->write_buf);
		ringbuf_free(hfp->read_buf);
		free(hfp);
		return NULL;
	}

	return hfp_hf_ref(hfp);
}
/**
 * main aac scanning routing.
 *
 * @param filename file to scan
 * @param pmp3 pointer to the MP3FILE to fill with data
 * @returns FALSE if file should not be added to database, TRUE otherwise
 */
int scan_get_aacinfo(char *filename, MP3FILE *pmp3) {
    IOHANDLE hfile;
    uint64_t atom_offset, pos;
    uint32_t bytes_read;
    unsigned int atom_length;

    long current_offset=0;
    uint32_t current_size;
    char current_atom[4];
    char *current_data;
    unsigned short us_data;
    int genre;
    int len;

    uint32_t sample_size;
    uint32_t samples;
    uint32_t bit_rate;
    int ms;
    unsigned char buffer[2];
    uint32_t time = 0;


    hfile = io_new();
    if(!hfile)
        DPRINTF(E_FATAL,L_SCAN,"Malloc error in scan_get_aacinfo\n");

    if(!io_open(hfile,"file://%U",filename)) {
        DPRINTF(E_INF,L_SCAN,"Cannot open file %s for reading: %s\n",filename,
            io_errstr(hfile));
        io_dispose(hfile);
        return FALSE;
    }

    atom_offset=scan_aac_drilltoatom(hfile, "moov:udta:meta:ilst", &atom_length);
    if(atom_offset != -1) {
        /* found the tag section - need to walk through now */
        while(current_offset < (uint64_t)atom_length) {
            bytes_read =  sizeof(uint32_t);
            if(!io_read(hfile,(unsigned char *)&current_size,&bytes_read) || !bytes_read) {
                DPRINTF(E_LOG,L_SCAN,"Error reading mp4 atoms: %s\n",io_errstr(hfile));
                io_dispose(hfile);
                return FALSE;
            }

            current_size=ntohl(current_size);

            DPRINTF(E_SPAM,L_SCAN,"Current size: %d\n",current_size);

            if(current_size <= 7) { /* something not right */
                DPRINTF(E_LOG,L_SCAN,"mp4 atom too small. Bad aac tags?\n");
                io_dispose(hfile);
                return FALSE;
            }


            bytes_read = 4;
            if(!io_read(hfile,(unsigned char *)current_atom,&bytes_read) || !bytes_read) {
                DPRINTF(E_LOG,L_SCAN,"Error reading mp4 atoms: %s\n",io_errstr(hfile));
                io_dispose(hfile);
                return FALSE;
            }

            DPRINTF(E_SPAM,L_SCAN,"Current Atom: %c%c%c%c\n",
                    current_atom[0],current_atom[1],current_atom[2],
                    current_atom[3]);

            if(current_size > 4096) { /* Does this break anything? */
                /* too big!  cover art, maybe? */
                io_setpos(hfile,current_size - 8, SEEK_CUR);
                DPRINTF(E_SPAM,L_SCAN,"Atom too big... skipping\n");
            } else {
                len=current_size-7;  /* for ill-formed too-short tags */
                if(len < 22) {
                    len=22;
                }

                current_data=(char*)malloc(len);  /* extra byte */
                memset(current_data,0x00,len);

                bytes_read = current_size - 8;
                if(!io_read(hfile,(unsigned char *)current_data,&bytes_read) || (!bytes_read)) {
                    DPRINTF(E_LOG,L_SCAN,"Error reading mp4 data: %s\n",io_errstr(hfile));
                    free(current_data);
                    io_dispose(hfile);
                    return FALSE;
                }

                if(!memcmp(current_atom,"\xA9" "nam",4)) { /* Song name */
                    pmp3->title=strdup((char*)&current_data[16]);
                } else if(!memcmp(current_atom,"aART",4)) {
                    pmp3->album_artist=strdup((char*)&current_data[16]);
                } else if(!memcmp(current_atom,"\xA9" "ART",4)) {
                    pmp3->artist=strdup((char*)&current_data[16]);
                } else if(!memcmp(current_atom,"\xA9" "alb",4)) {
                    pmp3->album=strdup((char*)&current_data[16]);
                } else if(!memcmp(current_atom,"\xA9" "cmt",4)) {
                    pmp3->comment=strdup((char*)&current_data[16]);
                } else if(!memcmp(current_atom,"\xA9" "wrt",4)) {
                    pmp3->composer=strdup((char*)&current_data[16]);
                } else if(!memcmp(current_atom,"\xA9" "grp",4)) {
                    pmp3->grouping=strdup((char*)&current_data[16]);
                } else if(!memcmp(current_atom,"\xA9" "gen",4)) {
                    /* can this be a winamp genre??? */
                    pmp3->genre=strdup((char*)&current_data[16]);
                } else if(!memcmp(current_atom,"tmpo",4)) {
                    us_data=*((unsigned short *)&current_data[16]);
                    us_data=ntohs(us_data);
                    pmp3->bpm=us_data;
                } else if(!memcmp(current_atom,"trkn",4)) {
                    us_data=*((unsigned short *)&current_data[18]);
                    us_data=ntohs(us_data);

                    pmp3->track=us_data;

                    us_data=*((unsigned short *)&current_data[20]);
                    us_data=ntohs(us_data);

                    pmp3->total_tracks=us_data;
                } else if(!memcmp(current_atom,"disk",4)) {
                    us_data=*((unsigned short *)&current_data[18]);
                    us_data=ntohs(us_data);

                    pmp3->disc=us_data;

                    us_data=*((unsigned short *)&current_data[20]);
                    us_data=ntohs(us_data);

                    pmp3->total_discs=us_data;
                } else if(!memcmp(current_atom,"\xA9" "day",4)) {
                    pmp3->year=atoi((char*)&current_data[16]);
                } else if(!memcmp(current_atom,"gnre",4)) {
                    genre=(int)(*((char*)&current_data[17]));
                    genre--;

                    if((genre < 0) || (genre > WINAMP_GENRE_UNKNOWN))
                        genre=WINAMP_GENRE_UNKNOWN;

                    pmp3->genre=strdup(scan_winamp_genre[genre]);
                } else if (!memcmp(current_atom, "cpil", 4)) {
                    pmp3->compilation = current_data[16];
                }

                free(current_data);
            }
            current_offset+=current_size;
        }
    }

    /* got the tag info, now let's get bitrate, etc */
    atom_offset = scan_aac_drilltoatom(hfile, "moov:mvhd", &atom_length);
    if(atom_offset != -1) {
        io_setpos(hfile,4,SEEK_CUR);

        /* FIXME: error handling */
        bytes_read = sizeof(uint32_t);
        if(!io_read(hfile,(unsigned char *)&time, &bytes_read)) {
            DPRINTF(E_LOG,L_SCAN,"Error reading time from moov:mvhd: %s\n",
                    io_errstr(hfile));
            io_dispose(hfile);
            return FALSE;
        }

        time = ntohl(time);
        pmp3->time_added = (int)scan_aac_mac_to_unix_time(time);

        bytes_read = sizeof(uint32_t);
        if(!io_read(hfile,(unsigned char *)&time, &bytes_read)) {
            DPRINTF(E_LOG,L_SCAN,"Error reading time from moov:mvhd: %s\n",
                    io_errstr(hfile));
            io_dispose(hfile);
            return FALSE;
        }

        time = ntohl(time);
        pmp3->time_modified = (int)scan_aac_mac_to_unix_time(time);

        bytes_read = sizeof(uint32_t);
        if(!io_read(hfile,(unsigned char *)&sample_size,&bytes_read)) {
            DPRINTF(E_LOG,L_SCAN,"Error reading sample_size from moov:mvhd: %s\n",
                    io_errstr(hfile));
            io_dispose(hfile);
            return FALSE;
        }

        bytes_read = sizeof(uint32_t);
        if(!io_read(hfile,(unsigned char*)&samples, &bytes_read)) {
            DPRINTF(E_LOG,L_SCAN,"Error reading samples from moov:mvhd: %s\n",
                    io_errstr(hfile));
            io_dispose(hfile);
            return FALSE;
        }

        sample_size=ntohl(sample_size);
        samples=ntohl(samples);

        /* avoid overflowing on large sample_sizes (90000) */
        ms=1000;
        while((ms > 9) && (!(sample_size % 10))) {
            sample_size /= 10;
            ms /= 10;
        }

        /* DWB: use ms time instead of sec */
        pmp3->song_length=(uint32_t)((samples * ms) / sample_size);
        DPRINTF(E_DBG,L_SCAN,"Song length: %d seconds\n",
                pmp3->song_length / 1000);
    }

    pmp3->bitrate = 0;

    /* see if it is aac or alac */
    atom_offset = scan_aac_drilltoatom(hfile,
                                       "moov:trak:mdia:minf:stbl:stsd:alac",
                                       &atom_length);

    if(atom_offset != -1) {
        /* should we still pull samplerate, etc from the this atom? */
        if(pmp3->codectype) {
            free(pmp3->codectype);
        }
        pmp3->codectype=strdup("alac");
    }

    /* Get the sample rate from the 'mp4a' atom (timescale). This is also
       found in the 'mdhd' atom which is a bit closer but we need to
       navigate to the 'mp4a' atom anyways to get to the 'esds' atom. */
    atom_offset=scan_aac_drilltoatom(hfile,
                                     "moov:trak:mdia:minf:stbl:stsd:mp4a",
                                     &atom_length);
    if(atom_offset == -1) {
        atom_offset=scan_aac_drilltoatom(hfile,
                                         "moov:trak:mdia:minf:stbl:stsd:drms",
                                         &atom_length);
    }

    if (atom_offset != -1) {
        io_setpos(hfile, atom_offset + 32, SEEK_SET);

        /* Timescale here seems to be 2 bytes here (the 2 bytes before it are
         * "reserved") though the timescale in the 'mdhd' atom is 4. Not sure
         * how this is dealt with when sample rate goes higher than 64K. */
        bytes_read = 2;
        if(!io_read(hfile, (unsigned char *)buffer, &bytes_read)) {
            DPRINTF(E_LOG,L_SCAN,"Error reading timescale from drms atom: %s\n",
                    io_errstr(hfile));
            io_dispose(hfile);
            return FALSE;
        }

        pmp3->samplerate = (buffer[0] << 8) | (buffer[1]);

        /* Seek to end of atom. */
        io_setpos(hfile, 2, SEEK_CUR);

        /* Get the bit rate from the 'esds' atom. We are already positioned
           in the parent atom so just scan ahead. */
        io_getpos(hfile,&pos);
        atom_offset = scan_aac_findatom(hfile,
                                        atom_length-(pos-atom_offset),
                                        "esds", &atom_length);

        if (atom_offset != -1) {
            /* Roku Soundbridge seems to believe anything above 320K is
             * an ALAC encoded m4a.  We'll lie on their behalf.
             */
            io_setpos(hfile, atom_offset + 22, SEEK_CUR);

            bytes_read = sizeof(unsigned int);
            if(!io_read(hfile, (unsigned char *)&bit_rate, &bytes_read)) {
                DPRINTF(E_LOG,L_SCAN,"Error reading bitrate from esds: %s\n",
                        io_errstr(hfile));
                io_dispose(hfile);
                return FALSE;
            }

            pmp3->bitrate = ntohl(bit_rate) / 1000;
            DPRINTF(E_DBG,L_SCAN,"esds bitrate: %d\n",pmp3->bitrate);

            if(pmp3->bitrate > 320) {
                pmp3->bitrate = 320;
            }
        } else {
            DPRINTF(E_DBG,L_SCAN, "Couldn't find 'esds' atom for bit rate.\n");
        }
    } else {
        DPRINTF(E_DBG,L_SCAN, "Couldn't find 'mp4a' atom for sample rate.\n");
    }

    /* Fallback if we can't find the info in the atoms. */
    if (pmp3->bitrate == 0) {
        /* calculate bitrate from song length... Kinda cheesy */
        DPRINTF(E_DBG,L_SCAN, "Guesstimating bit rate.\n");
        atom_offset=scan_aac_drilltoatom(hfile,"mdat",&atom_length);
        if ((atom_offset != -1) && (pmp3->song_length >= 1000)) {
            pmp3->bitrate = atom_length / ((pmp3->song_length / 1000) * 128);
        }
    }

    io_close(hfile);
    io_dispose(hfile);
    return TRUE;  /* we'll return as much as we got. */
}