Beispiel #1
0
        public static void Compile(Stream[] streams, Stream output, uint pageSize)
        {
            // ðàñ÷èòûâàåì ðàçìåðû
            uint streamsNumPages = 0;
            uint numStreams = Int2UInt(streams.Length);
            uint[] lengths = new uint[numStreams];
            for (int i = 0; i < numStreams; i++)
            {
                lengths[i] = Long2UInt(streams[i].Length) - Long2UInt(streams[i].Position);
                streamsNumPages += NumPages(lengths[i], pageSize);
            }
            uint rootStmSize = 0;
            uint rootStmNumPages = 0;
            while (true)
            {
                uint wasRootStmSize = rootStmSize;
                rootStmNumPages = NumPages(rootStmSize, pageSize);
                rootStmSize = 4 + 4 * (numStreams + 1) + 4 * (streamsNumPages + rootStmNumPages);
                if (wasRootStmSize == rootStmSize)
                    break;
            }
            uint rootStmIndexSize = rootStmNumPages * 4;
            uint rootStmIndexNumPages = NumPages(rootStmIndexSize, pageSize);
            uint filePages = 0;
            uint bitmapNumPages = 0;
            uint bitmapSizeBits = 0;
            while (true)
            {
                uint wasBitmapSizeBits = bitmapSizeBits;
                bitmapNumPages = NumPages(bitmapSizeBits, pageSize * 8);
                filePages = 1 + rootStmNumPages + streamsNumPages +
                    rootStmIndexNumPages + bitmapNumPages;
                bitmapSizeBits = filePages;
                if (wasBitmapSizeBits == bitmapSizeBits)
                    break;
            }
            uint startPage = 1 + bitmapNumPages;

            byte[] pad = new byte[pageSize - 1];
            byte[] onespad = new byte[pageSize - 1];
            for (int i = 0; i < onespad.Length; i++)
                onespad[i] = 0xff;
            byte[] buffer;
            // ïèøåì çàãîëîâîê
            const string SIGNATURE = "Microsoft C/C++ MSF 7.00\r\n\x001ADS\0\0\0";
            byte[] signature = Encoding.ASCII.GetBytes(SIGNATURE);
            output.Write(signature, 0, signature.Length);
            Header hdr = new Header();
            hdr.PageSize = pageSize;
            hdr.StartPage = startPage;
            hdr.FilePages = filePages;
            hdr.RootStreamSize = rootStmSize;
            hdr.RootPageIndex = filePages - rootStmIndexNumPages;
            buffer = GetBytes(hdr);
            output.Write(buffer, 0, buffer.Length);
            output.Write(pad, 0, PageRemains(Int2UInt(signature.Length +
                Marshal.SizeOf(typeof(Header))), pageSize));

            // ïèøåì áèòìàï
            byte[] bitmap = new byte[NumPages(bitmapSizeBits, 8)];
            byte lastByte = 0xff;
            byte bit = 1;
            uint lastByteBits = bitmapSizeBits - bitmapSizeBits / 8 * 8;
            for (uint i = 0; i < lastByteBits; i++)
            {
                lastByte &= (byte)~bit;
                bit <<= 1;
            }
            bitmap[bitmap.Length - 1] = lastByte;
            output.Write(bitmap, 0, bitmap.Length);
            output.Write(onespad, 0, PageRemains(NumPages(bitmapSizeBits, 8), pageSize));

            // çàïèñûâàåì êîðíåâîé ñòðèì (îãëàâëåíèå)
            buffer = BitConverter.GetBytes(numStreams + 1);
            output.Write(buffer, 0, buffer.Length);
            // ïèøåì ðàçìåð êîðíåâîãî (0-ãî) ñòðèìà
            buffer = BitConverter.GetBytes(rootStmSize);
            output.Write(buffer, 0, buffer.Length);
            // ïèøåì ðàçìåðû îñòàëüíûõ ñòðèìîâ
            foreach (uint len in lengths)
            {
                buffer = BitConverter.GetBytes(len);
                output.Write(buffer, 0, buffer.Length);
            }
            // ïèøåì èíäåêñû ñòðàíèö êîðíåâîãî ñòðèìà
            uint rootStmStartPage = startPage;
            uint pageIndex = rootStmStartPage;
            for (uint i = 0; i < rootStmNumPages; i++)
            {
                buffer = BitConverter.GetBytes(pageIndex);
                output.Write(buffer, 0, buffer.Length);
                pageIndex++;
            }
            // ïèøåì èíäåêñû ñòðàíèö îñòàëüíûõ ñòðèìîâ
            for (uint s = 0; s < numStreams; s++)
            {
                for (uint i = 0; i < NumPages(lengths[s], pageSize); i++)
                {
                    buffer = BitConverter.GetBytes(pageIndex);
                    output.Write(buffer, 0, buffer.Length);
                    pageIndex++;
                }
            }
            output.Write(pad, 0, PageRemains(rootStmSize, pageSize));

            // çàïèñûâàåì ñòðèìû
            for (uint i = 0; i < numStreams; i++)
            {
                if (lengths[i] == 0)
                    continue;
                PumpStreams(streams[i], output);
                output.Write(pad, 0, PageRemains(lengths[i], pageSize));
            }

            // çàïèñûâàåì èíäåêñ îãëàâëåíèÿ
            Debug.Assert(pageIndex == hdr.RootPageIndex);
            pageIndex = rootStmStartPage;
            for (uint i = 0; i < rootStmNumPages; i++)
            {
                buffer = BitConverter.GetBytes(pageIndex);
                output.Write(buffer, 0, buffer.Length);
                pageIndex++;
            }
            output.Write(pad, 0, PageRemains(rootStmIndexSize, pageSize));
        }