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 #include "GIFFManager.h"
00065 #include "GException.h"
00066 #include "debug.h"
00067
00068
00069 #ifdef HAVE_NAMESPACES
00070 namespace DJVU {
00071 # ifdef NOT_DEFINED // Just to fool emacs c++ mode
00072 }
00073 #endif
00074 #endif
00075
00076
00077 GIFFChunk::~GIFFChunk(void) {}
00078
00079 GIFFManager::~GIFFManager(void) {}
00080
00081 GP<GIFFManager>
00082 GIFFManager::create(void)
00083 {
00084 GIFFManager *iff=new GIFFManager();
00085 GP<GIFFManager> retval=iff;
00086 iff->init();
00087 return retval;
00088 }
00089
00090 GP<GIFFManager>
00091 GIFFManager::create(const GUTF8String &name)
00092 {
00093 GIFFManager *iff=new GIFFManager();
00094 GP<GIFFManager> retval=iff;
00095 iff->init(name);
00096 return retval;
00097 }
00098
00099 void
00100 GIFFChunk::set_name(GUTF8String name)
00101 {
00102 DEBUG_MSG("GIFFChunk::set_name(): name='" << name << "'\n");
00103 DEBUG_MAKE_INDENT(3);
00104
00105 const int colon=name.search(':');
00106 if(colon>=0)
00107 {
00108 type=name.substr(0,colon);
00109 name=name.substr(colon+1,(unsigned int)-1);
00110 if(name.search(':')>=0)
00111 G_THROW( ERR_MSG("GIFFManager.one_colon") );
00112 }
00113
00114 DEBUG_MSG("auto-setting type to '" << type << "'\n");
00115
00116 if (name.contains(".[]")>=0)
00117 G_THROW( ERR_MSG("GIFFManager.bad_char") );
00118
00119 strncpy(GIFFChunk::name, (const char *)name, 4);
00120 GIFFChunk::name[4]=0;
00121 for(int i=strlen(GIFFChunk::name);i<4;i++)
00122 GIFFChunk::name[i]=' ';
00123 }
00124
00125 bool
00126 GIFFChunk::check_name(GUTF8String name)
00127 {
00128 GUTF8String type;
00129 const int colon=name.search(':');
00130 if(colon>=0)
00131 {
00132 type=name.substr(0,colon);
00133 name=name.substr(colon+1,(unsigned int)-1);
00134 }
00135
00136 const GUTF8String sname=(name.substr(0,4)+" ").substr(0,4);
00137
00138 DEBUG_MSG("GIFFChunk::check_name(): type='" << type << "' name='" << sname << "'\n");
00139 return (type==GIFFChunk::type || !type.length() && GIFFChunk::type=="FORM")
00140 && sname==GIFFChunk::name;
00141 }
00142
00143 void
00144 GIFFChunk::save(IFFByteStream & istr, bool use_trick)
00145 {
00146 DEBUG_MSG("GIFFChunk::save(): saving chunk '" << get_full_name() << "'\n");
00147 DEBUG_MAKE_INDENT(3);
00148
00149 if (is_container())
00150 {
00151 istr.put_chunk(get_full_name(), use_trick);
00152 if (chunks.size())
00153 {
00154 GPosition pos;
00155 for(pos=chunks;pos;++pos)
00156 if (chunks[pos]->get_type()=="PROP")
00157 chunks[pos]->save(istr);
00158 for(pos=chunks;pos;++pos)
00159 if (chunks[pos]->get_type()!="PROP")
00160 chunks[pos]->save(istr);
00161 } else
00162 {
00163 DEBUG_MSG("but it's empty => saving empty container.\n");
00164 }
00165 istr.close_chunk();
00166 } else
00167 {
00168 istr.put_chunk(get_name(), use_trick);
00169 istr.get_bytestream()->writall((const char *) data, data.size());
00170 istr.close_chunk();
00171 }
00172 }
00173
00174 void
00175 GIFFChunk::add_chunk(const GP<GIFFChunk> & chunk, int position)
00176 {
00177 DEBUG_MSG("GIFFChunk::add_chunk(): Adding chunk to '" << get_name() <<
00178 "' @ position=" << position << "\n");
00179 DEBUG_MAKE_INDENT(3);
00180
00181 if (!type.length())
00182 {
00183 DEBUG_MSG("Converting the parent to FORM\n");
00184 type="FORM";
00185 }
00186
00187 if (chunk->get_type()=="PROP")
00188 {
00189 DEBUG_MSG("Converting the parent to LIST\n");
00190 type="LIST";
00191 }
00192
00193 GPosition pos;
00194 if (position>=0 && chunks.nth(position, pos))
00195 {
00196 chunks.insert_before(pos, chunk);
00197 }else
00198 {
00199 chunks.append(chunk);
00200 }
00201 }
00202
00203 GUTF8String
00204 GIFFChunk::decode_name(const GUTF8String &name, int &number)
00205 {
00206 DEBUG_MSG("GIFFChunk::decode_name(): Checking brackets in name '" << name << "'\n");
00207 DEBUG_MAKE_INDENT(3);
00208
00209 if (name.search('.')>=0)
00210 G_THROW( ERR_MSG("GIFFManager.no_dots") );
00211
00212 number=0;
00213 const int obracket=name.search('[');
00214 GUTF8String short_name;
00215 if (obracket >= 0)
00216 {
00217 const int cbracket=name.search(']',obracket+1);
00218 if (cbracket < 0)
00219 G_THROW( ERR_MSG("GIFFManager.unmatched") );
00220 if (name.length() > (unsigned int)(cbracket+1))
00221 G_THROW( ERR_MSG("GIFFManager.garbage") );
00222
00223 number= name.substr(obracket+1,cbracket-obracket-1).toInt();
00224 short_name=name.substr(0,obracket);
00225 }else
00226 {
00227 short_name=name;
00228 }
00229
00230 const int colon=short_name.search(':');
00231 if (colon>=0)
00232 short_name=short_name.substr(colon+1,(unsigned int)-1);
00233
00234 for(int i=short_name.length();i<4;i++)
00235 short_name.setat(i, ' ');
00236
00237 DEBUG_MSG("short_name='" << short_name << "'\n");
00238 DEBUG_MSG("number=" << number << "\n");
00239
00240 return short_name;
00241 }
00242
00243 void
00244 GIFFChunk::del_chunk(const GUTF8String &name)
00245
00246 {
00247 DEBUG_MSG("GIFFChunk::del_chunk(): Deleting chunk '" << name <<
00248 "' from '" << get_name() << "'\n");
00249 DEBUG_MAKE_INDENT(3);
00250
00251 int number;
00252 const GUTF8String short_name=decode_name(name,number);
00253
00254 GPosition pos=chunks;
00255 for(int num=0;pos;++pos)
00256 {
00257 if ((chunks[pos]->get_name()==short_name)&&(num++ == number))
00258 {
00259 chunks.del(pos);
00260 break;
00261 }
00262 }
00263 if(! pos)
00264 {
00265 G_THROW( ERR_MSG("GIFFManager.no_chunk") "\t"+short_name+"\t"+GUTF8String(number)+"\t"+get_name());
00266 }
00267 }
00268
00269 GP<GIFFChunk>
00270 GIFFChunk::get_chunk(const GUTF8String &name, int * pos_ptr)
00271
00272 {
00273 DEBUG_MSG("GIFFChunk::get_chunk(): Returning chunk '" << name <<
00274 "' from '" << get_name() << "'\n");
00275 DEBUG_MAKE_INDENT(3);
00276
00277 int number;
00278 const GUTF8String short_name=decode_name(name,number);
00279
00280 int num=0;
00281 int pos_num;
00282 GP<GIFFChunk> retval;
00283 GPosition pos;
00284 for(pos=chunks, pos_num=0;pos;++pos, pos_num++)
00285 {
00286 if (chunks[pos]->get_name()==short_name && num++==number)
00287 {
00288 if (pos_ptr)
00289 *pos_ptr=pos_num;
00290 retval=chunks[pos];
00291 break;
00292 }
00293 }
00294 return retval;
00295 }
00296
00297 int
00298 GIFFChunk::get_chunks_number(void)
00299 {
00300 DEBUG_MSG("GIFFChunk::get_chunks_number(): Returning number of chunks '" << name <<
00301 "' in '" << get_name() << "'\n");
00302 DEBUG_MAKE_INDENT(3);
00303 return chunks.size();
00304 }
00305
00306 int
00307 GIFFChunk::get_chunks_number(const GUTF8String &name)
00308 {
00309 DEBUG_MSG("GIFFChunk::get_chunks_number(): Returning number of chunks '" << name <<
00310 "' in '" << get_name() << "'\n");
00311 DEBUG_MAKE_INDENT(3);
00312
00313 if (name.contains("[]")>=0)
00314 G_THROW( ERR_MSG("GIFFManager.no_brackets") );
00315
00316 int number;
00317 GUTF8String short_name=decode_name(name,number);
00318
00319 int num=0;
00320 for(GPosition pos=chunks;pos;++pos)
00321 num+=(chunks[pos]->get_name()==short_name);
00322 return num;
00323 }
00324
00325
00326
00327 void
00328 GIFFManager::add_chunk(GUTF8String parent_name, const GP<GIFFChunk> & chunk,
00329 int pos)
00330
00331
00332
00333
00334 {
00335 DEBUG_MSG("GIFFManager::add_chunk(): Adding chunk to name='" << parent_name << "'\n");
00336 DEBUG_MAKE_INDENT(3);
00337
00338 if (!top_level->get_name().length())
00339 {
00340 if ((!parent_name.length())||(parent_name[0]!='.'))
00341 G_THROW( ERR_MSG("GIFFManager.no_top_name") );
00342 if (parent_name.length() < 2)
00343 {
00344
00345 DEBUG_MSG("since parent_name=='.', making the chunk top-level\n");
00346 if (!chunk->is_container())
00347 G_THROW( ERR_MSG("GIFFManager.no_top_cont") );
00348 top_level=chunk;
00349 return;
00350 }
00351
00352 DEBUG_MSG("Setting the name of the top-level chunk\n");
00353 const int next_dot=parent_name.search('.',1);
00354 if(next_dot>=0)
00355 {
00356 top_level->set_name(parent_name.substr(1,next_dot-1));
00357 }else
00358 {
00359 top_level->set_name(parent_name.substr(1,(unsigned int)-1));
00360 }
00361 }
00362
00363 DEBUG_MSG("top level chunk name='" << top_level->get_name() << "'\n");
00364
00365 if (parent_name.length() && parent_name[0] == '.')
00366 {
00367 int next_dot=parent_name.search('.',1);
00368 if(next_dot<0)
00369 {
00370 next_dot=parent_name.length();
00371 }
00372 GUTF8String top_name=parent_name.substr(1,next_dot-1);
00373 if (!top_level->check_name(top_name))
00374 G_THROW( ERR_MSG("GIFFManager.wrong_name") "\t"+top_name);
00375 parent_name=parent_name.substr(next_dot,(unsigned int)-1);
00376 }
00377
00378 GP<GIFFChunk> cur_sec=top_level;
00379 const char * start, * end=(const char *)parent_name-1;
00380 do
00381 {
00382 for(start=++end;*end&&(*end!='.');end++)
00383 EMPTY_LOOP;
00384 if (end>start)
00385 {
00386 GUTF8String name(start,end-start);
00387 GUTF8String short_name;
00388 int number=0;
00389 const int obracket=name.search('[');
00390 if (obracket >= 0)
00391 {
00392 const int cbracket=name.search(']',obracket+1);
00393 if (cbracket < 0)
00394 G_THROW( ERR_MSG("GIFFManager.unmatched") );
00395
00396 number = name.substr(obracket+1,cbracket-obracket-1).toInt();
00397 short_name=name.substr(0,obracket);
00398 }else
00399 {
00400 short_name=name;
00401 }
00402
00403 for(int i=cur_sec->get_chunks_number(short_name);i<number+1;i++)
00404 cur_sec->add_chunk(GIFFChunk::create(short_name));
00405 cur_sec=cur_sec->get_chunk(name);
00406 if (!cur_sec)
00407 G_THROW( ERR_MSG("GIFFManager.unknown") "\t"+name);
00408 }
00409 } while(*end);
00410 cur_sec->add_chunk(chunk, pos);
00411 }
00412
00413 void
00414 GIFFManager::add_chunk(GUTF8String name, const TArray<char> & data)
00415
00416
00417
00418 {
00419 DEBUG_MSG("GIFFManager::add_chunk(): adding plain chunk with name='" << name << "'\n");
00420 DEBUG_MAKE_INDENT(3);
00421
00422 GUTF8String chunk_name;
00423 const int lastdot=name.rsearch('.');
00424 if(lastdot < 0)
00425 {
00426 chunk_name=name;
00427 name=name.substr(0,lastdot);
00428 }else
00429 {
00430 chunk_name=name.substr(lastdot+1,(unsigned int)-1);
00431 }
00432
00433 int pos=-1;
00434 const int obracket=chunk_name.search('[');
00435 if (obracket >= 0)
00436 {
00437 const int cbracket=chunk_name.search(']',obracket+1);
00438 if (cbracket < 0)
00439 G_THROW( ERR_MSG("GIFFManager.unmatched") );
00440 if (name.length() > (unsigned int)(cbracket+1))
00441 G_THROW( ERR_MSG("GIFFManager.garbage") );
00442
00443 pos = chunk_name.substr(obracket+1,cbracket-obracket-1).toInt();
00444 chunk_name=chunk_name.substr(0,obracket);
00445 }
00446 DEBUG_MSG("Creating new chunk with name " << chunk_name << "\n");
00447 GP<GIFFChunk> chunk;
00448 chunk=GIFFChunk::create(chunk_name, data);
00449 add_chunk(name, chunk, pos);
00450 }
00451
00452 void
00453 GIFFManager::del_chunk(void)
00454 {
00455 DEBUG_MSG("GIFFManager::del_chunk(): Deleting chunk\n");
00456 DEBUG_MAKE_INDENT(3);
00457
00458 G_THROW( ERR_MSG("GIFFManager.del_empty") );
00459 }
00460
00461 void
00462 GIFFManager::del_chunk(GUTF8String name)
00463
00464
00465 {
00466 DEBUG_MSG("GIFFManager::del_chunk(): Deleting chunk '" << name << "'\n");
00467 DEBUG_MAKE_INDENT(3);
00468
00469 if (!name.length())
00470 G_THROW( ERR_MSG("GIFFManager.del_empty") );
00471
00472 if (name[0]=='.')
00473 {
00474 const int next_dot=name.search('.',1);
00475 if (next_dot < 0)
00476 {
00477 if (top_level->check_name(name.substr(1,(unsigned int)-1)))
00478 {
00479 DEBUG_MSG("Removing top level chunk..\n");
00480 top_level=GIFFChunk::create();
00481 return;
00482 }
00483 G_THROW( ERR_MSG("GIFFManager.wrong_name2") "\t"+name.substr(1,(unsigned int)-1));
00484 }
00485 const GUTF8String top_name=name.substr(1,next_dot-1);
00486 if (!top_level->check_name(top_name))
00487 G_THROW( ERR_MSG("GIFFManager.wrong_name2") "\t"+top_name);
00488 name=name.substr(next_dot+1,(unsigned int)-1);
00489 }
00490
00491 GP<GIFFChunk> cur_sec=top_level;
00492 const char * start, * end=(const char *)name-1;
00493 do
00494 {
00495 for(start=++end;*end&&(*end!='.');end++)
00496 EMPTY_LOOP;
00497 if (end>start && *end=='.')
00498 cur_sec=cur_sec->get_chunk(GUTF8String(start, end-start));
00499 if (!cur_sec)
00500 G_THROW( ERR_MSG("GIFFManager.cant_find") "\t"+GUTF8String(name));
00501 } while(*end);
00502
00503 if (!start[0])
00504 {
00505 G_THROW(GUTF8String( ERR_MSG("GIFFManager.malformed") "\t")+name);
00506 }
00507
00508 cur_sec->del_chunk(start);
00509 }
00510
00511 GP<GIFFChunk>
00512 GIFFManager::get_chunk(GUTF8String name, int * pos_num)
00513
00514
00515 {
00516 DEBUG_MSG("GIFFManager::get_chunk(): Returning chunk '" << name << "'\n");
00517 DEBUG_MAKE_INDENT(3);
00518
00519 if (!name.length())
00520 G_THROW( ERR_MSG("GIFFManager.get_empty") );
00521
00522 if (name[0]=='.')
00523 {
00524 const int next_dot=name.search('.',1);
00525 if (next_dot < 0)
00526 {
00527 if (top_level->check_name(name.substr(1,(unsigned int)-1)))
00528 {
00529 DEBUG_MSG("Removing top level chunk..\n");
00530 return top_level;
00531 }
00532 G_THROW( ERR_MSG("GIFFManager.wrong_name2") "\t"+name.substr(1,(unsigned int)-1));
00533 }
00534 const GUTF8String top_name=name.substr(1,next_dot-1);
00535 if (!top_level->check_name(top_name))
00536 G_THROW( ERR_MSG("GIFFManager.wrong_name2") "\t"+top_name);
00537 name=name.substr(next_dot+1,(unsigned int)-1);
00538 }
00539
00540 GP<GIFFChunk> cur_sec=top_level;
00541 const char * start, * end=(const char *) name-1;
00542 do
00543 {
00544 for(start=++end;*end&&(*end!='.');end++)
00545 EMPTY_LOOP;
00546 if (end>start)
00547 cur_sec=cur_sec->get_chunk(GUTF8String(start, end-start), pos_num);
00548 if (!cur_sec)
00549 break;
00550 } while(*end);
00551
00552 return cur_sec;
00553 }
00554
00555 int
00556 GIFFManager::get_chunks_number(void)
00557 {
00558 DEBUG_MSG("GIFFManager::get_chunks_number()\n");
00559 DEBUG_MAKE_INDENT(3);
00560 return top_level->get_chunks_number();
00561 }
00562
00563 int
00564 GIFFManager::get_chunks_number(const GUTF8String &name)
00565
00566 {
00567 DEBUG_MSG("GIFFManager::get_chunks_number(): name='" << name << "'\n");
00568 DEBUG_MAKE_INDENT(3);
00569
00570 int retval;
00571 const int last_dot=name.rsearch('.');
00572 if (last_dot<0)
00573 {
00574 retval=top_level->get_chunks_number(name);
00575 }else if(!last_dot)
00576 {
00577 retval=(top_level->get_name()==name.substr(1,(unsigned int)-1))?1:0;
00578 }else
00579 {
00580 GP<GIFFChunk> chunk=get_chunk(name.substr(0,last_dot));
00581 retval=( chunk
00582 ?(chunk->get_chunks_number(name.substr(last_dot+1,(unsigned int)-1)))
00583 :0 );
00584 }
00585 return retval;
00586 }
00587
00588 void
00589 GIFFManager::load_chunk(IFFByteStream & istr, GP<GIFFChunk> chunk)
00590 {
00591 DEBUG_MSG("GIFFManager::load_chunk(): loading contents of chunk '" <<
00592 chunk->get_name() << "'\n");
00593 DEBUG_MAKE_INDENT(3);
00594
00595 int chunk_size;
00596 GUTF8String chunk_id;
00597 while ((chunk_size=istr.get_chunk(chunk_id)))
00598 {
00599 if (istr.check_id(chunk_id))
00600 {
00601 GP<GIFFChunk> ch=GIFFChunk::create(chunk_id);
00602 load_chunk(istr, ch);
00603 chunk->add_chunk(ch);
00604 } else
00605 {
00606 TArray<char> data(chunk_size-1);
00607 istr.get_bytestream()->readall( (char*)data, data.size());
00608 GP<GIFFChunk> ch=GIFFChunk::create(chunk_id, data);
00609 chunk->add_chunk(ch);
00610 }
00611 istr.close_chunk();
00612 }
00613 }
00614
00615 void
00616 GIFFManager::load_file(const TArray<char> & data)
00617 {
00618 GP<ByteStream> str=ByteStream::create((const char *)data, data.size());
00619 load_file(str);
00620 }
00621
00622 void
00623 GIFFManager::load_file(GP<ByteStream> str)
00624 {
00625 DEBUG_MSG("GIFFManager::load_file(): Loading IFF file.\n");
00626 DEBUG_MAKE_INDENT(3);
00627
00628 GP<IFFByteStream> gistr=IFFByteStream::create(str);
00629 IFFByteStream &istr=*gistr;
00630 GUTF8String chunk_id;
00631 if (istr.get_chunk(chunk_id))
00632 {
00633 if (chunk_id.substr(0,5) != "FORM:")
00634 G_THROW( ERR_MSG("GIFFManager.cant_find2") );
00635 set_name(chunk_id);
00636 load_chunk(istr, top_level);
00637 istr.close_chunk();
00638 }
00639 }
00640
00641 void
00642 GIFFManager::save_file(TArray<char> & data)
00643 {
00644 GP<ByteStream> gstr=ByteStream::create();
00645 save_file(gstr);
00646 data=gstr->get_data();
00647 }
00648
00649 void
00650 GIFFManager::save_file(GP<ByteStream> str)
00651 {
00652 GP<IFFByteStream> istr=IFFByteStream::create(str);
00653 top_level->save(*istr, 1);
00654 }
00655
00656
00657 #ifdef HAVE_NAMESPACES
00658 }
00659 # ifndef NOT_USING_DJVU_NAMESPACE
00660 using namespace DJVU;
00661 # endif
00662 #endif
00663