00001 #include <stdio.h>
00002 #include <string.h>
00003 #include "Aportis.h"
00004 #include "my_list.h"
00005 #include "Bkmks.h"
00006
00007 Aportis::Aportis() : peanutfile(false) { }
00008
00009 void Aportis::dePeanut(int& ch)
00010 {
00011 if (peanutfile && ch != EOF)
00012 {
00013 unsigned char c = ch;
00014 if (peanutfile) c ^= 0xa5;
00015 ch = c;
00016 }
00017 }
00018
00019 CList<Bkmk>* Aportis::getbkmklist()
00020 {
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055 if (bCompressed != 4) return NULL;
00056 CList<Bkmk>* t = new CList<Bkmk>;
00057 unsuspend();
00058 size_t cur = ftell(fin);
00059 for (int i = 0; i < nRecs2; i++)
00060 {
00061 DWORD dwPos;
00062 fseek(fin, 0x56 + 8*i, SEEK_SET);
00063 fread(&dwPos, 4, 1, fin);
00064 dwPos = SwapLong(dwPos);
00065 fseek(fin,dwPos,SEEK_SET);
00066 unsigned char ch;
00067 fread(&ch,1,1,fin);
00068 if (ch != 241)
00069 {
00070 char name[17];
00071 name[16] = '\0';
00072 fseek(fin,dwPos,SEEK_SET);
00073 fread(name,1,16,fin);
00074 unsigned long lcn;
00075 fread(&lcn,sizeof(lcn),1,fin);
00076 lcn = SwapLong(lcn);
00077 #ifdef _UNICODE
00078 tchar tname[17];
00079 memset(tname, 0, sizeof(tname));
00080 for (int i = 0; name[i] != 0; i++)
00081 {
00082 tname[i] = name[i];
00083 }
00084 t->push_back(Bkmk(tname, NULL, lcn));
00085 #else
00086 t->push_back(Bkmk(name,lcn));
00087 #endif
00088 }
00089 }
00090 fseek(fin, cur, SEEK_SET);
00091 return t;
00092 }
00093
00094 int Aportis::OpenFile(const char *src)
00095 {
00096
00097 int ret = 0;
00098 html = false;
00099 mobiimagerec = 0;
00100 if (!Cpdb::openpdbfile(src)) return -1;
00101
00102 if (head.creator == 0x64414552
00103 || head.type == 0x74584554)
00104 {
00105 }
00106 else if (memcmp(&head.creator, "PPrs", 4) == 0 && memcmp(&head.type, "PNRd", 4) == 0)
00107 {
00108 peanutfile = true;
00109 }
00110 else if (memcmp(&head.creator, "MOBI", 4) == 0 && memcmp(&head.type, "BOOK", 4) == 0)
00111 {
00112 html = true;
00113 unsigned char vsn;
00114 fseek(fin, recordpos(0)+39, SEEK_SET);
00115 fread(&vsn, 1, sizeof(vsn), fin);
00116 qDebug("Mobi version:%x", vsn);
00117 if (vsn > 2)
00118 {
00119 fseek(fin, recordpos(0)+110, SEEK_SET);
00120 fread(&mobiimagerec, 1, sizeof(mobiimagerec), fin);
00121 mobiimagerec = ntohs(mobiimagerec)-1;
00122 }
00123 }
00124 else
00125 {
00126 return -2;
00127 }
00128
00129 nRecs2 = nRecs = SwapWord(head.recordList.numRecords) - 1;
00130
00131 struct stat _stat;
00132 stat(src,&_stat);
00133 dwLen = _stat.st_size;
00134
00135
00136
00137
00138 if (peanutfile)
00139 {
00140
00141 PeanutHeader hdr0;
00142 gotorecordnumber(0);
00143 fread(&hdr0, sizeof(hdr0), 1, fin);
00144
00145 if (hdr0.Version && 0x0200)
00146 {
00147 bCompressed = 2;
00148 }
00149 else
00150 {
00151 bCompressed = 1;
00152 }
00153 BlockSize = 4096;
00154 nRecs = SwapWord(hdr0.Records)-1;
00155 dwTLen = nRecs*BlockSize;
00156 }
00157 else
00158 {
00159 gotorecordnumber(0);
00160 tDocRecord0 hdr0;
00161 fread(&hdr0, sizeof(hdr0), 1, fin);
00162 bCompressed = SwapWord(hdr0.wVersion);
00163 if (bCompressed!=1 && bCompressed!=2 && bCompressed != 4) {
00164 qDebug("ERROR:Unrecognised compression type in Aportis:%u", bCompressed);
00165 ret = bCompressed;
00166 bCompressed = 2;
00167 }
00168 switch (bCompressed)
00169 {
00170 case 4:
00171 {
00172 dwTLen = 0;
00173 int i;
00174 for (i = 0; i < nRecs; i++)
00175 {
00176 unsigned int bs = GetBS(i);
00177 if (bs == 0) break;
00178 else dwTLen += bs;
00179 }
00180 nRecs = i;
00181 BlockSize = 0;
00182 }
00183 break;
00184 case 1:
00185 case 2:
00186 default:
00187 nRecs = SwapWord(hdr0.wNumRecs);
00188 if (mobiimagerec == 0 || mobiimagerec > nRecs2) mobiimagerec = nRecs;
00189 dwTLen = SwapLong(hdr0.dwStoryLen);
00190 BlockSize = SwapWord(hdr0.wRecSize);
00191 if (BlockSize == 0)
00192 {
00193 BlockSize = 4096;
00194 printf("WARNING: Blocksize not set in source file\n");
00195 }
00196 }
00197 }
00198
00199 qDebug("Mobi image rec:%u", mobiimagerec);
00200
00201
00202
00203 currentrec = 0;
00204 cbptr = 0;
00205 outptr = 0;
00206 refreshbuffer();
00207 if (!html)
00208 {
00209 int c;
00210 char htmltag[] = "<HTML>";
00211 char *p = htmltag;
00212 while (1)
00213 {
00214 c = getch();
00215 char ch = *p++;
00216 if (ch == 0)
00217 {
00218 html = true;
00219 break;
00220 }
00221 if (c != ch)
00222 {
00223 html = false;
00224 break;
00225 }
00226 }
00227 currentrec = 0;
00228 cbptr = 0;
00229 outptr = 0;
00230 refreshbuffer();
00231 }
00232
00233
00234
00235
00236
00237
00238
00239 qDebug("Number of records:[%u,%u]", nRecs, nRecs2);
00240 return ret;
00241 }
00242
00243 int Aportis::getch()
00244 {
00245 if (bCompressed == 1)
00246 {
00247 if ((dwRecLen == 0) && !refreshbuffer()) return EOF;
00248 else
00249 {
00250 unsuspend();
00251 int c = getc(fin);
00252 dePeanut(c);
00253 dwRecLen--;
00254 currentpos++;
00255 return c;
00256 }
00257 }
00258 if (outptr != cbptr)
00259 {
00260 currentpos++;
00261 return (circbuf[outptr = (outptr + 1) % 2048]);
00262 }
00263 if ((dwRecLen == 0) && !refreshbuffer()) return EOF;
00264 currentpos++;
00265 int c;
00266
00267
00268 unsuspend();
00269 c = getc(fin);
00270 dePeanut(c);
00271 dwRecLen--;
00272
00273
00274
00275 if (c == 0)
00276 {
00277 circbuf[outptr = cbptr = (cbptr+1)%2048] = c;
00278 return c;
00279 }
00280 else if (c >= 0x09 && c <= 0x7F)
00281 {
00282 circbuf[outptr = cbptr = (cbptr+1)%2048] = c;
00283 return c;
00284 }
00285 else if (c >= 0x01 && c <= 0x08)
00286 {
00287 dwRecLen -= c;
00288 while(c--)
00289 {
00290 int c = getc(fin);
00291 dePeanut(c);
00292 circbuf[cbptr = (cbptr+1)%2048] = c;
00293 }
00294 return circbuf[outptr = (outptr+1)%2048];
00295 }
00296 else if (c >= 0x80 && c <= 0xBF)
00297 {
00298 int m,n;
00299 c <<= 8;
00300 int c1 = getc(fin);
00301 dePeanut(c1);
00302 c += c1;
00303 dwRecLen--;
00304 m = (c & 0x3FFF) >> COUNT_BITS;
00305 n = c & ((1<<COUNT_BITS) - 1);
00306 n += 3;
00307 while (n--)
00308 {
00309 cbptr = (cbptr+1)%2048;
00310 circbuf[cbptr] = circbuf[(cbptr+2048-m)%2048];
00311 }
00312 return circbuf[outptr = (outptr+1)%2048];
00313 }
00314 else if (c >= 0xC0 && c <= 0xFF)
00315 {
00316 circbuf[cbptr = (cbptr+1)%2048] = ' ';
00317 circbuf[cbptr = (cbptr+1)%2048] = c^0x80;
00318 return circbuf[outptr = (outptr+1)%2048];
00319 }
00320 }
00321
00322 unsigned int Aportis::GetBS(unsigned int bn)
00323 {
00324 DWORD dwPos;
00325 WORD fs;
00326 unsuspend();
00327 fseek(fin, 0x56 + 8*bn, SEEK_SET);
00328 fread(&dwPos, 4, 1, fin);
00329 dwPos = SwapLong(dwPos);
00330 fseek(fin,dwPos,SEEK_SET);
00331
00332
00333 unsigned char ch;
00334 fread(&ch,1,1,fin);
00335 if (ch == 241)
00336 {
00337 fread(&fs,sizeof(fs),1,fin);
00338 fs = SwapWord(fs);
00339 }
00340 else
00341 fs = 0;
00342 return fs;
00343 }
00344
00345 unsigned int Aportis::locate()
00346 {
00347 if (bCompressed == 4)
00348 {
00349 unsuspend();
00350 size_t cur = ftell(fin);
00351 unsigned int clen = 0;
00352 for (unsigned int i = 0; i < currentrec-1; i++)
00353 {
00354 unsigned int bs = GetBS(i);
00355 if (bs == 0) break;
00356 clen += bs;
00357 }
00358 fseek(fin,cur,SEEK_SET);
00359 return clen+currentpos;
00360 }
00361 else
00362 return (currentrec-1)*BlockSize+currentpos;
00363 }
00364
00365 void Aportis::locate(unsigned int n)
00366 {
00367 unsigned int offset;
00368
00369 switch (bCompressed)
00370 {
00371 case 4:
00372 {
00373 DWORD clen = 0;
00374 offset = n;
00375 unsigned int i;
00376 for (i = 0; i < nRecs; i++)
00377 {
00378 unsigned int bs = GetBS(i);
00379 if (bs == 0) break;
00380 clen += bs;
00381 if (clen > n) break;
00382 offset = n - clen;
00383 }
00384 currentrec = i;
00385 }
00386 break;
00387 case 1:
00388 case 2:
00389 default:
00390 currentrec = n / BlockSize;
00391 offset = n % BlockSize;
00392 }
00393
00394 outptr = cbptr;
00395 refreshbuffer();
00396 while (currentpos < offset && getch() != EOF);
00397 }
00398
00399 bool Aportis::refreshbuffer()
00400 {
00401 if (currentrec < nRecs)
00402 {
00403 dwRecLen = recordlength(currentrec+1);
00404 gotorecordnumber(currentrec+1);
00405 if (bCompressed == 4)
00406 {
00407 unsigned char t[3];
00408 unsuspend();
00409 fread(t,1,3,fin);
00410 if (t[0] != 241)
00411 {
00412 printf("You shouldn't be here!\n");
00413 return false;
00414 }
00415 dwRecLen -= 3;
00416 }
00417
00418
00419
00420
00421
00422
00423
00424
00425 currentpos = 0;
00426 currentrec++;
00427 return true;
00428 }
00429 else {
00430 return false;
00431 }
00432 }
00433
00434 #include <qimage.h>
00435
00436 QImage* Aportis::getPicture(unsigned long tgt)
00437 {
00438 unsuspend();
00439 unsigned short tgtrec = tgt+mobiimagerec;
00440 if (tgtrec > nRecs2) return NULL;
00441 size_t cur = ftell(fin);
00442 unsigned short reclen = recordlength(tgtrec);
00443 gotorecordnumber(tgtrec);
00444 UInt8* imgbuffer = new UInt8[reclen];
00445 fread(imgbuffer, 1, reclen, fin);
00446 QByteArray arr;
00447 arr.assign((const char*)imgbuffer, reclen);
00448
00449 QImage* qimage = new QImage(arr);
00450 fseek(fin, cur, SEEK_SET);
00451
00452 return qimage;
00453 }
00454
00455 #ifndef __STATIC
00456 extern "C"
00457 {
00458 CExpander* newcodec() { return new Aportis; }
00459 }
00460 #endif