]> git.tuebingen.mpg.de Git - paraslash.git/blobdiff - aft.c
aacdec: Combine aac_open() and aacdec_open().
[paraslash.git] / aft.c
diff --git a/aft.c b/aft.c
index df295246db0cf1d1d6e3d0b202d43c86332db0f6..7d3a6e0d98a01e40974f22285e9be2d9fac01b46 100644 (file)
--- a/aft.c
+++ b/aft.c
@@ -335,8 +335,8 @@ enum afhi_offsets {
        CHUNKS_TOTAL_OFFSET = 20,
        /** The length of the audio file header (4 bytes). */
        HEADER_LEN_OFFSET = 24,
-       /** Was: The start of the audio file header (4 bytes). */
-       AFHI_UNUSED2_OFFSET = 28,
+       /** Size of the largest chunk in bytes. (4 bytes). */
+       AFHI_MAX_CHUNK_SIZE_OFFSET = 28,
        /** The seconds part of the chunk time (4 bytes). */
        CHUNK_TV_TV_SEC_OFFSET = 32,
        /** The microseconds part of the chunk time (4 bytes). */
@@ -376,7 +376,7 @@ static void save_afhi(struct afh_info *afhi, char *buf)
        write_u8(buf + AFHI_CHANNELS_OFFSET, afhi->channels);
        write_u32(buf + CHUNKS_TOTAL_OFFSET, afhi->chunks_total);
        write_u32(buf + HEADER_LEN_OFFSET, afhi->header_len);
-       write_u32(buf + AFHI_UNUSED2_OFFSET, 0);
+       write_u32(buf + AFHI_MAX_CHUNK_SIZE_OFFSET, afhi->max_chunk_size);
        write_u32(buf + CHUNK_TV_TV_SEC_OFFSET, afhi->chunk_tv.tv_sec);
        write_u32(buf + CHUNK_TV_TV_USEC_OFFSET, afhi->chunk_tv.tv_usec);
        p = buf + AFHI_INFO_STRING_OFFSET;
@@ -398,6 +398,7 @@ static void load_afhi(const char *buf, struct afh_info *afhi)
        afhi->channels = read_u8(buf + AFHI_CHANNELS_OFFSET);
        afhi->chunks_total = read_u32(buf + CHUNKS_TOTAL_OFFSET);
        afhi->header_len = read_u32(buf + HEADER_LEN_OFFSET);
+       afhi->max_chunk_size = read_u32(buf + AFHI_MAX_CHUNK_SIZE_OFFSET);
        afhi->chunk_tv.tv_sec = read_u32(buf + CHUNK_TV_TV_SEC_OFFSET);
        afhi->chunk_tv.tv_usec = read_u32(buf + CHUNK_TV_TV_USEC_OFFSET);
        afhi->techinfo = (char *)buf + AFHI_INFO_STRING_OFFSET;
@@ -408,42 +409,37 @@ static void load_afhi(const char *buf, struct afh_info *afhi)
        afhi->tags.comment = afhi->tags.album + strlen(afhi->tags.album) + 1;
 }
 
+/* Only used for saving the chunk table, but not for loading. */
 static unsigned sizeof_chunk_table(struct afh_info *afhi)
 {
-       if (!afhi)
+       if (!afhi || !afhi->chunk_table)
                return 0;
        return 4 * (afhi->chunks_total + 1);
 }
 
-static uint32_t save_chunk_table(struct afh_info *afhi, char *buf)
+static void save_chunk_table(struct afh_info *afhi, char *buf)
 {
-       int i;
-       uint32_t max = 0, old = 0;
+       uint32_t n;
 
-       for (i = 0; i <= afhi->chunks_total; i++) {
-               uint32_t val = afhi->chunk_table[i];
-               write_u32(buf + 4 * i, val);
-               /*
-                * If the first chunk is the header, do not consider it for the
-                * calculation of the largest chunk size.
-                */
-               if (i == 0 || (i == 1 && afhi->header_len > 0)) {
-                       old = val;
-                       continue;
-               }
-               max = PARA_MAX(max, val - old);
-               old = val;
-       }
-       return max;
+       if (!afhi->chunk_table)
+               return;
+       for (n = 0; n <= afhi->chunks_total; n++)
+               write_u32(buf + 4 * n, afhi->chunk_table[n]);
 }
 
