~neon/juk/master

« back to all changes in this revision

Viewing changes to mpris2/zbase32.cpp

  • Committer: Michael Pyne
  • Date: 2012-04-16 01:53:04 UTC
  • Revision ID: git-v1:54c6db81c2fe09999b9953249dce839f5c7a0a66
Initial MPRIS2 support.

Eike Hein has kindly donated a working Mpris2 adaptor with instructions
on how to integrate into JuK, so I've done so.

This is just at the "compiles and links" stage and the track ID will
give a lot of weirdness due to the strictness of the D-Bus Object Path
name spec.

The reason we don't just use an identifier for a track is that the
"primary key" JuK uses is the canonical file name. JuK has no internal
RDBMS or anything similar where primary keys would be assigned. Because
of this we encode track IDs using z-Base-32 so they will not violate the
D-Bus spec.

Thanks to Eike for the large code contribution and integration support!

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/***************************************************************************
 
2
    begin                : Sun Apr 16 14:23:12 EST 2012
 
3
    copyright            : (C) 2012 by Michael Pyne
 
4
    email                : mpyne@kde.org
 
5
***************************************************************************/
 
6
 
 
7
/***************************************************************************
 
8
 *                                                                         *
 
9
 *   This program is free software; you can redistribute it and/or modify  *
 
10
 *   it under the terms of the GNU General Public License as published by  *
 
11
 *   the Free Software Foundation; either version 2 of the License, or     *
 
12
 *   (at your option) any later version.                                   *
 
13
 *                                                                         *
 
14
 ***************************************************************************/
 
15
 
 
16
 
 
17
#include <QtDebug>
 
18
#include <QtCore/QLatin1String>
 
19
#include <QtCore/QString>
 
20
#include <QtCore/QByteArray>
 
21
#include <QtCore/QFile>
 
22
 
 
23
#include <kdemacros.h>
 
24
 
 
25
// The 0-based position of an entry in this table indicates its value.
 
26
static const char zBase32EncodingTable [] = "ybndrfg8ejkmcpqxot1uwisza345h769";
 
27
 
 
28
// 8 5-bit entries for 40-bits total
 
29
static const int ZBASE32_PARTIAL_BUFFER_SIZE = 8;
 
30
 
 
31
static int locateCharacterInTable(const QChar ch)
 
32
{
 
33
    for (int i = 0; i < 32; ++i) {
 
34
        if (zBase32EncodingTable[i] == ch) {
 
35
            return i;
 
36
        }
 
37
    }
 
38
 
 
39
    return -1;
 
40
}
 
41
 
 
42
// @p len is the number of **destination** items to utilize!
 
43
static void zBase32DecodeBufferIntoBuffer(
 
44
        unsigned char *destination,
 
45
        const unsigned char *source,
 
46
        int destinationLength)
 
47
{
 
48
    // Each item in source buffer is already masked to only take 5 bits.
 
49
    // We need to pick the appropriate bits of each item and place in
 
50
    // the right spot.
 
51
 
 
52
    // 00000000-11111111-22222222-33333333-44444444 destination
 
53
    // 01234567-01234567-01234567-01234567-01234567
 
54
    // 00000111-11222223-33334444-45555566-66677777 source
 
55
 
 
56
    switch (destinationLength) {
 
57
        case 5: destination[4] = ((source[6] & 0x07) << 5) | source[7];
 
58
                // fallthrough
 
59
        case 4: destination[3] = ((source[4] & 0x01) << 7) | (source[5] << 2) | ((source[6]) >> 3);
 
60
                // fallthrough
 
61
        case 3: destination[2] = ((source[3] & 0x0F) << 4) | (source[4] >> 1);
 
62
                // fallthrough
 
63
        case 2: destination[1] = ((source[1] & 0x03) << 6) | (source[2] << 1) | (source[3] >> 4);
 
64
                // fallthrough
 
65
        case 1: destination[0] = (source[0] << 3) | (source[1] >> 2);
 
66
            break;
 
67
        default:
 
68
            return;
 
69
    }
 
70
}
 
71
 
 
72
// Returns number of decoded bytes that are left from the given remainder
 
73
// length of source characters. This means the remainder length should be
 
74
// between 1 and 7 inclusive.
 
75
static int zBase32BytesAffectedFromSource(int sourceRemainderLength)
 
76
{
 
77
    switch (sourceRemainderLength) {
 
78
        case 7: return 5;
 
79
        case 6: return 4;
 
80
        case 5: return 4;
 
81
        case 4: return 3;
 
82
        case 3: return 2;
 
83
        case 2: return 2;
 
84
        case 1: return 1;
 
85
        case 0: return 0;
 
86
        default: return -1;
 
87
    }
 
88
}
 
89
 
 
90
QByteArray zBase32DecodeData(const QByteArray &str)
 
