TTKMusicPlayer  3.7.0.0
TTKMusicPlayer imitates Kugou UI, the music player uses of qmmp core library based on Qt for windows and linux
musiclrcfromkrc.cpp
Go to the documentation of this file.
1 #include "musiclrcfromkrc.h"
2 
3 #include <QFile>
4 #include <sys/stat.h>
5 
6 #include "zlib/zconf.h"
7 #include "zlib/zlib.h"
8 
9 static constexpr wchar_t key[] = {
10  L'@', L'G', L'a', L'w', L'^', L'2',
11  L't', L'G', L'Q', L'6', L'1', L'-',
12  L'Î', L'Ò', L'n', L'i'
13 };
14 
15 
17 {
18  m_resultBytes = new uchar[TTK_SN_MB2BT];
19 }
20 
22 {
23  delete[] m_resultBytes;
24 }
25 
26 bool MusicLrcFromKrc::decode(const QString &input, const QString &output)
27 {
28  FILE *fp = nullptr;
29  struct stat st;
30  size_t dstsize;
31 
32  if((fp = fopen(qPrintable(input), "rb")) == nullptr)
33  {
34  TTK_ERROR_STREAM("Open file error");
35  return false;
36  }
37 
38  if(fstat(fileno(fp), &st))
39  {
40  TTK_ERROR_STREAM("Fstat file error");
41  fclose(fp);
42  return false;
43  }
44 
45  uchar *src = new uchar[st.st_size];
46  if(fread(src, sizeof(uchar), st.st_size, fp) != (size_t)st.st_size)
47  {
48  TTK_ERROR_STREAM("Fread file error");
49  delete[] src;
50  fclose(fp);
51  return false;
52  }
53 
54  if(memcmp(src, "krc1", 4) != 0)
55  {
56  TTK_ERROR_STREAM("Error file format");
57  delete[] src;
58  fclose(fp);
59  return false;
60  }
61 
62  src += 4;
63  for(int i = 0; i < st.st_size; ++i)
64  {
65  src[i] = (uchar)(src[i] ^ key[i % 16]);
66  }
67 
68  decompression(src, st.st_size, &dstsize);
69  createLrc(m_resultBytes, TTKStaticCast(int, dstsize));
70 
71  delete[] src;
72  fclose(fp);
73 
74  if(!output.isEmpty())
75  {
76  QFile file(output);
77  if(file.open(QIODevice::WriteOnly))
78  {
79  QTextStream outstream(&file);
80  outstream.setCodec("UTF-8");
81  outstream << m_data;
82  QtStreamEndLine(outstream);
83  file.close();
84  }
85  }
86  return true;
87 }
88 
90 {
91  return m_data;
92 }
93 
94 int MusicLrcFromKrc::sncasecmp(char *s1, char *s2, size_t n)
95 {
96  uint c1, c2;
97  while(n)
98  {
99  c1 = (uint) *s1++;
100  c2 = (uint) *s2++;
101 
102  c1 = (c1 >= 'A' && c1 <= 'Z') ? (c1 | 0x20) : c1;
103  c2 = (c2 >= 'A' && c2 <= 'Z') ? (c2 | 0x20) : c2;
104 
105  if(c1 == c2)
106  {
107  if(c1)
108  {
109  n--;
110  continue;
111  }
112  return 0;
113  }
114  return c1 - c2;
115  }
116  return 0;
117 }
118 
119 int MusicLrcFromKrc::decompression(uchar *src, size_t srcsize, size_t *dstsize)
120 {
121  *dstsize = TTK_SN_MB2BT;
122  if(Z_OK != uncompress(m_resultBytes, (uLongf*)dstsize, src, srcsize))
123  {
124  return -1;
125  }
126  return 0;
127 }
128 
130 {
131  if(!sncasecmp(tok, TTKConstCast(char*, TTKString("[id").c_str()), 3))
132  {
133  return 1;
134  }
135  else if(!sncasecmp(tok, TTKConstCast(char*, TTKString("[by").c_str()), 3))
136  {
137  return 1;
138  }
139  else if(!sncasecmp(tok, TTKConstCast(char*, TTKString("[hash").c_str()), 5))
140  {
141  return 1;
142  }
143  else if(!sncasecmp(tok, TTKConstCast(char*, TTKString("[al").c_str()), 3))
144  {
145  return 1;
146  }
147  else if(!sncasecmp(tok, TTKConstCast(char*, TTKString("[sign").c_str()), 5))
148  {
149  return 1;
150  }
151  else if(!sncasecmp(tok, TTKConstCast(char*, TTKString("[total").c_str()), 6))
152  {
153  return 1;
154  }
155  else if(!sncasecmp(tok, TTKConstCast(char*, TTKString("[offset").c_str()), 7))
156  {
157  return 1;
158  }
159  return 0;
160 }
161 
162 void MusicLrcFromKrc::createLrc(uchar *lrc, int lrclen)
163 {
164  m_data.clear();
165  int top = 0;
166  for(int i = 0; i < lrclen; ++i)
167  {
168  int len;
169  if(top == 0)
170  {
171  switch(lrc[i])
172  {
173  case '<':
174  top++;
175  break;
176  case '[':
177  len = (strchr((char*)&lrc[i], ']') - (char*)&lrc[i]) + 1;
178  for(int j = 0; j < len; ++j)
179  {
180  if(lrc[i + j] == ':')
181  {
182  if(isfilter((char*)&lrc[i]))
183  {
184  while(lrc[++i] != '\n' && i < lrclen)
185  {
186 
187  }
188  }
189  goto filter_done;
190  }
191  }
192 
193  for(int j = 0; j < len; ++j)
194  {
195  int ms;
196  if(lrc[i + j] == ',')
197  {
198  char ftime[14];
199  lrc[i + j] = 0;
200  ms = atoi((char*)&lrc[i + 1]);
201  sprintf(ftime, "[%.2d:%.2d.%.2d]", (ms % TTK_DN_H2MS) / TTK_DN_M2MS, (ms % TTK_DN_M2MS) / TTK_DN_S2MS, (ms % TTK_DN_M2MS) % 100);
202 
203  for(j = 0; j < 10; ++j)
204  {
205  m_data.append(ftime[j]);
206  }
207  i = i + len - 1;
208  break;
209  }
210  }
211  break;
212  filter_done:
213  default:
214  m_data.append(lrc[i]);
215  break;
216  }
217 
218  }
219  else if(top == 1 && lrc[i] == '>')
220  {
221  top--;
222  }
223  }
224 }
#define TTKStaticCast(x, y)
Definition: ttkglobal.h:159
#define TTKConstCast(x, y)
Definition: ttkglobal.h:141
int ZEXPORT uncompress(Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen)
Definition: uncompr.c:82
static constexpr wchar_t key[]
QByteArray decodeString() const
#define TTK_SN_MB2BT
Definition: ttkglobal.h:315
#define TTK_DN_M2MS
Definition: ttkglobal.h:282
#define qPrintable(s)
Definition: ttkqtglobal.h:36
#define QtStreamEndLine(p)
Stream endl.
Definition: ttkqtcompat.h:115
int sncasecmp(char *s1, char *s2, size_t n)
#define TTK_DN_H2MS
Definition: ttkglobal.h:289
int isfilter(char *tok)
std::string TTKString
Definition: ttkglobal.h:121
void createLrc(uchar *lrc, int lrclen)
int decompression(uchar *src, size_t srcsize, size_t *dstsize)
#define TTK_DN_S2MS
Definition: ttkglobal.h:276
uLong FAR uLongf
Definition: zconf.h:407
QByteArray m_data
#define Z_OK
Definition: zlib.h:177
#define TTK_ERROR_STREAM(msg)
Definition: ttklogger.h:69
bool decode(const QString &input, const QString &output={})