1 /**
2 * @file io.c Microsoft Cabinet module I/O functions
3 *
4 * $Id: io.c,v 1.9 2003/01/04 19:50:52 chipx86 Exp $
5 *
6 * @Copyright (C) 1999-2003 The GNUpdate Project.
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
17 *
18 * You should have received a copy of the GNU Library General Public
19 * License along with this library; if not, write to the
20 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 * Boston, MA 02111-1307, USA.
22 */
23 #include "cab.h"
24
25 static void
__toLower(char * str)26 __toLower(char *str)
27 {
28 char *c;
29
30 for (c = str; *c != '\0'; c++)
31 *c = tolower(*c);
32 }
33
34 CxStatus
cxCabReadHeader(CxFP * fp,CabInfo ** destInfo,CxArchive * archive)35 cxCabReadHeader(CxFP *fp, CabInfo **destInfo, CxArchive *archive)
36 {
37 CabInfo *info;
38
39 *destInfo = NULL;
40
41 MEM_CHECK(info = (CabInfo *)malloc(sizeof(CabInfo)));
42 memset(info, 0, sizeof(CabInfo));
43
44 info->fp = fp;
45
46 if (cxRead(info->u.buffer, CAB_HEADER_SIZE, 1, fp) != 1)
47 return CX_CORRUPT;
48
49 if (info->u.header.sig[0] != 'M' || info->u.header.sig[1] != 'S' ||
50 info->u.header.sig[2] != 'C' || info->u.header.sig[3] != 'F')
51 {
52 return CX_INVALID_FORMAT;
53 }
54
55 *destInfo = info;
56
57 return CX_SUCCESS;
58 }
59
60 CxStatus
cxCabReadInfo(CxArchive * archive,CabInfo ** destInfo,CxFP * fp)61 cxCabReadInfo(CxArchive *archive, CabInfo **destInfo, CxFP *fp)
62 {
63 CxStatus status;
64 CabInfo *info;
65 char *buffer, *bufp;
66 size_t bufSize;
67 short reserveSize = 0;
68 char folderResSize = 0, dataResSize = 0;
69 int i;
70 CxDirectory *root;
71
72 if ((status = cxCabReadHeader(fp, &info, archive)) != CX_SUCCESS)
73 return status;
74
75 *destInfo = info;
76
77 if (CAB_HAS_RESERVE(&info->u.header))
78 {
79 char sizeBuf[4];
80 int counter = 0;
81
82 /* Get the sizes */
83 cxRead(sizeBuf, sizeof(long), 1, fp);
84
85 reserveSize = cxCabGet16(sizeBuf, &counter);
86 folderResSize = cxCabGet8(sizeBuf, &counter);
87 dataResSize = cxCabGet8(sizeBuf, &counter);
88
89 /* Skip past the reserve. */
90 cxSeek(fp, reserveSize, SEEK_CUR);
91 }
92
93 /* Get the previous and next files and descriptions. */
94 bufSize = info->u.header.firstOffset - cxTell(fp);
95
96 MEM_CHECK(buffer = (char *)malloc(bufSize));
97
98 if (cxRead(buffer, 1, bufSize, fp) != bufSize)
99 {
100 free(buffer);
101 return CX_CORRUPT;
102 }
103
104 bufp = buffer;
105
106 if (CAB_HAS_PREV(&info->u.header))
107 {
108 /* Get the previous filename. */
109 info->prevFile = strdup(bufp);
110 bufp += strlen(info->prevFile) + 1;
111
112 /* Get the previous description. */
113 info->prevDesc = strdup(bufp);
114 bufp += strlen(info->prevDesc) + 1;
115 }
116 else
117 {
118 info->prevFile = NULL;
119 info->prevDesc = NULL;
120 }
121
122 if (CAB_HAS_NEXT(&info->u.header))
123 {
124 /* Get the previous filename. */
125 info->nextFile = strdup(bufp);
126 bufp += strlen(info->nextFile) + 1;
127
128 /* Get the next description. */
129 info->nextDesc = strdup(bufp);
130 bufp += strlen(info->nextDesc) + 1;
131 }
132 else
133 {
134 info->nextFile = NULL;
135 info->nextDesc = NULL;
136 }
137
138 free(buffer);
139
140 /* Get the folders */
141 for (i = 0; i < info->u.header.folderCount; i++)
142 {
143 CabFolder folder;
144
145 if (cxRead(&folder, CAB_FOLDER_SIZE, 1, fp) != 1)
146 {
147 return CX_CORRUPT;
148 }
149
150 switch (folder.compressType & CAB_COMP_MASK)
151 {
152 case CAB_COMP_NONE: printf("Stored\n"); break;
153 case CAB_COMP_MSZIP: printf("MSZIP\n"); break;
154 case CAB_COMP_QUANTUM: printf("Quantum\n"); break;
155 case CAB_COMP_LZX: printf("LZX\n"); break;
156 default: printf("Unknown\n"); break;
157 }
158
159 if (folderResSize > 0)
160 {
161 /* Skip the folder reserve. */
162 cxSeek(fp, folderResSize, SEEK_CUR);
163 }
164 }
165
166 /* Make sure our offset is correct */
167 if (info->u.header.firstOffset != cxTell(fp))
168 cxSeek(fp, info->u.header.firstOffset, SEEK_SET);
169
170 /* Get the root directory of the archive. */
171 root = cxGetArchiveRoot(archive);
172
173 for (i = 0; i < info->u.header.fileCount; i++)
174 {
175 CabEntry entry;
176 char nameBuf[CAB_NAME_MAX];
177 char *baseName = NULL, *basePath = NULL;
178 long offset;
179 CxDirectory *dir;
180
181 /* Read in the entry. */
182 if (cxRead(&entry, CAB_ENTRY_SIZE, 1, fp) != 1)
183 {
184 return CX_CORRUPT;
185 }
186
187 /* Save the offset. */
188 offset = cxTell(fp);
189
190 /* Read in the filename. */
191 if (cxRead(nameBuf, 1, CAB_NAME_MAX, fp) != CAB_NAME_MAX)
192 {
193 return CX_CORRUPT;
194 }
195
196 /* Get back to the right position. */
197 cxSeek(fp, offset + strlen(nameBuf) + 1, SEEK_SET);
198
199 /* Make the filename lowercase */
200 __toLower(nameBuf);
201
202 cxSplitPath(nameBuf, &baseName, &basePath);
203
204 if (basePath != NULL)
205 {
206 dir = cxGetDirectory(root, basePath);
207
208 if (dir == NULL)
209 {
210 char *basePathName;
211
212 dir = cxNewDirectory();
213
214 basePathName = cxGetBaseName(basePath);
215 cxSetDirName(dir, basePathName);
216
217 free(basePathName);
218 }
219
220 free(basePath);
221 }
222 }
223
224 return CX_SUCCESS;
225 }
226