~ubuntu-branches/ubuntu/edgy/djvulibre/edgy

« back to all changes in this revision

Viewing changes to libdjvu/ddjvuapi.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Sebastien Bacher
  • Date: 2006-07-03 11:38:23 UTC
  • mfrom: (1.1.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20060703113823-un2te7742kk04c63
Tags: 3.5.17-1ubuntu1
* Sync with Debian
* debian/rules:
  - use dh_iconcache.

Show diffs side-by-side

added added

removed removed

Lines of Context:
52
52
//C- +------------------------------------------------------------------
53
53
//C- */ 
54
54
 
55
 
/* $Id: ddjvuapi.cpp,v 1.41 2005/09/12 21:31:06 leonb Exp $ */
 
55
/* $Id: ddjvuapi.cpp,v 1.66 2006/05/07 12:33:03 leonb Exp $ */
56
56
 
57
57
#ifdef HAVE_CONFIG_H
58
58
# include "config.h"
104
104
#include "DjVuImage.h"
105
105
#include "DjVuFileCache.h"
106
106
#include "DjVuDocument.h"
 
107
#include "DjVuDumpHelper.h"
107
108
#include "DjVuMessageLite.h"
108
109
#include "DjVuMessage.h"
109
110
#include "DjVmNav.h"
110
111
#include "DjVuText.h"
111
112
#include "DjVuAnno.h"
112
113
#include "DjVuToPS.h"
 
114
#include "DjVmDir.h"
 
115
#include "DjVmDir0.h"
 
116
#include "DjVuNavDir.h"
 
117
#include "DjVmDoc.h"
113
118
 
114
119
 
115
120
#include "miniexp.h"
154
159
  GMonitor monitor;
155
160
  GP<DjVuFileCache> cache;
156
161
  GPList<ddjvu_message_p> mlist;
 
162
  GP<ddjvu_message_p> mpeeked;
157
163
  int uniqueid;
158
164
  ddjvu_message_callback_t callbackfun;
159
165
  void *callbackarg;
165
171
  void *userdata;
166
172
  GP<ddjvu_context_s> myctx;
167
173
  GP<ddjvu_document_s> mydoc;
168
 
  virtual ~ddjvu_job_s();
 
174
  bool released;
 
175
  ddjvu_job_s();
169
176
  // virtual port functions:
170
177
  virtual bool inherits(const GUTF8String&);
171
178
  virtual bool notify_error(const DjVuPort*, const GUTF8String&);  
180
187
{
181
188
  GP<DjVuDocument> doc;
182
189
  GPMap<int,DataPool> streams;
 
190
  GMap<GUTF8String, int> names;
183
191
  GPMap<int,ddjvu_thumbnail_p> thumbnails;
184
192
  int streamid;
185
193
  bool fileflag;
195
203
  virtual bool notify_error(const DjVuPort*, const GUTF8String&);  
196
204
  virtual bool notify_status(const DjVuPort*, const GUTF8String&);
197
205
  virtual void notify_doc_flags_changed(const DjVuDocument*, long, long);
198
 
  virtual void notify_file_flags_changed(const DjVuFile*, long, long);
199
206
  virtual GP<DataPool> request_data(const DjVuPort*, const GURL&);
 
207
  static void callback(void *);
200
208
};
201
209
 
202
210
struct DJVUNS ddjvu_page_s : public ddjvu_job_s
205
213
  ddjvu_job_t *job;
206
214
  bool pageinfoflag;            // was the first m_pageinfo sent?
207
215
  bool pagedoneflag;            // was the final m_pageinfo sent?
208
 
  bool redisplayflag;           // did we receive a redisplay notification?
209
216
  // virtual job functions:
210
217
  virtual ddjvu_status_t status();
211
218
  virtual void release();
336
343
  G_TRY
337
344
    {
338
345
      setlocale(LC_ALL,"");
339
 
      DjVuMessage::use_language();
340
346
      if (programname)
341
347
        djvu_programname(programname);
 
348
      DjVuMessage::use_language();
 
349
      DjVuMessageLite::create();
342
350
      ctx = new ddjvu_context_s;
343
351
      ref(ctx);
344
352
      ctx->uniqueid = 0;
346
354
      ctx->callbackarg = 0;
347
355
      ctx->cache = DjVuFileCache::create();
348
356
    }
349
 
  G_CATCH(ex)
 
357
  G_CATCH_ALL
350
358
    {
351
359
      if (ctx)
352
360
        unref(ctx);
364
372
      if (ctx)
365
373
        unref(ctx);
366
374
    }
367
 
  G_CATCH(ex)
 
375
  G_CATCH_ALL
368
376
    {
369
377
    }
370
378
  G_ENDCATCH;
381
389
         GP<ddjvu_message_p> msg = 0)
382
390
{
383
391
  ddjvu_context_t *ctx = head.context;
384
 
  if (! msg) msg = new ddjvu_message_p;
385
 
  msg->p.m_any = head;
386
 
  {
387
 
    GMonitorLock lock(&ctx->monitor);
388
 
    ctx->mlist.append(msg);
389
 
    ctx->monitor.broadcast();
390
 
  }
 
392
  if (! msg) 
 
393
    msg = new ddjvu_message_p;
 
394
  msg->p.m_any = head; 
 
395
  GMonitorLock lock(&ctx->monitor);
 
396
  if ((head.document && head.document->released) ||
 
397
      (head.page && head.page->released) ||
 
398
      (head.job && head.job->released) )
 
399
    return;
391
400
  if (ctx->callbackfun) 
392
401
    (*ctx->callbackfun)(ctx, ctx->callbackarg);
 
402
  ctx->mlist.append(msg);
 
403
  ctx->monitor.broadcast();
393
404
}
394
405
 
395
406
static void
400
411
    {
401
412
      msg_push(head, msg);
402
413
    }
403
 
  G_CATCH(ex)
 
414
  G_CATCH_ALL
404
415
    {
405
416
    }
406
417
  G_ENDCATCH;
423
434
      p->tmp1 = DjVuMessageLite::LookUpUTF8(message);
424
435
      p->p.m_error.message = (const char*)(p->tmp1);
425
436
    }
426
 
  G_CATCH(ex) 
 
437
  G_CATCH_ALL 
427
438
    {
428
439
    } 
429
440
  G_ENDCATCH;
450
461
      p->p.m_error.filename = ex.get_file();
451
462
      p->p.m_error.lineno = ex.get_line();
452
463
    }
453
 
  G_CATCH(exc) 
 
464
  G_CATCH_ALL 
454
465
    {
455
466
    } 
456
467
  G_ENDCATCH;
471
482
 
472
483
 
473
484
#ifdef __GNUG__
474
 
# define ERROR(x, m) \
 
485
# define ERROR1(x, m) \
475
486
    msg_push_nothrow(xhead(DDJVU_ERROR,x),\
476
487
                     msg_prep_error(m,__func__,__FILE__,__LINE__))
477
488
#else
478
 
# define ERROR(x, m) \
 
489
# define ERROR1(x, m) \
479
490
    msg_push_nothrow(xhead(DDJVU_ERROR,x),\
480
491
                     msg_prep_error(m,0,__FILE__,__LINE__))
481
492
#endif
496
507
    }
497
508
  G_CATCH(ex) 
498
509
    {
499
 
      ERROR(ctx, ex);
 
510
      ERROR1(ctx, ex);
500
511
    }
501
512
  G_ENDCATCH;
502
513
}
512
523
    }
513
524
  G_CATCH(ex) 
514
525
    { 
515
 
      ERROR(ctx, ex);
 
526
      ERROR1(ctx, ex);
516
527
    }
517
528
  G_ENDCATCH;
518
529
  return 0;
525
536
    {
526
537
      GMonitorLock lock(&ctx->monitor);
527
538
      if (ctx->cache)
528
 
        return ctx->cache->clear();
 
539
      {
 
540
        ctx->cache->clear();
 
541
        return;
 
542
      }
529
543
    }
530
544
  G_CATCH(ex)
531
545
    {
532
 
      ERROR(ctx, ex);
 
546
      ERROR1(ctx, ex);
533
547
    }
534
548
  G_ENDCATCH;
535
549
 }
538
552
// ----------------------------------------
539
553
// Jobs
540
554
 
541
 
ddjvu_job_s::~ddjvu_job_s()
 
555
ddjvu_job_s::ddjvu_job_s()
 
556
  : userdata(0), released(false)
542
557
{
543
 
  G_TRY
544
 
    {
545
 
      ddjvu_context_t *ctx = myctx;
546
 
      if (!ctx) return;
547
 
      GMonitorLock lock(&ctx->monitor);
548
 
      GPosition p = ctx->mlist;
549
 
      while (p) {
550
 
        GPosition s = p; ++p;
551
 
        if (ctx->mlist[s]->p.m_any.job == this)
552
 
          ctx->mlist.del(s);
553
 
      }
554
 
    }
555
 
  G_CATCH()
556
 
    {
557
 
    }
558
 
  G_ENDCATCH;
559
558
}
560
559
 
561
560
bool
579
578
  return true;
580
579
}
581
580
 
