Logo Search packages:      
Sourcecode: djvulibre version File versions

void DjVuDocEditor::save_as ( const GURL where,
bool  bundled 
) [virtual]

Saves the document.

Reimplemented from DjVuDocument.

Definition at line 1900 of file DjVuDocEditor.cpp.

References GURL::base(), IFFByteStream::close_chunk(), ByteStream::copy(), DataPool::create(), ByteStream::create(), DjVmDir::encode(), IFFByteStream::flush(), DjVuDocument::get_djvm_doc(), DjVmDir::get_files_num(), DjVmDir::get_pages_num(), DjVuDocument::get_pages_num(), DjVuPort::get_portcaster(), get_thumbnails_num(), GURL::is_empty(), DataPool::load_file(), DjVuDocument::needs_compression(), DjVmDir::page_to_file(), DjVuDocument::page_to_url(), IFFByteStream::put_chunk(), remove_thumbnails(), DjVuPortcaster::request_data(), DjVmDir::resolve_duplicates(), and ByteStream::writall().

Referenced by save().

{
   DEBUG_MSG("DjVuDocEditor::save_as(): where='" << where << "'\n");
   DEBUG_MAKE_INDENT(3);

      // First see if we need to generate (or just reshuffle) thumbnails...
      // If we have an icon for every page, we will just call
      // file_thumbnails(), which will update DjVmDir and will create
      // the actual bundles with thumbnails (very fast)
      // Otherwise we will remove the thumbnails completely because
      // we really don't want to deal with documents, which have only
      // some of their pages thumbnailed.
   if (get_thumbnails_num()==get_pages_num())
   {
     file_thumbnails();
   }else
   { 
     remove_thumbnails();
   }

   GURL save_doc_url;

   if (where.is_empty())
   {
         // Assume, that we just want to 'save'. Check, that it's possible
         // and proceed.
      bool can_be_saved_bundled=orig_doc_type==BUNDLED ||
                                orig_doc_type==OLD_BUNDLED ||
                                orig_doc_type==SINGLE_PAGE ||
                                orig_doc_type==OLD_INDEXED && orig_doc_pages==1;
      if ((bundled ^ can_be_saved_bundled)!=0)
         G_THROW( ERR_MSG("DjVuDocEditor.cant_save2") );
      save_doc_url=doc_url;
   } else
   {
      save_doc_url=where;
   }

   int save_doc_type=bundled ? BUNDLED : INDIRECT;

   clean_files_map();

   GCriticalSectionLock lock(&files_lock);

   DjVuPortcaster * pcaster=DjVuPort::get_portcaster();

      // First consider saving in SINGLE_FILE format (one file)
   if(needs_compression())
   {
     DEBUG_MSG("Compressing on output\n");
     remove_thumbnails();
     if(! djvu_compress_codec)
     {
       G_THROW( ERR_MSG("DjVuDocEditor.no_codec") );
     }
     const GP<DjVmDoc> doc(get_djvm_doc());
     GP<ByteStream> mbs(ByteStream::create());
     doc->write(mbs);
     mbs->flush();
     mbs->seek(0,SEEK_SET);
     djvu_compress_codec(mbs,save_doc_url,(!(const DjVmDir *)djvm_dir)||(djvm_dir->get_files_num()==1)||(save_doc_type!=INDIRECT));
     files_map.empty();
     doc_url=GURL();
   }else
   {
     if (djvm_dir->get_files_num()==1)
     {
       // Here 'bundled' has no effect: we will save it as one page.
       DEBUG_MSG("saving one file...\n");
       GURL file_url=page_to_url(0);
       const GUTF8String file_id(djvm_dir->page_to_file(0)->get_load_name());
       GP<DataPool> file_pool;
       GPosition pos=files_map.contains(file_id);
       if (pos)
       {
         const GP<File> file_rec(files_map[pos]);
         if (file_rec->pool && (!file_rec->file ||
                                !file_rec->file->is_modified()))
         {
           file_pool=file_rec->pool;
         }else if (file_rec->file)
         {
           file_pool=file_rec->file->get_djvu_data(false);
         }
       }
       // Even if file has not been modified (pool==0) we still want
       // to save it.
       if (!file_pool)
         file_pool=pcaster->request_data(this, file_url);
       if (file_pool)
       {
         DEBUG_MSG("Saving '" << file_url << "' to '" << save_doc_url << "'\n");
         DataPool::load_file(save_doc_url);
         const GP<ByteStream> gstr_out(ByteStream::create(save_doc_url, "wb"));
         ByteStream &str_out=*gstr_out;
         str_out.writall(octets, 4);
         const GP<ByteStream> str_in(file_pool->get_stream());
         str_out.copy(*str_in);
       }

       // Update the document's DataPool (to save memory)
       const GP<DjVmDoc> doc(get_djvm_doc());
       const GP<ByteStream> gstr=ByteStream::create();// One page: we can do it in the memory
       doc->write(gstr);
       gstr->seek(0, SEEK_SET);
       const GP<DataPool> pool(DataPool::create(gstr));
       doc_pool=pool;
       init_data_pool=pool;

         // Also update DjVmDir (to reflect changes in offsets)
       djvm_dir=doc->get_djvm_dir();
     } else if (save_doc_type==INDIRECT)
     {
       DEBUG_MSG("Saving in INDIRECT format to '" << save_doc_url << "'\n");
       bool save_only_modified=!(save_doc_url!=doc_url || save_doc_type!=orig_doc_type);
       GPList<DjVmDir::File> xfiles_list=djvm_dir->resolve_duplicates(false);
       const GURL codebase=save_doc_url.base();
       int pages_num=djvm_dir->get_pages_num();
       GMap<GUTF8String, GUTF8String> map;
       // First go thru the pages
       for(int page_num=0;page_num<pages_num;page_num++)
       {
         const GUTF8String id(djvm_dir->page_to_file(page_num)->get_load_name());
         save_file(id, codebase, save_only_modified, map);
       }
       // Next go thru thumbnails and similar stuff
       GPosition pos;
       for(pos=xfiles_list;pos;++pos)
         save_file(xfiles_list[pos]->get_load_name(), codebase, save_only_modified, map);

         // Finally - save the top-level index file
       for(pos=xfiles_list;pos;++pos)
       {
         const GP<DjVmDir::File> file(xfiles_list[pos]);
         file->offset=0;
         file->size=0;
       }
       DataPool::load_file(save_doc_url);
       const GP<ByteStream> gstr(ByteStream::create(save_doc_url, "wb"));
       const GP<IFFByteStream> giff(IFFByteStream::create(gstr));
       IFFByteStream &iff=*giff;

       iff.put_chunk("FORM:DJVM", 1);
       iff.put_chunk("DIRM");
       djvm_dir->encode(giff->get_bytestream());
       iff.close_chunk();
       iff.close_chunk();
       iff.flush();

       // Update the document data pool (not required, but will save memory)
       doc_pool=DataPool::create(save_doc_url);
       init_data_pool=doc_pool;

       // No reason to update DjVmDir as for this format it doesn't
       // contain DJVM offsets
     } else if (save_doc_type==BUNDLED || save_doc_type==OLD_BUNDLED)
     {
        DEBUG_MSG("Saving in BUNDLED format to '" << save_doc_url << "'\n");

         // Can't be very smart here. Simply overwrite the file.
        const GP<DjVmDoc> doc(get_djvm_doc());
        DataPool::load_file(save_doc_url);
        const GP<ByteStream> gstr(ByteStream::create(save_doc_url, "wb"));
        doc->write(gstr);
        gstr->flush();

         // Update the document data pool (not required, but will save memory)
        doc_pool=DataPool::create(save_doc_url);
        init_data_pool=doc_pool;

         // Also update DjVmDir (to reflect changes in offsets)
        djvm_dir=doc->get_djvm_dir();
     } else
     {
       G_THROW( ERR_MSG("DjVuDocEditor.cant_save") );
     }

        // Now, after we have saved the document w/o any error, detach DataPools,
        // which are in the 'File's list to save memory. Detach everything.
        // Even in the case when File->file is non-zero. If File->file is zero,
        // remove the item from the list at all. If it's non-zero, it has
        // to stay there because by definition files_map[] contains the list
        // of all active files and customized DataPools
        //
        // In addition to it, look thru all active files and change their URLs
        // to reflect changes in the document's URL (if there was a change)
        // Another reason why file's URLs must be changed is that we may have
        // saved the document in a different format, which changes the rules
        // of file url composition.
     for(GPosition pos=files_map;pos;)
     {
        const GP<File> file_rec(files_map[pos]);
        file_rec->pool=0;
        if (file_rec->file==0)
        {
         GPosition this_pos=pos;
         ++pos;
         files_map.del(this_pos);
        } else
        {
            // Change the file's url;
         if (doc_url!=save_doc_url ||
             orig_doc_type!=save_doc_type)
            if (save_doc_type==BUNDLED)
               file_rec->file->move(save_doc_url);
            else file_rec->file->move(save_doc_url.base());
         ++pos;
        }
     }

   }
   orig_doc_type=save_doc_type;
   doc_type=save_doc_type;

   if (doc_url!=save_doc_url)
   {
     // Also update document's URL (we moved, didn't we?)
     doc_url=save_doc_url;
     init_url=save_doc_url;
   }
}


Generated by  Doxygen 1.6.0   Back to index