~ubuntu-branches/ubuntu/raring/djvulibre/raring

« back to all changes in this revision

Viewing changes to libdjvu/ddjvuapi.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Daniel Holbach
  • Date: 2007-05-18 11:21:21 UTC
  • mfrom: (1.1.3 upstream)
  • Revision ID: james.westby@ubuntu.com-20070518112121-rt7fum0zi0xoepm6
Tags: 3.5.19-2ubuntu1
* debian/control: Maintainer: Ubuntu Core Developers
  <ubuntu-devel-discuss@lists.ubuntu.com>.
* debian/rules: call dh_iconcache. 

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*C- 
 
1
//C-  -*- C++ -*-
2
2
//C- -------------------------------------------------------------------
3
3
//C- DjVuLibre-3.5
4
4
//C- Copyright (c) 2002  Leon Bottou and Yann Le Cun.
5
5
//C- Copyright (c) 2001  AT&T
6
6
//C-
7
7
//C- This software is subject to, and may be distributed under, the
8
 
//C- GNU General Public License, Version 2. The license should have
 
8
//C- GNU General Public License, either Version 2 of the license,
 
9
//C- or (at your option) any later version. The license should have
9
10
//C- accompanied the software or you may obtain a copy of the license
10
11
//C- from the Free Software Foundation at http://www.fsf.org .
11
12
//C-
14
15
//C- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
16
//C- GNU General Public License for more details.
16
17
//C- 
17
 
//C- DjVuLibre-3.5 is derived from the DjVu(r) Reference Library
18
 
//C- distributed by Lizardtech Software.  On July 19th 2002, Lizardtech 
19
 
//C- Software authorized us to replace the original DjVu(r) Reference 
20
 
//C- Library notice by the following text (see doc/lizard2002.djvu):
 
18
//C- DjVuLibre-3.5 is derived from the DjVu(r) Reference Library from
 
19
//C- Lizardtech Software.  Lizardtech Software has authorized us to
 
20
//C- replace the original DjVu(r) Reference Library notice by the following
 
21
//C- text (see doc/lizard2002.djvu and doc/lizardtech2007.djvu):
21
22
//C-
22
23
//C-  ------------------------------------------------------------------
23
24
//C- | DjVu (r) Reference Library (v. 3.5)
26
27
//C- | 6,058,214 and patents pending.
27
28
//C- |
28
29
//C- | This software is subject to, and may be distributed under, the
29
 
//C- | GNU General Public License, Version 2. The license should have
 
30
//C- | GNU General Public License, either Version 2 of the license,
 
31
//C- | or (at your option) any later version. The license should have
30
32
//C- | accompanied the software or you may obtain a copy of the license
31
33
//C- | from the Free Software Foundation at http://www.fsf.org .
32
34
//C- |
50
52
//C- | TO ANY WARRANTY OF NON-INFRINGEMENT, OR ANY IMPLIED WARRANTY OF
51
53
//C- | MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
52
54
//C- +------------------------------------------------------------------
53
 
//C- */ 
54
55
 
55
 
/* $Id: ddjvuapi.cpp,v 1.66 2006/05/07 12:33:03 leonb Exp $ */
 
56
/* $Id: ddjvuapi.cpp,v 1.85 2007/03/25 20:48:35 leonb Exp $ */
56
57
 
57
58
#ifdef HAVE_CONFIG_H
58
59
# include "config.h"
205
206
  virtual void notify_doc_flags_changed(const DjVuDocument*, long, long);
206
207
  virtual GP<DataPool> request_data(const DjVuPort*, const GURL&);
207
208
  static void callback(void *);
 
209
  bool want_pageinfo(void);
208
210
};
209
211
 
210
212
struct DJVUNS ddjvu_page_s : public ddjvu_job_s
683
685
      GMonitorLock lock(&ctx->monitor);
684
686
      if (ctx->mpeeked)
685
687
        return &ctx->mpeeked->p;        
 
688
      if (! ctx->mlist.size())
 
689
        ctx->monitor.wait(0);
686
690
      GPosition p = ctx->mlist;
687
691
      if (! p)
688
692
        return 0;
765
769
  for (p = streams; p; ++p)
766
770
    {
767
771
      GP<DataPool> pool = streams[p];
768
 
      pool->del_trigger(callback, (void*)this);
769
 
      pool->stop();
 
772
      if (pool)
 
773
        pool->del_trigger(callback, (void*)this);
 
774
      if (pool && !pool->is_eof())
 
775
        pool->stop();
770
776
    }