582
 
 
583
581
void
584
582
ddjvu_job_release(ddjvu_job_t *job)
585
583
{
589
587
        return;
590
588
      job->release();
591
589
      job->userdata = 0;
 
590
      job->released = true;
 
591
      // clean all messages
 
592
      ddjvu_context_t *ctx = job->myctx;
 
593
      if (ctx)
 
594
        {
 
595
          GMonitorLock lock(&ctx->monitor);
 
596
          GPosition p = ctx->mlist;
 
597
          while (p) 
 
598
            {
 
599
              GPosition s = p; ++p;
 
600
              if (ctx->mlist[s]->p.m_any.job == job ||
 
601
                  ctx->mlist[s]->p.m_any.document == job ||
 
602
                  ctx->mlist[s]->p.m_any.page == job )
 
603
                ctx->mlist.del(s);
 
604
            }
 
605
          // cleanup pointers in current message as well.
 
606
          if (ctx->mpeeked)
 
607
            {
 
608
              ddjvu_message_t *m = &ctx->mpeeked->p;
 
609
              if (m->m_any.job == job)       
 
610
                m->m_any.job = 0;
 
611
              if (m->m_any.document == job)
 
612
                m->m_any.document = 0;
 
613
              if (m->m_any.page == job)
 
614
                m->m_any.page = 0;
 
615
            }
 
616
        }
 
617
      // decrement reference counter
592
618
      unref(job);
593
619
    }
594
 
  G_CATCH(ex)
 
620
  G_CATCH_ALL
595
621
    {
596
622
    }
597
623
  G_ENDCATCH;
608
634
    }
609
635
  G_CATCH(ex)
610
636
    {
611
 
      ERROR(job, ex);
 
637
      ERROR1(job, ex);
612
638
    }
613
639
  G_ENDCATCH;
614
640
  return DDJVU_JOB_FAILED;
624
650
    }
625
651
  G_CATCH(ex)
626
652
    {
627
 
      ERROR(job, ex);
 
653
      ERROR1(job, ex);
628
654
    }
629
655
  G_ENDCATCH;
630
656
}
655
681
  G_TRY
656
682
    {
657
683
      GMonitorLock lock(&ctx->monitor);
 
684
      if (ctx->mpeeked)
 
685
        return &ctx->mpeeked->p;        
658
686
      GPosition p = ctx->mlist;
659
 
      if (p) 
660
 
        return &ctx->mlist[p]->p;
 
687
      if (! p)
 
688
        return 0;
 
689
      ctx->mpeeked = ctx->mlist[p];
 
690
      ctx->mlist.del(p);
 
691
      return &ctx->mpeeked->p;
661
692
    }
662
 
  G_CATCH(ex)
 
693
  G_CATCH_ALL
663
694
    {
664
695
    }
665
696
  G_ENDCATCH;
672
703
  G_TRY
673
704
    {
674
705
      GMonitorLock lock(&ctx->monitor);
 
706
      if (ctx->mpeeked)
 
707
        return &ctx->mpeeked->p;        
675
708
      while (! ctx->mlist.size())
676
709
        ctx->monitor.wait();
677
710
      GPosition p = ctx->mlist;
678
 
      if (p) 
679
 
        return &ctx->mlist[p]->p;
 
711
      if (! p)
 
712
        return 0;
 
713
      ctx->mpeeked = ctx->mlist[p];
 
714
      ctx->mlist.del(p);
 
715
      return &ctx->mpeeked->p;        
680
716
    }
681
 
  G_CATCH(ex)
 
717
  G_CATCH_ALL
682
718
    {
683
719
    }
684
720
  G_ENDCATCH;
691
727
  G_TRY
692
728
    {
693
729
      GMonitorLock lock(&ctx->monitor);
694
 
      GPosition p = ctx->mlist;
695
 
      if (p) 
696
 
        ctx->mlist.del(p);
 
730
      ctx->mpeeked = 0;
697
731
    }
698
 
  G_CATCH(ex)
 
732
  G_CATCH_ALL
699
733
    {
700
734
    }
701
735
  G_ENDCATCH;
729
763
        thumb->pool->del_trigger(ddjvu_thumbnail_p::callback, (void*)thumb);
730
764
    }
731
765
  for (p = streams; p; ++p)
732
 
    streams[p]->stop();
 
766
    {
 
767
      GP<DataPool> pool = streams[p];
 
768
      pool->del_trigger(callback, (void*)this);
 
769
      pool->stop();
 
770
    }
733
771
}
734
772
 
735
773
ddjvu_status_t
782
820
  }
783
821
}
784
822
 
 
823
 
785
824
void 
786
 
ddjvu_document_s::notify_file_flags_changed(const DjVuFile*, long s, long)
 
825
ddjvu_document_s::callback(void *arg)
787
826
{
788
 
  if (pageinfoflag && !fileflag)
789
 
    if (s & DjVuFile::ALL_DATA_PRESENT)
790
 
      msg_push(xhead(DDJVU_PAGEINFO, this));
 
827
  ddjvu_document_t *doc = (ddjvu_document_t *)arg;
 
828
  if (doc && doc->pageinfoflag && !doc->fileflag) 
 
829
    msg_push(xhead(DDJVU_PAGEINFO, doc));
791
830
}
792
831
 
 
832
 
793
833
GP<DataPool> 
794
834
ddjvu_document_s::request_data(const DjVuPort *p, const GURL &url)
795
835
{
 
836
  // Note: the following line try to restore
 
837
  //       the bytes stored in the djvu file
 
838
  //       despite LT's i18n and gurl classes.
 
839
  GUTF8String name = (const char*)url.fname(); 
796
840
  GMonitorLock lock(&monitor);
797
841
  GP<DataPool> pool;
798
 
  if (fileflag)
 
842
  if (names.contains(name))
 
843
    {
 
844
      int streamid = names[name];
 
845
      return streams[streamid];
 
846
    }
 
847
  else if (fileflag)
799
848
    {
800
849
      if (doc && url.is_local_file_url())
801
850
        return DataPool::create(url);
802
851
    }
803
852
  else if (doc)
804
853
    {
 
854
      // prepare pool
805
855
      if (++streamid > 0)
806
856
        streams[streamid] = pool = DataPool::create();
807
857
      else
808
858
        pool = streams[(streamid = 0)];
 
859
      names[name] = streamid;
 
860
      pool->add_trigger(-1, callback, (void*)this);
809
861
      // build message
810
862
      GP<ddjvu_message_p> p = new ddjvu_message_p;
811
863
      p->p.m_newstream.streamid = streamid;
812
 
      // Note: the following line try to restore
813
 
      //       the bytes stored in the djvu file
814
 
      //       despite LT's i18n and gurl classes.
815
 
      p->tmp1 = (const char*)url.fname(); 
 
864
      p->tmp1 = name;
816
865
      p->p.m_newstream.name = (const char*)(p->tmp1);
817
866
      p->p.m_newstream.url = 0;
818
867
      if (urlflag)
851
900
      d->pageinfoflag = false;
852
901
      d->myctx = ctx;
853
902
      d->mydoc = 0;
854
 
      d->userdata = 0;
855
903
      d->doc = DjVuDocument::create_noinit();
856
904
      if (url)
857
905
        {
873
921
      if (d) 
874
922
        unref(d);
875
923
      d = 0;
876
 
      ERROR(ctx, ex);
 
924
      ERROR1(ctx, ex);
877
925
    }
878
926
  G_ENDCATCH;
879
927
  return d;
900
948
      d->docinfoflag = false;
901
949
      d->myctx = ctx;
902
950
      d->mydoc = 0;
903
 
      d->userdata = 0;
904
951
      d->doc = DjVuDocument::create_noinit();
905
952
      d->doc->start_init(gurl, d, xcache);
906
953
    }
909
956
      if (d)
910
957
        unref(d);
911
958
      d = 0;
912
 
      ERROR(ctx, ex);
 
959
      ERROR1(ctx, ex);
913
960
    }
914
961
  G_ENDCATCH;
915
962
  return d;
947
994
    }
948
995
  G_CATCH(ex)
949
996
    {
950
 
      ERROR(doc,ex);
 
997
      ERROR1(doc,ex);
951
998
    }
952
999
  G_ENDCATCH;
953
1000
}
968
1015
      if (! pool)
969
1016
        G_THROW("Unknown stream ID");
970
1017
      if (stop)
971
 
        pool->stop();
972
 
      else
973
 
        pool->set_eof();
 
1018
        pool->stop(true);
 
1019
      pool->set_eof();
974
1020
    }
975
1021
  G_CATCH(ex)
976
1022
    {
977
 
      ERROR(doc, ex);
 
1023
      ERROR1(doc, ex);
978
1024
    }
979
1025
  G_ENDCATCH;
980
1026
}
1011
1057
    }
1012
1058
  G_CATCH(ex)
1013
1059
    {
1014
 
      ERROR(document,ex);
 
1060
      ERROR1(document,ex);
1015
1061
    }
1016
1062
  G_ENDCATCH;
1017
1063
  return DDJVU_DOCTYPE_UNKNOWN;
1018
1064
}
1019
1065
 
 
1066
 
1020
1067
int
1021
1068
ddjvu_document_get_pagenum(ddjvu_document_t *document)
1022
1069
{
1028
1075
    }
1029
1076
  G_CATCH(ex)
1030
1077
    {
1031
 
      ERROR(document,ex);
 
1078
      ERROR1(document,ex);
1032
1079
    }
1033
1080
  G_ENDCATCH;
1034
1081
  return 1;
1035
1082
}
1036
1083
 
1037
 
ddjvu_status_t
1038
 
ddjvu_document_get_pageinfo(ddjvu_document_t *document, int pageno, 
1039
 
                            ddjvu_pageinfo_t *pageinfo)
1040
 
{
1041
 
  G_TRY
1042
 
    {
 
1084
 
 
1085
int
 
1086
ddjvu_document_get_filenum(ddjvu_document_t *document)
 
1087
{
 
1088
  G_TRY
 
1089
    {
 
1090
      DjVuDocument *doc = document->doc;
 
1091
      if (! (doc && doc->is_init_ok()))
 
1092
        return 0;
 
1093
      int doc_type = doc->get_doc_type();
 
1094
      if (doc_type == DjVuDocument::BUNDLED ||
 
1095
          doc_type == DjVuDocument::INDIRECT )
 
1096
        {
 
1097
          GP<DjVmDir> dir = doc->get_djvm_dir();
 
1098
          return dir->get_files_num();
 
1099
        }
 
1100
      else if (doc_type == DjVuDocument::OLD_BUNDLED)
 
1101
        {
 
1102
          GP<DjVmDir0> dir0 = doc->get_djvm_dir0();
 
1103
          return dir0->get_files_num();
 
1104
        }
 
1105
      else 
 
1106
        return doc->get_pages_num();
 
1107
    }
 
1108
  G_CATCH(ex)
 
1109
    {
 
1110
      ERROR1(document,ex);
 
1111
    }
 
1112
  G_ENDCATCH;
 
1113
  return 0;
 
1114
}
 
1115
 
 
1116
 
 
1117
#undef ddjvu_document_get_fileinfo
 
1118
 
 
1119
extern "C" DDJVUAPI ddjvu_status_t
 
1120
ddjvu_document_get_fileinfo(ddjvu_document_t *d, int f, ddjvu_fileinfo_t *i);
 
1121
 
 
1122
ddjvu_status_t
 
1123
ddjvu_document_get_fileinfo(ddjvu_document_t *d, int f, ddjvu_fileinfo_t *i)
 
1124
{
 
1125
  // for binary backward compatibility with ddjvuapi=17
 
1126
  struct info17_s { char t; int p,s; const char *d, *n, *l; };
 
1127
  return ddjvu_document_get_fileinfo_imp(d,f,i,sizeof(info17_s));
 
1128
}
 
1129
 
 
1130
ddjvu_status_t
 
1131
ddjvu_document_get_fileinfo_imp(ddjvu_document_t *document, int fileno, 
 
1132
                                ddjvu_fileinfo_t *info, 
 
1133
                                unsigned int infosz )
 
1134
{
 
1135
  struct info17_s { char t; int p,s; const char *d, *n, *l; };
 
1136
  
 
1137
  G_TRY
 
1138
    {
 
1139
      memset(info, 0, infosz);
 
1140
      DjVuDocument *doc = document->doc;
 
1141
      if (! doc)
 
1142
        return DDJVU_JOB_NOTSTARTED;
 
1143
      if (! doc->is_init_ok())
 
1144
        return document->status();
 
1145
      int type = doc->get_doc_type();
 
1146
      if ( type == DjVuDocument::BUNDLED ||
 
1147
           type == DjVuDocument::INDIRECT )
 
1148
        {
 
1149
          GP<DjVmDir> dir = doc->get_djvm_dir();
 
1150
          GP<DjVmDir::File> file = dir->pos_to_file(fileno, &info->pageno);
 
1151
          if (! file)
 
1152
            G_THROW("Illegal file number");
 
1153
          info->type = 'I';
 
1154
          if (file->is_page())
 
1155
            info->type = 'P';
 
1156
          else
 
1157
            info->pageno = -1;
 
1158
          if (file->is_thumbnails())
 
1159
            info->type = 'T';
 
1160
          if (file->is_shared_anno())
 
1161
            info->type = 'S';
 
1162
          info->size = file->size;
 
1163
          info->id = file->get_load_name();
 
1164
          info->name = file->get_save_name();
 
1165
          info->title = file->get_title();
 
1166
          return DDJVU_JOB_OK;
 
1167
        }
 
1168
      else if (type == DjVuDocument::OLD_BUNDLED)
 
1169
        {
 
1170
          GP<DjVmDir0> dir0 = doc->get_djvm_dir0();
 
1171
          GP<DjVuNavDir> nav = doc->get_nav_dir();
 
1172
          GP<DjVmDir0::FileRec> frec = dir0->get_file(fileno);
 
1173
          if (! frec)
 
1174
            G_THROW("Illegal file number");
 
1175
          info->size = frec->size;
 
1176
          info->id = (const char*) frec->name;
 
1177
          info->name = info->title = info->id;
 
1178
          if (! nav)
 
1179
            return DDJVU_JOB_STARTED;
 
1180
          else if (nav->name_to_page(frec->name) >= 0)
 
1181
            info->type = 'P';
 
1182
          else
 
1183
            info->type = 'I';
 
1184
          return DDJVU_JOB_OK;
 
1185
        }
 
1186
      else 
 
1187
        {
 
1188
          if (fileno<0 || fileno>=doc->get_pages_num())
 
1189
            G_THROW("Illegal file number");
 
1190
          info->type = 'P';
 
1191
          info->pageno = fileno;
 
1192
          info->size = -1;
 
1193
          GP<DjVuNavDir> nav = doc->get_nav_dir();
 
1194
          info->id = (nav) ? (const char *) nav->page_to_name(fileno) : 0;
 
1195
          info->name = info->title = info->id;
 
1196
          GP<DjVuFile> file = doc->get_djvu_file(fileno, true);
 
1197
          GP<DataPool> pool = (file) ? file->get_init_data_pool() : 0;
 
1198
          info->size = (pool) ? pool->get_length() : -1;
 
1199
          return DDJVU_JOB_OK;
 
1200
        }
 
1201
    }
 
1202
  G_CATCH(ex)
 
1203
    {
 
1204
      ERROR1(document,ex);
 
1205
    }
 
1206
  G_ENDCATCH;
 
1207
  return DDJVU_JOB_FAILED;
 
1208
}
 
1209
 
 
1210
 
 
1211
int
 
1212
ddjvu_document_search_pageno(ddjvu_document_t *document, const char *name)
 
1213
{
 
1214
  G_TRY
 
1215
    {
 
1216
      DjVuDocument *doc = document->doc;
 
1217
      if (! (doc && doc->is_init_ok()))
 
1218
        return -1;
 
1219
      GP<DjVmDir> dir = doc->get_djvm_dir();
 
1220
      if (! dir)
 
1221
        return 0;
 
1222
      GP<DjVmDir::File> file;
 
1223
      if (! (file = dir->id_to_file(GUTF8String(name))))
 
1224
        if (! (file = dir->name_to_file(GUTF8String(name))))
 
1225
          if (! (file = dir->title_to_file(GUTF8String(name))))
 
1226
            {
 
1227
              char *edata=0;
 
1228
              long int p = strtol(name, &edata, 10);
 
1229
              if (edata!=name && !*edata && p>=1)
 
1230
                file = dir->page_to_file(p-1);
 
1231
            }
 
1232
      if (file)
 
1233
        {
 
1234
          int pageno = -1;
 
1235
          int fileno = dir->get_file_pos(file);
 
1236
          if (dir->pos_to_file(fileno, &pageno))
 
1237
            return pageno;
 
1238
        }
 
1239
    }
 
1240
  G_CATCH(ex)
 
1241
    {
 
1242
      ERROR1(document,ex);
 
1243
    }
 
1244
  G_ENDCATCH;
 
1245
  return -1;
 
1246
}
 
1247
 
 
1248
 
 
1249
int 
 
1250
ddjvu_document_check_pagedata(ddjvu_document_t *document, int pageno)
 
1251
{
 
1252
  G_TRY
 
1253
    {
 
1254
      document->pageinfoflag = true;
 
1255
      DjVuDocument *doc = document->doc;
 
1256
      if (doc && doc->is_init_ok())
 
1257
        {
 
1258
          GP<DjVuFile> file;
 
1259
          if (doc->get_doc_type()==DjVuDocument::INDIRECT)
 
1260
            file = doc->get_djvu_file(pageno, true);
 
1261
          else
 
1262
            file = doc->get_djvu_file(pageno, false);            
 
1263
          if (file && file->is_data_present())
 
1264
            return 1;
 
1265
        }
 
1266
    }
 
1267
  G_CATCH(ex)
 
1268
    {
 
1269
      ERROR1(document,ex);
 
1270
    }
 
1271
  G_ENDCATCH;
 
1272
  return 0;
 
1273
}
 
1274
 
 
1275
 
 
1276
#undef ddjvu_document_get_pageinfo
 
1277
 
 
1278
extern "C" DDJVUAPI ddjvu_status_t
 
1279
ddjvu_document_get_pageinfo(ddjvu_document_t *d, int p, ddjvu_pageinfo_t *i);
 
1280
 
 
1281
ddjvu_status_t
 
1282
ddjvu_document_get_pageinfo(ddjvu_document_t *d, int p, ddjvu_pageinfo_t *i)
 
1283
{
 
1284
  // for binary backward compatibility with ddjvuapi<=17
 
1285
  struct info17_s { int w; int h; int d; };
 
1286
  return ddjvu_document_get_pageinfo_imp(d,p,i,sizeof(struct info17_s));
 
1287
}
 
1288
 
 
1289
ddjvu_status_t
 
1290
ddjvu_document_get_pageinfo_imp(ddjvu_document_t *document, int pageno, 
 
1291
                                ddjvu_pageinfo_t *pageinfo, 
 
1292
                                unsigned int infosz)
 
1293
{
 
1294
  struct info17_s { int w; int h; int d; };
 
1295
 
 
1296
  G_TRY
 
1297
    {
 
1298
      memset(pageinfo, 0, infosz);
1043
1299
      DjVuDocument *doc = document->doc;
1044
1300
      if (doc)
1045
1301
        {
1061
1317
                      GP<ByteStream> gbs = iff->get_bytestream();
1062
1318
                      GP<DjVuInfo> info=DjVuInfo::create();
1063
1319
                      info->decode(*gbs);
1064
 
                      int rot = ((360-GRect::findangle(info->orientation))/90)%4;
 
1320
                      int rot = info->orientation;
 
1321
                      int w = (rot&1) ? info->height : info->width;
 
1322
                      int h = (rot&1) ? info->width : info->height;
1065
1323
                      if (pageinfo)
1066
1324
                        {
1067
 
                          pageinfo->width = (rot&1) ? info->height : info->width;
1068
 
                          pageinfo->height = (rot&1) ? info->width : info->height;
 
1325
                          pageinfo->width = w;
 
1326
                          pageinfo->height = h;
1069
1327
                          pageinfo->dpi = info->dpi;
 
1328
                          if (infosz > sizeof(struct info17_s))
 
1329
                            {
 
1330
                              pageinfo->rotation = rot;
 
1331
                              pageinfo->version = info->version;
 
1332
                            }
1070
1333
                        }
1071
1334
                      return DDJVU_JOB_OK;
1072
1335
                    }
1073
1336
                }
1074
1337
              else if (chkid == "FORM:BM44" || chkid == "FORM:PM44")
1075
1338
                {
1076
 
                  while (iff->get_chunk(chkid) && chkid!="BM44" && chkid!="PM44")
 
1339
                  while (iff->get_chunk(chkid) && 
 
1340
                         chkid!="BM44" && chkid!="PM44")
1077
1341
                    iff->close_chunk();
1078
1342
                  if (chkid=="BM44" || chkid=="PM44")
1079
1343
                    {
1081
1345
                      if (gbs->read8() == 0)
1082
1346
                        {
1083
1347
                          gbs->read8();
1084
 
                          gbs->read8();
 
1348
                          unsigned char vhi = gbs->read8();
 
1349
                          unsigned char vlo = gbs->read8();
1085
1350
                          unsigned char xhi = gbs->read8();
1086
1351
                          unsigned char xlo = gbs->read8();
1087
1352
                          unsigned char yhi = gbs->read8();
1091
1356
                              pageinfo->width = (xhi<<8)+xlo;
1092
1357
                              pageinfo->height = (yhi<<8)+ylo;
1093
1358
                              pageinfo->dpi = 100;
 
1359
                              if (infosz > sizeof(struct info17_s))
 
1360
                                {
 
1361
                                  pageinfo->rotation = 0;
 
1362
                                  pageinfo->version = (vhi<<8)+vlo;
 
1363
                                }
 
1364
                              return DDJVU_JOB_OK;
1094
1365
                            }
1095
 
                          return DDJVU_JOB_OK;
1096
1366
                        }
1097
1367
                    }
1098
1368
                }
1101
1371
    }
1102
1372
  G_CATCH(ex)
1103
1373
    {
1104
 
      ERROR(document, ex);
 
1374
      ERROR1(document, ex);
1105
1375
    }
1106
1376
  G_ENDCATCH;
1107
1377
  return DDJVU_JOB_FAILED;
1108
1378
}
1109
1379
 
