File Coverage

src/dsf.c
Criterion Covered Total %
statement 54 72 75.0
branch 23 46 50.0
condition n/a
subroutine n/a
pod n/a
total 77 118 65.2


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 3           get_dsf_metadata(PerlIO *infile, char *file, HV *info, HV *tags)
21             {
22             Buffer buf;
23             off_t file_size;
24 3           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 3           file_size = _file_size(infile);
31              
32 3           buffer_init(&buf, DSF_BLOCK_SIZE);
33              
34 3 50         if ( !_check_buf(infile, &buf, 80, DSF_BLOCK_SIZE) ) {
35 0           err = -1;
36 0           goto out;
37             }
38              
39 3 50         if ( !strncmp( (char *)buffer_ptr(&buf), "DSD ", 4 ) ) {
40 3           buffer_consume(&buf, 4);
41              
42 3           my_hv_store( info, "file_size", newSVuv(file_size) );
43              
44 3           chunk_size = buffer_get_int64_le(&buf);
45 3           total_size = buffer_get_int64_le(&buf);
46 3           metadata_offset = buffer_get_int64_le(&buf);
47              
48 3 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 3 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 3           buffer_consume(&buf, 4);
62 3           chunk_size = buffer_get_int64_le(&buf);
63 3           format_version = buffer_get_int_le(&buf);
64 3           format_id = buffer_get_int_le(&buf);
65 3           channel_type = buffer_get_int_le(&buf);
66 3           channel_num = buffer_get_int_le(&buf);
67 3           sampling_frequency = buffer_get_int_le(&buf);
68 3           bits_per_sample = buffer_get_int_le(&buf);
69 3           sample_count = buffer_get_int64_le(&buf);
70 3           block_size_per_channel = buffer_get_int_le(&buf);
71              
72 3 50         if ( (chunk_size != 52) ||
    50          
73 3 50         (format_version != 1) ||
74 3 50         (format_id != 0) ||
75 3 50         (block_size_per_channel != 4096) ||
76 3           strncmp( (char *)buffer_ptr(&buf), "\0\0\0\0", 4 ) ) {
77 0           PerlIO_printf(PerlIO_stderr(), "Invalid DSF file: unsupported fmt header: %s\n", file);
78 0           err = -1;
79 0           goto out;
80             }
81              
82 3           buffer_consume(&buf, 4);
83              
84 3 50         if ( strncmp( (char *)buffer_ptr(&buf), "data", 4 ) ) {
85 0           PerlIO_printf(PerlIO_stderr(), "Invalid DSF file: missing data header: %s\n", file);
86 0           err = -1;
87 0           goto out;
88             }
89              
90 3           buffer_consume(&buf, 4);
91              
92 3           sample_bytes = buffer_get_int64_le(&buf) - 12;
93              
94 3           song_length_ms = ((sample_count * 1.0) / sampling_frequency) * 1000;
95              
96 3           my_hv_store( info, "audio_offset", newSVuv( 28 + 52 + 12 ) );
97 3           my_hv_store( info, "audio_size", newSVuv(sample_bytes) );
98 3           my_hv_store( info, "samplerate", newSVuv(sampling_frequency) );
99 3           my_hv_store( info, "song_length_ms", newSVuv(song_length_ms) );
100 3           my_hv_store( info, "channels", newSVuv(channel_num) );
101 3           my_hv_store( info, "bits_per_sample", newSVuv(1) );
102 3           my_hv_store( info, "block_size_per_channel", newSVuv(block_size_per_channel) );
103 3           my_hv_store( info, "bitrate", newSVuv( _bitrate(file_size - (28 + 52 + 12), song_length_ms) ) );
104              
105 3 50         if (metadata_offset) {
106 3           PerlIO_seek(infile, metadata_offset, SEEK_SET);
107 3           buffer_clear(&buf);
108 3 50         if ( !_check_buf(infile, &buf, 10, DSF_BLOCK_SIZE) ) {
109 0           goto out;
110             }
111              
112 3           bptr = buffer_ptr(&buf);
113 3 50         if (
114 3 50         (bptr[0] == 'I' && bptr[1] == 'D' && bptr[2] == '3') &&
    50          
    50          
115 3 50         bptr[3] < 0xff && bptr[4] < 0xff &&
    50          
116 3 50         bptr[6] < 0x80 && bptr[7] < 0x80 && bptr[8] < 0x80 && bptr[9] < 0x80
    50          
    50          
117             ) {
118 3           parse_id3(infile, file, info, tags, metadata_offset, file_size);
119             }
120             }
121             }
122             else {
123 0           PerlIO_printf(PerlIO_stderr(), "Invalid DSF file: missing DSD header: %s\n", file);
124 0           err = -1;
125 0           goto out;
126             }
127              
128             out:
129 3           buffer_free(&buf);
130              
131 3 50         if (err) return err;
132              
133 3           return 0;
134             }