771
777
}
772
778
 
876
882
}
877
883
 
878
884
 
 
885
bool
 
886
ddjvu_document_s::want_pageinfo()
 
887
{
 
888
  if (doc && docinfoflag && !pageinfoflag)
 
889
    {
 
890
      pageinfoflag = true;
 
891
      int doctype = doc->get_doc_type();
 
892
      if (doctype == DjVuDocument::BUNDLED ||
 
893
          doctype == DjVuDocument::OLD_BUNDLED )
 
894
        {
 
895
          GP<DataPool> pool;
 
896
          {
 
897
            GMonitorLock lock(&monitor);
 
898
            if (streams.contains(0))
 
899
              pool = streams[0];
 
900
          }
 
901
          if (pool && doctype == DjVuDocument::BUNDLED)
 
902
            {
 
903
              GP<DjVmDir> dir = doc->get_djvm_dir();
 
904
              if (dir)
 
905
                for (int i=0; i<dir->get_files_num(); i++)
 
906
                  {
 
907
                    GP<DjVmDir::File> f = dir->pos_to_file(i);
 
908
                    if (! pool->has_data(f->offset, f->size))
 
909
                      pool->add_trigger(f->offset, f->size, callback, (void*)this );
 
910
                  }
 
911
            }
 
912
          else if (pool && doctype == DjVuDocument::OLD_BUNDLED)
 
913
            {
 
914
              GP<DjVmDir0> dir = doc->get_djvm_dir0();
 
915
              if (dir)
 
916
                for (int i=0; i<dir->get_files_num(); i++)
 
917
                  {
 
918
                    GP<DjVmDir0::FileRec> f = dir->get_file(i);
 
919
                    if (! pool->has_data(f->offset, f->size))
 
920
                      pool->add_trigger(f->offset, f->size, callback, (void*)this );
 
921
                  }
 
922
            }
 
923
        }
 
924
    }
 
925
  return pageinfoflag;
 
926
}
 
927
 
 
928
 
879
929
// ----------------------------------------
880
930
// Documents
881
931
 
904
954
      if (url)
905
955
        {
906
956
          GURL gurl = GUTF8String(url);
 
957
          gurl.clear_djvu_cgi_arguments();
907
958
          d->urlflag = true;
908
959
          d->doc->start_init(gurl, d, xcache);
909
960
        }
1132
1183
                                ddjvu_fileinfo_t *info, 
1133
1184
                                unsigned int infosz )
1134
1185
{
1135
 
  struct info17_s { char t; int p,s; const char *d, *n, *l; };
1136
 
  
1137
1186
  G_TRY
1138
1187
    {
 
1188
      ddjvu_fileinfo_t myinfo;
1139
1189
      memset(info, 0, infosz);
 
1190
      if (infosz > sizeof(myinfo))
 
1191
        return DDJVU_JOB_FAILED;
1140
1192
      DjVuDocument *doc = document->doc;
1141
1193
      if (! doc)
1142
1194
        return DDJVU_JOB_NOTSTARTED;
1147
1199
           type == DjVuDocument::INDIRECT )
1148
1200
        {
1149
1201
          GP<DjVmDir> dir = doc->get_djvm_dir();
1150
 
          GP<DjVmDir::File> file = dir->pos_to_file(fileno, &info->pageno);
 
1202
          GP<DjVmDir::File> file = dir->pos_to_file(fileno, &myinfo.pageno);
1151
1203
          if (! file)
1152
1204
            G_THROW("Illegal file number");
1153
 
          info->type = 'I';
 
1205
          myinfo.type = 'I';
1154
1206
          if (file->is_page())
1155
 
            info->type = 'P';
 
1207
            myinfo.type = 'P';
1156
1208
          else
1157
 
            info->pageno = -1;
 
1209
            myinfo.pageno = -1;
1158
1210
          if (file->is_thumbnails())
1159
 
            info->type = 'T';
 
1211
            myinfo.type = 'T';
1160
1212
          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();
 
1213
            myinfo.type = 'S';
 
1214
          myinfo.size = file->size;
 
1215
          myinfo.id = file->get_load_name();
 
1216
          myinfo.name = file->get_save_name();
 
1217
          myinfo.title = file->get_title();
 
1218
          memcpy(info, &myinfo, infosz);
1166
1219
          return DDJVU_JOB_OK;
1167
1220
        }
1168
1221
      else if (type == DjVuDocument::OLD_BUNDLED)
1172
1225
          GP<DjVmDir0::FileRec> frec = dir0->get_file(fileno);
1173
1226
          if (! frec)
1174
1227
            G_THROW("Illegal file number");
1175
 
          info->size = frec->size;
1176
 
          info->id = (const char*) frec->name;
1177
 
          info->name = info->title = info->id;
 
1228
          myinfo.size = frec->size;
 
1229
          myinfo.id = (const char*) frec->name;
 
1230
          myinfo.name = myinfo.title = myinfo.id;
1178
1231
          if (! nav)
1179
1232
            return DDJVU_JOB_STARTED;
1180
1233
          else if (nav->name_to_page(frec->name) >= 0)
1181
 
            info->type = 'P';
 
1234
            myinfo.type = 'P';
1182
1235
          else
1183
 
            info->type = 'I';
 
1236
            myinfo.type = 'I';
 
1237
          memcpy(info, &myinfo, infosz);
1184
1238
          return DDJVU_JOB_OK;
1185
1239
        }