1110
1380
 
 
1381
static char *
 
1382
get_file_dump(DjVuFile *file)
 
1383
{
 
1384
  DjVuDumpHelper dumper;
 
1385
  GP<DataPool> pool = file->get_init_data_pool();
 
1386
  GP<ByteStream> str = dumper.dump(pool);
 
1387
  int size = str->size();
 
1388
  char *buffer;
 
1389
  if ((size = str->size()) > 0 && (buffer = (char*)malloc(size+1)))
 
1390
    {
 
1391
      str->seek(0);
 
1392
      int len = str->readall(buffer, size);
 
1393
      buffer[len] = 0;
 
1394
      return buffer;
 
1395
    }
 
1396
  return 0;
 
1397
}
 
1398
 
 
1399
 
 
1400
char *
 
1401
ddjvu_document_get_pagedump(ddjvu_document_t *document, int pageno)
 
1402
{
 
1403
  G_TRY
 
1404
    {
 
1405
      DjVuDocument *doc = document->doc;
 
1406
      if (doc)
 
1407
        {
 
1408
          document->pageinfoflag = true;
 
1409
          GP<DjVuFile> file = doc->get_djvu_file(pageno);
 
1410
          if (file && file->is_data_present())
 
1411
            return get_file_dump(file);
 
1412
        }
 
1413
    }
 
1414
  G_CATCH(ex)
 
1415
    {
 
1416
      ERROR1(document, ex);
 
1417
    }
 
1418
  G_ENDCATCH;
 
1419
  return 0;
 
1420
}
 
1421
 
 
1422
 
 
1423
char *
 
1424
ddjvu_document_get_filedump(ddjvu_document_t *document, int fileno)
 
1425
{
 
1426
  G_TRY
 
1427
    {
 
1428
      DjVuDocument *doc = document->doc;
 
1429
      if (doc)
 
1430
        {
 
1431
          GP<DjVuFile> file;
 
1432
          int type = doc->get_doc_type();
 
1433
          if ( type != DjVuDocument::BUNDLED &&
 
1434
               type != DjVuDocument::INDIRECT )
 
1435
            file = doc->get_djvu_file(fileno);
 
1436
          else
 
1437
            {
 
1438
              GP<DjVmDir> dir = doc->get_djvm_dir();
 
1439
              GP<DjVmDir::File> fdesc = dir->pos_to_file(fileno);
 
1440
              if (fdesc)
 
1441
                file = doc->get_djvu_file(fdesc->get_load_name());
 
1442
            }
 
1443
          document->pageinfoflag = true;
 
1444
          if (file && file->is_data_present())
 
1445
            return get_file_dump(file);
 
1446
        }
 
1447
    }
 
1448
  G_CATCH(ex)
 
1449
    {
 
1450
      ERROR1(document, ex);
 
1451
    }
 
1452
  G_ENDCATCH;
 
1453
  return 0;
 
1454
}
 
1455
 
 
1456
 
 
1457
 
1111
1458
// ----------------------------------------
1112
1459
// Page
1113
1460
 
1125
1472
      GMonitorLock lock(&p->monitor);
1126
1473
      p->myctx = document->myctx;
1127
1474
      p->mydoc = document;
1128
 
      p->userdata = 0;
1129
1475
      p->pageinfoflag = false;
1130
1476
      p->pagedoneflag = false;
1131
 
      p->redisplayflag = false;
1132
 
      if (job)
1133
 
        p->job = job;
1134
 
      else
1135
 
        p->job = job = p;
 
1477
      p->job = job = ((job) ? job : p);
1136
1478
      if (pageid)
1137
1479
        p->img = doc->get_page(GNativeString(pageid), false, job);
1138
1480
      else
1143
1485
      if (p)
1144
1486
        unref(p);
1145
1487
      p = 0;
1146
 
      ERROR(document, ex);
 
1488
      ERROR1(document, ex);
1147
1489
    }
1148
1490
  G_ENDCATCH;
1149
1491
  return p;
1241
1583
ddjvu_page_s::notify_relayout(const DjVuImage *dimg)
1242
1584
{
1243
1585
  GMonitorLock lock(&monitor);
1244
 
  if (! img || pageinfoflag) return;
1245
 
  msg_push(xhead(DDJVU_PAGEINFO, this));
1246
 
  pageinfoflag = true;
1247
 
  msg_push(xhead(DDJVU_RELAYOUT, this));
1248
 
  if ( redisplayflag )
1249
 
    notify_redisplay(img);
 
1586
  if (img && !pageinfoflag)
 
1587
    {
 
1588
      msg_push(xhead(DDJVU_PAGEINFO, this));
 
1589
      msg_push(xhead(DDJVU_RELAYOUT, this));
 
1590
      pageinfoflag = true;
 
1591
    }
1250
1592
}
1251
1593
 
1252
1594
void 
1253
1595
ddjvu_page_s::notify_redisplay(const DjVuImage *dimg)
1254
1596
{
1255
1597
  GMonitorLock lock(&monitor);
1256
 
  redisplayflag = true;
 
1598
  if (img && !pageinfoflag)
 
1599
    {
 
1600
      msg_push(xhead(DDJVU_PAGEINFO, this));
 
1601
      msg_push(xhead(DDJVU_RELAYOUT, this));
 
1602
      pageinfoflag = true;
 
1603
    }
1257
1604
  if (img && pageinfoflag)
1258
1605
    msg_push(xhead(DDJVU_REDISPLAY, this));
1259
1606
}
1283
1630
    }
1284
1631
  G_CATCH(ex)
1285
1632
    {
1286
 
      ERROR(page, ex);
 
1633
      ERROR1(page, ex);
1287
1634
    }
1288
1635
  G_ENDCATCH;
1289
1636
  return 0;
1299
1646
    }
1300
1647
  G_CATCH(ex)
1301
1648
    {
1302
 
      ERROR(page, ex);
 
1649
      ERROR1(page, ex);
1303
1650
    }
1304
1651
  G_ENDCATCH;
1305
1652
  return 0;
1315
1662
    }
1316
1663
  G_CATCH(ex)
1317
1664
    {
1318
 
      ERROR(page, ex);
 
1665
      ERROR1(page, ex);
1319
1666
    }
1320
1667
  G_ENDCATCH;
1321
1668
  return 0;
1331
1678
    }
1332
1679
  G_CATCH(ex)
1333
1680
    {
1334
 
      ERROR(page, ex);
 
1681
      ERROR1(page, ex);
1335
1682
    }
1336
1683
  G_ENDCATCH;
1337
1684
  return 2.2;
1347
1694
    }
1348
1695
  G_CATCH(ex)
1349
1696
    {
1350
 
      ERROR(page, ex);
 
1697
      ERROR1(page, ex);
1351
1698
    }
1352
1699
  G_ENDCATCH;
1353
1700
  return DJVUVERSION;
