// Copyright © Microsoft Corporation. // This source file is subject to the Microsoft Permissive License. // See http://www.microsoft.com/resources/sharedsource/licensingbasics/sharedsourcelicenses.mspx. // All other rights reserved. using System; #if CCINamespace using Microsoft.Cci; #else using System.Compiler; #endif using System.Diagnostics; using System.IO; using System.Globalization; using System.Runtime.InteropServices; using System.Text; #if CCINamespace namespace Microsoft.Cci.Metadata{ #else namespace System.Compiler.Metadata { #endif unsafe internal sealed class MemoryCursor { private byte* buffer, pb; readonly internal int Length; #if !ROTOR internal MemoryCursor(MemoryMappedFile/*!*/ memoryMap) : this(memoryMap.Buffer, memoryMap.Length) { } #endif internal MemoryCursor(byte* buffer, int length, int position) { this.buffer = buffer; this.pb = buffer + position; this.Length = length; } internal MemoryCursor(byte* buffer, int length) : this(buffer, length, 0) { } internal MemoryCursor(MemoryCursor/*!*/ c) { this.buffer = c.buffer; this.pb = c.pb; this.Length = c.Length; } internal byte* GetBuffer() { return this.buffer; } internal int Position { get { return (int)(this.pb - this.buffer); } set { this.pb = this.buffer + value; } } internal void Align(int size) { Debug.Assert(size == 2 || size == 4 || size == 8 || size == 16 || size == 32 || size == 64); int remainder = Position & (size - 1); if (remainder != 0) pb += size - remainder; } //internal System.Char Char(int i){ return *(System.Char*)(this.pb+i*sizeof(System.Char)); } //internal System.SByte SByte(int i){ return *(System.SByte*)(this.pb+i*sizeof(System.SByte)); } internal System.Int16 Int16(int i) { return *(System.Int16*)(this.pb + i * sizeof(System.Int16)); } internal System.Int32 Int32(int i) { return *(System.Int32*)(this.pb + i * sizeof(System.Int32)); } //internal System.Int64 Int64(int i){ return *(System.Int64*)(this.pb+i*sizeof(System.Int64)); } internal System.Byte Byte(int i) { return *(System.Byte*)(this.pb + i * sizeof(System.Byte)); } internal System.UInt16 UInt16(int i) { return *(System.UInt16*)(this.pb + i * sizeof(System.UInt16)); } //internal System.UInt32 UInt32(int i){ return *(System.UInt32*)(this.pb+i*sizeof(System.UInt32)); } //internal System.UInt64 UInt64(int i){ return *(System.UInt64*)(this.pb+i*sizeof(System.UInt64)); } //internal System.Boolean Boolean(int i){ return *(System.Boolean*)(this.pb+i*sizeof(System.Boolean)); } //internal System.Single Single(int i){ return *(System.Single*)(this.pb+i*sizeof(System.Single)); } //internal System.Double Double(int i){ return *(System.Double*)(this.pb+i*sizeof(System.Double)); } //internal void SkipChar(int c){ this.pb += c*sizeof(System.Char); } //internal void SkipSByte(int c){ this.pb += c*sizeof(System.SByte); } internal void SkipInt16(int c) { this.pb += c * sizeof(System.Int16); } internal void SkipInt32(int c) { this.pb += c * sizeof(System.Int32); } //internal void SkipInt64(int c){ this.pb += c*sizeof(System.Int64); } internal void SkipByte(int c) { this.pb += c * sizeof(System.Byte); } internal void SkipUInt16(int c) { this.pb += c * sizeof(System.UInt16); } //internal void SkipUInt32(int c){ this.pb += c*sizeof(System.UInt32); } //internal void SkipUInt64(int c){ this.pb += c*sizeof(System.UInt64); } //internal void SkipBoolean(int c){ this.pb += c*sizeof(System.Boolean); } //internal void SkipSingle(int c){ this.pb += c*sizeof(System.Single); } //internal void SkipDouble(int c){ this.pb += c*sizeof(System.Double); } internal System.Char ReadChar() { byte* pb = this.pb; System.Char v = *(System.Char*)pb; this.pb = pb + sizeof(System.Char); return v; } internal System.SByte ReadSByte() { byte* pb = this.pb; System.SByte v = *(System.SByte*)pb; this.pb = pb + sizeof(System.SByte); return v; } internal System.Int16 ReadInt16() { byte* pb = this.pb; System.Int16 v = *(System.Int16*)pb; this.pb = pb + sizeof(System.Int16); return v; } internal System.Int32 ReadInt32() { byte* pb = this.pb; System.Int32 v = *(System.Int32*)pb; this.pb = pb + sizeof(System.Int32); return v; } internal System.Int64 ReadInt64() { byte* pb = this.pb; System.Int64 v = *(System.Int64*)pb; this.pb = pb + sizeof(System.Int64); return v; } internal System.Byte ReadByte() { byte* pb = this.pb; System.Byte v = *(System.Byte*)pb; this.pb = pb + sizeof(System.Byte); return v; } internal System.UInt16 ReadUInt16() { byte* pb = this.pb; System.UInt16 v = *(System.UInt16*)pb; this.pb = pb + sizeof(System.UInt16); return v; } internal System.UInt32 ReadUInt32() { byte* pb = this.pb; System.UInt32 v = *(System.UInt32*)pb; this.pb = pb + sizeof(System.UInt32); return v; } internal System.UInt64 ReadUInt64() { byte* pb = this.pb; System.UInt64 v = *(System.UInt64*)pb; this.pb = pb + sizeof(System.UInt64); return v; } internal System.Boolean ReadBoolean() { byte* pb = this.pb; System.Boolean v = *(System.Boolean*)pb; this.pb = pb + sizeof(System.Boolean); return v; } internal System.Single ReadSingle() { byte* pb = this.pb; System.Single v = *(System.Single*)pb; this.pb = pb + sizeof(System.Single); return v; } internal System.Double ReadDouble() { byte* pb = this.pb; System.Double v = *(System.Double*)pb; this.pb = pb + sizeof(System.Double); return v; } internal System.Int32 ReadReference(int refSize) { if (refSize == 2) return ReadUInt16(); return ReadInt32(); } internal int ReadCompressedInt() { byte headerByte = ReadByte(); int result; if ((headerByte & 0x80) == 0x00) result = headerByte; else if ((headerByte & 0x40) == 0x00) result = ((headerByte & 0x3f) << 8) | ReadByte(); else if (headerByte == 0xFF) result = -1; else result = ((headerByte & 0x3f) << 24) | (ReadByte() << 16) | (ReadByte() << 8) | ReadByte(); return result; } internal byte[]/*!*/ ReadBytes(int c) { byte[] result = new byte[c]; byte* pb = this.pb; for (int i = 0; i < c; i++) result[i] = *pb++; this.pb = pb; return result; } internal unsafe Identifier/*!*/ ReadIdentifierFromSerString() { byte* pb = this.pb; byte headerByte = *pb++; uint length = 0; if ((headerByte & 0x80) == 0x00) length = headerByte; else if ((headerByte & 0x40) == 0x00) length = (uint)((headerByte & 0x3f) << 8) | *pb++; else length = (uint)((headerByte & 0x3f) << 24) | (uint)(*pb++ << 16) | (uint)(*pb++ << 8) | (*pb++); this.pb = pb + length; return Identifier.For(pb, length/*, this.KeepAlive*/); } internal string/*!*/ ReadUTF8(int bytesToRead) { char[] buffer = new char[bytesToRead]; byte* pb = this.pb; this.pb += bytesToRead; int j = 0; while (bytesToRead > 0) { byte b = *pb++; bytesToRead--; if ((b & 0x80) == 0 || bytesToRead == 0) { buffer[j++] = (char)b; continue; } char ch; byte b1 = *pb++; bytesToRead--; if ((b & 0x20) == 0) ch = (char)(((b & 0x1F) << 6) | (b1 & 0x3F)); else { if (bytesToRead == 0) { //Dangling lead bytes, do not decompose buffer[j++] = (char)((b << 8) | b1); break; } byte b2 = *pb++; bytesToRead--; uint ch32; if ((b & 0x10) == 0) ch32 = (uint)(((b & 0x0F) << 12) | ((b1 & 0x3F) << 6) | (b2 & 0x3F)); else { if (bytesToRead == 0) { //Dangling lead bytes, do not decompose buffer[j++] = (char)((b << 8) | b1); buffer[j++] = (char)b2; break; } byte b3 = *pb++; bytesToRead--; ch32 = (uint)(((b & 0x07) << 18) | ((b1 & 0x3F) << 12) | ((b2 & 0x3F) << 6) | (b3 & 0x3F)); } if ((ch32 & 0xFFFF0000) == 0) ch = (char)ch32; else { //break up into UTF16 surrogate pair buffer[j++] = (char)((ch32 >> 10) | 0xD800); ch = (char)((ch32 & 0x3FF) | 0xDC00); } } buffer[j++] = ch; } if (j > 0 && buffer[j - 1] == 0) j--; return new String(buffer, 0, j); } internal string/*!*/ ReadUTF8() { byte* pb = this.pb; StringBuilder sb = new StringBuilder(); byte b = 0; for (; ; ) { b = *pb++; if (b == 0) break; if ((b & 0x80) == 0) { sb.Append((char)b); continue; } char ch; byte b1 = *pb++; if (b1 == 0) { //Dangling lead byte, do not decompose sb.Append((char)b); break; } if ((b & 0x20) == 0) { ch = (char)(((b & 0x1F) << 6) | (b1 & 0x3F)); } else { byte b2 = *pb++; if (b2 == 0) { //Dangling lead bytes, do not decompose sb.Append((char)((b << 8) | b1)); break; } uint ch32; if ((b & 0x10) == 0) ch32 = (uint)(((b & 0x0F) << 12) | ((b1 & 0x3F) << 6) | (b2 & 0x3F)); else { byte b3 = *pb++; if (b3 == 0) { //Dangling lead bytes, do not decompose sb.Append((char)((b << 8) | b1)); sb.Append((char)b2); break; } ch32 = (uint)(((b & 0x07) << 18) | ((b1 & 0x3F) << 12) | ((b2 & 0x3F) << 6) | (b3 & 0x3F)); } if ((ch32 & 0xFFFF0000) == 0) ch = (char)ch32; else { //break up into UTF16 surrogate pair sb.Append((char)((ch32 >> 10) | 0xD800)); ch = (char)((ch32 & 0x3FF) | 0xDC00); } } sb.Append(ch); } this.pb = pb; return sb.ToString(); } internal string/*!*/ ReadUTF16(int charsToRead) { char* pc = (char*)this.pb; char[] buffer = new char[charsToRead]; for (int i = 0; i < charsToRead; i++) buffer[i] = *pc++; this.pb = (byte*)pc; return new String(buffer, 0, charsToRead); } internal string/*!*/ ReadUTF16() { string result = new string((char*)this.pb); this.pb += (result.Length + 1) * 2; return result; } internal string/*!*/ ReadASCII(int bytesToRead) { int c = bytesToRead; if (bytesToRead == -1) c = 128; //buffer size byte* pb = this.pb; char[] buffer = new char[c]; int j = 0; byte b = 0; Restart: while (j < c) { b = *pb++; if (b == 0) break; buffer[j++] = (char)b; } if (bytesToRead == -1) { if (b != 0) { char[] newBuffer = new char[c *= 2]; for (int copy = 0; copy < j; copy++) newBuffer[copy] = buffer[copy]; buffer = newBuffer; goto Restart; } this.pb = pb; } else this.pb += bytesToRead; return new String(buffer, 0, j); } internal string/*!*/ ReadASCII() { return ReadASCII(-1); } } #if !ROTOR #if !FxCop /// /// Public only for use by the Framework. Do not use this class. /// Well, if you really really must, use it only if you can tolerate keeping the file locked for at least as long as any Identifier /// derived from the file stays alive. /// unsafe public sealed class MemoryMappedFile : IDisposable, ISourceTextBuffer { #else unsafe sealed class MemoryMappedFile : IDisposable{ #endif private byte* buffer; private int length; public MemoryMappedFile(string fileName) { this.OpenMap(fileName); } ~MemoryMappedFile() { this.CloseMap(); } public void Dispose() { this.CloseMap(); GC.SuppressFinalize(this); } public byte* Buffer { get { Debug.Assert(this.buffer != null); return this.buffer; } } public int Length { get { Debug.Assert(this.buffer != null); return this.length; } } #if !FxCop string ISourceText.Substring(int start, int length) { Debug.Assert(false, "Can't use Substring on memory mapped files"); return null; } char ISourceText.this[int index] { get { Debug.Assert(false, "Can't access memory mapped files via an indexer, use Buffer"); return ' '; } } #endif private void OpenMap(string filename) { IntPtr hmap; int length; using (FileStream stream = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read)) { if (stream.Length > Int32.MaxValue) throw new FileLoadException(ExceptionStrings.FileTooBig, filename); length = unchecked((int)stream.Length); #if WHIDBEY && !OldWhidbey hmap = CreateFileMapping(stream.SafeFileHandle.DangerousGetHandle(), IntPtr.Zero, PageAccess.PAGE_READONLY, 0, length, null); #else hmap = CreateFileMapping(stream.Handle, IntPtr.Zero, PageAccess.PAGE_READONLY, 0, length, null); #endif if (hmap == IntPtr.Zero) { int rc = Marshal.GetLastWin32Error(); throw new FileLoadException(String.Format(CultureInfo.CurrentCulture, ExceptionStrings.CreateFileMappingReturnedErrorCode, rc.ToString()), filename); } } this.buffer = (byte*)MapViewOfFile(hmap, FileMapAccess.FILE_MAP_READ, 0, 0, (IntPtr)length); MemoryMappedFile.CloseHandle(hmap); if (this.buffer == null) { int rc = Marshal.GetLastWin32Error(); throw new FileLoadException(String.Format(CultureInfo.CurrentCulture, ExceptionStrings.MapViewOfFileReturnedErrorCode, rc.ToString()), filename); } this.length = length; } private void CloseMap() { if (buffer != null) { UnmapViewOfFile(buffer); buffer = null; } } #if !FxCop void ISourceText.MakeCollectible() { } #endif private enum PageAccess : int { PAGE_READONLY = 0x02 }; private enum FileMapAccess : int { FILE_MAP_READ = 0x0004 }; [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] private static extern IntPtr CreateFileMapping( IntPtr hFile, // handle to file IntPtr lpAttributes, // security PageAccess flProtect, // protection int dwMaximumSizeHigh, // high-order DWORD of size int dwMaximumSizeLow, // low-order DWORD of size string lpName // object name ); [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] private static extern void* MapViewOfFile( IntPtr hFileMappingObject, // handle to file-mapping object FileMapAccess dwDesiredAccess, // access mode int dwFileOffsetHigh, // high-order DWORD of offset int dwFileOffsetLow, // low-order DWORD of offset IntPtr dwNumberOfBytesToMap // number of bytes to map ); [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool UnmapViewOfFile( void* lpBaseAddress // starting address ); [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool CloseHandle( IntPtr hObject // handle to object ); } #endif }