1186
1240
      else 
1187
1241
        {
1188
1242
          if (fileno<0 || fileno>=doc->get_pages_num())
1189
1243
            G_THROW("Illegal file number");
1190
 
          info->type = 'P';
1191
 
          info->pageno = fileno;
1192
 
          info->size = -1;
 
1244
          myinfo.type = 'P';
 
1245
          myinfo.pageno = fileno;
 
1246
          myinfo.size = -1;
1193
1247
          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;
 
1248
          myinfo.id = (nav) ? (const char *) nav->page_to_name(fileno) : 0;
 
1249
          myinfo.name = myinfo.title = myinfo.id;
1196
1250
          GP<DjVuFile> file = doc->get_djvu_file(fileno, true);
1197
1251
          GP<DataPool> pool = (file) ? file->get_init_data_pool() : 0;
1198
 
          info->size = (pool) ? pool->get_length() : -1;
 
1252
          myinfo.size = (pool) ? pool->get_length() : -1;
 
1253
          memcpy(info, &myinfo, infosz);
1199
1254
          return DDJVU_JOB_OK;
1200
1255
        }
1201
1256
    }
1246
1301
}
1247
1302
 
1248
1303
 
 
1304
 
1249
1305
int 
1250
1306
ddjvu_document_check_pagedata(ddjvu_document_t *document, int pageno)
1251
1307
{
1252
1308
  G_TRY
1253
1309
    {
1254
 
      document->pageinfoflag = true;
 
1310
      document->want_pageinfo();
1255
1311
      DjVuDocument *doc = document->doc;
1256
1312
      if (doc && doc->is_init_ok())
1257
1313
        {
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);            
 
1314
          bool dontcreate = false;
 
1315
          if (doc->get_doc_type() == DjVuDocument::INDIRECT ||
 
1316
              doc->get_doc_type() == DjVuDocument::OLD_INDEXED )
 
1317
            {
 
1318
              dontcreate = true;
 
1319
              GURL url = doc->page_to_url(pageno);
 
1320
              if (! url.is_empty())
 
1321
                {
 
1322
                  GUTF8String name = (const char*)url.fname();
 
1323
                  GMonitorLock lock(&document->monitor);
 
1324
                  if (document->names.contains(name))
 
1325
                    dontcreate = false;
 
1326
                }
 
1327
            }
 
1328
          GP<DjVuFile> file = doc->get_djvu_file(pageno, dontcreate);
1263
1329
          if (file && file->is_data_present())
1264
1330
            return 1;
1265
1331
        }
1291
1357
                                ddjvu_pageinfo_t *pageinfo, 
1292
1358
                                unsigned int infosz)
