~ubuntu-branches/ubuntu/quantal/recoll/quantal

« back to all changes in this revision

Viewing changes to internfile/internfile.cpp

  • Committer: Package Import Robot
  • Author(s): Kartik Mistry
  • Date: 2012-03-27 12:15:51 UTC
  • mfrom: (1.3.8)
  • Revision ID: package-import@ubuntu.com-20120327121551-nmntidzpehudushy
Tags: 1.17.1-1
* New upstream release.
* Enable Python module resulting into new binary: python-recoll.
* debian/control:
  + Updated Build-Deps: libqtwebkit-dev, python-all-dev.
  + Added python-recoll binary.
  + Updated Standards-Version to 3.9.3
* debian/rules:
  + Build Python module by default.
* debian/recoll.menu, debian/python-recoll.install, debian/recoll.install:
  + Changes for new binary package.
* debian/copyright:
  + Updated to copyright-format 1.0
  + Updated upstream and Debian copyright.
  + Fixed unicode.org/copyright.html URL.

Show diffs side-by-side

added added

removed removed

Lines of Context:
32
32
using namespace std;
33
33
#endif /* NO_NAMESPACES */
34
34
 
 
35
#include "cstr.h"
35
36
#include "internfile.h"
36
37
#include "rcldoc.h"
37
38
#include "mimetype.h"
51
52
#include "pxattr.h"
52
53
#endif // RCL_USE_XATTR
53
54
 
54
 
static const string cstr_stxtplain("text/plain");
55
55
 
56
56
// The internal path element separator. This can't be the same as the rcldb 
57
57
// file to ipath separator : "|"
206
206
    // Indexing by udi makes things easier (because they sometimes get a temp 
207
207
    // as input
208
208
    string udi;
209
 
    make_udi(f, "", udi);
 
209
    make_udi(f, cstr_null, udi);
210
210
 
211
211
    cnf->setKeyDir(path_getfather(m_fn));
212
212
 
239
239
            l_mime = *imime;
240
240
    }
241
241
 
 
242
    size_t docsize = stp->st_size;
 
243
 
