/** * @file io.c Microsoft Cabinet module I/O functions * * $Id: io.c,v 1.9 2003/01/04 19:50:52 chipx86 Exp $ * * @Copyright (C) 1999-2003 The GNUpdate Project. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include "cab.h" static void __toLower(char *str) { char *c; for (c = str; *c != '\0'; c++) *c = tolower(*c); } CxStatus cxCabReadHeader(CxFP *fp, CabInfo **destInfo, CxArchive *archive) { CabInfo *info; *destInfo = NULL; MEM_CHECK(info = (CabInfo *)malloc(sizeof(CabInfo))); memset(info, 0, sizeof(CabInfo)); info->fp = fp; if (cxRead(info->u.buffer, CAB_HEADER_SIZE, 1, fp) != 1) return CX_CORRUPT; if (info->u.header.sig[0] != 'M' || info->u.header.sig[1] != 'S' || info->u.header.sig[2] != 'C' || info->u.header.sig[3] != 'F') { return CX_INVALID_FORMAT; } *destInfo = info; return CX_SUCCESS; } CxStatus cxCabReadInfo(CxArchive *archive, CabInfo **destInfo, CxFP *fp) { CxStatus status; CabInfo *info; char *buffer, *bufp; size_t bufSize; short reserveSize = 0; char folderResSize = 0, dataResSize = 0; int i; CxDirectory *root; if ((status = cxCabReadHeader(fp, &info, archive)) != CX_SUCCESS) return status; *destInfo = info; if (CAB_HAS_RESERVE(&info->u.header)) { char sizeBuf[4]; int counter = 0; /* Get the sizes */ cxRead(sizeBuf, sizeof(long), 1, fp); reserveSize = cxCabGet16(sizeBuf, &counter); folderResSize = cxCabGet8(sizeBuf, &counter); dataResSize = cxCabGet8(sizeBuf, &counter); /* Skip past the reserve. */ cxSeek(fp, reserveSize, SEEK_CUR); } /* Get the previous and next files and descriptions. */ bufSize = info->u.header.firstOffset - cxTell(fp); MEM_CHECK(buffer = (char *)malloc(bufSize)); if (cxRead(buffer, 1, bufSize, fp) != bufSize) { free(buffer); return CX_CORRUPT; } bufp = buffer; if (CAB_HAS_PREV(&info->u.header)) { /* Get the previous filename. */ info->prevFile = strdup(bufp); bufp += strlen(info->prevFile) + 1; /* Get the previous description. */ info->prevDesc = strdup(bufp); bufp += strlen(info->prevDesc) + 1; } else { info->prevFile = NULL; info->prevDesc = NULL; } if (CAB_HAS_NEXT(&info->u.header)) { /* Get the previous filename. */ info->nextFile = strdup(bufp); bufp += strlen(info->nextFile) + 1; /* Get the next description. */ info->nextDesc = strdup(bufp); bufp += strlen(info->nextDesc) + 1; } else { info->nextFile = NULL; info->nextDesc = NULL; } free(buffer); /* Get the folders */ for (i = 0; i < info->u.header.folderCount; i++) { CabFolder folder; if (cxRead(&folder, CAB_FOLDER_SIZE, 1, fp) != 1) { return CX_CORRUPT; } switch (folder.compressType & CAB_COMP_MASK) { case CAB_COMP_NONE: printf("Stored\n"); break; case CAB_COMP_MSZIP: printf("MSZIP\n"); break; case CAB_COMP_QUANTUM: printf("Quantum\n"); break; case CAB_COMP_LZX: printf("LZX\n"); break; default: printf("Unknown\n"); break; } if (folderResSize > 0) { /* Skip the folder reserve. */ cxSeek(fp, folderResSize, SEEK_CUR); } } /* Make sure our offset is correct */ if (info->u.header.firstOffset != cxTell(fp)) cxSeek(fp, info->u.header.firstOffset, SEEK_SET); /* Get the root directory of the archive. */ root = cxGetArchiveRoot(archive); for (i = 0; i < info->u.header.fileCount; i++) { CabEntry entry; char nameBuf[CAB_NAME_MAX]; char *baseName = NULL, *basePath = NULL; long offset; CxDirectory *dir; /* Read in the entry. */ if (cxRead(&entry, CAB_ENTRY_SIZE, 1, fp) != 1) { return CX_CORRUPT; } /* Save the offset. */ offset = cxTell(fp); /* Read in the filename. */ if (cxRead(nameBuf, 1, CAB_NAME_MAX, fp) != CAB_NAME_MAX) { return CX_CORRUPT; } /* Get back to the right position. */ cxSeek(fp, offset + strlen(nameBuf) + 1, SEEK_SET); /* Make the filename lowercase */ __toLower(nameBuf); cxSplitPath(nameBuf, &baseName, &basePath); if (basePath != NULL) { dir = cxGetDirectory(root, basePath); if (dir == NULL) { char *basePathName; dir = cxNewDirectory(); basePathName = cxGetBaseName(basePath); cxSetDirName(dir, basePathName); free(basePathName); } free(basePath); } } return CX_SUCCESS; }