1354
1701
}
1355
1702
 
 
1703
int
 
1704
ddjvu_code_get_version(void)
 
1705
{
 
1706
  return DJVUVERSION;
 
1707
}
 
1708
 
1356
1709
ddjvu_page_type_t
1357
1710
ddjvu_page_get_type(ddjvu_page_t *page)
1358
1711
{
1369
1722
    }
1370
1723
  G_CATCH(ex)
1371
1724
    {
1372
 
      ERROR(page, ex);
 
1725
      ERROR1(page, ex);
1373
1726
    }
1374
1727
  G_ENDCATCH;
1375
1728
  return DDJVU_PAGETYPE_UNKNOWN;
1388
1741
    }
1389
1742
  G_CATCH(ex)
1390
1743
    {
1391
 
      ERROR(page, ex);
 
1744
      ERROR1(page, ex);
1392
1745
    }
1393
1746
  G_ENDCATCH;
1394
1747
  return 0;
1407
1760
    }
1408
1761
  G_CATCH(ex)
1409
1762
    {
1410
 
      ERROR(page, ex);
 
1763
      ERROR1(page, ex);
1411
1764
    }
1412
1765
  G_ENDCATCH;
1413
1766
  return 0;
1417
1770
// ----------------------------------------
1418
1771
// Rotations
1419
1772
 
1420
 
ddjvu_page_rotation_t
1421
 
ddjvu_page_get_rotation(ddjvu_page_t *page)
1422
 
{
1423
 
  ddjvu_page_rotation_t rot = DDJVU_ROTATE_0;
1424
 
  G_TRY
1425
 
    {
1426
 
      if (page && page->img)
1427
 
        rot = (ddjvu_page_rotation_t)page->img->get_rotate();
1428
 
    }
1429
 
  G_CATCH(ex)
1430
 
    {
1431
 
      ERROR(page, ex);
1432
 
    }
1433
 
  G_ENDCATCH;
1434
 
  return rot;
1435
 
}
1436
 
 
1437
1773
void
1438
1774
ddjvu_page_set_rotation(ddjvu_page_t *page,
1439
1775
                        ddjvu_page_rotation_t rot)
1446
1782
        case DDJVU_ROTATE_90:
1447
1783
        case DDJVU_ROTATE_180:
1448
1784
        case DDJVU_ROTATE_270:
1449
 
          if (page && page->img && page->pageinfoflag)
1450
 
            {
1451
 
              int old = page->img->get_rotate();
1452
 
              if (old != (int)rot)
1453
 
                {
1454
 
                  page->img->set_rotate((int)rot);
1455
 
                  msg_push(xhead(DDJVU_RELAYOUT, page));
1456
 
                  if (page->redisplayflag)
1457
 
                    msg_push(xhead(DDJVU_REDISPLAY, page));
1458
 
                }
1459
 
            }
 
1785
          if (page && page->img && page->img->get_info())
 
1786
            page->img->set_rotate((int)rot);
1460
1787
          break;
1461
1788
        default:
1462
1789
          G_THROW("Illegal ddjvu rotation code");
1465
1792
    }
1466
1793
  G_CATCH(ex)
1467
1794
    {
1468
 
      ERROR(page, ex);
1469
 
    }
1470
 
  G_ENDCATCH;
 
1795
      ERROR1(page, ex);
 
1796
    }
 
1797
  G_ENDCATCH;
 
1798
}
 
1799
 
 
1800
ddjvu_page_rotation_t
 
1801
ddjvu_page_get_rotation(ddjvu_page_t *page)
 
1802
{
 
1803
  ddjvu_page_rotation_t rot = DDJVU_ROTATE_0;
 
1804
  G_TRY
 
1805
    {
 
1806
      if (page && page->img)
 
1807
        rot = (ddjvu_page_rotation_t)(page->img->get_rotate() & 3);
 
1808
    }
 
1809
  G_CATCH(ex)
 
1810
    {
 
1811
      ERROR1(page, ex);
 
1812
    }
 
1813
  G_ENDCATCH;
 
1814
  return rot;
 
1815
}
 
1816
 
 
1817
ddjvu_page_rotation_t
 
1818
ddjvu_page_get_initial_rotation(ddjvu_page_t *page)
 
1819
{
 
1820
  ddjvu_page_rotation_t rot = DDJVU_ROTATE_0;
 
1821
  G_TRY
 
1822
    {
 
1823
      GP<DjVuInfo> info;
 
1824
      if (page && page->img)
 
1825
        info = page->img->get_info();
 
1826
      if (info)
 
1827
        rot = (ddjvu_page_rotation_t)(info->orientation & 3);
 
1828
    }
 
1829
  G_CATCH(ex)
 
1830
    {
 
1831
      ERROR1(page, ex);
 
1832
    }
 
1833
  G_ENDCATCH;
 
1834
  return rot;
 
1835
}
 
1836
 
 
1837
 
 
1838
// ----------------------------------------
 
1839
// Rectangles
 
1840
 
 
1841
static void
 
1842
rect2grect(const ddjvu_rect_t *r, GRect &g)
 
1843
{
 
1844
  g.xmin = r->x;
 
1845
  g.ymin = r->y;
 
1846
  g.xmax = r->x + r->w;
 
1847
  g.ymax = r->y + r->h;
 
1848
}
 
1849
 
 
1850
static void
 
1851
grect2rect(const GRect &g, ddjvu_rect_t *r)
 
1852
{
 
1853
  if (g.isempty())
 
1854
    {
 
1855
      r->x = r->y = 0;
 
1856
      r->w = r->h = 0;
 
1857
    }
 
1858
  else
 
1859
    {
 
1860
      r->x = g.xmin;
 
1861
      r->y = g.ymin;
 
1862
      r->w = g.width();
 
1863
      r->h = g.height();
 
1864
    }
 
1865
}
 
1866
 
 
1867
ddjvu_rectmapper_t *
 
1868
ddjvu_rectmapper_create(ddjvu_rect_t *input, ddjvu_rect_t *output)
 
1869
{
 
1870
  GRect ginput, goutput;
 
1871
  rect2grect(input, ginput);
 
1872
  rect2grect(output, goutput);
 
1873
  GRectMapper *mapper = new GRectMapper;
 
1874
  if (!ginput.isempty())
 
1875
    mapper->set_input(ginput);
 
1876
  if (!goutput.isempty())
 
1877
    mapper->set_output(goutput);
 
1878
  return (ddjvu_rectmapper_t*)mapper;
 
1879
}
 
1880
 
 
1881
void
 
1882
ddjvu_rectmapper_modify(ddjvu_rectmapper_t *mapper,
 
1883
                        int rotation, int mirrorx, int mirrory)
 
1884
{
 
1885
  GRectMapper *gmapper = (GRectMapper*)mapper;
 
1886
  if (! gmapper) return;
 
1887
  gmapper->rotate(rotation);
 
1888
  if (mirrorx & 1)
 
1889
    gmapper->mirrorx();
 
1890
  if (mirrory & 1)
 
1891
    gmapper->mirrory();
 
1892
}
 
1893
 
 
1894
void 
 
1895
ddjvu_rectmapper_release(ddjvu_rectmapper_t *mapper)
 
1896
{
 
1897
  GRectMapper *gmapper = (GRectMapper*)mapper;
 
1898
  if (! gmapper) return;
 
1899
  delete gmapper;
 
1900
}
 
1901
 
 
1902
void 
 
1903
ddjvu_map_point(ddjvu_rectmapper_t *mapper, int *x, int *y)
 
1904
{
 
1905
  GRectMapper *gmapper = (GRectMapper*)mapper;
 
1906
  if (! gmapper) return;
 
1907
  gmapper->map(*x,*y);
 
1908
}
 
1909
 
 
1910
void 
 
1911
ddjvu_map_rect(ddjvu_rectmapper_t *mapper, ddjvu_rect_t *rect)
 
1912
{
 
1913
  GRectMapper *gmapper = (GRectMapper*)mapper;
 
1914
  if (! gmapper) return;
 
1915
  GRect grect;
 
1916
  rect2grect(rect,grect);
 
1917
  gmapper->map(grect);
 
1918
  grect2rect(grect,rect);
 
1919
}
 
1920
 
 
1921
void 
 
1922
ddjvu_unmap_point(ddjvu_rectmapper_t *mapper, int *x, int *y)
 
1923
{
 
1924
  GRectMapper *gmapper = (GRectMapper*)mapper;
 
1925
  if (! gmapper) return;
 
1926
  gmapper->unmap(*x,*y);
 
1927
}
 
1928
 
 
1929
void 
 
1930
ddjvu_unmap_rect(ddjvu_rectmapper_t *mapper, ddjvu_rect_t *rect)
 
1931
{
 
1932
  GRectMapper *gmapper = (GRectMapper*)mapper;
 
1933
  if (! gmapper) return;
 
1934
  GRect grect;
 
1935
  rect2grect(rect,grect);
 
1936
  gmapper->unmap(grect);
 
1937
  grect2rect(grect,rect);
1471
1938
}
1472
1939
 
1473
1940
 
1479
1946
  ddjvu_format_style_t style;
1480
1947
  uint32_t rgb[3][256];
1481
1948
  uint32_t palette[6*6*6];
 
1949
  uint32_t xorval;
1482
1950
  double gamma;
1483
1951
  char ditherbits;
1484
1952
  bool rtoptobottom;
