1#include <muleunit/test.h>
2
3#include <wx/filename.h>
4#include <MemFile.h>
5#include <tags/FileTags.h>
6#include <math.h>
7
8#include "MD4Hash.h"
9#include "amule.h"
10#include "Packet.h"
11#include <vector>
12
13using namespace muleunit;
14
15DECLARE_SIMPLE(CTag)
16
17void test_taglist_serialization(TagPtrList & taglist, byte* packet, uint64 packet_len);
18
19template <class T1, class T2>
20void AssertEquals(const T1& a, const T2& b)
21{
22	ASSERT_EQUALS(a, b);
23}
24
25struct BLOBValue : std::vector<byte>
26{
27	BLOBValue(uint32 _length, const byte* _ptr)
28		: std::vector<byte > (_ptr, _ptr + _length)
29	{}
30};
31
32struct BSOBValue : std::vector<byte>
33{
34	BSOBValue(uint8 _length, const byte* _ptr)
35		: std::vector<byte > (_ptr, _ptr + _length)
36	{}
37};
38
39BLOBValue valid_tag_value(const BLOBValue& x)	{ return x; }
40BSOBValue valid_tag_value(const BSOBValue& x)	{ return x; }
41CMD4Hash valid_tag_value(const CMD4Hash& x)	{ return x; }
42float valid_tag_value(float x)			{ return x; }
43wxString valid_tag_value(const wxString& x)	{ return x; }
44uint64 valid_tag_value(int x)			{ return x; }
45uint64 valid_tag_value(long long x)		{ return x; }
46uint64 valid_tag_value(uint64 x)		{ return x; }
47
48template<class T>
49wxString toString(const T& value)
50{
51	wxString buf;
52
53	return buf << value;
54}
55
56template<class T>
57wxString toString(T& value)
58{
59	wxString buf;
60
61	return buf << value;
62}
63
64template<>
65wxString toString(const CMD4Hash& value)
66{
67	return value.Encode();
68}
69
70template<>
71wxString toString(CMemFile& buf)
72{
73	uint64 curpos = buf.GetPosition();
74	wxString result;
75	buf.Seek(0, wxFromStart);
76	for (uint64 i = 0; i < buf.GetLength(); i++) {
77		result += wxString::Format(wxT("0x%02x,"), buf.ReadUInt8());
78	}
79	buf.Seek(curpos, wxFromStart);
80
81	return result;
82}
83
84template<>
85wxString toString(const BSOBValue& buf)
86{
87	wxString result;
88	for (uint64 i = 0; i < buf.size(); i++) {
89		result += wxString::Format(wxT("0x%02x,"), buf[i]);
90	}
91	return result;
92}
93
94template<>
95wxString toString(const BLOBValue& buf)
96{
97	wxString result;
98	for (uint64 i = 0; i < buf.size(); i++) {
99		result += wxString::Format(wxT("0x%02x,"), buf[i]);
100	}
101	return result;
102}
103
104template<>
105void AssertEquals(const CMD4Hash& a, const CMD4Hash& b)
106{
107	CONTEXT(wxT("Compare CMD4Hashes"));
108	ASSERT_EQUALS(a.Encode(), b.Encode());
109}
110
111template<>
112void AssertEquals(const BSOBValue& a, const BSOBValue& b)
113{
114	CONTEXT(wxT("Compare BSOBValue"));
115	ASSERT_EQUALS(toString(a), toString(b));
116}
117
118template<>
119void AssertEquals(const BLOBValue& a, const BLOBValue& b)
120{
121	CONTEXT(wxT("Compare BLOBValue"));
122	ASSERT_EQUALS(toString(a), toString(b));
123}
124
125void CheckTagName(const wxString& tagName, CTag* tag)
126{
127	CONTEXT(wxT("Checking string tagname"));
128	ASSERT_EQUALS(tagName, tag->GetName());
129}
130
131void CheckTagName(uint8 tagName, CTag* tag)
132{
133	CONTEXT(wxT("Checking int tagname"));
134	ASSERT_EQUALS(tagName, tag->GetNameID());
135}
136
137
138typedef bool (CTag::*CTagTypeChecker)() const;
139
140template<class T>
141struct CTagAccess {};
142
143template<>
144struct CTagAccess<wxString>
145{
146	static bool IsRightType(CTag* tag)
147	{
148		return tag->IsStr();
149	}
150
151	static const wxString & GetValue(CTag* tag)
152	{
153		return tag->GetStr();
154	}
155};
156
157template<>
158struct CTagAccess<CMD4Hash>
159{
160	static bool IsRightType(CTag* tag)
161	{
162		return tag->IsHash();
163	}
164
165	static const CMD4Hash & GetValue(CTag* tag)
166	{
167		return tag->GetHash();
168	}
169};
170
171template<>
172struct CTagAccess<float>
173{
174	static bool IsRightType(CTag* tag)
175	{
176		return tag->IsFloat();
177	}
178
179	static float GetValue(CTag* tag)
180	{
181		return tag->GetFloat();
182	}
183};
184
185template<>
186struct CTagAccess<uint64>
187{
188	static bool IsRightType(CTag* tag)
189	{
190		return tag->IsInt();
191	}
192
193	static uint64 GetValue(CTag* tag)
194	{
195		return tag->GetInt();
196	}
197};
198
199template<>
200struct CTagAccess<BLOBValue>
201{
202	static bool IsRightType(CTag* tag)
203	{
204		return tag->IsBlob();
205	}
206
207	static BLOBValue GetValue(CTag* tag)
208	{
209		return BLOBValue(tag->GetBlobSize(), tag->GetBlob());
210	}
211};
212
213template<>
214struct CTagAccess<BSOBValue>
215{
216	static bool IsRightType(CTag* tag)
217	{
218		return tag->IsBsob();
219	}
220
221	static BSOBValue GetValue(CTag* tag) {
222		return BSOBValue(tag->GetBsobSize(), tag->GetBsob());
223	}
224};
225
226template<class V>
227void CheckTagValue(V tagValue, CTag* tag)
228{
229	CONTEXT(wxT("Check tag value"));
230
231	AssertEquals(tagValue, CTagAccess< V >::GetValue(tag));
232}
233
234template<class V>
235void CheckTagType(V, CTag* tag)
236{
237	CONTEXT(wxT("Check tag type"));
238	ASSERT_EQUALS(true, CTagAccess<V>::IsRightType(tag));
239}
240
241template<class V, class TName>
242void CheckTagData(CTag* tag, TName tagName, const V& tagValue)
243{
244	CONTEXT(wxT("Expected tag value:") + toString(tagValue));
245	CONTEXT(wxT("Parsed tag info:") + tag->GetFullInfo());
246
247	CheckTagType(tagValue, tag);
248	CheckTagName(tagName, tag);
249	CheckTagValue(valid_tag_value(tagValue), tag);
250}
251
252void test_taglist_serialization(TagPtrList& taglist, byte* packet, uint64 packet_len)
253{
254	CMemFile fout;
255
256	{
257		CONTEXT(wxT("Writing taglist to CMemFile"));
258
259		fout.WriteTagPtrList(taglist);
260	}
261
262	// Rewind file
263	fout.Seek(0, wxFromStart);
264
265	{
266		CONTEXT(wxT("Check taglist serialization length"));
267		ASSERT_EQUALS(packet_len, fout.GetLength());
268	}
269
270	std::vector<byte> buf(packet_len);
271
272	{
273		CONTEXT(wxT("Reading back serialized taglist bytes from CMemFile"));
274		fout.Read(&buf[0], packet_len);
275	}
276
277	for (uint64 i = 0; i < packet_len; i++) {
278		CONTEXT(wxString::Format(wxT("Comparing serialized byte #%d"), i));
279
280		ASSERT_EQUALS(packet[i], buf[i]);
281	}
282}
283
284void ReadTagPtrList(TagPtrList& taglist, byte* packet, uint64 packet_len)
285{
286
287	CONTEXT(wxT("Reading taglist from buffer"));
288	CMemFile fin(packet, packet_len);
289	fin.ReadTagPtrList(&taglist, true);
290
291	{
292		CONTEXT(wxT("Verify position is at end of packet"));
293		ASSERT_EQUALS(packet_len, fin.GetPosition());
294	}
295}
296
297TEST_M(CTag, ReadTagList1, wxT("Kad: Parse taglist from Kad packet with UTF8 string #1"))
298{
299	byte packet[] = {
300		0x07,
301		/*Tag1*/ 0x02, 0x01, 0x00, 0x01, 0x22, 0x00, 0x47, 0x65, 0x6d, 0x20, 0x42, 0x6f, 0x79, 0x20, 0x2d,
302		0x20, 0x53, 0x61, 0x72, 0xc3, 0xa0, 0x20, 0x70, 0x65, 0x72, 0x63, 0x68, 0xc3, 0xa8, 0x20, 0x74,
303		0x69, 0x20, 0x61, 0x6d, 0x6f, 0x2e, 0x6d, 0x70, 0x33,
304		/*Tag2*/ 0x03, 0x01, 0x00, 0x02, 0x1d, 0x6f, 0x1f, 0x00,
305		/*Tag3*/ 0x09, 0x01, 0x00, 0x15, 0x01,
306		/*Tag4*/ 0x02, 0x01, 0x00, 0x03, 0x05, 0x00, 0x41, 0x75, 0x64, 0x69, 0x6f,
307		/*Tag5*/ 0x09, 0x01, 0x00, 0xd3, 0x6b,
308		/*Tag6*/ 0x09, 0x01, 0x00, 0xd4, 0x9a,
309		/*Tag7*/ 0x03, 0x01, 0x00, 0x33, 0x2f, 0x00, 0x01, 0x01
310	};
311
312	TagPtrList taglist;
313	ReadTagPtrList(taglist, packet, sizeof (packet));
314	TagPtrList::iterator it = taglist.begin();
315
316	CheckTagData(*it++, TAG_FILENAME, valid_tag_value(wxT("Gem Boy - Sar�� perch�� ti amo.mp3")));
317	CheckTagData(*it++, TAG_FILESIZE, valid_tag_value(2060061));
318	CheckTagData(*it++, TAG_SOURCES, valid_tag_value(1));
319	CheckTagData(*it++, TAG_FILETYPE, valid_tag_value(ED2KFTSTR_AUDIO));
320	CheckTagData(*it++, TAG_MEDIA_LENGTH, valid_tag_value(107));
321	CheckTagData(*it++, TAG_MEDIA_BITRATE, valid_tag_value(154));
322	CheckTagData(*it++, TAG_PUBLISHINFO, valid_tag_value(16842799));
323
324	ASSERT_TRUE(it == taglist.end());
325	test_taglist_serialization(taglist, packet, sizeof (packet));
326	deleteTagPtrListEntries(&taglist);
327}
328
329TEST_M(CTag, ReadTagList2, wxT("Kad: Parse taglist from Kad packet with UTF8 string #2"))
330{
331	byte packet[] = {
332		0x05,
333		/*Tag1*/0x02, 0x01, 0x00, 0x01, 0x33, 0x00, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61,
334		0x74, 0x69, 0x6f, 0x6e, 0x20, 0x54, 0x65, 0x73, 0x74, 0x20, 0x46, 0x69, 0x6c, 0x65, 0x20, 0x31,
335		0x38, 0x39, 0x33, 0x2d, 0xe2, 0x82, 0xac, 0xe2, 0x82, 0xac, 0xc3, 0xa8, 0xc3, 0xa9, 0xc3, 0xa7,
336		0xc3, 0xa0, 0xc3, 0xb9, 0xc2, 0xa7, 0x2e, 0x74, 0x78, 0x74,
337		/*Tag2*/0x09, 0x01, 0x00, 0x02, 0x0d,
338		/*Tag3*/0x09, 0x01, 0x00, 0x15, 0x00,
339		/*Tag4*/0x02, 0x01, 0x00, 0x03, 0x03, 0x00, 0x44, 0x6f, 0x63, 0x03, 0x01, 0x00,
340		0x33, 0xe8, 0x03, 0x01, 0x01
341	};
342
343	TagPtrList taglist;
344	ReadTagPtrList(taglist, packet, sizeof (packet));
345	TagPtrList::iterator it = taglist.begin();
346
347	CheckTagData(*it++, TAG_FILENAME, valid_tag_value(wxT("Serialization Test File 1893-������������������.txt")));
348	CheckTagData(*it++, TAG_FILESIZE, valid_tag_value(13));
349	CheckTagData(*it++, TAG_SOURCES, valid_tag_value(0));
350	CheckTagData(*it++, TAG_FILETYPE, valid_tag_value(ED2KFTSTR_DOCUMENT));
351	CheckTagData(*it++, TAG_PUBLISHINFO, valid_tag_value(16843752));
352
353	ASSERT_TRUE(it == taglist.end());
354	test_taglist_serialization(taglist, packet, sizeof (packet));
355	deleteTagPtrListEntries(&taglist);
356
357}
358
359TEST_M(CTag, Float, wxT("Kad: Read/Write floats"))
360{
361	byte packet[] = {
362		0x02,
363		/*Tag1*/0x04, 0x01, 0x00, 0xFF, 0x79, 0xe9, 0xf6, 0x42,
364		/*Tag2*/0x04, 0x01, 0x00, 0xFF, 0x79, 0xd9, 0xd6, 0x42,
365	};
366
367	TagPtrList taglist;
368	ReadTagPtrList(taglist, packet, sizeof (packet));
369	TagPtrList::iterator it = taglist.begin();
370
371	CheckTagData(*it++, TAG_SOURCETYPE, valid_tag_value((float) 123.456));
372	CheckTagData(*it++, TAG_SOURCETYPE, valid_tag_value((float) 107.424751));
373
374	ASSERT_TRUE(it == taglist.end());
375	test_taglist_serialization(taglist, packet, sizeof (packet));
376	deleteTagPtrListEntries(&taglist);
377}
378
379TEST_M(CTag, CMD4Hash, wxT("Kad: Read/Write CMD4Hash"))
380{
381	byte packet[] = {
382		0x01,
383		/*Tag1*/0x01,
384		0x01, 0x00, 0xFF,
385		0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
386		0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
387	};
388
389	TagPtrList taglist;
390	ReadTagPtrList(taglist, packet, sizeof (packet));
391	TagPtrList::iterator it = taglist.begin();
392
393	CMD4Hash hash;
394	ASSERT_TRUE(hash.Decode("000102030405060708090A0B0C0D0E0F"));
395
396	CheckTagData(*it++, TAG_SOURCETYPE, valid_tag_value(hash));
397
398	ASSERT_TRUE(it == taglist.end());
399	test_taglist_serialization(taglist, packet, sizeof (packet));
400	deleteTagPtrListEntries(&taglist);
401}
402
403template<class T, class V>
404void check_single_kad_tag(byte* packet, size_t packet_len, T tagName, V tagValue)
405{
406	CMemFile buf(packet, packet_len);
407	CONTEXT(wxT("Starting buffer: ") + toString(buf));
408	CTag* tag = buf.ReadTag(true);
409
410	CheckTagData(tag, tagName, valid_tag_value(tagValue));
411	{
412		CONTEXT(wxT("Check end of buffer"));
413		ASSERT_EQUALS(packet_len, buf.GetPosition());
414	}
415
416	{
417		CMemFile newbuf;
418		newbuf.WriteTag(*tag);
419
420		CONTEXT(wxT("Serialized    : ") + toString(newbuf));
421
422		newbuf.Seek(0, wxFromStart);
423		for (size_t i = 0; i < packet_len; i++) {
424			CONTEXT(wxString::Format(wxT("Comparing byte #%d"), i));
425
426			ASSERT_EQUALS(packet[i], newbuf.ReadUInt8());
427		}
428
429		ASSERT_EQUALS(packet_len, buf.GetPosition());
430	}
431	delete tag;
432}
433
434TEST_M(CTag, KadBsob, wxT("Kad: Read/Write BSOB"))
435{
436	byte packet[] = {
437		/*Tag1*/ 0x0A, 0x01, 0x00, 0x02, 0x04, 0x01, 0x02, 0x03, 0x04,
438	};
439	byte raw_data[] = {0x01, 0x02, 0x03, 0x04};
440	{
441		CONTEXT(wxT("Create BSOBValue"));
442		BSOBValue bsob(sizeof (raw_data), raw_data);
443
444		CONTEXT(wxT("check_single_kad_tag BSOBValue"));
445		check_single_kad_tag(packet, sizeof (packet), TAG_FILESIZE, bsob);
446	}
447}
448
449TEST_M(CTag, KadInt64, wxT("Kad: Read/Write integer 64bit"))
450{
451	byte packet[] = {
452		/*Tag1*/ 0x0b, 0x01, 0x00, 0x02, 0x10, 0x11, 0x12, 0x13, 0x20, 0x21, 0x22, 0x23, // 64 bit int
453	};
454	check_single_kad_tag(packet, sizeof (packet), TAG_FILESIZE, 0x2322212013121110LL);
455}
456
457TEST_M(CTag, KadInt32, wxT("Kad: Read/Write integer 32bit"))
458{
459	byte packet[] = {
460		/*Tag1*/ 0x03, 0x01, 0x00, 0x02, 0x12, 0x34, 0x56, 0x78, // 32 bit int
461	};
462	check_single_kad_tag(packet, sizeof (packet), TAG_FILESIZE, 0x78563412);
463}
464
465TEST_M(CTag, KadInt16, wxT("Kad: Read/Write integer 16bit"))
466{
467	byte packet[] = {
468		/*Tag1*/ 0x08, 0x01, 0x00, 0x02, 0x12, 0x34, // 16 bit int
469	};
470	check_single_kad_tag(packet, sizeof (packet), TAG_FILESIZE, 0x3412);
471}
472
473TEST_M(CTag, KadInt8, wxT("Kad: Read/Write integer  8bit"))
474{
475	byte packet[] = {
476		/*Tag1*/ 0x09, 0x01, 0x00, 0x02, 0x12, //  8 bit int
477	};
478	check_single_kad_tag(packet, sizeof (packet), TAG_FILESIZE, 0x12);
479}
480
481TEST_M(CTag, ReadIntegers, wxT("Kad: Read/Write multiple integers"))
482{
483	byte packet[] = {
484		0x08,
485		/*Tag1*/ 0x03, 0x01, 0x00, 0x02, 0x12, 0x34, 0x56, 0x78, // 32 bit int
486		/*Tag2*/ 0x08, 0x01, 0x00, 0x02, 0x12, 0x34, // 16 bit int
487		/*Tag3*/ 0x09, 0x01, 0x00, 0x02, 0x12, //  8 bit int
488		/*Tag4*/ 0x0b, 0x01, 0x00, 0x02, 0x10, 0x11, 0x12, 0x13, 0x20, 0x21, 0x22, 0x23, // 64 bit int
489
490		/*Tag5*/ 0x03, 0x01, 0x00, 0x02, 0x12, 0x34, 0x56, 0x78, // 32 bit int
491		/*Tag6*/ 0x08, 0x01, 0x00, 0x02, 0x12, 0x34, // 16 bit int
492		/*Tag7*/ 0x09, 0x01, 0x00, 0x02, 0x12, //  8 bit int
493		/*Tag8*/ 0x0b, 0x01, 0x00, 0x02, 0x10, 0x11, 0x12, 0x13, 0x20, 0x21, 0x22, 0x23, // 64 bit int
494	};
495
496	TagPtrList taglist;
497	ReadTagPtrList(taglist, packet, sizeof (packet));
498	TagPtrList::iterator it = taglist.begin();
499
500	CheckTagData(*it++, TAG_FILESIZE, valid_tag_value(0x78563412));
501	CheckTagData(*it++, TAG_FILESIZE, valid_tag_value(0x3412));
502	CheckTagData(*it++, TAG_FILESIZE, valid_tag_value(0x12));
503	CheckTagData(*it++, TAG_FILESIZE, valid_tag_value(0x2322212013121110LL));
504
505	CheckTagData(*it++, TAG_FILESIZE, valid_tag_value(0x78563412));
506	CheckTagData(*it++, TAG_FILESIZE, valid_tag_value(0x3412));
507	CheckTagData(*it++, TAG_FILESIZE, valid_tag_value(0x12));
508	CheckTagData(*it++, TAG_FILESIZE, valid_tag_value(0x2322212013121110LL));
509
510	ASSERT_TRUE(it == taglist.end());
511	test_taglist_serialization(taglist, packet, sizeof (packet));
512	deleteTagPtrListEntries(&taglist);
513}
514
515
516#include <map>
517
518typedef std::map<wxString, wxString> TagNamesByString;
519
520TEST_M(CTag, KadTagNames, wxT("Kad: Test Kad tags (name=string) - write/read every valid tag name"))
521{
522	TagNamesByString tagNames;
523
524	tagNames[TAG_FILENAME] = wxT("TAG_FILENAME");
525	tagNames[TAG_FILESIZE] = wxT("TAG_FILESIZE");
526	tagNames[TAG_FILESIZE_HI] = wxT("TAG_FILESIZE_HI");
527	tagNames[TAG_FILETYPE] = wxT("TAG_FILETYPE");
528	tagNames[TAG_FILEFORMAT] = wxT("TAG_FILEFORMAT");
529	tagNames[TAG_COLLECTION] = wxT("TAG_COLLECTION");
530	tagNames[TAG_PART_PATH] = wxT("TAG_PART_PATH");
531	tagNames[TAG_PART_HASH] = wxT("TAG_PART_HASH");
532	tagNames[TAG_COPIED] = wxT("TAG_COPIED");
533	tagNames[TAG_GAP_START] = wxT("TAG_GAP_START");
534	tagNames[TAG_GAP_END] = wxT("TAG_GAP_END");
535	tagNames[TAG_DESCRIPTION] = wxT("TAG_DESCRIPTION");
536	tagNames[TAG_PING] = wxT("TAG_PING");
537	tagNames[TAG_FAIL] = wxT("TAG_FAIL");
538	tagNames[TAG_PREFERENCE] = wxT("TAG_PREFERENCE");
539	tagNames[TAG_PORT] = wxT("TAG_PORT");
540	tagNames[TAG_IP_ADDRESS] = wxT("TAG_IP_ADDRESS");
541	tagNames[TAG_VERSION] = wxT("TAG_VERSION");
542	tagNames[TAG_TEMPFILE] = wxT("TAG_TEMPFILE");
543	tagNames[TAG_PRIORITY] = wxT("TAG_PRIORITY");
544	tagNames[TAG_STATUS] = wxT("TAG_STATUS");
545	tagNames[TAG_SOURCES] = wxT("TAG_SOURCES");
546	tagNames[TAG_AVAILABILITY] = wxT("TAG_AVAILABILITY");
547	tagNames[TAG_PERMISSIONS] = wxT("TAG_PERMISSIONS");
548	tagNames[TAG_QTIME] = wxT("TAG_QTIME");
549	tagNames[TAG_PARTS] = wxT("TAG_PARTS");
550	tagNames[TAG_PUBLISHINFO] = wxT("TAG_PUBLISHINFO");
551	tagNames[TAG_MEDIA_ARTIST] = wxT("TAG_MEDIA_ARTIST");
552	tagNames[TAG_MEDIA_ALBUM] = wxT("TAG_MEDIA_ALBUM");
553	tagNames[TAG_MEDIA_TITLE] = wxT("TAG_MEDIA_TITLE");
554	tagNames[TAG_MEDIA_LENGTH] = wxT("TAG_MEDIA_LENGTH");
555	tagNames[TAG_MEDIA_BITRATE] = wxT("TAG_MEDIA_BITRATE");
556	tagNames[TAG_MEDIA_CODEC] = wxT("TAG_MEDIA_CODEC");
557	tagNames[TAG_KADMISCOPTIONS] = wxT("TAG_KADMISCOPTIONS");
558	tagNames[TAG_ENCRYPTION] = wxT("TAG_ENCRYPTION");
559	tagNames[TAG_FILERATING] = wxT("TAG_FILERATING");
560	tagNames[TAG_BUDDYHASH] = wxT("TAG_BUDDYHASH");
561	tagNames[TAG_CLIENTLOWID] = wxT("TAG_CLIENTLOWID");
562	tagNames[TAG_SERVERPORT] = wxT("TAG_SERVERPORT");
563	tagNames[TAG_SERVERIP] = wxT("TAG_SERVERIP");
564	tagNames[TAG_SOURCEUPORT] = wxT("TAG_SOURCEUPORT");
565	tagNames[TAG_SOURCEPORT] = wxT("TAG_SOURCEPORT");
566	tagNames[TAG_SOURCEIP] = wxT("TAG_SOURCEIP");
567	tagNames[TAG_SOURCETYPE] = wxT("TAG_SOURCETYPE");
568
569	CMemFile buf;
570	buf.WriteUInt8(tagNames.size());
571	int counter = 0;
572	// For each tagNames entry write an 8bit int tag (type:0x9)
573	for (TagNamesByString::iterator it_name = tagNames.begin(); it_name != tagNames.end(); it_name++) {
574		buf.WriteUInt8(0x09); // 8 bit int tag type
575
576		buf.WriteUInt8(0x01); // single char string
577		buf.WriteUInt8(0x00); //
578
579		buf.WriteUInt8(it_name->first.GetChar(0)); // Write string first char
580		buf.WriteUInt8(counter++); // write tag value
581	}
582
583	TagPtrList taglist;
584	buf.Seek(0, wxFromStart);
585	size_t packet_len = buf.GetLength();
586	std::vector<byte> packet(packet_len);
587	buf.Read(&packet[0], packet_len);
588
589	ReadTagPtrList(taglist, &packet[0], packet_len);
590
591	TagPtrList::iterator it = taglist.begin();
592
593	counter = 0;
594	for (TagNamesByString::iterator it_name = tagNames.begin(); it_name != tagNames.end(); it_name++) {
595		CONTEXT(wxT("Testing tag name: ") + it_name->second);
596		CheckTagData(*it++, it_name->first, valid_tag_value(counter++));
597	}
598
599	ASSERT_TRUE(it == taglist.end());
600	test_taglist_serialization(taglist, &packet[0], packet_len);
601	deleteTagPtrListEntries(&taglist);
602}
603
604typedef std::map<int, wxString> TagNamesByInt;
605
606TEST_M(CTag, ED2kTagNames, wxT("Ed2k: Test ed2k tags (name=id) - write/read every valid tag name"))
607{
608	TagNamesByInt tagNames;
609
610	tagNames[FT_FILENAME] = wxT("FT_FILENAME");
611	tagNames[FT_FILESIZE] = wxT("FT_FILESIZE");
612	tagNames[FT_FILESIZE_HI] = wxT("FT_FILESIZE_HI");
613	tagNames[FT_FILETYPE] = wxT("FT_FILETYPE");
614	tagNames[FT_FILEFORMAT] = wxT("FT_FILEFORMAT");
615	tagNames[FT_LASTSEENCOMPLETE] = wxT("FT_LASTSEENCOMPLETE");
616	tagNames[FT_TRANSFERRED] = wxT("FT_TRANSFERRED");
617	tagNames[FT_GAPSTART] = wxT("FT_GAPSTART");
618	tagNames[FT_GAPEND] = wxT("FT_GAPEND");
619	tagNames[FT_PARTFILENAME] = wxT("FT_PARTFILENAME");
620	tagNames[FT_OLDDLPRIORITY] = wxT("FT_OLDDLPRIORITY");
621	tagNames[FT_STATUS] = wxT("FT_STATUS");
622	tagNames[FT_SOURCES] = wxT("FT_SOURCES");
623	tagNames[FT_PERMISSIONS] = wxT("FT_PERMISSIONS");
624	tagNames[FT_OLDULPRIORITY] = wxT("FT_OLDULPRIORITY");
625	tagNames[FT_DLPRIORITY] = wxT("FT_DLPRIORITY");
626	tagNames[FT_ULPRIORITY] = wxT("FT_ULPRIORITY");
627	tagNames[FT_KADLASTPUBLISHKEY] = wxT("FT_KADLASTPUBLISHKEY");
628	tagNames[FT_KADLASTPUBLISHSRC] = wxT("FT_KADLASTPUBLISHSRC");
629	tagNames[FT_FLAGS] = wxT("FT_FLAGS");
630	tagNames[FT_DL_ACTIVE_TIME] = wxT("FT_DL_ACTIVE_TIME");
631	tagNames[FT_CORRUPTEDPARTS] = wxT("FT_CORRUPTEDPARTS");
632	tagNames[FT_DL_PREVIEW] = wxT("FT_DL_PREVIEW");
633	tagNames[FT_KADLASTPUBLISHNOTES] = wxT("FT_KADLASTPUBLISHNOTES");
634	tagNames[FT_AICH_HASH] = wxT("FT_AICH_HASH");
635	tagNames[FT_COMPLETE_SOURCES] = wxT("FT_COMPLETE_SOURCES");
636	tagNames[FT_PUBLISHINFO] = wxT("FT_PUBLISHINFO");
637	tagNames[FT_ATTRANSFERRED] = wxT("FT_ATTRANSFERRED");
638	tagNames[FT_ATREQUESTED] = wxT("FT_ATREQUESTED");
639	tagNames[FT_ATACCEPTED] = wxT("FT_ATACCEPTED");
640	tagNames[FT_CATEGORY] = wxT("FT_CATEGORY");
641	tagNames[FT_ATTRANSFERREDHI] = wxT("FT_ATTRANSFERREDHI");
642	tagNames[FT_MEDIA_ARTIST] = wxT("FT_MEDIA_ARTIST");
643	tagNames[FT_MEDIA_ALBUM] = wxT("FT_MEDIA_ALBUM");
644	tagNames[FT_MEDIA_TITLE] = wxT("FT_MEDIA_TITLE");
645	tagNames[FT_MEDIA_LENGTH] = wxT("FT_MEDIA_LENGTH");
646	tagNames[FT_MEDIA_BITRATE] = wxT("FT_MEDIA_BITRATE");
647	tagNames[FT_MEDIA_CODEC] = wxT("FT_MEDIA_CODEC");
648	tagNames[FT_FILERATING] = wxT("FT_FILERATING");
649
650
651	CMemFile buf;
652
653	uint64 counter = 0;
654	for (TagNamesByInt::iterator it_name = tagNames.begin(); it_name != tagNames.end(); it_name++) {
655		// m_uType
656		buf.WriteUInt8(0x09 + 0x80);
657		// m_uName
658		buf.WriteUInt8(it_name->first);
659		// 8 bit
660		buf.WriteUInt8(counter++);
661	}
662
663	buf.Seek(0, wxFromStart);
664
665	counter = 0;
666	for (TagNamesByInt::iterator it_name = tagNames.begin(); it_name != tagNames.end(); it_name++) {
667		CONTEXT(wxString::Format(wxT("Reading tag#%d"), counter));
668		CTag* newtag = new CTag(buf, true);
669		CheckTagName(it_name->first, newtag);
670		CheckTagValue( valid_tag_value( counter ), newtag);
671		delete newtag;
672		counter++;
673	}
674}
675
676TEST_M(CTag, Ed2kBlob1, wxT("Ed2k: Read/Write BLOB - numeric tagname"))
677{
678	byte packet[] = {
679		/*Tag1*/ 0x87, 0xFF, 0x04, 0x00, 0x00, 0x00,
680		0x01, 0x02, 0x03, 0x04,
681	};
682
683	CMemFile buf(packet, sizeof (packet));
684	buf.Seek(0, wxFromStart);
685	byte raw_data[] = {0x01, 0x02, 0x03, 0x04};
686	{
687		CONTEXT(wxT("Create BLOBValue"));
688		BLOBValue blob(sizeof (raw_data), raw_data);
689
690		CTag tag(buf, true);
691		CheckTagName(0xFF, &tag);
692		CheckTagValue( valid_tag_value( blob ), &tag);
693	}
694}
695
696TEST_M(CTag, Ed2kBlob2, wxT("Ed2k: Read/Write BLOB - string tagname"))
697{
698	byte packet[] = {
699		/*Tag1*/ 0x07, 0x02, 0x00, 'A', 'A', 0x04, 0x00, 0x00, 0x00,
700		0x01, 0x02, 0x03, 0x04,
701	};
702
703	CMemFile buf(packet, sizeof (packet));
704	buf.Seek(0, wxFromStart);
705	byte raw_data[] = {0x01, 0x02, 0x03, 0x04};
706	{
707		CONTEXT(wxT("Create BLOBValue"));
708		BLOBValue blob(sizeof (raw_data), raw_data);
709
710		CTag tag(buf, true);
711		CheckTagName(wxT("AA"), &tag);
712		CheckTagValue( valid_tag_value( blob ), &tag);
713	}
714}
715