File: pakfile.cpp

package info (click to toggle)
amoeba 1.1-13
  • links: PTS
  • area: contrib
  • in suites: sarge
  • size: 732 kB
  • ctags: 971
  • sloc: cpp: 8,315; makefile: 178
file content (122 lines) | stat: -rw-r--r-- 2,539 bytes parent folder | download | duplicates (7)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
/*
 * Sesse's demolib
 */ 
 
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#ifdef __linux__
#include <unistd.h>
#else
#include <io.h>
#define strncasecmp strnicmp
#endif
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <errno.h>
#include <endian.h>

#include "demolib_prefs.h"
#include "file.h"
#include "pakfile.h"
#include "../exception.h"

#if DEMOLIB_DATA_PAKFILE

#if __BYTE_ORDER != __LITTLE_ENDIAN
#define fixendianl(x) \
     ((((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >>  8) |               \
      (((x) & 0x0000ff00) <<  8) | (((x) & 0x000000ff) << 24))
#else
#define fixendianl(x) (x)
#endif

PakFile::PakFile(char *filename)
{
	char buf[12];
	int err, dirpos, dirsize;
	unsigned int i;

#if __linux__
	int fd = open("/usr/share/amoeba/demo.dat", O_RDONLY);
#else
	int fd = open("demo.dat", O_RDONLY | O_BINARY);
#endif
	if (fd == -1) throw new FileNotFoundException("demo.dat wasn't found");

	/* first verify that this is indeed a pakfile */
	err = read(fd, buf, 12);
	if (err != 12 || strncasecmp(buf, "PACK", 4) != 0) {
		throw new FatalException("demo.dat is not a valid pakfile");
	}
	
	/* seek to the beginning of the directory */
	dirpos = fixendianl(*(int *)(buf + 4));
	if (lseek(fd, dirpos, SEEK_SET) != dirpos) {
		throw new FatalException("demo.dat is truncated");
	}
	dirsize = fixendianl(*(int *)(buf + 8));
	
	for (i = 0; i < dirsize / sizeof(struct pak_direntry); i++) {
		char *ptr;
		struct pak_direntry d;
		
		if (read(fd, (char *)(&d), sizeof(d)) != sizeof(d)) {
			throw new FatalException("demo.dat is truncated");
		}

		d.pos = fixendianl(d.pos);
		d.size = fixendianl(d.size);

		d.filename[55] = 0;
		if (strcmp(filename, d.filename) != 0) continue;
		
		ptr = (char *)(malloc(d.size));
		if (ptr == NULL) {
			throw new FatalException("Out of memory!");
		}

		if (lseek(fd, d.pos, SEEK_SET) == -1) {
			throw new FatalException("pakfile truncated!");
		}

		unsigned int i = 0;
		while (i < d.size) {
			int num_bytes = d.size - i;
			int err;

			if (num_bytes > 4096) num_bytes = 4096;
			err = read(fd, ptr + i, num_bytes);

			if (err <= 0)
				throw new FatalException("Error on read()", strerror(errno));
			i += err;
		}

		this->data = ptr;
		this->length = d.size;

		close(fd);
		return;
	}
	
	throw new FileNotFoundException("file not found in demo.dat");
}

PakFile::~PakFile()
{
	free(this->data);
}

char *PakFile::get_data()
{
	return this->data;
}

int PakFile::data_length()
{
	return this->length;
}
#endif /* DEMOLIB_DATA_PAKFILE */