1293
1359
{
1294
 
  struct info17_s { int w; int h; int d; };
1295
 
 
1296
1360
  G_TRY
1297
1361
    {
 
1362
      ddjvu_pageinfo_t myinfo;
1298
1363
      memset(pageinfo, 0, infosz);
 
1364
      if (infosz > sizeof(myinfo))
 
1365
        return DDJVU_JOB_FAILED;
1299
1366
      DjVuDocument *doc = document->doc;
1300
1367
      if (doc)
1301
1368
        {
1302
 
          document->pageinfoflag = true;
 
1369
          document->want_pageinfo();
1303
1370
          GP<DjVuFile> file = doc->get_djvu_file(pageno);
1304
1371
          if (! file || ! file->is_data_present() )
1305
1372
            return DDJVU_JOB_STARTED;
1318
1385
                      GP<DjVuInfo> info=DjVuInfo::create();
1319
1386
                      info->decode(*gbs);
1320
1387
                      int rot = info->orientation;
1321
 
                      int w = (rot&1) ? info->height : info->width;
1322
 
                      int h = (rot&1) ? info->width : info->height;
1323
 
                      if (pageinfo)
1324
 
                        {
1325
 
                          pageinfo->width = w;
1326
 
                          pageinfo->height = h;
1327
 
                          pageinfo->dpi = info->dpi;
1328
 
                          if (infosz > sizeof(struct info17_s))
1329
 
                            {
1330
 
                              pageinfo->rotation = rot;
1331
 
                              pageinfo->version = info->version;
1332
 
                            }
1333
 
                        }
 
1388
                      myinfo.rotation = rot;
 
1389
                      myinfo.width = (rot&1) ? info->height : info->width;
 
1390
                      myinfo.height = (rot&1) ? info->width : info->height;
 
1391
                      myinfo.dpi = info->dpi;
 
1392
                      myinfo.version = info->version;
 
1393
                      memcpy(pageinfo, &myinfo, infosz);
1334
1394
                      return DDJVU_JOB_OK;
1335
1395
                    }
1336
1396
                }
1351
1411
                          unsigned char xlo = gbs->read8();
1352
1412
                          unsigned char yhi = gbs->read8();
1353
1413
                          unsigned char ylo = gbs->read8();
1354
 
                          if (pageinfo)
1355
 
                            {
1356
 
                              pageinfo->width = (xhi<<8)+xlo;
1357
 
                              pageinfo->height = (yhi<<8)+ylo;
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;
1365
 
                            }
 
1414
                          myinfo.width = (xhi<<8)+xlo;
 
1415
                          myinfo.height = (yhi<<8)+ylo;
 
1416
                          myinfo.dpi = 100;
 
1417
                          myinfo.rotation = 0;
 
1418
                          myinfo.version = (vhi<<8)+vlo;
 
1419
                          memcpy(pageinfo, &myinfo, infosz);
1366
1420
                        }
1367
1421
                    }
1368
1422
                }
1405
1459
      DjVuDocument *doc = document->doc;
1406
1460
      if (doc)
