IKVM11  11
Java SE 11 Virtual Machine for .NET
Loading...
Searching...
No Matches
BigEndianBinaryReader.cs
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2014 Jeroen Frijters
3
4 This software is provided 'as-is', without any express or implied
5 warranty. In no event will the authors be held liable for any damages
6 arising from the use of this software.
7
8 Permission is granted to anyone to use this software for any purpose,
9 including commercial applications, and to alter it and redistribute it
10 freely, subject to the following restrictions:
11
12 1. The origin of this software must not be misrepresented; you must not
13 claim that you wrote the original software. If you use this software
14 in a product, an acknowledgment in the product documentation would be
15 appreciated but is not required.
16 2. Altered source versions must be plainly marked as such, and must not be
17 misrepresented as being the original software.
18 3. This notice may not be removed or altered from any source distribution.
19
20 Jeroen Frijters
21 jeroen@frijters.net
22
23*/
24using System;
25using System.Text;
26
27namespace IKVM.Runtime
28{
29
31 {
32
33 readonly ReadOnlyMemory<byte> buf;
34
35 int pos;
36
42 internal BigEndianBinaryReader(ReadOnlyMemory<byte> buf)
43 {
44 this.buf = buf;
45 this.pos = 0;
46 }
47
48 internal BigEndianBinaryReader Section(uint length)
49 {
50 var br = new BigEndianBinaryReader(buf.Slice(pos, checked((int)length)));
51 Skip(length);
52 return br;
53 }
54
55 internal bool IsAtEnd => pos == buf.Length;
56
57 internal int Position => pos;
58
59 internal void Skip(uint count)
60 {
61 if (buf.Length - pos < count)
62 throw new ClassFormatError("Truncated class file");
63
64 checked
65 {
66 pos += (int)count;
67 }
68 }
69
70 internal byte ReadByte()
71 {
72 if (pos == buf.Length)
73 throw new ClassFormatError("Truncated class file");
74
75 return buf.Span[pos++];
76 }
77
78 internal sbyte ReadSByte()
79 {
80 if (pos == buf.Length)
81 throw new ClassFormatError("Truncated class file");
82
83 return (sbyte)buf.Span[pos++];
84 }
85
86 internal double ReadDouble()
87 {
88 return BitConverter.Int64BitsToDouble(ReadInt64());
89 }
90
91 internal short ReadInt16()
92 {
93 if (buf.Length - pos < 2)
94 throw new ClassFormatError("Truncated class file");
95
96 var s = (short)((buf.Span[pos] << 8) + buf.Span[pos + 1]);
97 pos += 2;
98
99 return s;
100 }
101
102 internal int ReadInt32()
103 {
104 if (buf.Length - pos < 4)
105 throw new ClassFormatError("Truncated class file");
106
107 var i = (int)((buf.Span[pos] << 24) + (buf.Span[pos + 1] << 16) + (buf.Span[pos + 2] << 8) + buf.Span[pos + 3]);
108 pos += 4;
109 return i;
110 }
111
112 internal long ReadInt64()
113 {
114 if (buf.Length - pos < 8)
115 throw new ClassFormatError("Truncated class file");
116
117 var i1 = (uint)((buf.Span[pos] << 24) + (buf.Span[pos + 1] << 16) + (buf.Span[pos + 2] << 8) + buf.Span[pos + 3]);
118 var i2 = (uint)((buf.Span[pos + 4] << 24) + (buf.Span[pos + 5] << 16) + (buf.Span[pos + 6] << 8) + buf.Span[pos + 7]);
119 var l = (((long)i1) << 32) + i2;
120 pos += 8;
121 return l;
122 }
123
124 internal float ReadSingle()
125 {
126 return BitConverter.ToSingle(BitConverter.GetBytes(ReadInt32()), 0);
127 }
128
129 internal unsafe string ReadString(string classFile, int majorVersion)
130 {
131 int len = ReadUInt16();
132 if (buf.Length - pos < len)
133 throw new ClassFormatError("{0} (Truncated class file)", classFile);
134
135 // special code path for ASCII strings (which occur *very* frequently)
136 for (int j = 0; j < len; j++)
137 {
138 if (buf.Span[pos + j] == 0 || buf.Span[pos + j] >= 128)
139 {
140 // NOTE we *cannot* use System.Text.UTF8Encoding, because this is *not* compatible
141 // (esp. for embedded nulls)
142 char[] ch = new char[len];
143 int l = 0;
144 for (int i = 0; i < len; i++)
145 {
146 int c = buf.Span[pos + i];
147 int char2, char3;
148 switch (c >> 4)
149 {
150 case 0:
151 if (c == 0)
152 {
153 goto default;
154 }
155 break;
156 case 1:
157 case 2:
158 case 3:
159 case 4:
160 case 5:
161 case 6:
162 case 7:
163 // 0xxxxxxx
164 break;
165 case 12:
166 case 13:
167 // 110x xxxx 10xx xxxx
168 char2 = buf.Span[pos + ++i];
169 if ((char2 & 0xc0) != 0x80 || i >= len)
170 {
171 goto default;
172 }
173 c = (((c & 0x1F) << 6) | (char2 & 0x3F));
174 if (c < 0x80 && c != 0 && majorVersion >= 48)
175 {
176 goto default;
177 }
178 break;
179 case 14:
180 // 1110 xxxx 10xx xxxx 10xx xxxx
181 char2 = buf.Span[pos + ++i];
182 char3 = buf.Span[pos + ++i];
183 if ((char2 & 0xc0) != 0x80 || (char3 & 0xc0) != 0x80 || i >= len)
184 {
185 goto default;
186 }
187 c = (((c & 0x0F) << 12) | ((char2 & 0x3F) << 6) | ((char3 & 0x3F) << 0));
188 if (c < 0x800 && majorVersion >= 48)
189 {
190 goto default;
191 }
192 break;
193 default:
194 throw new ClassFormatError("Illegal UTF8 string in constant pool in class file {0}", classFile ?? "<Unknown>");
195 }
196 ch[l++] = (char)c;
197 }
198 pos += len;
199 return new string(ch, 0, l);
200 }
201 }
202
203#if NETFRAMEWORK
204 string s;
205 fixed (byte* p = buf.Slice(pos, len).Span)
206 s = Encoding.ASCII.GetString(p, buf.Length);
207#else
208 var s = Encoding.ASCII.GetString(buf.Slice(pos, len).Span);
209#endif
210 pos += len;
211 return s;
212 }
213
214 internal ushort ReadUInt16()
215 {
216 if (buf.Length - pos < 2)
217 throw new ClassFormatError("Truncated class file");
218
219 var s = (ushort)((buf.Span[pos] << 8) + buf.Span[pos + 1]);
220 pos += 2;
221 return s;
222 }
223
224 internal uint ReadUInt32()
225 {
226 if (buf.Length - pos < 4)
227 throw new ClassFormatError("Truncated class file");
228
229 uint i = (uint)((buf.Span[pos] << 24) + (buf.Span[pos + 1] << 16) + (buf.Span[pos + 2] << 8) + buf.Span[pos + 3]);
230 pos += 4;
231 return i;
232 }
233
234 internal byte[] ToArray()
235 {
236 var res = new byte[buf.Length - pos];
237 buf.Slice(pos, res.Length).CopyTo(res);
238 return res;
239 }
240
241 }
242
243}