00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include <klaola.h>
00021 #include <kdebug.h>
00022
00023 const int KLaola::s_area = 30510;
00024
00025 KLaola::KLaola(const myFile &file) {
00026
00027 smallBlockDepot=0L;
00028 bigBlockDepot=0L;
00029 smallBlockFile=0L;
00030 bbd_list=0L;
00031 ok=true;
00032 m_nodeList.setAutoDelete(true);
00033
00034
00035 if( (file.length % 0x200) != 0 ) {
00036 kdError(s_area) << "KLaola::KLaola(): Invalid file size!" << endl;
00037 ok=false;
00038 }
00039 if(ok) {
00040 m_file=file;
00041 maxblock = file.length / 0x200 - 2;
00042 maxSblock=0;
00043
00044 if(!parseHeader())
00045 ok=false;
00046 if(ok) {
00047 readBigBlockDepot();
00048 readSmallBlockDepot();
00049 readSmallBlockFile();
00050 readRootList();
00051 }
00052 }
00053 m_currentPath.clear();
00054 testIt();
00055
00056
00057 m_currentPath.clear();
00058 if ( !m_nodeTree.isEmpty() )
00059 m_currentPath.append(m_nodeTree.getFirst()->getFirst()->node);
00060 }
00061
00062 KLaola::~KLaola() {
00063
00064 delete [] bigBlockDepot;
00065 bigBlockDepot=0L;
00066 delete [] smallBlockDepot;
00067 smallBlockDepot=0L;
00068 delete [] smallBlockFile;
00069 smallBlockFile=0L;
00070 delete [] bbd_list;
00071 bbd_list=0L;
00072 }
00073
00074
00075 void KLaola::createTree(const int handle, const short index) {
00076
00077 Node *node = dynamic_cast<Node *>(m_nodeList.at(handle));
00078 SubTree *subtree;
00079
00080 TreeNode *tree=new TreeNode;
00081 tree->node=node;
00082 tree->subtree=-1;
00083
00084
00085
00086
00087
00088
00089
00090 if(node->prevHandle!=-1) {
00091
00092 createTree(node->prevHandle, index);
00093 }
00094 if(node->dirHandle!=-1) {
00095 subtree=new SubTree;
00096 subtree->setAutoDelete(true);
00097 m_nodeTree.append(subtree);
00098 tree->subtree=m_nodeTree.at();
00099
00100 createTree(node->dirHandle, tree->subtree);
00101 }
00102 subtree=m_nodeTree.at(index);
00103
00104 subtree->append(tree);
00105 if(node->nextHandle!=-1) {
00106
00107 createTree(node->nextHandle, index);
00108 }
00109 }
00110
00111 const KLaola::NodeList KLaola::currentPath() const {
00112 return m_currentPath;
00113 }
00114
00115 bool KLaola::enterDir(const OLENode *dirHandle) {
00116
00117 NodeList nodes;
00118 Node *node;
00119
00120 if(ok) {
00121 nodes = parseCurrentDir();
00122 for (node = dynamic_cast<Node *>(nodes.first()); node; node = dynamic_cast<Node *>(nodes.next()))
00123 {
00124 if(node->m_handle==dirHandle->handle() && node->isDirectory() && !node->deadDir) {
00125 m_currentPath.append(node);
00126 return true;
00127 }
00128 }
00129 }
00130 return false;
00131 }
00132
00133 const KLaola::NodeList KLaola::find(const QString &name, bool onlyCurrentDir) {
00134
00135 OLENode *node;
00136 NodeList ret;
00137 int i=0;
00138
00139 if(ok) {
00140 if(!onlyCurrentDir) {
00141 for(node=m_nodeList.first(); node; node=m_nodeList.next()) {
00142 if(node->name()==name) {
00143 ret.append(node);
00144 ++i;
00145 }
00146 }
00147 }
00148 else {
00149 NodeList list=parseCurrentDir();
00150
00151 for(node=list.first(); node; node=list.next()) {
00152 if(node->name()==name) {
00153 ret.append(node);
00154 ++i;
00155 }
00156 }
00157 }
00158 }
00159 return ret;
00160 }
00161
00162 bool KLaola::leaveDir() {
00163
00164 if (ok) {
00165 return m_currentPath.removeLast();
00166 }
00167 return false;
00168 }
00169
00170 int KLaola::nextBigBlock(int pos) const
00171 {
00172
00173 int x=pos*4;
00174 return ( (bigBlockDepot[x+3] << 24) + (bigBlockDepot[x+2] << 16) +
00175 (bigBlockDepot[x+1] << 8) + bigBlockDepot[x] );
00176 }
00177
00178 int KLaola::nextSmallBlock(int pos) const
00179 {
00180
00181 if(smallBlockDepot) {
00182 int x=pos*4;
00183 return ( (smallBlockDepot[x+3] << 24) + (smallBlockDepot[x+2] << 16) +
00184 (smallBlockDepot[x+1] << 8) + smallBlockDepot[x] );
00185 }
00186 else
00187 return -2;
00188 }
00189
00190 bool KLaola::parseHeader() {
00191
00192 if(qstrncmp((const char*)m_file.data,"\xd0\xcf\x11\xe0\xa1\xb1\x1a\xe1",8 )!=0) {
00193 kdError(s_area) << "KLaola::parseHeader(): Invalid file format (unexpected id in header)!" << endl;
00194 return false;
00195 }
00196
00197 num_of_bbd_blocks=read32(0x2c);
00198 root_startblock=read32(0x30);
00199 sbd_startblock=read32(0x3c);
00200
00201 if (num_of_bbd_blocks >= 0x800000) {
00202 kdError(s_area) << "KLaola::parseHeader(): Too many bbd blocks found in header!" << endl;
00203 return false;
00204 }
00205 bbd_list=new unsigned int[num_of_bbd_blocks];
00206
00207 unsigned int i, j;
00208 for(i=0, j=0; i<num_of_bbd_blocks; ++i, j=j+4) {
00209 bbd_list[i]=read32(0x4c+j);
00210 if (bbd_list[i] >= (0x800000 - 1)) {
00211 kdError(s_area) << "KLaola::parseHeader(): bbd " << i << " offset (" << bbd_list[i] << ") too large" << endl;
00212 return false;
00213 }
00214 }
00215 return true;
00216 }
00217
00218 KLaola::NodeList KLaola::parseCurrentDir() {
00219
00220 Node *node;
00221 SubTree *subtree;
00222 NodeList nodeList;
00223 TreeNode *treeNode;
00224 unsigned int i;
00225 bool found;
00226
00227 if(ok) {
00228 for(i=0, subtree=m_nodeTree.first(); i<m_currentPath.count(); ++i) {
00229 treeNode=subtree->first();
00230 found=false;
00231 do {
00232 if(treeNode==0) {
00233 kdError(s_area) << "KLaola::parseCurrentDir(): path seems to be corrupted!" << endl;
00234 ok=false;
00235 }
00236 else if(treeNode->node->handle()==m_currentPath.at(i)->handle() && treeNode->subtree!=-1) {
00237 found=true;
00238 }
00239 else
00240 treeNode=subtree->next();
00241 } while(!found && ok);
00242 subtree=m_nodeTree.at(treeNode->subtree);
00243 }
00244 }
00245 if(ok) {
00246 for(treeNode=subtree->first(); treeNode!=0; treeNode=subtree->next()) {
00247 node=new Node(*treeNode->node);
00248 node->deadDir = (node->dirHandle==-1 && node->isDirectory());
00249
00250 if (node->deadDir)
00251 kdDebug(s_area) << "ignoring: " << node->describe() << " is empty" << endl;
00252 else
00253 nodeList.append(node);
00254 }
00255 }
00256 return nodeList;
00257 }
00258
00259 KLaola::NodeList KLaola::parseRootDir() {
00260
00261 NodeList tmpNodeList;
00262 NodeList tmp;
00263
00264 if(ok) {
00265 tmp=m_currentPath;
00266 m_currentPath.clear();
00267 m_currentPath.append(m_nodeTree.getFirst()->getFirst()->node);
00268 tmpNodeList=parseCurrentDir();
00269 m_currentPath=tmp;
00270 }
00271 return tmpNodeList;
00272 }
00273
00274 unsigned char KLaola::read8(int i) const
00275 {
00276 return m_file.data[i];
00277 }
00278
00279 unsigned short KLaola::read16(int i) const
00280 {
00281 return ( (m_file.data[i+1] << 8) + m_file.data[i] );
00282 }
00283
00284 unsigned int KLaola::read32(int i) const
00285 {
00286 return ( (read16(i+2) << 16) + read16(i) );
00287 }
00288
00289 const unsigned char *KLaola::readBBStream(int start, bool setmaxSblock)
00290 {
00291
00292 int i=0, tmp;
00293 unsigned char *p=0;
00294
00295 tmp=start;
00296
00297 while(tmp!=-2 && tmp>=0 && i<0x10000 && tmp<=static_cast<int>(maxblock)) {
00298 ++i;
00299 tmp=nextBigBlock(tmp);
00300 }
00301 if(i!=0) {
00302 p=new unsigned char[i*0x200];
00303 if(setmaxSblock)
00304 maxSblock=i*8-1;
00305 i=0;
00306 tmp=start;
00307 while(tmp!=-2 && tmp>=0 && i<0x10000 && tmp<=static_cast<int>(maxblock)) {
00308 memcpy(&p[i*0x200], &m_file.data[(tmp+1)*0x200], 0x200);
00309 tmp=nextBigBlock(tmp);
00310 ++i;
00311 }
00312 }
00313 return p;
00314 }
00315
00316 const unsigned char *KLaola::readSBStream(int start) const {
00317
00318 int i=0, tmp;
00319 unsigned char *p=0;
00320
00321 tmp=start;
00322
00323 while(tmp!=-2 && tmp>=0 && i<0x10000 && tmp<=static_cast<int>(maxSblock)) {
00324 ++i;
00325 tmp=nextSmallBlock(tmp);
00326 }
00327 if(i!=0) {
00328 p=new unsigned char[i*0x40];
00329 i=0;
00330 tmp=start;
00331 while(tmp!=-2 && tmp>=0 && i<0x10000 && tmp<=static_cast<int>(maxSblock)) {
00332 memcpy(&p[i*0x40], &smallBlockFile[tmp*0x40], 0x40);
00333 tmp=nextSmallBlock(tmp);
00334 ++i;
00335 }
00336 }
00337 return p;
00338 }
00339
00340 void KLaola::readBigBlockDepot() {
00341 if (num_of_bbd_blocks >= 0x800000)
00342 return;
00343
00344 bigBlockDepot=new unsigned char[0x200*num_of_bbd_blocks];
00345 for(unsigned int i=0; i<num_of_bbd_blocks; ++i) {
00346 unsigned int offset = (bbd_list[i]+1)*0x200;
00347 if (offset > m_file.length - 0x200) {
00348
00349 memset(&bigBlockDepot[i*0x200], 0, 0x200);
00350 }
00351 else {
00352 memcpy(&bigBlockDepot[i*0x200], &m_file.data[offset], 0x200);
00353 }
00354 }
00355 }
00356
00357 void KLaola::readSmallBlockDepot() {
00358 smallBlockDepot=const_cast<unsigned char*>(readBBStream(sbd_startblock));
00359 }
00360
00361 void KLaola::readSmallBlockFile() {
00362 smallBlockFile=const_cast<unsigned char*>(readBBStream( read32( (root_startblock+1)*0x200 + 0x74), true));
00363 }
00364
00365 void KLaola::readRootList() {
00366
00367 int pos=root_startblock;
00368 int handle=0;
00369
00370 while(pos!=-2 && pos>=0 && pos<=static_cast<int>(maxblock)) {
00371 for(int i=0; i<4; ++i, ++handle)
00372 readPPSEntry((pos+1)*0x200+0x80*i, handle);
00373 pos=nextBigBlock(pos);
00374 }
00375 SubTree *subtree=new SubTree;
00376 subtree->setAutoDelete(true);
00377 m_nodeTree.append(subtree);
00378
00379 createTree(0, 0);
00380 }
00381
00382
00383 void KLaola::readPPSEntry(int pos, const int handle) {
00384
00385 int nameSize = read16(pos + 0x40);
00386
00387
00388
00389 if (nameSize)
00390 {
00391 int i;
00392 Node *node = new Node(this);
00393
00394
00395 node->m_prefix = static_cast<Prefix>(read16(pos));
00396 if (node->m_prefix <= RESERVED_LAST)
00397 {
00398 i = 1;
00399 }
00400 else
00401 {
00402 node->m_prefix = NONE;
00403 i = 0;
00404 }
00405
00406
00407 for (; i < (nameSize / 2) - 1; ++i)
00408 {
00409 QChar tmp;
00410
00411 tmp = read16(pos + 2 * i);
00412 node->m_name += tmp;
00413 }
00414 node->m_handle = handle;
00415 node->type = static_cast<NodeType>(read8(pos + 0x42));
00416 node->prevHandle = static_cast<int>(read32(pos + 0x44));
00417 node->nextHandle = static_cast<int>(read32(pos + 0x48));
00418 node->dirHandle = static_cast<int>(read32(pos + 0x4C));
00419 node->ts1s = static_cast<int>(read32(pos + 0x64));
00420 node->ts1d = static_cast<int>(read32(pos + 0x68));
00421 node->ts2s = static_cast<int>(read32(pos + 0x6C));
00422 node->ts2d = static_cast<int>(read32(pos + 0x70));
00423 node->sb = read32(pos + 0x74);
00424 node->size = read32(pos + 0x78);
00425 node->deadDir = false;
00426 m_nodeList.append(node);
00427 }
00428 }
00429
00430 myFile KLaola::stream(const OLENode *node) {
00431
00432 const Node *realNode = dynamic_cast<const Node *>(node);
00433 const unsigned char *temp;
00434 myFile ret;
00435
00436 if(ok) {
00437 if(realNode->size>=0x1000)
00438 temp = readBBStream(realNode->sb);
00439 else
00440 temp = readSBStream(realNode->sb);
00441 ret.setRawData(temp, realNode->size);
00442 }
00443 return ret;
00444 }
00445
00446 myFile KLaola::stream(unsigned handle) {
00447
00448 OLENode *node;
00449
00450 node = m_nodeList.at(handle);
00451 return stream(node);
00452 }
00453
00454 void KLaola::testIt(QString prefix)
00455 {
00456
00457 NodeList nodes;
00458 OLENode *node;
00459
00460 nodes = parseCurrentDir();
00461 for (node = nodes.first(); node; node = nodes.next())
00462 {
00463 kdDebug(s_area) << prefix + node->describe() << endl;
00464 if (node->isDirectory())
00465 {
00466 enterDir(node);
00467 testIt(prefix + " ");
00468 }
00469 }
00470 }
00471
00472
00473 QString KLaola::Node::describe() const
00474 {
00475 QString description;
00476 myFile file;
00477 unsigned i;
00478
00479 description = QString::number(m_handle) + " " +
00480 m_name + "(" +
00481 QString::number(sb) + " " +
00482 QString::number(size) + " bytes)";
00483 if (isDirectory())
00484 description += ", directory";
00485 switch (m_prefix)
00486 {
00487 case OLE_MANAGED_0:
00488 description += ", OLE_0";
00489 break;
00490 case CLSID:
00491 description += ", CLSID=";
00492 description += readClassStream();
00493 file = m_laola->stream(this);
00494 description += ", ";
00495 for (i = 16; i < file.length; i++)
00496 {
00497 description += QString::number((file.data[i] >> 4) & 0xf, 16);
00498 description += QString::number(file.data[i] & 0xf, 16);
00499 }
00500 description += ", ";
00501 for (i = 16; i < file.length; i++)
00502 {
00503 QChar tmp = file.data[i];
00504
00505 if (tmp.isPrint())
00506 description += tmp;
00507 else
00508 description += '.';
00509 }
00510 break;
00511 case OLE_MANAGED_2:
00512 description += ", OLE_2";
00513 break;
00514 case PARENT_MANAGED:
00515 description += ", parent managed";
00516 break;
00517 case STRUCTURED_STORAGE:
00518 description += ", reserved 0x" + QString::number(m_prefix, 16);
00519 break;
00520 case NONE:
00521 break;
00522 default:
00523 description += ", reserved 0x" + QString::number(m_prefix, 16);
00524 break;
00525 }
00526 return description;
00527 }
00528
00529 QString KLaola::Node::name() const
00530 {
00531 return m_name;
00532 }
00533
00534
00535 QString KLaola::Node::readClassStream() const
00536 {
00537 if (isDirectory())
00538 return QString::null;
00539 if (m_prefix == CLSID)
00540 {
00541 myFile file;
00542 unsigned i;
00543 QString clsid;
00544
00545
00546 file = m_laola->stream(this);
00547 for (i = 0; i < 4; i++)
00548 {
00549 clsid += QString::number((file.data[i] >> 4) & 0xf, 16);
00550 clsid += QString::number(file.data[i] & 0xf, 16);
00551 }
00552 clsid += '-';
00553 for (; i < 6; i++)
00554 {
00555 clsid += QString::number((file.data[i] >> 4) & 0xf, 16);
00556 clsid += QString::number(file.data[i] & 0xf, 16);
00557 }
00558 clsid += '-';
00559 for (; i < 8; i++)
00560 {
00561 clsid += QString::number((file.data[i] >> 4) & 0xf, 16);
00562 clsid += QString::number(file.data[i] & 0xf, 16);
00563 }
00564 clsid += '-';
00565 for (; i < 10; i++)
00566 {
00567 clsid += QString::number((file.data[i] >> 4) & 0xf, 16);
00568 clsid += QString::number(file.data[i] & 0xf, 16);
00569 }
00570 clsid += '-';
00571 for (; i < 16; i++)
00572 {
00573 clsid += QString::number((file.data[i] >> 4) & 0xf, 16);
00574 clsid += QString::number(file.data[i] & 0xf, 16);
00575 }
00576 return clsid;
00577 }
00578 return QString::null;
00579 }