1518
1986
      {
1519
1987
        if (sizeof(uint16_t)!=2 || sizeof(uint32_t)!=4)
1520
1988
          return fmt_error(fmt);
1521
 
        if (nargs!=3 || !args)
 
1989
        if (!args || nargs<3 || nargs>4)
1522
1990
          return fmt_error(fmt);
1523
 
        for (int j=0; j<3; j++)
 
1991
        { // extra nesting for windows
 
1992
          for (int j=0; j<3; j++)
1524
1993
          {
1525
1994
            int shift = 0;
1526
1995
            uint32_t mask = args[j];
1531
2000
            for (int i=0; i<256; i++)
1532
2001
              fmt->rgb[j][i] = (mask & ((int)((i*mask+127.0)/255.0)))<<shift;
1533
2002
          }
 
2003
        }
 
2004
        if (nargs >= 4)
 
2005
          fmt->xorval = args[3];
1534
2006
        break;
1535
2007
      }
1536
2008
    case DDJVU_FORMAT_PALETTE8:
1537
2009
      {
1538
2010
        if (nargs!=6*6*6 || !args)
1539
2011
          return fmt_error(fmt);
1540
 
        for (int k=0; k<6*6*6; k++)
1541
 
          fmt->palette[k] = args[k];
1542
 
        int j=0;
1543
 
        for(int i=0; i<6; i++)
1544
 
          for(; j < (i+1)*0x33 - 0x19 && j<256; j++)
 
2012
        { // extra nesting for windows
 
2013
          for (int k=0; k<6*6*6; k++)
 
2014
            fmt->palette[k] = args[k];
 
2015
        }
 
2016
        { // extra nesting for windows
 
2017
          int j=0;
 
2018
          for(int i=0; i<6; i++)
 
2019
            for(; j < (i+1)*0x33 - 0x19 && j<256; j++)
1545
2020
            {
1546
2021
              fmt->rgb[0][j] = i * 6 * 6;
1547
2022
              fmt->rgb[1][j] = i * 6;
1548
2023
              fmt->rgb[2][j] = i;
1549
2024
            }
 
2025
        }
1550
2026
        break;
1551
2027
      }
1552
2028
    case DDJVU_FORMAT_RGB24:
1599
2075
                const ddjvu_format_t *fmt, char *buf)
1600
2076
{
1601
2077
  const uint32_t (*r)[256] = fmt->rgb;
 
2078
  const uint32_t xorval = fmt->xorval;
1602
2079
  switch(fmt->style)
1603
2080
    {
1604
2081
    case DDJVU_FORMAT_BGR24:    /* truecolor 24 bits in BGR order */
1618
2095
      {
1619
2096
        uint16_t *b = (uint16_t*)buf;
1620
2097
        while (--w >= 0) {
1621
 
          b[0]=(r[0][p->r]+r[1][p->g]+r[2][p->b]); 
 
2098
          b[0]=(r[0][p->r]|r[1][p->g]|r[2][p->b])^xorval; 
1622
2099
          b+=1; p+=1; 
1623
2100
        }
1624
2101
        break;
1627
2104
      {
1628
2105
        uint32_t *b = (uint32_t*)buf;
1629
2106
        while (--w >= 0) {
1630
 
          b[0]=(r[0][p->r]+r[1][p->g]+r[2][p->b]); 
 
2107
          b[0]=(r[0][p->r]|r[1][p->g]|r[2][p->b])^xorval; 
1631
2108
          b+=1; p+=1; 
1632
2109
        }
1633
2110
        break;
1697
2174
                const ddjvu_format_t *fmt, char *buf)
1698
2175
{
1699
2176
  const uint32_t (*r)[256] = fmt->rgb;
 
2177
  const uint32_t xorval = fmt->xorval;
1700
2178
  switch(fmt->style)
1701
2179
    {
1702
2180
    case DDJVU_FORMAT_BGR24:    /* truecolor 24 bits in BGR order */
1713
2191
        uint16_t *b = (uint16_t*)buf;
1714
2192
        while (--w >= 0) {
1715
2193
          unsigned char x = g[*p];
1716
 
          b[0]=(r[0][x]+r[1][x]+r[2][x]); 
 
2194
          b[0]=(r[0][x]|r[1][x]|r[2][x])^xorval; 
1717
2195
          b+=1; p+=1; 
1718
2196
        }
1719
2197
        break;
1723
2201
        uint32_t *b = (uint32_t*)buf;
1724
2202
        while (--w >= 0) {
1725
2203
          unsigned char x = g[*p];
1726
 
          b[0]=(r[0][x]+r[1][x]+r[2][x]); 
 
2204
          b[0]=(r[0][x]|r[1][x]|r[2][x])^xorval; 
1727
2205
          b+=1; p+=1; 
1728
2206
        }
1729
2207
        break;
1823
2301
    {
1824
2302
      GP<GPixmap> pm;
1825
2303
      GP<GBitmap> bm;
1826
 
      GRect prect;
1827
 
      GRect rrect;
 
2304
      GRect prect, rrect;
 
2305
      rect2grect(pagerect, prect);
 
2306
      rect2grect(renderrect, rrect);
1828
2307
      if (pixelformat && pixelformat->ytoptobottom)
1829
2308
        {
1830
 
          prect.xmin = pagerect->x;
1831
 
          prect.xmax = prect.xmin + pagerect->w;
1832
2309
          prect.ymin = renderrect->y + renderrect->h;
1833
2310
          prect.ymax = prect.ymin + pagerect->h;
1834
 
          rrect.xmin = renderrect->x;
1835
 
          rrect.xmax = rrect.xmin + renderrect->w;
1836
2311
          rrect.ymin = pagerect->y + pagerect->h;
1837
2312
          rrect.ymax = rrect.ymin + renderrect->h;
1838
2313
        }
1839
 
      else
1840
 
        {
1841
 
          prect.xmin = pagerect->x;
1842
 
          prect.xmax = prect.xmin + pagerect->w;
1843
 
          prect.ymin = pagerect->y;
1844
 
          prect.ymax = prect.ymin + pagerect->h;
1845
 
          rrect.xmin = renderrect->x;
1846
 
          rrect.xmax = rrect.xmin + renderrect->w;
1847
 
          rrect.ymin = renderrect->y;
1848
 
          rrect.ymax = rrect.ymin + renderrect->h;
1849
 
        }
1850
2314
 
1851
2315
      DjVuImage *img = page->img;
1852
2316
      if (img) 
1874
2338
              break;
1875
2339
            case DDJVU_RENDER_FOREGROUND:
1876
2340
              pm = img->get_fg_pixmap(rrect, prect, pixelformat->gamma);
 
2341
              if (! pm) 
 
2342
                bm = img->get_bitmap(rrect, prect);
1877
2343
              break;
1878
2344
            }
1879
2345
        }
1893
2359
    }
1894
2360
  G_CATCH(ex)
1895
2361
    {
1896
 
      ERROR(page, ex);
 
2362
      ERROR1(page, ex);
1897
2363
    }
1898
2364
  G_ENDCATCH;
1899
2365
  return 0;
1920
2386
              thumb->data.resize(0,size-1);
1921
2387
              pool->get_data( (void*)(char*)thumb->data, 0, size);
1922
2388
            }
1923
 
          G_CATCH(ex)
 
2389
          G_CATCH_ALL
1924
2390
            {
1925
2391
              thumb->data.empty();
1926
2392
              G_RETHROW;
1972
2438
    }
1973
2439
  G_CATCH(ex)
1974
2440
    {
1975
 
      ERROR(document, ex);
 
2441
      ERROR1(document, ex);
1976
2442
    }
1977
2443
  G_ENDCATCH;
1978
2444
  return DDJVU_JOB_FAILED;
2029
2495
    }
2030
2496
  G_CATCH(ex)
2031
2497
    {
2032
 
      ERROR(document, ex);
 
2498
      ERROR1(document, ex);
2033
2499
    }
2034
2500
  G_ENDCATCH;
2035
2501
  return FALSE;
2105
2571
      self->progress(0);
2106
2572
      r = self->run();
2107
2573
    }
2108
 
  G_CATCH(ex)
 
2574
  G_CATCH_ALL
2109
2575
    {
2110
2576
      r = DDJVU_JOB_FAILED;
2111
2577
      if (self && self->mystop)
2161
2627
  double progress_high;
2162
2628
};
2163
2629
 
 
2630
bool 
 
2631
ddjvu_printjob_s::inherits(const GUTF8String &classname)
 
2632
{
 
2633
  return (classname == "ddjvu_printjob_s") 
 
2634
    || ddjvu_runnablejob_s::inherits(classname);
 
2635
}
 
2636
 
2164
2637
ddjvu_status_t 
2165
2638
ddjvu_printjob_s::run()
2166
2639
{
 
2640
  mydoc->doc->wait_for_complete_init();
2167
2641
  progress_low = 0;
2168
2642
  progress_high = 1;
2169
2643
  printer.set_refresh_cb(cbrefresh, (void*)this);
2174
2648
  return DDJVU_JOB_OK;
2175
2649
}
2176
2650
 
2177
 
bool 
2178
 
ddjvu_printjob_s::inherits(const GUTF8String &classname)
2179
 
{
2180
 
  return (classname == "ddjvu_printjob_s") 
2181
 
    || ddjvu_runnablejob_s::inherits(classname);
2182
 
}
2183
 
 
2184
2651
void
2185
2652
ddjvu_printjob_s::cbrefresh(void *data)
2186
2653
{
2188
2655
  if (self->mystop)
2189
2656
    {
2190
2657
      msg_push(xhead(DDJVU_INFO,self), msg_prep_info("Print job stopped"));
2191
 
      G_THROW("STOP");
 
2658
      G_THROW(DataPool::Stop);
2192
2659
    }
2193
2660
}
2194
2661
 
2465
2932
      if (job) 
2466
2933
        unref(job);
2467
2934
      job = 0;
