~jcowgill/ubuntu/trusty/easytag/bug-1295882

« back to all changes in this revision

Viewing changes to src/vcedit.c

  • Committer: Bazaar Package Importer
  • Author(s): Michal Čihař
  • Date: 2008-09-08 21:44:11 UTC
  • mfrom: (3.1.10 hardy)
  • Revision ID: james.westby@ubuntu.com-20080908214411-v237hcgn5d97ecut
Tags: 2.1.4-1.1
* Non-maintainer upload.
* Warn user when ogg vorbis tags will be lost, fix handling of multiple same
  ogg vorbis tags (Closes: #460247).
* Fix lintian warnings:
  - Add watch file.
  - Install icon for menu file (Closes: #477456).
  - Fix section in menu file.
  - Drop version from NAME section of man page to `apropos' and `whatis'
    happy.
  - Include copyright information in debian/copyright.

Show diffs side-by-side

added added

removed removed

Lines of Context:
30
30
{
31
31
    vcedit_state *state = malloc(sizeof(vcedit_state));
32
32
    memset(state, 0, sizeof(vcedit_state));
 
33
    state->oggtype = VCEDIT_IS_UNKNOWN;
33
34
 
34
35
    return state;
35
36
}
69
70
    if(state->bookbuf)
70
71
        free(state->bookbuf);
71
72
    if(state->vi) {
72
 
       vorbis_info_clear(state->vi);
 
73
        vorbis_info_clear(state->vi);
73
74
        free(state->vi);
74
75
    }
75
76
 
98
99
    }
99
100
}
100
101
 
101
 
static int _commentheader_out(vorbis_comment *vc, char *vendor, ogg_packet *op)
 
102
static int _commentheader_out(vcedit_state *state, ogg_packet *op)
102
103
{
 
104
    vorbis_comment *vc = state->vc;
 
105
    char           *vendor = state->vendor;
103
106
    oggpack_buffer opb;
104
107
 
105
108
    oggpack_writeinit(&opb);
106
109
 
107
 
    /* preamble */  
108
 
    oggpack_write(&opb,0x03,8);
109
 
    _v_writestring(&opb,"vorbis", 6);
 
110
    if (state->oggtype == VCEDIT_IS_OGGVORBIS)
 
111
    {
 
112
        /* preamble */
 
113
        oggpack_write(&opb,0x03,8);
 
114
        _v_writestring(&opb,"vorbis", 6);
 
115
    }
110
116
 
111
117
    /* vendor */
112
118
    oggpack_write(&opb,strlen(vendor),32);
119
125
        for(i=0;i<vc->comments;i++){
120
126
            if(vc->user_comments[i]){
121
127
                oggpack_write(&opb,vc->comment_lengths[i],32);
122
 
                _v_writestring(&opb,vc->user_comments[i], 
123
 
                        vc->comment_lengths[i]);
 
128
                _v_writestring(&opb,vc->user_comments[i],
 
129
                               vc->comment_lengths[i]);
124
130
            }else{
125
131
                oggpack_write(&opb,0,32);
126
132
            }
135
141
    op->b_o_s=0;
136
142
    op->e_o_s=0;
137
143
    op->granulepos=0;
 
144
    if (state->oggtype == VCEDIT_IS_OGGVORBIS)
 
145
    {
 
146
        op->packetno = 1;
 
147
    }
138
148
 
139
149
    oggpack_writeclear(&opb);
140
150
    return 0;
174
184
            buffer = ogg_sync_buffer(s->oy, CHUNKSIZE);
175
185
            bytes = s->read(buffer,1, CHUNKSIZE, s->in);
176
186
            ogg_sync_wrote(s->oy, bytes);
177
 
            if(bytes == 0) 
 
187
            if(bytes == 0)
178
188
                return 0;
179
189
        }
180
190
        if(ogg_page_eos(page))
191
201
    }
192
202
}
193
203
 
 
204
/*
 
205
 * Next functions pulled straight from libvorbis,
 
206
 */
 
207
static void _v_readstring(oggpack_buffer *o,char *buf,int bytes){
 
208
  while(bytes--){
 
209
    *buf++=oggpack_read(o,8);
 
210
  }
 
211
}
 
212
 
 
213
/*
 
214
 * Next functions pulled straight from libvorbis, apart from one change
 
215
 * - disabled the EOP check
 
216
 */
 
217
static int _speex_unpack_comment(vorbis_comment *vc,oggpack_buffer *opb)
 
