/// <summary> /// Allocates a decompressor for each cab and merges any cabs that need merged. /// </summary> /// <param name="cabinets"></param> /// <returns></returns> private static IEnumerable <MSCabinet> MergeCabs(IList <CabInfo> cabInfos) { /* Sometimes cab files are part of a set. We must merge those into their set before we leave here. * Otherwise extracting a file that extends beyond the bounds of one cab in the set will fail. This happens in VBRuntime.msi * * It can be determined if a cabinet has further parts to load by examining the mscabd_cabinet::flags field: * if (flags & MSCAB_HDR_PREVCAB) is non-zero, there is a predecessor cabinet to open() and prepend(). Its MS-DOS case-insensitive filename is mscabd_cabinet::prevname * if (flags & MSCAB_HDR_NEXTCAB) is non-zero, there is a successor cabinet to open() and append(). Its MS-DOS case-insensitive filename is mscabd_cabinet::nextname */ var decompressors = new List <MSCabinet>(); for (int i = 0; i < cabInfos.Count; i++) { CabInfo cab = cabInfos[i]; MSCabinet msCab = null; try { msCab = new MSCabinet(cab.LocalCabFile); // NOTE: Deliberately not disposing. Caller must cleanup. } catch (Exception) { // As seen in https://github.com/activescott/lessmsi/issues/104, sometimes bogus cabs are inside of a msi but they're not needed to extract any files from. So we should attempt to ignore this failure here: Debug.Fail( string.Format("Cab name \"{0}\" could not be read by cab reader. Will attempt to ignore...", cab.CabSourceName) ); continue; } if ((msCab.Flags & MSCabinetFlags.MSCAB_HDR_NEXTCAB) != 0) { Debug.Assert(!string.IsNullOrEmpty(msCab.NextName), "Header indcates next cab but new cab not found."); // load the cab found in NextName: // Append it to msCab Debug.Print("Found cabinet set. Nextname: " + msCab.NextName); var nextCab = FindCabAndRemoveFromList(cabInfos, msCab.NextName); var msCabNext = new MSCabinet(nextCab.LocalCabFile); msCab.Append(msCabNext); decompressors.Add(msCab); } else if ((msCab.Flags & MSCabinetFlags.MSCAB_HDR_PREVCAB) != 0) { Debug.Assert(!string.IsNullOrEmpty(msCab.PrevName), "Header indcates prev cab but new cab not found."); Debug.Print("Found cabinet set. PrevName: " + msCab.PrevName); var prevCabInfo = FindCabAndRemoveFromList(cabInfos, msCab.PrevName); var msCabPrev = new MSCabinet(prevCabInfo.LocalCabFile); msCabPrev.Append(msCab); decompressors.Add(msCabPrev); } else { // just a simple standalone cab decompressors.Add(msCab); } } return(decompressors); }
public void CabinetSet() { //NO WORKY! var root = Path.Combine(AppPath, "cabinetset"); var cabFilename1 = Path.Combine(root, "Disk1.CAB"); var cabFilename2 = Path.Combine(root, "Disk2.CAB"); using (var cab1 = new MSCabinet(cabFilename1)) using (var cab2 = new MSCabinet(cabFilename2)) { cab1.Append(cab2); ExplodeCab(cab1, OutDir(cabFilename1)); } Console.ReadLine(); }
public void CabinetSet() { string root = Path.Combine(AppContext.BaseDirectory, "test_files", "cabinetset"); string cabFilename1 = Path.Combine(root, "Disk1.CAB"); string cabFilename2 = Path.Combine(root, "Disk2.CAB"); Assert.True(File.Exists(cabFilename1)); Assert.True(File.Exists(cabFilename2)); using (var cab1 = new MSCabinet(cabFilename1)) using (var cab2 = new MSCabinet(cabFilename2)) { cab1.Append(cab2); ExplodeCab(cab1, OutDir(cabFilename1)); } }
/// <summary> /// Allocates a decompressor for each cab and merges any cabs that need merged. /// </summary> /// <param name="cabinets"></param> /// <returns></returns> private static IEnumerable <MSCabinet> MergeCabs(IList <CabInfo> cabInfos) { /* Sometimes cab files are part of a set. We must merge those into their set before we leave here. * Otherwise extracting a file that extends beyond the bounds of one cab in the set will fail. This happens in VBRuntime.msi * * It can be determined if a cabinet has further parts to load by examining the mscabd_cabinet::flags field: * if (flags & MSCAB_HDR_PREVCAB) is non-zero, there is a predecessor cabinet to open() and prepend(). Its MS-DOS case-insensitive filename is mscabd_cabinet::prevname * if (flags & MSCAB_HDR_NEXTCAB) is non-zero, there is a successor cabinet to open() and append(). Its MS-DOS case-insensitive filename is mscabd_cabinet::nextname */ var decompressors = new List <MSCabinet>(); for (int i = 0; i < cabInfos.Count; i++) { CabInfo cab = cabInfos[i]; var msCab = new MSCabinet(cab.LocalCabFile); //NOTE: Deliberately not disposing. Caller must cleanup. if ((msCab.Flags & MSCabinetFlags.MSCAB_HDR_NEXTCAB) != 0) { Debug.Assert(!string.IsNullOrEmpty(msCab.NextName), "Header indcates next cab but new cab not found."); // load the cab found in NextName: // Append it to msCab Debug.Print("Found cabinet set. Nextname: " + msCab.NextName); var nextCab = FindCabAndRemoveFromList(cabInfos, msCab.NextName); var msCabNext = new MSCabinet(nextCab.LocalCabFile); msCab.Append(msCabNext); decompressors.Add(msCab); } else if ((msCab.Flags & MSCabinetFlags.MSCAB_HDR_PREVCAB) != 0) { Debug.Assert(!string.IsNullOrEmpty(msCab.PrevName), "Header indcates prev cab but new cab not found."); Debug.Print("Found cabinet set. PrevName: " + msCab.PrevName); var prevCabInfo = FindCabAndRemoveFromList(cabInfos, msCab.PrevName); var msCabPrev = new MSCabinet(prevCabInfo.LocalCabFile); msCabPrev.Append(msCab); decompressors.Add(msCabPrev); } else { // just a simple standalone cab decompressors.Add(msCab); } } return(decompressors); }
static void Main() { IEnumerable <string> files = Directory.GetFiles(AppPath, "*.cab"); foreach (var f in files) { ExplodeCab(f); } //NO WORKY! var root = Path.Combine(AppPath, "cabinetset"); var cabFilename1 = Path.Combine(root, "Disk1.CAB"); var cabFilename2 = Path.Combine(root, "Disk2.CAB"); using (var cab1 = new MSCabinet(cabFilename1)) using (var cab2 = new MSCabinet(cabFilename2)) { cab1.Append(cab2); ExplodeCab(cab1, OutDir(cabFilename1)); } Console.ReadLine(); }
/// <summary> /// Allocates a decompressor for each cab and merges any cabs that need merged. /// </summary> /// <param name="cabinets"></param> /// <returns></returns> private static IEnumerable<MSCabinet> MergeCabs(IList<CabInfo> cabInfos) { /* Sometimes cab files are part of a set. We must merge those into their set before we leave here. * Otherwise extracting a file that extends beyond the bounds of one cab in the set will fail. This happens in VBRuntime.msi * * It can be determined if a cabinet has further parts to load by examining the mscabd_cabinet::flags field: * if (flags & MSCAB_HDR_PREVCAB) is non-zero, there is a predecessor cabinet to open() and prepend(). Its MS-DOS case-insensitive filename is mscabd_cabinet::prevname * if (flags & MSCAB_HDR_NEXTCAB) is non-zero, there is a successor cabinet to open() and append(). Its MS-DOS case-insensitive filename is mscabd_cabinet::nextname */ var decompressors = new List<MSCabinet>(); for (int i=0; i < cabInfos.Count; i++) { CabInfo cab = cabInfos[i]; var msCab = new MSCabinet(cab.LocalCabFile);//NOTE: Deliberately not disposing. Caller must cleanup. if ((msCab.Flags & MSCabinetFlags.MSCAB_HDR_NEXTCAB) != 0) { Debug.Assert(!string.IsNullOrEmpty(msCab.NextName), "Header indcates next cab but new cab not found."); // load the cab found in NextName: // Append it to msCab Debug.Print("Found cabinet set. Nextname: " + msCab.NextName); var nextCab = FindCabAndRemoveFromList(cabInfos, msCab.NextName); var msCabNext = new MSCabinet(nextCab.LocalCabFile); msCab.Append(msCabNext); decompressors.Add(msCab); } else if ((msCab.Flags & MSCabinetFlags.MSCAB_HDR_PREVCAB) != 0) { Debug.Assert(!string.IsNullOrEmpty(msCab.PrevName), "Header indcates prev cab but new cab not found."); Debug.Print("Found cabinet set. PrevName: " + msCab.PrevName); var prevCabInfo = FindCabAndRemoveFromList(cabInfos, msCab.PrevName); var msCabPrev = new MSCabinet(prevCabInfo.LocalCabFile); msCabPrev.Append(msCab); decompressors.Add(msCabPrev); } else { // just a simple standalone cab decompressors.Add(msCab); } } return decompressors; }