2468
 
      ERROR(document, ex);
 
2935
      ERROR1(document, ex);
2469
2936
    }
2470
2937
  G_ENDCATCH;
2471
2938
  return job;
2472
2939
}
2473
2940
 
2474
2941
// ----------------------------------------
2475
 
// Not yet implemented
 
2942
// Saving (insufficiently tested)
 
2943
 
 
2944
struct DJVUNS ddjvu_savejob_s : public ddjvu_runnablejob_s
 
2945
{
 
2946
  GP<ByteStream> obs;
 
2947
  virtual ddjvu_status_t run();
 
2948
  // virtual port functions:
 
2949
  virtual bool inherits(const GUTF8String&);
 
2950
  virtual void notify_file_flags_changed(const DjVuFile*, long, long);
 
2951
  // data
 
2952
  GMonitor monitor;
 
2953
};
 
2954
 
 
2955
bool 
 
2956
ddjvu_savejob_s::inherits(const GUTF8String &classname)
 
2957
{
 
2958
  return (classname == "ddjvu_savejob_s") 
 
2959
    || ddjvu_runnablejob_s::inherits(classname);
 
2960
}
 
2961
 
 
2962
void
 
2963
ddjvu_savejob_s::notify_file_flags_changed(const DjVuFile *file, long mask, long)
 
2964
{
 
2965
  if (mask & (DjVuFile::ALL_DATA_PRESENT ||
 
2966
              DjVuFile::DECODE_FAILED || DjVuFile::DECODE_STOPPED ||
 
2967
              DjVuFile::STOPPED || DjVuFile::DECODE_STOPPED ))
 
2968
    {
 
2969
      GMonitorLock lock(&monitor);
 
2970
      monitor.signal();
 
2971
    }
 
2972
}
 
2973
 
 
2974
ddjvu_status_t 
 
2975
ddjvu_savejob_s::run()
 
2976
{
 
2977
  DjVuDocument *doc = mydoc->doc;
 
2978
  doc->wait_for_complete_init();
 
2979
  // Determine which components to save
 
2980
  int ncomp;
 
2981
  GArray<GUTF8String> comp_ids;
 
2982
  GPArray<DjVuFile> comp_files;
 
2983
  if (doc->get_doc_type()==DjVuDocument::BUNDLED ||
 
2984
      doc->get_doc_type()==DjVuDocument::INDIRECT)
 
2985
    {
 
2986
      GP<DjVmDir> dir = doc->get_djvm_dir();
 
2987
      ncomp = dir->get_files_num();
 
2988
      comp_ids.resize(ncomp - 1);
 
2989
      comp_files.resize(ncomp - 1);
 
2990
      GPList<DjVmDir::File> flist = dir->get_files_list();
 
2991
      GPosition pos=flist;
 
2992
      for (int comp=0; comp<ncomp; ++pos, ++comp)
 
2993
        comp_ids[comp] = flist[pos]->get_load_name();
 
2994
    } 
 
2995
  else 
 
2996
    { 
 
2997
      ncomp = doc->get_pages_num();
 
2998
      comp_ids.resize(ncomp - 1);
 
2999
      comp_files.resize(ncomp - 1);
 
3000
      { // extra nesting for windows
 
3001
        for (int comp=0; comp<ncomp; comp++)
 
3002
          comp_ids[comp] = GUTF8String(comp);
 
3003
      }
 
3004
    }
 
3005
  // Monitoring download progress
 
3006
  int lo = 0;
 
3007
  int hi = 0;
 
3008
  get_portcaster()->add_route(doc, this);
 
3009
  while (lo < ncomp && !mystop)
 
3010
    {
 
3011
      int in_progress = 0;
 
3012
      GMonitorLock lock(&monitor);
 
3013
      while (lo<hi && comp_files[lo]->is_data_present())
 
3014
        lo += 1;
 
3015
      { // extra nesting for windows
 
3016
        for (int comp=lo; comp<hi; comp++)
 
3017
          if (! comp_files[comp]->is_data_present())
 
3018
            in_progress += 1;
 
3019
      }
 
3020
      while (hi<ncomp && in_progress < 2)
 
3021
        {
 
3022
          comp_files[hi] = doc->get_djvu_file(comp_ids[hi]);
 
3023
          in_progress += 1;
 
3024
          hi += 1;
 
3025
        }
 
3026
      if (in_progress > 0)
 
3027
        monitor.wait();
 
3028
    }
 
3029
  if (mystop)
 
3030
    G_THROW("STOP");
 
3031
  // Saving!
 
3032
  doc->write(obs);
 
3033
  return DDJVU_JOB_OK;
 
3034
}
 
3035
 
2476
3036
 
2477
3037
ddjvu_job_t *
2478
3038
ddjvu_document_save(ddjvu_document_t *document, FILE *output, 
2479
3039
                    int optc, const char * const * optv)
2480
3040
{
2481
 
  return 0;
 
3041
  ddjvu_savejob_s *job = 0;
 
3042
  G_TRY
 
3043
    {
 
3044
      job = new ddjvu_savejob_s;
 
3045
      ref(job);
 
3046
      job->myctx = document->myctx;
 
3047
      job->mydoc = document;
 
3048
      // parse options
 
3049
      while (optc>0)
 
3050
        {
 
3051
          GNativeString narg(optv[0]);
 
3052
          GUTF8String uarg = narg;
 
3053
          complain(uarg, "Unrecognized option.");
 
3054
          optc -= 1;
 
3055
          optv += 1;
 
3056
        }
 
3057
      // go
 
3058
      job->obs = ByteStream::create(output, "wb", false);
 
3059
      job->start();
 
3060
    }
 
3061
  G_CATCH(ex)
 
3062
    {
 
3063
      if (job) 
 
3064
        unref(job);
 
3065
      job = 0;
 
3066
      ERROR1(document, ex);
 
3067
    }
 
3068
  G_ENDCATCH;
 
3069
  return job;
2482
3070
}
2483
3071
 
2484
3072
 
2485
3073
 
 
3074
 
2486
3075
// ----------------------------------------
2487
3076
// S-Expressions (generic)
2488
3077
 
2501
3090
static void
2502
3091
miniexp_protect(ddjvu_document_t *document, miniexp_t expr)
2503
3092
{
2504
 
  for(miniexp_t p=document->protect; miniexp_consp(p); p=miniexp_cdr(p))
2505
 
    if (miniexp_car(p) == expr)
2506
 
      return;
 
3093
  { // extra nesting for windows
 
3094
    for(miniexp_t p=document->protect; miniexp_consp(p); p=miniexp_cdr(p))
 
3095
      if (miniexp_car(p) == expr)
 
3096
        return;
 
3097
  }
2507
3098
  if (miniexp_consp(expr) || miniexp_objectp(expr))
2508
3099
    document->protect = miniexp_cons(expr, document->protect);
2509
3100
}
2573
3164
    }
2574
3165
  G_CATCH(ex)
2575
3166
    {
2576
 
      ERROR(document, ex);
 
3167
      ERROR1(document, ex);
2577
3168
    }
2578
3169
  G_ENDCATCH;
2579
3170
  return miniexp_status(DDJVU_JOB_FAILED);
2580
3171
}
2581
3172
 
2582
3173
 
 
3174
 
 
3175
 
2583
3176
// ----------------------------------------
2584
3177
// S-Expressions (text)
2585
3178
 
2609
3202
  minivar_t p;
2610
3203
  minivar_t a;
2611
3204
  bool gather = zone.children.isempty();
2612
 
  for (GPosition pos=zone.children; pos; ++pos)
2613
 
    if (zone.children[pos].ztype > detail)
2614
 
      gather = true;
 
3205
  { // extra nesting for windows
 
3206
    for (GPosition pos=zone.children; pos; ++pos)
 
3207
      if (zone.children[pos].ztype > detail)
 
3208
        gather = true;
 
3209
  }
2615
3210
  if (gather)
2616
3211
    {
2617
3212
      const char *data = (const char*)(txt->textUTF8) + zone.text_start;
2666
3261
            return miniexp_nil;
2667
3262
          minivar_t result;
2668
3263
          DjVuTXT::ZoneType detail = DjVuTXT::CHARACTER;
2669
 
          for (int i=0; zone_names[i].name; i++)
2670
 
            if (maxdetail && !strcmp(maxdetail, zone_names[i].name))
2671
 
              detail = zone_names[i].ztype;
 
3264
          { // extra nesting for windows
 
3265
            for (int i=0; zone_names[i].name; i++)
 
3266
              if (maxdetail && !strcmp(maxdetail, zone_names[i].name))
 
3267
                detail = zone_names[i].ztype;
 
3268
          }
2672
3269
          result = pagetext_sub(txt, txt->page_zone, detail);
2673
3270
          miniexp_protect(document, result);
2674
3271
          return result;
2676
3273
    }
2677
3274
  G_CATCH(ex)
2678
3275
    {
2679
 
      ERROR(document, ex);
 
3276
      ERROR1(document, ex);
2680
3277
    }
2681
3278
  G_ENDCATCH;
2682
3279
  return miniexp_status(DDJVU_JOB_FAILED);
2698
3295
// characters or illegal backslash sequences. Function <anno_getc()> then 
2699
3296
// creates the proper escapes on the fly.
2700
3297
 
 
3298
 
2701
3299
static struct {
2702
3300
  const char *s;
2703
3301
  char buf[8];
2707
3305
  bool eof;
2708
3306
} anno_dat;
2709
3307
 
 
3308
 
2710
3309
static bool
2711
3310
anno_compat(const char *s)
2712
3311
{
2739
3338
  return compat;
2740
3339
}
2741
3340
 
 
3341
 
