1 /***************************************************************************
2     copyright            : (C) 2014 by Peking Duck Labs
3     email                : pekingducklabs@gmail.com
4  ***************************************************************************/
5 
6 /***************************************************************************
7  *   This library is free software; you can redistribute it and/or modify  *
8  *   it under the terms of the GNU Lesser General Public License version   *
9  *   2.1 as published by the Free Software Foundation.                     *
10  *                                                                         *
11  *   This library is distributed in the hope that it will be useful, but   *
12  *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
13  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
14  *   Lesser General Public License for more details.                       *
15  *                                                                         *
16  *   You should have received a copy of the GNU Lesser General Public      *
17  *   License along with this library; if not, write to the Free Software   *
18  *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA         *
19  *   02110-1301  USA                                                       *
20  ***************************************************************************/
21 
22 #include <cstdint>
23 
24 #include <bitset>
25 
26 // Kid3: Remove taglib/ from includes
27 #include <tbytevector.h>
28 #include <tstring.h>
29 #include <trefcounter.h>
30 // Kid3: Use debug() instead of std::cerr
31 #include <tdebug.h>
32 
33 #include "dsfheader.h"
34 
35 class DSFHeader::HeaderPrivate : public TagLib::RefCounter
36 {
37 public:
HeaderPrivate()38   HeaderPrivate()
39     : isValid(false),
40       version(Version1),
41       sampleCount(0),
42       channelType(Stereo),
43       channelNum(2),
44       sampleRate(0),
45       bitsPerSample(0),
46       ID3v2Offset(0),
47       fileSize(0)
48   {}
49 
50   bool isValid;
51   Version version; // format version
52   uint64_t sampleCount;
53   ChannelType channelType;
54   unsigned short channelNum;
55   unsigned int sampleRate;
56   unsigned short bitsPerSample;
57   uint64_t ID3v2Offset;
58   uint64_t fileSize;
59 };
60 
61 ////////////////////////////////////////////////////////////////////////////////
62 // public members
63 ////////////////////////////////////////////////////////////////////////////////
64 
DSFHeader(const TagLib::ByteVector & data)65 DSFHeader::DSFHeader(const TagLib::ByteVector &data)
66 {
67   d = new HeaderPrivate;
68   parse(data);
69 }
70 
DSFHeader(const DSFHeader & h)71 DSFHeader::DSFHeader(const DSFHeader &h) : d(h.d)
72 {
73   d->ref();
74 }
75 
~DSFHeader()76 DSFHeader::~DSFHeader()
77 {
78   if (d->deref())
79     delete d;
80 }
81 
isValid() const82 bool DSFHeader::isValid() const
83 {
84   return d->isValid;
85 }
86 
version() const87 DSFHeader::Version DSFHeader::version() const
88 {
89   return d->version;
90 }
91 
sampleRate() const92 unsigned int DSFHeader::sampleRate() const
93 {
94   return d->sampleRate;
95 }
96 
channelType() const97 DSFHeader::ChannelType DSFHeader::channelType() const
98 {
99   return d->channelType;
100 }
101 
channelNum() const102 unsigned short DSFHeader::channelNum() const
103 {
104   return d->channelNum;
105 }
106 
sampleCount() const107 uint64_t DSFHeader::sampleCount() const
108 {
109   return d->sampleCount;
110 }
111 
ID3v2Offset() const112 uint64_t DSFHeader::ID3v2Offset() const
113 {
114   return d->ID3v2Offset;
115 }
116 
fileSize() const117 uint64_t DSFHeader::fileSize() const
118 {
119   return d->fileSize;
120 }
121 
bitsPerSample() const122 unsigned short DSFHeader::bitsPerSample() const
123 {
124   return d->bitsPerSample;
125 }
126 
operator =(const DSFHeader & h)127 DSFHeader &DSFHeader::operator=(const DSFHeader &h)
128 {
129   if(&h == this)
130     return *this;
131 
132   if(d->deref())
133     delete d;
134 
135   d = h.d;
136   d->ref();
137   return *this;
138 }
139 
140 ////////////////////////////////////////////////////////////////////////////////
141 // private members
142 ////////////////////////////////////////////////////////////////////////////////
143 
parse(const TagLib::ByteVector & data)144 void DSFHeader::parse(const TagLib::ByteVector &data)
145 {
146   if (data.size() < DSD_HEADER_SIZE + FMT_HEADER_SIZE) {
147     debug("DSFHeader::parse(): header size incorrect");
148     return;
149   }
150 
151   const char *hdr = data.data();
152   size_t offset = 0;
153 
154   //
155   // ******** DSD chunk header ********
156   // DSD header chunk should start with "DSD ".
157   //
158   if (hdr[0] != 'D' || hdr[1] != 'S' || hdr[2] != 'D' || hdr[3] != ' ')
159   {
160     debug("DSD::Header::parse(): DSD header's first 4 bytes != 'DSD '");
161     return;
162   }
163   offset += 4;
164 
165   // The next 8 bytes contain the size of DSD header
166   // (numerical data is stored in little endian)
167   if (data.toLongLong(offset, false) != DSD_HEADER_SIZE)
168   {
169     debug("DSD::Header::parse(): DSD header size is incorrect");
170     return;
171   }
172   offset += LONG_INT_SIZE;
173 
174   // The next 8 bytes contains the file size
175   d->fileSize = bytesToUInt64(&hdr[0], offset);
176   offset += LONG_INT_SIZE;
177 
178   // The next 8 bytes contains the offset to id3v2 tag (0 if not exists)
179   d->ID3v2Offset = bytesToUInt64(&hdr[0], offset);
180   offset += LONG_INT_SIZE;
181 
182   //
183   // ********* FMT chunk ********
184   //
185   // FMT header chunk should start with "fmt ".
186   //
187   if (hdr[offset] != 'f' || hdr[offset + 1] != 'm' ||
188       hdr[offset + 2] != 't' || hdr[offset + 3] != ' ')
189   {
190     debug("DSD::Header::parse(): FMT header's first 4 bytes != 'fmt '");
191     return;
192   }
193   offset += 4;
194 
195   // The next 8 bytes contain the size of FMT header, which should be 52
196   if (data.toLongLong(offset, false) != FMT_HEADER_SIZE)
197   {
198     debug("DSD::Header::parse(): FMT header size is incorrect");
199     return;
200   }
201   offset += LONG_INT_SIZE;
202 
203   // Format version
204   // There's only version 1 for now...
205   unsigned int ver = data.toUInt(offset, false);
206   if (ver != 1) {
207     debug("DSD::Header::parse(): format version != 1");
208     return;
209   }
210   d->version = static_cast<Version>(ver);
211   offset += INT_SIZE;
212 
213   // Format ID
214   if (data.toUInt(offset, false) != 0) {
215     debug("DSD::Header::parse(): format ID != 0");
216     return;
217   }
218   offset += INT_SIZE;
219 
220   // Channel Type
221   unsigned int ct = data.toUInt(offset, false);
222   if (ct < 1 || ct > 7) {
223     debug("DSD::Header::parse(): channel type out of range");
224     return;
225   }
226   d->channelType = static_cast<ChannelType>(ct);
227   offset += INT_SIZE;
228 
229   // Channel Num
230   d->channelNum = data.toUInt(offset, false);
231   // Kid3: Removed check "d->channelNum < MinType || ", is always false.
232   if (d->channelNum > MaxType) {
233     debug("DSD::Header::parse(): channel num out of range");
234     return;
235   }
236   offset += INT_SIZE;
237 
238   // Sampling frequency
239   d->sampleRate = data.toUInt(offset, false);
240   if (d->sampleRate != 2822400 && d->sampleRate != 5644800) {
241     debug("DSD::Header::parse(): invalid sampling frequency");
242   }
243   offset += INT_SIZE;
244 
245   // Bits per sample
246   d->bitsPerSample = data.toUInt(offset, false);
247   if (d->bitsPerSample != 1 && d->bitsPerSample != 8) {
248     debug("DSD::Header::parse(): bits per sample invalid");
249     return;
250   }
251   offset += INT_SIZE;
252 
253   // Sample count
254   d->sampleCount = bytesToUInt64(&hdr[0], offset);
255   offset += LONG_INT_SIZE;
256 
257   // Block size per channel
258   if (data.toUInt(offset, false) != 4096) {
259     debug("DSD::Header::parse(): block size != 4096");
260     return;
261   }
262     //offset += 4;
263 
264   // Reserved
265   // offset += 4;
266 
267   d->isValid = true;
268 }
269