1 /* ScummVM - Graphic Adventure Engine
2  *
3  * ScummVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the COPYRIGHT
5  * file distributed with this source distribution.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  *
21  */
22 
23 #ifndef ULTIMA8_USECODE_UCLIST_H
24 #define ULTIMA8_USECODE_UCLIST_H
25 
26 #include "ultima/shared/std/containers.h"
27 #include "ultima/shared/std/string.h"
28 
29 namespace Ultima {
30 namespace Ultima8 {
31 
32 // stringlists: _elementSize = 2, each element is actually a stringref
33 // see for example the 0x0E opcode: there is no way to see if the
34 // created list is a stringlist or not
35 // the opcodes which do need a distinction have a operand for this.
36 
37 // Question: how are unionList/subtractList supposed to know what to do?
38 // their behaviour differs if this is a stringlist
39 
40 // Question: does subtractList remove _all_ occurences of elements or only 1?
41 
42 class UCList {
43 	Std::vector<uint8> _elements;
44 	unsigned int _elementSize;
45 	unsigned int _size;
46 
47 public:
48 	UCList(unsigned int elementSize, unsigned int capacity = 0) :
_elementSize(elementSize)49 		_elementSize(elementSize), _size(0) {
50 		if (capacity > 0)
51 			_elements.reserve(_elementSize * capacity);
52 	}
53 
~UCList()54 	~UCList() {
55 		// Slight problem: we don't know if we're a stringlist.
56 		// So we need to hope something else has ensured any strings
57 		// are already freed.
58 		free();
59 	}
60 
61 	const uint8 *operator[](uint32 index) const {
62 		// check that index isn't out of bounds...
63 		return &(_elements[index * _elementSize]);
64 	}
65 
getuint16(uint32 index)66 	uint16 getuint16(uint32 index) const {
67 		assert(_elementSize == 2);
68 		uint16 t = _elements[index * _elementSize];
69 		t += _elements[index * _elementSize + 1] << 8;
70 		return t;
71 	}
72 
append(const uint8 * e)73 	void append(const uint8 *e) {
74 		_elements.resize((_size + 1) * _elementSize);
75 		for (unsigned int i = 0; i < _elementSize; i++)
76 			_elements[_size * _elementSize + i] = e[i];
77 		_size++;
78 	}
79 
appenduint16(uint16 val)80 	void appenduint16(uint16 val) {
81 		assert(_elementSize == 2);
82 		uint8 buf[2];
83 		buf[0] = static_cast<uint8>(val);
84 		buf[1] = static_cast<uint8>(val >> 8);
85 		append(buf);
86 	}
87 
remove(const uint8 * e)88 	void remove(const uint8 *e) {
89 		// do we need to erase all occurences of e or just the first one?
90 		// (deleting all, currently)
91 		for (unsigned int i = 0; i < _size; i++) {
92 			bool equal = true;
93 			for (unsigned int j = 0; j < _elementSize && equal; j++)
94 				equal = equal && (_elements[i * _elementSize + j] == e[j]);
95 			if (equal) {
96 				_elements.erase(_elements.begin() + i * _elementSize,
97 				               _elements.begin() + (i + 1)*_elementSize);
98 				_size--;
99 				i--; // back up a bit
100 			}
101 		}
102 	}
103 
inList(const uint8 * e)104 	bool inList(const uint8 *e) const {
105 		for (unsigned int i = 0; i < _size; i++) {
106 			bool equal = true;
107 			for (unsigned int j = 0; j < _elementSize && equal; j++)
108 				equal = (_elements[i * _elementSize + j] == e[j]);
109 			if (equal)
110 				return true;
111 		}
112 		return false;
113 	}
114 
appendList(const UCList & l)115 	void appendList(const UCList &l) {
116 		// elementsizes should match...
117 		assert(_elementSize == l.getElementSize());
118 		_elements.reserve(_elementSize * (_size + l._size));
119 		for (unsigned int i = 0; i < l._size; i++)
120 			append(l[i]);
121 	}
unionList(const UCList & l)122 	void unionList(const UCList &l) { // like append, but remove duplicates
123 		// elementsizes should match...
124 		assert(_elementSize == l.getElementSize());
125 		_elements.reserve(_elementSize * (_size + l._size));
126 		for (unsigned int i = 0; i < l._size; i++)
127 			if (!inList(l[i]))
128 				append(l[i]);
129 	}
subtractList(const UCList & l)130 	void subtractList(const UCList &l) {
131 		// elementsizes should match...
132 		assert(_elementSize == l.getElementSize());
133 		for (unsigned int i = 0; i < l._size; i++)
134 			remove(l[i]);
135 	}
136 
free()137 	void free() {
138 		_elements.clear();
139 		_size = 0;
140 	}
getSize()141 	uint32 getSize() const {
142 		return _size;
143 	}
getElementSize()144 	unsigned int getElementSize() const {
145 		return _elementSize;
146 	}
147 
assign(uint32 index,const uint8 * e)148 	void assign(uint32 index, const uint8 *e) {
149 		// need to check that index isn't out-of-bounds? (or grow list?)
150 		for (unsigned int i = 0; i < _elementSize; i++)
151 			_elements[index * _elementSize + i] = e[i];
152 	}
153 
copyList(const UCList & l)154 	void copyList(const UCList &l) { // deep copy for list
155 		free();
156 		appendList(l);
157 	}
158 
159 	void freeStrings();
160 	void copyStringList(const UCList &l) ;
161 	void unionStringList(UCList &l);
162 	void subtractStringList(const UCList &l);
163 	bool stringInList(uint16 str) const;
164 	void assignString(uint32 index, uint16 str);
165 	void removeString(uint16 str, bool nodel = false);
166 
167 	uint16 getStringIndex(uint32 index) const;
168 
169 	void save(Common::WriteStream *ws) const;
170 	bool load(Common::ReadStream *rs, uint32 version);
171 
172 private:
173 	const Std::string &getString(uint32 index) const;
174 };
175 
176 } // End of namespace Ultima8
177 } // End of namespace Ultima
178 
179 #endif
180