IKVM11  11
Java SE 11 Virtual Machine for .NET
Loading...
Searching...
No Matches
ResourceDirectoryEntry.cs
Go to the documentation of this file.
1/*
2 Copyright (C) 2010-2012 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.Collections.Generic;
26using System.Linq;
27
29{
30
32 {
33
34 internal readonly OrdinalOrName ordinalOrName;
35 internal readonly List<ResourceDirectoryEntry> entries = new();
36 internal int namedEntries;
37
38 internal ByteBuffer data;
39
44 internal ResourceDirectoryEntry(OrdinalOrName ordinalOrName)
45 {
46 this.ordinalOrName = ordinalOrName;
47 }
48
54 {
55 if (other is null)
56 throw new ArgumentNullException(nameof(other));
57
58 this.ordinalOrName = other.ordinalOrName;
59 this.entries = other.entries.Select(i => new ResourceDirectoryEntry(i)).ToList();
60 this.namedEntries = other.namedEntries;
61 }
62
66 public int Count => entries.Count;
67
74 {
75 get
76 {
77 foreach (var entry in entries)
78 if (entry.ordinalOrName.Equals(id))
79 return entry;
80
81 // the entries must be sorted
82 var newEntry = new ResourceDirectoryEntry(id);
83 if (id.Name == null)
84 {
85 for (var i = namedEntries; i < entries.Count; i++)
86 {
87 if (entries[i].ordinalOrName.IsGreaterThan(id))
88 {
89 entries.Insert(i, newEntry);
90 return newEntry;
91 }
92 }
93
94 entries.Add(newEntry);
95 return newEntry;
96 }
97 else
98 {
99 for (int i = 0; i < namedEntries; i++)
100 {
101 if (entries[i].ordinalOrName.IsGreaterThan(id))
102 {
103 entries.Insert(i, newEntry);
104 namedEntries++;
105 return newEntry;
106 }
107 }
108
109 entries.Insert(namedEntries++, newEntry);
110 return newEntry;
111 }
112 }
113 }
114
115 int DirectoryLength
116 {
117 get
118 {
119 if (data != null)
120 {
121 return 16;
122 }
123 else
124 {
125 var length = 16 + entries.Count * 8;
126 foreach (var entry in entries)
127 length += entry.DirectoryLength;
128
129 return length;
130 }
131 }
132 }
133
134 internal void Write(ByteBuffer bb, List<int> linkOffsets)
135 {
136 if (entries.Count != 0)
137 {
138 var stringTableOffset = DirectoryLength;
139 var strings = new Dictionary<string, int>();
140 var stringTable = new ByteBuffer(16);
141 int offset = 16 + entries.Count * 8;
142 for (int pass = 0; pass < 3; pass++)
143 Write(bb, pass, 0, ref offset, strings, ref stringTableOffset, stringTable);
144
145 // the pecoff spec says that the string table is between the directory entries and the data entries,
146 // but the windows linker puts them after the data entries, so we do too.
147 stringTable.Align(4);
148 offset += stringTable.Length;
149 WriteResourceDataEntries(bb, linkOffsets, ref offset);
150 bb.Write(stringTable);
151 WriteData(bb);
152 }
153 }
154
155 void WriteResourceDataEntries(ByteBuffer bb, List<int> linkOffsets, ref int offset)
156 {
157 foreach (var entry in entries)
158 {
159 if (entry.data != null)
160 {
161 linkOffsets.Add(bb.Position);
162 bb.Write(offset);
163 bb.Write(entry.data.Length);
164 bb.Write(0); // code page
165 bb.Write(0); // reserved
166 offset += (entry.data.Length + 3) & ~3;
167 }
168 else
169 {
170 entry.WriteResourceDataEntries(bb, linkOffsets, ref offset);
171 }
172 }
173 }
174
175 void WriteData(ByteBuffer bb)
176 {
177 foreach (var entry in entries)
178 {
179 if (entry.data != null)
180 {
181 bb.Write(entry.data);
182 bb.Align(4);
183 }
184 else
185 {
186 entry.WriteData(bb);
187 }
188 }
189 }
190
191 void Write(ByteBuffer bb, int writeDepth, int currentDepth, ref int offset, Dictionary<string, int> strings, ref int stringTableOffset, ByteBuffer stringTable)
192 {
193 if (currentDepth == writeDepth)
194 {
195 // directory header
196 bb.Write(0); // Characteristics
197 bb.Write(0); // Time/Date Stamp
198 bb.Write(0); // Version (Major / Minor)
199 bb.Write((ushort)namedEntries);
200 bb.Write((ushort)(entries.Count - namedEntries));
201 }
202
203 foreach (var entry in entries)
204 {
205 if (currentDepth == writeDepth)
206 entry.WriteEntry(bb, ref offset, strings, ref stringTableOffset, stringTable);
207 else
208 entry.Write(bb, writeDepth, currentDepth + 1, ref offset, strings, ref stringTableOffset, stringTable);
209 }
210 }
211
212 void WriteEntry(ByteBuffer bb, ref int offset, Dictionary<string, int> strings, ref int stringTableOffset, ByteBuffer stringTable)
213 {
214 WriteNameOrOrdinal(bb, ordinalOrName, strings, ref stringTableOffset, stringTable);
215 if (data == null)
216 bb.Write(0x80000000U | (uint)offset);
217 else
218 bb.Write(offset);
219
220 offset += 16 + entries.Count * 8;
221 }
222
223 static void WriteNameOrOrdinal(ByteBuffer bb, OrdinalOrName id, Dictionary<string, int> strings, ref int stringTableOffset, ByteBuffer stringTable)
224 {
225 if (id.Name == null)
226 {
227 bb.Write((int)id.Ordinal);
228 }
229 else
230 {
231 if (strings.TryGetValue(id.Name, out var stringOffset) == false)
232 {
233 stringOffset = stringTableOffset;
234 strings.Add(id.Name, stringOffset);
235 stringTableOffset += id.Name.Length * 2 + 2;
236 stringTable.Write((ushort)id.Name.Length);
237 foreach (var c in id.Name)
238 stringTable.Write((short)c);
239 }
240
241 bb.Write(0x80000000U | (uint)stringOffset);
242 }
243 }
244
245 }
246
247}
global::java.lang.invoke.LambdaForm.Name Name
int Count
Gets the number of entries added.
readonly record struct OrdinalOrName(ushort Ordinal, string Name)