コード例 #1
0
        protected void ReadFile()
        {
            try
            {
                if (_disposed)
                {
                    throw new ObjectDisposedException("RegionFile", "Attempting to use a RegionFile after it has been disposed.");
                }

                /*// Get last udpate time
                 * long newModified = -1;
                 * try
                 * {
                 *  if (File.Exists(fileName))
                 *  {
                 *      newModified = Timestamp(File.GetLastWriteTime(fileName));
                 *  }
                 * }
                 * catch (UnauthorizedAccessException e)
                 * {
                 *  Console.WriteLine(e.Message);
                 *  return;
                 * }
                 *
                 * // If it hasn't been modified, we don't need to do anything
                 * if (newModified == lastModified)
                 * {
                 *  return;
                 * }*/

                try
                {
                    lock (this.fileLock)
                    {
                        file = new FileStream(fileName, FileMode.OpenOrCreate, FileAccess.Read /*Write*/, FileShare.ReadWrite);

                        /*//using (file) {
                         * if (file.Length < SectorBytes)
                         * {
                         *  byte[] int0 = BitConverter.GetBytes((int)0);
                         *
                         *  // we need to write the chunk offset table
                         *  for (int i = 0; i < SectorInts; ++i)
                         *  {
                         *      file.Write(int0, 0, 4);
                         *  }
                         *  // write another sector for the timestamp info
                         *  for (int i = 0; i < SectorInts; ++i)
                         *  {
                         *      file.Write(int0, 0, 4);
                         *  }
                         *
                         *  file.Flush();
                         *
                         *  sizeDelta += SectorBytes * 2;
                         * }
                         *
                         * if ((file.Length & 0xfff) != 0)
                         * {
                         *  // the file size is not a multiple of 4KB, grow it
                         *  file.Seek(0, SeekOrigin.End);
                         *  for (int i = 0; i < (file.Length & 0xfff); ++i)
                         *  {
                         *      file.WriteByte(0);
                         *  }
                         *
                         *  file.Flush();
                         * }*/

                        // set up the available sector map
                        int nSectors = (int)file.Length / SectorBytes;
                        sectorFree = new List <Boolean>(nSectors);

                        for (int i = 0; i < nSectors; ++i)
                        {
                            sectorFree.Add(true);
                        }

                        sectorFree[0] = false; // chunk offset table
                        sectorFree[1] = false; // for the last modified info

                        file.Seek(0, SeekOrigin.Begin);
                        for (int i = 0; i < SectorInts; ++i)
                        {
                            byte[] offsetBytes = new byte[4];
                            file.Read(offsetBytes, 0, 4);

                            if (BitConverter.IsLittleEndian)
                            {
                                Array.Reverse(offsetBytes);
                            }
                            int offset = BitConverter.ToInt32(offsetBytes, 0);

                            offsets[i] = offset;
                            if (offset != 0 && (offset >> 8) + (offset & 0xFF) <= sectorFree.Count)
                            {
                                for (int sectorNum = 0; sectorNum < (offset & 0xFF); ++sectorNum)
                                {
                                    sectorFree[(offset >> 8) + sectorNum] = false;
                                }
                            }
                        }
                        for (int i = 0; i < SectorInts; ++i)
                        {
                            byte[] modBytes = new byte[4];
                            file.Read(modBytes, 0, 4);

                            if (BitConverter.IsLittleEndian)
                            {
                                Array.Reverse(modBytes);
                            }
                            int lastModValue = BitConverter.ToInt32(modBytes, 0);

                            chunkTimestamps[i] = lastModValue;
                        }
                    }
                }
                catch (IOException Excepción)
                {
                    Depurador.Escribir_Excepción(Excepción != null ? Excepción.ToString() : null);
                    //System.Console.WriteLine(Excepción.Message);
                    //System.Console.WriteLine(Excepción.StackTrace);
                }
            }
            catch (Exception Excepción) { Depurador.Escribir_Excepción(Excepción != null ? Excepción.ToString() : null); }
        }