242
244
    if (!l_mime.empty()) {
243
245
        // Has mime: check for a compressed file. If so, create a
244
246
        // temporary uncompressed file, and rerun the mime type
255
257
                LOGDEB1(("FileInterner:: after ucomp: m_tdir %s, tfile %s\n", 
256
258
                         m_tdir.dirname(), m_tfile.c_str()));
257
259
                m_fn = m_tfile;
258
 
                // Note: still using the original file's stat. right ?
259
 
                l_mime = mimetype(m_fn, stp, m_cfg, usfci);
 
260
                // Stat the uncompressed file, mainly to get the size
 
261
                struct stat ucstat;
 
262
                if (stat(m_fn.c_str(), &ucstat) != 0) {
 
263
                    LOGERR(("FileInterner: can't stat the uncompressed file"
 
264
                            "[%s] errno %d\n", m_fn.c_str(), errno));
 
265
                    return;
 
266
                } else {
 
267
                    docsize = ucstat.st_size;
 
268
                }
 
269
                l_mime = mimetype(m_fn, &ucstat, m_cfg, usfci);
260
270
                if (l_mime.empty() && imime)
261
271
                    l_mime = *imime;
262
272
            } else {
294
304
    reapXAttrs(f);
295
305
#endif //RCL_USE_XATTR
296
306
 
 
307
    df->set_docsize(docsize);
297
308
    if (!df->set_document_file(m_fn)) {
298
309
        LOGERR(("FileInterner:: error converting %s\n", m_fn.c_str()));
299
310
        return;
335
346
                            m_forPreview ? "view" : "index");
336
347
 
337
348
    bool setres = false;
 
349
    df->set_docsize(data.length());
338
350
    if (df->is_data_input_ok(Dijon::Filter::DOCUMENT_STRING)) {
339
351
        setres = df->set_document_string(data);
340
352
    } else if (df->is_data_input_ok(Dijon::Filter::DOCUMENT_DATA)) {
366
378
    m_handlers.reserve(MAXHANDLERS);
367
379
    for (unsigned int i = 0; i < MAXHANDLERS; i++)
368
380
        m_tmpflgs[i] = false;
369
 
    m_targetMType = cstr_stxtplain;
 
381
    m_targetMType = cstr_textplain;
370
382
}
371
383
 
372
 
// We used a single beagle cache object to access beagle data. We protect it 
 
384
// We use a single beagle cache object to access beagle data. We protect it 
373
385
// against multiple thread access.
374
386
static PTMutexInit o_beagler_mutex;
375
387
 
391
403
    // and use some kind of backstore object factory next time we add a 
392
404
    // backend (if ever). 
393
405
    string backend;
394
 
    map<string, string>::const_iterator it;
395
 
    if ((it = idoc.meta.find(Rcl::Doc::keybcknd)) != idoc.meta.end())
396
 
        backend = it->second;
 
406
    idoc.getmeta(Rcl::Doc::keybcknd, &backend);
397
407
    
398
408
    if (backend.empty() || !backend.compare("FS")) {
399
409
        // Filesystem document. Intern from file.
400
410
        // The url has to be like file://
401
 
        if (idoc.url.find("file://") != 0) {
 
411
        if (idoc.url.find(cstr_fileu) != 0) {
402
412
            LOGERR(("FileInterner: FS backend and non fs url: [%s]\n",
403
413
                    idoc.url.c_str()));
404
414
            return;
412
422
        }
413
423
        init(fn, &st, cnf, flags, &idoc.mimetype);
414
424
    } else if (!backend.compare("BGL")) {
 
425
        string udi;
 
426
        if (!idoc.getmeta(Rcl::Doc::keyudi, &udi) || udi.empty()) {
 
427
            LOGERR(("FileInterner:: no udi in idoc\n"));
 
428
            return;
 
429
        }
 
430
 
415
431
        string data;
416
432
        Rcl::Doc dotdoc;
417
 
        map<string,string>::const_iterator it = 
418
 
            idoc.meta.find(Rcl::Doc::keyudi);
419
 
        if (it == idoc.meta.end() || it->second.empty()) {
420
 
            LOGERR(("FileInterner:: no udi in idoc\n"));
421
 
            return;
422
 
        }
423
 
        string udi = it->second;
424
 
 
425
433
        {
426
434
            PTMutexLocker locker(o_beagler_mutex);
427
435
            // Retrieve from our webcache (beagle data). The beagler
445
453
    }
446
454
}
447
455
 
 
456
#include "fsindexer.h"
 
457
bool FileInterner::makesig(const Rcl::Doc& idoc, string& sig)
 
458
{
 
459
    if (idoc.url.empty()) {
 
460
        LOGERR(("FileInterner::makesig:: no url!\n"));
 
461
        return false;
 
462
    }
 
463
    string backend;
 
464
    idoc.getmeta(Rcl::Doc::keybcknd, &backend);
 
465
    
 
466
    if (backend.empty() || !backend.compare("FS")) {
 
467
        if (idoc.url.find(cstr_fileu) != 0) {
 
468
            LOGERR(("FileInterner: FS backend and non fs url: [%s]\n",
 
469
                    idoc.url.c_str()));
 
470
            return false;
 
471
        }
 
472
        string fn = idoc.url.substr(7, string::npos);
 
473
        struct stat st;
 
474
        if (stat(fn.c_str(), &st) < 0) {
 
475
            LOGERR(("FileInterner:: cannot access document file: [%s]\n",
 
476
                    fn.c_str()));
 
477
            return false;
 
478
        }
 
479
        FsIndexer::makesig(&st, sig);
 
480
        return true;
 
481
    } else if (!backend.compare("BGL")) {
 
482
        // Bgl sigs are empty
 
483
        sig.clear();
 
484
        return true;
 
485
    } else {
 
486
        LOGERR(("FileInterner:: unknown backend: [%s]\n", backend.c_str()));
 
487
        return false;
 
488
    }
 
489
    return false;
 
490
}
 
491
 
448
492
FileInterner::~FileInterner()
449
493
{
450
494
    tmpcleanup();
547
591
    }
548
592
}
549
593
 
 
594
void FileInterner::getMissingFromDescription(FIMissingStore *st, const string& in)
 
595
{
 
596
    if (st == 0)
 
597
        return;
 
598
 
 
599
    // The "missing" file is text. Each line defines a missing filter
 
600
    // and the list of mime types actually encountered that needed it (see method
 
601
    // getMissingDescription())
 
602
 
 
603
    vector<string> lines;
 
604
    stringToTokens(in, lines, "\n");
 
605
 
 
606
    for (vector<string>::const_iterator it = lines.begin();
 
607
         it != lines.end(); it++) {
 
608
        // Lines from the file are like: 
 
609
        //
 
610
        // filter name string (mime1 mime2) 
 
611
        //
 
612
        // We can't be too sure that there will never be a parenthesis
 
613
        // inside the filter string as this comes from the filter
 
614
        // itself. The list part is safer, so we start from the end.
 
615
        const string& line = *it;
 
616
        string::size_type lastopen = line.find_last_of("(");
 
617
        if (lastopen == string::npos)
 
618
            continue;
 
619
        string::size_type lastclose = line.find_last_of(")");
 
620
        if (lastclose == string::npos || lastclose <= lastopen + 1)
 
621
            continue;
 
622
        string smtypes = line.substr(lastopen+1, lastclose - lastopen - 1);
 
623
        vector<string> mtypes;
 
624
        stringToTokens(smtypes, mtypes);
 
625
        string filter = line.substr(0, lastopen);
 
626
        trimstring(filter);
 
627
        if (filter.empty())
 
628
            continue;
 
629
 
 
630
        st->m_missingExternal.insert(filter);
 
631
        for (vector<string>::const_iterator itt = mtypes.begin(); 
 
632
             itt != mtypes.end(); itt++) {
 
633
            st->m_typesForMissing[filter].insert(*itt);
 
634
        }
 
635
    }
 
636
}
 
637
 
550
638
// Helper for extracting a value from a map.
551
639
static inline bool getKeyValue(const map<string, string>& docdata, 
552
640
                               const string& key, string& value)
562
650
    return false;
563
651
}
564
652
 
