public void calculateHashes(Dictionary <int, Content> allContents) { byte[] header = rawData; // Calculating offset for the hashes int cnt = Utils.SwapEndianness(BitConverter.ToInt32(header, 0x10)); int start_offset = 0x40 + cnt * 0x04; int offset = 0; // We have to make sure, that the list is ordered by index List <Content> contents = new List <Content>(allContents.Values); contents.Sort(delegate(Content c1, Content c2) { return(c1.index.CompareTo(c2.index)); }); foreach (Content c in allContents.Values) { if (!c.isHashed() || !c.isEncrypted()) { continue; } // The encrypted content are splitted in 0x10000 chunk. For each 0x1000 chunk we need one entry in the h3 int cnt_hashes = (int)(c.encryptedFileSize / 0x10000 / 0x1000) + 1; byte[] hash = Arrays.copyOfRange(header, start_offset + offset * 0x14, start_offset + (offset + cnt_hashes) * 0x14); // Checking the hash of the h3 file. if (!Arrays.Equals(HashUtil.hashSHA1(hash), c.SHA2Hash)) { log.TraceEvent(TraceEventType.Error, 0, "h3 incorrect from WUD"); } addH3Hashes(c.index, hash); offset += cnt_hashes; } calculatedHashes = (true); }
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); }