2742
3342
static int
2743
3343
anno_getc(void)
2744
3344
{
2746
3346
    {
2747
3347
      anno_dat.blen--;
2748
3348
      char c = anno_dat.buf[0];
2749
 
      for (int i=0; i<anno_dat.blen; i++)
2750
 
        anno_dat.buf[i] = anno_dat.buf[i+1];
 
3349
      { // extra nesting for windows
 
3350
        for (int i=0; i<anno_dat.blen; i++)
 
3351
          anno_dat.buf[i] = anno_dat.buf[i+1];
 
3352
      }
2751
3353
      return c;
2752
3354
    }
2753
3355
  if (! *anno_dat.s)
2787
3389
  return c;
2788
3390
}
2789
3391
 
 
3392
 
2790
3393
static int
2791
3394
anno_ungetc(int c)
2792
3395
{
2794
3397
    return EOF;
2795
3398
  if (anno_dat.blen>=(int)sizeof(anno_dat.buf))
2796
3399
    return EOF;
2797
 
  for (int i=anno_dat.blen; i>0; i--)
2798
 
    anno_dat.buf[i] = anno_dat.buf[i-1];
 
3400
  { // extra nesting for windows
 
3401
    for (int i=anno_dat.blen; i>0; i--)
 
3402
      anno_dat.buf[i] = anno_dat.buf[i-1];
 
3403
  }
2799
3404
  anno_dat.blen += 1;
2800
3405
  anno_dat.buf[0] = c;
2801
3406
  return c;
2802
3407
}
2803
3408
 
 
3409
 
2804
3410
static void
2805
3411
anno_sub(ByteStream *bs, miniexp_t &result)
2806
3412
{
2811
3417
  while ((length=bs->read(buffer, sizeof(buffer))))
2812
3418
    raw += GUTF8String(buffer, length);
2813
3419
  // Prepare 
2814
 
  minivar_t a;
 
3420
  miniexp_t a;
2815
3421
  anno_dat.s = (const char*)raw;
2816
3422
  anno_dat.compat = anno_compat(anno_dat.s);
2817
3423
  anno_dat.blen = 0;
2818
3424
  anno_dat.state = 0;
2819
3425
  anno_dat.eof = false;
 
3426
  int (*saved_getc)(void) = minilisp_getc;
 
3427
  int (*saved_ungetc)(int) = minilisp_ungetc;
 
3428
  // Process
2820
3429
  minilisp_getc = anno_getc;
2821
3430
  minilisp_ungetc = anno_ungetc;
2822
 
  // Process
2823
3431
  while (* anno_dat.s )
2824
3432
    if ((a = miniexp_read()) != miniexp_dummy)
2825
3433
      result = miniexp_cons(a, result);
2826
 
}
 
3434
  // Restore
 
3435
  minilisp_getc = saved_getc;
 
3436
  minilisp_ungetc = saved_ungetc;
 
3437
}
 
3438
 
 
3439
 
 
3440
static miniexp_t
 
3441
get_bytestream_anno(GP<ByteStream> annobs)
 
3442
{
 
3443
  if (! (annobs && annobs->size()))
 
3444
    return miniexp_nil;
 
3445
  GP<IFFByteStream> iff = IFFByteStream::create(annobs);
 
3446
  GUTF8String chkid;
 
3447
  minivar_t result;
 
3448
  while (iff->get_chunk(chkid))
 
3449
    {
 
3450
      GP<ByteStream> bs;
 
3451
      if (chkid == "ANTa") 
 
3452
        bs = iff->get_bytestream();
 
3453
      else if (chkid == "ANTz")
 
3454
        bs = BSByteStream::create(iff->get_bytestream());
 
3455
      if (bs)
 
3456
        anno_sub(bs, result);
 
3457
      iff->close_chunk();
 
3458
    }
 
3459
  return miniexp_reverse(result);
 
3460
}
 
3461
 
 
3462
 
 
3463
static miniexp_t
 
3464
get_file_anno(GP<DjVuFile> file)
 
3465
{
 
3466
  // Make sure all data is present
 
3467
  if (! file || ! file->is_all_data_present())
 
3468
    {
 
3469
      if (file && file->is_data_present())
 
3470
        {
 
3471
          if (! file->are_incl_files_created())
 
3472
            file->process_incl_chunks();
 
3473
          if (! file->are_incl_files_created())
 
3474
            return miniexp_status(DDJVU_JOB_FAILED);
 
3475
        }
 
3476
      return miniexp_dummy;
 
3477
    }
 
3478
  // Access annotation data
 
3479
  return get_bytestream_anno(file->get_merged_anno());
 
3480
}
 
3481
 
2827
3482
 
2828
3483
miniexp_t
2829
3484
ddjvu_document_get_pageanno(ddjvu_document_t *document, int pageno)
2834
3489
      if (doc)
2835
3490
        {
2836
3491
          document->pageinfoflag = true;
2837
 
          GP<DjVuFile> file = doc->get_djvu_file(pageno);
2838
 
          // Make sure all data is present
2839
 
          if (! file || ! file->is_all_data_present())
2840
 
            {
2841
 
              if (file->is_data_present())
2842
 
                {
2843
 
                  if (! file->are_incl_files_created())
2844
 
                    file->process_incl_chunks();
2845
 
                  if (! file->are_incl_files_created())
2846
 
                    return miniexp_status(DDJVU_JOB_FAILED);
2847
 
                }
2848
 
              return miniexp_dummy;
2849
 
            }
2850
 
          // Access annotation data
2851
 
          GP<ByteStream> annobs = file->get_merged_anno();
2852
 
          if (! (annobs && annobs->size()))
2853
 
            return miniexp_nil;
2854
 
          minivar_t result;
2855
 
          GP<IFFByteStream> iff = IFFByteStream::create(annobs);
2856
 
          GUTF8String chkid;
2857
 
          while (iff->get_chunk(chkid))
2858
 
            {
2859
 
              GP<ByteStream> bs;
2860
 
              if (chkid == "ANTa") 
2861
 
                bs = iff->get_bytestream();
2862
 
              else if (chkid == "ANTz")
2863
 
                bs = BSByteStream::create(iff->get_bytestream());
2864
 
              if (bs)
2865
 
                anno_sub(bs, result);
2866
 
              iff->close_chunk();
2867
 
            }
2868
 
          result = miniexp_reverse(result);
2869
 
          miniexp_protect(document, result);
 
3492
          minivar_t result = get_file_anno( doc->get_djvu_file(pageno) );
 
3493
          if (miniexp_consp(result))
 
3494
            miniexp_protect(document, result);
2870
3495
          return result;
2871
3496
        }
2872
3497
    }
2873
3498
  G_CATCH(ex)
2874
3499
    {
2875
 
      ERROR(document, ex);
 
3500
      ERROR1(document, ex);
2876
3501
    }
2877
3502
  G_ENDCATCH;
2878
3503
  return miniexp_status(DDJVU_JOB_FAILED);
2879
3504
}
2880
3505
 
2881
3506
 
 
3507
miniexp_t
 
3508
ddjvu_document_get_anno(ddjvu_document_t *document, int compat)
 
3509
{
 
3510
  G_TRY
 
3511
    {
 
3512
      DjVuDocument *doc = document->doc;
 
3513
      if (doc)
 
3514
        {
 
3515
#if EXPERIMENTAL_DOCUMENT_ANNOTATIONS
 
3516
          // not yet implemented
 
3517
          GP<ByteStream> anno = doc->get_document_anno();
 
3518
          if (anno)
 
3519
            return get_bytestream_anno(anno);
 
3520
#endif
 
3521
          if (compat)
 
3522
            {
 
3523
              // look for shared annotations
 
3524
              int doc_type = doc->get_doc_type();
 
3525
              if (doc_type != DjVuDocument::BUNDLED &&
 
3526
                  doc_type != DjVuDocument::INDIRECT )
 
3527
                return miniexp_nil;
 
3528
              GP<DjVmDir> dir = doc->get_djvm_dir();
 
3529
              int filenum = dir->get_files_num();
 
3530
              GP<DjVmDir::File> fdesc;
 
3531
              for (int i=0; i<filenum; i++)
 
3532
                {
 
3533
                  GP<DjVmDir::File> f = dir->pos_to_file(i);
 
3534
                  if (!f->is_shared_anno())
 
3535
                    continue;
 
3536
                  if (fdesc)
 
3537
                    return miniexp_nil;
 
3538
                  fdesc = f;
 
3539
                }
 
3540
              if (fdesc)
 
3541
                {
 
3542
                  GUTF8String id = fdesc->get_load_name();
 
3543
                  return get_file_anno(doc->get_djvu_file(id));
 
3544
                }
 
3545
            }
 
3546
        }
 
3547
    }
 
3548
  G_CATCH(ex)
 
3549
    {
 
3550
      ERROR1(document, ex);
 
3551
    }
 
3552
  G_ENDCATCH;
 
3553
  return miniexp_nil;
 
3554
}
 
3555
 
 
3556
 
 
3557
 
2882
3558
 
2883
3559
/* ------ helpers for annotations ---- */
2884
3560
 
2984
3660
  miniexp_t *k = (miniexp_t*)malloc((1+i)*sizeof(miniexp_t));
2985
3661
  if (! k) return 0;
2986
3662
  i = 0;
2987
 
  for (GPosition p=m; p; ++p)
2988
 
    k[i++] = m.key(p);
 
3663
  { // extra nesting for windows
 
3664
    for (GPosition p=m; p; ++p)
 
3665
      k[i++] = m.key(p);
 
3666
  }
2989
3667
  k[i] = 0;
2990
3668
  return k;
2991
3669
}