218
{
 
219
    int i;
 
220
    int vendorlen=oggpack_read(opb,32);
 
221
    if (vendorlen<0) 
 
222
        goto err_out;
 
223
 
 
224
    vc->vendor=_ogg_calloc(vendorlen+1,1);
 
225
    _v_readstring(opb,vc->vendor,vendorlen);
 
226
 
 
227
    vc->comments=oggpack_read(opb,32);
 
228
    if (vc->comments<0)
 
229
        goto err_out;
 
230
    vc->user_comments=_ogg_calloc(vc->comments+1,sizeof(*vc->user_comments));
 
231
    vc->comment_lengths=_ogg_calloc(vc->comments+1, sizeof(*vc->comment_lengths));
 
232
    for (i=0;i<vc->comments;i++){
 
233
        int len=oggpack_read(opb,32);
 
234
        if (len<0)
 
235
            goto err_out;
 
236
        vc->comment_lengths[i]=len;
 
237
        vc->user_comments[i]=_ogg_calloc(len+1,1);
 
238
        _v_readstring(opb,vc->user_comments[i],len);
 
239
    }
 
240
    //if(oggpack_read(opb,1)!=1)goto err_out; /* EOP check */
 
241
    return(0);
 
242
 
 
243
err_out:
 
244
    vorbis_comment_clear(vc);
 
245
    return(1);
 
246
}
 
247
 
194
248
int vcedit_open(vcedit_state *state, FILE *in)
195
249
{
196
 
    return vcedit_open_callbacks(state, (void *)in, 
 
250
    return vcedit_open_callbacks(state, (void *)in,
197
251
            (vcedit_read_func)fread, (vcedit_write_func)fwrite);
198
252
}
199
253
 
205
259
    int bytes,i;
206
260
    int chunks = 0;
207
261
    ogg_packet *header;
208
 
    ogg_packet    header_main;
 
262
    ogg_packet  header_main;
209
263
    ogg_packet  header_comments;
210
 
    ogg_packet    header_codebooks;
 
264
    ogg_packet  header_codebooks;
211
265
    ogg_page    og;
212
266
 
213
267
    state->in = in;
260
314
        goto err;
261
315
    }
262
316
 
263
 
    if(vorbis_synthesis_headerin(state->vi, state->vc, &header_main) < 0)
264
 
    {
265
 
        state->lasterror = _("Ogg bitstream does not contain vorbis data.");
266
 
        goto err;
267
 
    }
268
 
 
 
317
    // We save the main header first, (it seems speex_packet_to_header munge's it??)
269
318
    state->mainlen = header_main.bytes;
270
319
    state->mainbuf = malloc(state->mainlen);
271
320
    memcpy(state->mainbuf, header_main.packet, header_main.bytes);
272
321
 
273
 
    i = 0;
274
 
    header = &header_comments;