91
{
 
92
    QByteArray result;
 
93
    unsigned char buffer[ZBASE32_PARTIAL_BUFFER_SIZE] = { 0 };
 
94
    int strSize = str.size();
 
95
    int runLength = (strSize / ZBASE32_PARTIAL_BUFFER_SIZE) * ZBASE32_PARTIAL_BUFFER_SIZE;
 
96
    int remainder = strSize - runLength;
 
97
 
 
98
    result.resize(strSize / ZBASE32_PARTIAL_BUFFER_SIZE * 5 + zBase32BytesAffectedFromSource(remainder));
 
99
    int destinationPointer = 0;
 
100
 
 
101
    for (int i = 0; i < runLength; ++i) {
 
102
        int pos = locateCharacterInTable(str[i]);
 
103
        if (KDE_ISUNLIKELY(pos < 0)) {
 
104
            return QByteArray();
 
105
        }
 
106
 
 
107
        if (zBase32EncodingTable[pos] != str[i]) {
 
108
            return QByteArray();
 
109
        }
 
110
 
 
111
        buffer[i % ZBASE32_PARTIAL_BUFFER_SIZE] = pos;
 
112
 
 
113
        if (((i + 1) % ZBASE32_PARTIAL_BUFFER_SIZE) == 0) {
 
114
            // End of row, compress
 
115
            unsigned char *encodedData = reinterpret_cast<unsigned char *>(result.data()) + destinationPointer;
 
116
 
 
117
            zBase32DecodeBufferIntoBuffer(encodedData, buffer, 5);
 
118
            destinationPointer += 5;
 
119
 
 
120
            for (int j = 0; j < ZBASE32_PARTIAL_BUFFER_SIZE; j++) {
 
121
                buffer[j] = 0;
 
122
            }
 
123
        }
 
124
    }
 
125
 
 
126
    // Complete weird remainder. buffer should have already been cleared
 
127
    // above.
 
128
    for (int i = 0; i < remainder; ++i) {
 
129
        int pos = locateCharacterInTable(str[i + runLength]);
 
130
        if (KDE_ISUNLIKELY(pos < 0)) {
 
131
            return QByteArray();
 
132
        }
 
133
 
 
134
        buffer[i] = pos;
 
135
    }
 
136
 
 
137
    zBase32DecodeBufferIntoBuffer(
 
138
            reinterpret_cast<unsigned char *>(result.data()) + destinationPointer,
 
139
            buffer,
 
140
            zBase32BytesAffectedFromSource(remainder));
 
141
 
 
142
    return result;
 
143
}
 
144
 
 
145
// Returns the number of destination entries used to encode the given bytes
 
146
// of the source.
 
147
static int zBase32EncodeBufferIntoBuffer(
 
148
        unsigned char *destination,
 
149
        const unsigned char *source,
 
150
        int sourceLength)
 
151
{
 
152
    // Each item in destination buffer must be masked to only take 5 bits.
 
153
    // We need to pick the appropriate bits of each item and place in
 
154
    // the right spot.
 
155
 
 
156
    // 00000000-11111111-22222222-33333333-44444444 source
 
157
    // 01234567-01234567-01234567-01234567-01234567
 
158
    // 00000111-11222223-33334444-45555566-66677777 destination
 
159
 
 
160
    for (int i = 0; i < ZBASE32_PARTIAL_BUFFER_SIZE; ++i) {
 
161
        destination[i] = 0;
 
162
    }
 
163
 
 
164
    int entriesUsed = 0;
 
165
 
 
166
    switch (sourceLength) {
 
167
        case 5:
 
168
            entriesUsed = 8;
 
169
            destination[7] = source[4] & 0x1f;
 
170
                // fallthrough
 
171
        case 4:
 
172
            entriesUsed = entriesUsed ? entriesUsed : 7;
 
173
            destination[6] = ((source[4] & 0xe0) >> 5) | ((source[3] & 0x03) << 3);
 
174
            destination[5] = ((source[3] & 0x7c) >> 2);
 
175
                // fallthrough
 
176
        case 3:
 
177
            entriesUsed = entriesUsed ? entriesUsed : 5;
 
178
            destination[4] = ((source[2] & 0x0f) << 1) | ((source[3] & 0x80) >> 7);
 
179
                // fallthrough
 
180
        case 2:
 
181
            entriesUsed = entriesUsed ? entriesUsed : 4;
 
182
            destination[3] = ((source[1] & 0x01) << 4) | ((source[2] & 0xf0) >> 4);
 
183
            destination[2] = ((source[1] & 0x3e) >> 1);
 
184
                // fallthrough
 
185
        case 1:
 
186
            entriesUsed = entriesUsed ? entriesUsed : 2;
 
187
            destination[1] = ((source[0] & 0x07) << 2) | ((source[1] & 0xc0) >> 6);
 
188
            destination[0] = ((source[0] & 0xf8) >> 3);
 
189
            break;
 
190
        default:
 
191
            return -1;
 
192
    }
 
193
 
 
194
    // We still have binary values, encode them to legible items from the table
 
195
    for (int i = 0; i < entriesUsed; ++i) {
 
196
        destination[i] = zBase32EncodingTable[destination[i]];
 
197
    }
 
198
 
 
199
    return entriesUsed;
 
200
}
 
201
 
 
202
QByteArray zBase32EncodeData(const QByteArray &data)
 
203
{
 
204
    QByteArray result;
 
205
    result.reserve((data.size() * 8 / 5) + 1);
 
206
 
 
207
    int runLength = data.size() / 5 * 5;
 
208
    int remainder = data.size() - runLength;
 
209
 
 
210
    unsigned char buffer[ZBASE32_PARTIAL_BUFFER_SIZE] = { 0 };
 
211
 
 
212
    for (int i = 0; i < runLength; i += 5) {
 
213
        zBase32EncodeBufferIntoBuffer(buffer, reinterpret_cast<unsigned const char *>(data.constData()) + i, 5);
 
214
        result.append(reinterpret_cast<const char *>(buffer), 8);
 
215
    }
 
216
 
 
217
    int entriesUsed = zBase32EncodeBufferIntoBuffer(
 
218
        buffer,
 
219
        reinterpret_cast<const unsigned char *>(data.constData()) + runLength,
 
220
        remainder);
 
221
 
 
222
    result.append(reinterpret_cast<const char *>(buffer), entriesUsed);
 
223
    result.resize((runLength / 5 * 8) + entriesUsed);
 
224
 
 
225
    return result;
 
226
}