~ubuntu-branches/ubuntu/karmic/kid3/karmic

« back to all changes in this revision

Viewing changes to kid3/attributedata.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Patrick Matthäi
  • Date: 2009-05-20 16:12:30 UTC
  • mfrom: (1.2.3 upstream)
  • mto: This revision was merged to the branch mainline in revision 23.
  • Revision ID: james.westby@ubuntu.com-20090520161230-qetp532r8ydujkz2
Tags: upstream-1.2
Import upstream version 1.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/**
 
2
 * \file attributedata.cpp
 
3
 * String representation of attribute data.
 
4
 *
 
5
 * \b Project: Kid3
 
6
 * \author Urs Fleisch
 
7
 * \date 28 Mar 2009
 
8
 *
 
9
 * Copyright (C) 2009  Urs Fleisch
 
10
 *
 
11
 * This file is part of Kid3.
 
12
 *
 
13
 * Kid3 is free software; you can redistribute it and/or modify
 
14
 * it under the terms of the GNU General Public License as published by
 
15
 * the Free Software Foundation; either version 2 of the License, or
 
16
 * (at your option) any later version.
 
17
 *
 
18
 * Kid3 is distributed in the hope that it will be useful,
 
19
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
20
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
21
 * GNU General Public License for more details.
 
22
 *
 
23
 * You should have received a copy of the GNU General Public License
 
24
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
25
 */
 
26
 
 
27
#include "attributedata.h"
 
28
#include <qmap.h>
 
29
#include "qtcompatmac.h"
 
30
 
 
31
/**
 
32
 * Constructor.
 
33
 *
 
34
 * @param name owner of Windows media PRIV frame
 
35
 */
 
36
AttributeData::AttributeData(const QString& name)
 
37
{
 
38
        /** PRIV-owner and type of Windows media PRIV frames */
 
39
        static const struct TypeOfWmPriv {
 
40
                const char* str;
 
41
                Type type;
 
42
        } typeOfWmPriv[] = {
 
43
                { "AverageLevel", DWord },
 
44
                { "PeakValue", DWord },
 
45
                { "WM/AlbumArtist", Utf16 },
 
46
                { "WM/AuthorURL", Utf16 },
 
47
                { "WM/BeatsPerMinute", Utf16 },
 
48
                { "WM/Composer", Utf16 },
 
49
                { "WM/Conductor", Utf16 },
 
50
                { "WM/ContentDistributor", Utf16 },
 
51
                { "WM/ContentGroupDescription", Utf16 },
 
52
                { "WM/EncodedBy", Utf16 },
 
53
                { "WM/EncodingSettings", Utf16 },
 
54
                { "WM/EncodingTime", Binary },
 
55
                { "WM/Genre", Utf16 },
 
56
                { "WM/InitialKey", Utf16 },
 
57
                { "WM/Language", Utf16 },
 
58
                { "WM/Lyrics", Utf16 },
 
59
                { "WM/Lyrics_Synchronised", Binary },
 
60
                { "WM/MCDI", Binary },
 
61
                { "WM/MediaClassPrimaryID", Guid },
 
62
                { "WM/MediaClassSecondaryID", Guid },
 
63
                { "WM/Mood", Utf16 },
 
64
                { "WM/ParentalRating", Utf16 },
 
65
                { "WM/PartOfSet", Utf16 },
 
66
                { "WM/Period", Utf16 },
 
67
                { "WM/Picture", Binary },
 
68
                { "WM/Producer", Utf16 },
 
69
                { "WM/PromotionURL", Utf16 },
 
70
                { "WM/Provider", Utf16 },
 
71
                { "WM/Publisher", Utf16 },
 
72
                { "WM/SubTitle", Utf16 },
 
73
                { "WM/ToolName", Utf16 },
 
74
                { "WM/ToolVersion", Utf16 },
 
75
                { "WM/TrackNumber", Utf16 },
 
76
                { "WM/UniqueFileIdentifier", Utf16 },
 
77
                { "WM/UserWebURL", Binary },
 
78
                { "WM/WMCollectionGroupID", Guid },
 
79
                { "WM/WMCollectionID", Guid },
 
80
                { "WM/WMContentID", Guid },
 
81
                { "WM/Writer", Utf16 }
 
82
        };
 
83
 
 
84
        static QMap<QString, int> strNumMap;
 
85
        if (strNumMap.empty()) {
 
86
                // first time initialization
 
87
                for (unsigned i = 0; i < sizeof(typeOfWmPriv) / sizeof(typeOfWmPriv[0]);
 
88
                     ++i) {
 
89
                        strNumMap.insert(QString(typeOfWmPriv[i].str), typeOfWmPriv[i].type);
 
90
                }
 
91
        }
 
92
        QMap<QString, int>::const_iterator it =
 
93
                strNumMap.find(name);
 
94
        m_type = (it != strNumMap.end()) ? static_cast<Type>(*it) : Unknown;
 
95
}
 
96
 
 
97
/**
 
98
 * Convert attribute data to string.
 
99
 *
 
100
 * @param data byte array with data
 
101
 * @param str  result string
 
102
 *
 
103
 * @return true if ok.
 
104
 */
 
105
bool AttributeData::toString(const QByteArray& data, QString& str)
 
