1 /*
2 * Copyright 2003-2021 The Music Player Daemon Project
3 * http://www.musicpd.org
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 /* \file
21 *
22 * This file contains functions used by the DSF and DSDIFF decoders.
23 *
24 */
25
26 #include "config.h"
27 #include "DsdLib.hxx"
28 #include "../DecoderAPI.hxx"
29 #include "input/InputStream.hxx"
30 #include "tag/Id3Scan.hxx"
31
32 #ifdef ENABLE_ID3TAG
33 #include <id3tag.h>
34 #endif
35
36 #include <string.h>
37 #include <stdlib.h>
38
39 bool
Equals(const char * s) const40 DsdId::Equals(const char *s) const noexcept
41 {
42 assert(s != nullptr);
43 assert(strlen(s) == sizeof(value));
44
45 return memcmp(value, s, sizeof(value)) == 0;
46 }
47
48 /**
49 * Skip the #InputStream to the specified offset.
50 */
51 bool
dsdlib_skip_to(DecoderClient * client,InputStream & is,offset_type offset)52 dsdlib_skip_to(DecoderClient *client, InputStream &is,
53 offset_type offset)
54 {
55 if (is.IsSeekable()) {
56 try {
57 is.LockSeek(offset);
58 } catch (...) {
59 return false;
60 }
61 }
62
63 if (is.GetOffset() > offset)
64 return false;
65
66 return dsdlib_skip(client, is, offset - is.GetOffset());
67 }
68
69 /**
70 * Skip some bytes from the #InputStream.
71 */
72 bool
dsdlib_skip(DecoderClient * client,InputStream & is,offset_type delta)73 dsdlib_skip(DecoderClient *client, InputStream &is,
74 offset_type delta)
75 {
76 if (delta == 0)
77 return true;
78
79 if (is.IsSeekable()) {
80 try {
81 is.LockSeek(is.GetOffset() + delta);
82 } catch (...) {
83 return false;
84 }
85 }
86
87 if (delta > 1024 * 1024)
88 /* don't skip more than one megabyte; it would be too
89 expensive */
90 return false;
91
92 return decoder_skip(client, is, delta);
93 }
94
95 bool
dsdlib_valid_freq(uint32_t samplefreq)96 dsdlib_valid_freq(uint32_t samplefreq) noexcept
97 {
98 switch (samplefreq) {
99 case 2822400: /* DSD64, 64xFs, Fs = 44.100kHz */
100 case 3072000: /* DSD64 with Fs = 48.000 kHz */
101 case 5644800:
102 case 6144000:
103 case 11289600:
104 case 12288000:
105 case 22579200:/* DSD512 */
106 case 24576000:
107 return true;
108
109 default:
110 return false;
111 }
112 }
113
114 #ifdef ENABLE_ID3TAG
115 void
dsdlib_tag_id3(InputStream & is,TagHandler & handler,offset_type tagoffset)116 dsdlib_tag_id3(InputStream &is, TagHandler &handler,
117 offset_type tagoffset)
118 {
119 if (tagoffset == 0 || !is.KnownSize())
120 return;
121
122 /* Prevent broken files causing problems */
123 const auto size = is.GetSize();
124 if (tagoffset >= size)
125 return;
126
127 const auto count64 = size - tagoffset;
128 if (count64 < 10 || count64 > 4 * 1024 * 1024)
129 return;
130
131 if (!dsdlib_skip_to(nullptr, is, tagoffset))
132 return;
133
134 const id3_length_t count = count64;
135
136 auto *const id3_buf = new id3_byte_t[count];
137 if (id3_buf == nullptr)
138 return;
139
140 if (!decoder_read_full(nullptr, is, id3_buf, count)) {
141 delete[] id3_buf;
142 return;
143 }
144
145 struct id3_tag *id3_tag = id3_tag_parse(id3_buf, count);
146 delete[] id3_buf;
147 if (id3_tag == nullptr)
148 return;
149
150 scan_id3_tag(id3_tag, handler);
151
152 id3_tag_delete(id3_tag);
153 }
154 #endif
155