1407
1461
        {
1408
 
          document->pageinfoflag = true;
 
1462
          document->want_pageinfo();
1409
1463
          GP<DjVuFile> file = doc->get_djvu_file(pageno);
1410
1464
          if (file && file->is_data_present())
1411
1465
            return get_file_dump(file);
1426
1480
  G_TRY
1427
1481
    {
1428
1482
      DjVuDocument *doc = document->doc;
 
1483
      document->want_pageinfo();
1429
1484
      if (doc)
1430
1485
        {
1431
1486
          GP<DjVuFile> file;
1440
1495
              if (fdesc)
1441
1496
                file = doc->get_djvu_file(fdesc->get_load_name());
1442
1497
            }
1443
 
          document->pageinfoflag = true;
1444
1498
          if (file && file->is_data_present())
1445
1499
            return get_file_dump(file);
1446
1500
        }
1474
1528
      p->mydoc = document;
1475
1529
      p->pageinfoflag = false;
1476
1530
      p->pagedoneflag = false;
1477
 
      p->job = job = ((job) ? job : p);
 
1531
      if (! job)
 
1532
        job = p;
 
1533
      p->job = job;
1478
1534
      if (pageid)
1479
1535
        p->img = doc->get_page(GNativeString(pageid), false, job);
1480
1536
      else
2389
2445
          G_CATCH_ALL
2390
2446
            {
2391
2447
              thumb->data.empty();
2392
 
              G_RETHROW;
2393
2448
            }
2394
2449
          G_ENDCATCH;
2395
2450
          if (thumb->document->doc)
2407
2462
{
2408
2463
  G_TRY
2409
2464
    {
2410
 
      GMonitorLock lock(&document->monitor);
2411
 
      GPosition p = document->thumbnails.contains(pagenum);
2412
2465
      GP<ddjvu_thumbnail_p> thumb;
2413
 
      if (p)
2414
 
        {
2415
 
          thumb = document->thumbnails[p];
2416
 
        } 
2417
 
      else
2418
 
        {
2419
 
          DjVuDocument *doc = document->doc;
 
2466
      DjVuDocument* doc = document->doc;
 
2467
      if (doc)
 
2468
        {
 
2469
          GMonitorLock lock(&document->monitor);
 
2470
          GPosition p = document->thumbnails.contains(pagenum);
 
2471
          if (p)
 
2472
            thumb = document->thumbnails[p];
 
2473
        }
 
2474
      if (!thumb && doc)
 
2475
        {
2420
2476
          GP<DataPool> pool = doc->get_thumbnail(pagenum, !start);
2421
2477
          if (pool)
2422
2478
            {
 
2479
              GMonitorLock lock(&document->monitor);
2423
2480
              thumb = new ddjvu_thumbnail_p;
2424
2481
              thumb->document = document;
2425
2482
              thumb->pagenum = pagenum;
2426
2483
              thumb->pool = pool;
2427
2484
              document->thumbnails[pagenum] = thumb;
2428
 
              pool->add_trigger(-1, ddjvu_thumbnail_p::callback, 
2429
 
                                (void*)(ddjvu_thumbnail_p*)thumb);
2430
2485
            }
2431
 
        }
 
2486
          if (thumb)
 
2487
            pool->add_trigger(-1, ddjvu_thumbnail_p::callback, 
 
2488
                              (void*)(ddjvu_thumbnail_p*)thumb);
 
2489
        } 
2432
2490
      if (! thumb)
2433
2491
        return DDJVU_JOB_NOTSTARTED;        
2434
2492
      else if (thumb->pool)
2568
2626
  ddjvu_status_t r;
2569
2627
  G_TRY
2570
2628
    {
2571
 
      self->progress(0);
2572
 
      r = self->run();
 
2629
      G_TRY
 
2630
        {
 
2631
          self->progress(0);
 
2632
          r = self->run();
 
2633
        }
 
2634
      G_CATCH(ex)
 
2635
        {
 
2636
          ERROR1(self, ex);
 
2637
          G_RETHROW;
 
2638
        }
 
2639
      G_ENDCATCH;
2573
2640
    }
2574
2641
  G_CATCH_ALL
2575
2642
    {
2769
2836
            {
2770
2837
              if (arg == "a" || arg == "auto" )
2771
2838
                options.set_orientation(DjVuToPS::Options::AUTO);
2772
 
              if (arg == "l" || arg == "landscape" )
 
2839
              else if (arg == "l" || arg == "landscape" )
2773
2840
                options.set_orientation(DjVuToPS::Options::LANDSCAPE);
2774
 
              if (arg == "p" || arg == "portrait" )
 
2841
              else if (arg == "p" || arg == "portrait" )
2775
2842
                options.set_orientation(DjVuToPS::Options::PORTRAIT);
2776
2843
              else
2777
2844
                complain(uarg,"Invalid orientation. Use \"auto\", "
2938
3005
  return job;
2939
3006
}
2940
3007
 
 
3008
 
 
3009
 
2941
3010
// ----------------------------------------
2942
 
// Saving (insufficiently tested)
 
3011
// Saving
2943
3012
 
2944
3013
struct DJVUNS ddjvu_savejob_s : public ddjvu_runnablejob_s
2945
3014
{
2946
3015
  GP<ByteStream> obs;
 
3016
  GURL           odir;  
 
3017
  GUTF8String    oname;
 
3018
  GUTF8String    pages;
 
3019
  GTArray<char>       comp_flags;
 
3020
  GArray<GUTF8String> comp_ids;
 
3021
  GPArray<DjVuFile>   comp_files;
 
3022
  GMonitor monitor;
 
3023
  // thread routine
2947
3024
  virtual ddjvu_status_t run();
2948
3025
  // virtual port functions:
2949
3026
  virtual bool inherits(const GUTF8String&);
2950
3027
  virtual void notify_file_flags_changed(const DjVuFile*, long, long);
2951
 
  // data
2952
 
  GMonitor monitor;
 
3028
  // helpers
 
3029
  bool parse_pagespec(const char *s, int npages, bool *flags);
 
3030
  void mark_included_files(DjVuFile *file);
2953
3031
};
2954
3032
 
2955
3033
bool 
2960
3038
}
2961
3039
 
2962
3040
void
2963
 
ddjvu_savejob_s::notify_file_flags_changed(const DjVuFile *file, long mask, long)
 
3041
ddjvu_savejob_s::notify_file_flags_changed(const DjVuFile *file, 
 
3042
                                           long mask, long)
2964
3043
{
2965
 
  if (mask & (DjVuFile::ALL_DATA_PRESENT ||
2966
 
              DjVuFile::DECODE_FAILED || DjVuFile::DECODE_STOPPED ||
2967
 
              DjVuFile::STOPPED || DjVuFile::DECODE_STOPPED ))
 
3044
  if (mask & (DjVuFile::ALL_DATA_PRESENT | DjVuFile::DATA_PRESENT |
 
3045
              DjVuFile::DECODE_FAILED | DjVuFile::DECODE_STOPPED |
 
3046
              DjVuFile::STOPPED | DjVuFile::DECODE_STOPPED ))
2968
3047
    {
2969
3048
      GMonitorLock lock(&monitor);
2970
3049
      monitor.signal();
2971
3050
    }
2972
3051
}
2973
3052
 
 
3053
bool
 
3054
ddjvu_savejob_s::parse_pagespec(const char *s, int npages, bool *flags)
 
3055
{
 
3056
  int spec = 0;
 
3057
  int both = 1;
 
3058
  int start_page = 1;
 
3059
  int end_page = npages;
 
3060
  int pageno;
 
3061
  char *p = (char*)s;
 
3062
  while (*p)
 
3063
    {
 
3064
      spec = 0;
 
3065
      while (*p==' ')
 
3066
        p += 1;
 
3067
      if (! *p)
 
3068
        break;
 
3069
      if (*p>='0' && *p<='9') {
 
3070
        end_page = strtol(p, &p, 10);
 
3071
        spec = 1;
 
3072
      } else if (*p=='$') {
 
3073
        spec = 1;
 
3074
        end_page = npages;
 
3075
        p += 1;
 
3076
      } else if (both) {
 
3077
        end_page = 1;
 
3078
      } else {
 
3079
        end_page = npages;
 
3080
      }
 
3081
      while (*p==' ')
 
3082
        p += 1;
 
3083
      if (both) {
 
3084
        start_page = end_page;
 
3085
        if (*p == '-') {
 
3086
          p += 1;
 
3087
          both = 0;
 
3088
          continue;
 
3089
        }
 
3090
      }
 
3091
      both = 1;
 
3092
      while (*p==' ')
 
3093
        p += 1;
 
3094
      if (*p && *p != ',')
 
3095
        return false;
 
3096
      if (*p == ',')
 
3097
        p += 1;
 
3098
      if (! spec)
 
3099
        return false;
 
3100
      if (end_page < 0)
 
3101
        end_page = 0;
 
3102
      if (start_page < 0)
 
3103
        start_page = 0;
 
3104
      if (end_page > npages)
 
3105
        end_page = npages;
 
3106
      if (start_page > npages)
 
3107
        start_page = npages;
 
3108
      if (start_page <= end_page)
 
3109
        for(pageno=start_page; pageno<=end_page; pageno++)
 
3110
          flags[pageno-1] = true;
 
3111
      else
 
3112
        for(pageno=start_page; pageno>=end_page; pageno--)
 
3113
          flags[pageno-1] = true;
 
3114
    }
 
3115
  if (!spec)
 
3116
    return false;
 
3117
  return true;
 
3118
}
 
3119
 
 
3120
void 
 
3121
ddjvu_savejob_s::mark_included_files(DjVuFile *file)
 
3122
{
 
3123
  GP<DataPool> pool = file->get_init_data_pool();
 
3124
  GP<ByteStream> str(pool->get_stream());
 
3125
  GP<IFFByteStream> iff(IFFByteStream::create(str));
 
3126
  GUTF8String chkid;
 
3127
  if (!iff->get_chunk(chkid)) 
 
3128
    return;
 
3129
  while (iff->get_chunk(chkid))
 
3130
    {
 
3131
      if (chkid == "INCL")
 
3132
        {
 
3133
          GP<ByteStream> incl = iff->get_bytestream();
 
3134
          GUTF8String fileid;
 
3135
          char buffer[1024];
 
3136
          int length;
 
3137
          while((length=incl->read(buffer, 1024)))
 
3138
            fileid += GUTF8String(buffer, length);
 
3139
          for (int i=0; i<comp_ids.size(); i++)
 
3140
            if (fileid == comp_ids[i] && !comp_flags[i])
 
3141
              comp_flags[i] = 1;
 
3142
        }
 
3143
      iff->close_chunk();
 
3144
    }
 
3145
  iff->close_chunk();
 
3146
  pool->clear_stream();
 
3147
}
 
3148
 
2974
3149
ddjvu_status_t 
2975
3150
ddjvu_savejob_s::run()
2976
3151
{
2977
3152
  DjVuDocument *doc = mydoc->doc;
2978
3153
  doc->wait_for_complete_init();
2979
 
  // Determine which components to save
2980
 
  int ncomp;
2981
 
  GArray<GUTF8String> comp_ids;
2982
 
  GPArray<DjVuFile> comp_files;
 
3154
 
 
3155
  // Determine which pages to save
 
3156
  int npages = doc->get_pages_num();
 
3157
  GTArray<bool> page_flags(0, npages-1);
 
3158
  if (!pages)
 
3159
    {
 
3160
      for (int pageno=0; pageno<npages; pageno++)
 
3161
        page_flags[pageno] = true;
 
3162
    }
 
3163
  else
 
3164
    {
 
3165
      const char *s = pages;
 
3166
      while (*s && *s!='=')
 
3167
        s += 1;
 
3168
      for (int pageno=0; pageno<npages; pageno++)
 
3169
        page_flags[pageno] = false;
 
3170
      if ((*s != '=') || !parse_pagespec(s+1, npages, (bool*)page_flags))
 
3171
        complain(pages,"Illegal page specification");
 
3172
      if (doc->get_doc_type()==DjVuDocument::OLD_BUNDLED ||
 
3173
          doc->get_doc_type()==DjVuDocument::OLD_INDEXED )
 
3174
        complain(pages,"Saving subsets of obsolete formats is not supported");
 
3175
    }
 
3176
  
 
3177
  // Determine which component files to save
 
3178
  int ncomps;
2983
3179
  if (doc->get_doc_type()==DjVuDocument::BUNDLED ||
2984
3180
      doc->get_doc_type()==DjVuDocument::INDIRECT)
2985
3181
    {
2986
3182
      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);
 
3183
      ncomps = dir->get_files_num();
 
3184
      comp_ids.resize(ncomps - 1);
 
3185
      comp_flags.resize(ncomps - 1);
 
3186
      comp_files.resize(ncomps - 1);
 
3187
      int pageno = 0;
2990
3188
      GPList<DjVmDir::File> flist = dir->get_files_list();
2991
3189
      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;
 
3190
      for (int comp=0; comp<ncomps; ++pos, ++comp)
 
3191
        {
 
3192
          DjVmDir::File *file = flist[pos];
 
3193
          comp_ids[comp] = file->get_load_name();
 
3194
          comp_flags[comp] = 0;
 
3195
          if (file->is_page() && page_flags[pageno++])
 
3196
            comp_flags[comp] = 1;
 
3197
        }
 
3198
    }
 
3199
  else
 
3200
    {
 
3201
      ncomps = npages;
 
3202
      comp_flags.resize(ncomps - 1);
 
3203
      comp_files.resize(ncomps - 1);
 
3204
      for (int comp=0; comp<ncomps; ++comp)
 
3205
        comp_flags[comp] = page_flags[comp];
 
3206
    }
 
3207
  
 
3208
  // Download
3008
3209
  get_portcaster()->add_route(doc, this);
3009
 
  while (lo < ncomp && !mystop)
 
3210
  while (!mystop)
3010
3211
    {
3011
 
      int in_progress = 0;
 
3212
      int comp;
 
3213
      int wanted = 0;
 
3214
      int loaded = 0;
 
3215
      int asked = 0;
 
3216
      for (comp=0; comp<ncomps; comp++)
 
3217
        {
 
3218
          int flags = comp_flags[comp];
 
3219
          if (flags > 2)
 
3220
            loaded += 1;
 
3221
          else if (flags < 2)
 
3222
            continue;
 
3223
          else if (!comp_files[comp]->is_data_present())
 
3224
            asked += 1;
 
3225
          else 
 
3226
            {
 
3227
              comp_flags[comp] += 1;
 
3228
              mark_included_files(comp_files[comp]);
 
3229
            } 
 
3230
        }
 
3231
      for (comp=0; comp<ncomps; comp++)
 
3232
        if (comp_flags[comp] > 0)
 
3233
          wanted += 1;
 
3234
      progress(loaded * 100 / wanted);
 
3235
      if (wanted == loaded)
 
3236
        break;
 
3237
      for (comp=0; comp<ncomps && asked < 2; comp++)
 
3238
        if (comp_flags[comp] == 1)
 
3239
          {
 
3240
            if (comp_ids.size() > 0)
 
3241
              comp_files[comp] = doc->get_djvu_file(comp_ids[comp]);
 
3242
            else
 
3243
              comp_files[comp] = doc->get_djvu_file(comp);
 
3244
            comp_flags[comp] += 1;
 
3245
            if (!comp_files[comp]->is_data_present())
 
3246
              asked += 1;
 
3247
          }
3012
3248
      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++)
 
3249
      for (comp=0; comp<ncomps; comp++)
 
3250
        if (comp_flags[comp] == 2)
3017
3251
          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();
 
3252
            {
 
3253
              monitor.wait();
 
3254
              break;
 
3255
            }
3028
3256
    }
3029
3257
  if (mystop)
3030
 
    G_THROW("STOP");
 
3258
    G_THROW(DataPool::Stop);
3031
3259
  // Saving!
3032
 
  doc->write(obs);
 
3260
  GP<DjVmDoc> djvm;
 
3261
  if (! pages)
 
3262
    {
 
3263
      djvm = doc->get_djvm_doc();
 
3264
    }
 
3265
  else
 
3266
    {
 
3267
      djvm = DjVmDoc::create();
 
3268
      GP<DjVmDir> dir = doc->get_djvm_dir();
 
3269
      GPList<DjVmDir::File> flist = dir->get_files_list();
 
3270
      GPosition pos=flist;
 
3271
      int pageno = 0;
 
3272
      for (int comp=0; comp<ncomps; ++pos, ++comp)
 
3273
        {
 
3274
          if (flist[pos]->is_page())
 
3275
            pageno += 1;
 
3276
          if (comp_flags[comp])
 
3277
            {
 
3278
              GP<DjVmDir::File> f = new DjVmDir::File(*flist[pos]);
 
3279
              if (f->is_page() && f->get_save_name()==f->get_title())
 
3280
                f->set_title(GUTF8String(pageno));
 
3281
              GP<DjVuFile> file = comp_files[comp];
 
3282
              GP<DataPool> data = file->get_init_data_pool();
 
3283
              djvm->insert_file(f, data);
 
3284
            }
 
3285
        }
 
3286
    }
 
3287
  if (obs)
 
3288
    djvm->write(obs);
 
3289
  else if (odir.is_valid() && oname.length() > 0)
 
3290
    djvm->expand(odir, oname);
3033
3291
  return DDJVU_JOB_OK;
3034
3292
}
3035
3293
 
3045
3303
      ref(job);
3046
3304
      job->myctx = document->myctx;
3047
3305
      job->mydoc = document;
 
3306
      bool indirect = false;
3048
3307
      // parse options
3049
3308
      while (optc>0)
3050
3309
        {
3051
3310
          GNativeString narg(optv[0]);
3052
3311
          GUTF8String uarg = narg;
3053
 
          complain(uarg, "Unrecognized option.");
 
3312
          const char *s1 = (const char*)narg;
 
3313
          if (s1[0] == '-') s1++;
 
3314
          if (s1[0] == '-') s1++;
 
3315
          // separate arguments
 
3316
          if (!strncmp(s1, "page=", 5) ||
 
3317
              !strncmp(s1, "pages=", 6) )
 
3318
            {
 
3319
              if (job->pages.length())
 
3320
                complain(uarg,"multiple page specifications");
 
3321
              job->pages = uarg;
 
3322
            }
 
3323
          else if (!strncmp(s1, "indirect=", 9))
 
3324
            {
 
3325
              GURL oname = GURL::Filename::UTF8(s1 + 9);
 
3326
              job->odir = oname.base();
 
3327
              job->oname = oname.fname();
 
3328
              indirect = true;
 
3329
            }
 
3330
          else
 
3331
            {
 
3332
              complain(uarg, "Unrecognized option.");
 
3333
            }
 
3334
          // next option
3054
3335
          optc -= 1;
3055
3336
          optv += 1;
3056
3337
        }
3057
3338
      // go
3058
 
      job->obs = ByteStream::create(output, "wb", false);
 
3339
      job->obs = (indirect) ? 0 : ByteStream::create(output, "wb", false);
3059
3340
      job->start();
3060
3341
    }
3061
3342
  G_CATCH(ex)