コード例 #2
0
        /**
         * @param inputFile The XWB file to extract
         * @param outputDirectory The directory to put the extracted files inside
         * @param statusReporter The status reporter to use for reporting which tracks that are currently extracted.
         *
         * @throws XnbException If the XWB file was malformed
         * @throws IOException If an I/O error occurs
         */
        public static bool Extract(string inputFile, string outputDirectory)
        {
            try
            {
                //Status("Parsing XWB file header");
                //Percentage(0f);

                //ByteBuffer buffer = ByteBuffer.wrap(FileUtils.readFileToByteArray(inputFile));
                //buffer.order(ByteOrder.LITTLE_ENDIAN);
                BinaryReader reader = new BinaryReader(new FileStream(inputFile, FileMode.Open));

                int Format           = 0;
                int PlayRegionLength = 0;
                int PlayRegionOffset = 0;

                int wavebank_offset = 0;

                if (!CompareBytesToString(reader.ReadBytes(4), "WBND"))
                {
                    throw new XwbException("not an XWB file: " + Path.GetFileName(inputFile));
                }

                int Version = reader.ReadInt32();

                // Skip trailing bytes of the version
                reader.ReadInt32();

                if (Version != 46)
                {
                    throw new XwbException("unsupported version: " + Version);
                }

                int[] segmentOffsets = new int[5];
                int[] segmentLengths = new int[5];

                for (int i = 0; i < 5; i++)
                {
                    segmentOffsets[i] = reader.ReadInt32();
                    segmentLengths[i] = reader.ReadInt32();
                }

                reader.BaseStream.Position = segmentOffsets[0];

                int Flags      = reader.ReadInt32();
                int EntryCount = reader.ReadInt32();

                // Skip terraria's wave bank's name. "Wave Bank".
                reader.BaseStream.Position += 64;

                int EntryMetaDataElementSize = reader.ReadInt32();
                reader.ReadInt32(); // EntryNameElementSize
                reader.ReadInt32(); // Alignment
                wavebank_offset = segmentOffsets[1];

                if ((Flags & Flag_Compact) != 0)
                {
                    throw new XwbException("compact wavebanks are not supported");
                }

                int playregion_offset = segmentOffsets[4];
                for (int current_entry = 0; current_entry < EntryCount; current_entry++)
                {
                    String track = current_entry < TrackNames.Length ? TrackNames[current_entry] : (current_entry + 1) + " Unknown";

                    //Status("Extracting " + track);
                    //Percentage(0.1f + (0.9f / EntryCount) * current_entry);

                    reader.BaseStream.Position = wavebank_offset;
                    if (EntryMetaDataElementSize >= 4)
                    {
                        reader.ReadInt32(); // FlagsAndDuration
                    }
                    if (EntryMetaDataElementSize >= 8)
                    {
                        Format = reader.ReadInt32();
                    }
                    if (EntryMetaDataElementSize >= 12)
                    {
                        PlayRegionOffset = reader.ReadInt32();
                    }
                    if (EntryMetaDataElementSize >= 16)
                    {
                        PlayRegionLength = reader.ReadInt32();
                    }
                    if (EntryMetaDataElementSize >= 20)
                    {
                        reader.ReadInt32(); // LoopRegionOffset
                    }
                    if (EntryMetaDataElementSize >= 24)
                    {
                        reader.ReadInt32(); // LoopRegionLength
                    }
                    wavebank_offset  += EntryMetaDataElementSize;
                    PlayRegionOffset += playregion_offset;

                    int codec = (Format) & ((1 << 2) - 1);
                    int chans = (Format >> (2)) & ((1 << 3) - 1);
                    int rate  = (Format >> (2 + 3)) & ((1 << 18) - 1);
                    int align = (Format >> (2 + 3 + 18)) & ((1 << 8) - 1);

                    reader.BaseStream.Position = PlayRegionOffset;
                    byte[] audiodata = reader.ReadBytes(PlayRegionLength);

                    // The codecs used by Terraria are currently xWMA and ADPCM.
                    // The xWMA format is not supported by FNA, so it's only used
                    // on Windows. This implementation uses ffmpeg to convert the raw
                    // xWMA data to WAVE; a minified Windows executable is embedded.
                    // PCM was introduced for the last tracks in the 1.3.3 update.
                    string path = Path.Combine(outputDirectory, track + ".wav");
                    if (codec == MiniFormatTag_PCM)
                    {
                        Depurador.Escribir_Excepción("MiniFormatTag_PCM");
                        FileStream   stream = new FileStream(path, FileMode.OpenOrCreate);
                        BinaryWriter writer = new BinaryWriter(stream);
                        stream.SetLength(0);
                        writer.Write(Label_RIFF);            // chunk id
                        writer.Write(audiodata.Length + 36); // chunk size
                        writer.Write(Label_WAVE);            // RIFF type
                        writer.Write(Label_fmt);             // chunk id
                        writer.Write((int)16);               // format header size
                        writer.Write((short)1);              // format (PCM)
                        writer.Write((short)chans);          // channels
                        writer.Write(rate);                  // samples per second
                        int bitsPerSample = 16;
                        int blockAlign    = (bitsPerSample / 8) * chans;
                        writer.Write(rate * blockAlign); // byte rate/ average bytes per second
                        writer.Write((short)blockAlign);
                        writer.Write((short)bitsPerSample);
                        writer.Write(Label_data);       // chunk id
                        writer.Write(audiodata.Length); // data size


                        writer.Write(audiodata);
                        writer.Close();
                    }
                    else if (codec == MiniFormatTag_WMA)
                    {
                        Depurador.Escribir_Excepción("MiniFormatTag_WMA");
                        // Note that it could still be another codec than xWma,
                        // but that scenario isn't handled here.

                        // This part has been ported from XWMA-to-pcm-u8
                        // Not the most beautiful code in the world,
                        // but it does the job.

                        // I do not know if this code outputs valid XWMA files,
                        // but FFMPEG accepts them so it's all right for this usage.

                        //File xWmaFile = new File(outputDirectory, track + ".wma");

                        //FileOutputStream xWmaOutput = FileUtils.openOutputStream(xWmaFile);
                        // xWmaOutput.write(output.array(), output.arrayOffset(), output.position());
                        string       wmaPath = Path.Combine(outputDirectory, track + ".wma");
                        BinaryWriter writer  = new BinaryWriter(new FileStream(wmaPath, FileMode.OpenOrCreate));

                        //BufferWriter output = new BufferWriter(xWmaOutput);
                        //output.setOrder(ByteOrder.LITTLE_ENDIAN);
                        writer.Write(Label_RIFF);   // chunk id
                        writer.Write(0);            // Full file size, ignored by ffmpeg
                        writer.Write(Label_XWMA);   // RIFF type
                        writer.Write(Label_fmt);    // chunk id
                        writer.Write((int)18);      // format header size
                        writer.Write((short)0x161); // format (PCM)
                        writer.Write((short)chans); // channels
                        writer.Write(rate);         // samples per second


                        int[] wmaAverageBytesPerSec = new int[]
                        {
                            12000,
                            24000,
                            4000,
                            6000,
                            8000,
                            20000
                        };
                        int[] wmaBlockAlign = new int[]
                        {
                            929,
                            1487,
                            1280,
                            2230,
                            8917,
                            8192,
                            4459,
                            5945,
                            2304,
                            1536,
                            1485,
                            1008,
                            2731,
                            4096,
                            6827,
                            5462
                        };

                        int averageBytesPerSec = align > wmaAverageBytesPerSec.Length ? wmaAverageBytesPerSec[align >> 5] : wmaAverageBytesPerSec[align];

                        int blockAlign = align > wmaBlockAlign.Length ? wmaBlockAlign[align & 0xf] : wmaBlockAlign[align];

                        writer.Write(averageBytesPerSec);
                        writer.Write((short)blockAlign);
                        writer.Write((short)16);
                        writer.Write((short)0);
                        writer.Write(Label_dpds);
                        int packetLength = blockAlign;
                        int packetNum    = audiodata.Length / packetLength;
                        writer.Write(packetNum * 4);

                        int fullSize = (PlayRegionLength * averageBytesPerSec % 4096 != 0) ? (1 + (int)(PlayRegionLength
                                                                                                        * averageBytesPerSec / 4096)) * 4096
                                : PlayRegionLength;
                        int allBlocks          = fullSize / 4096;
                        int avgBlocksPerPacket = allBlocks / packetNum;
                        int spareBlocks        = allBlocks - (avgBlocksPerPacket * packetNum);

                        int accu = 0;
                        for (int i = 0; i < packetNum; ++i)
                        {
                            accu += avgBlocksPerPacket * 4096;
                            if (spareBlocks != 0)
                            {
                                accu += 4096;
                                --spareBlocks;
                            }
                            writer.Write(accu);
                        }

                        writer.Write(Label_data);

                        writer.Write(PlayRegionLength);
                        writer.Write(audiodata);
                        // Replacing the file size placeholder, doesn't matter with ffmpeg
                        // int pos = output.position();
                        // output.position(odRIChunkSize);
                        // output.putInt(pos - 8);
                        // output.position(pos);
                        writer.Close();

                        FFmpeg.Convert(wmaPath, path);

                        File.Delete(wmaPath);
                    }
                    else if (codec == MiniFormatTag_ADPCM)
                    {
                        Depurador.Escribir_Excepción("MiniFormatTag_ADPCM");
                        // Convert ADPCM data to PCM
                        /*audiodata = ADPCMConverter.ConvertToPCM(audiodata, (short)chans, (short)align);*/
                        // Encode PCM as a WAVE file; note that most magic values used
                        // here were obtained via trial and error, so it might break...
                        //ByteBuffer writeBuffer = ByteBuffer.allocate(wavHeaderSize);
                        //writeBuffer.order(ByteOrder.LITTLE_ENDIAN);
                        FileStream   stream = new FileStream(path, FileMode.OpenOrCreate);
                        BinaryWriter writer = new BinaryWriter(stream);
                        stream.SetLength(0);

                        /*writer.Write(Label_RIFF);
                         * writer.Write(audiodata.Length + 36);
                         * writer.Write(Label_WAVE);
                         * writer.Write(Label_fmt);
                         * writer.Write((int)16);
                         * writer.Write((short)1); // format code
                         * writer.Write((short)chans); // channels
                         * writer.Write(rate); // blocks per second
                         * writer.Write(rate * 4); // bytes per second
                         * writer.Write((short)4); // data block alignment
                         * writer.Write((short)16); // bits per sample
                         * writer.Write(Label_data);
                         * writer.Write(audiodata.Length); // dataChunkSize
                         */
                        writer.Write(audiodata);
                        writer.Close();
                    }
                    else
                    {
                        Depurador.Escribir_Excepción("unimplemented");
                        throw new XwbException("unimplemented codec " + codec);
                    }
                }
                reader.Close();
                return(true);
            }
            catch (Exception Excepción) { Depurador.Escribir_Excepción(Excepción != null ? Excepción.ToString() : null); }
            return(false);
        }
コード例 #3
0
        /*
         * gets an (uncompressed) stream representing the chunk data returns null if
         * the chunk is not found or an error occurs
         */
        public Stream GetChunkDataInputStream(int x, int z, out string Compresión)
        {
            Compresión = null;
            if (_disposed)
            {
                throw new ObjectDisposedException("RegionFile", "Attempting to use a RegionFile after it has been disposed.");
            }

            if (OutOfBounds(x, z))
            {
                Debugln("READ", x, z, "out of bounds");
                return(null);
            }

            try
            {
                int offset = GetOffset(x, z);
                if (offset == 0)
                {
                    // Debugln("READ", x, z, "miss");
                    return(null);
                }

                int sectorNumber = offset >> 8;
                int numSectors   = offset & 0xFF;

                lock (this.fileLock)
                {
                    if (sectorNumber + numSectors > sectorFree.Count)
                    {
                        Debugln("READ", x, z, "invalid sector");
                        return(null);
                    }

                    file.Seek(sectorNumber * SectorBytes, SeekOrigin.Begin);
                    byte[] lengthBytes = new byte[4];
                    file.Read(lengthBytes, 0, 4);

                    if (BitConverter.IsLittleEndian)
                    {
                        Array.Reverse(lengthBytes);
                    }
                    int length = BitConverter.ToInt32(lengthBytes, 0);

                    if (length > SectorBytes * numSectors)
                    {
                        Debugln("READ", x, z, "invalid length: " + length + " > 4096 * " + numSectors);
                        return(null);
                    }

                    byte version = (byte)file.ReadByte();
                    if (version == VERSION_GZIP)
                    {
                        byte[] data = new byte[length - 1];
                        file.Read(data, 0, data.Length);
                        Stream ret = new GZipStream(new MemoryStream(data), CompressionMode.Decompress);
                        Compresión = "[GZipStream] ";
                        return(ret);
                    }
                    else if (version == VERSION_DEFLATE)
                    {
                        byte[] data = new byte[length - 1];
                        file.Read(data, 0, data.Length);
                        Stream ret = new ZlibStream(new MemoryStream(data), CompressionMode.Decompress, true);
                        Compresión = "[ZlibStream] ";
                        return(ret);

                        /*MemoryStream sinkZ = new MemoryStream();
                         * ZlibStream zOut = new ZlibStream(sinkZ, CompressionMode.Decompress, true);
                         * zOut.Write(data, 0, data.Length);
                         * zOut.Flush();
                         * zOut.Close();
                         *
                         * sinkZ.Seek(0, SeekOrigin.Begin);
                         * return sinkZ;*/
                    }

                    Debugln("READ", x, z, "unknown version " + version);
                    return(null);
                }
            }
            catch (IOException Excepción)
            {
                Depurador.Escribir_Excepción(Excepción != null ? Excepción.ToString() : null);
                //Debugln("READ", x, z, "exception");
                return(null);
            }
        }