-static void load_chunk_table(struct afh_info *afhi, char *buf)
+static void load_chunk_table(struct afh_info *afhi, const struct osl_object *ct)
 {
        int i;
+       size_t sz;
 
-       afhi->chunk_table = para_malloc(sizeof_chunk_table(afhi));
-       for (i = 0; i <= afhi->chunks_total; i++)
-               afhi->chunk_table[i] = read_u32(buf + 4 * i);
+       if (!ct->data || ct->size < 4) {
+               afhi->chunk_table = NULL;
+               return;
+       }
+       sz  = PARA_MIN(((size_t)afhi->chunks_total + 1) * 4, ct->size) + 1;
+       afhi->chunk_table = para_malloc(sz);
+       for (i = 0; i <= afhi->chunks_total && i * 4 + 3 < ct->size; i++)
+               afhi->chunk_table[i] = read_u32(ct->data + 4 * i);
 }
 
 /**
@@ -638,7 +634,13 @@ static int save_afd(struct audio_file_data *afd)
                goto err;
        buf = shm_afd;
        buf += sizeof(*afd);
-       afd->max_chunk_size = save_chunk_table(&afd->afhi, buf);
+       save_chunk_table(&afd->afhi, buf);
+       if (afd->afhi.max_chunk_size == 0) { /* v0.5.x on-disk afhi */
+               set_max_chunk_size(&afd->afhi);
+               PARA_NOTICE_LOG("max chunk size unset, re-add required\n");
+       } else
+               PARA_INFO_LOG("using max chunk size from afhi\n");
+       afd->max_chunk_size = afd->afhi.max_chunk_size;
        *(struct audio_file_data *)shm_afd = *afd;
        shm_detach(shm_afd);
        return shmid;
@@ -663,14 +665,22 @@ int load_afd(int shmid, struct audio_file_data *afd)
 {
        void *shm_afd;
        int ret;
+       struct osl_object obj;
 
        ret = shm_attach(shmid, ATTACH_RO, &shm_afd);
        if (ret < 0)
                return ret;
+       ret = shm_size(shmid, &obj.size);
+       if (ret < 0)
+               goto detach;
        *afd = *(struct audio_file_data *)shm_afd;
-       load_chunk_table(&afd->afhi, shm_afd + sizeof(*afd));
+       obj.data = shm_afd + sizeof(*afd);
+       obj.size -= sizeof(*afd);
+       load_chunk_table(&afd->afhi, &obj);
+       ret = 1;
+detach:
        shm_detach(shm_afd);
-       return 1;
+       return ret;
 }
 
 static int get_local_time(uint64_t *seconds, char *buf, size_t size,
@@ -738,11 +748,11 @@ static void get_duration_buf(int seconds, char *buf, struct ls_options *opts)
        if (!hours) { /* m:ss or mm:ss */
                max_width = opts->mode == LS_MODE_LONG?
                        opts->widths.duration_width : 4;
-               sprintf(buf, "%*u:%02u", max_width - 3, mins, seconds % 60);
+               sprintf(buf, "%*u:%02d", max_width - 3, mins, seconds % 60);
        } else { /* more than one hour => h:mm:ss, hh:mm:ss, hhh:mm:ss, ... */
                max_width = opts->mode == LS_MODE_LONG?
                        opts->widths.duration_width : 7;
-               sprintf(buf, "%*u:%02u:%02u", max_width - 6, hours, mins,
+               sprintf(buf, "%*u:%02u:%02d", max_width - 6, hours, mins,
                        seconds % 60);
        }
 }
@@ -820,7 +830,11 @@ static int print_chunk_table(struct ls_data *d, struct para_buffer *b)
                (long unsigned) d->afhi.chunk_tv.tv_usec
        );
        buf = chunk_table_obj.data;
-       for (i = 0; i <= d->afhi.chunks_total; i++)
+       for (
+               i = 0;
+               i <= d->afhi.chunks_total && 4 * i + 3 < chunk_table_obj.size;
+               i++
+       )
                para_printf(b, "%u ", (unsigned) read_u32(buf + 4 * i));
        para_printf(b, "\n");
        ret = 1;
