• Skip to content
  • Skip to link menu
KDE 3.5 API Reference
  • KDE API Reference
  • API Reference
  • Sitemap
  • Contact Us
 

kviewshell

DjVmDir.cpp

Go to the documentation of this file.
00001 //C-  -*- C++ -*-
00002 //C- -------------------------------------------------------------------
00003 //C- DjVuLibre-3.5
00004 //C- Copyright (c) 2002  Leon Bottou and Yann Le Cun.
00005 //C- Copyright (c) 2001  AT&T
00006 //C-
00007 //C- This software is subject to, and may be distributed under, the
00008 //C- GNU General Public License, Version 2. The license should have
00009 //C- accompanied the software or you may obtain a copy of the license
00010 //C- from the Free Software Foundation at http://www.fsf.org .
00011 //C-
00012 //C- This program is distributed in the hope that it will be useful,
00013 //C- but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 //C- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 //C- GNU General Public License for more details.
00016 //C- 
00017 //C- DjVuLibre-3.5 is derived from the DjVu(r) Reference Library
00018 //C- distributed by Lizardtech Software.  On July 19th 2002, Lizardtech 
00019 //C- Software authorized us to replace the original DjVu(r) Reference 
00020 //C- Library notice by the following text (see doc/lizard2002.djvu):
00021 //C-
00022 //C-  ------------------------------------------------------------------
00023 //C- | DjVu (r) Reference Library (v. 3.5)
00024 //C- | Copyright (c) 1999-2001 LizardTech, Inc. All Rights Reserved.
00025 //C- | The DjVu Reference Library is protected by U.S. Pat. No.
00026 //C- | 6,058,214 and patents pending.
00027 //C- |
00028 //C- | This software is subject to, and may be distributed under, the
00029 //C- | GNU General Public License, Version 2. The license should have
00030 //C- | accompanied the software or you may obtain a copy of the license
00031 //C- | from the Free Software Foundation at http://www.fsf.org .
00032 //C- |
00033 //C- | The computer code originally released by LizardTech under this
00034 //C- | license and unmodified by other parties is deemed "the LIZARDTECH
00035 //C- | ORIGINAL CODE."  Subject to any third party intellectual property
00036 //C- | claims, LizardTech grants recipient a worldwide, royalty-free, 
00037 //C- | non-exclusive license to make, use, sell, or otherwise dispose of 
00038 //C- | the LIZARDTECH ORIGINAL CODE or of programs derived from the 
00039 //C- | LIZARDTECH ORIGINAL CODE in compliance with the terms of the GNU 
00040 //C- | General Public License.   This grant only confers the right to 
00041 //C- | infringe patent claims underlying the LIZARDTECH ORIGINAL CODE to 
00042 //C- | the extent such infringement is reasonably necessary to enable 
00043 //C- | recipient to make, have made, practice, sell, or otherwise dispose 
00044 //C- | of the LIZARDTECH ORIGINAL CODE (or portions thereof) and not to 
00045 //C- | any greater extent that may be necessary to utilize further 
00046 //C- | modifications or combinations.
00047 //C- |
00048 //C- | The LIZARDTECH ORIGINAL CODE is provided "AS IS" WITHOUT WARRANTY
00049 //C- | OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
00050 //C- | TO ANY WARRANTY OF NON-INFRINGEMENT, OR ANY IMPLIED WARRANTY OF
00051 //C- | MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
00052 //C- +------------------------------------------------------------------
00053 // 
00054 // $Id: DjVmDir.cpp,v 1.10 2004/05/05 15:12:42 leonb Exp $
00055 // $Name: release_3_5_15 $
00056 
00057 #ifdef HAVE_CONFIG_H
00058 # include "config.h"
00059 #endif
00060 #if NEED_GNUG_PRAGMAS
00061 # pragma implementation
00062 #endif
00063 
00064 #include "DjVmDir.h"
00065 #include "BSByteStream.h"
00066 #include "GURL.h"
00067 #include "debug.h"
00068 
00069 #include <ctype.h>
00070 
00071 
00072 #ifdef HAVE_NAMESPACES
00073 namespace DJVU {
00074 # ifdef NOT_DEFINED // Just to fool emacs c++ mode
00075 }
00076 #endif
00077 #endif
00078 
00079 
00080 GP<DjVmDir::File>
00081 DjVmDir::File::create(const GUTF8String &load_name,
00082   const GUTF8String &save_name, const GUTF8String &title,
00083   const FILE_TYPE file_type)
00084 {
00085   File *file_ptr=new File();
00086   GP<File> file=file_ptr;
00087   file_ptr->set_load_name(load_name);
00088   file_ptr->set_save_name(save_name);
00089   file_ptr->set_title(title);
00090   file_ptr->flags=(file_type & TYPE_MASK);
00091   return file;
00092 }
00093 
00094 const GUTF8String &
00095 DjVmDir::File::check_save_name(const bool xis_bundled)
00096 {
00097   if(!xis_bundled && !valid_name)
00098   {
00099     GUTF8String retval=name.length()?name:id;
00100     if(GUTF8String(GNativeString(retval)) != retval)
00101     {
00102       const_cast<bool &>(valid_name)=true;
00103       char *buf;
00104       GPBuffer<char> gbuf(buf,2*retval.length()+1);
00105       char *s=buf;
00106       int i=0;
00107       for(char c=retval[i++];c;)
00108       {
00109         static const char hex[]="0123456789ABCDEF";
00110         int len=retval.nextChar(i)-i;
00111         if(len>1 || ((len == 1)&&(c&0x80)))
00112         {
00113           do
00114           {
00115             s++[0]=hex[(c>>4)&0xf];
00116             s++[0]=hex[(c&0xf)];
00117             c=retval[i++];
00118           } while(c && ((--len) > 0));
00119         }else
00120         {
00121           s++[0]=c;
00122           c=retval[i++];
00123         }
00124       }
00125       s++[0]=0;
00126       oldname=retval;
00127       name=buf;
00128     }
00129     const_cast<bool &>(valid_name)=true;
00130   }
00131   return *(name.length()?&name:&id);
00132 }
00133 
00134 const GUTF8String &
00135 DjVmDir::File::get_save_name(void) const
00136 {
00137   return *(name.length()?&name:&id);
00138 }
00139 
00140 void
00141 DjVmDir::File::set_load_name(const GUTF8String &xid)
00142 {
00143   GURL url=GURL::UTF8(xid);
00144   if(!url.is_valid())
00145   {
00146     url=GURL::Filename::UTF8(xid);
00147   }
00148   id=url.fname();
00149 }
00150 
00151 void
00152 DjVmDir::File::set_save_name(const GUTF8String &xname)
00153 {
00154   GURL url;
00155   valid_name=false;
00156   if(!xname.length())
00157   {
00158     GURL url=GURL::UTF8(id);
00159     if(!url.is_valid())
00160     {
00161       name=id;
00162     }else
00163     {
00164       name=url.fname();
00165     }
00166   }else
00167   {
00168     GURL url=GURL::UTF8(xname);
00169     if(!url.is_valid())
00170     {
00171       url=GURL::Filename::UTF8(xname);
00172     }
00173     name=url.fname();
00174   }
00175   oldname="";
00176 }
00177 
00178 /* DjVmDir::File */
00179 
00180 DjVmDir::File::File(void) : offset(0), size(0), valid_name(false),
00181    flags(0), page_num(-1) { }
00182 
00183 GUTF8String
00184 DjVmDir::File::get_str_type(void) const
00185 {
00186    GUTF8String type;
00187    switch(flags & TYPE_MASK)
00188    {
00189       case INCLUDE:
00190         type="INCLUDE";
00191         break;
00192       case PAGE:
00193         type="PAGE";
00194         break;
00195       case THUMBNAILS:
00196         type="THUMBNAILS";
00197         break;
00198       case SHARED_ANNO:
00199         type="SHARED_ANNO";
00200         break;
00201       default:
00202         //  Internal error: please modify DjVmDir::File::get_str_type()
00203         //  to contain all possible File types.
00204           G_THROW( ERR_MSG("DjVmDir.get_str_type") );
00205    }
00206    return type;
00207 }
00208 
00209 
00210 const int DjVmDir::version=1;
00211 
00212 void 
00213 DjVmDir::decode(const GP<ByteStream> &gstr)
00214 {
00215    ByteStream &str=*gstr;
00216    DEBUG_MSG("DjVmDir::decode(): decoding contents of 'DIRM' chunk...\n");
00217    DEBUG_MAKE_INDENT(3);
00218    
00219    GCriticalSectionLock lock(&class_lock);
00220 
00221    GPosition pos;
00222 
00223    files_list.empty();
00224    page2file.resize(-1);
00225    name2file.empty();
00226    id2file.empty();
00227    title2file.empty();
00228 
00229    int ver=str.read8();
00230    bool bundled=(ver & 0x80)!=0;
00231    ver&=0x7f;
00232 
00233    DEBUG_MSG("DIRM version=" << ver << ", our version=" << version << "\n");
00234    if (ver>version)
00235       G_THROW( ERR_MSG("DjVmDir.version_error") "\t" 
00236                + GUTF8String(version) + "\t" + GUTF8String(ver));
00237    // Unable to read DJVM directories of versions higher than xxx
00238    // Data version number is yyy.
00239    DEBUG_MSG("bundled directory=" << bundled << "\n");
00240    DEBUG_MSG("reading the directory records...\n");
00241    int files=str.read16();
00242    DEBUG_MSG("number of files=" << files << "\n");
00243 
00244    if (files)
00245    {
00246       DEBUG_MSG("reading offsets (and sizes for ver==0)\n");
00247       for(int nfile=0;nfile<files;nfile++)
00248       {
00249          GP<File> file=new File();
00250          files_list.append(file);
00251          if (bundled)
00252          {
00253             file->offset=str.read32();
00254             if (ver==0)
00255               file->size=str.read24();
00256             if (file->offset==0)
00257                G_THROW( ERR_MSG("DjVmDir.no_indirect") );
00258          } else
00259          {
00260            file->offset=file->size=0;
00261          }
00262       }
00263 
00264       GP<ByteStream> gbs_str=BSByteStream::create(gstr);
00265       ByteStream &bs_str=*gbs_str;
00266       if (ver>0)
00267       {
00268          DEBUG_MSG("reading and decompressing sizes...\n");
00269          for(GPosition pos=files_list;pos;++pos)
00270             files_list[pos]->size=bs_str.read24();
00271       }
00272          
00273       DEBUG_MSG("reading and decompressing flags...\n");
00274       for(pos=files_list;pos;++pos)
00275          files_list[pos]->flags=bs_str.read8();
00276 
00277       if (!ver)
00278       {
00279          DEBUG_MSG("converting flags from version 0...\n");
00280          for(pos=files_list;pos;++pos)
00281          {
00282             unsigned char flags_0=files_list[pos]->flags;
00283             unsigned char flags_1;
00284             flags_1=(flags_0 & File::IS_PAGE_0)?(File::PAGE):(File::INCLUDE);
00285             if (flags_0 & File::HAS_NAME_0)
00286               flags_1|=File::HAS_NAME;
00287             if (flags_0 & File::HAS_TITLE_0)
00288               flags_1|=File::HAS_TITLE;
00289             files_list[pos]->flags=flags_1;
00290          }
00291       }
00292    
00293       DEBUG_MSG("reading and decompressing names...\n");
00294       GTArray<char> strings;
00295       char buffer[1024];
00296       int length;
00297       while((length=bs_str.read(buffer, 1024)))
00298       {
00299          int strings_size=strings.size();
00300          strings.resize(strings_size+length-1);
00301          memcpy((char*) strings+strings_size, buffer, length);
00302       }
00303       DEBUG_MSG("size of decompressed names block=" << strings.size() << "\n");
00304    
00305          // Copy names into the files
00306       const char * ptr=strings;
00307       for(pos=files_list;pos;++pos)
00308       {
00309          GP<File> file=files_list[pos];
00310 
00311          file->id=ptr;
00312          ptr+=file->id.length()+1;
00313          if (file->flags & File::HAS_NAME)
00314          {
00315             file->name=ptr;
00316             ptr+=file->name.length()+1;
00317          } else
00318          {
00319             file->name=file->id;
00320          }
00321          if (file->flags & File::HAS_TITLE)
00322          {
00323             file->title=ptr;
00324        ptr+=file->title.length()+1;
00325          } else
00326        file->title=file->id;
00327    /* msr debug:  multipage file, file->title is null.  
00328          DEBUG_MSG(file->name << ", " << file->id << ", " << file->title << ", " <<
00329                    file->offset << ", " << file->size << ", " <<
00330                    file->is_page() << "\n"); */
00331       }
00332 
00333          // Check that there is only one file with SHARED_ANNO flag on
00334       int shared_anno_cnt=0;
00335       for(pos=files_list;pos;++pos)
00336       {
00337          if (files_list[pos]->is_shared_anno())
00338          {
00339             shared_anno_cnt++;
00340          }
00341       }
00342       if (shared_anno_cnt>1)
00343         G_THROW( ERR_MSG("DjVmDir.corrupt") );
00344 
00345          // Now generate page=>file array for direct access
00346       int pages=0;
00347       for(pos=files_list;pos;++pos)
00348               pages+=files_list[pos]->is_page() ? 1 : 0;
00349       DEBUG_MSG("got " << pages << " pages\n");
00350       page2file.resize(pages-1);
00351       int page_num=0;
00352       for(pos=files_list;pos;++pos)
00353       {
00354                GP<File> file=files_list[pos];
00355                if (file->is_page())
00356                {
00357                   page2file[page_num]=file;
00358                   file->page_num=page_num++;
00359                }
00360       }
00361 
00362          // Generate name2file map
00363       for(pos=files_list;pos;++pos)
00364       {
00365            GP<File> file=files_list[pos];
00366            if (name2file.contains(file->name))
00367               G_THROW( ERR_MSG("DjVmDir.dupl_name") "\t" + file->name );
00368            name2file[file->name]=file;
00369       }
00370 
00371          // Generate id2file map
00372       for(pos=files_list;pos;++pos)
00373       {
00374            GP<File> file=files_list[pos];
00375            if (id2file.contains(file->id))
00376               G_THROW( ERR_MSG("DjVmDir.dupl_id") "\t" + file->id);
00377            id2file[file->id]=file;
00378       }
00379 
00380          // Generate title2file map
00381       for(pos=files_list;pos;++pos)
00382       {
00383            GP<File> file=files_list[pos];
00384            if (file->title.length())
00385            {
00386               if (title2file.contains(file->title))
00387                  G_THROW( ERR_MSG("DjVmDir.dupl_title") "\t" + file->title);
00388               title2file[file->title]=file;
00389            }
00390       }
00391    }
00392 }
00393 
00394 
00395 void
00396 DjVmDir::encode(const GP<ByteStream> &gstr, const bool do_rename) const
00397 {
00398   bool bundled = true;
00399   GPosition pos = files_list;
00400   if (files_list.size() && !files_list[pos]->offset)
00401     bundled = false;
00402   for (pos=files_list; pos; ++pos)
00403     if ( !bundled !=  !files_list[pos]->offset)
00404       //  There directory contains both indirect and bundled records.
00405       G_THROW( ERR_MSG("DjVmDir.bad_dir") );
00406   // Do the real work
00407   encode(gstr, bundled, do_rename);
00408 }
00409 
00410 void
00411 DjVmDir::encode(const GP<ByteStream> &gstr, const bool bundled, const bool do_rename) const
00412 {
00413   ByteStream &str=*gstr;
00414   DEBUG_MSG("DjVmDir::encode(): encoding contents of the 'DIRM' chunk do_rename=" << do_rename << "\n");
00415   DEBUG_MAKE_INDENT(3);
00416    
00417   GCriticalSectionLock lock((GCriticalSection *) &class_lock);
00418   GPosition pos;
00419 
00420   DEBUG_MSG("encoding version number=" << version << ", bundled=" << bundled << "\n");
00421   str.write8(version | ((int) bundled<< 7));
00422    
00423   DEBUG_MSG("storing the number of records=" << files_list.size() << "\n");
00424   str.write16(files_list.size());
00425 
00426   if (files_list.size())
00427     {
00428       // Check that there is only one file with shared annotations
00429       int shared_anno_cnt=0;
00430       for (pos=files_list; pos; ++pos)
00431         if (files_list[pos]->is_shared_anno())
00432           shared_anno_cnt++;
00433       if (shared_anno_cnt>1)
00434         G_THROW( ERR_MSG("DjVmDir.multi_save") );
00435       
00436       if (bundled)
00437         {
00438           // We need to store offsets uncompressed. That's because when
00439           // we save a DjVmDoc, we first compress the DjVmDir with dummy
00440           // offsets and after computing the real offsets we rewrite the
00441           // DjVmDir, which should not change its size during this operation
00442           DEBUG_MSG("storing offsets for every record\n");
00443           for (pos=files_list; pos; ++pos)
00444             {
00445               GP<File> file=files_list[pos];
00446               if (!file->offset)
00447                 // The directory contains record without offset
00448                 G_THROW( ERR_MSG("DjVmDir.bad_dir") );
00449               str.write32(file->offset);
00450             }
00451         }
00452       
00453       GP<ByteStream> gbs_str=BSByteStream::create(gstr, 50);
00454       ByteStream &bs_str=*gbs_str;
00455       DEBUG_MSG("storing and compressing sizes for every record\n");
00456       for (pos=files_list; pos; ++pos)
00457         {
00458           const GP<File> file(files_list[pos]);
00459           bs_str.write24(file->size);
00460         }
00461       DEBUG_MSG("storing and compressing flags for every record\n");
00462       const bool xdo_rename=(do_rename||!bundled);
00463       for(pos=files_list;pos;++pos)
00464         {
00465           const GP<File> file(files_list[pos]);
00466           if(xdo_rename)
00467             {
00468               const GUTF8String new_id = file->name;
00469               if (! new_id)
00470                 if(!file->oldname.length() || file->oldname == new_id)
00471                   file->flags &= ~File::HAS_NAME;
00472                 else
00473                   file->flags |= File::HAS_NAME;
00474             }
00475           else 
00476             {
00477               if (!file->name.length() || file->name == file->id)
00478                 file->flags &= ~File::HAS_NAME;
00479               else
00480                 file->flags |= File::HAS_NAME;
00481             }
00482           if (file->title.length() && (file->title!=file->id))
00483             file->flags |= File::HAS_TITLE;
00484           else
00485             file->flags &= ~File::HAS_TITLE;
00486 
00487        bs_str.write8(file->flags);
00488      }
00489 
00490      DEBUG_MSG("storing and compressing names...\n");
00491      for(pos=files_list;pos;++pos)
00492      {
00493          GP<File> file=files_list[pos];
00494          GUTF8String id;
00495          GUTF8String name;
00496          GUTF8String title;
00497          if (xdo_rename)
00498            {
00499              id = file->name;
00500              if (! id)
00501                id = file->id;
00502              if ((file->flags) & File::HAS_NAME)
00503                name = file->oldname;
00504            }
00505          else
00506            {
00507              id=file->id;
00508              if ((file->flags) & File::HAS_NAME)
00509                name = file->name;
00510            }
00511          if ((file->flags) & File::HAS_TITLE)
00512            title = file->title;
00513          DEBUG_MSG("rename=" <<xdo_rename<<" id='" << id << "' name='" << name << "' title='" << title << "'\n");
00514          bs_str.writestring(id);
00515          bs_str.write8(0);
00516          if (name.length())
00517            {
00518              bs_str.writestring(name);
00519              bs_str.write8(0);
00520            }
00521          if (title.length())
00522            {
00523              bs_str.writestring(title);
00524              bs_str.write8(0);
00525            }
00526      }
00527     }
00528   DEBUG_MSG("done\n");
00529 }
00530 
00531 GP<DjVmDir::File>
00532 DjVmDir::page_to_file(int page_num) const
00533 {
00534    GCriticalSectionLock lock((GCriticalSection *) &class_lock);
00535 
00536    return (page_num<page2file.size())?page2file[page_num]:(GP<DjVmDir::File>(0));
00537 }
00538 
00539 GP<DjVmDir::File>
00540 DjVmDir::name_to_file(const GUTF8String & name) const
00541 {
00542    GCriticalSectionLock lock((GCriticalSection *) &class_lock);
00543 
00544    GPosition pos;
00545    return (name2file.contains(name, pos))?name2file[pos]:(GP<DjVmDir::File>(0));
00546 }
00547 
00548 GP<DjVmDir::File>
00549 DjVmDir::id_to_file(const GUTF8String &id) const
00550 {
00551    GCriticalSectionLock lock((GCriticalSection *) &class_lock);
00552 
00553    GPosition pos;
00554    return (id2file.contains(id, pos))?id2file[pos]:(GP<DjVmDir::File>(0));
00555 }
00556 
00557 GP<DjVmDir::File>
00558 DjVmDir::title_to_file(const GUTF8String &title) const
00559 {
00560    GCriticalSectionLock lock((GCriticalSection *) &class_lock);
00561 
00562    GPosition pos;
00563    return (title2file.contains(title, pos))?title2file[pos]:(GP<DjVmDir::File>(0));
00564 }
00565 
00566 GPList<DjVmDir::File>
00567 DjVmDir::get_files_list(void) const
00568 {
00569   GCriticalSectionLock lock((GCriticalSection *) &class_lock);
00570   return files_list;
00571 }
00572 
00573 int
00574 DjVmDir::get_files_num(void) const
00575 {
00576   GCriticalSectionLock lock((GCriticalSection *) &class_lock);
00577   return files_list.size();
00578 }
00579 
00580 int
00581 DjVmDir::get_pages_num(void) const
00582 {
00583    GCriticalSectionLock lock((GCriticalSection *) &class_lock);
00584    return page2file.size();
00585 }
00586 
00587 int
00588 DjVmDir::get_file_pos(const File * f) const
00589 {
00590    GCriticalSectionLock lock((GCriticalSection *) &class_lock);
00591    int cnt;
00592    GPosition pos;
00593    for(pos=files_list, cnt=0;pos&&(files_list[pos]!=f);++pos, cnt++)
00594                    continue;
00595    return (pos)?cnt:(-1);
00596 }
00597 
00598 int
00599 DjVmDir::get_page_pos(int page_num) const
00600 {
00601    GCriticalSectionLock lock((GCriticalSection *) &class_lock);
00602    
00603    GP<File> file=page_to_file(page_num);
00604    return (file)?get_file_pos(file):(-1);
00605 }
00606 
00607 GP<DjVmDir::File>
00608 DjVmDir::get_shared_anno_file(void) const
00609 {
00610    GCriticalSectionLock lock((GCriticalSection *) &class_lock);
00611 
00612    GP<File> file;
00613    for(GPosition pos=files_list;pos;++pos)
00614    {
00615       GP<File> frec=files_list[pos];
00616       if (frec->is_shared_anno())
00617       {
00618          file=frec;
00619          break;
00620       }
00621    }
00622    return file;
00623 }
00624 
00625 int
00626 DjVmDir::insert_file(const GP<File> & file, int pos_num)
00627 {
00628    DEBUG_MSG("DjVmDir::insert_file(): name='" << file->name << "', pos=" << pos_num << "\n");
00629    DEBUG_MAKE_INDENT(3);
00630    
00631    GCriticalSectionLock lock((GCriticalSection *) &class_lock);
00632    
00633    if (pos_num<0)
00634      pos_num=files_list.size();
00635 
00636       // Modify maps
00637 //   if (! File::is_legal_id(file->id))
00638 //     G_THROW( ERR_MSG("DjVmDir.bad_file") "\t" + file->id);
00639    if (id2file.contains(file->id))
00640      G_THROW( ERR_MSG("DjVmDir.dupl_id2") "\t" + file->id);
00641    if (name2file.contains(file->name))
00642      G_THROW( ERR_MSG("DjVmDir.dupl_name2") "\t" + file->name);
00643    name2file[file->name]=file;
00644    id2file[file->id]=file;
00645    if (file->title.length())
00646      {
00647        if (title2file.contains(file->title))  // duplicate titles may become ok some day
00648          G_THROW( ERR_MSG("DjVmDir.dupl_title2") "\t" + file->title);
00649        title2file[file->title]=file;
00650      }
00651 
00652       // Make sure that there is no more than one file with shared annotations
00653    if (file->is_shared_anno())
00654    {
00655       for(GPosition pos=files_list;pos;++pos)
00656          if (files_list[pos]->is_shared_anno())
00657             G_THROW( ERR_MSG("DjVmDir.multi_save2") );
00658    }
00659    
00660       // Add the file to the list
00661    int cnt;
00662    GPosition pos;
00663    for(pos=files_list, cnt=0;pos&&(cnt!=pos_num);++pos, cnt++)
00664                    continue;
00665    if (pos)
00666      files_list.insert_before(pos, file);
00667    else
00668      files_list.append(file);
00669 
00670    if (file->is_page())
00671    {
00672          // This file is also a page
00673          // Count its number
00674       int page_num=0;
00675       for(pos=files_list;pos;++pos)
00676       {
00677          GP<File> &f=files_list[pos];
00678          if (f==file)
00679            break;
00680          if (f->is_page())
00681            page_num++;
00682       }
00683 
00684       int i;
00685       page2file.resize(page2file.size());
00686       for(i=page2file.size()-1;i>page_num;i--)
00687          page2file[i]=page2file[i-1];
00688       page2file[page_num]=file;
00689       for(i=page_num;i<page2file.size();i++)
00690          page2file[i]->page_num=i;
00691    }
00692    return pos_num;
00693 }
00694 
00695 void
00696 DjVmDir::delete_file(const GUTF8String &id)
00697 {
00698    DEBUG_MSG("Deleting file with id='" << (const char *)id << "'\n");
00699    DEBUG_MAKE_INDENT(3);
00700 
00701    GCriticalSectionLock lock((GCriticalSection *) &class_lock);
00702    
00703    for(GPosition pos=files_list;pos;++pos)
00704    {
00705       GP<File> & f=files_list[pos];
00706       if (id == f->id)
00707       {
00708          name2file.del(f->name);
00709          id2file.del(f->id);
00710          title2file.del(f->title);
00711          if (f->is_page())
00712          {
00713             for(int page=0;page<page2file.size();page++)
00714             {
00715                if (page2file[page]==f)
00716                {
00717                   int i;
00718                   for(i=page;i<page2file.size()-1;i++)
00719                      page2file[i]=page2file[i+1];
00720                   page2file.resize(page2file.size()-2);
00721                   for(i=page;i<page2file.size();i++)
00722                      page2file[i]->page_num=i;
00723                   break;
00724                }
00725             }
00726          }
00727          files_list.del(pos);
00728          break;
00729       }
00730    }
00731 }
00732 
00733 void
00734 DjVmDir::set_file_name(const GUTF8String &id, const GUTF8String &name)
00735 {
00736    DEBUG_MSG("DjVmDir::set_file_name(): id='" << id << "', name='" << name << "'\n");
00737    DEBUG_MAKE_INDENT(3);
00738    
00739    GCriticalSectionLock lock((GCriticalSection *) &class_lock);
00740 
00741    GPosition pos;
00742    
00743       // First see, if the name is unique
00744    for(pos=files_list;pos;++pos)
00745    {
00746       GP<File> file=files_list[pos];
00747       if (file->id!=id && file->name==name)
00748         G_THROW( ERR_MSG("DjVmDir.name_in_use") "\t" + GUTF8String(name));
00749    }
00750 
00751       // Check if ID is valid
00752    if (!id2file.contains(id, pos))
00753       G_THROW( ERR_MSG("DjVmDir.no_info") "\t" + GUTF8String(id));
00754    GP<File> file=id2file[pos];
00755    name2file.del(file->name);
00756    file->name=name;
00757    name2file[name]=file;
00758 }
00759 
00760 void
00761 DjVmDir::set_file_title(const GUTF8String &id, const GUTF8String &title)
00762 {
00763    DEBUG_MSG("DjVmDir::set_file_title(): id='" << id << "', title='" << title << "'\n");
00764    DEBUG_MAKE_INDENT(3);
00765    
00766    GCriticalSectionLock lock((GCriticalSection *) &class_lock);
00767 
00768    GPosition pos;
00769    
00770       // First see, if the title is unique
00771    for(pos=files_list;pos;++pos)
00772    {
00773       GP<File> file=files_list[pos];
00774       if (file->id!=id && file->title==title)
00775         G_THROW( ERR_MSG("DjVmDir.title_in_use") "\t" + GUTF8String(title));
00776    }
00777 
00778       // Check if ID is valid
00779    if (!id2file.contains(id, pos))
00780       G_THROW( ERR_MSG("DjVmDir.no_info") "\t" + GUTF8String(id));
00781    GP<File> file=id2file[pos];
00782    title2file.del(file->title);
00783    file->title=title;
00784    title2file[title]=file;
00785 }
00786 
00787 GPList<DjVmDir::File>
00788 DjVmDir::resolve_duplicates(const bool save_as_bundled)
00789 {
00790   GCriticalSectionLock lock((GCriticalSection *) &class_lock);
00791   // Make sure all the filenames are unique.
00792   GPosition pos;
00793   GMap<GUTF8String,void *> save_map;
00794   GMap<GUTF8String,GPList<DjVmDir::File> > conflicts;
00795   for(pos=files_list;pos;++pos)
00796   {
00797     const GUTF8String save_name=files_list[pos]->check_save_name(save_as_bundled).downcase();
00798     if(save_map.contains(save_name))
00799     {
00800       conflicts[save_name].append(files_list[pos]);
00801     }else
00802     {
00803       save_map[save_name]=0;
00804     }
00805   }
00806   for(pos=conflicts;pos;++pos)
00807   {
00808     const GUTF8String &save_name=conflicts.key(pos);
00809     const int dot=save_name.rsearch('.',0);
00810     GPList<DjVmDir::File> &cfiles=conflicts[pos];
00811     int count=1;
00812     for(GPosition qpos=cfiles;qpos;++qpos)
00813     {
00814       GUTF8String new_name=cfiles[qpos]->get_load_name();
00815       if((new_name != GUTF8String(GNativeString(new_name)))
00816         ||conflicts.contains(new_name))
00817       {
00818         do
00819         {
00820           new_name=(dot<0)
00821             ?(save_name+"-"+GUTF8String(count++))
00822             :(save_name.substr(0,dot)+"-"+GUTF8String(count++)+
00823               save_name.substr(dot,(unsigned int)(-1)));
00824         } while(save_map.contains(new_name.downcase()));
00825       }
00826       cfiles[qpos]->set_save_name(new_name);
00827       save_map[new_name]=0;
00828     }
00829   }
00830   return files_list;
00831 }
00832 
00833 
00834 #ifdef HAVE_NAMESPACES
00835 }
00836 # ifndef NOT_USING_DJVU_NAMESPACE
00837 using namespace DJVU;
00838 # endif
00839 #endif

kviewshell

Skip menu "kviewshell"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members

API Reference

Skip menu "API Reference"
  • kviewshell
Generated for API Reference by doxygen 1.5.9
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal