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