@@ -876,14 +890,14 @@ static int print_list_item(struct ls_data *d, struct ls_options *opts,
                para_printf(b,
                        "%s "   /* attributes */
                        "%*u "  /* amp */
-                       "%*d "  /* image_id  */
-                       "%*d "  /* lyrics_id */
-                       "%*d "  /* bitrate */
+                       "%*u "  /* image_id  */
+                       "%*u "  /* lyrics_id */
+                       "%*u "  /* bitrate */
                        "%*s "  /* audio format */
-                       "%*d "  /* frequency */
-                       "%d "   /* channels */
+                       "%*u "  /* frequency */
+                       "%u "   /* channels */
                        "%s "   /* duration */
-                       "%*d "  /* num_played */
+                       "%*u "  /* num_played */
                        "%s "   /* last_played */
                        "%s\n", /* path */
                        att_buf,
@@ -930,11 +944,13 @@ static int print_list_item(struct ls_data *d, struct ls_options *opts,
        WRITE_STATUS_ITEM(b, SI_SECONDS_TOTAL, "%" PRIu32 "\n",
                afhi->seconds_total);
        WRITE_STATUS_ITEM(b, SI_LAST_PLAYED, "%s\n", last_played_time);
-       WRITE_STATUS_ITEM(b, SI_NUM_PLAYED, "%d\n", afsi->num_played);
+       WRITE_STATUS_ITEM(b, SI_NUM_PLAYED, "%u\n", afsi->num_played);
        WRITE_STATUS_ITEM(b, SI_AMPLIFICATION, "%u\n", afsi->amp);
        WRITE_STATUS_ITEM(b, SI_CHUNK_TIME, "%lu\n", tv2ms(&afhi->chunk_tv));
        WRITE_STATUS_ITEM(b, SI_NUM_CHUNKS, "%" PRIu32 "\n",
                afhi->chunks_total);
+       WRITE_STATUS_ITEM(b, SI_MAX_CHUNK_SIZE, "%" PRIu32 "\n",
+               afhi->max_chunk_size);
        WRITE_STATUS_ITEM(b, SI_TECHINFO, "%s\n", afhi->techinfo);
        WRITE_STATUS_ITEM(b, SI_ARTIST, "%s\n", afhi->tags.artist);
        WRITE_STATUS_ITEM(b, SI_TITLE, "%s\n", afhi->tags.title);
@@ -1054,8 +1070,15 @@ again:
        d->afhi.chunk_table = afd->afhi.chunk_table = NULL;
        ret = osl(osl_open_disk_object(audio_file_table, current_aft_row,
                AFTCOL_CHUNKS, &chunk_table_obj));
-       if (ret < 0)
-               return ret;
+       if (ret < 0) {
+               if (!afh_supports_dynamic_chunks(d->afsi.audio_format_id))
+                       return ret;
+               PARA_INFO_LOG("no chunk table for %s\n", d->path);
+               chunk_table_obj.data = NULL;
+               chunk_table_obj.size = 0;
+       } else {
+               PARA_INFO_LOG("chunk table: %zu bytes\n", chunk_table_obj.size);
+       }
        ret = mmap_full_file(d->path, O_RDONLY, &map.data, &map.size, &afd->fd);
        if (ret < 0)
                goto out;
@@ -1072,7 +1095,7 @@ again:
        save_afsi(&new_afsi, &afsi_obj); /* in-place update */
 
        afd->audio_format_id = d->afsi.audio_format_id;
-       load_chunk_table(&afd->afhi, chunk_table_obj.data);
+       load_chunk_table(&afd->afhi, &chunk_table_obj);
        aced.aft_row = current_aft_row;
        aced.old_afsi = &d->afsi;
        /*
@@ -1085,7 +1108,8 @@ again:
        ret = save_afd(afd);
 out:
        free(afd->afhi.chunk_table);
-       osl_close_disk_object(&chunk_table_obj);
+       if (chunk_table_obj.data)
+               osl_close_disk_object(&chunk_table_obj);
        if (ret < 0) {
                PARA_ERROR_LOG("%s: %s\n", d->path, para_strerror(-ret));
                ret = score_delete(current_aft_row);
@@ -1736,6 +1760,7 @@ static int com_add_callback(struct afs_callback_arg *aca)
                        &objs[AFTCOL_AFHI]));
                if (ret < 0)
                        goto out;
+               /* truncate the file to size zero if there is no chunk table */
                ret = osl(osl_update_object(audio_file_table, row, AFTCOL_CHUNKS,
                        &objs[AFTCOL_CHUNKS]));
                if (ret < 0)
@@ -2044,6 +2069,22 @@ static int com_touch_callback(struct afs_callback_arg *aca)
                .data = aca,
                .action = touch_audio_file
        };
+       if (cto->image_id >= 0) {
+               ret = img_get_name_by_id(cto->image_id, NULL);
+               if (ret < 0) {
+                       para_printf(&aca->pbout, "invalid image ID: %d\n",
+                               cto->image_id);
+                       return ret;
+               }
+       }
+       if (cto->lyrics_id >= 0) {
+               ret = lyr_get_name_by_id(cto->lyrics_id, NULL);
+               if (ret < 0) {
+                       para_printf(&aca->pbout, "invalid lyrics ID: %d\n",
+                               cto->lyrics_id);
+                       return ret;
+               }
+       }
        if (cto->flags & TOUCH_FLAG_FNM_PATHNAME)
                pmd.fnmatch_flags |= FNM_PATHNAME;
        ret = for_each_matching_row(&pmd);
@@ -2625,7 +2666,7 @@ static int aft_open(const char *dir)
        if (ret >= 0) {
                unsigned num;
                osl_get_num_rows(audio_file_table, &num);
-               PARA_INFO_LOG("audio file table contains %d files\n", num);
+               PARA_INFO_LOG("audio file table contains %u files\n", num);
                return ret;
        }
        PARA_NOTICE_LOG("failed to open audio file table\n");