preliminary lua scripting framework for objects
[oweals/minetest.git] / src / utility.h
1 /*
2 Minetest-c55
3 Copyright (C) 2010 celeron55, Perttu Ahola <celeron55@gmail.com>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #ifndef UTILITY_HEADER
21 #define UTILITY_HEADER
22
23 #include <iostream>
24 #include <fstream>
25 #include <string>
26 #include <sstream>
27 #include <jthread.h>
28 #include <jmutex.h>
29 #include <jmutexautolock.h>
30
31 #include "common_irrlicht.h"
32 #include "debug.h"
33 #include "strfnd.h"
34 #include "exceptions.h"
35 #include "porting.h"
36
37 extern const v3s16 g_26dirs[26];
38
39 // 26th is (0,0,0)
40 extern const v3s16 g_27dirs[27];
41
42 inline void writeU32(u8 *data, u32 i)
43 {
44         data[0] = ((i>>24)&0xff);
45         data[1] = ((i>>16)&0xff);
46         data[2] = ((i>> 8)&0xff);
47         data[3] = ((i>> 0)&0xff);
48 }
49
50 inline void writeU16(u8 *data, u16 i)
51 {
52         data[0] = ((i>> 8)&0xff);
53         data[1] = ((i>> 0)&0xff);
54 }
55
56 inline void writeU8(u8 *data, u8 i)
57 {
58         data[0] = ((i>> 0)&0xff);
59 }
60
61 inline u32 readU32(u8 *data)
62 {
63         return (data[0]<<24) | (data[1]<<16) | (data[2]<<8) | (data[3]<<0);
64 }
65
66 inline u16 readU16(u8 *data)
67 {
68         return (data[0]<<8) | (data[1]<<0);
69 }
70
71 inline u8 readU8(u8 *data)
72 {
73         return (data[0]<<0);
74 }
75
76 // Signed variants of the above
77
78 inline void writeS32(u8 *data, s32 i){
79         writeU32(data, (u32)i);
80 }
81 inline s32 readS32(u8 *data){
82         return (s32)readU32(data);
83 }
84
85 inline void writeS16(u8 *data, s16 i){
86         writeU16(data, (u16)i);
87 }
88 inline s16 readS16(u8 *data){
89         return (s16)readU16(data);
90 }
91
92 inline void writeV3S32(u8 *data, v3s32 p)
93 {
94         writeS32(&data[0], p.X);
95         writeS32(&data[4], p.Y);
96         writeS32(&data[8], p.Z);
97 }
98
99 inline v3s32 readV3S32(u8 *data)
100 {
101         v3s32 p;
102         p.X = readS32(&data[0]);
103         p.Y = readS32(&data[4]);
104         p.Z = readS32(&data[8]);
105         return p;
106 }
107
108 inline void writeV2S16(u8 *data, v2s16 p)
109 {
110         writeS16(&data[0], p.X);
111         writeS16(&data[2], p.Y);
112 }
113
114 inline v2s16 readV2S16(u8 *data)
115 {
116         v2s16 p;
117         p.X = readS16(&data[0]);
118         p.Y = readS16(&data[2]);
119         return p;
120 }
121
122 inline void writeV2S32(u8 *data, v2s32 p)
123 {
124         writeS32(&data[0], p.X);
125         writeS32(&data[2], p.Y);
126 }
127
128 inline v2s32 readV2S32(u8 *data)
129 {
130         v2s32 p;
131         p.X = readS32(&data[0]);
132         p.Y = readS32(&data[2]);
133         return p;
134 }
135
136 inline void writeV3S16(u8 *data, v3s16 p)
137 {
138         writeS16(&data[0], p.X);
139         writeS16(&data[2], p.Y);
140         writeS16(&data[4], p.Z);
141 }
142
143 inline v3s16 readV3S16(u8 *data)
144 {
145         v3s16 p;
146         p.X = readS16(&data[0]);
147         p.Y = readS16(&data[2]);
148         p.Z = readS16(&data[4]);
149         return p;
150 }
151
152 /*
153         None of these are used at the moment
154 */
155
156 template <typename T>
157 class SharedPtr
158 {
159 public:
160         SharedPtr(T *t=NULL)
161         {
162                 refcount = new int;
163                 *refcount = 1;
164                 ptr = t;
165         }
166         SharedPtr(SharedPtr<T> &t)
167         {
168                 //*this = t;
169                 drop();
170                 refcount = t.refcount;
171                 (*refcount)++;
172                 ptr = t.ptr;
173         }
174         ~SharedPtr()
175         {
176                 drop();
177         }
178         SharedPtr<T> & operator=(T *t)
179         {
180                 drop();
181                 refcount = new int;
182                 *refcount = 1;
183                 ptr = t;
184                 return *this;
185         }
186         SharedPtr<T> & operator=(SharedPtr<T> &t)
187         {
188                 drop();
189                 refcount = t.refcount;
190                 (*refcount)++;
191                 ptr = t.ptr;
192                 return *this;
193         }
194         T* operator->()
195         {
196                 return ptr;
197         }
198         T & operator*()
199         {
200                 return *ptr;
201         }
202         bool operator!=(T *t)
203         {
204                 return ptr != t;
205         }
206         bool operator==(T *t)
207         {
208                 return ptr == t;
209         }
210         T & operator[](unsigned int i)
211         {
212                 return ptr[i];
213         }
214 private:
215         void drop()
216         {
217                 assert((*refcount) > 0);
218                 (*refcount)--;
219                 if(*refcount == 0)
220                 {
221                         delete refcount;
222                         if(ptr != NULL)
223                                 delete ptr;
224                 }
225         }
226         T *ptr;
227         int *refcount;
228 };
229
230 template <typename T>
231 class Buffer
232 {
233 public:
234         Buffer(unsigned int size)
235         {
236                 m_size = size;
237                 data = new T[size];
238         }
239         Buffer(const Buffer &buffer)
240         {
241                 m_size = buffer.m_size;
242                 data = new T[buffer.m_size];
243                 memcpy(data, buffer.data, buffer.m_size);
244         }
245         Buffer(T *t, unsigned int size)
246         {
247                 m_size = size;
248                 data = new T[size];
249                 memcpy(data, t, size);
250         }
251         ~Buffer()
252         {
253                 delete[] data;
254         }
255         T & operator[](unsigned int i) const
256         {
257                 return data[i];
258         }
259         T * operator*() const
260         {
261                 return data;
262         }
263         unsigned int getSize() const
264         {
265                 return m_size;
266         }
267 private:
268         T *data;
269         unsigned int m_size;
270 };
271
272 template <typename T>
273 class SharedBuffer
274 {
275 public:
276         SharedBuffer(unsigned int size)
277         {
278                 m_size = size;
279                 data = new T[size];
280                 refcount = new unsigned int;
281                 (*refcount) = 1;
282         }
283         SharedBuffer(const SharedBuffer &buffer)
284         {
285                 //std::cout<<"SharedBuffer(const SharedBuffer &buffer)"<<std::endl;
286                 m_size = buffer.m_size;
287                 data = buffer.data;
288                 refcount = buffer.refcount;
289                 (*refcount)++;
290         }
291         SharedBuffer & operator=(const SharedBuffer & buffer)
292         {
293                 //std::cout<<"SharedBuffer & operator=(const SharedBuffer & buffer)"<<std::endl;
294                 if(this == &buffer)
295                         return *this;
296                 drop();
297                 m_size = buffer.m_size;
298                 data = buffer.data;
299                 refcount = buffer.refcount;
300                 (*refcount)++;
301                 return *this;
302         }
303         /*
304                 Copies whole buffer
305         */
306         SharedBuffer(T *t, unsigned int size)
307         {
308                 m_size = size;
309                 data = new T[size];
310                 memcpy(data, t, size);
311                 refcount = new unsigned int;
312                 (*refcount) = 1;
313         }
314         /*
315                 Copies whole buffer
316         */
317         SharedBuffer(const Buffer<T> &buffer)
318         {
319                 m_size = buffer.m_size;
320                 data = new T[buffer.getSize()];
321                 memcpy(data, *buffer, buffer.getSize());
322                 refcount = new unsigned int;
323                 (*refcount) = 1;
324         }
325         ~SharedBuffer()
326         {
327                 drop();
328         }
329         T & operator[](unsigned int i) const
330         {
331                 return data[i];
332         }
333         T * operator*() const
334         {
335                 return data;
336         }
337         unsigned int getSize() const
338         {
339                 return m_size;
340         }
341 private:
342         void drop()
343         {
344                 assert((*refcount) > 0);
345                 (*refcount)--;
346                 if(*refcount == 0)
347                 {
348                         delete[] data;
349                         delete refcount;
350                 }
351         }
352         T *data;
353         unsigned int m_size;
354         unsigned int *refcount;
355 };
356
357 inline SharedBuffer<u8> SharedBufferFromString(const char *string)
358 {
359         SharedBuffer<u8> b((u8*)string, strlen(string)+1);
360         return b;
361 }
362
363 template<typename T>
364 class MutexedVariable
365 {
366 public:
367         MutexedVariable(T value):
368                 m_value(value)
369         {
370                 m_mutex.Init();
371         }
372
373         T get()
374         {
375                 JMutexAutoLock lock(m_mutex);
376                 return m_value;
377         }
378
379         void set(T value)
380         {
381                 JMutexAutoLock lock(m_mutex);
382                 m_value = value;
383         }
384         
385         // You'll want to grab this in a SharedPtr
386         JMutexAutoLock * getLock()
387         {
388                 return new JMutexAutoLock(m_mutex);
389         }
390         
391         // You pretty surely want to grab the lock when accessing this
392         T m_value;
393
394 private:
395         JMutex m_mutex;
396 };
397
398 /*
399         TimeTaker
400 */
401
402 class IrrlichtWrapper;
403
404 class TimeTaker
405 {
406 public:
407         TimeTaker(const char *name, u32 *result=NULL);
408
409         ~TimeTaker()
410         {
411                 stop();
412         }
413
414         u32 stop(bool quiet=false);
415
416         u32 getTime();
417
418 private:
419         const char *m_name;
420         u32 m_time1;
421         bool m_running;
422         u32 *m_result;
423 };
424
425 // Calculates the borders of a "d-radius" cube
426 inline void getFacePositions(core::list<v3s16> &list, u16 d)
427 {
428         if(d == 0)
429         {
430                 list.push_back(v3s16(0,0,0));
431                 return;
432         }
433         if(d == 1)
434         {
435                 /*
436                         This is an optimized sequence of coordinates.
437                 */
438                 list.push_back(v3s16( 0, 1, 0)); // top
439                 list.push_back(v3s16( 0, 0, 1)); // back
440                 list.push_back(v3s16(-1, 0, 0)); // left
441                 list.push_back(v3s16( 1, 0, 0)); // right
442                 list.push_back(v3s16( 0, 0,-1)); // front
443                 list.push_back(v3s16( 0,-1, 0)); // bottom
444                 // 6
445                 list.push_back(v3s16(-1, 0, 1)); // back left
446                 list.push_back(v3s16( 1, 0, 1)); // back right
447                 list.push_back(v3s16(-1, 0,-1)); // front left
448                 list.push_back(v3s16( 1, 0,-1)); // front right
449                 list.push_back(v3s16(-1,-1, 0)); // bottom left
450                 list.push_back(v3s16( 1,-1, 0)); // bottom right
451                 list.push_back(v3s16( 0,-1, 1)); // bottom back
452                 list.push_back(v3s16( 0,-1,-1)); // bottom front
453                 list.push_back(v3s16(-1, 1, 0)); // top left
454                 list.push_back(v3s16( 1, 1, 0)); // top right
455                 list.push_back(v3s16( 0, 1, 1)); // top back
456                 list.push_back(v3s16( 0, 1,-1)); // top front
457                 // 18
458                 list.push_back(v3s16(-1, 1, 1)); // top back-left
459                 list.push_back(v3s16( 1, 1, 1)); // top back-right
460                 list.push_back(v3s16(-1, 1,-1)); // top front-left
461                 list.push_back(v3s16( 1, 1,-1)); // top front-right
462                 list.push_back(v3s16(-1,-1, 1)); // bottom back-left
463                 list.push_back(v3s16( 1,-1, 1)); // bottom back-right
464                 list.push_back(v3s16(-1,-1,-1)); // bottom front-left
465                 list.push_back(v3s16( 1,-1,-1)); // bottom front-right
466                 // 26
467                 return;
468         }
469
470         // Take blocks in all sides, starting from y=0 and going +-y
471         for(s16 y=0; y<=d-1; y++)
472         {
473                 // Left and right side, including borders
474                 for(s16 z=-d; z<=d; z++)
475                 {
476                         list.push_back(v3s16(d,y,z));
477                         list.push_back(v3s16(-d,y,z));
478                         if(y != 0)
479                         {
480                                 list.push_back(v3s16(d,-y,z));
481                                 list.push_back(v3s16(-d,-y,z));
482                         }
483                 }
484                 // Back and front side, excluding borders
485                 for(s16 x=-d+1; x<=d-1; x++)
486                 {
487                         list.push_back(v3s16(x,y,d));
488                         list.push_back(v3s16(x,y,-d));
489                         if(y != 0)
490                         {
491                                 list.push_back(v3s16(x,-y,d));
492                                 list.push_back(v3s16(x,-y,-d));
493                         }
494                 }
495         }
496
497         // Take the bottom and top face with borders
498         // -d<x<d, y=+-d, -d<z<d
499         for(s16 x=-d; x<=d; x++)
500         for(s16 z=-d; z<=d; z++)
501         {
502                 list.push_back(v3s16(x,-d,z));
503                 list.push_back(v3s16(x,d,z));
504         }
505 }
506
507 class IndentationRaiser
508 {
509 public:
510         IndentationRaiser(u16 *indentation)
511         {
512                 m_indentation = indentation;
513                 (*m_indentation)++;
514         }
515         ~IndentationRaiser()
516         {
517                 (*m_indentation)--;
518         }
519 private:
520         u16 *m_indentation;
521 };
522
523 inline s16 getContainerPos(s16 p, s16 d)
524 {
525         return (p>=0 ? p : p-d+1) / d;
526 }
527
528 inline v2s16 getContainerPos(v2s16 p, s16 d)
529 {
530         return v2s16(
531                 getContainerPos(p.X, d),
532                 getContainerPos(p.Y, d)
533         );
534 }
535
536 inline v3s16 getContainerPos(v3s16 p, s16 d)
537 {
538         return v3s16(
539                 getContainerPos(p.X, d),
540                 getContainerPos(p.Y, d),
541                 getContainerPos(p.Z, d)
542         );
543 }
544
545 inline v2s16 getContainerPos(v2s16 p, v2s16 d)
546 {
547         return v2s16(
548                 getContainerPos(p.X, d.X),
549                 getContainerPos(p.Y, d.Y)
550         );
551 }
552
553 inline v3s16 getContainerPos(v3s16 p, v3s16 d)
554 {
555         return v3s16(
556                 getContainerPos(p.X, d.X),
557                 getContainerPos(p.Y, d.Y),
558                 getContainerPos(p.Z, d.Z)
559         );
560 }
561
562 inline bool isInArea(v3s16 p, s16 d)
563 {
564         return (
565                 p.X >= 0 && p.X < d &&
566                 p.Y >= 0 && p.Y < d &&
567                 p.Z >= 0 && p.Z < d
568         );
569 }
570
571 inline bool isInArea(v2s16 p, s16 d)
572 {
573         return (
574                 p.X >= 0 && p.X < d &&
575                 p.Y >= 0 && p.Y < d
576         );
577 }
578
579 inline bool isInArea(v3s16 p, v3s16 d)
580 {
581         return (
582                 p.X >= 0 && p.X < d.X &&
583                 p.Y >= 0 && p.Y < d.Y &&
584                 p.Z >= 0 && p.Z < d.Z
585         );
586 }
587
588 inline s16 rangelim(s16 i, s16 max)
589 {
590         if(i < 0)
591                 return 0;
592         if(i > max)
593                 return max;
594         return i;
595 }
596
597 #define rangelim(d, min, max) ((d) < (min) ? (min) : ((d)>(max)?(max):(d)))
598
599 inline v3s16 arealim(v3s16 p, s16 d)
600 {
601         if(p.X < 0)
602                 p.X = 0;
603         if(p.Y < 0)
604                 p.Y = 0;
605         if(p.Z < 0)
606                 p.Z = 0;
607         if(p.X > d-1)
608                 p.X = d-1;
609         if(p.Y > d-1)
610                 p.Y = d-1;
611         if(p.Z > d-1)
612                 p.Z = d-1;
613         return p;
614 }
615
616 inline std::wstring narrow_to_wide(const std::string& mbs)
617 {
618         size_t wcl = mbs.size();
619         SharedBuffer<wchar_t> wcs(wcl+1);
620         size_t l = mbstowcs(*wcs, mbs.c_str(), wcl);
621         wcs[l] = 0;
622         return *wcs;
623 }
624
625 inline std::string wide_to_narrow(const std::wstring& wcs)
626 {
627         size_t mbl = wcs.size()*4;
628         SharedBuffer<char> mbs(mbl+1);
629         size_t l = wcstombs(*mbs, wcs.c_str(), mbl);
630         if((int)l == -1)
631                 mbs[0] = 0;
632         else
633                 mbs[l] = 0;
634         return *mbs;
635 }
636
637 /*
638         See test.cpp for example cases.
639         wraps degrees to the range of -360...360
640         NOTE: Wrapping to 0...360 is not used because pitch needs negative values.
641 */
642 inline float wrapDegrees(float f)
643 {
644         // Take examples of f=10, f=720.5, f=-0.5, f=-360.5
645         // This results in
646         // 10, 720, -1, -361
647         int i = floor(f);
648         // 0, 2, 0, -1
649         int l = i / 360;
650         // NOTE: This would be used for wrapping to 0...360
651         // 0, 2, -1, -2
652         /*if(i < 0)
653                 l -= 1;*/
654         // 0, 720, 0, -360
655         int k = l * 360;
656         // 10, 0.5, -0.5, -0.5
657         f -= float(k);
658         return f;
659 }
660
661 inline std::string lowercase(const std::string &s)
662 {
663         std::string s2;
664         for(size_t i=0; i<s.size(); i++)
665         {
666                 char c = s[i];
667                 if(c >= 'A' && c <= 'Z')
668                         c -= 'A' - 'a';
669                 s2 += c;
670         }
671         return s2;
672 }
673
674 inline bool is_yes(const std::string &s)
675 {
676         std::string s2 = lowercase(trim(s));
677         if(s2 == "y" || s2 == "yes" || s2 == "true" || s2 == "1")
678                 return true;
679         return false;
680 }
681
682 inline s32 stoi(const std::string &s, s32 min, s32 max)
683 {
684         s32 i = atoi(s.c_str());
685         if(i < min)
686                 i = min;
687         if(i > max)
688                 i = max;
689         return i;
690 }
691
692 inline s32 stoi(std::string s)
693 {
694         return atoi(s.c_str());
695 }
696
697 inline float stof(std::string s)
698 {
699         float f;
700         std::istringstream ss(s);
701         ss>>f;
702         return f;
703 }
704
705 inline std::string itos(s32 i)
706 {
707         std::ostringstream o;
708         o<<i;
709         return o.str();
710 }
711
712 inline std::string ftos(float f)
713 {
714         std::ostringstream o;
715         o<<f;
716         return o.str();
717 }
718
719 inline void str_replace(std::string & str, std::string const & pattern,
720                 std::string const & replacement)
721 {
722         std::string::size_type start = str.find(pattern, 0);
723         while(start != str.npos)
724         {
725                 str.replace(start, pattern.size(), replacement);
726                 start = str.find(pattern, start+replacement.size());
727         }
728 }
729
730 inline void str_replace_char(std::string & str, char from, char to)
731 {
732         for(unsigned int i=0; i<str.size(); i++)
733         {
734                 if(str[i] == from)
735                         str[i] = to;
736         }
737 }
738
739 /*
740         A base class for simple background thread implementation
741 */
742
743 class SimpleThread : public JThread
744 {
745         bool run;
746         JMutex run_mutex;
747
748 public:
749
750         SimpleThread():
751                 JThread(),
752                 run(true)
753         {
754                 run_mutex.Init();
755         }
756
757         virtual ~SimpleThread()
758         {}
759
760         virtual void * Thread() = 0;
761
762         bool getRun()
763         {
764                 JMutexAutoLock lock(run_mutex);
765                 return run;
766         }
767         void setRun(bool a_run)
768         {
769                 JMutexAutoLock lock(run_mutex);
770                 run = a_run;
771         }
772
773         void stop()
774         {
775                 setRun(false);
776                 while(IsRunning())
777                         sleep_ms(100);
778         }
779 };
780
781 /*
782         Config stuff
783 */
784
785 enum ValueType
786 {
787         VALUETYPE_STRING,
788         VALUETYPE_FLAG // Doesn't take any arguments
789 };
790
791 struct ValueSpec
792 {
793         ValueSpec(ValueType a_type, const char *a_help=NULL)
794         {
795                 type = a_type;
796                 help = a_help;
797         }
798         ValueType type;
799         const char *help;
800 };
801
802 class Settings
803 {
804 public:
805         Settings()
806         {
807                 m_mutex.Init();
808         }
809
810         void writeLines(std::ostream &os)
811         {
812                 JMutexAutoLock lock(m_mutex);
813                 
814                 for(core::map<std::string, std::string>::Iterator
815                                 i = m_settings.getIterator();
816                                 i.atEnd() == false; i++)
817                 {
818                         std::string name = i.getNode()->getKey();
819                         std::string value = i.getNode()->getValue();
820                         os<<name<<" = "<<value<<"\n";
821                 }
822         }
823
824         bool parseConfigLine(const std::string &line)
825         {
826                 JMutexAutoLock lock(m_mutex);
827                 
828                 std::string trimmedline = trim(line);
829                 
830                 // Ignore comments
831                 if(trimmedline[0] == '#')
832                         return true;
833
834                 //dstream<<"trimmedline=\""<<trimmedline<<"\""<<std::endl;
835
836                 Strfnd sf(trim(line));
837
838                 std::string name = sf.next("=");
839                 name = trim(name);
840
841                 if(name == "")
842                         return true;
843                 
844                 std::string value = sf.next("\n");
845                 value = trim(value);
846
847                 /*dstream<<"Config name=\""<<name<<"\" value=\""
848                                 <<value<<"\""<<std::endl;*/
849                 
850                 m_settings[name] = value;
851                 
852                 return true;
853         }
854
855         // Returns false on EOF
856         bool parseConfigObject(std::istream &is)
857         {
858                 if(is.eof())
859                         return false;
860                 
861                 /*
862                         NOTE: This function might be expanded to allow multi-line
863                               settings.
864                 */
865                 std::string line;
866                 std::getline(is, line);
867                 //dstream<<"got line: \""<<line<<"\""<<std::endl;
868
869                 return parseConfigLine(line);
870         }
871
872         /*
873                 Read configuration file
874
875                 Returns true on success
876         */
877         bool readConfigFile(const char *filename)
878         {
879                 std::ifstream is(filename);
880                 if(is.good() == false)
881                 {
882                         dstream<<"Error opening configuration file \""
883                                         <<filename<<"\""<<std::endl;
884                         return false;
885                 }
886
887                 dstream<<"Parsing configuration file: \""
888                                 <<filename<<"\""<<std::endl;
889                                 
890                 while(parseConfigObject(is));
891                 
892                 return true;
893         }
894
895         /*
896                 Reads a configuration object from stream (usually a single line)
897                 and adds it to dst.
898                 
899                 Preserves comments and empty lines.
900
901                 Settings that were added to dst are also added to updated.
902                 key of updated is setting name, value of updated is dummy.
903
904                 Returns false on EOF
905         */
906         bool getUpdatedConfigObject(std::istream &is,
907                         core::list<std::string> &dst,
908                         core::map<std::string, bool> &updated)
909         {
910                 JMutexAutoLock lock(m_mutex);
911                 
912                 if(is.eof())
913                         return false;
914                 
915                 // NOTE: This function will be expanded to allow multi-line settings
916                 std::string line;
917                 std::getline(is, line);
918
919                 std::string trimmedline = trim(line);
920
921                 std::string line_end = "";
922                 if(is.eof() == false)
923                         line_end = "\n";
924                 
925                 // Ignore comments
926                 if(trimmedline[0] == '#')
927                 {
928                         dst.push_back(line+line_end);
929                         return true;
930                 }
931
932                 Strfnd sf(trim(line));
933
934                 std::string name = sf.next("=");
935                 name = trim(name);
936
937                 if(name == "")
938                 {
939                         dst.push_back(line+line_end);
940                         return true;
941                 }
942                 
943                 std::string value = sf.next("\n");
944                 value = trim(value);
945                 
946                 if(m_settings.find(name))
947                 {
948                         std::string newvalue = m_settings[name];
949                         
950                         if(newvalue != value)
951                         {
952                                 dstream<<"Changing value of \""<<name<<"\" = \""
953                                                 <<value<<"\" -> \""<<newvalue<<"\""
954                                                 <<std::endl;
955                         }
956
957                         dst.push_back(name + " = " + newvalue + line_end);
958
959                         updated[name] = true;
960                 }
961                 
962                 return true;
963         }
964
965         /*
966                 Updates configuration file
967
968                 Returns true on success
969         */
970         bool updateConfigFile(const char *filename)
971         {
972                 dstream<<"Updating configuration file: \""
973                                 <<filename<<"\""<<std::endl;
974                 
975                 core::list<std::string> objects;
976                 core::map<std::string, bool> updated;
977                 
978                 // Read and modify stuff
979                 {
980                         std::ifstream is(filename);
981                         if(is.good() == false)
982                         {
983                                 dstream<<"INFO: updateConfigFile():"
984                                                 " Error opening configuration file"
985                                                 " for reading: \""
986                                                 <<filename<<"\""<<std::endl;
987                         }
988                         else
989                         {
990                                 while(getUpdatedConfigObject(is, objects, updated));
991                         }
992                 }
993                 
994                 JMutexAutoLock lock(m_mutex);
995                 
996                 // Write stuff back
997                 {
998                         std::ofstream os(filename);
999                         if(os.good() == false)
1000                         {
1001                                 dstream<<"Error opening configuration file"
1002                                                 " for writing: \""
1003                                                 <<filename<<"\""<<std::endl;
1004                                 return false;
1005                         }
1006                         
1007                         /*
1008                                 Write updated stuff
1009                         */
1010                         for(core::list<std::string>::Iterator
1011                                         i = objects.begin();
1012                                         i != objects.end(); i++)
1013                         {
1014                                 os<<(*i);
1015                         }
1016
1017                         /*
1018                                 Write stuff that was not already in the file
1019                         */
1020                         for(core::map<std::string, std::string>::Iterator
1021                                         i = m_settings.getIterator();
1022                                         i.atEnd() == false; i++)
1023                         {
1024                                 if(updated.find(i.getNode()->getKey()))
1025                                         continue;
1026                                 std::string name = i.getNode()->getKey();
1027                                 std::string value = i.getNode()->getValue();
1028                                 dstream<<"Adding \""<<name<<"\" = \""<<value<<"\""
1029                                                 <<std::endl;
1030                                 os<<name<<" = "<<value<<"\n";
1031                         }
1032                 }
1033                 
1034                 return true;
1035         }
1036
1037         /*
1038                 NOTE: Types of allowed_options are ignored
1039
1040                 returns true on success
1041         */
1042         bool parseCommandLine(int argc, char *argv[],
1043                         core::map<std::string, ValueSpec> &allowed_options)
1044         {
1045                 int i=1;
1046                 for(;;)
1047                 {
1048                         if(i >= argc)
1049                                 break;
1050                         std::string argname = argv[i];
1051                         if(argname.substr(0, 2) != "--")
1052                         {
1053                                 dstream<<"Invalid command-line parameter \""
1054                                                 <<argname<<"\": --<option> expected."<<std::endl;
1055                                 return false;
1056                         }
1057                         i++;
1058
1059                         std::string name = argname.substr(2);
1060
1061                         core::map<std::string, ValueSpec>::Node *n;
1062                         n = allowed_options.find(name);
1063                         if(n == NULL)
1064                         {
1065                                 dstream<<"Unknown command-line parameter \""
1066                                                 <<argname<<"\""<<std::endl;
1067                                 return false;
1068                         }
1069
1070                         ValueType type = n->getValue().type;
1071
1072                         std::string value = "";
1073                         
1074                         if(type == VALUETYPE_FLAG)
1075                         {
1076                                 value = "true";
1077                         }
1078                         else
1079                         {
1080                                 if(i >= argc)
1081                                 {
1082                                         dstream<<"Invalid command-line parameter \""
1083                                                         <<name<<"\": missing value"<<std::endl;
1084                                         return false;
1085                                 }
1086                                 value = argv[i];
1087                                 i++;
1088                         }
1089                         
1090
1091                         dstream<<"Valid command-line parameter: \""
1092                                         <<name<<"\" = \""<<value<<"\""
1093                                         <<std::endl;
1094                         set(name, value);
1095                 }
1096
1097                 return true;
1098         }
1099
1100         void set(std::string name, std::string value)
1101         {
1102                 JMutexAutoLock lock(m_mutex);
1103                 
1104                 m_settings[name] = value;
1105         }
1106
1107         void setDefault(std::string name, std::string value)
1108         {
1109                 JMutexAutoLock lock(m_mutex);
1110                 
1111                 m_defaults[name] = value;
1112         }
1113
1114         bool exists(std::string name)
1115         {
1116                 JMutexAutoLock lock(m_mutex);
1117                 
1118                 return (m_settings.find(name) || m_defaults.find(name));
1119         }
1120
1121         std::string get(std::string name)
1122         {
1123                 JMutexAutoLock lock(m_mutex);
1124                 
1125                 core::map<std::string, std::string>::Node *n;
1126                 n = m_settings.find(name);
1127                 if(n == NULL)
1128                 {
1129                         n = m_defaults.find(name);
1130                         if(n == NULL)
1131                         {
1132                                 dstream<<"INFO: Settings: Setting not found: \""
1133                                                 <<name<<"\""<<std::endl;
1134                                 throw SettingNotFoundException("Setting not found");
1135                         }
1136                 }
1137
1138                 return n->getValue();
1139         }
1140
1141         bool getBool(std::string name)
1142         {
1143                 return is_yes(get(name));
1144         }
1145         
1146         bool getFlag(std::string name)
1147         {
1148                 try
1149                 {
1150                         return getBool(name);
1151                 }
1152                 catch(SettingNotFoundException &e)
1153                 {
1154                         return false;
1155                 }
1156         }
1157
1158         // Asks if empty
1159         bool getBoolAsk(std::string name, std::string question, bool def)
1160         {
1161                 // If it is in settings
1162                 if(exists(name))
1163                         return getBool(name);
1164                 
1165                 std::string s;
1166                 char templine[10];
1167                 std::cout<<question<<" [y/N]: ";
1168                 std::cin.getline(templine, 10);
1169                 s = templine;
1170
1171                 if(s == "")
1172                         return def;
1173
1174                 return is_yes(s);
1175         }
1176
1177         float getFloat(std::string name)
1178         {
1179                 return stof(get(name));
1180         }
1181
1182         u16 getU16(std::string name)
1183         {
1184                 return stoi(get(name), 0, 65535);
1185         }
1186
1187         u16 getU16Ask(std::string name, std::string question, u16 def)
1188         {
1189                 // If it is in settings
1190                 if(exists(name))
1191                         return getU16(name);
1192                 
1193                 std::string s;
1194                 char templine[10];
1195                 std::cout<<question<<" ["<<def<<"]: ";
1196                 std::cin.getline(templine, 10);
1197                 s = templine;
1198
1199                 if(s == "")
1200                         return def;
1201
1202                 return stoi(s, 0, 65535);
1203         }
1204
1205         s16 getS16(std::string name)
1206         {
1207                 return stoi(get(name), -32768, 32767);
1208         }
1209
1210         s32 getS32(std::string name)
1211         {
1212                 return stoi(get(name));
1213         }
1214
1215         v3f getV3F(std::string name)
1216         {
1217                 v3f value;
1218                 Strfnd f(get(name));
1219                 f.next("(");
1220                 value.X = stof(f.next(","));
1221                 value.Y = stof(f.next(","));
1222                 value.Z = stof(f.next(")"));
1223                 return value;
1224         }
1225
1226         u64 getU64(std::string name)
1227         {
1228                 u64 value = 0;
1229                 std::string s = get(name);
1230                 std::istringstream ss(s);
1231                 ss>>value;
1232                 return value;
1233         }
1234
1235         void setS32(std::string name, s32 value)
1236         {
1237                 set(name, itos(value));
1238         }
1239
1240         void setFloat(std::string name, float value)
1241         {
1242                 set(name, ftos(value));
1243         }
1244
1245         void setV3F(std::string name, v3f value)
1246         {
1247                 std::ostringstream os;
1248                 os<<"("<<value.X<<","<<value.Y<<","<<value.Z<<")";
1249                 set(name, os.str());
1250         }
1251
1252         void setU64(std::string name, u64 value)
1253         {
1254                 std::ostringstream os;
1255                 os<<value;
1256                 set(name, os.str());
1257         }
1258
1259         void clear()
1260         {
1261                 JMutexAutoLock lock(m_mutex);
1262                 
1263                 m_settings.clear();
1264                 m_defaults.clear();
1265         }
1266
1267         Settings & operator+=(Settings &other)
1268         {
1269                 JMutexAutoLock lock(m_mutex);
1270                 JMutexAutoLock lock2(other.m_mutex);
1271                 
1272                 if(&other == this)
1273                         return *this;
1274
1275                 for(core::map<std::string, std::string>::Iterator
1276                                 i = other.m_settings.getIterator();
1277                                 i.atEnd() == false; i++)
1278                 {
1279                         m_settings.insert(i.getNode()->getKey(),
1280                                         i.getNode()->getValue());
1281                 }
1282                 
1283                 for(core::map<std::string, std::string>::Iterator
1284                                 i = other.m_defaults.getIterator();
1285                                 i.atEnd() == false; i++)
1286                 {
1287                         m_defaults.insert(i.getNode()->getKey(),
1288                                         i.getNode()->getValue());
1289                 }
1290
1291         }
1292
1293         Settings & operator=(Settings &other)
1294         {
1295                 JMutexAutoLock lock(m_mutex);
1296                 JMutexAutoLock lock2(other.m_mutex);
1297                 
1298                 if(&other == this)
1299                         return *this;
1300
1301                 clear();
1302                 (*this) += other;
1303                 
1304                 return *this;
1305         }
1306
1307 private:
1308         core::map<std::string, std::string> m_settings;
1309         core::map<std::string, std::string> m_defaults;
1310         // All methods that access m_settings/m_defaults directly should lock this.
1311         JMutex m_mutex;
1312 };
1313
1314 /*
1315         FIFO queue
1316 */
1317 template<typename T>
1318 class Queue
1319 {
1320 public:
1321         void push_back(T t)
1322         {
1323                 m_list.push_back(t);
1324         }
1325         
1326         T pop_front()
1327         {
1328                 if(m_list.size() == 0)
1329                         throw ItemNotFoundException("MutexedQueue: queue is empty");
1330
1331                 typename core::list<T>::Iterator begin = m_list.begin();
1332                 T t = *begin;
1333                 m_list.erase(begin);
1334                 return t;
1335         }
1336
1337         u32 size()
1338         {
1339                 return m_list.size();
1340         }
1341
1342 protected:
1343         core::list<T> m_list;
1344 };
1345
1346 /*
1347         Thread-safe FIFO queue
1348 */
1349
1350 template<typename T>
1351 class MutexedQueue
1352 {
1353 public:
1354         MutexedQueue()
1355         {
1356                 m_mutex.Init();
1357         }
1358         u32 size()
1359         {
1360                 return m_list.size();
1361         }
1362         void push_back(T t)
1363         {
1364                 JMutexAutoLock lock(m_mutex);
1365                 m_list.push_back(t);
1366         }
1367         T pop_front(u32 wait_time_max_ms=0)
1368         {
1369                 u32 wait_time_ms = 0;
1370
1371                 for(;;)
1372                 {
1373                         {
1374                                 JMutexAutoLock lock(m_mutex);
1375
1376                                 if(m_list.size() > 0)
1377                                 {
1378                                         typename core::list<T>::Iterator begin = m_list.begin();
1379                                         T t = *begin;
1380                                         m_list.erase(begin);
1381                                         return t;
1382                                 }
1383
1384                                 if(wait_time_ms >= wait_time_max_ms)
1385                                         throw ItemNotFoundException("MutexedQueue: queue is empty");
1386                         }
1387
1388                         // Wait a while before trying again
1389                         sleep_ms(10);
1390                         wait_time_ms += 10;
1391                 }
1392         }
1393
1394         JMutex & getMutex()
1395         {
1396                 return m_mutex;
1397         }
1398
1399         core::list<T> & getList()
1400         {
1401                 return m_list;
1402         }
1403
1404 protected:
1405         JMutex m_mutex;
1406         core::list<T> m_list;
1407 };
1408
1409 template<typename Caller, typename Data>
1410 class CallerInfo
1411 {
1412 public:
1413         Caller caller;
1414         Data data;
1415 };
1416
1417 template<typename Key, typename T, typename Caller, typename CallerData>
1418 class GetResult
1419 {
1420 public:
1421         Key key;
1422         T item;
1423         core::list<CallerInfo<Caller, CallerData> > callers;
1424 };
1425
1426 template<typename Key, typename T, typename Caller, typename CallerData>
1427 class ResultQueue: public MutexedQueue< GetResult<Key, T, Caller, CallerData> >
1428 {
1429 };
1430
1431 template<typename Key, typename T, typename Caller, typename CallerData>
1432 class GetRequest
1433 {
1434 public:
1435         GetRequest()
1436         {
1437                 dest = NULL;
1438         }
1439         GetRequest(ResultQueue<Key,T, Caller, CallerData> *a_dest)
1440         {
1441                 dest = a_dest;
1442         }
1443         GetRequest(ResultQueue<Key,T, Caller, CallerData> *a_dest,
1444                         Key a_key)
1445         {
1446                 dest = a_dest;
1447                 key = a_key;
1448         }
1449         ~GetRequest()
1450         {
1451         }
1452         
1453         Key key;
1454         ResultQueue<Key, T, Caller, CallerData> *dest;
1455         core::list<CallerInfo<Caller, CallerData> > callers;
1456 };
1457
1458 /*
1459         Quickhands for typical request-result queues.
1460         Used for distributing work between threads.
1461 */
1462
1463 template<typename Key, typename T, typename Caller, typename CallerData>
1464 class RequestQueue
1465 {
1466 public:
1467         u32 size()
1468         {
1469                 return m_queue.size();
1470         }
1471
1472         void add(Key key, Caller caller, CallerData callerdata,
1473                         ResultQueue<Key, T, Caller, CallerData> *dest)
1474         {
1475                 JMutexAutoLock lock(m_queue.getMutex());
1476                 
1477                 /*
1478                         If the caller is already on the list, only update CallerData
1479                 */
1480                 for(typename core::list< GetRequest<Key, T, Caller, CallerData> >::Iterator
1481                                 i = m_queue.getList().begin();
1482                                 i != m_queue.getList().end(); i++)
1483                 {
1484                         GetRequest<Key, T, Caller, CallerData> &request = *i;
1485
1486                         if(request.key == key)
1487                         {
1488                                 for(typename core::list< CallerInfo<Caller, CallerData> >::Iterator
1489                                                 i = request.callers.begin();
1490                                                 i != request.callers.end(); i++)
1491                                 {
1492                                         CallerInfo<Caller, CallerData> &ca = *i;
1493                                         if(ca.caller == caller)
1494                                         {
1495                                                 ca.data = callerdata;
1496                                                 return;
1497                                         }
1498                                 }
1499                                 CallerInfo<Caller, CallerData> ca;
1500                                 ca.caller = caller;
1501                                 ca.data = callerdata;
1502                                 request.callers.push_back(ca);
1503                                 return;
1504                         }
1505                 }
1506
1507                 /*
1508                         Else add a new request to the queue
1509                 */
1510
1511                 GetRequest<Key, T, Caller, CallerData> request;
1512                 request.key = key;
1513                 CallerInfo<Caller, CallerData> ca;
1514                 ca.caller = caller;
1515                 ca.data = callerdata;
1516                 request.callers.push_back(ca);
1517                 request.dest = dest;
1518                 
1519                 m_queue.getList().push_back(request);
1520         }
1521
1522         GetRequest<Key, T, Caller, CallerData> pop(bool wait_if_empty=false)
1523         {
1524                 return m_queue.pop_front(wait_if_empty);
1525         }
1526
1527 private:
1528         MutexedQueue< GetRequest<Key, T, Caller, CallerData> > m_queue;
1529 };
1530
1531 /*
1532         Pseudo-random (VC++ rand() sucks)
1533 */
1534 int myrand(void);
1535 void mysrand(unsigned seed);
1536 #define MYRAND_MAX 32767
1537
1538 inline int myrand_range(int min, int max)
1539 {
1540         if(min > max)
1541         {
1542                 assert(0);
1543                 return max;
1544         }
1545         return (myrand()%(max-min+1))+min;
1546 }
1547
1548 /*
1549         Miscellaneous functions
1550 */
1551
1552 bool isBlockInSight(v3s16 blockpos_b, v3f camera_pos, v3f camera_dir, f32 range,
1553                 f32 *distance_ptr=NULL);
1554
1555 /*
1556         Queue with unique values with fast checking of value existence
1557 */
1558
1559 template<typename Value>
1560 class UniqueQueue
1561 {
1562 public:
1563         
1564         /*
1565                 Does nothing if value is already queued.
1566                 Return value:
1567                         true: value added
1568                         false: value already exists
1569         */
1570         bool push_back(Value value)
1571         {
1572                 // Check if already exists
1573                 if(m_map.find(value) != NULL)
1574                         return false;
1575
1576                 // Add
1577                 m_map.insert(value, 0);
1578                 m_list.push_back(value);
1579                 
1580                 return true;
1581         }
1582
1583         Value pop_front()
1584         {
1585                 typename core::list<Value>::Iterator i = m_list.begin();
1586                 Value value = *i;
1587                 m_map.remove(value);
1588                 m_list.erase(i);
1589                 return value;
1590         }
1591
1592         u32 size()
1593         {
1594                 assert(m_list.size() == m_map.size());
1595                 return m_list.size();
1596         }
1597
1598 private:
1599         core::map<Value, u8> m_map;
1600         core::list<Value> m_list;
1601 };
1602
1603 #if 0
1604 template<typename Key, typename Value>
1605 class MutexedCache
1606 {
1607 public:
1608         MutexedCache()
1609         {
1610                 m_mutex.Init();
1611                 assert(m_mutex.IsInitialized());
1612         }
1613         
1614         void set(const Key &name, const Value &value)
1615         {
1616                 JMutexAutoLock lock(m_mutex);
1617
1618                 m_values[name] = value;
1619         }
1620         
1621         bool get(const Key &name, Value *result)
1622         {
1623                 JMutexAutoLock lock(m_mutex);
1624
1625                 typename core::map<Key, Value>::Node *n;
1626                 n = m_values.find(name);
1627
1628                 if(n == NULL)
1629                         return false;
1630
1631                 *result = n->getValue();
1632                 return true;
1633         }
1634
1635 private:
1636         core::map<Key, Value> m_values;
1637         JMutex m_mutex;
1638 };
1639 #endif
1640
1641 /*
1642         Generates ids for comparable values.
1643         Id=0 is reserved for "no value".
1644
1645         Is fast at:
1646         - Returning value by id (very fast)
1647         - Returning id by value
1648         - Generating a new id for a value
1649
1650         Is not able to:
1651         - Remove an id/value pair (is possible to implement but slow)
1652 */
1653 template<typename T>
1654 class MutexedIdGenerator
1655 {
1656 public:
1657         MutexedIdGenerator()
1658         {
1659                 m_mutex.Init();
1660                 assert(m_mutex.IsInitialized());
1661         }
1662         
1663         // Returns true if found
1664         bool getValue(u32 id, T &value)
1665         {
1666                 if(id == 0)
1667                         return false;
1668                 JMutexAutoLock lock(m_mutex);
1669                 if(m_id_to_value.size() < id)
1670                         return false;
1671                 value = m_id_to_value[id-1];
1672                 return true;
1673         }
1674         
1675         // If id exists for value, returns the id.
1676         // Otherwise generates an id for the value.
1677         u32 getId(const T &value)
1678         {
1679                 JMutexAutoLock lock(m_mutex);
1680                 typename core::map<T, u32>::Node *n;
1681                 n = m_value_to_id.find(value);
1682                 if(n != NULL)
1683                         return n->getValue();
1684                 m_id_to_value.push_back(value);
1685                 u32 new_id = m_id_to_value.size();
1686                 m_value_to_id.insert(value, new_id);
1687                 return new_id;
1688         }
1689
1690 private:
1691         JMutex m_mutex;
1692         // Values are stored here at id-1 position (id 1 = [0])
1693         core::array<T> m_id_to_value;
1694         core::map<T, u32> m_value_to_id;
1695 };
1696
1697 /*
1698         Checks if a string contains only supplied characters
1699 */
1700 inline bool string_allowed(const std::string &s, const std::string &allowed_chars)
1701 {
1702         for(u32 i=0; i<s.size(); i++)
1703         {
1704                 bool confirmed = false;
1705                 for(u32 j=0; j<allowed_chars.size(); j++)
1706                 {
1707                         if(s[i] == allowed_chars[j])
1708                         {
1709                                 confirmed = true;
1710                                 break;
1711                         }
1712                 }
1713                 if(confirmed == false)
1714                         return false;
1715         }
1716         return true;
1717 }
1718
1719 /*
1720         Forcefully wraps string into rows using \n
1721         (no word wrap, used for showing paths in gui)
1722 */
1723 inline std::string wrap_rows(const std::string &from, u32 rowlen)
1724 {
1725         std::string to;
1726         for(u32 i=0; i<from.size(); i++)
1727         {
1728                 if(i != 0 && i%rowlen == 0)
1729                         to += '\n';
1730                 to += from[i];
1731         }
1732         return to;
1733 }
1734
1735 /*
1736         Some helper stuff
1737 */
1738 #define MYMIN(a,b) ((a)<(b)?(a):(b))
1739 #define MYMAX(a,b) ((a)>(b)?(a):(b))
1740
1741 /*
1742         Returns integer position of node in given floating point position
1743 */
1744 inline v3s16 floatToInt(v3f p, f32 d)
1745 {
1746         v3s16 p2(
1747                 (p.X + (p.X>0 ? d/2 : -d/2))/d,
1748                 (p.Y + (p.Y>0 ? d/2 : -d/2))/d,
1749                 (p.Z + (p.Z>0 ? d/2 : -d/2))/d);
1750         return p2;
1751 }
1752
1753 /*
1754         Returns floating point position of node in given integer position
1755 */
1756 inline v3f intToFloat(v3s16 p, f32 d)
1757 {
1758         v3f p2(
1759                 (f32)p.X * d,
1760                 (f32)p.Y * d,
1761                 (f32)p.Z * d
1762         );
1763         return p2;
1764 }
1765
1766 /*
1767         More serialization stuff
1768 */
1769
1770 // Creates a string with the length as the first two bytes
1771 inline std::string serializeString(const std::string plain)
1772 {
1773         assert(plain.size() <= 65535);
1774         char buf[2];
1775         writeU16((u8*)&buf[0], plain.size());
1776         std::string s;
1777         s.append(buf, 2);
1778         s.append(plain);
1779         return s;
1780 }
1781
1782 // Reads a string with the length as the first two bytes
1783 inline std::string deSerializeString(const std::string encoded)
1784 {
1785         u16 s_size = readU16((u8*)&encoded.c_str()[0]);
1786         std::string s;
1787         s.reserve(s_size);
1788         s.append(&encoded.c_str()[2], s_size);
1789         return s;
1790 }
1791
1792 // Reads a string with the length as the first two bytes
1793 inline std::string deSerializeString(std::istream &is)
1794 {
1795         char buf[2];
1796         is.read(buf, 2);
1797         u16 s_size = readU16((u8*)buf);
1798         Buffer<char> buf2(s_size);
1799         is.read(&buf2[0], s_size);
1800         std::string s;
1801         s.reserve(s_size);
1802         s.append(&buf2[0], s_size);
1803         return s;
1804 }
1805
1806 // Creates a string with the length as the first four bytes
1807 inline std::string serializeLongString(const std::string plain)
1808 {
1809         char buf[4];
1810         writeU32((u8*)&buf[0], plain.size());
1811         std::string s;
1812         s.append(buf, 4);
1813         s.append(plain);
1814         return s;
1815 }
1816
1817 // Reads a string with the length as the first four bytes
1818 inline std::string deSerializeLongString(const std::string encoded)
1819 {
1820         u32 s_size = readU32((u8*)&encoded.c_str()[0]);
1821         std::string s;
1822         s.reserve(s_size);
1823         s.append(&encoded.c_str()[2], s_size);
1824         return s;
1825 }
1826
1827 // Reads a string with the length as the first four bytes
1828 inline std::string deSerializeLongString(std::istream &is)
1829 {
1830         char buf[4];
1831         is.read(buf, 4);
1832         u32 s_size = readU32((u8*)buf);
1833         Buffer<char> buf2(s_size);
1834         is.read(&buf2[0], s_size);
1835         std::string s;
1836         s.reserve(s_size);
1837         s.append(&buf2[0], s_size);
1838         return s;
1839 }
1840
1841 #endif
1842