106
{
 
107
        switch (m_type) {
 
108
                case Utf16: {
 
109
                        const ushort* unicode = reinterpret_cast<const ushort*>(data.data());
 
110
                        int size = data.size() / 2;
 
111
                        while (size > 0 && unicode[size - 1] == 0) {
 
112
                                --size;
 
113
                        }
 
114
#if QT_VERSION >= 0x040000
 
115
                        str = QString::fromUtf16(unicode, size);
 
116
#else
 
117
                        str.setUnicodeCodes(unicode, size);
 
118
#endif
 
119
                        return true;
 
120
                }
 
121
                case Guid:
 
122
                        if (data.size() == 16) {
 
123
#if QT_VERSION >= 0x040000
 
124
                                str.clear();
 
125
#else
 
126
                                str.truncate(0);
 
127
#endif
 
128
                                for (int i = 0; i < 16; ++i) {
 
129
                                        if (i == 4 || i == 6 || i == 8 || i == 10) {
 
130
                                                str += '-';
 
131
                                        }
 
132
                                        unsigned char c = (unsigned char)data[i];
 
133
                                        unsigned char d = c >> 4;
 
134
                                        str += d >= 10 ? d - 10 + 'A' : d + '0';
 
135
                                        d = c & 0x0f;
 
136
                                        str += d >= 10 ? d - 10 + 'A' : d + '0';
 
137
                                }
 
138
                                return true;
 
139
                        }
 
140
                        break;
 
141
                case DWord:
 
142
                        if (data.size() == 4) {
 
143
                                ulong num = 0;
 
144
                                for (int i = 3; i >= 0; --i) {
 
145
                                        num <<= 8;
 
146
                                        num |= static_cast<unsigned char>(data[i]);
 
147
                                }
 
148
                                str.setNum(num);
 
149
                                return true;
 
150
                        }
 
151
                        break;
 
152
                case Binary:
 
153
                case Unknown:
 
154
                default:
 
155
                        ;
 
156
        }
 
157
        return false;
 
158
}
 
159
 
 
160
/**
 
161
 * Convert attribute data string to byte array.
 
162
 *
 
163
 * @param str  string representation of data
 
164
 * @param data result data
 
165
 *
 
166
 * @return true if ok.
 
167
 */
 
168
bool AttributeData::toByteArray(const QString& str, QByteArray& data)
 
169
{
 
170
        switch (m_type) {
 
171
                case Utf16: {
 
172
#if QT_VERSION >= 0x040000
 
173
                        const ushort* unicode = str.utf16();
 
174
#else
 
175
                        const ushort* unicode = str.ucs2();
 
176
#endif
 
177
                        QCM_duplicate(data, reinterpret_cast<const char*>(unicode),
 
178
                                      (str.length() + 1) * 2);
 
179
                        return true;
 
180
                }
 
181
                case Guid: {
 
182
                        QString hexStr(str.QCM_toUpper());
 
183
                        hexStr.remove('-');
 
184
                        if (hexStr.length() == 32) {
 
185
                                unsigned char buf[16];
 
186
                                unsigned char* bufPtr = buf;
 
187
                                for (int i = 0; i < 32;) {
 
188
#if QT_VERSION >= 0x040000
 
189
                                        unsigned char h = (unsigned char)hexStr[i++].toLatin1();
 
190
                                        unsigned char l = (unsigned char)hexStr[i++].toLatin1();
 
191
#else
 
192
                                        unsigned char h = (unsigned char)hexStr[i++].latin1();
 
193
                                        unsigned char l = (unsigned char)hexStr[i++].latin1();
 
194
#endif
 
195
                                        if (!((h >= '0' && h <= '9') || (h >= 'A' && h <= 'F')) ||
 
196
                                                        !((l >= '0' && l <= '9') || (l >= 'A' && l <= 'F'))) {
 
197
                                                return false;
 
198
                                        }
 
199
                                        *bufPtr++ = ((h >= 'A' ? h + 10 - 'A' : h - '0') << 4) |
 
200
                                          (l >= 'A' ? l + 10 - 'A' : l - '0');
 
201
                                }
 
202
                                QCM_duplicate(data, reinterpret_cast<char*>(buf), 16);
 
203
                                return true;
 
204
                        }
 
205
                        break;
 
206
                }
 
207
                case DWord: {
 
208
                        bool ok;
 
209
                        ulong num = str.toULong(&ok);
 
210
                        if (ok) {
 
211
                                data.resize(4);
 
212
                                for (int i = 0; i < 4; ++i) {
 
213
                                        data[i] = num & 0xff;
 
214
                                        num >>= 8;
 
215
                                }
 
216
                                return true;
 
217
                        }
 
218
                        break;
 
219
                }
 
220
                case Binary:
 
221
                case Unknown:
 
222
                default:
 
223
                        ;
 
224
        }
 
225
        return false;
 
226
}
 
227
 
 
228
/**
 
229
 * Check if a string represents a hexadecimal number, i.e.
 
230
 * contains only characters 0..9, A..F.
 
231
 *
 
232
 * @param str string to check
 
233
 * @param lastAllowedLetter last allowed character (normally 'F')
 
234
 * @param additionalChars additional allowed characters
 
235
 *
 
236
 * @return true if string has hex format.
 
237
 */
 
238
bool AttributeData::isHexString(const QString& str, char lastAllowedLetter,
 
239
                                const QString additionalChars)
 
240
{
 
241
        if (str.isEmpty()) {
 
242
                return false;
 
243
        }
 
244
        for (int i = 0; i < static_cast<int>(str.length()); ++i) {
 
245
#if QT_VERSION >= 0x040000
 
246
                char c = str[i].toLatin1();
 
247
#else
 
248
                char c = str[i].latin1();
 
249
#endif
 
250
                if (!((c >= '0' && c <= '9') || (c >= 'A' && c <= lastAllowedLetter) ||
 
251
                                        additionalChars.QCM_indexOf(c) != -1)) {
 
252
                        return false;
 
253
                }
 
254
        }
 
255
        return true;
 
256
}