1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 
5 #include "ztypes.h"
6 #include "pickle.h"
7 
8 /* This file is the source code for the PICKLE Reader Library.
9 	Version 1. */
10 
11 /* This library is a very simple one, intended for use in interpreters
12 	that want to support reading PICKLE files. This library does not
13 	have functions to write or analyze PICKLE files, just to read them
14 	in the rather limited way that interpreters should want to. */
15 
16 #ifdef BIG_END_MODE
17 static char contentmessage[] = "\nPICKLE Reader Library 1.0.0 (big-endian)\n";
18 #endif
19 
20 #ifdef LITTLE_END_MODE
21 static char contentmessage[] = "\nPICKLE Reader Library 1.0.0 (little-endian)\n";
22 #endif
23 
24 #ifdef __STDC__
25 static char contentmessage2[] = "\nLibrary compiled with __STDC__\n";
26 #else
27 static char contentmessage2[] = "\nLibrary compiled without __STDC__\n";
28 #endif
29 
30 #define pik_InitedMagic (0x18328EEB)
31 
32 #if defined(BIG_END_MODE) || defined(LITTLE_END_MODE)
33 
34 #ifdef BIG_END_MODE
35 #define pikNative(v) (v)
36 #endif
37 
38 #ifdef LITTLE_END_MODE
39 #define pikNative(v) (   \
40 	  ((((long)(v)) >> 24) & 0x000000ff)   \
41 	| ((((long)(v)) >> 8)  & 0x0000ff00)   \
42 	| ((((long)(v)) << 8)  & 0x00ff0000)   \
43 	| ((((long)(v)) << 24) & 0xff000000)   \
44 )
45 #endif
46 
47 #else
48 
49 #define pikNative(v) (0)
50 
51 #endif
52 
53 struct pikDescriptorData {
54 	pikType use;
55 	pikLong number;
56 	pikType format;
57 	pikLong formatversion;
58 	pikLong startpos;
59 	pikLong length;
60 
61 	void *data; /* (non-Mac systems) */
62 	/*Handle data;*/ /* (Mac only) */
63 };
64 typedef struct pikDescriptorData pikDescriptor;
65 
66 struct pikMapData {
67 	pikLong inited; /* contains pik_InitedMagic while the map is in existence */
68 	FILE *file; /* (non-Mac systems) */
69 	/*short file;*/ /* (Mac only) */
70 
71 	pikLong numchunks;
72 	pikLong filelength;
73 
74 	pikDescriptor *chunks; /* pointer to an array of descriptors */
75 };
76 typedef struct pikMapData pikMap;
77 
78 #ifdef __STDC__
pikIsPickleHeader(char * header)79 short pikIsPickleHeader(char *header)
80 #else
81 short pikIsPickleHeader(header)
82 char *header;
83 #endif
84 {
85 	if (header[0] == 0x70
86 		&& header[1] == 0x69
87 		&& header[2] == 0x6b
88 		&& header[3] == 0x6c) {
89 		return TRUE;
90 	}
91 	else {
92 		return FALSE;
93 	}
94 }
95 
96 #ifdef __STDC__
pikCreateMap(FILE * file,pikMapPtr * newmap)97 pikErr pikCreateMap(FILE *file, pikMapPtr *newmap)
98 #else
99 pikErr pikCreateMap(file, newmap)
100 FILE *file;
101 pikMapPtr *newmap;
102 #endif
103 {
104 	pikMapPtr map;
105 	pikLong buffer[6];
106 	int err;
107 	long count;
108 	long lx;
109 	pikLong numchunks;
110 	pikLong filelength;
111 	pikDescriptor *chunks;
112 
113 	if (sizeof(pikLong) != 4) {
114 		return pikerr_WrongSizeInts;
115 	}
116 	{
117 		pikLong testval;
118 		unsigned char *cx;
119 		cx = (unsigned char *)(&testval);
120 		cx[0] = 0x12;
121 		cx[1] = 0x34;
122 		cx[2] = 0x56;
123 		cx[3] = 0x78;
124 		if (pikNative(testval) != 0x12345678) {
125 			return pikerr_WrongEndian;
126 		}
127 	}
128 
129 	if (!file) {
130 		return pikerr_BadOption;
131 	}
132 
133 	err = fseek(file, 0, 0);
134 	if (err) {
135 		return pikerr_CantRead;
136 	}
137 
138 	count = fread(buffer, 1, 16, file);
139 	if (count != 16) {
140 		return pikerr_CantRead;
141 	}
142 
143 	if (pikNative(buffer[0]) != pikMakeType('p', 'i', 'k', 'l')
144 		|| pikNative(buffer[1]) != 1) {
145 		return pikerr_NotAMap;
146 	}
147 
148 	numchunks = pikNative(buffer[2]);
149 	filelength = pikNative(buffer[3]);
150 
151 	err = fseek(file, 0, 2);
152 	if (err) {
153 		return pikerr_CantRead;
154 	}
155 	count = ftell(file);
156 	if (count == (-1)) {
157 		return pikerr_CantRead;
158 	}
159 	if (count != filelength) {
160 		return pikerr_NotAMap;
161 	}
162 	err = fseek(file, 16, 0);
163 	if (err) {
164 		return pikerr_CantRead;
165 	}
166 
167 	map = (pikMapPtr)malloc(sizeof(pikMap));
168 	if (!map) {
169 		return pikerr_Memory;
170 	}
171 	chunks = (pikDescriptor *)malloc(sizeof(pikDescriptor) * numchunks);
172 	if (!chunks) {
173 		free(map);
174 		return pikerr_Memory;
175 	}
176 
177 	for (lx=0; lx<numchunks; lx++) {
178 
179 		count = fread(buffer, 1, 24, file);
180 		if (count != 24) {
181 			free(chunks);
182 			free(map);
183 			return pikerr_CantRead;
184 		}
185 
186 		chunks[lx].use = pikNative(buffer[0]);
187 		chunks[lx].number = pikNative(buffer[1]);
188 		chunks[lx].format = pikNative(buffer[2]);
189 		chunks[lx].formatversion = pikNative(buffer[3]);
190 		chunks[lx].startpos = pikNative(buffer[4]);
191 		chunks[lx].length = pikNative(buffer[5]);
192 		chunks[lx].data = NULL;
193 	}
194 
195 	map->chunks = chunks;
196 	map->numchunks = numchunks;
197 	map->filelength = filelength;
198 	map->file = file;
199 	map->inited = pik_InitedMagic;
200 
201 	*newmap = map;
202 	return pikerr_None;
203 }
204 
205 #ifdef __STDC__
pikDestroyMap(pikMapPtr map)206 pikErr pikDestroyMap(pikMapPtr map)
207 #else
208 pikErr pikDestroyMap(map)
209 pikMapPtr map;
210 #endif
211 {
212 	pikLong lx;
213 	pikDescriptor *desc;
214 
215 	if (!map || !map->chunks || map->inited != pik_InitedMagic) {
216 		return pikerr_NotAMap;
217 	}
218 
219 	for (lx=0; lx<map->numchunks; lx++) {
220 		desc = (&(map->chunks[lx]));
221 		if (desc->data) {
222 			free(desc->data);
223 			desc->data = NULL;
224 		}
225 	}
226 
227 	map->inited = 0;
228 	free(map->chunks);
229 	free(map);
230 
231 	return pikerr_None;
232 }
233 
234 #ifdef __STDC__
pikFindChunk(pikMapPtr map,pikType use,pikLong number,short numformats,pikFormat * formatlist,pikChunkID * idfound)235 pikErr pikFindChunk(pikMapPtr map, pikType use, pikLong number,
236 	short numformats, pikFormat *formatlist, pikChunkID *idfound)
237 #else
238 pikErr pikFindChunk(map, use, number, numformats, formatlist, idfound)
239 pikMapPtr map;
240 pikType use;
241 pikLong number;
242 short numformats;
243 pikFormat *formatlist;
244 pikChunkID *idfound;
245 #endif
246 {
247 	pikDescriptor *desc;
248 	pikLong id, bestid;
249 	short fx, sofar;
250 
251 	if (!map || !map->chunks || map->inited != pik_InitedMagic) {
252 		return pikerr_NotAMap;
253 	}
254 
255 	if (numformats < 0 || (numformats > 0 && !formatlist)) {
256 		return pikerr_BadOption;
257 	}
258 
259 	sofar = (-1);
260 	for (id=0, desc=map->chunks; id<map->numchunks; id++, desc++) {
261 		if (desc->use == use && desc->number == number) {
262 			if (numformats == 0) {
263 				if (idfound)
264 					*idfound = id;
265 				return pikerr_None;
266 			}
267 			for (fx=0; fx<numformats; fx++) {
268 				if (desc->format == formatlist[fx].name &&
269 					desc->formatversion == formatlist[fx].version) {
270 					if (sofar < 0 || fx < sofar) {
271 						sofar = fx;
272 						bestid = id;
273 					}
274 				}
275 			}
276 		}
277 	}
278 
279 	if (sofar >= 0) {
280 		if (idfound)
281 			*idfound = bestid;
282 		return pikerr_None;
283 	}
284 
285 	if (idfound)
286 		*idfound = pik_NoChunk;
287 	return pikerr_NotFound;
288 }
289 
290 #ifdef __STDC__
pikLoadChunk(pikMapPtr map,pikChunkID id,short method,pikChunk * found)291 pikErr pikLoadChunk(pikMapPtr map, pikChunkID id, short method, pikChunk *found)
292 #else
293 pikErr pikLoadChunk(map, id, method, found)
294 pikMapPtr map;
295 pikChunkID id;
296 short method;
297 pikChunk *found;
298 #endif
299 {
300 	pikDescriptor *desc;
301 
302 	if (!map || !map->chunks || map->inited != pik_InitedMagic) {
303 		return pikerr_NotAMap;
304 	}
305 
306 	if (id < 0 || id >= map->numchunks) {
307 		return pikerr_BadOption;
308 	}
309 	if (!found) {
310 		return pikerr_BadOption;
311 	}
312 
313 	desc = (&(map->chunks[id]));
314 	switch (method) {
315 		case pikmethod_DontRead:
316 			break;
317 		case pikmethod_FilePos:
318 			found->data.startpos = desc->startpos;
319 			break;
320 		case pikmethod_Memory:
321 			if (!desc->data) {
322 				long count;
323 				int err;
324 				desc->data = malloc(desc->length);
325 				if (!desc->data) {
326 					return pikerr_Memory;
327 				}
328 				err = fseek(map->file, desc->startpos, 0);
329 				if (err) {
330 					return pikerr_CantRead;
331 				}
332 				count = fread(desc->data, 1, desc->length, map->file);
333 				if (count != desc->length) {
334 					return pikerr_CantRead;
335 				}
336 			}
337 			found->data.ptr = desc->data;
338 			break;
339 		default:
340 			return pikerr_BadOption;
341 	}
342 
343 	found->length = desc->length;
344 	found->format.name = desc->format;
345 	found->format.version = desc->formatversion;
346 
347 	return pikerr_None;
348 }
349 
350 #ifdef __STDC__
pikUnloadChunk(pikMapPtr map,pikChunkID id)351 pikErr pikUnloadChunk(pikMapPtr map, pikChunkID id)
352 #else
353 pikErr pikUnloadChunk(map, id)
354 pikMapPtr map;
355 pikChunkID id;
356 #endif
357 {
358 	pikDescriptor *desc;
359 
360 	if (!map || !map->chunks || map->inited != pik_InitedMagic) {
361 		return pikerr_NotAMap;
362 	}
363 
364 	if (id < 0 || id >= map->numchunks) {
365 		return pikerr_BadOption;
366 	}
367 
368 	desc = (&(map->chunks[id]));
369 
370 	if (desc->data) {
371 		free(desc->data);
372 		desc->data = NULL;
373 		return pikerr_None;
374 	}
375 	else {
376 		return pikerr_NotFound;
377 	}
378 }
379 
380