00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057 #ifdef HAVE_CONFIG_H
00058 # include "config.h"
00059 #endif
00060 #if NEED_GNUG_PRAGMAS
00061 # pragma implementation
00062 #endif
00063
00064
00065
00066
00067
00068
00069
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
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
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
00106
00107
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
00122
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
00137
00138
00139 int
00140 IFFByteStream::check_id(const char *id)
00141 {
00142 int i;
00143
00144 for (i=0; i<4; i++)
00145 if (id[i]<0x20 || id[i]>0x7e)
00146 return -1;
00147
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
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
00158 return 0;
00159 }
00160
00161
00162
00163
00164
00165
00166 int
00167 IFFByteStream::get_chunk(GUTF8String &chkid, int *rawoffsetptr, int *rawsizeptr)
00168 {
00169 int bytes;
00170 char buffer[8];
00171
00172
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
00180 if (seekto > offset)
00181 {
00182 bs->seek(seekto);
00183 offset = seekto;
00184 }
00185
00186
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
00198 int rawoffset = offset;
00199
00200
00201
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
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
00235 int composite = check_id(buffer);
00236 if (composite < 0)
00237 G_THROW( ERR_MSG("IFFByteStream.corrupt_id") );
00238
00239
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
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
00280 ctx = nctx;
00281 chkid = GUTF8String(ctx->idOne, 4);
00282 if (composite)
00283 chkid = chkid + ":" + GUTF8String(ctx->idTwo, 4);
00284
00285
00286 if (rawoffsetptr)
00287 *rawoffsetptr = rawoffset;
00288 if (rawsizeptr)
00289 *rawsizeptr = ( ctx->offEnd - rawoffset + 1) & ~0x1;
00290 return size;
00291 }
00292
00293
00294
00295
00296
00297
00298 void
00299 IFFByteStream::put_chunk(const char *chkid, int insert_magic)
00300 {
00301 int bytes;
00302 char buffer[8];
00303
00304
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
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
00318 assert(seekto <= offset);
00319 memset((void*)buffer, 0, 8);
00320 if (offset & 1)
00321 offset += bs->write((void*)&buffer[4], 1);
00322
00323
00324 if (insert_magic)
00325 {
00326
00327
00328
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
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
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
00374 ctx = nctx;
00375 }
00376
00377
00378
00379 void
00380 IFFByteStream::close_chunk()
00381 {
00382
00383 if (!ctx)
00384 G_THROW( ERR_MSG("IFFByteStream.cant_close") );
00385
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
00400 seekto = ctx->offEnd;
00401
00402 IFFContext *octx = ctx;
00403 ctx = octx->next;
00404 assert(ctx==0 || ctx->bComposite);
00405 delete octx;
00406 }
00407
00408
00409
00410
00411
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
00424
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
00439
00440
00441 void
00442 IFFByteStream::full_id(GUTF8String &chkid)
00443 {
00444 short_id(chkid);
00445 if (ctx->bComposite)
00446 return;
00447
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
00460
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
00468 if (seekto > offset) {
00469 bs->seek(seekto);
00470 offset = seekto;
00471 }
00472
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
00478 size_t bytes = bs->read(buffer, size);
00479 offset += bytes;
00480 return bytes;
00481 }
00482
00483
00484
00485
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
00500
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