Seek() public method

public Seek ( long dest, SeekOrigin, origin ) : long
dest long
origin SeekOrigin,
return long
        public void Seek_Result(long offset, SeekOrigin origin, long expectedPosition)
        {
            MemoryStream stream = new MemoryStream(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 });

            SubStream subStream = new SubStream(stream, 5);
            long      result    = subStream.Seek(offset, origin);

            Assert.Equal(expectedPosition, result);
        }
Beispiel #2
0
        public void Seek_FromCurrent()
        {
            // Verify that we can seek via the [Seek/current] method.

            using (var parent = new MemoryStream())
            {
                parent.Write(new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 });

                using (var substream = new SubStream(parent, 0, 10))
                {
                    for (int i = 0; i < 5; i++)
                    {
                        substream.Position = 5;
                        Assert.Equal(i + 5, substream.Seek(i, SeekOrigin.Current));
                        Assert.Equal(i + 5, substream.ReadByte());
                    }
                }
            }

            // Verify that we can't seek before the beginning of the substream.

            using (var parent = new MemoryStream())
            {
                parent.Write(new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 });

                using (var substream = new SubStream(parent, 5, 5))
                {
                    Assert.Throws <IOException>(
                        () =>
                    {
                        substream.Position = 0;
                        substream.Seek(-1, SeekOrigin.Current);
                    });
                }
            }

            // Verify that we can't seek past the end of the substream.

            using (var parent = new MemoryStream())
            {
                parent.Write(new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 });

                using (var substream = new SubStream(parent, 5, 5))
                {
                    Assert.Throws <IOException>(
                        () =>
                    {
                        substream.Seek(6, SeekOrigin.Current);
                    });
                }
            }
        }
Beispiel #3
0
        public void Seek_FromEnd()
        {
            // Verify that we can seek via the [Seek/end] method.

            using (var parent = new MemoryStream())
            {
                parent.Write(new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 });

                using (var substream = new SubStream(parent, 0, 10))
                {
                    for (int i = 0; i < 10; i++)
                    {
                        Assert.Equal(9 - i, substream.Seek(-(i + 1), SeekOrigin.End));
                        Assert.Equal(9 - i, substream.ReadByte());
                    }
                }
            }

            // Verify that we can't seek before the beginning of the substream.

            using (var parent = new MemoryStream())
            {
                parent.Write(new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 });

                using (var substream = new SubStream(parent, 5, 5))
                {
                    Assert.Throws <IOException>(
                        () =>
                    {
                        substream.Seek(-6, SeekOrigin.End);
                    });
                }
            }

            // Verify that we can't seek past the end of the substream.

            using (var parent = new MemoryStream())
            {
                parent.Write(new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 });

                using (var substream = new SubStream(parent, 5, 5))
                {
                    Assert.Throws <IOException>(
                        () =>
                    {
                        substream.Seek(1, SeekOrigin.End);
                    });
                }
            }
        }
Beispiel #4
0
        public void SeekTest()
        {
            var encoded = Helpers.GetExampleBytes("31 0D 05 00 06 09 2A 86 48 86 F7 0D 01 01 0B");

            using (var ms = new MemoryStream(encoded))
            {
                ms.Seek(3, SeekOrigin.Begin);

                var sub1 = new SubStream(ms, 3);

                // ORIGIN BEGIN
                // zero offset
                sub1.Seek(0, SeekOrigin.Begin);
                Assert.True(sub1.Position == 0);

                // positive offset
                sub1.Seek(1, SeekOrigin.Begin);
                Assert.True(sub1.Position == 1);

                // ORIGIN END
                // negative offset
                sub1.Seek(-1, SeekOrigin.End);
                Assert.True(sub1.Position == sub1.Length - 1);

                // zero offset
                sub1.Seek(0, SeekOrigin.End);
                Assert.True(sub1.Position == sub1.Length);

                // positive offset
                sub1.Seek(1, SeekOrigin.End);
                Assert.True(sub1.Position > sub1.Length);

                // ORIGIN CURRENT
                // negative offset
                sub1.Seek(-2, SeekOrigin.Current);
                Assert.True(sub1.Position < sub1.Length);

                // zero offset
                var lastPosition = sub1.Position;
                sub1.Seek(0, SeekOrigin.Current);
                Assert.True(sub1.Position == lastPosition);

                // positive offset
                sub1.Seek(sub1.Length * 3, SeekOrigin.Current);
                Assert.True(sub1.Position > sub1.Length);
            }
        }