565
 
// These defs are for the Dijon meta array. Rcl::Doc predefined field
566
 
// names are used where appropriate. In some cases, Rcl::Doc names are
567
 
// used inside the Dijon metadata (ex: origcharset)
568
 
static const string cstr_keyau("author");
569
 
static const string cstr_keycs("charset");
570
 
static const string cstr_keyct("content");
571
 
static const string cstr_keyds("description");
572
 
static const string cstr_keyfn("filename");
573
 
static const string cstr_keymd("modificationdate");
574
 
static const string cstr_keymt("mimetype");
575
 
static const string cstr_keytt("title");
576
 
 
577
653
bool FileInterner::dijontorcl(Rcl::Doc& doc)
578
654
{
579
655
    Dijon::Filter *df = m_handlers.back();
586
662
 
587
663
    for (map<string,string>::const_iterator it = docdata.begin(); 
588
664
         it != docdata.end(); it++) {
589
 
        if (it->first == cstr_keyct) {
 
665
        if (it->first == cstr_dj_keycontent) {
590
666
            doc.text = it->second;
591
 
        } else if (it->first == cstr_keymd) {
 
667
            if (doc.fbytes.empty()) {
 
668
                // It's normally set by walking the filter stack, in
 
669
                // collectIpathAndMt, which was called before us.  It
 
670
                // can happen that the doc size is still empty at this
 
671
                // point if the last container filter is directly
 
672
                // returning text/plain content, so that there is no
 
673
                // ipath-less filter at the top
 
674
                char cbuf[30];
 
675
                sprintf(cbuf, "%d", int(doc.text.length()));
 
676
                doc.fbytes = cbuf;
 
677
            }
 
678
        } else if (it->first == cstr_dj_keymd) {
592
679
            doc.dmtime = it->second;
593
 
        } else if (it->first == Rcl::Doc::keyoc) {
 
680
        } else if (it->first == cstr_dj_keyorigcharset) {
594
681
            doc.origcharset = it->second;
595
 
        } else if (it->first == cstr_keymt || it->first == cstr_keycs) {
 
682
        } else if (it->first == cstr_dj_keymt || 
 
683
                   it->first == cstr_dj_keycharset) {
596
684
            // don't need/want these.
597
685
        } else {
598
686
            doc.meta[it->first] = it->second;
599
687
        }
600
688
    }
601
 
    if (doc.meta[Rcl::Doc::keyabs].empty() && !doc.meta[cstr_keyds].empty()) {
602
 
        doc.meta[Rcl::Doc::keyabs] = doc.meta[cstr_keyds];
603
 
        doc.meta.erase(cstr_keyds);
 
689
    if (doc.meta[Rcl::Doc::keyabs].empty() && 
 
690
        !doc.meta[cstr_dj_keyds].empty()) {
 
691
        doc.meta[Rcl::Doc::keyabs] = doc.meta[cstr_dj_keyds];
 
692
        doc.meta.erase(cstr_dj_keyds);
604
693
    }
605
694
    return true;
606
695
}
607
696
 
608
697
// Collect the ipath from the current path in the document tree.
609
 
// While we're at it, we also set the mimetype and filename, which are special 
610
 
// properties: we want to get them from the topmost doc
611
 
// with an ipath, not the last one which is usually text/plain
612
 
// We also set the author and modification time from the last doc
613
 
// which has them.
 
698
// While we're at it, we also set the mimetype and filename,
 
699
// which are special properties: we want to get them from the topmost
 
700
// doc with an ipath, not the last one which is usually text/plain We
 
701
// also set the author and modification time from the last doc which
 
702
// has them.
 
703
//
 
704
// The docsize is fetched from the first element without an ipath
 
705
// (first non container). If the last element directly returns
 
706
// text/plain so that there is no ipath-less element, the value will
 
707
// be set in dijontorcl(). 
 
708
// 
 
709
// The whole thing is a bit messy but it's not obvious how it should
 
710
// be cleaned up as the "inheritance" rules inside the stack are
 
711
// actually complicated.
614
712
void FileInterner::collectIpathAndMT(Rcl::Doc& doc) const
615
713
{
616
714
    LOGDEB2(("FileInterner::collectIpathAndMT\n"));
632
730
    for (vector<Dijon::Filter*>::const_iterator hit = m_handlers.begin();
633
731
         hit != m_handlers.end(); hit++) {
634
732
        const map<string, string>& docdata = (*hit)->get_meta_data();
635
 
        if (getKeyValue(docdata, "ipath", ipathel)) {
 
733
        if (getKeyValue(docdata, cstr_dj_keyipath, ipathel)) {
636
734
            if (!ipathel.empty()) {
637
735
                // We have a non-empty ipath
638
736
                hasipath = true;
639
 
                getKeyValue(docdata, cstr_keymt, doc.mimetype);
640
 
                getKeyValue(docdata, cstr_keyfn, doc.utf8fn);
 
737
                getKeyValue(docdata, cstr_dj_keymt, doc.mimetype);
 
738
                getKeyValue(docdata, cstr_dj_keyfn, doc.utf8fn);
 
739
            } else {
 
740
                if (doc.fbytes.empty())
 
741
                    getKeyValue(docdata, cstr_dj_keydocsize, doc.fbytes);
641
742
            }
642
743
            doc.ipath += colon_hide(ipathel) + cstr_isep;
643
744
        } else {
 
745
            if (doc.fbytes.empty())
 
746
                getKeyValue(docdata, cstr_dj_keydocsize, doc.fbytes);
644
747
            doc.ipath += cstr_isep;
645
748
        }
646
 
        getKeyValue(docdata, cstr_keyau, doc.meta[Rcl::Doc::keyau]);
647
 
        getKeyValue(docdata, cstr_keymd, doc.dmtime);
 
749
        getKeyValue(docdata, cstr_dj_keyauthor, doc.meta[Rcl::Doc::keyau]);
 
750
        getKeyValue(docdata, cstr_dj_keymd, doc.dmtime);
648
751
    }
649
752
 
650
753
    // Trim empty tail elements in ipath.
682
785
{
683
786
    const map<string, string>& docdata = m_handlers.back()->get_meta_data();
684
787
    string charset, mimetype;
685
 
    getKeyValue(docdata, cstr_keycs, charset);
686
 
    getKeyValue(docdata, cstr_keymt, mimetype);
 
788
    getKeyValue(docdata, cstr_dj_keycharset, charset);
 
789
    getKeyValue(docdata, cstr_dj_keymt, mimetype);
687
790
 
688
791
    LOGDEB(("FileInterner::addHandler: next_doc is %s\n", mimetype.c_str()));
689
792
 
691
794
    // general), we're done decoding. If we hit text/plain, we're done
692
795
    // in any case
693
796
    if (!stringicmp(mimetype, m_targetMType) || 
694
 
        !stringicmp(mimetype, cstr_stxtplain)) {
 
797
        !stringicmp(mimetype, cstr_textplain)) {
695
798
        m_reachedMType = mimetype;
696
799
        LOGDEB1(("FileInterner::addHandler: target reached\n"));
697
800
        return ADD_BREAK;
724
827
    const string *txt = &ns;
725
828
    {
726
829
        map<string,string>::const_iterator it;
727
 
        it = docdata.find(cstr_keyct);
 
830
        it = docdata.find(cstr_dj_keycontent);
728
831
        if (it != docdata.end())
729
832
            txt = &it->second;
730
833
    }
731
834
    bool setres = false;
 
835
    newflt->set_docsize(txt->length());
732
836
    if (newflt->is_data_input_ok(Dijon::Filter::DOCUMENT_STRING)) {
733
837
        setres = newflt->set_document_string(*txt);
734
838
    } else if (newflt->is_data_input_ok(Dijon::Filter::DOCUMENT_DATA)) {