ACSMDownloader

ACSMDownloader Git Source Tree

Root/include/rmsdk_wrapper.h

Source at commit 1f582f55f35b3a6898ced8d388e043ee81168bd1 created 4 months 21 days ago.
By Grégory Soutadé, First clean working version
1#ifndef RMSDK_WRAPPER_H
2#define RMSDK_WRAPPER_H
3
4#include <iostream>
5#include <sys/types.h>
6#include <sys/stat.h>
7#include <fcntl.h>
8#include <unistd.h>
9#include <string.h>
10
11#include <adept.h>
12#include <librmsdk.h>
13#include <dpdrm.h>
14#include <dpio.h>
15#include <dpdev.h>
16#include <dpnet.h>
17
18#include <QNetworkAccessManager>
19#include <QNetworkReply>
20#include <QCoreApplication>
21#include <QFile>
22
23#include <log.h>
24
25class MockDevice;
26
27class MockDRMProcessorClient: public dpdrm::DRMProcessorClient
28{
29public:
30 MockDRMProcessorClient(const char* output):
31output(output), sourceName(0), targetName(0)
32 {}
33
34 virtual ~MockDRMProcessorClient() {
35if (sourceName) free(sourceName);
36if (targetName) free(targetName);
37 }
38
39 virtual void mockclientfn0() {LOG_FUNC();}
40 virtual void mockclientfn1() {LOG_FUNC();}
41
42 virtual void workflowFinished(unsigned int workflow, dp::String& str)
43 {
44LOG(DEBUG, "Workflow finished " << workflow << " " << str.utf8());
45
46if (workflow & WORKFLOW_FULFILLMENT)
47{
48 dp::list<dpdrm::FulfillmentItem> list = processor->getFulfillmentItems();
49 if (list.length())
50 {
51// Downloaded file
52uft::String url = list[0]->getDownloadURL().uft();
53int slashIdx = url.lastIndexOf("/", url.length());
54/*
55 Extract name without extension from url like :
56 http://acs.tea-ebook.com/media/a2192551-57b1-4de7-b19c-2e7f4579b91f.epub
57*/
58uft::String tmpName = url.substr(slashIdx+1, url.length()-5);
59uft::String fullTmpName = uft::String("/tmp/") + tmpName;
60
61sourceName = strdup(fullTmpName.utf8());
62
63dp::String title = getMetadata(list[0], "title");
64uft::String fullName;
65
66if (output)
67 targetName = strdup(output);
68else if (title.utf8())
69{
70 uft::String fullName = title.uft() + ".epub";
71 targetName = fullName.utf8();
72
73 if (!targetName || !strlen(targetName))
74targetName = (char*) "output.epub";
75 else
76targetName = strdup(targetName);
77}
78else
79{
80 uft::String fullName = tmpName + ".epub";
81 targetName = fullName.utf8();
82
83 if (!targetName || !strlen(targetName))
84targetName = (char*) "output.epub";
85 else
86targetName = strdup(targetName);
87}
88 }
89}
90 }
91
92 virtual void mockclientfn3(void) {LOG_FUNC();}
93 virtual void mockclientfn4(void) {LOG_FUNC();}
94 virtual void mockclientfn5(void) {LOG_FUNC();}
95 virtual void workflowProgress(unsigned int workflow, dp::String& title, double progress)
96 {
97LOG(WARN, "Progress " << workflow << " " << title.utf8() << " " << progress << " %%");
98if (workflow & WORKFLOW_DOWNLOAD)
99{
100 if (progress == 100.0)
101 {
102// Copy tmp file into destination
103QFile file(targetName);
104if (file.exists())
105{
106 LOG(DEBUG, "Removing existant target");
107 file.remove();
108}
109
110if (QFile::rename(sourceName, targetName))
111{
112 LOG(INFO, "Created \"" << targetName << "\"");
113}
114else
115{
116 LOG(ERROR, "Unable to copy \"" << sourceName << "\" into \"" << targetName << "\"");
117}
118 }
119}
120 }
121 virtual void workflowError(unsigned int workflow, dp::String& error)
122 {
123LOG(ERROR, "Workflow error " << workflow << " " << error.utf8());
124 }
125
126 void setProcessor(adept::DRMProcessorImpl* processor)
127 { this->processor = processor; }
128
129private:
130 adept::DRMProcessorImpl* processor;
131 const char* output;
132 char* sourceName;
133 char* targetName;
134 /*
135 Try to get metadata with :
136 * DC. + name
137 * dc. + name
138 * name
139 */
140 dp::String getMetadata(dp::ref<dpdrm::FulfillmentItem> item, const char* name)
141 {
142uft::String newName = uft::String("DC.") + name;
143
144dp::String res = item->getMetadata(newName.utf8());
145if (res.utf8())
146 return res;
147
148newName = uft::String("dc.") + name;
149res = item->getMetadata(newName);
150if (res.utf8())
151 return res;
152
153return item->getMetadata(name);
154 }
155};
156
157class MockPartition : public dpio::Partition
158{
159public:
160 MockPartition(dpdev::Device* device, int index,
161 dp::String name, dp::String type,
162 dp::String rootPath, dp::String docPath,
163 dp::String tempPath):
164device(device), index(index), name(name), type(type),
165rootPath(rootPath), docPath(docPath),
166tempPath(tempPath)
167 {
168
169 }
170
171 virtual void mockpartitionfn0() {LOG_FUNC();}
172 virtual void* getOptionalInterface( const char * name ) {LOG_FUNC(); return 0;}
173 virtual dpdev::Device * getDevice() {LOG_FUNC(); return device;}
174 virtual int getIndex() {LOG_FUNC(); return index;}
175 virtual dp::String getPartitionName() {LOG_FUNC(); return name;}
176 virtual dp::String getPartitionType() {LOG_FUNC(); return type;}
177 virtual dp::String getRootURL() {LOG_FUNC(); return rootPath;}
178 virtual dp::String getDocumentFolderURL() {LOG_FUNC(); return docPath;}
179 virtual dp::String getTemporaryFolderURL() {LOG_FUNC(); return tempPath;}
180
181 virtual dpio::Stream * readFile( const dp::String& path, dpio::StreamClient* client, unsigned int p2 )
182 {
183LOG_FUNC();
184return 0;
185 }
186 virtual void createUniqueFile( const dp::String& path, const dp::String& p2, dp::Callback* callback )
187 {
188LOG_FUNC();
189 }
190 virtual void writeFile( const dp::String& path, dpio::Stream* streamData, dp::Callback* callback )
191 {
192LOG_FUNC();
193QFile file(path.utf8());
194
195dp::Data data = streamData->readSynchronousStream(streamData);
196
197LOG(DEBUG, "Read from stream " << data.length() << " bytes");
198bool ret = file.open(QIODevice::WriteOnly|QIODevice::Truncate);
199if (!ret)
200{
201 LOG(ERROR, "Unable to open file " << path.utf8());
202 return;
203}
204else
205 LOG(WARN, "Write file " << path.utf8());
206
207file.write((const char*)data.data(), data.length());
208file.close();
209
210callback->reportProgress(100.0);
211 }
212
213 virtual void removeFile( const dp::String& path, dp::Callback* callback )
214 {
215LOG_FUNC();
216 }
217
218private:
219 dpdev::Device * device;
220 int index;
221 dp::String name;
222 dp::String type;
223 dp::String rootPath;
224 dp::String docPath;
225 dp::String tempPath;
226};
227
228class MockProvider : public dpdev::DeviceProvider
229{
230
231public:
232 MockProvider(dpdev::Device* device):device(device) {}
233 void getIdentifier() {LOG_FUNC();}
234 virtual int getIndex() {LOG_FUNC(); return 0;}
235 virtual dpdev::Device* getDevice( int index ){
236LOG_FUNC();
237if (index == 0)
238 return device;
239else
240 return 0;
241 }
242 virtual bool mount(const dp::String& root, const dp::String& name, const dp::String& type)
243 {
244LOG(INFO, "Mount " << root.utf8() << " " << name.utf8() << " " << type.utf8());
245return true;
246 }
247 virtual bool unmount(const dp::String& root)
248 {
249LOG_FUNC();
250return true;
251 }
252 virtual void mockproviderfn0(void) {LOG_FUNC();}
253 virtual void mockproviderfn1(void) {LOG_FUNC();}
254 virtual void mockproviderfn2(void) {LOG_FUNC();}
255 virtual void mockproviderfn3(void) {LOG_FUNC();}
256
257private:
258 dpdev::Device* device;
259};
260
261
262class MockDevice : public dpdev::Device, public mdom::DocumentHandler
263{
264public:
265 MockDevice(dpdrm::DRMProcessorClient* processorClient, char* deviceFile, char* activationFile, char* devkeyFile) :deviceProvider(0), processorClient(processorClient)
266 {
267partition = new MockPartition(this, 0, "root", "Fixed", "/tmp", "/tmp", "/tmp");
268
269readFile(activationFile, &activationRecord, &activationRecordLength);
270
271/* Default values */
272dp::setVersionInfo("hobbes", "9.2.38311");
273dp::setVersionInfo("clientVersion", "Boo Reader");
274dp::setVersionInfo("clientOS", "Linux 2.6.32 armv7l");
275dp::setVersionInfo("clientLocale", "fr");
276
277unsigned char* deviceXML;
278readFile(deviceFile, &deviceXML, 0, true);
279
280wisdom = adept::parseXML((const char*)deviceXML);
281mdom::Node node = wisdom->getRoot();
282node.walkBranch(this);
283
284// deviceXML is already freed...
285// delete[] deviceXML;
286
287readFile(devkeyFile, &devkey, &devkeyLength);
288 }
289
290 void setProvider(dpdev::DeviceProvider* deviceProvider)
291 {this->deviceProvider = deviceProvider;}
292
293 void setProcessorClient(dpdrm::DRMProcessorClient* processorClient)
294 {this->processorClient = processorClient;}
295
296 virtual void * getOptionalInterface( const char * name ) {LOG_FUNC(); return 0;}
297 virtual void prepareDeviceKey() {LOG_FUNC();}
298 virtual dpdev::DeviceProvider* getProvider() {LOG_FUNC(); return deviceProvider;}
299 virtual int getIndex() {LOG_FUNC(); return 0;}
300 virtual dp::String getDeviceName() {LOG_FUNC(); return deviceName;}
301 virtual dp::Data getDeviceKey() {LOG_FUNC(); return dp::Data(devkey, devkeyLength);}
302 virtual dp::String getDeviceType() {LOG_FUNC(); return deviceType;}
303 virtual dp::Data getFingerprint() {LOG_FUNC(); return fingerprint;}
304 virtual dp::Data getActivationRecord() {LOG_FUNC(); return dp::Data(activationRecord, activationRecordLength);}
305 virtual void setActivationRecord(const dp::Data& data);
306 virtual dpio::Partition* getPartition(int index) {LOG_FUNC(); return partition;}
307 virtual dp::String getVersionInfo(const dp::String& name);
308 virtual bool isTrusted() {LOG_FUNC();return false;};
309
310 /* mdom::DocumentHandler */
311 virtual bool characters(uft::Value const&) {return true;}
312 virtual bool comment(uft::Value const&) {return true;}
313 virtual bool endDocument() {return true;}
314 virtual bool endElement(uft::Value const& p0, uft::Value const& p1, uft::Value const& p2) {return true;}
315 virtual bool endEntity(uft::Value const&) {return true;}
316 virtual bool processingInstruction(uft::Value const&, uft::Value const&) {return true;}
317 virtual bool startDocument() {return true;}
318 virtual bool startElement(mdom::Node const& node, uft::Value const& xmlns, uft::Value const& element, uft::Value const& ns, mdom::NameValueIterator* attributesIterator) {
319if (!element.isNull() && element.isString())
320{
321 int i=0;
322 char* name = element.toString().c_str();
323 uft::String value = adept::getChildValue(node, 3);
324
325 if (!strcmp(name, "deviceClass"))
326deviceClass = dp::String(value.utf8());
327 else if (!strcmp(name, "deviceSerial"))
328deviceSerial = dp::String(value.utf8());
329 else if (!strcmp(name, "deviceName"))
330deviceName = dp::String(value.utf8());
331 else if (!strcmp(name, "deviceType"))
332deviceType = dp::String(value.utf8());
333 // <adept:version name="hobbes" value="9.2.38311">
334 else if (!strcmp(name, "version"))
335 {
336/* Hardcode decode because p0 is a structure */
337uft::Value p0, p1;
338attributesIterator->next(&p0, &p1);
339char* attrName = p1.toString().c_str();
340attributesIterator->next(&p0, &p1);
341char* attrValue = p1.toString().c_str();
342if (attrName && attrValue)
343 dp::setVersionInfo(attrName, attrValue);
344i++;
345
346 }
347 else if (!strcmp(name, "fingerprint"))
348 {
349unsigned char rawFingerprint[32];
350int res = dp::decodeBase64(value.c_str(), rawFingerprint, sizeof(rawFingerprint));
351fingerprint = dp::Data(rawFingerprint, res);
352 }
353 i++;
354}
355return true;
356 }
357 virtual bool startEntity(uft::Value const&) {return true;}
358
359 static int readFile(char* filePath, unsigned char** res, int* length = 0, bool addFinalZero=false)
360 {
361int _length, fd;
362QFile file(filePath);
363
364if (!length) length = &_length;
365
366if (addFinalZero)
367 *res = new unsigned char[file.size()+1];
368else
369 *res = new unsigned char[file.size()];
370fd = open(filePath, O_RDONLY);
371*length = read(fd, *res, file.size());
372close (fd);
373if (*length > 0 && addFinalZero)
374{
375 (*res)[*length] = 0;
376 *length += 1;
377}
378
379return *length;
380 }
381
382private:
383 dpdev::DeviceProvider* deviceProvider;
384 dpdrm::DRMProcessorClient* processorClient;
385 unsigned char *activationRecord;
386 int activationRecordLength;
387 unsigned char *devkey;
388 int devkeyLength;
389 dpio::Partition* partition;
390 dp::String deviceSerial;
391 dp::String deviceClass;
392 dp::String deviceName;
393 dp::String deviceType;
394 dp::Data fingerprint;
395 MetroWisDOM* wisdom;
396};
397
398void MockDevice::setActivationRecord( const dp::Data& data ) {
399 LOG_FUNC();
400 delete[] activationRecord;
401 activationRecordLength = data.length();
402 activationRecord = new unsigned char[activationRecordLength];
403 memcpy(activationRecord, data.data(), activationRecordLength);
404 LOG(DEBUG, "New activation record :" << std::endl << activationRecord);
405}
406
407dp::String MockDevice::getVersionInfo( const dp::String& name ) {
408 LOG_FUNC();
409 LOG(DEBUG, ">>> " << name.utf8());
410 dp::String res = dp::getVersionInfo(name);
411 return res;
412}
413
414class MockStream : public dpio::Stream {
415public:
416 MockStream(const dp::String& method, const dp::String& url, dpio::StreamClient* client,
417 dpio::Stream* postData):
418method(method), url(url), client(client)
419 {
420
421LOG(DEBUG, "New stream " << method.utf8() << " " << url.utf8());
422
423QNetworkRequest request(QUrl(url.utf8()));
424request.setRawHeader("Accept", "*/*");
425request.setRawHeader("Content-Type", "application/vnd.adobe.adept+xml");
426request.setRawHeader("User-Agent", "book2png");
427if (postData)
428{
429 dp::Data data = dpio::Stream::readSynchronousStream(postData);
430 LOG(DEBUG, "Len " << data.length());
431 LOG(DEBUG, "data " << data.data());
432 reply = networkManager.post(request, QByteArray((const char*)data.data(), data.length()));
433}
434else
435{
436 reply = networkManager.get(request);
437}
438 }
439
440 virtual void release() {LOG_FUNC();}
441 virtual void setStreamClient(dpio::StreamClient * client)
442 {
443LOG_FUNC();
444this->client = client;
445 }
446 virtual int getCapabilities()
447 {
448LOG_FUNC();
449return 1;
450 }
451 virtual void requestInfo()
452 {
453LOG_FUNC();
454
455QCoreApplication* app = QCoreApplication::instance();
456networkManager.moveToThread(app->thread());
457while (!reply->isFinished())
458 app->processEvents();
459requestBytes(0, -1);
460 }
461
462 virtual void requestBytes(unsigned int offset, unsigned int len)
463 {
464LOG_FUNC();
465
466LOG(DEBUG, "Offset " << offset << ", Len " << len);
467
468if (!client)
469{
470 LOG(ERROR, "Error, No client");
471 return;
472}
473
474size_t bytes = (size_t)reply->bytesAvailable();
475QByteArray _replyData = reply->readAll();
476const unsigned char* replyData = (const unsigned char*)_replyData.constData();
477LOG(DEBUG, "Reply " << bytes << " bytes");
478
479if (reply->hasRawHeader("Content-Type"))
480 client->propertyReady("Content-Type", reply->rawHeader("Content-Type").constData());
481if (reply->hasRawHeader("Content-Length"))
482 client->propertyReady("Content-Length", reply->rawHeader("Content-Length").constData());
483client->totalLengthReady(bytes);
484client->bytesReady(0, dp::Data(replyData, bytes), true);
485 }
486
487 virtual void reportWriteError(const dp::String& error)
488 {
489LOG_FUNC();
490 }
491
492 virtual void adjustModifiedStream(unsigned int offset, unsigned int len, void* param0, dpio::StreamClient * client)
493 {
494LOG_FUNC();
495setStreamClient(client);
496requestBytes(offset, len);
497 }
498 virtual void streamfn2() {LOG_FUNC();}
499 virtual void streamfn3() {LOG_FUNC();}
500 virtual void streamfn4() {LOG_FUNC();}
501
502private:
503 dp::String method;
504 dp::String url;
505 dpio::StreamClient *client;
506 QNetworkAccessManager networkManager;
507 QNetworkReply *reply;
508};
509
510class MockNetProvider : public dpnet::NetProvider
511{
512 virtual void netfn0() {LOG_FUNC();}
513 virtual void netfn1() {LOG_FUNC();}
514 virtual void netfn2() {LOG_FUNC();}
515 virtual void netfn3() {LOG_FUNC();}
516 virtual dpio::Stream * netfn4(dp::String& method, dp::String& url, adept::UrlLoader<adept::DRMProcessorImpl>* client, unsigned int param1, dpio::Stream* stream) {
517LOG_FUNC();
518return new MockStream(method, url, (dpio::StreamClient*)(client), stream);
519 }
520 virtual void netfn5() {LOG_FUNC();}
521 virtual void netfn6() {LOG_FUNC();}
522};
523
524#endif

Archive Download this file

Branches