Пример #1
0
        public static void WAVFromPCM(Stream input, Stream output, short channels, int samplesPerSec, int bitsPerSample, int samples = 0, IProgressReport writingProgress = null)
        {
            short sample_size = (short)((bitsPerSample / 8) * channels);

            using (BinaryWriter writer = new BinaryWriter(new StreamKeeper(output)))
            {
                writer.Write(new char[] { 'R', 'I', 'F', 'F' });
                writer.Write((int)0); // Skip size of wave file
                writer.Write(new char[] { 'W', 'A', 'V', 'E' });
                writer.Write(new char[] { 'f', 'm', 't', ' ' });
                writer.Write((int)16);  // Size of header
                writer.Write((short)1); // Format tag - PCM
                writer.Write(channels);
                writer.Write(samplesPerSec);
                writer.Write((int)(sample_size * samplesPerSec)); // average bytes per sec
                writer.Write(sample_size);                        // full sample size..
                writer.Write((short)bitsPerSample);
                writer.Write(new char[] { 'd', 'a', 't', 'a' });
                writer.Write((int)0); // Skip size of data
            }
            if (samples != 0)
            {
                if (input.CopyToCount(output, samples * sample_size, writingProgress) != samples * sample_size)
                {
                    // Check output size
                    throw new Exception("Invalid WAV size");
                }
            }
            else
            {
                // Write the pcm
                input.CopyTo(output);

                if (writingProgress != null)
                {
                    writingProgress.SetProgress(writingProgress.GetFullValue());
                }
            }
            output.Seek(4, SeekOrigin.Begin);
            // Write the size
            using (BinaryWriter writer = new BinaryWriter(new StreamKeeper(output)))
            {
                writer.Write((int)(output.Length - 8));
            }
            output.Seek(40, SeekOrigin.Begin);
            // Write the size
            using (BinaryWriter writer = new BinaryWriter(new StreamKeeper(output)))
            {
                writer.Write((int)(output.Length - 44));
            }
        }
Пример #2
0
 public void SetProgress(long value)
 {
     Parent.SetProgress((long)(StartProgress + value * Unit));
 }
Пример #3
0
        /* TODO:
         * private void WriteDataInline(Stream stream, List<Entry> entries, Dictionary<Entry, Structs.RPF7EntryInfoTemplate> entriesInfo, int headersEnd)
         * {
         *  Range<FileEntry> oldFileLayout = new Range<FileEntry>(Math.Max(stream.Length, (long)headersEnd));
         *  List<FileEntry> emptyEntries = new List<FileEntry>();
         *  List<FileEntry> moveEntries = new List<FileEntry>();
         *  List<FileEntry> newEntries = new List<FileEntry>();
         *  // Entries that should be written to temporary files
         *  List<FileEntry> newSavedEntries = new List<FileEntry>();
         *
         *  // A dictionary of the raw data stream that we need to write to the file
         *  Dictionary<FileEntry, Stream> entriesStream = new Dictionary<FileEntry, System.IO.Stream>();
         *
         *  // Add the header
         *  oldFileLayout.AddItem(0, headersEnd, null);
         *
         *  foreach (Entry entry in entries)
         *  {
         *      FileEntry fentry = entry as FileEntry;
         *      if (fentry != null)
         *      {
         *
         *          // We need to find all the files that depends on the origianl stream first
         *          FileStreamCreator originalStream = fentry.TryGetOriginalFileStreamCreator();
         *          if (fentry.Data.GetSize() == 0 && fentry.IsRegularFile() && !((RegularFileEntry)fentry).Compressed)
         *          {
         *              emptyEntries.Add(fentry);
         *          }
         *          else if (originalStream != null && originalStream.FileStream == this.Stream)
         *          {
         *              if (originalStream.Offset < headersEnd) {
         *                  moveEntries.Add(fentry);
         *              }
         *              if (!oldFileLayout.AddItem(originalStream.Offset, originalStream.Size, fentry, false))
         *              {
         *                  // If failed for some reason.. well it can happen if two entries have the same data. Anyway I don't want that two entries will use the same data.
         *                  newSavedEntries.Add(fentry);
         *              }
         *              else
         *              {
         *                  entriesStream[fentry] = new PartialStream(this.Stream, originalStream.Offset, originalStream.Size);
         *              }
         *          }
         *          else if (fentry.Data is FileStreamCreator && ((FileStreamCreator)fentry.Data).FileStream == this.Stream)
         *          {
         *              // This file points to the original file, but something about it changed (compression, encryption, ..)
         *              newSavedEntries.Add(fentry);
         *          }
         *          // From here are entries that are not depends on the original strema
         *          else if ((fentry.IsRegularFile() && ((RegularFileEntry)fentry).Compressed) || fentry.IsResource())
         *          {
         *              newSavedEntries.Add(fentry);
         *          }
         *          else
         *          {
         *              entriesStream[fentry] = fentry.Data.GetStream();
         *              newEntries.Add(fentry);
         *          }
         *      }
         *  }
         *
         *  foreach (FileEntry entry in newSavedEntries)
         *  {
         *      string filepath = Path.GetTempFileName();
         *      // Let's copy the file to temp folder, this file will be deleted on close
         *      FileStream writeStream = new FileStream(filepath, FileMode.Create, FileAccess.Write, FileShare.ReadWrite | FileShare.Delete, 0x1000, FileOptions.DeleteOnClose);
         *
         *      entry.Data.GetStream().CopyTo(writeStream);
         *
         *      // Take an handle to the file, so it will be delete only when this handle will be closed.
         *      FileStream readStream = File.Open(filepath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite | FileShare.Delete);
         *      writeStream.Close();
         *
         *      entriesStream[entry] = writeStream;
         *  }
         *
         *  Range<FileEntry> newFileLayout = new Range<FileEntry>();
         * }
         */

        public void Write(Stream stream, IProgressReport progressReport = null)
        {
            if (progressReport != null)
            {
                progressReport.SetMessage("Preparing...");
                progressReport.SetProgress(-1);
            }
            if (this.Filename == "")
            {
                throw new Exception("Can't save");
            }
            // Get all the entries
            List <Entry> entries = new List <Entry>();

            this.Root.AddToList(entries);


            Dictionary <Entry, Structs.RPF7EntryInfoTemplate> entriesInfo = new Dictionary <Entry, Structs.RPF7EntryInfoTemplate>();

            foreach (Entry entry in entries)
            {
                Structs.RPF7EntryInfoTemplate entryInfo = new Structs.RPF7EntryInfoTemplate();
                // update the is resource field
                entryInfo.Field1   = (entry is ResourceEntry) ? 1U : 0U;
                entriesInfo[entry] = entryInfo;
            }

            int    shiftNameAccessBy;
            Stream names = WriteNames(entries, entriesInfo, out shiftNameAccessBy);

            // Fill the header
            Info.EntriesCount       = entries.Count;
            Info.ShiftNameAccessBy  = shiftNameAccessBy;
            Info.EntriesNamesLength = (int)names.Length;

            // Go to current position
            stream.Seek(0x10 + 0x10 * Info.EntriesCount + Info.EntriesNamesLength, SeekOrigin.Begin);

            // align to 0x200
            if (stream.Position % (1 << 9) != 0)
            {
                stream.Write(new byte[(1 << 9) - ((int)stream.Position % (1 << 9))], 0, (1 << 9) - ((int)stream.Position % (1 << 9)));
            }
            WriteData(stream, entries, entriesInfo, progressReport);

            long end = stream.Position;

            using (Stream writer = AES.EncryptStream(new StreamKeeper(stream), sixteenRoundsDecrypt))
            {
                int currentFreeIndex = 1;
                // Last finish to build and write the file
                stream.Seek(0, SeekOrigin.Begin);
                Info.Write(stream);
                Queue <Entry> entriesToProcess = new Queue <Entry>();
                entriesToProcess.Enqueue(this.Root);
                while (entriesToProcess.Count > 0)
                {
                    Entry entry = entriesToProcess.Dequeue();
                    if (entry is DirectoryEntry)
                    {
                        Structs.RPF7EntryInfoTemplate entryInfo = entriesInfo[entry];
                        IList <Entry> subentries = (entry as DirectoryEntry).GetEntries();
                        // Update the info on the sub entries
                        entryInfo.Field5   = (uint)currentFreeIndex;
                        entryInfo.Field6   = (uint)subentries.Count;
                        entriesInfo[entry] = entryInfo;
                        // Process the sub entries
                        foreach (Entry subentry in subentries)
                        {
                            entriesToProcess.Enqueue(subentry);
                        }
                        currentFreeIndex += subentries.Count;
                    }
                    // Write the entry info
                    entriesInfo[entry].Write(writer);
                }

                // Write names
                names.Seek(0, SeekOrigin.Begin);
                names.CopyTo(writer);
            }

            // Seek to end
            stream.Seek(end, SeekOrigin.Begin);
            // Done!
        }