private void parseCompressedFragmentFiles(string rootFolder, FileInfo fi, MemoryStream ms) { try { List<FileInfo> compFr2 = null; int fnameLen; long fsize; string fname; while (ms.Position < ms.Length) { if (previousMs != null) // recovery mode { byte[] buff = new byte[24]; int a = previousMs.Read(buff, 0, buff.Length); if (a < buff.Length) ms.Read(buff, a, buff.Length - a); fnameLen = BitConverter.ToInt32(buff, 0); if (fnameLen > 2048) // out of memory prevention { throw new ApplicationException(string.Format("Invalid filename length: {0}", fnameLen)); } fsize = BitConverter.ToUInt32(buff, 4); buff = new byte[fnameLen * 2]; a = previousMs.Read(buff, 0, buff.Length); if (a < buff.Length) ms.Read(buff, a, buff.Length - a); fname = System.Text.Encoding.Unicode.GetString(buff); previousMs.Dispose(); previousMs = null; // leave recovery mode addLine("leaving recovery mode with filename: " + fname); } else { if ((ms.Position + 24) > ms.Length) // 24 = sizeof(fnameLen + fsize) + 16 { previousMs = ms; addLine("file header behind end of fragment - entering recovery mode"); return; } fnameLen = StreamUtils.ReadUInt32asInt(ms); if (fnameLen > 2048) // out of memory prevention { throw new ApplicationException(string.Format("Invalid filename length: {0}", fnameLen)); } fsize = StreamUtils.ReadUInt32(ms); ms.Seek(16, SeekOrigin.Current); // 8 bytes?? + 8bytes date and time?? if ((ms.Position + 2 * fnameLen) > ms.Length) { ms.Seek(-24, SeekOrigin.Current); previousMs = ms; // enter recovery mode addLine("file name behind end of fragment - entering recovery mode"); return; } fname = StreamUtils.ReadString(ms, fnameLen); } addLine(fname); string dir = Path.GetDirectoryName(fname); bool canBeMessage = ExpectMessage(dir); compFr2 = findOrCreateFileInfoList(rootFolder + "\\" + dir); fname = Path.GetFileName(fname).Trim(); if (fname.Length > 0) { if (ms.Length >= ms.Position + fsize) { FileInfoCfPart ficp = new FileInfoCfPart(fname, fi.Start, fi.RawSize, DateTime.MinValue, ms.Position, fsize); if (canBeMessage) parseSymbianMessage(ficp); compFr2.Add(ficp); StreamUtils.Counter += fsize; } else { currentIncompleteMultipartFile = new FileInfoCfMultiPart(fname, DateTime.MinValue, fsize, compFr2, canBeMessage); currentIncompleteMultipartFile.Parts.Add(new FileInfoCfPart("", fi.Start, fi.RawSize, DateTime.MinValue, ms.Position, ms.Length - ms.Position)); StreamUtils.Counter += (ms.Length - ms.Position); addLine("incomplete file, continue on next fragment..."); } } ms.Seek(fsize, SeekOrigin.Current); } } catch (Exception exc) { previousMs = null; // reset recovery addLine(string.Format("Parsing ERROR at position {0}: {1}", ms.Position.ToString("X"), exc.Message)); } }
private void parseCompressedFragment(string rootFolder, FileinfoCf fi, long lenUncomp) { long initCounter = StreamUtils.Counter; MemoryStream ms = new MemoryStream(); try { fi.CopyToStream(currentFileName, ms); if (ms.Length != lenUncomp) { addLine(string.Format("WARNING: uncompressed size ({0}) differs from expected ({1})", ms.Length, lenUncomp)); } } catch (Exception exc) { previousMs = null; // reset recovery mode addLine("ERROR decompressing fragment: " + exc.Message); if (currentIncompleteMultipartFile != null) { if (currentIncompleteMultipartFile.MissingLength >= lenUncomp) { addLine(string.Format("Incomplete multipart file '{0}' shortened", currentIncompleteMultipartFile.Filename)); currentIncompleteMultipartFile.Shorten(lenUncomp); return; } else { addLine(string.Format("Incomplete multipart file '{0}' corrupted and lost", currentIncompleteMultipartFile.Filename)); currentIncompleteMultipartFile = null; return; } } } ms.Seek(0, SeekOrigin.Begin); if (previousMs != null) { // continue recovery mode started by previous fragment parseCompressedFragmentFiles(rootFolder, fi, ms); } else if (currentHeaderLengthToSkip > 0) { // continnue skipping useless header if (currentHeaderLengthToSkip > ms.Length) { currentHeaderLengthToSkip -= ms.Length; addLine("still incomplete header, continue on next fragment..."); } else { ms.Seek(currentHeaderLengthToSkip, SeekOrigin.Begin); currentHeaderLengthToSkip = 0; addLine("end of header reached, looking for files in rest of fragment..."); parseCompressedFragmentFiles(rootFolder, fi, ms); } } else if (currentIncompleteMultipartFile != null) { // continue collecting parts of multifragment file long missingLength = currentIncompleteMultipartFile.MissingLength; if (missingLength > ms.Length) { currentIncompleteMultipartFile.Parts.Add(new FileInfoCfPart("", fi.Start, fi.RawSize, fi.FileTime, 0, ms.Length)); StreamUtils.Counter += ms.Length; addLine("still incomplete file, continue on next fragment..."); } else { if (currentIncompleteMultipartFile.Shortened) { addLine(string.Format("multipart file '{0}' complete, but corrupted (shortened) - skipping", currentIncompleteMultipartFile.Filename)); } else { addLine(string.Format("multipart file '{0}' complete.", currentIncompleteMultipartFile.Filename)); currentIncompleteMultipartFile.Parts.Add(new FileInfoCfPart("", fi.Start, fi.RawSize, fi.FileTime, 0, missingLength)); if (currentIncompleteMultipartFile.CanBeMessage) { parseSymbianMessage(currentIncompleteMultipartFile); } currentIncompleteMultipartFile.Finish(); } currentIncompleteMultipartFile = null; StreamUtils.Counter += missingLength; ms.Seek(missingLength, SeekOrigin.Begin); if (ms.Length > missingLength) { addLine("looking for next files in rest of fragment..."); parseCompressedFragmentFiles(rootFolder, fi, ms); } } } else { if (ms.Length <= 16) { addLine("empty fragment\r\n"); return; } // detection of fragment type ms.Seek(0, SeekOrigin.Begin); UInt32 test1 = StreamUtils.ReadUInt32(ms); UInt32 test2 = StreamUtils.ReadUInt32(ms); UInt32 test3 = StreamUtils.ReadUInt32(ms); UInt32 test4 = StreamUtils.ReadUInt32(ms); if (test3 == 0x20 || test3 == 0 || (test3 == 1 && test4 == 8)) { ms.Seek(0, SeekOrigin.Begin); parseCompressedFragmentFiles(rootFolder, fi, ms); } else if (test3 == 1 || test3 == 2) { ms.Seek(0, SeekOrigin.Begin); UInt32 headerLength = StreamUtils.ReadUInt32(ms) + 4; if (headerLength > ms.Length) { currentHeaderLengthToSkip = headerLength - ms.Length; addLine("header fragment start, continue on next fragment..."); } else { ms.Seek(headerLength, SeekOrigin.Begin); parseCompressedFragmentFiles(rootFolder, fi, ms); } } else if (test1 == 1 && test2 == 1 && test4 == 0x10202be9) { addLine("phone settings fragment type\r\n"); return; } else if (test1 == 0 && (test2 & 0xFFF00F) == 4) // test2 == 0x0224 || 0x24 || 0x0464 || 0x0444 || 0x0434 { addLine("ignored fragment type\r\n"); return; } else { addLine(string.Format("{0} - unknown fragment type\r\n", fi.Filename)); } } long uncompressedCoverage = StreamUtils.Counter - initCounter; if (uncompressedCoverage > 0) { double ratio = (double)uncompressedCoverage / ms.Length; StreamUtils.Counter = initCounter + (long)(fi.RawSize * ratio); addLine(string.Format("fragment coverage {0:0.##}%", 100 * ratio)); } addLine(""); }