public WUDImage(FileInfo file) { if (file == null || !file.Exists) { //MessageBox.Show("WUD file is null or does not exist"); //System.exit(1); } fileStream = new FileStream(file.FullName, FileMode.Open, FileAccess.Read); BinaryReader br1 = new BinaryReader(fileStream); br1.BaseStream.Seek(0, SeekOrigin.Begin); byte[] wuxheader = new byte[WUDImageCompressedInfo.WUX_HEADER_SIZE]; int n = br1.Read(wuxheader, 0, WUDImageCompressedInfo.WUX_HEADER_SIZE); WUDImageCompressedInfo compressedInfo = new WUDImageCompressedInfo(wuxheader); if (compressedInfo.isWUX()) { //MessageBox.Show("Image is compressed"); this.isCompressed = true; this.isSplitted = false; Dictionary <int, long> indexTable = new Dictionary <int, long>(); long offsetIndexTable = compressedInfo.offsetIndexTable; br1.BaseStream.Seek(offsetIndexTable, SeekOrigin.Begin); byte[] tableData = new byte[(int)(compressedInfo.indexTableEntryCount * 0x04)]; br1.Read(tableData, 0, tableData.Length); int cur_offset = 0x00; for (long i = 0; i < compressedInfo.indexTableEntryCount; i++) { indexTable[(int)i] = BitConverter.ToInt32(tableData, (int)cur_offset); cur_offset += 0x04; } compressedInfo.indexTable = indexTable; this.compressedInfo = compressedInfo; } else { this.isCompressed = false; if (file.Name.Equals(String.Format(WUDDiscReaderSplitted.WUD_SPLITTED_DEFAULT_FILEPATTERN, 1)) && (file.Length == WUDDiscReaderSplitted.WUD_SPLITTED_FILE_SIZE)) { this.isSplitted = true; //MessageBox.Show("Image is splitted"); } else { //MessageBox.Show("Image is not splitted"); this.isSplitted = false; } } if (isCompressed) { this.WUDDiscReader = new WUDDiscReaderCompressed(this); } else if (isSplitted) { this.WUDDiscReader = new WUDDiscReaderSplitted(this); } else { this.WUDDiscReader = new WUDDiscReaderUncompressed(this); } fileStream.Close(); this.fileHandle = file; }
public static FileInfo compressWUDToWUX(WUDImage image, String outputFolder, String filename, bool overwrite) { if (image.isCompressed) { //log.info("Given image is already compressed"); return(null); } if (image.getWUDFileSize() != WUDImage.WUD_FILESIZE) { //log.info("Given WUD has not the expected filesize"); return(null); } String usedOutputFolder = outputFolder; if (usedOutputFolder == null) { usedOutputFolder = ""; } Utils.createDir(usedOutputFolder); String filePath; if (usedOutputFolder == String.Empty) { filePath = filename; } else { filePath = usedOutputFolder + Path.DirectorySeparatorChar + filename; } FileInfo outputFile = new FileInfo(filePath); if (outputFile.Exists && !overwrite) { //log.info("Couldn't compress wud, target file already exists (" + outputFile.getAbsolutePath() + ")"); return(null); } //log.info("Writing compressed file to: " + outputFile.getAbsolutePath()); FileStream fileStream = new FileStream(outputFile.FullName, FileMode.Create); BinaryWriter fileOutput = new BinaryWriter(fileStream); WUDImageCompressedInfo info = WUDImageCompressedInfo.getDefaultCompressedInfo(); byte[] header = info.getHeaderAsBytes(); //log.info("Writing header"); fileOutput.Write(header); int sectorTableEntryCount = (int)((image.getWUDFileSize() + WUDImageCompressedInfo.SECTOR_SIZE - 1) / (long)WUDImageCompressedInfo.SECTOR_SIZE); long sectorTableStart = fileOutput.BaseStream.Position; long sectorTableEnd = Utils.align(sectorTableEntryCount * 0x04, WUDImageCompressedInfo.SECTOR_SIZE); byte[] sectorTablePlaceHolder = new byte[(int)(sectorTableEnd - sectorTableStart)]; fileOutput.Write(sectorTablePlaceHolder); Dictionary <ByteArrayWrapper, int> sectorHashes = new Dictionary <ByteArrayWrapper, int>(); Dictionary <int, int> sectorMapping = new Dictionary <int, int>(); MemoryStream min = image.WUDDiscReader.readEncryptedToInputStream(0, image.getWUDFileSize()); int bufferSize = WUDImageCompressedInfo.SECTOR_SIZE; byte[] blockBuffer = new byte[bufferSize]; ByteArrayBuffer overflow = new ByteArrayBuffer(bufferSize); long written = 0; int curSector = 0; int realSector = 0; //log.info("Writing sectors"); Int32 oldOffset = int.MinValue; min.Seek(0, SeekOrigin.Begin); do { //int read = StreamUtils.getChunkFromStream(in, blockBuffer, overflow, bufferSize); int read = min.Read(blockBuffer, 0, bufferSize); ByteArrayWrapper hash = new ByteArrayWrapper(HashUtil.hashSHA1(blockBuffer)); if (!sectorHashes.TryGetValue(hash, out oldOffset)) { sectorMapping.Add(curSector, realSector); sectorHashes.Add(hash, realSector); fileOutput.Write(blockBuffer); realSector++; } else { sectorMapping.Add(curSector, oldOffset); oldOffset = int.MinValue; } written += read; curSector++; if (curSector % 10 == 0) { double readMB = written / 1024.0 / 1024.0; double writtenMB = ((long)realSector * (long)bufferSize) / 1024.0 / 1024.0; double percent = ((double)written / image.getWUDFileSize()) * 100; double ratio = 1 / (writtenMB / readMB); //System.out.print(String.format(Locale.ROOT, "\rCompressing into .wux | Progress %.2f%% | Ratio: 1:%.2f | Read: %.2fMB | Written: %.2fMB\t", percent, ratio, readMB, writtenMB)); } } while (written < image.getWUDFileSize()); //System.out.println(); //System.out.println("Sectors compressed."); //log.info("Writing sector table"); fileOutput.BaseStream.Seek(sectorTableStart, SeekOrigin.Begin); ByteBuffer buffer = ByteBuffer.allocate(sectorTablePlaceHolder.Length); //buffer.order(ByteOrder.LITTLE_ENDIAN); foreach (var e in sectorMapping) { buffer.putInt(e.Value); } fileOutput.Write(buffer.array()); fileOutput.Close(); return(outputFile); }
/** * Expects the .wux format by Exzap. You can more infos about it here. https://gbatemp.net/threads/wii-u-image-wud-compression-tool.397901/ */ public override void readEncryptedToOutputStream(Stream outputStream, long offset, long size) { // make sure there is no out-of-bounds read WUDImageCompressedInfo info = image.compressedInfo; long fileBytesLeft = info.uncompressedSize - offset; long usedOffset = offset; long usedSize = size; if (fileBytesLeft <= 0) { //MessageBox.Show("offset too big"); //System.exit(1); return; } if (fileBytesLeft < usedSize) { usedSize = fileBytesLeft; } // compressed read must be handled on a per-sector level int bufferSize = 0x8000; byte[] buffer = new byte[bufferSize]; BinaryReader input = getRandomAccessFileStream(); while (usedSize > 0) { long sectorOffset = (usedOffset % info.sectorSize); long remainingSectorBytes = info.sectorSize - sectorOffset; long sectorIndex = (usedOffset / info.sectorSize); int bytesToRead = (int)((remainingSectorBytes < usedSize) ? remainingSectorBytes : usedSize); // read only up to the end of the current sector // look up real sector index long realSectorIndex = info.getSectorIndex((int)sectorIndex); long offset2 = info.offsetSectorArray + realSectorIndex * info.sectorSize + sectorOffset; input.BaseStream.Seek(offset2, SeekOrigin.Begin); int read = input.Read(buffer, 0, buffer.Length); if (read < 0) { return; } try { outputStream.Write(buffer, 0, bytesToRead); } catch (Exception) { //if (e.getMessage().equals("Pipe closed")) { // break; //} else { // throw e; //} } usedSize -= bytesToRead; usedOffset += bytesToRead; } input.Close(); }