bool ReadEcfFromStream()
        {
            bool result = true;

            result = EcfHeader.VerifyIsEcf(mEcfStream.Reader);
            if (!result)
            {
                if (VerboseOutput != null)
                {
                    VerboseOutput.WriteLine("\tFailed: File is either not even an ECF-based file, or corrupt");
                }
            }
            else
            {
                mEcfFile = new EcfFile();
                mEcfFile.Serialize(mEcfStream);
            }

            return(result);
        }
        bool BuildInternal(string workPath, string outputPath)
        {
            EcfDefinition.WorkingDirectory = workPath;

            string ecf_name = EcfDefinition.EcfName;

            if (ecf_name.IsNotNullOrEmpty())
            {
                ecf_name = Path.GetFileNameWithoutExtension(mSourceFile);
            }

            string ecf_filename = Path.Combine(outputPath, ecf_name);

                        #if false // I'm no longer doing this since we don't strip the file ext off listing when expanding
            // #TODO I bet a user could forget to include the preceding dot
            if (EcfDefinition.EcfFileExtension.IsNotNullOrEmpty())
            {
                ecf_filename += EcfDefinition.EcfFileExtension;
            }
                        #endif

            if (File.Exists(ecf_filename))
            {
                var attrs = File.GetAttributes(ecf_filename);
                if (attrs.HasFlag(FileAttributes.ReadOnly))
                {
                    throw new IOException("ECF file is readonly, can't build: " + ecf_filename);
                }
            }

            mEcfFile = new EcfFile();
            mEcfFile.SetupHeaderAndChunks(EcfDefinition);

            const FA  k_mode = FA.Write;
            const int k_initial_buffer_size = 8 * IntegerMath.kMega;             // 8MB

            if (ProgressOutput != null)
            {
                ProgressOutput.WriteLine("Building {0} to {1}...", ecf_name, outputPath);
            }

            if (ProgressOutput != null)
            {
                ProgressOutput.WriteLine("\tAllocating memory...");
            }
            bool result = true;
            using (var ms = new MemoryStream(k_initial_buffer_size))
                using (var ecf_memory = new IO.EndianStream(ms, Shell.EndianFormat.Big, this, permissions: k_mode))
                {
                    ecf_memory.StreamMode = k_mode;
                    ecf_memory.VirtualAddressTranslationInitialize(Shell.ProcessorSize.x32);

                    long preamble_size = mEcfFile.CalculateHeaderAndChunkEntriesSize();
                    ms.SetLength(preamble_size);
                    ms.Seek(preamble_size, SeekOrigin.Begin);

                    // now we can start embedding the files
                    if (ProgressOutput != null)
                    {
                        ProgressOutput.WriteLine("\tPacking chunks...");
                    }

                    result = result && PackChunks(ecf_memory);

                    if (result)
                    {
                        if (ProgressOutput != null)
                        {
                            ProgressOutput.WriteLine("\tFinializing...");
                        }

                        // seek back to the start of the ECF and write out the finalized header and chunk descriptors
                        ms.Seek(0, SeekOrigin.Begin);
                        mEcfFile.Serialize(ecf_memory);

                        Contract.Assert(ecf_memory.BaseStream.Position == preamble_size,
                                        "Written ECF header size is NOT EQUAL what we calculated");

                        // Update sizes and checksums
                        ms.Seek(0, SeekOrigin.Begin);
                        mEcfFile.SerializeBegin(ecf_memory, isFinalizing: true);
                        mEcfFile.SerializeEnd(ecf_memory);

                        // finally, bake the ECF memory stream into a file

                        using (var fs = new FileStream(ecf_filename, FileMode.Create, FA.Write))
                            ms.WriteTo(fs);
                    }
                }

            return(result);
        }