useval.cc

Go to the documentation of this file.
00001 /*
00002  *  useval.cc - Values used in Usecode interpreter.
00003  *
00004  *  Copyright (C) 1999  Jeffrey S. Freedman
00005  *  Copyright (C) 2000-2002  The Exult Team
00006  *
00007  *  This program is free software; you can redistribute it and/or modify
00008  *  it under the terms of the GNU General Public License as published by
00009  *  the Free Software Foundation; either version 2 of the License, or
00010  *  (at your option) any later version.
00011  *
00012  *  This program is distributed in the hope that it will be useful,
00013  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  *  GNU General Public License for more details.
00016  *
00017  *  You should have received a copy of the GNU General Public License
00018  *  along with this program; if not, write to the Free Software
00019  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00020  */
00021 
00022 #ifdef HAVE_CONFIG_H
00023 #  include <config.h>
00024 #endif
00025 
00026 #ifndef ALPHA_LINUX_CXX
00027   #include <fstream>
00028   #include <cstring>
00029   #include <iomanip>
00030   #include <iostream>
00031   #include <cstdlib>
00032   #include <cstdio>
00033 #endif
00034 
00035 #include "useval.h"
00036 #include "utils.h"
00037 
00038 #ifndef UNDER_CE
00039 using std::cout;
00040 using std::endl;
00041 using std::dec;
00042 using std::hex;
00043 using std::memcpy;
00044 using std::ostream;
00045 using std::setfill;
00046 using std::setw;
00047 using std::strcmp;
00048 using std::strlen;
00049 #endif
00050 
00051 
00052 
00053 /*
00054  *  Get array size.
00055  */
00056 
00057 int Usecode_value::count_array
00058   (
00059   const Usecode_value& val
00060   )
00061   {
00062   int i;
00063   for (i = 0; val.value.array[i].type != end_of_array_type; i++)
00064     ;
00065   return (i);
00066   }
00067 
00068 /*
00069  *  Destructor
00070  *
00071  */
00072 
00073 Usecode_value::~Usecode_value()
00074 {
00075   if (type == array_type)
00076     delete [] value.array;
00077   else if (type == string_type)
00078     delete [] value.str;
00079 }
00080 
00081 /*
00082  *  Copy another to this.
00083  */
00084 
00085 Usecode_value& Usecode_value::operator=
00086   (
00087   const Usecode_value& v2
00088   )
00089   {
00090   if (&v2 == this)
00091     return *this;
00092   if (type == array_type)
00093     delete [] value.array;
00094   else if (type == string_type)
00095     delete [] value.str;
00096   type = v2.type;     // Assign new values.
00097   if (type == int_type)
00098     value.intval = v2.value.intval;
00099   else if (type == pointer_type)
00100     value.ptr = v2.value.ptr;
00101   else if (type == string_type)
00102     value.str = v2.value.str ? newstrdup(v2.value.str) : 0;
00103   else if (type == array_type)
00104     {
00105                 int tempsize = 1+count_array(v2);
00106     value.array = new Usecode_value[tempsize];
00107     int i = 0;
00108     do
00109       value.array[i] = v2.value.array[i];
00110     while (value.array[i++].type != end_of_array_type);
00111     }
00112 
00113   undefined = v2.undefined;
00114 
00115   return *this;
00116   }
00117 
00118 /*
00119  *  Set this to (a copy of) a string.
00120  */
00121 
00122 
00123 Usecode_value& Usecode_value::operator=
00124   (
00125   const char *str
00126   )
00127   {
00128   if (type == array_type)
00129     delete [] value.array;
00130   else if (type == string_type)
00131     delete [] value.str;
00132   type = string_type;
00133   value.str = str ? newstrdup(str) : 0;
00134   return *this;
00135   }
00136 
00137 /*
00138  *  Create a string value.
00139  */
00140 
00141 Usecode_value::Usecode_value
00142   (
00143   const char *s
00144   ) : type(string_type), undefined(false)
00145   {
00146   value.str = s ? newstrdup(s) : 0; 
00147   }
00148 
00149 /*
00150  *  Resize array (or turn single element into an array).  The new values
00151  *  are (integer) 0.
00152  *
00153  *  Output: Always true.
00154  */
00155 
00156 int Usecode_value::resize
00157   (
00158   int new_size
00159   )
00160   {
00161   if (type != array_type) // Turn it into an array.
00162     {
00163     Usecode_value elem(*this);
00164     *this = Usecode_value(new_size, &elem);
00165     return (1);
00166     }
00167   int size = count_array(*this);  // Get current size.
00168   if (new_size == size)
00169     return (1);   // Nothing to do.
00170   Usecode_value *newvals = new Usecode_value[new_size + 1];
00171   newvals[new_size].type = end_of_array_type;
00172           // Move old values over.
00173   int cnt = new_size < size ? new_size : size;
00174   for (int i = 0; i < cnt; i++)
00175     newvals[i] = value.array[i];
00176   delete [] value.array;    // Delete old list.
00177   value.array = newvals;    // Store new.
00178   return (1);
00179   }
00180 
00181 void  Usecode_value::push_back(int i)
00182 {
00183   resize(count_array(*this)+1);
00184   value.array[count_array(*this)-1]=Usecode_value(i);
00185 }
00186 
00187 /*
00188  *  Comparator.
00189  *
00190  *  Output: 1 if they match, else 0.
00191  */
00192 
00193 bool Usecode_value::operator==
00194   (
00195   const Usecode_value& v2
00196   ) const
00197   {
00198   if (&v2 == this)
00199     return true;    // Same object.
00200   if (type == int_type)   // Might be ptr==0.
00201     return (v2.type == int_type || v2.type == pointer_type) ?
00202           (value.intval == v2.value.intval)
00203           // Okay if 0==empty array.
00204       : v2.type == array_type &&
00205           !value.intval && !v2.get_array_size();
00206   else if (type == pointer_type)  // Might be ptr==0.
00207     {     // Or ptr == array.  Test elem. 0.
00208     if (v2.type == pointer_type || v2.type == int_type)
00209       return (value.ptr == v2.value.ptr);
00210     else if (v2.type == array_type && v2.get_array_size())
00211       {
00212       const Usecode_value& val2 = v2.value.array[0];
00213       return (value.ptr == val2.value.ptr);
00214       }
00215     else
00216       return false;
00217     }
00218   else if (type == array_type)
00219     {
00220     if (v2.type == int_type)
00221       return !get_array_size() && !v2.get_int_value();
00222     else if (v2.type == pointer_type && get_array_size())
00223       {
00224       Usecode_value& v = get_elem(0);
00225       return v2.value.ptr == v.value.ptr;
00226       }
00227     if (v2.type != array_type)
00228       return false;
00229     int cnt = get_array_size();
00230     if (cnt != v2.get_array_size())
00231       return false;
00232     for (int i = 0; i < cnt; i++)
00233       {
00234       Usecode_value& e1 = get_elem(i);
00235       const Usecode_value& e2 = v2.get_elem(i);
00236       if (!(e1 == e2))
00237         return false;
00238       }
00239     return true;    // Arrays matched.
00240     }
00241   else if (type == string_type)
00242     return (v2.type == string_type &&
00243           strcmp(value.str, v2.value.str) == 0);
00244   else
00245     return false;
00246   }
00247 
00248 /*
00249  *  Search an array for a given value.
00250  *
00251  *  Output: Index if found, else -1.
00252  */
00253 
00254 int Usecode_value::find_elem
00255   (
00256   const Usecode_value& val
00257   )
00258   {
00259   if (type != array_type)
00260     return (-1);    // Not an array.
00261   int i;
00262   for (i = 0; value.array[i].type != end_of_array_type; i++)
00263     if (value.array[i] == val)
00264       return (i);
00265   return (-1);
00266   }
00267 
00268 /*
00269  *  Concatenate another value onto this.
00270  *
00271  *  Output: This.
00272  */
00273 
00274 Usecode_value& Usecode_value::concat
00275   (
00276   Usecode_value& val2   // Concat. val2 onto end.
00277   )
00278   {
00279   int size;     // Size of result.
00280   if (type != array_type)   // Not an array?  Create one.
00281     {     // Current value becomes 1st elem.
00282     Usecode_value tmp(1, this);
00283     *this = tmp;
00284     size = 1;
00285     }
00286   else
00287     size = get_array_size();
00288   if (val2.type != array_type)  // Appending a single value?
00289     {
00290     resize(size + 1);
00291     put_elem(size, val2);
00292     }
00293   else        // Appending an array.
00294     {
00295     int size2 = val2.get_array_size();
00296     resize(size + size2);
00297     for (int i = 0; i < size2; i++)
00298       put_elem(size + i, val2.get_elem(i));
00299     }
00300   return (*this);
00301   }
00302 
00303 /*
00304  *  Append a list of integer values.
00305  */
00306 
00307 void Usecode_value::append
00308   (
00309   int *vals,
00310   int cnt
00311   )
00312   {
00313   assert(type == array_type);
00314   int sz = get_array_size();
00315   resize(sz + cnt);
00316   for (int i = 0; i < cnt; i++)
00317     value.array[sz + i].value.intval = vals[i];
00318   }
00319 
00320 /*
00321  *  Given an array and an index, and a 2nd value, add the new value at that
00322  *  index, or if the new value is an array itself, add its values.
00323  *
00324  *  Output: # elements added.
00325  */
00326 
00327 int Usecode_value::add_values
00328   (
00329   int index,
00330   Usecode_value& val2
00331   )
00332   {
00333   int size = get_array_size();
00334   if (!val2.is_array())   // Simple case?
00335     {
00336     if (index >= size)
00337       resize(index + 1);
00338     put_elem(index, val2);
00339     return (1);
00340     }
00341           // Add each element.
00342   int size2 = val2.get_array_size();
00343   if (index + size2 > size)
00344     resize(index + size2);
00345   for (int i = 0; i < size2; i++)
00346     put_elem(index++, val2.get_elem(i));
00347   return (size2);     // Return # added.
00348   }
00349 
00350 /*
00351  *  Print in ASCII.
00352  */
00353 
00354 void Usecode_value::print
00355   (
00356    ostream& out, bool shortformat
00357   )
00358   {
00359   switch ((Val_type) type)
00360     {
00361   case int_type:
00362     out << hex << setfill((char)0x30) << setw(4);
00363     out << (value.intval&0xffff);
00364     out << dec;
00365     break;
00366   case pointer_type:
00367     out << hex << setfill((char)0x30) << setw(8);
00368     out << (long)value.ptr;
00369     out << dec;
00370     break;
00371   case string_type:
00372     out << '"' << value.str << '"'; break;
00373   case array_type:
00374     {
00375     out << "[ ";
00376     int i;
00377     for (i = 0; value.array[i].type != end_of_array_type; i++) {
00378       if (!shortformat || i < 2) {
00379         if (i)
00380           out << ", ";
00381         
00382         value.array[i].print(out);
00383       }
00384     }
00385     if (shortformat && i > 2)
00386       out << ", ... (size " << i << ")";
00387     out << " ]";
00388     }
00389     break;
00390   default:
00391     break;
00392     }
00393   }
00394 
00395 Usecode_value Usecode_value::operator+(const Usecode_value& v2)
00396 {
00397   char buf[300];
00398   Usecode_value& v1 = *this;
00399   Usecode_value sum(0);
00400 
00401   if (v1.is_undefined())
00402   {
00403     sum = v2;
00404   }
00405   else if (v2.is_undefined())
00406   {
00407     sum = v1;
00408   } 
00409   else if (v1.get_type() == Usecode_value::int_type)
00410   {
00411     if (v2.get_type() == Usecode_value::int_type) {
00412       sum = Usecode_value(v1.get_int_value()
00413           + v2.get_int_value());
00414     } else if (v2.get_type() == Usecode_value::string_type) {
00415       snprintf(buf, 300, "%ld%s", 
00416           v1.get_int_value(),
00417           v2.get_str_value());
00418       sum = Usecode_value(buf);
00419     } else {
00420       sum = v1;
00421     }
00422   }
00423   else if (v1.get_type() == Usecode_value::string_type)
00424   {
00425     if (v2.get_type() == Usecode_value::int_type) {
00426       snprintf(buf, 300, "%s%ld", 
00427         v1.get_str_value(),
00428         v2.get_int_value());
00429       sum = Usecode_value(buf);
00430     } else if (v2.get_type() == Usecode_value::string_type) {
00431       snprintf(buf, 300, "%s%s", 
00432           v1.get_str_value(),
00433           v2.get_str_value());
00434       sum = Usecode_value(buf);
00435     } else {
00436       sum = v1;
00437     }
00438   }
00439   return sum;
00440 }
00441 
00442 /*
00443  *  Serialize out.
00444  *
00445  *  Output: # bytes stored, or -1 if error.
00446  */
00447 
00448 int Usecode_value::save
00449   (
00450   unsigned char *buf,
00451   int buflen
00452   )
00453   {
00454   uint8 *ptr = buf;
00455   switch ((Val_type) type)
00456     {
00457   case int_type:
00458     if (buflen < 5)
00459       return -1;
00460     *ptr++ = type;
00461     Write4(ptr, value.intval);
00462     break;
00463   case pointer_type:
00464     if (buflen < 5)
00465       return -1;
00466     *ptr++ = type;
00467     Write4(ptr, (int)value.ptr);
00468     break;
00469   case string_type:
00470     {
00471     int len = std::strlen(value.str);
00472     if (buflen < len + 3)
00473       return -1;
00474     *ptr++ = type;
00475     Write2(ptr, len);
00476     std::memcpy(ptr, value.str, len);
00477     ptr += len;
00478     break;
00479     }
00480   case array_type:
00481     {
00482     if (buflen < 3)
00483       return -1;
00484     *ptr++ = type;
00485     int len = count_array(*this);
00486     Write2(ptr, len); // first length, then length Usecode_values
00487     int remaining = buflen - 3;
00488     for (int i=0; i < len; i++) {
00489       int retval = value.array[i].save(ptr, remaining);
00490       if (retval == -1)
00491         return -1;
00492 
00493       ptr += retval;
00494       remaining -= retval;
00495     }
00496     break;
00497     }
00498   default:
00499     return -1;
00500     }
00501   return (ptr - buf);
00502   }
00503 
00504 /*
00505  *  Serialize in.  Assumes 'this' contains no data yet.
00506  *
00507  *  Output: False if error.
00508  */
00509 
00510 bool Usecode_value::restore
00511   (
00512   unsigned char *& ptr,   // Ptr. to data.  Updated past it.
00513   int buflen
00514   )
00515   {
00516   undefined = false;
00517   type = (Val_type) *ptr++;
00518   switch (type)
00519     {
00520   case int_type:
00521     if (buflen < 5)
00522       return false;
00523     value.intval = Read4(ptr);
00524     return true;
00525   case pointer_type:
00526     if (buflen < 5)
00527       return false;
00528     value.ptr = (Game_object*)Read4(ptr); //DON'T dereference this pointer!
00529     // Maybe add a new type "serialized_pointer" to prevent "accidents"?
00530     return true;
00531   case string_type:
00532     {
00533     int len = Read2(ptr);
00534     if (buflen < len + 3)
00535       return false;
00536     value.str = new char[len + 1];
00537     std::memcpy(value.str, ptr, len);
00538     value.str[len] = 0;
00539     ptr += len;
00540     return true;
00541     }
00542   case array_type:
00543     {
00544     if (buflen < 3)
00545       return false;
00546     int len = Read2(ptr);
00547     int remaining = buflen - 3; // already read one byte
00548     *this = Usecode_value(len, 0); // create array
00549     for (int i=0; i < len; i++) {
00550       uint8* t = ptr;
00551       bool retval = value.array[i].restore(ptr, remaining);
00552       remaining -= (ptr - t);
00553       if (!retval)
00554         return false;
00555     }
00556     return true;
00557     }
00558   default:
00559     return false;
00560     }
00561   }
00562 
00563 
00564 ostream& operator<<(ostream& out, Usecode_value& val)
00565 {
00566   val.print(out, true);
00567   return out;
00568 }

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