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

kviewshell

IFFByteStream.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: IFFByteStream.cpp,v 1.10 2004/08/06 15:11:29 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 // -- Implementation of IFFByteStream
00065 // - Author: Leon Bottou, 06/1998
00066 
00067 // From: Leon Bottou, 1/31/2002
00068 // This has been changed by Lizardtech to fit better 
00069 // with their re-implementation of ByteStreams.
00070 
00071 #include <assert.h>
00072 #include "IFFByteStream.h"
00073 
00074 
00075 #ifdef HAVE_NAMESPACES
00076 namespace DJVU {
00077 # ifdef NOT_DEFINED // Just to fool emacs c++ mode
00078 }
00079 #endif
00080 #endif
00081 
00082 
00083 // Constructor
00084 IFFByteStream::IFFByteStream(const GP<ByteStream> &xbs,const int xpos)
00085 : ByteStream::Wrapper(xbs), has_magic(false), ctx(0), dir(0)
00086 {
00087   offset = seekto = xpos;
00088 }
00089 
00090 // Destructor
00091 IFFByteStream::~IFFByteStream()
00092 {
00093   while (ctx)
00094     close_chunk();
00095 }
00096 
00097 GP<IFFByteStream>
00098 IFFByteStream::create(const GP<ByteStream> &bs)
00099 {
00100   const int pos=bs->tell();
00101   return new IFFByteStream(bs,pos);
00102 }
00103 
00104 
00105 // IFFByteStream::ready
00106 // -- indicates if bytestream is ready for reading
00107 //    returns number of bytes available
00108 
00109 int 
00110 IFFByteStream::ready()
00111 {
00112   if (ctx && dir < 0)
00113     return ctx->offEnd - offset;
00114   else if (ctx)
00115     return 1;
00116   else
00117     return 0;
00118 }
00119 
00120 
00121 // IFFByteStream::composite
00122 // -- indicates if bytestream is ready for putting or getting chunks
00123 
00124 int 
00125 IFFByteStream::composite()
00126 {
00127   if (ctx && !ctx->bComposite)
00128     return 0;
00129   else
00130     return 1;
00131 }
00132 
00133 
00134 
00135 
00136 // IFFByteStream::check_id
00137 // -- checks if an id is legal
00138 
00139 int 
00140 IFFByteStream::check_id(const char *id)
00141 {
00142   int i;
00143   // check absence of null bytes
00144   for (i=0; i<4; i++)
00145     if (id[i]<0x20 || id[i]>0x7e)
00146       return -1;
00147   // check composite chunks
00148   static char *szComposite[] = { "FORM", "LIST", "PROP", "CAT ", 0 };
00149   for (i=0; szComposite[i]; i++) 
00150     if (!memcmp(id, szComposite[i], 4))
00151       return 1;
00152   // check reserved chunks
00153   static char *szReserved[] = { "FOR", "LIS", "CAT", 0 };
00154   for (i=0; szReserved[i]; i++) 
00155     if (!memcmp(id, szReserved[i], 3) && id[3]>='1' && id[3]<='9')
00156       return -1;
00157   // regular chunk
00158   return 0;
00159 }
00160 
00161 
00162 
00163 // IFFByteStream::get_chunk
00164 // -- get next chunk header
00165 
00166 int  
00167 IFFByteStream::get_chunk(GUTF8String &chkid, int *rawoffsetptr, int *rawsizeptr)
00168 {
00169   int bytes;
00170   char buffer[8];
00171   
00172   // Check that we are allowed to read a chunk
00173   if (dir > 0)
00174     G_THROW( ERR_MSG("IFFByteStream.read_write") );
00175   if (ctx && !ctx->bComposite)
00176     G_THROW( ERR_MSG("IFFByteStream.not_ready") );
00177   dir = -1;
00178 
00179   // Seek to end of previous chunk if necessary
00180   if (seekto > offset)
00181     {
00182       bs->seek(seekto);
00183       offset = seekto;
00184     }
00185 
00186   // Skip padding byte
00187   if (ctx && offset == ctx->offEnd)
00188     return 0;
00189   if (offset & 1)
00190     {
00191       bytes = bs->read( (void*)buffer, 1);
00192       if (bytes==0 && !ctx)
00193         return 0;
00194       offset += bytes;
00195     }
00196   
00197   // Record raw offset
00198   int rawoffset = offset;
00199   
00200   // Read chunk id (skipping magic sequences inserted here to make
00201   // DjVu files recognizable.)
00202   for(;;)
00203   {
00204     if (ctx && offset == ctx->offEnd)
00205       return 0;
00206     if (ctx && offset+4 > ctx->offEnd)
00207       G_THROW( ERR_MSG("IFFByteStream.corrupt_end") );
00208     bytes = bs->readall( (void*)&buffer[0], 4);
00209     offset = seekto = offset + bytes;
00210     if (bytes==0 && !ctx)
00211       return 0;
00212     if (bytes != 4)
00213       G_THROW( ByteStream::EndOfFile );
00214     if(buffer[0] != 0x41 || buffer[1] != 0x54 ||
00215        buffer[2] != 0x26 || buffer[3] != 0x54 )
00216       break;
00217     has_magic=true;
00218   }
00219   
00220   // Read chunk size
00221   if (ctx && offset+4 > ctx->offEnd)
00222     G_THROW( ERR_MSG("IFFByteStream.corrupt_end2") );
00223   bytes = bs->readall( (void*)&buffer[4], 4);
00224   offset = seekto = offset + bytes;
00225   if (bytes != 4)
00226     G_THROW( ByteStream::EndOfFile );
00227   long size = ((unsigned char)buffer[4]<<24) |
00228               ((unsigned char)buffer[5]<<16) |
00229               ((unsigned char)buffer[6]<<8)  |
00230               ((unsigned char)buffer[7]);
00231   if (ctx && offset+size > ctx->offEnd)
00232     G_THROW( ERR_MSG("IFFByteStream.corrupt_mangled") );
00233   
00234   // Check if composite 
00235   int composite = check_id(buffer);
00236   if (composite < 0)
00237     G_THROW( ERR_MSG("IFFByteStream.corrupt_id") );
00238   
00239   // Read secondary id of composite chunk
00240   if (composite)
00241   {
00242     if (ctx && ctx->offEnd<offset+4)
00243       G_THROW( ERR_MSG("IFFByteStream.corrupt_header") );
00244     bytes = bs->readall( (void*)&buffer[4], 4);
00245     offset += bytes;
00246     if (bytes != 4)
00247       G_THROW( ByteStream::EndOfFile );
00248     if (check_id(&buffer[4]))
00249       G_THROW( ERR_MSG("IFFByteStream.corrupt_2nd_id") );
00250   }
00251 
00252   // Create context record
00253   IFFContext *nctx = new IFFContext;
00254   G_TRY
00255   {
00256     nctx->next = ctx;
00257     nctx->offStart = seekto;
00258     nctx->offEnd = seekto + size;
00259     if (composite)
00260     {
00261       memcpy( (void*)(nctx->idOne), (void*)&buffer[0], 4);
00262       memcpy( (void*)(nctx->idTwo), (void*)&buffer[4], 4);
00263       nctx->bComposite = 1;
00264     }
00265     else
00266     {
00267       memcpy( (void*)(nctx->idOne), (void*)&buffer[0], 4);
00268       memset( (void*)(nctx->idTwo), 0, 4);
00269       nctx->bComposite = 0;
00270     }
00271   }
00272   G_CATCH_ALL
00273   {
00274     delete nctx;
00275     G_RETHROW;
00276   }
00277   G_ENDCATCH;
00278   
00279   // Install context record
00280   ctx = nctx;
00281   chkid = GUTF8String(ctx->idOne, 4);
00282   if (composite)
00283     chkid = chkid + ":" + GUTF8String(ctx->idTwo, 4);
00284 
00285   // Return
00286   if (rawoffsetptr)
00287     *rawoffsetptr = rawoffset;
00288   if (rawsizeptr)
00289     *rawsizeptr = ( ctx->offEnd - rawoffset + 1) & ~0x1;
00290   return size;
00291 }
00292 
00293 
00294 
00295 // IFFByteStream::put_chunk
00296 // -- write new chunk header
00297 
00298 void  
00299 IFFByteStream::put_chunk(const char *chkid, int insert_magic)
00300 {
00301   int bytes;
00302   char buffer[8];
00303 
00304   // Check that we are allowed to write a chunk
00305   if (dir < 0)
00306     G_THROW( ERR_MSG("IFFByteStream.read_write") );
00307   if (ctx && !ctx->bComposite)
00308     G_THROW( ERR_MSG("IFFByteStream.not_ready2") );
00309   dir = +1;
00310 
00311   // Check primary id
00312   int composite = check_id(chkid);
00313   if ((composite<0) || (composite==0 && chkid[4])
00314       || (composite && (chkid[4]!=':' || check_id(&chkid[5]) || chkid[9])) )
00315     G_THROW( ERR_MSG("IFFByteStream.bad_chunk") );
00316 
00317   // Write padding byte
00318   assert(seekto <= offset);
00319   memset((void*)buffer, 0, 8);
00320   if (offset & 1)
00321     offset += bs->write((void*)&buffer[4], 1);
00322 
00323   // Insert magic to make this file recognizable as DjVu
00324   if (insert_magic)
00325   {
00326     // Don't change the way you do the file magic!
00327     // I rely on these bytes letters in some places
00328     // (like DjVmFile.cpp and djvm.cpp) -- eaf
00329     buffer[0]=0x41;
00330     buffer[1]=0x54;
00331     buffer[2]=0x26;
00332     buffer[3]=0x54;
00333     offset += bs->writall((void*)&buffer[0], 4);
00334   }
00335 
00336   // Write chunk header
00337   memcpy((void*)&buffer[0], (void*)&chkid[0], 4);
00338   bytes = bs->writall((void*)&buffer[0], 8);
00339   offset = seekto = offset + bytes;
00340   if (composite)
00341   {
00342     memcpy((void*)&buffer[4], (void*)&chkid[5], 4);
00343     bytes = bs->writall((void*)&buffer[4], 4);
00344     offset = offset + bytes;    
00345   }
00346 
00347   // Create new context record
00348   IFFContext *nctx = new IFFContext;
00349   G_TRY
00350   {
00351     nctx->next = ctx;
00352     nctx->offStart = seekto;
00353     nctx->offEnd = 0;
00354     if (composite)
00355     {
00356       memcpy( (void*)(nctx->idOne), (void*)&buffer[0], 4);
00357       memcpy( (void*)(nctx->idTwo), (void*)&buffer[4], 4);
00358       nctx->bComposite = 1;
00359     }
00360     else
00361     {
00362       memcpy( (void*)(nctx->idOne), (void*)&buffer[0], 4);
00363       memset( (void*)(nctx->idTwo), 0, 4);
00364       nctx->bComposite = 0;
00365     }
00366   }
00367   G_CATCH_ALL
00368   {
00369     delete nctx;
00370     G_RETHROW;
00371   }
00372   G_ENDCATCH; 
00373   // Install context record and leave
00374   ctx = nctx;
00375 }
00376 
00377 
00378 
00379 void 
00380 IFFByteStream::close_chunk()
00381 {
00382   // Check that this is ok
00383   if (!ctx)
00384     G_THROW( ERR_MSG("IFFByteStream.cant_close") );
00385   // Patch size field in new chunk
00386   if (dir > 0)
00387     {
00388       ctx->offEnd = offset;
00389       long size = ctx->offEnd - ctx->offStart;
00390       char buffer[4];
00391       buffer[0] = (unsigned char)(size>>24);
00392       buffer[1] = (unsigned char)(size>>16);
00393       buffer[2] = (unsigned char)(size>>8);
00394       buffer[3] = (unsigned char)(size);
00395       bs->seek(ctx->offStart - 4);
00396       bs->writall((void*)buffer, 4);
00397       bs->seek(offset);
00398     }
00399   // Arrange for reader to seek at next chunk
00400   seekto = ctx->offEnd;
00401   // Remove ctx record
00402   IFFContext *octx = ctx;
00403   ctx = octx->next;
00404   assert(ctx==0 || ctx->bComposite);
00405   delete octx;
00406 }
00407 
00408 // This is the same as above, but adds a seek to the close
00409 // Otherwise an EOF in this chunk won't be reported until we
00410 // try to open the next chunk, which makes error recovery
00411 // very difficult.
00412 void  
00413 IFFByteStream::seek_close_chunk(void)
00414 {
00415   close_chunk();
00416   if ((dir <= 0)&&((!ctx)||(ctx->bComposite))&&(seekto > offset))
00417   {
00418     bs->seek(seekto);
00419     offset = seekto;
00420   }
00421 }
00422 
00423 // IFFByteStream::short_id
00424 // Returns the id of the current chunk
00425 
00426 void 
00427 IFFByteStream::short_id(GUTF8String &chkid)
00428 {
00429   if (!ctx)
00430     G_THROW( ERR_MSG("IFFByteStream.no_chunk_id") );
00431   if (ctx->bComposite)
00432     chkid = GUTF8String(ctx->idOne, 4) + ":" + GUTF8String(ctx->idTwo, 4);
00433   else
00434     chkid = GUTF8String(ctx->idOne, 4);
00435 }
00436 
00437 
00438 // IFFByteStream::full_id
00439 // Returns the full chunk id of the current chunk
00440 
00441 void 
00442 IFFByteStream::full_id(GUTF8String &chkid)
00443 {
00444   short_id(chkid);
00445   if (ctx->bComposite)
00446     return;
00447   // Search parent FORM or PROP chunk.
00448   for (IFFContext *ct = ctx->next; ct; ct=ct->next)
00449     if (memcmp(ct->idOne, "FOR", 3)==0 || 
00450         memcmp(ct->idOne, "PRO", 3)==0  )
00451       {
00452         chkid = GUTF8String(ct->idTwo, 4) + "." + chkid;
00453         break;
00454       }
00455 }
00456 
00457 
00458 
00459 // IFFByteStream::read
00460 // -- read bytes from IFF file chunk
00461 
00462 size_t 
00463 IFFByteStream::read(void *buffer, size_t size)
00464 {
00465   if (! (ctx && dir < 0))
00466     G_THROW( ERR_MSG("IFFByteStream.not_ready3") );
00467   // Seek if necessary
00468   if (seekto > offset) {
00469     bs->seek(seekto);
00470     offset = seekto;
00471   }
00472   // Ensure that read does not extend beyond chunk
00473   if (offset > ctx->offEnd)
00474     G_THROW( ERR_MSG("IFFByteStream.bad_offset") );
00475   if (offset + (long)size >  ctx->offEnd)
00476     size = (size_t) (ctx->offEnd - offset);
00477   // Read bytes
00478   size_t bytes = bs->read(buffer, size);
00479   offset += bytes;
00480   return bytes;
00481 }
00482 
00483 
00484 // IFFByteStream::write
00485 // -- write bytes to IFF file chunk
00486 
00487 size_t 
00488 IFFByteStream::write(const void *buffer, size_t size)
00489 {
00490   if (! (ctx && dir > 0))
00491     G_THROW( ERR_MSG("IFFByteStream.not_ready4") );
00492   if (seekto > offset)
00493     G_THROW( ERR_MSG("IFFByteStream.cant_write") );
00494   size_t bytes = bs->write(buffer, size);
00495   offset += bytes;
00496   return bytes;
00497 }
00498 
00499 // IFFByteStream::tell
00500 // -- tell position
00501 
00502 long 
00503 IFFByteStream::tell() const
00504 {
00505   return (seekto>offset)?seekto:offset;
00506 }
00507 
00508 bool
00509 IFFByteStream::compare(IFFByteStream &iff)
00510 {
00511   bool retval=(&iff == this);
00512   if(!retval)
00513   {
00514     GUTF8String chkid1, chkid2;
00515     int size;
00516     while((size=get_chunk(chkid1)) == iff.get_chunk(chkid2))
00517     {
00518       if(chkid1 != chkid2)
00519       {
00520         break;
00521       }
00522       if(!size)
00523       {
00524         retval=true;
00525         break;
00526       }
00527       char buf[4096];
00528       int len;
00529       while((len=read(buf,sizeof(buf))))
00530       {
00531         int s=0;
00532         char buf2[sizeof(buf)];
00533         while(s<len)
00534         {
00535           const int i=iff.read(buf2+s,len-s);
00536           if(!i)
00537             break;
00538           s+=i;
00539         }
00540         if((s != len)||memcmp(buf,buf2,len))
00541           break;
00542       }
00543       if(len)
00544         break;
00545       iff.close_chunk();
00546       close_chunk();
00547     }
00548   }
00549   return retval;
00550 }
00551 
00552 
00553 #ifdef HAVE_NAMESPACES
00554 }
00555 # ifndef NOT_USING_DJVU_NAMESPACE
00556 using namespace DJVU;
00557 # endif
00558 #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