275
 
    while(i<2) {
276
 
        while(i<2) {
 
322
    state->oggtype = VCEDIT_IS_UNKNOWN;
 
323
    int headerpackets = 0;
 
324
    if(vorbis_synthesis_headerin(state->vi, state->vc, &header_main) == 0)
 
325
    {
 
326
        state->oggtype = VCEDIT_IS_OGGVORBIS;
 
327
    }
 
328
#ifdef ENABLE_SPEEX
 
329
    else
 
330
    {
 
331
        // Done after "Ogg test" to avoid to display an error message in function
 
332
        // speex_packet_to_header when the file is not Speex.
 
333
        state->si = malloc(sizeof(SpeexHeader));
 
334
        if((state->si = speex_packet_to_header((char*)(&header_main)->packet,(&header_main)->bytes)))
 
335
            state->oggtype = VCEDIT_IS_SPEEX;
 
336
    }
 
337
#endif
 
338
 
 
339
    if (state->oggtype == VCEDIT_IS_UNKNOWN)
 
340
    {
 
341
        state->lasterror = _("Ogg bitstream contains neither speex or vorbis data.");
 
342
        goto err;
 
343
    }
 
344
 
 
345
    switch (state->oggtype)
 
346
    {
 
347
        case VCEDIT_IS_OGGVORBIS:
 
348
            header = &header_comments;
 
349
            headerpackets = 3;
 
350
            break;
 
351
#ifdef ENABLE_SPEEX
 
352
        case VCEDIT_IS_SPEEX:
 
353
            header = &header_comments;
 
354
            headerpackets = 2 + state->si->extra_headers;
 
355
            break;
 
356
#endif
 
357
    }
 
358
    oggpack_buffer opb;
 
359
    i = 1;
 
360
    while(i<headerpackets)
 
361
    {
 
362
        while(i<headerpackets)
 
363
        {
277
364
            int result = ogg_sync_pageout(state->oy, &og);
278
365
            if(result == 0) break; /* Too little data so far */
279
366
            else if(result == 1)
280
367
            {
281
368
                ogg_stream_pagein(state->os, &og);
282
 
                while(i<2)
 
369
                while(i< headerpackets)
283
370
                {
284
371
                    result = ogg_stream_packetout(state->os, header);
285
372
                    if(result == 0) break;
288
375
                        state->lasterror = _("Corrupt secondary header.");
289
376
                        goto err;
290
377
                    }
291
 
                    vorbis_synthesis_headerin(state->vi, state->vc, header);
292
 
                    if(i==1)
 
378
                    switch (state->oggtype)
293
379
                    {
294
 
                        state->booklen = header->bytes;
295
 
                        state->bookbuf = malloc(state->booklen);
296
 
                        memcpy(state->bookbuf, header->packet, 
297
 
                                header->bytes);
 
380
                        case VCEDIT_IS_OGGVORBIS:
 
381
                            vorbis_synthesis_headerin(state->vi, state->vc, header);
 
382
                            switch (i) 
 
383
                            {
 
384
                                // 0 packet was the vorbis header
 
385
                                case 1:
 
386
                                    header = &header_codebooks;
 
387
                                    break;
 
388
                                case 2:
 
389
                                    state->booklen = header->bytes;
 
390
                                    state->bookbuf = malloc(state->booklen);
 
391
                                    memcpy(state->bookbuf, header->packet, 
 
392
                                           header->bytes);
 
393
                                    break;
 
394
                            }
 
395
                            break;
 
396
                        case VCEDIT_IS_SPEEX:
 
397
                            switch (i) 
 
398
                            {
 
399
                                // 0 packet was the speex header
 
400
                                case 1:
 
401
                                    oggpack_readinit(&opb,header->packet,header->bytes);
 
402
                                    _speex_unpack_comment(state->vc,&opb);
 
403
                                    break;
 
404
                                default:
 
405
                                    state->lasterror = _("Need to save extra headers - TODO!!");
 
406
                                    goto err;
 
407
                                    break;
 
408
                            }
298
409
                    }
299
410
                    i++;
300
 
                    header = &header_codebooks;
301
411
                }
302
412
            }
303
413
        }
356
466
 
357
467
    ogg_stream_init(&streamout, state->serial);
358
468
 
359
 
    _commentheader_out(state->vc, state->vendor, &header_comments);
360
 
 
361
 
    /* 2002/10/22 - new code here for padded headers */
362
 
    //header_comments.packet = realloc(header_comments.packet, header_comments.bytes + 1000);
363
 
    //header_comments.bytes += 1000;
364
 
    /* end of new code */
 
469
    _commentheader_out(state, &header_comments);
365
470
 
366
471
    ogg_stream_packetin(&streamout, &header_main);
367
472
    ogg_stream_packetin(&streamout, &header_comments);
368
 
    ogg_stream_packetin(&streamout, &header_codebooks);
 
473
 
 
474
    if (state->oggtype != VCEDIT_IS_SPEEX)
 
475
        ogg_stream_packetin(&streamout, &header_codebooks);
369
476
 
370
477
    while((result = ogg_stream_flush(&streamout, &ogout)))
371
478
    {
372
479
        if(state->write(ogout.header,1,ogout.header_len, out) !=
373
480
                (size_t) ogout.header_len)
374
481
            goto cleanup;
375
 
        if(state->write(ogout.body,1,ogout.body_len, out) != 
 
482
        if(state->write(ogout.body,1,ogout.body_len, out) !=
376
483
                (size_t) ogout.body_len)
377
484
            goto cleanup;
378
485
    }
379
486
 
380
487
    while(_fetch_next_packet(state, &op, &ogin))
381
488
    {
382
 
        int size;
383
 
        size = _blocksize(state, &op);
384
 
        granpos += size;
385
 
 
386
489
        if(needflush)
387
490
        {
388
491
            if(ogg_stream_flush(&streamout, &ogout))
389
492
            {
390
 
                if(state->write(ogout.header,1,ogout.header_len, 
 
493
                if(state->write(ogout.header,1,ogout.header_len,
391
494
                            out) != (size_t) ogout.header_len)
392
495
                    goto cleanup;
393
 
                if(state->write(ogout.body,1,ogout.body_len, 
 
496
                if(state->write(ogout.body,1,ogout.body_len,
394
497
                            out) != (size_t) ogout.body_len)
395
498
                    goto cleanup;
396
499
            }
399
502
        {
400
503
            if(ogg_stream_pageout(&streamout, &ogout))
401
504
            {
402
 
                if(state->write(ogout.header,1,ogout.header_len, 
 
505
                if(state->write(ogout.header,1,ogout.header_len,
403
506
                            out) != (size_t) ogout.header_len)
404
507
                    goto cleanup;
405
 
                if(state->write(ogout.body,1,ogout.body_len, 
 
508
                if(state->write(ogout.body,1,ogout.body_len,
406
509
                            out) != (size_t) ogout.body_len)
407
510
                    goto cleanup;
408
511
            }
410
513
 
411
514
        needflush=needout=0;
412
515
 
413
 
        if(op.granulepos == -1)
414
 
        {
415
 
            op.granulepos = granpos;
 
516
        if (state->oggtype == VCEDIT_IS_OGGVORBIS)
 
517
        {
 
518
            int size;
 
519
            size = _blocksize(state, &op);
 
520
            granpos += size;
 
521
 
 
522
            if(op.granulepos == -1)
 
523
            {
 
524
                op.granulepos = granpos;
 
525
                ogg_stream_packetin(&streamout, &op);
 
526
            }
 
527
            else /* granulepos is set, validly. Use it, and force a flush to 
 
528
                account for shortened blocks (vcut) when appropriate */ 
 
529
            {
 
530
                if(granpos > op.granulepos)
 
531
                {
 
532
                    granpos = op.granulepos;
 
533
                    ogg_stream_packetin(&streamout, &op);
 
534
                    needflush=1;
 
535
                }
 
536
                else 
 
537
                {
 
538
                    ogg_stream_packetin(&streamout, &op);
 
539
                    needout=1;
 
540
                }
 
541
            }
 
542
        }
 
543
        /* Don't know about granulepos for speex, will just assume the original 
 
544
           was appropriate. Not sure about the flushing?? */
 
545
        else if (state->oggtype == VCEDIT_IS_SPEEX)
 
546
        {
416
547
            ogg_stream_packetin(&streamout, &op);
 
548
            needout=1;
417
549
        }
418
 
        else /* granulepos is set, validly. Use it, and force a flush to 
419
 
                account for shortened blocks (vcut) when appropriate */ 
420
 
        {
421
 
            if(granpos > op.granulepos)
422
 
            {
423
 
                granpos = op.granulepos;
424
 
                ogg_stream_packetin(&streamout, &op);
425
 
                needflush=1;
426
 
            }
427
 
            else 
428
 
            {
429
 
                ogg_stream_packetin(&streamout, &op);
430
 
                needout=1;
431
 
            }
432
 
        }        
433
550
    }
434
551
 
435
552
    streamout.e_o_s = 1;
436
553
    while(ogg_stream_flush(&streamout, &ogout))
437
554
    {
438
 
        if(state->write(ogout.header,1,ogout.header_len, 
 
555
        if(state->write(ogout.header,1,ogout.header_len,
439
556
                    out) != (size_t) ogout.header_len)
440
557
            goto cleanup;
441
 
        if(state->write(ogout.body,1,ogout.body_len, 
 
558
        if(state->write(ogout.body,1,ogout.body_len,
442
559
                    out) != (size_t) ogout.body_len)
443
560
            goto cleanup;
444
561
    }
467
584
                state->lasterror = _("Corrupt or missing data, continuing...");
468
585
            else
469
586
            {
470
 
                /* Don't bother going through the rest, we can just 
 
587
                /* Don't bother going through the rest, we can just
471
588
                 * write the page out now */
472
 
                if(state->write(ogout.header,1,ogout.header_len, 
 
589
                if(state->write(ogout.header,1,ogout.header_len,
473
590
                        out) != (size_t) ogout.header_len) {
474
591
                    goto cleanup;
475
592
                }
482
599
        buffer = ogg_sync_buffer(state->oy, CHUNKSIZE);
483
600
        bytes = state->read(buffer,1, CHUNKSIZE, state->in);
484
601
        ogg_sync_wrote(state->oy, bytes);
485
 
        if(bytes == 0) 
 
602
        if(bytes == 0)
486
603
        {
487
604
            state->eosin = 1;
488
605
            break;
492
609
 
493
610
cleanup:
494
611
    ogg_stream_clear(&streamout);
495
 
 
496
 
    /* We don't ogg_packet_clear() this, because the memory was allocated in
497
 
       _commentheader_out(), so we mirror that here */
498
 
    _ogg_free(header_comments.packet);
 
612
    ogg_packet_clear(&header_comments);
499
613
 
500
614
    free(state->mainbuf);
501
615
    free(state->bookbuf);