1 /*-
2  * Copyright (c) 2004 Patrick Mauritz <oxygene@openbios.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  */
27 #include "fpk.h"
28 
29 /* internal functions */
30 
fpk__readlfile(FILE * fpk)31 char* fpk__readlfile(FILE* fpk) {
32   unsigned char tmp;
33   unsigned int len;
34   char* result;
35 
36   fread(&tmp,1,1,fpk);
37   len=tmp;
38 
39   result=(char*)malloc(len);
40   fread(result,1,len,fpk);
41 
42   return result;
43 }
44 
fpk__readLE4(FILE * fpk)45 unsigned int fpk__readLE4(FILE* fpk) {
46   unsigned char tmp[4];
47   fread(&tmp,1,4,fpk);
48   return (tmp[3]<<24)+(tmp[2]<<16)+(tmp[1]<<8)+tmp[0];
49 }
50 
fpk__clearfiles(struct fpkmeta * meta)51 void fpk__clearfiles(struct fpkmeta* meta) {
52   signed int c;
53   if (!(meta->files)) return; /* clean already */
54   for (c=0;c<meta->numfiles;c++) {
55     if (meta->files[c].name) free(meta->files[c].name);
56     if (meta->files[c].directory) free(meta->files[c].directory);
57   }
58   free(meta->files);
59 }
60 
fpk__getmeta(struct fpkmeta * meta)61 void fpk__getmeta(struct fpkmeta* meta) {
62   unsigned int c;
63 
64   fseek(meta->fpk,8L,SEEK_SET);
65   fread(meta->shortname,1,13,meta->fpk);
66   fread(meta->longname,1,64,meta->fpk);
67   fread(meta->author,1,36,meta->fpk);
68 
69   if (meta->rootpath) free(meta->rootpath);
70   c=getc(meta->fpk);
71   (void)getc(meta->fpk);
72   meta->rootpath=(char*)malloc(c);
73   fread(meta->rootpath,1,c,meta->fpk);
74 
75   return;
76 }
77 
78 
79 /* exported functions */
80 
fpkmagic(struct fpkmeta * meta)81 int fpkmagic(struct fpkmeta* meta) {
82   char test[8];
83   rewind(meta->fpk);
84   fread(&test,1,8,meta->fpk);
85   return memcmp(test,"GPKG\0\0\0\0",8);
86 }
87 
fpkgetdir(struct fpkmeta * meta)88 void fpkgetdir(struct fpkmeta* meta) {
89   unsigned int c,c2;
90 
91   fseek(meta->fpk,136L,SEEK_SET);
92   c=fpk__readLE4(meta->fpk);
93 
94   meta->size=0;
95 
96   if (meta->files) fpk__clearfiles(meta);
97   meta->files=(struct fpkfile*)malloc(sizeof(struct fpkfile)*c);
98   meta->numfiles=c;
99 
100   for (c2=0;c2<c;c2++) {
101     char v=getc(meta->fpk);
102     char *dir, *file;
103     unsigned int length;
104     if (v=='2') {
105       // finish
106       meta->files[c2].offset=-1;
107       meta->files[c2].size=-1;
108       meta->files[c2].directory=0;
109       meta->files[c2].name=0;
110       break;
111     }
112     dir=fpk__readlfile(meta->fpk);
113     file=fpk__readlfile(meta->fpk);
114     meta->files[c2].directory=dir;
115     meta->files[c2].name=file;
116     if (v=='0') {
117       length=0;
118       meta->files[c2].offset=0;
119       // directory
120     }
121     if (v=='1') {
122       length=fpk__readLE4(meta->fpk);
123       meta->files[c2].offset=ftell(meta->fpk);
124       fseek(meta->fpk,length,SEEK_CUR);
125       // file
126     }
127     meta->files[c2].size=length;
128     meta->size+=length;
129   }
130 }
131 
fpkinit(struct fpkmeta * meta,const char * filename)132 signed int fpkinit(struct fpkmeta *meta, const char *filename) {
133   meta->files=0;
134   meta->rootpath=0;
135   meta->iter=-1;
136   meta->numfiles=0;
137   meta->size=0;
138 
139   meta->fpk=fopen(filename,"r");
140   if (!meta->fpk) return -1;
141 
142   if (fpkmagic(meta)) {
143     fclose(meta->fpk);
144     return -1;
145   }
146   fpk__getmeta(meta);
147   return 0;
148 }
149 
fpkclose(struct fpkmeta * meta)150 void fpkclose(struct fpkmeta *meta) {
151   fclose(meta->fpk);
152   fpk__clearfiles(meta);
153 }
154 
fpkrewind(struct fpkmeta * meta)155 void fpkrewind(struct fpkmeta *meta) {
156   meta->iter=-1;
157 }
158 
fpknextfile(struct fpkmeta * meta)159 struct fpkfile* fpknextfile(struct fpkmeta *meta) {
160   while ((meta->iter<meta->numfiles) && (meta->files[++meta->iter].offset<=0)) {};
161   if (meta->iter>=meta->numfiles)
162     return NULL;
163   else
164     return &meta->files[meta->iter];
165 }
166 
fpknextdir(struct fpkmeta * meta)167 struct fpkfile* fpknextdir(struct fpkmeta *meta) {
168   while ((meta->iter<meta->numfiles) && (meta->files[++meta->iter].offset!=0)) {};
169   if (meta->iter>=meta->numfiles)
170     return NULL;
171   else
172     return &meta->files[meta->iter];
173 }
174 
fpkgetfile(struct fpkmeta * meta,struct fpkfile * file)175 unsigned char* fpkgetfile(struct fpkmeta *meta, struct fpkfile *file){
176   char *tmp;
177   if (file->offset<=0) return NULL; /* not a file */
178   fseek(meta->fpk,file->offset,SEEK_SET);
179   tmp=(unsigned char*)malloc(file->size);
180   fread(tmp,file->size,1,meta->fpk);
181   return tmp;
182 }
183