File Coverage

src/dsf.c
Criterion Covered Total %
statement 56 74 75.6
branch 25 50 50.0
condition n/a
subroutine n/a
pod n/a
total 81 124 65.3


line stmt bran cond sub pod time code
1             /*
2             * This program is free software; you can redistribute it and/or modify
3             * it under the terms of the GNU General Public License as published by
4             * the Free Software Foundation; either version 2 of the License, or
5             * (at your option) any later version.
6             *
7             * This program is distributed in the hope that it will be useful,
8             * but WITHOUT ANY WARRANTY; without even the implied warranty of
9             * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10             * GNU General Public License for more details.
11             *
12             * You should have received a copy of the GNU General Public License
13             * along with this program; if not, write to the Free Software
14             * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15             */
16              
17             #include "dsf.h"
18              
19             int
20 2           get_dsf_metadata(PerlIO *infile, char *file, HV *info, HV *tags)
21             {
22             Buffer buf;
23             off_t file_size;
24 2           int err = 0;
25             uint64_t chunk_size, total_size, metadata_offset, sample_count, sample_bytes;
26             uint32_t format_version, format_id, channel_type, channel_num,
27             sampling_frequency, block_size_per_channel, bits_per_sample, song_length_ms;
28             unsigned char *bptr;
29              
30 2           file_size = _file_size(infile);
31              
32 2           buffer_init(&buf, DSF_BLOCK_SIZE);
33              
34 2 50         if ( !_check_buf(infile, &buf, 80, DSF_BLOCK_SIZE) ) {
35 0           err = -1;
36 0           goto out;
37             }
38              
39 2 50         if ( !strncmp( (char *)buffer_ptr(&buf), "DSD ", 4 ) ) {
40 2           buffer_consume(&buf, 4);
41              
42 2           my_hv_store( info, "file_size", newSVuv(file_size) );
43              
44 2           chunk_size = buffer_get_int64_le(&buf);
45 2           total_size = buffer_get_int64_le(&buf);
46 2           metadata_offset = buffer_get_int64_le(&buf);
47              
48 2 50         if ((chunk_size != 28) ||
    50          
49             metadata_offset > total_size) {
50 0           PerlIO_printf(PerlIO_stderr(), "Invalid DSF file header: %s\n", file);
51 0           err = -1;
52 0           goto out;
53             }
54              
55 2 50         if ( strncmp( (char *)buffer_ptr(&buf), "fmt ", 4 ) ) {
56 0           PerlIO_printf(PerlIO_stderr(), "Invalid DSF file: missing fmt header: %s\n", file);
57 0           err = -1;
58 0           goto out;
59             }
60              
61 2           buffer_consume(&buf, 4);
62 2           chunk_size = buffer_get_int64_le(&buf);
63 2           format_version = buffer_get_int_le(&buf);
64 2           format_id = buffer_get_int_le(&buf);
65 2           channel_type = buffer_get_int_le(&buf);
66 2           channel_num = buffer_get_int_le(&buf);
67 2           sampling_frequency = buffer_get_int_le(&buf);
68 2           bits_per_sample = buffer_get_int_le(&buf);
69 2           sample_count = buffer_get_int64_le(&buf);
70 2           block_size_per_channel = buffer_get_int_le(&buf);
71              
72 2 50         if ( (chunk_size != 52) ||
    50          
73 2 50         (format_version != 1) ||
74 2 50         (format_id != 0) ||
75 2 50         (channel_type != 2) ||
76 2 50         (channel_num != 2) ||
77 2 50         (block_size_per_channel != 4096) ||
78 2           strncmp( (char *)buffer_ptr(&buf), "\0\0\0\0", 4 ) ) {
79 0           PerlIO_printf(PerlIO_stderr(), "Invalid DSF file: unsupported fmt header: %s\n", file);
80 0           err = -1;
81 0           goto out;
82             }
83              
84 2           buffer_consume(&buf, 4);
85              
86 2 50         if ( strncmp( (char *)buffer_ptr(&buf), "data", 4 ) ) {
87 0           PerlIO_printf(PerlIO_stderr(), "Invalid DSF file: missing data header: %s\n", file);
88 0           err = -1;
89 0           goto out;
90             }
91              
92 2           buffer_consume(&buf, 4);
93              
94 2           sample_bytes = buffer_get_int64_le(&buf) - 12;
95              
96 2           song_length_ms = ((sample_count * 1.0) / sampling_frequency) * 1000;
97              
98 2           my_hv_store( info, "audio_offset", newSVuv( 28 + 52 + 12 ) );
99 2           my_hv_store( info, "audio_size", newSVuv(sample_bytes) );
100 2           my_hv_store( info, "samplerate", newSVuv(sampling_frequency) );
101 2           my_hv_store( info, "song_length_ms", newSVuv(song_length_ms) );
102 2           my_hv_store( info, "channels", newSVuv(channel_num) );
103 2           my_hv_store( info, "bits_per_sample", newSVuv(1) );
104 2           my_hv_store( info, "block_size_per_channel", newSVuv(block_size_per_channel) );
105 2           my_hv_store( info, "bitrate", newSVuv( _bitrate(file_size - (28 + 52 + 12), song_length_ms) ) );
106              
107 2 50         if (metadata_offset) {
108 2           PerlIO_seek(infile, metadata_offset, SEEK_SET);
109 2           buffer_clear(&buf);
110 2 50         if ( !_check_buf(infile, &buf, 10, DSF_BLOCK_SIZE) ) {
111 0           goto out;
112             }
113              
114 2           bptr = buffer_ptr(&buf);
115 2 50         if (
116 2 50         (bptr[0] == 'I' && bptr[1] == 'D' && bptr[2] == '3') &&
    50          
    50          
117 2 50         bptr[3] < 0xff && bptr[4] < 0xff &&
    50          
118 2 50         bptr[6] < 0x80 && bptr[7] < 0x80 && bptr[8] < 0x80 && bptr[9] < 0x80
    50          
    50          
119             ) {
120 2           parse_id3(infile, file, info, tags, metadata_offset, file_size);
121             }
122             }
123             }
124             else {
125 0           PerlIO_printf(PerlIO_stderr(), "Invalid DSF file: missing DSD header: %s\n", file);
126 0           err = -1;
127 0           goto out;
128             }
129              
130             out:
131 2           buffer_free(&buf);
132              
133 2 50         if (err) return err;
134              
135 2           return 0;
136             }