Beispiel #5
0
        public void MustSeekCorrectly()
        {
            var sut = new SubStream(stream.Object, 100, 200);

            sut.Seek(10, SeekOrigin.Begin);
            Assert.AreEqual(10, sut.Position);

            sut.Seek(15, SeekOrigin.Current);
            Assert.AreEqual(25, sut.Position);

            sut.Seek(-5, SeekOrigin.Current);
            Assert.AreEqual(20, sut.Position);

            sut.Seek(-50, SeekOrigin.End);
            Assert.AreEqual(150, sut.Position);

            sut.Seek(10, SeekOrigin.End);
            Assert.AreEqual(210, sut.Position);

            sut.Seek(-10, SeekOrigin.Begin);
            Assert.AreEqual(-10, sut.Position);
        }
Beispiel #6
0
        public async Task <HttpResponseMessage> UploadFileAsync(
            Int64 containerId,
            String itemPath,
            Stream fileStream,
            byte[] contentId,
            Int64 fileLength,
            Boolean isGzipped,
            Guid scopeIdentifier,
            CancellationToken cancellationToken = default(CancellationToken),
            int chunkSize         = c_defaultChunkSize,
            int chunkRetryTimes   = c_defaultChunkRetryTimes,
            bool uploadFirstChunk = false,
            Object userState      = null)
        {
            if (containerId < 1)
            {
                throw new ArgumentException(WebApiResources.ContainerIdMustBeGreaterThanZero(), "containerId");
            }

            if (chunkSize > c_maxChunkSize)
            {
                chunkSize = c_maxChunkSize;
            }

            // if a contentId is specified but the chunk size is not a 2mb multiple error
            if (contentId != null && (chunkSize % c_ContentChunkMultiple) != 0)
            {
                throw new ArgumentException(FileContainerResources.ChunksizeWrongWithContentId(c_ContentChunkMultiple), "chunkSize");
            }

            ArgumentUtility.CheckForNull(fileStream, "fileStream");

            ApiResourceVersion gzipSupportedVersion = new ApiResourceVersion(new Version(1, 0), 2);
            ApiResourceVersion requestVersion       = await NegotiateRequestVersionAsync(FileContainerResourceIds.FileContainer, s_currentApiVersion, userState, cancellationToken).ConfigureAwait(false);

            if (isGzipped &&
                (requestVersion.ApiVersion < gzipSupportedVersion.ApiVersion ||
                 (requestVersion.ApiVersion == gzipSupportedVersion.ApiVersion && requestVersion.ResourceVersion < gzipSupportedVersion.ResourceVersion)))
            {
                throw new ArgumentException(FileContainerResources.GzipNotSupportedOnServer(), "isGzipped");
            }

            if (isGzipped && fileStream.Length >= fileLength)
            {
                throw new ArgumentException(FileContainerResources.BadCompression(), "fileLength");
            }

            HttpRequestMessage requestMessage           = null;
            List <KeyValuePair <String, String> > query = AppendItemQueryString(itemPath, scopeIdentifier);

            if (fileStream.Length == 0)
            {
                // zero byte upload
                FileUploadTrace(itemPath, $"Upload zero byte file '{itemPath}'.");
                requestMessage = await CreateRequestMessageAsync(HttpMethod.Put, FileContainerResourceIds.FileContainer, routeValues : new { containerId = containerId }, version : s_currentApiVersion, queryParameters : query, userState : userState, cancellationToken : cancellationToken).ConfigureAwait(false);

                return(await SendAsync(requestMessage, userState, cancellationToken).ConfigureAwait(false));
            }

            bool multiChunk  = false;
            int  totalChunks = 1;

            if (fileStream.Length > chunkSize)
            {
                totalChunks = (int)Math.Ceiling(fileStream.Length / (double)chunkSize);
                FileUploadTrace(itemPath, $"Begin chunking upload file '{itemPath}', chunk size '{chunkSize} Bytes', total chunks '{totalChunks}'.");
                multiChunk = true;
            }
            else
            {
                FileUploadTrace(itemPath, $"File '{itemPath}' will be uploaded in one chunk.");
                chunkSize = (int)fileStream.Length;
            }

            StreamParser        streamParser  = new StreamParser(fileStream, chunkSize);
            SubStream           currentStream = streamParser.GetNextStream();
            HttpResponseMessage response      = null;

            Byte[]    dataToSend   = new Byte[chunkSize];
            int       currentChunk = 0;
            Stopwatch uploadTimer  = new Stopwatch();

            while (currentStream.Length > 0 && !cancellationToken.IsCancellationRequested)
            {
                currentChunk++;

                for (int attempt = 1; attempt <= chunkRetryTimes && !cancellationToken.IsCancellationRequested; attempt++)
                {
                    if (attempt > 1)
                    {
                        TimeSpan backoff = BackoffTimerHelper.GetRandomBackoff(TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(10));
                        FileUploadTrace(itemPath, $"Backoff {backoff.TotalSeconds} seconds before attempt '{attempt}' chunk '{currentChunk}' of file '{itemPath}'.");
                        await Task.Delay(backoff, cancellationToken).ConfigureAwait(false);

                        currentStream.Seek(0, SeekOrigin.Begin);
                    }

                    FileUploadTrace(itemPath, $"Attempt '{attempt}' for uploading chunk '{currentChunk}' of file '{itemPath}'.");

                    // inorder for the upload to be retryable, we need the content to be re-readable
                    // to ensure this we copy the chunk into a byte array and send that
                    // chunk size ensures we can convert the length to an int
                    int bytesToCopy = (int)currentStream.Length;
                    using (MemoryStream ms = new MemoryStream(dataToSend))
                    {
                        await currentStream.CopyToAsync(ms, bytesToCopy, cancellationToken).ConfigureAwait(false);
                    }

                    // set the content and the Content-Range header
                    HttpContent byteArrayContent = new ByteArrayContent(dataToSend, 0, bytesToCopy);
                    byteArrayContent.Headers.ContentType   = new System.Net.Http.Headers.MediaTypeHeaderValue("application/octet-stream");
                    byteArrayContent.Headers.ContentLength = currentStream.Length;
                    byteArrayContent.Headers.ContentRange  = new System.Net.Http.Headers.ContentRangeHeaderValue(currentStream.StartingPostionOnOuterStream,
                                                                                                                 currentStream.EndingPostionOnOuterStream,
                                                                                                                 streamParser.Length);
                    FileUploadTrace(itemPath, $"Generate new HttpRequest for uploading file '{itemPath}', chunk '{currentChunk}' of '{totalChunks}'.");

                    try
                    {
                        if (requestMessage != null)
                        {
                            requestMessage.Dispose();
                            requestMessage = null;
                        }

                        requestMessage = await CreateRequestMessageAsync(
                            HttpMethod.Put,
                            FileContainerResourceIds.FileContainer,
                            routeValues : new { containerId = containerId },
                            version : s_currentApiVersion,
                            content : byteArrayContent,
                            queryParameters : query,
                            userState : userState,
                            cancellationToken : cancellationToken).ConfigureAwait(false);
                    }
                    catch (OperationCanceledException) when(cancellationToken.IsCancellationRequested)
                    {
                        // stop re-try on cancellation.
                        throw;
                    }
                    catch (Exception ex) when(attempt < chunkRetryTimes)  // not the last attempt
                    {
                        FileUploadTrace(itemPath, $"Chunk '{currentChunk}' attempt '{attempt}' of file '{itemPath}' fail to create HttpRequest. Error: {ex.ToString()}.");
                        continue;
                    }

                    if (isGzipped)
                    {
                        //add gzip header info
                        byteArrayContent.Headers.ContentEncoding.Add("gzip");
                        byteArrayContent.Headers.Add("x-tfs-filelength", fileLength.ToString(System.Globalization.CultureInfo.InvariantCulture));
                    }

                    if (contentId != null)
                    {
                        byteArrayContent.Headers.Add("x-vso-contentId", Convert.ToBase64String(contentId)); // Base64FormattingOptions.None is default when not supplied
                    }

                    FileUploadTrace(itemPath, $"Start uploading file '{itemPath}' to server, chunk '{currentChunk}'.");
                    uploadTimer.Restart();

                    try
                    {
                        if (response != null)
                        {
                            response.Dispose();
                            response = null;
                        }

                        response = await SendAsync(requestMessage, userState, cancellationToken).ConfigureAwait(false);
                    }
                    catch (OperationCanceledException) when(cancellationToken.IsCancellationRequested)
                    {
                        // stop re-try on cancellation.
                        throw;
                    }
                    catch (Exception ex) when(attempt < chunkRetryTimes)  // not the last attempt
                    {
                        FileUploadTrace(itemPath, $"Chunk '{currentChunk}' attempt '{attempt}' of file '{itemPath}' fail to send request to server. Error: {ex.ToString()}.");
                        continue;
                    }

                    uploadTimer.Stop();
                    FileUploadTrace(itemPath, $"Finished upload chunk '{currentChunk}' of file '{itemPath}', elapsed {uploadTimer.ElapsedMilliseconds} (ms), response code '{response.StatusCode}'.");

                    if (multiChunk)
                    {
                        FileUploadProgress(itemPath, currentChunk, (int)Math.Ceiling(fileStream.Length / (double)chunkSize));
                    }

                    if (response.IsSuccessStatusCode)
                    {
                        break;
                    }
                    else if (IsFastFailResponse(response))
                    {
                        FileUploadTrace(itemPath, $"Chunk '{currentChunk}' attempt '{attempt}' of file '{itemPath}' received non-success status code {response.StatusCode} for sending request and cannot continue.");
                        break;
                    }
                    else
                    {
                        FileUploadTrace(itemPath, $"Chunk '{currentChunk}' attempt '{attempt}' of file '{itemPath}' received non-success status code {response.StatusCode} for sending request.");
                        continue;
                    }
                }

                // if we don't have success then bail and return the failed response
                if (!response.IsSuccessStatusCode)
                {
                    break;
                }

                if (contentId != null && response.StatusCode == HttpStatusCode.Created)
                {
                    // no need to keep uploading since the server said it has all the content
                    FileUploadTrace(itemPath, $"Stop chunking upload the rest of the file '{itemPath}', since server already has all the content.");
                    break;
                }

                currentStream = streamParser.GetNextStream();
                if (uploadFirstChunk)
                {
                    break;
                }
            }

            cancellationToken.ThrowIfCancellationRequested();

            return(response);
        }
Beispiel #7
0
        public void ReadTest()
        {
            var encoded = Helpers.GetExampleBytes("31 0D 05 00 06 09 2A 86 48 86 F7 0D 01 01 0B");

            using (var ms = new MemoryStream(encoded))
            {
                var sub1 = new SubStream(ms, 3);
                ms.Seek(3, SeekOrigin.Begin);

                var sub2 = new SubStream(ms, 5);
                ms.Seek(5, SeekOrigin.Current);

                var sub3 = new SubStream(ms, 4);
                ms.Seek(4, SeekOrigin.Current);

                var sub4 = new SubStream(ms, 3);
                ms.Seek(3, SeekOrigin.End);

                var val1 = new byte[3];
                sub1.Read(val1, 0, 3);

                //ComparisonResult result = compareLogic.Compare(new byte[] { 0x31, 0x0d, 0x05 }, val1);
                //Assert.True(result.AreEqual, result.DifferencesString);
                val1.ShouldBeEquivalentTo(new byte[] { 0x31, 0x0d, 0x05 }, options => options.AllowingInfiniteRecursion());

                var val2 = new byte[5];
                sub2.Read(val2, 0, 5);

                //result = compareLogic.Compare(new byte[] { 0x00, 0x06, 0x09, 0x2A, 0x86 }, val2);
                //Assert.True(result.AreEqual, result.DifferencesString);
                val2.ShouldBeEquivalentTo(new byte[] { 0x00, 0x06, 0x09, 0x2A, 0x86 }, options => options.AllowingInfiniteRecursion());

                var val3 = new byte[4];
                sub3.Read(val3, 0, 4);

                //result = compareLogic.Compare(new byte[] { 0x48, 0x86, 0xF7, 0x0D }, val3);
                //Assert.True(result.AreEqual, result.DifferencesString);
                val3.ShouldBeEquivalentTo(new byte[] { 0x48, 0x86, 0xF7, 0x0D }, options => options.AllowingInfiniteRecursion());


                var val4 = new byte[3];
                sub4.Read(val4, 0, 3);

                //result = compareLogic.Compare(new byte[] { 0x01, 0x01, 0x0B }, val4);
                //Assert.True(result.AreEqual, result.DifferencesString);
                val4.ShouldBeEquivalentTo(new byte[] { 0x01, 0x01, 0x0B }, options => options.AllowingInfiniteRecursion());


                sub1.Seek(0, SeekOrigin.Begin);
                val1 = new byte[3];
                sub1.Read(val1, 0, 3);
                //result = compareLogic.Compare(new byte[] { 0x31, 0x0d, 0x05 }, val1);
                //Assert.True(result.AreEqual, result.DifferencesString);
                val1.ShouldBeEquivalentTo(new byte[] { 0x31, 0x0d, 0x05 }, options => options.AllowingInfiniteRecursion());


                sub1.Seek(-2, SeekOrigin.End);

                val1 = new byte[2];
                sub1.Read(val1, 0, 2);
                //result = compareLogic.Compare(new byte[] { 0x0d, 0x05 }, val1);
                //Assert.True(result.AreEqual, result.DifferencesString);

                val1.ShouldBeEquivalentTo(new byte[] { 0x0d, 0x05 }, options => options.AllowingInfiniteRecursion());
            }
        }
Beispiel #8
0
        static void Main(string[] args)
        {
            if (!File.Exists(AppDomain.CurrentDomain.SetupInformation.ConfigurationFile))
            {
                Settings.Default.Reset();
                Settings.Default.Save();
            }

            if (args.Length < 1)
            {
                Console.WriteLine(Resources.Description);
                Console.ReadLine();
                return;
            }
#if !DEBUG
            try
            {
#endif
            if (args[0].EndsWith(".acb", StringComparison.OrdinalIgnoreCase))
            {
                var extractor = new DataExtractor();
                extractor.ProgressChanged += OnProgressChanged;

                extractor.BufferSize      = Settings.Default.BufferSize;
                extractor.EnableThreading = Settings.Default.EnableThreading;
                extractor.MaxThreads      = Settings.Default.MaxThreads;

                string baseDirectory       = Path.GetDirectoryName(args[0]);
                string outputDirectoryPath = Path.ChangeExtension(args[0], null);
                string extAfs2ArchivePath  = string.Empty;

                Directory.CreateDirectory(outputDirectoryPath);

                using (CriTableReader acbReader = CriTableReader.Create(args[0]))
                {
                    acbReader.Read();

                    CriAfs2Archive afs2Archive    = new CriAfs2Archive();
                    CriAfs2Archive extAfs2Archive = new CriAfs2Archive();

                    CriCpkArchive cpkArchive    = new CriCpkArchive();
                    CriCpkArchive extCpkArchive = null;

                    extAfs2ArchivePath = outputDirectoryPath + ".awb";
                    bool found = File.Exists(extAfs2ArchivePath);

                    if (!found)
                    {
                        extAfs2ArchivePath = outputDirectoryPath + "_streamfiles.awb";
                        found = File.Exists(extAfs2ArchivePath);
                    }

                    if (!found)
                    {
                        extAfs2ArchivePath = outputDirectoryPath + "_STR.awb";
                        found = File.Exists(extAfs2ArchivePath);
                    }

                    bool cpkMode = true;

                    long awbPosition = acbReader.GetPosition("AwbFile");
                    if (acbReader.GetLength("AwbFile") > 0)
                    {
                        using (SubStream afs2Stream = acbReader.GetSubStream("AwbFile"))
                        {
                            cpkMode = !CheckIfAfs2(afs2Stream);

                            if (cpkMode)
                            {
                                cpkArchive.Read(afs2Stream);
                            }

                            else
                            {
                                afs2Archive.Read(afs2Stream);
                            }
                        }
                    }

                    if (acbReader.GetLength("StreamAwbAfs2Header") > 0)
                    {
                        cpkMode = false;

                        using (SubStream extAfs2Stream = acbReader.GetSubStream("StreamAwbAfs2Header"))
                        {
                            bool utfMode = DataStream.ReadCString(extAfs2Stream, 4) == "@UTF";
                            extAfs2Stream.Seek(0, SeekOrigin.Begin);

                            if (utfMode)
                            {
                                using (CriTableReader utfAfs2HeaderReader = CriTableReader.Create(extAfs2Stream))
                                {
                                    utfAfs2HeaderReader.Read();

                                    using (SubStream extAfs2HeaderStream = utfAfs2HeaderReader.GetSubStream("Header"))
                                    {
                                        extAfs2Archive.Read(extAfs2HeaderStream);
                                    }
                                }
                            }

                            else
                            {
                                extAfs2Archive.Read(extAfs2Stream);
                            }
                        }

                        if (!found)
                        {
                            throw new FileNotFoundException("Cannot find the external .AWB file for this .ACB file. Please ensure that the external .AWB file is stored in the directory where the .ACB file is.");
                        }
                    }

                    using (SubStream waveformTableStream = acbReader.GetSubStream("WaveformTable"))
                        using (CriTableReader waveformReader = CriTableReader.Create(waveformTableStream))
                        {
                            while (waveformReader.Read())
                            {
                                byte encodeType = waveformReader.GetByte("EncodeType");
                                bool streaming  = waveformReader.GetBoolean("Streaming");

                                ushort id =
                                    waveformReader.ContainsField("MemoryAwbId") ?
                                    streaming ? waveformReader.GetUInt16("StreamAwbId") : waveformReader.GetUInt16("MemoryAwbId") :
                                    waveformReader.GetUInt16("Id");

                                string outputName = id.ToString("D5");
                                if (streaming)
                                {
                                    outputName += "_streaming";
                                }

                                outputName += GetExtension(encodeType);
                                outputName  = Path.Combine(outputDirectoryPath, outputName);

                                if (streaming)
                                {
                                    if (!found)
                                    {
                                        throw new Exception("Cannot find the external .AWB file for this .ACB file. Please ensure that the external .AWB file is stored in the directory where the .ACB file is.");
                                    }

                                    else if (extCpkArchive == null && cpkMode)
                                    {
                                        extCpkArchive = new CriCpkArchive();
                                        extCpkArchive.Load(extAfs2ArchivePath, Settings.Default.BufferSize);
                                    }

                                    EntryBase afs2Entry = null;

                                    if (cpkMode)
                                    {
                                        afs2Entry = extCpkArchive.GetById(id);
                                    }

                                    else
                                    {
                                        afs2Entry = extAfs2Archive.GetById(id);
                                    }

                                    extractor.Add(extAfs2ArchivePath, outputName, afs2Entry.Position, afs2Entry.Length);
                                }

                                else
                                {
                                    EntryBase afs2Entry = null;

                                    if (cpkMode)
                                    {
                                        afs2Entry = cpkArchive.GetById(id);
                                    }

                                    else
                                    {
                                        afs2Entry = afs2Archive.GetById(id);
                                    }

                                    extractor.Add(args[0], outputName, awbPosition + afs2Entry.Position, afs2Entry.Length);
                                }
                            }
                        }
                }

                extractor.Run();
            }

            else if (File.GetAttributes(args[0]).HasFlag(FileAttributes.Directory))
            {
                string baseDirectory = Path.GetDirectoryName(args[0]);
                string acbPath       = args[0] + ".acb";

                string awbPath = args[0] + "_streamfiles.awb";
                bool   found   = File.Exists(awbPath);

                if (!found)
                {
                    awbPath = args[0] + "_STR.awb";
                    found   = File.Exists(awbPath);
                }

                if (!found)
                {
                    awbPath = args[0] + ".awb";
                }

                if (!File.Exists(acbPath))
                {
                    throw new FileNotFoundException("Cannot find the .ACB file for this directory. Please ensure that the .ACB file is stored in the directory where this directory is.");
                }

                CriTable acbFile = new CriTable();
                acbFile.Load(acbPath, Settings.Default.BufferSize);

                CriAfs2Archive afs2Archive    = new CriAfs2Archive();
                CriAfs2Archive extAfs2Archive = new CriAfs2Archive();

                CriCpkArchive cpkArchive    = new CriCpkArchive();
                CriCpkArchive extCpkArchive = new CriCpkArchive();
                cpkArchive.Mode = extCpkArchive.Mode = CriCpkMode.Id;

                afs2Archive.ProgressChanged    += OnProgressChanged;
                extAfs2Archive.ProgressChanged += OnProgressChanged;
                cpkArchive.ProgressChanged     += OnProgressChanged;
                extCpkArchive.ProgressChanged  += OnProgressChanged;

                bool cpkMode = true;

                byte[] awbFile             = (byte[])acbFile.Rows[0]["AwbFile"];
                byte[] streamAwbAfs2Header = (byte[])acbFile.Rows[0]["StreamAwbAfs2Header"];

                cpkMode = !(awbFile != null && awbFile.Length >= 4 && Encoding.ASCII.GetString(awbFile, 0, 4) == "AFS2") && (streamAwbAfs2Header == null || streamAwbAfs2Header.Length == 0);

                using (CriTableReader reader = CriTableReader.Create((byte[])acbFile.Rows[0]["WaveformTable"]))
                {
                    while (reader.Read())
                    {
                        byte encodeType = reader.GetByte("EncodeType");
                        bool streaming  = reader.GetBoolean("Streaming");

                        ushort id =
                            reader.ContainsField("MemoryAwbId") ?
                            streaming ? reader.GetUInt16("StreamAwbId") : reader.GetUInt16("MemoryAwbId") :
                            reader.GetUInt16("Id");

                        string inputName = id.ToString("D5");
                        if (streaming)
                        {
                            inputName += "_streaming";
                        }

                        inputName += GetExtension(encodeType);
                        inputName  = Path.Combine(args[0], inputName);

                        if (!File.Exists(inputName))
                        {
                            throw new FileNotFoundException($"Cannot find audio file with id {id} for replacement.\nPath attempt: {inputName}");
                        }

                        if (cpkMode)
                        {
                            CriCpkEntry entry = new CriCpkEntry();
                            entry.FilePath = new FileInfo(inputName);
                            entry.Id       = id;

                            if (streaming)
                            {
                                extCpkArchive.Add(entry);
                            }

                            else
                            {
                                cpkArchive.Add(entry);
                            }
                        }

                        else
                        {
                            CriAfs2Entry entry = new CriAfs2Entry();
                            entry.FilePath = new FileInfo(inputName);
                            entry.Id       = id;

                            if (streaming)
                            {
                                extAfs2Archive.Add(entry);
                            }

                            else
                            {
                                afs2Archive.Add(entry);
                            }
                        }
                    }
                }

                acbFile.Rows[0]["AwbFile"]             = null;
                acbFile.Rows[0]["StreamAwbAfs2Header"] = null;

                if (afs2Archive.Count > 0 || cpkArchive.Count > 0)
                {
                    Console.WriteLine("Saving internal AWB...");
                    acbFile.Rows[0]["AwbFile"] = cpkMode ? cpkArchive.Save() : afs2Archive.Save();
                    Console.WriteLine();
                }

                if (extAfs2Archive.Count > 0 || extCpkArchive.Count > 0)
                {
                    Console.WriteLine("Saving external AWB...");
                    if (cpkMode)
                    {
                        extCpkArchive.Save(awbPath, Settings.Default.BufferSize);
                    }

                    else
                    {
                        extAfs2Archive.Save(awbPath, Settings.Default.BufferSize);

                        if (Encoding.UTF8.GetString(streamAwbAfs2Header, 0, 4) == "@UTF")
                        {
                            CriTable headerTable = new CriTable();
                            headerTable.Load(streamAwbAfs2Header);

                            headerTable.Rows[0]["Header"]          = extAfs2Archive.Header;
                            headerTable.WriterSettings             = CriTableWriterSettings.Adx2Settings;
                            acbFile.Rows[0]["StreamAwbAfs2Header"] = headerTable.Save();
                        }

                        else
                        {
                            acbFile.Rows[0]["StreamAwbAfs2Header"] = extAfs2Archive.Header;
                        }
                    }
                }

                acbFile.WriterSettings = CriTableWriterSettings.Adx2Settings;
                acbFile.Save(acbPath, Settings.Default.BufferSize);
            }
#if !DEBUG
        }

        catch (Exception exception)
        {
            MessageBox.Show($"{exception.Message}", "ACB Editor", MessageBoxButtons.OK, MessageBoxIcon.Error);
        }
#endif
        }