shapefile.cc

Go to the documentation of this file.
00001 
00007 /*
00008 Copyright (C) 2002 The Exult Team
00009 
00010 This program is free software; you can redistribute it and/or
00011 modify it under the terms of the GNU General Public License
00012 as published by the Free Software Foundation; either version 2
00013 of the License, or (at your option) any later version.
00014 
00015 This program is distributed in the hope that it will be useful,
00016 but WITHOUT ANY WARRANTY; without even the implied warranty of
00017 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018 GNU General Public License for more details.
00019 
00020 You should have received a copy of the GNU General Public License
00021 along with this program; if not, write to the Free Software
00022 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00023 */
00024 
00025 #ifdef HAVE_CONFIG_H
00026 #  include <config.h>
00027 #endif
00028 
00029 #include "shapefile.h"
00030 #include "u7drag.h"
00031 #include "shapegroup.h"
00032 #include "shapevga.h"
00033 #include "shapelst.h"
00034 #include "chunklst.h"
00035 #include "paledit.h"
00036 #include "utils.h"
00037 #include "Flex.h"
00038 #include "exceptions.h"
00039 #include "combo.h"
00040 #include "studio.h"
00041 
00042 using std::vector;
00043 using std::string;
00044 using std::cerr;
00045 using std::endl;
00046 using std::ofstream;
00047 
00048 /*
00049  *  Delete file and groups.
00050  */
00051 
00052 Shape_file_info::~Shape_file_info
00053   (
00054   )
00055   {
00056   delete groups;
00057   delete browser;
00058   }
00059 
00060 /*
00061  *  Get the main browser for this file, or create it.
00062  *
00063  *  Output: ->browser.
00064  */
00065 
00066 Object_browser *Shape_file_info::get_browser
00067   (
00068   Shape_file_info *vgafile,
00069   unsigned char *palbuf
00070   )
00071   {
00072   if (browser)
00073     return browser;   // Okay.
00074   browser = create_browser(vgafile, palbuf, 0);
00075           // Add a reference (us).
00076   gtk_widget_ref(browser->get_widget());
00077   return browser;
00078   }
00079 
00080 /*
00081  *  Cleanup.
00082  */
00083 
00084 Image_file_info::~Image_file_info
00085   (
00086   )
00087   {
00088   delete ifile;
00089   }
00090 
00091 /*
00092  *  Create a browser for our data.
00093  */
00094 
00095 Object_browser *Image_file_info::create_browser
00096   (
00097   Shape_file_info *vgafile, // THE 'shapes.vga' file.
00098   unsigned char *palbuf,    // Palette for displaying.
00099   Shape_group *g      // Group, or 0.
00100   )
00101   {
00102   Shape_chooser *chooser = new Shape_chooser(ifile, palbuf, 400, 64, 
00103                 g, this);
00104           // Fonts?  Show 'A' as the default.
00105   if (strcasecmp(basename.c_str(), "fonts.vga") == 0)
00106     chooser->set_framenum0('A');
00107   if (this == vgafile)    // Main 'shapes.vga' file?
00108     {
00109     chooser->set_shapes_file(
00110       (Shapes_vga_file *) vgafile->get_ifile());
00111     }
00112   return chooser;
00113   }
00114 
00115 /*
00116  *  Write out if modified.  May throw exception.
00117  */
00118 
00119 void Image_file_info::flush
00120   (
00121   )
00122   {
00123   if (!modified)
00124     return;
00125   modified = false;
00126   int nshapes = ifile->get_num_shapes();
00127   int shnum;      // First read all entries.
00128   Shape **shapes = new Shape *[nshapes];
00129   for (shnum = 0; shnum < nshapes; shnum++)
00130     shapes[shnum] = ifile->extract_shape(shnum);
00131   string filestr("<PATCH>/"); // Always write to 'patch'.
00132   filestr += basename;
00133           // !flex means single-shape.
00134   write_file(filestr.c_str(), shapes, nshapes, !ifile->is_flex());
00135   delete [] shapes;
00136           // Tell Exult to reload this file.
00137   unsigned char buf[Exult_server::maxlength];
00138   unsigned char *ptr = &buf[0];
00139   Write2(ptr, ifile->get_u7drag_type());
00140   ExultStudio *studio = ExultStudio::get_instance();
00141   studio->send_to_server(Exult_server::reload_shapes, buf, ptr - buf);
00142   }
00143 
00144 /*
00145  *  Revert to what's on disk.
00146  *
00147  *  Output: True (meaning we support 'revert').
00148  */
00149 
00150 bool Image_file_info::revert
00151   (
00152   )
00153   {
00154   if (modified)
00155     {
00156     ifile->load(pathname.c_str());
00157     modified = false;
00158     }
00159   return true;
00160   }
00161 
00162 /*
00163  *  Write a shape file.  (Note:  static method.)
00164  *  May print an error.
00165  */
00166 
00167 void Image_file_info::write_file
00168   (
00169   const char *pathname,   // Full path.
00170   Shape **shapes,     // List of shapes to write.
00171   int nshapes,      // # shapes.
00172   bool single     // Don't write a FLEX file.
00173   )
00174   {
00175   ofstream out;
00176   U7open(out, pathname);    // May throw exception.
00177   if (single)
00178     {
00179     if (nshapes)
00180       shapes[0]->write(out);
00181     out.flush();
00182     if (!out.good())
00183       throw file_write_exception(pathname);
00184     out.close();
00185     return;
00186     }
00187   Flex_writer writer(out, "Written by ExultStudio", nshapes);
00188           // Write all out.
00189   for (int shnum = 0; shnum < nshapes; shnum++)
00190     {
00191     shapes[shnum]->write(out);
00192     writer.mark_section_done();
00193     }
00194   if (!writer.close())
00195     throw file_write_exception(pathname);
00196   }
00197 
00198 /*
00199  *  Cleanup.
00200  */
00201 
00202 Chunks_file_info::~Chunks_file_info
00203   (
00204   )
00205   {
00206   delete file;
00207   }
00208 
00209 /*
00210  *  Create a browser for our data.
00211  */
00212 
00213 Object_browser *Chunks_file_info::create_browser
00214   (
00215   Shape_file_info *vgafile, // THE 'shapes.vga' file.
00216   unsigned char *palbuf,    // Palette for displaying.
00217   Shape_group *g      // Group, or 0.
00218   )
00219   {
00220           // Must be 'u7chunks' (for now).
00221   return new Chunk_chooser(vgafile->get_ifile(), *file, palbuf, 
00222                 400, 64, g);
00223   }
00224 
00225 /*
00226  *  Write out if modified.  May throw exception.
00227  */
00228 
00229 void Chunks_file_info::flush
00230   (
00231   )
00232   {
00233   if (!modified)
00234     return;
00235   modified = false;
00236   cerr << "Chunks should be stored by Exult" << endl;
00237   }
00238 
00239 /*
00240  *  Init.
00241  */
00242 
00243 Flex_file_info::Flex_file_info
00244   (
00245   const char *bnm,    // Basename,
00246   const char *pnm,    // Full pathname,
00247   Flex *fl,     // Flex file (we'll own it).
00248   Shape_group_file *g   // Group file (or 0).
00249   ) : Shape_file_info(bnm, pnm, g), flex(fl), write_flat(false)
00250   {
00251   entries.resize(flex->number_of_objects());
00252   lengths.resize(entries.size());
00253   }
00254 
00255 /*
00256  *  Init. for single-palette.
00257  */
00258 
00259 Flex_file_info::Flex_file_info
00260   (
00261   const char *bnm,    // Basename,
00262   const char *pnm,    // Full pathname,
00263   int size      // File size.
00264   ) : Shape_file_info(bnm, pnm, 0), flex(0), write_flat(true)
00265   {
00266   entries.resize(size > 0);
00267   lengths.resize(entries.size());
00268   if (size > 0)     // Read in whole thing.
00269     {
00270     std::ifstream in;
00271     U7open(in, pnm);  // Shouldn't fail.
00272     entries[0] = new char[size];
00273     in.read(entries[0], size);
00274     lengths[0] = size;
00275     }
00276   }
00277 
00278 /*
00279  *  Cleanup.
00280  */
00281 
00282 Flex_file_info::~Flex_file_info
00283   (
00284   )
00285   {
00286   delete flex;
00287   int cnt = entries.size();
00288   for (int i = 0; i < cnt; i++)
00289     delete entries[i];
00290   }
00291 
00292 /*
00293  *  Get i'th entry.
00294  */
00295 
00296 char *Flex_file_info::get
00297   (
00298   int i,
00299   size_t& len
00300   )
00301   {
00302   if (i >= 0 && i < entries.size())
00303     {
00304     if (!entries[i])  // Read it if necessary.
00305       {
00306       entries[i] = flex->retrieve(i, len);
00307       lengths[i] = len;
00308       }
00309     len = lengths[i];
00310     return entries[i];
00311     }
00312   else
00313     return 0;
00314   }
00315 
00316 /*
00317  *  Set i'th entry.
00318  */
00319 
00320 void Flex_file_info::set
00321   (
00322   int i,
00323   char *newentry,     // Allocated data that we'll own.
00324   int entlen      // Length.
00325   )
00326   {
00327   if (i < 0 || i > entries.size())
00328     return;
00329   if (i == entries.size())  // Appending?
00330     {
00331     entries.push_back(newentry);
00332     lengths.push_back(entlen);
00333     }
00334   else
00335     {
00336     delete entries[i];
00337     entries[i] = newentry;
00338     lengths[i] = entlen;
00339     }
00340   }
00341 
00342 /*
00343  *  Swap the i'th and i+1'th entries.
00344  */
00345 
00346 void Flex_file_info::swap
00347   (
00348   int i
00349   )
00350   {
00351   assert (i >= 0 && i < entries.size() - 1);
00352   char *tmpent = entries[i];
00353   int tmplen = lengths[i];
00354   entries[i] = entries[i + 1];
00355   lengths[i] = lengths[i + 1];
00356   entries[i + 1] = tmpent;
00357   lengths[i + 1] = tmplen;
00358   }
00359 
00360 /*
00361  *  Remove i'th entry.
00362  */
00363 
00364 void Flex_file_info::remove
00365   (
00366   int i
00367   )
00368   {
00369   assert (i >= 0 && i < entries.size());
00370   delete entries[i];    // Free memory.
00371   entries.erase(entries.begin() + i);
00372   lengths.erase(lengths.begin() + i);
00373   }
00374 
00375 /*
00376  *  Create a browser for our data.
00377  */
00378 
00379 Object_browser *Flex_file_info::create_browser
00380   (
00381   Shape_file_info *vgafile, // THE 'shapes.vga' file.
00382   unsigned char *palbuf,    // Palette for displaying.
00383   Shape_group *g      // Group, or 0.
00384   )
00385   {
00386   const char *bname = basename.c_str();
00387   if (strcasecmp(bname, "palettes.flx") == 0 ||
00388       strcasecmp(".pal", bname + strlen(bname) - 4) == 0)
00389     return new Palette_edit(this);
00390   return new Combo_chooser(vgafile->get_ifile(), this, palbuf,
00391                 400, 64, g);
00392   }
00393 
00394 /*
00395  *  Write out if modified.  May throw exception.
00396  */
00397 
00398 void Flex_file_info::flush
00399   (
00400   )
00401   {
00402   if (!modified)
00403     return;
00404   modified = false;
00405   int cnt = entries.size();
00406   size_t len;
00407   int i;
00408   for (i = 0; i < cnt; i++) // Make sure all are read.
00409     {
00410     if (!entries[i])
00411       get(i, len);
00412     }
00413   ofstream out;
00414   string filestr("<PATCH>/"); // Always write to 'patch'.
00415   filestr += basename;
00416   U7open(out, filestr.c_str()); // May throw exception.
00417   if (cnt <= 1 && write_flat) // Write flat file.
00418     {
00419     if (cnt)
00420       out.write(entries[0], lengths[0]);
00421     out.close();
00422     if (!out.good())
00423       throw file_write_exception(filestr.c_str());
00424     return;
00425     }
00426   Flex_writer writer(out, "Written by ExultStudio", cnt);
00427           // Write all out.
00428   for (int i = 0; i < cnt; i++)
00429     {
00430     out.write(entries[i], lengths[i]);
00431     writer.mark_section_done();
00432     }
00433   if (!writer.close())
00434     throw file_write_exception(filestr.c_str());
00435   }
00436 
00437 /*
00438  *  Revert to what's on disk.
00439  *
00440  *  Output: True (meaning we support 'revert').
00441  */
00442 
00443 bool Flex_file_info::revert
00444   (
00445   )
00446   {
00447   if (!modified)
00448     return true;
00449   modified = false;
00450   int cnt = entries.size();
00451   for (int i = 0; i < cnt; i++)
00452     {
00453     delete entries[i];
00454     entries[i] = 0;
00455     lengths[i] = 0;
00456     }
00457   if (flex)
00458     {
00459     cnt = flex->number_of_objects();
00460     entries.resize(cnt);
00461     lengths.resize(entries.size());
00462     }
00463   else        // Single palette.
00464     {
00465     std::ifstream in;
00466     U7open(in, pathname.c_str()); // Shouldn't fail.
00467     in.seekg(0, std::ios::end); // Figure size.
00468     int sz = in.tellg();
00469     cnt = sz > 0 ? 1 : 0;
00470     entries.resize(cnt);
00471     lengths.resize(entries.size());
00472     in.seekg(0);
00473     if (cnt)
00474       {
00475       entries[0] = new char[sz];
00476       in.read(entries[0], sz);
00477       lengths[0] = sz;
00478       }
00479     }
00480   return true;
00481   }
00482 
00483 /*
00484  *  Delete set's entries.
00485  */
00486 
00487 Shape_file_set::~Shape_file_set
00488   (
00489   )
00490   {
00491   for (vector<Shape_file_info *>::iterator it = files.begin(); 
00492           it != files.end(); ++it)
00493     delete (*it);
00494   }
00495 
00496 /*
00497  *  This routines tries to create files that don't yet exist.
00498  *
00499  *  Output: true if successful.
00500  */
00501 
00502 static bool Create_file
00503   (
00504   const char *basename,   // Base file name.
00505   const string& pathname    // Full name.
00506   )
00507   {
00508   int namelen = strlen(basename);
00509   if (strcasecmp(".flx", basename + namelen - 4) == 0)
00510     {     // We can create an empty flx.
00511     ofstream out;
00512     U7open(out, pathname.c_str());  // May throw exception.
00513     Flex_writer writer(out, "Written by ExultStudio", 0);
00514     if (!writer.close())
00515       throw file_write_exception(pathname.c_str());
00516     return true;
00517     }
00518   else if (strcasecmp(".pal", basename + namelen - 4) == 0)
00519     {     // Empty 1-palette file.
00520     ofstream out;
00521     U7open(out, pathname.c_str());  // May throw exception.
00522     out.close();    // Empty file.
00523     return true;
00524     }
00525   return false;     // Might add more later.
00526   }
00527 
00528 /*
00529  *  Create a new 'Shape_file_info', or return existing one.
00530  *
00531  *  Output: ->file info, or 0 if error.
00532  */
00533 
00534 Shape_file_info *Shape_file_set::create
00535   (
00536   const char *basename    // Like 'shapes.vga'.
00537   )
00538   {
00539           // Already have it open?
00540   for (vector<Shape_file_info *>::iterator it = files.begin(); 
00541           it != files.end(); ++it)
00542     if (strcasecmp((*it)->basename.c_str(), basename) == 0)
00543       return *it; // Found it.
00544           // Look in 'static', 'patch'.
00545   string sstr = string("<STATIC>/") + basename;
00546   string pstr = string("<PATCH>/") + basename;
00547   const char *spath = sstr.c_str(), *ppath = pstr.c_str();
00548   bool sexists = U7exists(spath);
00549   bool pexists = U7exists(ppath);
00550   if (!sexists && !pexists) // Neither place.  Try to create.
00551     if (!(pexists = Create_file(basename, ppath)))
00552       return 0;
00553           // Use patch file if it exists.
00554   const char *fullname = pexists ? ppath : spath;
00555   string group_name(basename);  // Create groups file.
00556   group_name += ".grp";
00557   Shape_group_file *groups = new Shape_group_file(group_name.c_str());
00558   if (strcasecmp(basename, "shapes.vga") == 0)
00559     return append(new Image_file_info(basename, fullname, 
00560       new Shapes_vga_file(spath, U7_SHAPE_SHAPES, ppath), 
00561                 groups));
00562   else if (strcasecmp(basename, "gumps.vga") == 0)
00563     return append(new Image_file_info(basename, fullname,
00564       new Vga_file(spath, U7_SHAPE_GUMPS, ppath), groups));
00565   else if (strcasecmp(basename, "faces.vga") == 0)
00566     return append(new Image_file_info(basename, fullname,
00567       new Vga_file(spath, U7_SHAPE_FACES, ppath), groups));
00568   else if (strcasecmp(basename, "sprites.vga") == 0)
00569     return append(new Image_file_info(basename, fullname,
00570       new Vga_file(spath, U7_SHAPE_SPRITES, ppath), groups));
00571   else if (strcasecmp(basename, "paperdol.vga") == 0)
00572     return append(new Image_file_info(basename, fullname,
00573           new Vga_file(spath, U7_SHAPE_PAPERDOL, ppath), groups));
00574   else if (strcasecmp(basename, "fonts.vga") == 0)
00575     return append(new Image_file_info(basename, fullname,
00576           new Vga_file(spath, U7_SHAPE_FONTS, ppath), groups));
00577   else if (strcasecmp(basename, "u7chunks") == 0)
00578     {
00579     std::ifstream *file = new std::ifstream;
00580     U7open(*file, fullname);
00581     return append(new Chunks_file_info(basename, fullname, 
00582                 file, groups));
00583     }
00584   else if (strcasecmp(basename, "combos.flx") == 0 ||
00585      strcasecmp(basename, "palettes.flx") == 0)
00586     return append(new Flex_file_info(basename, fullname, 
00587             new Flex(fullname), groups));
00588   else if (strcasecmp(".pal", basename + strlen(basename) - 4) == 0)
00589     {     // Single palette?
00590     std::ifstream in;
00591     U7open(in, fullname);
00592     in.seekg(0, std::ios::end); // Figure size.
00593     int sz = in.tellg();
00594     return append(new Flex_file_info(basename, fullname, sz));
00595     }
00596   else        // Not handled above?
00597     {     // Get image file for this path.
00598     Vga_file *ifile = new Vga_file(spath, U7_SHAPE_UNK, ppath);
00599     if (ifile->is_good())
00600       return append(new Image_file_info(basename, fullname,
00601               ifile, groups));
00602     delete ifile;
00603     }
00604   cerr << "Error opening image file '" << basename << "'.\n";
00605   return 0;
00606   }
00607 
00608 /*
00609  *  Write any modified image files.
00610  */
00611 
00612 void Shape_file_set::flush
00613   (
00614   )
00615   {
00616   for (vector<Shape_file_info *>::iterator it = files.begin(); 
00617           it != files.end(); ++it)
00618     (*it)->flush();
00619   }
00620 
00621 /*
00622  *  Any files modified?
00623  */
00624 
00625 bool Shape_file_set::is_modified
00626   (
00627   )
00628   {
00629   for (vector<Shape_file_info *>::iterator it = files.begin(); 
00630           it != files.end(); ++it)
00631     if ((*it)->modified)
00632       return true;
00633   return false;
00634   }

Generated on Mon Jul 9 14:42:48 2007 for ExultEngine by  doxygen 1.5.1