DCL 4.0
Loading...
Searching...
No Matches
APEv2.cpp
Go to the documentation of this file.
1#include <dcl/Config.h>
2
3#include <stdlib.h>
4
5#if __DCL_WINDOWS
6#include <windows.h>
7#endif
8
9#include <string.h>
10
11#include <dcl/String.h>
12#include <dcl/Charset.h>
13#include <dcl/File.h>
14
15#include "APEv2.h"
16
17#define __TRACE_THIS 0
18#if __TRACE_THIS
19#define __DCL_TRACE1_N __DCL_TRACE1
20#define __DCL_TRACE2_N __DCL_TRACE2
21#define __DCL_TRACE3_N __DCL_TRACE3
22#else
23#define __DCL_TRACE1_N(fmt, arg)
24#define __DCL_TRACE2_N(fmt, arg1, arg2)
25#define __DCL_TRACE3_N(fmt, arg1, arg2, arg3)
26#endif
27
28__DCL_BEGIN_NAMESPACE
29
30#if __DCL_DEBUG
31#undef __THIS_FILE__
32static const char_t __THIS_FILE__[] = __T("media/APEv2.cpp");
33#endif
34
36
37APEv2::APEv2()
38{
40 __data = NULL;
41}
42
43APEv2::~APEv2()
44{
45 if (__data) {
46 free(__data);
47 __data = NULL;
48 }
49
50 for (size_t i = 0; i < __items.size(); i++) {
51 delete (APEv2Item*)__items[i];
52 }
53}
54
55uint32_t APEv2::word(const char _chars[4])
56{
57 uint32_t r = (byte_t)_chars[3];
58 r = (r << 8) | (byte_t)_chars[2];
59 r = (r << 8) | (byte_t)_chars[1];
60 r = (r << 8) | (byte_t)_chars[0];
61 return r;
62}
63
64bool APEv2::read(File& _file, const char _footerOr[32], File::off_t _off)
65{
66 char buf[160]; // 32 + 128
67 if (_footerOr == NULL) {
68 // ID3v1이 있는것으로 가정하여
69 // 파일의 끝에서 160 바이트를 읽는다.
70 _file.seek(-160, File::END);
71 size_t n = _file.read(buf, 160);
72 if (n < 160) {
73 return false;
74 }
75
76 __DCL_TRACE1_N(L"[%ls]\n", String::tryString(buf, 32).data());
77 if (memcmp(buf, "APETAGEX", 8) == 0) {
78 _footerOr = buf;
79 _off = -160;
80 }
81 else {
82 __DCL_TRACE1_N(L"[%ls]\n", String::tryString(&buf[128], 32).data());
83 if (memcmp(&buf[128], "APETAGEX", 8) == 0) {
84 _footerOr = &buf[128];
85 _off = -32;
86 }
87 }
88 }
89
90 if (_footerOr == NULL) {
91 // 파일의 시작에서 32 바이트를 읽는다.
92 _file.seek(0, File::BEGIN);
93 size_t n = _file.read(buf, 32);
94 if (n < 32) {
95 return false;
96 }
97 _footerOr = buf;
98 _off = 0;
99 }
100
101 if (_footerOr == NULL || memcmp(_footerOr, "APETAGEX", 8) != 0) {
102 return false;
103 }
104
105 __APETAGEX = AsciiDecoder::decode(&_footerOr[0], 8);
106 __version = word(&_footerOr[8]);
107 __size = word(&_footerOr[12]);
108 __count = word(&_footerOr[16]);
109 __flags = word(&_footerOr[20]);
110 // Reserved 24 ~ 31
111
112 __DCL_TRACE2_N(L"[%lld] %ls\n", _off, toString().data());
113
114 // Header, Item 데이터를 읽는다.
115 if (_off < 0) {
116 _file.seek(_off - __size, File::END);
117 }
118
119 __data = (char*)malloc(__size);
120 size_t n = _file.read(__data, __size);
121 if (n < __size) {
122 return false;
123 }
124
125 __DCL_TRACE2_N(L"[%zd] [%ls]\n", n, String::tryString(__data, n, 500).data());
126
127 const char* _begin = __data;
128 const char* _end = _begin + n;
129
130 if (__flags & 0x80000000 && _begin + 32 <= _end) {
131 // header가 있다.
132 String sig = AsciiDecoder::decode(_begin, 8);
133 uint32_t version = word(_begin + 8);
134 uint32_t size = word(_begin + 12);
135 uint32_t count = word(_begin + 16);
136 uint32_t flags = word(_begin + 20);
137
138 String s = String::format(L""
139 "Header[%ls] version[%d] size[%d] count[%d] flags[%x]",
140 sig.data(),
141 version, size, count, flags
142 );
143 __DCL_TRACE1_N(L"%ls\n", s.data());
144 _begin += 32;
145 }
146
147 // Item을 읽는다.
148 // 최소 8 bytes (size 4, flags 4)가 있어야 한다.
149 while (_begin + 8 < _end) {
150 APEv2Item* item = new APEv2Item;
151 _begin += item->read(_begin, _end);
152 __DCL_TRACE1_N(L"%ls\n", item->toString().data());
153 __items.add(item);
154 }
155
156 return true;
157}
158
159String APEv2::toString() const
160{
161 return String::format(L""
162 "%ls version[%d] size[%d] count[%d] flags[%x]",
163 __APETAGEX.data(),
165 );
166}
167
169
170APEv2Item::APEv2Item()
171{
172 __size = __flags = 0;
173}
174
175size_t APEv2Item::read(const char* _begin, const char* _end)
176{
177 // 최소 8 bytes는 되어야 한다.
178 __DCL_ASSERT(_begin + 8 < _end);
179 __size = APEv2::word(_begin);
180 __flags = APEv2::word(_begin + 4);
181 _begin += 8;
182
183 // bit 2... 1
184 int type = (__flags & 0x0006) >> 1;
185 if (_begin < _end) {
187 ByteString::length(_begin, _end - _begin));
188 _begin += __key.length() + 1;
189 }
190 if (_begin + __size < _end) {
191 switch (type) {
192 case 0: {
193 size_t n = ByteString::length(_begin, __size);
194 try {
195 __value = UTF8Decoder::decode(_begin, n);
196 }
197 catch (CharsetConvertException* e) {
198 __DCL_TRACE0(L"UTF8Decoder::decode failed. retry Latin1Decoder\n");
199 __DCL_TRACE3(L"Item size[%d] flags[%x] type[%d] ",
200 __size, __flags, type);
201 __DCL_TRACE3(L"%ls key[%ls] [%ls]\n",
202 e->toStringAll().data(),
203 __key.data(), String::tryString(_begin, __size).data()
204 );
205 e->destroy();
207 }
208 __value = __value.trim();
209 break;
210 }
211 case 1 :
212 __value = String::tryString(_begin,
213 ByteString::length(_begin, __size));
214 case 2 :
215 default :
216 ;
217 }
218 }
219
220 return 4 + 4 + __key.length() + 1 + __size;
221}
222
223String APEv2Item::toString() const
224{
225 StringBuilder sb;
226 sb.format(L"size[%d] flags[%x] key[%ls] value[%ls]",
228 __key.data(), __value.data());
229
230 return sb;
231}
232__DCL_END_NAMESPACE
#define __THIS_FILE__
Definition _trace.h:14
#define NULL
Definition Config.h:340
wchar_t char_t
Definition Config.h:275
unsigned char byte_t
Definition Config.h:274
#define __DCL_TRACE1_N(fmt, arg)
#define __DCL_TRACE2_N(fmt, arg1, arg2)
#define __DCL_TRACE0(psz)
Definition Object.h:375
#define __DCL_TRACE3(fmt, arg1, arg2, arg3)
Definition Object.h:378
#define __DCL_ASSERT(expr)
Definition Object.h:371
#define IMPLEMENT_CLASSINFO(class_name, base_class_name)
Definition Object.h:228
#define __T(str)
Definition Object.h:44
ByteString r
ByteBuffer * buf
void CharsetConvertException *size_t n
Definition SQLField.cpp:253
Definition APEv2.h:16
uint32_t __flags
Definition APEv2.h:89
uint32_t __count
Definition APEv2.h:86
String __APETAGEX
Definition APEv2.h:77
uint32_t __size
Definition APEv2.h:83
char * __data
Definition APEv2.h:91
PointerArray __items
Definition APEv2.h:93
uint32_t __version
Definition APEv2.h:80
uint32_t __flags
Definition APEv2.h:126
String __value
Definition APEv2.h:130
uint32_t __size
Definition APEv2.h:124
String __key
Definition APEv2.h:128
static String decode(const char *_mbs, size_t _mbslen=(size_t) -1)
virtual void destroy()
Definition Exception.cpp:74
String toStringAll() const
Definition Exception.cpp:45
Definition File.h:38
@ END
Definition File.h:207
@ BEGIN
Definition File.h:205
off_t seek(off_t _offset, int _whence) __DCL_THROWS1(IOException *)
Definition File.cpp:590
virtual size_t read(void *_buf, size_t _n) __DCL_THROWS1(IOException *)
Definition File.cpp:476
static String decode(const char *_mbs, size_t _nmbs=(size_t) -1)
virtual String toString() const
Definition Object.cpp:187