1 | unit BGRAWinResource;
|
---|
2 |
|
---|
3 | {$mode objfpc}{$H+}
|
---|
4 |
|
---|
5 | interface
|
---|
6 |
|
---|
7 | uses
|
---|
8 | Classes, SysUtils, BGRAMultiFileType, BGRABitmapTypes, BGRAReadBMP;
|
---|
9 |
|
---|
10 | const
|
---|
11 | RT_CURSOR = 1;
|
---|
12 | RT_BITMAP = 2;
|
---|
13 | RT_ICON = 3;
|
---|
14 |
|
---|
15 | RT_MENU = 4;
|
---|
16 | RT_DIALOG = 5;
|
---|
17 | RT_STRING = 6;
|
---|
18 | RT_FONTDIR = 7;
|
---|
19 | RT_FONT = 8;
|
---|
20 | RT_ACCELERATOR = 9;
|
---|
21 | RT_RCDATA = 10;
|
---|
22 | RT_MESSAGETABLE = 11;
|
---|
23 |
|
---|
24 | RT_GROUP = 11;
|
---|
25 | RT_GROUP_CURSOR = RT_GROUP + RT_CURSOR;
|
---|
26 | RT_GROUP_ICON = RT_GROUP + RT_ICON;
|
---|
27 |
|
---|
28 | RT_VERSION = 16;
|
---|
29 | RT_ANICURSOR = 21;
|
---|
30 | RT_ANIICON = 22;
|
---|
31 | RT_HTML = 23;
|
---|
32 | RT_MANIFEST = 24;
|
---|
33 |
|
---|
34 | ICON_OR_CURSOR_FILE_ICON_TYPE = 1;
|
---|
35 | ICON_OR_CURSOR_FILE_CURSOR_TYPE = 2;
|
---|
36 |
|
---|
37 | type
|
---|
38 | TNameOrId = record
|
---|
39 | Id: integer;
|
---|
40 | Name: utf8string;
|
---|
41 | end;
|
---|
42 |
|
---|
43 | { TResourceInfo }
|
---|
44 |
|
---|
45 | TResourceInfo = object
|
---|
46 | DataVersion: DWord;
|
---|
47 | MemoryFlags: Word;
|
---|
48 | LanguageId: Word;
|
---|
49 | Version: DWord;
|
---|
50 | Characteristics: DWord;
|
---|
51 | procedure SwapIfNecessary;
|
---|
52 | end;
|
---|
53 |
|
---|
54 | TWinResourceContainer = class;
|
---|
55 |
|
---|
56 | { TCustomResourceEntry }
|
---|
57 |
|
---|
58 | TCustomResourceEntry = class(TMultiFileEntry)
|
---|
59 | private
|
---|
60 | class function GetNextEntry(AContainer: TMultiFileContainer; AStream: TStream): TCustomResourceEntry;
|
---|
61 | procedure Serialize(ADestination: TStream);
|
---|
62 | protected
|
---|
63 | FTypeNameOrId: TNameOrId;
|
---|
64 | FEntryNameOrId: TNameOrId;
|
---|
65 | FResourceInfo: TResourceInfo;
|
---|
66 | FReferenceCount: integer;
|
---|
67 | function GetName: utf8string; override;
|
---|
68 | procedure SetName(AValue: utf8string); override;
|
---|
69 | function GetId: integer;
|
---|
70 | procedure SetId(AValue: integer);
|
---|
71 | function GetTypeId: integer;
|
---|
72 | function GetTypeName: utf8string;
|
---|
73 | procedure IncrementReferences; virtual;
|
---|
74 | procedure DecrementReferences; virtual;
|
---|
75 | procedure SerializeHeader(ADestination: TStream); virtual;
|
---|
76 | procedure SerializeData(ADestination: TStream); virtual; abstract;
|
---|
77 | function GetDataSize: integer; virtual; abstract;
|
---|
78 | function GetLanguageId: integer;
|
---|
79 | procedure SetLanguageId(AValue: integer);
|
---|
80 | public
|
---|
81 | constructor Create(AContainer: TMultiFileContainer; ATypeNameOrId: TNameOrId; AEntryNameOrId: TNameOrId; const AResourceInfo: TResourceInfo);
|
---|
82 | property Id: integer read GetId write SetId;
|
---|
83 | property TypeName: utf8string read GetTypeName;
|
---|
84 | property TypeId: integer read GetTypeId;
|
---|
85 | property LanguageId: integer read GetLanguageId write SetLanguageId;
|
---|
86 | end;
|
---|
87 |
|
---|
88 | { TUnformattedResourceEntry }
|
---|
89 |
|
---|
90 | TUnformattedResourceEntry = class(TCustomResourceEntry)
|
---|
91 | protected
|
---|
92 | FDataStream: TStream;
|
---|
93 | function GetFileSize: int64; override;
|
---|
94 | function GetDataSize: integer; override;
|
---|
95 | procedure SerializeData(ADestination: TStream); override;
|
---|
96 | function GetExtension: utf8string; override;
|
---|
97 | public
|
---|
98 | constructor Create(AContainer: TMultiFileContainer; ATypeNameOrId: TNameOrId; AEntryNameOrId: TNameOrId; const AResourceInfo: TResourceInfo; ADataStream: TStream);
|
---|
99 | destructor Destroy; override;
|
---|
100 | function CopyTo(ADestination: TStream): int64; override;
|
---|
101 | end;
|
---|
102 |
|
---|
103 | { TBitmapResourceEntry }
|
---|
104 |
|
---|
105 | TBitmapResourceEntry = class(TUnformattedResourceEntry)
|
---|
106 | protected
|
---|
107 | function GetFileSize: int64; override;
|
---|
108 | function GetExtension: utf8string; override;
|
---|
109 | public
|
---|
110 | constructor Create(AContainer: TMultiFileContainer; AEntryNameOrId: TNameOrId; const AResourceInfo: TResourceInfo; ADataStream: TStream);
|
---|
111 | function CopyTo(ADestination: TStream): int64; override;
|
---|
112 | procedure CopyFrom(ASource: TStream);
|
---|
113 | end;
|
---|
114 |
|
---|
115 | { TGroupIconHeader }
|
---|
116 |
|
---|
117 | TGroupIconHeader = object
|
---|
118 | Reserved, ResourceType, ImageCount: Word;
|
---|
119 | procedure SwapIfNecessary;
|
---|
120 | end;
|
---|
121 | TGroupIconDirEntry = packed record
|
---|
122 | Width, Height, Colors, Reserved: byte;
|
---|
123 | //stored in little endian
|
---|
124 | case byte of
|
---|
125 | 0: (Variable: DWord; ImageSize: DWord; ImageId: Word);
|
---|
126 | 1: (Planes, BitsPerPixel: Word);
|
---|
127 | 2: (HotSpotX, HotSpotY: Word);
|
---|
128 | end;
|
---|
129 | TIconFileDirEntry = packed record
|
---|
130 | Width, Height, Colors, Reserved: byte;
|
---|
131 | //stored in little endian
|
---|
132 | case byte of
|
---|
133 | 0: (Variable: DWord; ImageSize: DWord; ImageOffset: DWord);
|
---|
134 | 1: (Planes, BitsPerPixel: Word);
|
---|
135 | 2: (HotSpotX, HotSpotY: Word);
|
---|
136 | end;
|
---|
137 |
|
---|
138 | { TGroupIconOrCursorEntry }
|
---|
139 |
|
---|
140 | TGroupIconOrCursorEntry = class(TCustomResourceEntry)
|
---|
141 | private
|
---|
142 | function GetNbIcons: integer;
|
---|
143 | protected
|
---|
144 | FGroupIconHeader: TGroupIconHeader;
|
---|
145 | FDirectory: packed array of TGroupIconDirEntry;
|
---|
146 | function GetFileSize: int64; override;
|
---|
147 | function GetDataSize: integer; override;
|
---|
148 | procedure SerializeData(ADestination: TStream); override;
|
---|
149 | procedure IncrementReferences; override;
|
---|
150 | procedure DecrementReferences; override;
|
---|
151 | function ExpectedResourceType: word; virtual; abstract;
|
---|
152 | public
|
---|
153 | constructor Create(AContainer: TMultiFileContainer; ATypeNameOrId: TNameOrId; AEntryNameOrId: TNameOrId; const AResourceInfo: TResourceInfo; ADataStream: TStream);
|
---|
154 | constructor Create(AContainer: TMultiFileContainer; ATypeNameOrId: TNameOrId; AEntryNameOrId: TNameOrId; const AResourceInfo: TResourceInfo);
|
---|
155 | procedure Clear;
|
---|
156 | function CopyTo(ADestination: TStream): int64; override;
|
---|
157 | procedure CopyFrom(ASource: TStream);
|
---|
158 | property NbIcons: integer read GetNbIcons;
|
---|
159 | end;
|
---|
160 |
|
---|
161 | { TGroupIconEntry }
|
---|
162 |
|
---|
163 | TGroupIconEntry = class(TGroupIconOrCursorEntry)
|
---|
164 | protected
|
---|
165 | function GetExtension: utf8string; override;
|
---|
166 | function ExpectedResourceType: word; override;
|
---|
167 | public
|
---|
168 | constructor Create(AContainer: TMultiFileContainer; AEntryNameOrId: TNameOrId; const AResourceInfo: TResourceInfo; ADataStream: TStream);
|
---|
169 | constructor Create(AContainer: TMultiFileContainer; AEntryNameOrId: TNameOrId; const AResourceInfo: TResourceInfo);
|
---|
170 | end;
|
---|
171 |
|
---|
172 | { TGroupCursorEntry }
|
---|
173 |
|
---|
174 | TGroupCursorEntry = class(TGroupIconOrCursorEntry)
|
---|
175 | protected
|
---|
176 | function GetExtension: utf8string; override;
|
---|
177 | function ExpectedResourceType: word; override;
|
---|
178 | public
|
---|
179 | constructor Create(AContainer: TMultiFileContainer; AEntryNameOrId: TNameOrId; const AResourceInfo: TResourceInfo; ADataStream: TStream);
|
---|
180 | constructor Create(AContainer: TMultiFileContainer; AEntryNameOrId: TNameOrId; const AResourceInfo: TResourceInfo);
|
---|
181 | end;
|
---|
182 |
|
---|
183 | { TWinResourceContainer }
|
---|
184 |
|
---|
185 | TWinResourceContainer = class(TMultiFileContainer)
|
---|
186 | private
|
---|
187 | function InternalFind(const AEntry: TNameOrId; const AType: TNameOrId; ALanguageId: integer = 0): TCustomResourceEntry;
|
---|
188 | procedure AddHidden(AEntry: TCustomResourceEntry);
|
---|
189 | function GetMaxId(AType: TNameOrId): integer;
|
---|
190 | procedure IncrementReferenceOf(ANameId, ATypeId: integer);
|
---|
191 | procedure DecrementReferenceOf(ANameId, ATypeId: integer);
|
---|
192 | protected
|
---|
193 | FHiddenEntries: TMultiFileEntryList;
|
---|
194 | procedure Init; override;
|
---|
195 | procedure ClearHiddenEntries;
|
---|
196 | procedure RemoveHidden(AEntry: TCustomResourceEntry);
|
---|
197 | function CreateEntry(AName: utf8string; AExtension: utf8string; AContent: TStream; ALanguageId: integer): TMultiFileEntry; overload;
|
---|
198 | function CreateEntry(AName: utf8string; AExtension: utf8string; AContent: TStream): TMultiFileEntry; override;
|
---|
199 | public
|
---|
200 | procedure Clear; override;
|
---|
201 | destructor Destroy; override;
|
---|
202 | procedure Delete(AIndex: integer); override;
|
---|
203 | procedure LoadFromStream(AStream: TStream); override;
|
---|
204 | function IndexOf(AName: utf8string; AExtenstion: utf8string; ACaseSensitive: boolean = True): integer; override;
|
---|
205 | function IndexOf(AName: utf8string; AExtenstion: utf8string; ALanguageId: integer; ACaseSensitive: boolean = True): integer; overload;
|
---|
206 | procedure SaveToStream(ADestination: TStream); override;
|
---|
207 | end;
|
---|
208 |
|
---|
209 | implementation
|
---|
210 |
|
---|
211 | uses Math, BGRAUTF8;
|
---|
212 |
|
---|
213 | operator =(const ANameOrId1, ANameOrId2: TNameOrId): boolean;
|
---|
214 | begin
|
---|
215 | if (ANameOrId1.Id < 0) then
|
---|
216 | result := (ANameOrId2.Id < 0) and (ANameOrId2.Name = ANameOrId1.Name)
|
---|
217 | else
|
---|
218 | result := ANameOrId2.Id = ANameOrId1.Id;
|
---|
219 | end;
|
---|
220 |
|
---|
221 | function NameOrId(AName: string): TNameOrId; overload;
|
---|
222 | begin
|
---|
223 | result.Id := -1;
|
---|
224 | result.Name := AName;
|
---|
225 | end;
|
---|
226 |
|
---|
227 | function NameOrId(AId: integer): TNameOrId; overload;
|
---|
228 | begin
|
---|
229 | result.Id := AId;
|
---|
230 | result.Name := IntToStr(AId);
|
---|
231 | end;
|
---|
232 |
|
---|
233 | { TGroupCursorEntry }
|
---|
234 |
|
---|
235 | function TGroupCursorEntry.GetExtension: utf8string;
|
---|
236 | begin
|
---|
237 | Result:= 'cur';
|
---|
238 | end;
|
---|
239 |
|
---|
240 | function TGroupCursorEntry.ExpectedResourceType: word;
|
---|
241 | begin
|
---|
242 | result := ICON_OR_CURSOR_FILE_CURSOR_TYPE;
|
---|
243 | end;
|
---|
244 |
|
---|
245 | constructor TGroupCursorEntry.Create(AContainer: TMultiFileContainer;
|
---|
246 | AEntryNameOrId: TNameOrId; const AResourceInfo: TResourceInfo;
|
---|
247 | ADataStream: TStream);
|
---|
248 | begin
|
---|
249 | inherited Create(AContainer,NameOrId(RT_GROUP_CURSOR),AEntryNameOrId,AResourceInfo,ADataStream);
|
---|
250 | end;
|
---|
251 |
|
---|
252 | constructor TGroupCursorEntry.Create(AContainer: TMultiFileContainer;
|
---|
253 | AEntryNameOrId: TNameOrId; const AResourceInfo: TResourceInfo);
|
---|
254 | begin
|
---|
255 | inherited Create(AContainer,NameOrId(RT_GROUP_CURSOR),AEntryNameOrId,AResourceInfo);
|
---|
256 | end;
|
---|
257 |
|
---|
258 | { TGroupIconEntry }
|
---|
259 |
|
---|
260 | function TGroupIconEntry.GetExtension: utf8string;
|
---|
261 | begin
|
---|
262 | Result:= 'ico';
|
---|
263 | end;
|
---|
264 |
|
---|
265 | function TGroupIconEntry.ExpectedResourceType: word;
|
---|
266 | begin
|
---|
267 | result := ICON_OR_CURSOR_FILE_ICON_TYPE;
|
---|
268 | end;
|
---|
269 |
|
---|
270 | constructor TGroupIconEntry.Create(AContainer: TMultiFileContainer;
|
---|
271 | AEntryNameOrId: TNameOrId; const AResourceInfo: TResourceInfo;
|
---|
272 | ADataStream: TStream);
|
---|
273 | begin
|
---|
274 | inherited Create(AContainer,NameOrId(RT_GROUP_ICON),AEntryNameOrId,AResourceInfo,ADataStream);
|
---|
275 | end;
|
---|
276 |
|
---|
277 | constructor TGroupIconEntry.Create(AContainer: TMultiFileContainer;
|
---|
278 | AEntryNameOrId: TNameOrId; const AResourceInfo: TResourceInfo);
|
---|
279 | begin
|
---|
280 | inherited Create(AContainer,NameOrId(RT_GROUP_ICON),AEntryNameOrId,AResourceInfo);
|
---|
281 | end;
|
---|
282 |
|
---|
283 | { TGroupIconHeader }
|
---|
284 |
|
---|
285 | procedure TGroupIconHeader.SwapIfNecessary;
|
---|
286 | begin
|
---|
287 | Reserved := LEtoN(Reserved);
|
---|
288 | ResourceType := LEtoN(ResourceType);
|
---|
289 | ImageCount := LEtoN(ImageCount);
|
---|
290 | end;
|
---|
291 |
|
---|
292 | { TGroupIconOrCursorEntry }
|
---|
293 |
|
---|
294 | function TGroupIconOrCursorEntry.GetNbIcons: integer;
|
---|
295 | begin
|
---|
296 | result := FGroupIconHeader.ImageCount;
|
---|
297 | end;
|
---|
298 |
|
---|
299 | function TGroupIconOrCursorEntry.GetFileSize: int64;
|
---|
300 | var
|
---|
301 | i: Integer;
|
---|
302 | begin
|
---|
303 | Result:= sizeof(FGroupIconHeader) + sizeof(TIconFileDirEntry)*NbIcons;
|
---|
304 | for i := 0 to NbIcons-1 do
|
---|
305 | Result += LEtoN(FDirectory[i].ImageSize);
|
---|
306 | end;
|
---|
307 |
|
---|
308 | function TGroupIconOrCursorEntry.GetDataSize: integer;
|
---|
309 | begin
|
---|
310 | result := sizeof(FGroupIconHeader) + sizeof(TGroupIconDirEntry)*NbIcons;
|
---|
311 | end;
|
---|
312 |
|
---|
313 | procedure TGroupIconOrCursorEntry.SerializeData(ADestination: TStream);
|
---|
314 | begin
|
---|
315 | FGroupIconHeader.SwapIfNecessary;
|
---|
316 | try
|
---|
317 | ADestination.WriteBuffer(FGroupIconHeader, sizeof(FGroupIconHeader));
|
---|
318 | finally
|
---|
319 | FGroupIconHeader.SwapIfNecessary;
|
---|
320 | end;
|
---|
321 | ADestination.WriteBuffer(FDirectory[0], sizeof(TGroupIconDirEntry)*NbIcons);
|
---|
322 | end;
|
---|
323 |
|
---|
324 | procedure TGroupIconOrCursorEntry.IncrementReferences;
|
---|
325 | var
|
---|
326 | i: Integer;
|
---|
327 | begin
|
---|
328 | for i := 0 to NbIcons-1 do
|
---|
329 | TWinResourceContainer(Container).IncrementReferenceOf(LEtoN(FDirectory[i].ImageId), TypeId - RT_GROUP);
|
---|
330 | end;
|
---|
331 |
|
---|
332 | procedure TGroupIconOrCursorEntry.DecrementReferences;
|
---|
333 | var
|
---|
334 | i: Integer;
|
---|
335 | begin
|
---|
336 | for i := 0 to NbIcons-1 do
|
---|
337 | TWinResourceContainer(Container).DecrementReferenceOf(LEtoN(FDirectory[i].ImageId), TypeId - RT_GROUP);
|
---|
338 | end;
|
---|
339 |
|
---|
340 | constructor TGroupIconOrCursorEntry.Create(AContainer: TMultiFileContainer;
|
---|
341 | ATypeNameOrId: TNameOrId; AEntryNameOrId: TNameOrId; const AResourceInfo: TResourceInfo;
|
---|
342 | ADataStream: TStream);
|
---|
343 | begin
|
---|
344 | inherited Create(AContainer,ATypeNameOrId,AEntryNameOrId,AResourceInfo);
|
---|
345 |
|
---|
346 | ADataStream.ReadBuffer(FGroupIconHeader, sizeof(FGroupIconHeader));
|
---|
347 | FGroupIconHeader.SwapIfNecessary;
|
---|
348 | if FGroupIconHeader.ResourceType <> ExpectedResourceType then
|
---|
349 | raise exception.Create('Unexpected group type');
|
---|
350 |
|
---|
351 | if ADataStream.Position + NbIcons*sizeof(TGroupIconDirEntry) > ADataStream.Size then
|
---|
352 | raise exception.Create('Directory dimension mismatch');
|
---|
353 | setlength(FDirectory, NbIcons);
|
---|
354 | ADataStream.ReadBuffer(FDirectory[0], NbIcons*sizeof(TGroupIconDirEntry));
|
---|
355 | ADataStream.Free;
|
---|
356 | end;
|
---|
357 |
|
---|
358 | constructor TGroupIconOrCursorEntry.Create(AContainer: TMultiFileContainer;
|
---|
359 | ATypeNameOrId: TNameOrId; AEntryNameOrId: TNameOrId;
|
---|
360 | const AResourceInfo: TResourceInfo);
|
---|
361 | begin
|
---|
362 | inherited Create(AContainer,ATypeNameOrId,AEntryNameOrId,AResourceInfo);
|
---|
363 |
|
---|
364 | FGroupIconHeader.Reserved := 0;
|
---|
365 | FGroupIconHeader.ResourceType := ExpectedResourceType;
|
---|
366 | FGroupIconHeader.ImageCount := 0;
|
---|
367 | end;
|
---|
368 |
|
---|
369 | procedure TGroupIconOrCursorEntry.Clear;
|
---|
370 | begin
|
---|
371 | DecrementReferences;
|
---|
372 | FDirectory := nil;
|
---|
373 | FGroupIconHeader.ImageCount := 0;
|
---|
374 | end;
|
---|
375 |
|
---|
376 | function TGroupIconOrCursorEntry.CopyTo(ADestination: TStream): int64;
|
---|
377 | var
|
---|
378 | fileDir: packed array of TIconFileDirEntry;
|
---|
379 | offset, written, i: integer;
|
---|
380 | iconEntry: TCustomResourceEntry;
|
---|
381 | iconEntrySize: DWord;
|
---|
382 | iconData: TMemoryStream;
|
---|
383 | copyCount: Int64;
|
---|
384 | subType: TNameOrId;
|
---|
385 |
|
---|
386 | procedure FillZero(ACount: integer);
|
---|
387 | var
|
---|
388 | Zero: packed array[0..255] of byte;
|
---|
389 | begin
|
---|
390 | if ACount <= 0 then exit;
|
---|
391 | FillChar({%H-}Zero, Sizeof(Zero), 0);
|
---|
392 | while ACount > 0 do
|
---|
393 | begin
|
---|
394 | ADestination.WriteBuffer(Zero, Min(ACount, sizeof(Zero)));
|
---|
395 | Dec(ACount, Min(ACount, sizeof(Zero)));
|
---|
396 | end;
|
---|
397 | end;
|
---|
398 |
|
---|
399 | begin
|
---|
400 | result:= 0;
|
---|
401 | FGroupIconHeader.SwapIfNecessary;
|
---|
402 | try
|
---|
403 | ADestination.WriteBuffer(FGroupIconHeader, sizeof(FGroupIconHeader));
|
---|
404 | finally
|
---|
405 | FGroupIconHeader.SwapIfNecessary;
|
---|
406 | end;
|
---|
407 | Inc(result, sizeof(FGroupIconHeader));
|
---|
408 |
|
---|
409 | offset := result+sizeof(TIconFileDirEntry)*NbIcons;
|
---|
410 | setlength(fileDir, NbIcons);
|
---|
411 | for i := 0 to NbIcons-1 do
|
---|
412 | begin
|
---|
413 | move(FDirectory[i], fileDir[i], 12);
|
---|
414 | fileDir[i].ImageOffset := NtoLE(offset);
|
---|
415 | inc(offset, fileDir[i].ImageSize);
|
---|
416 | end;
|
---|
417 |
|
---|
418 | ADestination.WriteBuffer(fileDir[0], sizeof(TIconFileDirEntry)*NbIcons);
|
---|
419 | inc(result, sizeof(TIconFileDirEntry)*NbIcons);
|
---|
420 |
|
---|
421 | subType := NameOrId(TypeId - RT_GROUP);
|
---|
422 | for i := 0 to NbIcons-1 do
|
---|
423 | begin
|
---|
424 | iconEntry := (Container as TWinResourceContainer).InternalFind(NameOrId(LEtoN(FDirectory[i].ImageId)),subType); //no language for icons
|
---|
425 | iconEntrySize := LEtoN(FDirectory[i].ImageSize);
|
---|
426 | if iconEntry = nil then
|
---|
427 | FillZero(iconEntrySize) else
|
---|
428 | begin
|
---|
429 | iconData := TMemoryStream.Create;
|
---|
430 | try
|
---|
431 | iconEntry.CopyTo(IconData);
|
---|
432 | iconData.Position:= 0;
|
---|
433 | copyCount := Min(IconData.Size, iconEntrySize);
|
---|
434 | if copyCount > 0 then written := ADestination.CopyFrom(IconData, copyCount)
|
---|
435 | else written := 0;
|
---|
436 | FillZero(iconEntrySize-written);
|
---|
437 | finally
|
---|
438 | IconData.Free;
|
---|
439 | end;
|
---|
440 | end;
|
---|
441 | result += iconEntrySize;
|
---|
442 | end;
|
---|
443 | end;
|
---|
444 |
|
---|
445 | procedure TGroupIconOrCursorEntry.CopyFrom(ASource: TStream);
|
---|
446 | var
|
---|
447 | tempGroup: TGroupIconHeader;
|
---|
448 | fileDir: packed array of TIconFileDirEntry;
|
---|
449 | iconStream: array of TMemoryStream;
|
---|
450 | startPos: int64;
|
---|
451 | maxId, i: integer;
|
---|
452 | iconEntry: TUnformattedResourceEntry;
|
---|
453 | resourceInfo: TResourceInfo;
|
---|
454 | subType: TNameOrId;
|
---|
455 | begin
|
---|
456 | startPos := ASource.Position;
|
---|
457 | ASource.ReadBuffer({%H-}tempGroup, sizeof(tempGroup));
|
---|
458 | tempGroup.SwapIfNecessary;
|
---|
459 | if tempGroup.ResourceType <> ExpectedResourceType then
|
---|
460 | raise exception.Create('Unexpected resource type');
|
---|
461 |
|
---|
462 | if ASource.Position + sizeof(TIconFileDirEntry)*tempGroup.ImageCount > ASource.Size then
|
---|
463 | raise exception.Create('Directory dimension mismatch');
|
---|
464 |
|
---|
465 | setlength(fileDir, tempGroup.ImageCount);
|
---|
466 | ASource.ReadBuffer(fileDir[0], sizeof(TIconFileDirEntry)*tempGroup.ImageCount);
|
---|
467 |
|
---|
468 | try
|
---|
469 | setlength(iconStream, tempGroup.ImageCount);
|
---|
470 | for i := 0 to tempGroup.ImageCount-1 do
|
---|
471 | begin
|
---|
472 | ASource.Position:= startPos + LEtoN(fileDir[i].ImageOffset);
|
---|
473 | iconStream[i] := TMemoryStream.Create;
|
---|
474 | iconStream[i].CopyFrom(ASource, LEtoN(fileDir[i].ImageSize));
|
---|
475 | end;
|
---|
476 |
|
---|
477 | subType := NameOrId(self.TypeId - RT_GROUP);
|
---|
478 | maxId := TWinResourceContainer(Container).GetMaxId(subType);
|
---|
479 |
|
---|
480 | Clear;
|
---|
481 | FGroupIconHeader.ImageCount := tempGroup.ImageCount;
|
---|
482 | setlength(FDirectory, tempGroup.ImageCount);
|
---|
483 | fillchar({%H-}resourceInfo,sizeof(resourceInfo),0);
|
---|
484 | for i := 0 to tempGroup.ImageCount-1 do
|
---|
485 | begin
|
---|
486 | move(fileDir[i], FDirectory[i], 12);
|
---|
487 | inc(maxId);
|
---|
488 | FDirectory[i].ImageId := maxId;
|
---|
489 | iconEntry := TUnformattedResourceEntry.Create(Container, subType, NameOrId(maxId), resourceInfo, iconStream[i]);
|
---|
490 | iconStream[i] := nil;
|
---|
491 | TWinResourceContainer(Container).AddHidden(iconEntry);
|
---|
492 | end;
|
---|
493 |
|
---|
494 | finally
|
---|
495 | for i := 0 to high(iconStream) do
|
---|
496 | iconStream[i].Free;
|
---|
497 | iconStream := nil;
|
---|
498 | end;
|
---|
499 | end;
|
---|
500 |
|
---|
501 | { TBitmapResourceEntry }
|
---|
502 |
|
---|
503 | function TBitmapResourceEntry.GetFileSize: int64;
|
---|
504 | begin
|
---|
505 | result := sizeof(TBitMapFileHeader)+FDataStream.Size;
|
---|
506 | end;
|
---|
507 |
|
---|
508 | function TBitmapResourceEntry.GetExtension: utf8string;
|
---|
509 | begin
|
---|
510 | Result:= 'bmp';
|
---|
511 | end;
|
---|
512 |
|
---|
513 | constructor TBitmapResourceEntry.Create(AContainer: TMultiFileContainer;
|
---|
514 | AEntryNameOrId: TNameOrId; const AResourceInfo: TResourceInfo;
|
---|
515 | ADataStream: TStream);
|
---|
516 | begin
|
---|
517 | inherited Create(AContainer, NameOrId(RT_BITMAP), AEntryNameOrId, AResourceInfo, ADataStream);
|
---|
518 | end;
|
---|
519 |
|
---|
520 | function TBitmapResourceEntry.CopyTo(ADestination: TStream): int64;
|
---|
521 | var fileHeader: TBitMapFileHeader;
|
---|
522 | begin
|
---|
523 | result := 0;
|
---|
524 | FDataStream.Position := 0;
|
---|
525 | fileHeader := MakeBitmapFileHeader(FDataStream);
|
---|
526 | ADestination.WriteBuffer(fileHeader, sizeof(fileHeader));
|
---|
527 | result += sizeof(fileHeader);
|
---|
528 | FDataStream.Position := 0;
|
---|
529 | result += ADestination.CopyFrom(FDataStream, FDataStream.Size);
|
---|
530 | end;
|
---|
531 |
|
---|
532 | procedure TBitmapResourceEntry.CopyFrom(ASource: TStream);
|
---|
533 | var
|
---|
534 | fileHeader: TBitMapFileHeader;
|
---|
535 | dataSize: integer;
|
---|
536 | begin
|
---|
537 | ASource.ReadBuffer({%H-}fileHeader, sizeof(fileHeader));
|
---|
538 | if fileHeader.bfType <> Word('BM') then
|
---|
539 | raise exception.Create('Invalid file header');
|
---|
540 | dataSize := LEtoN(fileHeader.bfSize) - sizeof(fileHeader);
|
---|
541 | if ASource.Position + dataSize > ASource.Size then
|
---|
542 | raise exception.Create('Invalid file size');
|
---|
543 |
|
---|
544 | FDataStream.Free;
|
---|
545 | FDataStream := TMemoryStream.Create;
|
---|
546 | FDataStream.CopyFrom(ASource, dataSize);
|
---|
547 | end;
|
---|
548 |
|
---|
549 | { TUnformattedResourceEntry }
|
---|
550 |
|
---|
551 | function TUnformattedResourceEntry.GetFileSize: int64;
|
---|
552 | begin
|
---|
553 | Result:= FDataStream.Size;
|
---|
554 | end;
|
---|
555 |
|
---|
556 | function TUnformattedResourceEntry.GetDataSize: integer;
|
---|
557 | begin
|
---|
558 | result := FDataStream.Size;
|
---|
559 | end;
|
---|
560 |
|
---|
561 | procedure TUnformattedResourceEntry.SerializeData(ADestination: TStream);
|
---|
562 | begin
|
---|
563 | if FDataStream.Size > 0 then
|
---|
564 | begin
|
---|
565 | FDataStream.Position := 0;
|
---|
566 | ADestination.CopyFrom(FDataStream, FDataStream.Size);
|
---|
567 | end;
|
---|
568 | end;
|
---|
569 |
|
---|
570 | function TUnformattedResourceEntry.GetExtension: utf8string;
|
---|
571 | var format: TBGRAImageFormat;
|
---|
572 | begin
|
---|
573 | case TypeId of
|
---|
574 | RT_MANIFEST: result := 'manifest';
|
---|
575 | RT_HTML: result := 'html';
|
---|
576 | RT_RCDATA:
|
---|
577 | begin
|
---|
578 | FDataStream.Position:= 0;
|
---|
579 | format := DetectFileFormat(FDataStream);
|
---|
580 | if format = ifUnknown then
|
---|
581 | result := 'dat'
|
---|
582 | else
|
---|
583 | result := SuggestImageExtension(format);
|
---|
584 | end;
|
---|
585 | RT_ANICURSOR: result := 'ani';
|
---|
586 | else
|
---|
587 | if TypeName = 'ANICURSOR' then
|
---|
588 | result := 'ani'
|
---|
589 | else
|
---|
590 | result := '';
|
---|
591 | end;
|
---|
592 | end;
|
---|
593 |
|
---|
594 | constructor TUnformattedResourceEntry.Create(AContainer: TMultiFileContainer;
|
---|
595 | ATypeNameOrId: TNameOrId; AEntryNameOrId: TNameOrId;
|
---|
596 | const AResourceInfo: TResourceInfo; ADataStream: TStream);
|
---|
597 | begin
|
---|
598 | inherited Create(AContainer,ATypeNameOrId,AEntryNameOrId,AResourceInfo);
|
---|
599 | FDataStream := ADataStream;
|
---|
600 | end;
|
---|
601 |
|
---|
602 | destructor TUnformattedResourceEntry.Destroy;
|
---|
603 | begin
|
---|
604 | FreeAndNil(FDataStream);
|
---|
605 | inherited Destroy;
|
---|
606 | end;
|
---|
607 |
|
---|
608 | function TUnformattedResourceEntry.CopyTo(ADestination: TStream): int64;
|
---|
609 | begin
|
---|
610 | if FDataStream.Size > 0 then
|
---|
611 | begin
|
---|
612 | FDataStream.Position := 0;
|
---|
613 | result := ADestination.CopyFrom(FDataStream, FDataStream.Size)
|
---|
614 | end
|
---|
615 | else
|
---|
616 | result := 0;
|
---|
617 | end;
|
---|
618 |
|
---|
619 | { TResourceInfo }
|
---|
620 |
|
---|
621 | procedure TResourceInfo.SwapIfNecessary;
|
---|
622 | begin
|
---|
623 | DataVersion := LEtoN(DataVersion);
|
---|
624 | MemoryFlags := LEtoN(MemoryFlags);
|
---|
625 | LanguageId := LEtoN(LanguageId);
|
---|
626 | Version := LEtoN(Version);
|
---|
627 | Characteristics := LEtoN(Characteristics);
|
---|
628 | end;
|
---|
629 |
|
---|
630 | { TCustomResourceEntry }
|
---|
631 |
|
---|
632 | function TCustomResourceEntry.GetId: integer;
|
---|
633 | begin
|
---|
634 | result := FEntryNameOrId.Id;
|
---|
635 | end;
|
---|
636 |
|
---|
637 | function TCustomResourceEntry.GetTypeId: integer;
|
---|
638 | begin
|
---|
639 | result := FTypeNameOrId.Id;
|
---|
640 | end;
|
---|
641 |
|
---|
642 | function GetDWord(var ASource: PByte; var ARemainingBytes: Integer): DWord;
|
---|
643 | begin
|
---|
644 | if ARemainingBytes >= 4 then
|
---|
645 | begin
|
---|
646 | result := LEtoN(PDWord(ASource)^);
|
---|
647 | inc(ASource, 4);
|
---|
648 | dec(ARemainingBytes, 4);
|
---|
649 | end else
|
---|
650 | begin
|
---|
651 | result := 0;
|
---|
652 | inc(ASource, ARemainingBytes);
|
---|
653 | ARemainingBytes:= 0;
|
---|
654 | end;
|
---|
655 | end;
|
---|
656 |
|
---|
657 | function GetWord(var ASource: PByte; var ARemainingBytes: Integer): Word;
|
---|
658 | begin
|
---|
659 | if ARemainingBytes >= 2 then
|
---|
660 | begin
|
---|
661 | result := LEtoN(PWord(ASource)^);
|
---|
662 | inc(ASource, 2);
|
---|
663 | dec(ARemainingBytes, 2);
|
---|
664 | end else
|
---|
665 | begin
|
---|
666 | result := 0;
|
---|
667 | inc(ASource, ARemainingBytes);
|
---|
668 | ARemainingBytes:= 0;
|
---|
669 | end;
|
---|
670 | end;
|
---|
671 |
|
---|
672 | function GetNameOrId(var ASource: PByte; var ARemainingBytes: Integer): TNameOrId;
|
---|
673 | var curChar: Word;
|
---|
674 | pstart: PByte;
|
---|
675 | begin
|
---|
676 | pstart := ASource;
|
---|
677 | curChar := GetWord(ASource,ARemainingBytes);
|
---|
678 | if curChar = $ffff then
|
---|
679 | begin
|
---|
680 | result.Id := GetWord(ASource,ARemainingBytes);
|
---|
681 | result.Name := IntToStr(result.Id);
|
---|
682 | end else
|
---|
683 | begin
|
---|
684 | while curChar <> 0 do
|
---|
685 | curChar := GetWord(ASource,ARemainingBytes);
|
---|
686 | result.Id := -1;
|
---|
687 | result.Name := UTF8Encode(WideCharLenToString(PWideChar(pstart), (ASource-pstart) div 2 -1));
|
---|
688 | end;
|
---|
689 | end;
|
---|
690 |
|
---|
691 | function TCustomResourceEntry.GetLanguageId: integer;
|
---|
692 | begin
|
---|
693 | result := FResourceInfo.LanguageId;
|
---|
694 | end;
|
---|
695 |
|
---|
696 | class function TCustomResourceEntry.GetNextEntry(AContainer: TMultiFileContainer; AStream: TStream): TCustomResourceEntry;
|
---|
697 | var
|
---|
698 | entrySize, headerSize, remaining, padding: Integer;
|
---|
699 | headerData: Pointer;
|
---|
700 | pHeaderData: PByte;
|
---|
701 | typeNameOrId: TNameOrId;
|
---|
702 | entryNameOrId: TNameOrId;
|
---|
703 | info: TResourceInfo;
|
---|
704 | dataStream: TMemoryStream;
|
---|
705 | dummy: DWord;
|
---|
706 | begin
|
---|
707 | result := nil;
|
---|
708 | if AStream.Position + 16 < AStream.Size then
|
---|
709 | begin
|
---|
710 | entrySize := LEtoN(AStream.ReadDWord);
|
---|
711 | headerSize := LEtoN(AStream.ReadDWord);
|
---|
712 | if headerSize < 16 then
|
---|
713 | raise exception.Create('Header too small');
|
---|
714 | remaining := ((headerSize-8) + 3) and not 3;
|
---|
715 | if AStream.Position + remaining + entrySize > AStream.Size then
|
---|
716 | raise exception.Create('Data would be outside of stream');
|
---|
717 |
|
---|
718 | GetMem(headerData, remaining);
|
---|
719 | try
|
---|
720 | AStream.ReadBuffer(headerData^, remaining);
|
---|
721 | pHeaderData := PByte(headerData);
|
---|
722 | typeNameOrId := GetNameOrId(pHeaderData, remaining);
|
---|
723 | entryNameOrId := GetNameOrId(pHeaderData, remaining);
|
---|
724 | padding := (4 - ((pHeaderData-PByte(headerData)) and 3)) and 3;
|
---|
725 | inc(pHeaderData, padding);
|
---|
726 | dec(remaining, padding);
|
---|
727 |
|
---|
728 | FillChar({%H-}info, SizeOf(info), 0);
|
---|
729 | Move(pHeaderData^, info, Min(Sizeof(info), remaining));
|
---|
730 | info.SwapIfNecessary;
|
---|
731 |
|
---|
732 | dataStream := TMemoryStream.Create;
|
---|
733 | if entrySize > 0 then dataStream.CopyFrom(AStream, entrySize);
|
---|
734 | padding := ((entrySize+3) and not 3) - entrySize;
|
---|
735 | if padding > 0 then AStream.Read({%H-}dummy, padding);
|
---|
736 | finally
|
---|
737 | FreeMem(headerData);
|
---|
738 | end;
|
---|
739 |
|
---|
740 | dataStream.Position := 0;
|
---|
741 | case typeNameOrId.Id of
|
---|
742 | RT_BITMAP: result := TBitmapResourceEntry.Create(AContainer,entryNameOrId,info,dataStream);
|
---|
743 | RT_GROUP_ICON: result := TGroupIconEntry.Create(AContainer,entryNameOrId,info,dataStream);
|
---|
744 | RT_GROUP_CURSOR: result := TGroupCursorEntry.Create(AContainer,entryNameOrId,info,dataStream);
|
---|
745 | else
|
---|
746 | result := TUnformattedResourceEntry.Create(AContainer,typeNameOrId,entryNameOrId,info,dataStream);
|
---|
747 | end;
|
---|
748 | end;
|
---|
749 | end;
|
---|
750 |
|
---|
751 | procedure WriteNameOrId(ADestination: TStream; ANameOrId: TNameOrId);
|
---|
752 | var buffer: PUnicodeChar;
|
---|
753 | maxLen,actualLen: integer;
|
---|
754 | begin
|
---|
755 | if ANameOrId.Id < 0 then
|
---|
756 | begin
|
---|
757 | maxLen := length(ANameOrId.Name)*2 + 1;
|
---|
758 | getmem(buffer, maxLen*sizeof(UnicodeChar));
|
---|
759 | try
|
---|
760 | fillchar(buffer^, maxLen*sizeof(UnicodeChar), 0);
|
---|
761 | actualLen := Utf8ToUnicode(buffer, maxLen, @ANameOrId.Name[1], length(ANameOrId.Name));
|
---|
762 | ADestination.WriteBuffer(buffer^, actualLen*sizeof(UnicodeChar));
|
---|
763 | finally
|
---|
764 | freemem(buffer);
|
---|
765 | end;
|
---|
766 | end else
|
---|
767 | begin
|
---|
768 | ADestination.WriteWord($ffff);
|
---|
769 | ADestination.WriteWord(NtoLE(Word(ANameOrId.Id)));
|
---|
770 | end;
|
---|
771 | end;
|
---|
772 |
|
---|
773 | procedure TCustomResourceEntry.Serialize(ADestination: TStream);
|
---|
774 | var zero: DWord;
|
---|
775 | padding: integer;
|
---|
776 | begin
|
---|
777 | SerializeHeader(ADestination);
|
---|
778 | SerializeData(ADestination);
|
---|
779 | padding := (4-(GetDataSize and 3)) and 3;
|
---|
780 | if padding > 0 then
|
---|
781 | begin
|
---|
782 | zero := 0;
|
---|
783 | ADestination.WriteBuffer(zero, padding);
|
---|
784 | end;
|
---|
785 | end;
|
---|
786 |
|
---|
787 | procedure TCustomResourceEntry.SetLanguageId(AValue: integer);
|
---|
788 | begin
|
---|
789 | if (AValue >= 0) and (AValue <= 65535) then
|
---|
790 | begin
|
---|
791 | if AValue = LanguageId then exit;
|
---|
792 | if FTypeNameOrId.Id >= 0 then
|
---|
793 | begin
|
---|
794 | if TWinResourceContainer(Container).InternalFind(FEntryNameOrId, FTypeNameOrId, AValue) <> nil then
|
---|
795 | raise exception.Create('Language id already used for this resource');
|
---|
796 | end else
|
---|
797 | raise exception.Create('Language id cannot be specified for custom types');
|
---|
798 | FEntryNameOrId.Id := AValue;
|
---|
799 | FEntryNameOrId.Name := IntToStr(AValue);
|
---|
800 | end
|
---|
801 | else
|
---|
802 | raise ERangeError.Create('Id out of bounds');
|
---|
803 | end;
|
---|
804 |
|
---|
805 | procedure TCustomResourceEntry.SerializeHeader(ADestination: TStream);
|
---|
806 | var
|
---|
807 | entryHeader: record
|
---|
808 | EntrySize: integer;
|
---|
809 | HeaderSize: integer;
|
---|
810 | end;
|
---|
811 | headerStream: TMemoryStream;
|
---|
812 | begin
|
---|
813 | entryHeader.EntrySize := LEtoN(GetDataSize);
|
---|
814 | headerStream := TMemoryStream.Create;
|
---|
815 | try
|
---|
816 | WriteNameOrId(headerStream,FTypeNameOrId);
|
---|
817 | WriteNameOrId(headerStream,FEntryNameOrId);
|
---|
818 | if headerStream.Position and 3 = 2 then headerStream.WriteWord(0);
|
---|
819 | FResourceInfo.SwapIfNecessary;
|
---|
820 | try
|
---|
821 | headerStream.WriteBuffer(FResourceInfo, sizeof(FResourceInfo));
|
---|
822 | finally
|
---|
823 | FResourceInfo.SwapIfNecessary;
|
---|
824 | end;
|
---|
825 | entryHeader.HeaderSize := LEtoN(integer(headerStream.Size+8));
|
---|
826 | headerStream.Position:= 0;
|
---|
827 | ADestination.WriteBuffer(entryHeader, sizeof(entryHeader));
|
---|
828 | ADestination.CopyFrom(headerStream, headerStream.Size);
|
---|
829 | if headerStream.Size and 3 = 2 then ADestination.WriteWord(0);
|
---|
830 | finally
|
---|
831 | headerStream.Free;
|
---|
832 | end;
|
---|
833 | end;
|
---|
834 |
|
---|
835 | constructor TCustomResourceEntry.Create(AContainer: TMultiFileContainer;
|
---|
836 | ATypeNameOrId: TNameOrId; AEntryNameOrId: TNameOrId;
|
---|
837 | const AResourceInfo: TResourceInfo);
|
---|
838 | begin
|
---|
839 | inherited Create(AContainer);
|
---|
840 | FTypeNameOrId := ATypeNameOrId;
|
---|
841 | FEntryNameOrId := AEntryNameOrId;
|
---|
842 | FResourceInfo := AResourceInfo;
|
---|
843 | end;
|
---|
844 |
|
---|
845 | procedure TCustomResourceEntry.SetId(AValue: integer);
|
---|
846 | begin
|
---|
847 | if (AValue >= 0) and (AValue <= 65535) then
|
---|
848 | begin
|
---|
849 | if AValue = FEntryNameOrId.Id then exit;
|
---|
850 | if TWinResourceContainer(Container).InternalFind(NameOrId(AValue), FTypeNameOrId, LanguageId) <> nil then
|
---|
851 | raise exception.Create('Id already used for this resource type');
|
---|
852 | FEntryNameOrId.Id := AValue;
|
---|
853 | FEntryNameOrId.Name := IntToStr(AValue);
|
---|
854 | end
|
---|
855 | else
|
---|
856 | raise ERangeError.Create('Id out of bounds');
|
---|
857 | end;
|
---|
858 |
|
---|
859 | function TCustomResourceEntry.GetName: utf8string;
|
---|
860 | begin
|
---|
861 | Result:= FEntryNameOrId.Name;
|
---|
862 | end;
|
---|
863 |
|
---|
864 | procedure TCustomResourceEntry.SetName(AValue: utf8string);
|
---|
865 | begin
|
---|
866 | if FEntryNameOrId = NameOrId(AValue) then exit;
|
---|
867 | if TWinResourceContainer(Container).InternalFind(NameOrId(AValue), FTypeNameOrId, LanguageId) <> nil then
|
---|
868 | raise exception.Create('Name already used for this resource type');
|
---|
869 | FEntryNameOrId.Name := AValue;
|
---|
870 | FEntryNameOrId.Id := -1;
|
---|
871 | end;
|
---|
872 |
|
---|
873 | function TCustomResourceEntry.GetTypeName: utf8string;
|
---|
874 | begin
|
---|
875 | result := FTypeNameOrId.Name;
|
---|
876 | end;
|
---|
877 |
|
---|
878 | procedure TCustomResourceEntry.IncrementReferences;
|
---|
879 | begin
|
---|
880 | //nothing
|
---|
881 | end;
|
---|
882 |
|
---|
883 | procedure TCustomResourceEntry.DecrementReferences;
|
---|
884 | begin
|
---|
885 | //nothing
|
---|
886 | end;
|
---|
887 |
|
---|
888 | { TWinResourceContainer }
|
---|
889 |
|
---|
890 | procedure TWinResourceContainer.LoadFromStream(AStream: TStream);
|
---|
891 | var curEntry: TCustomResourceEntry;
|
---|
892 | i: Integer;
|
---|
893 | begin
|
---|
894 | Clear;
|
---|
895 | repeat
|
---|
896 | curEntry := TCustomResourceEntry.GetNextEntry(self, AStream);
|
---|
897 | if curEntry <> nil then
|
---|
898 | begin
|
---|
899 | if curEntry.TypeId in [RT_ICON,RT_CURSOR] then
|
---|
900 | FHiddenEntries.Add(curEntry)
|
---|
901 | else
|
---|
902 | AddEntry(curEntry);
|
---|
903 | end;
|
---|
904 | until curEntry = nil;
|
---|
905 | for i := 0 to Count-1 do
|
---|
906 | TCustomResourceEntry(Entry[i]).IncrementReferences;
|
---|
907 | end;
|
---|
908 |
|
---|
909 | function TWinResourceContainer.IndexOf(AName: utf8string; AExtenstion: utf8string; ACaseSensitive: boolean): integer;
|
---|
910 | begin
|
---|
911 | result := IndexOf(AName, AExtenstion, 0, ACaseSensitive);
|
---|
912 | end;
|
---|
913 |
|
---|
914 | function TWinResourceContainer.IndexOf(AName: utf8string; AExtenstion: utf8string;
|
---|
915 | ALanguageId: integer; ACaseSensitive: boolean): integer;
|
---|
916 | var
|
---|
917 | i: Integer;
|
---|
918 | entryId, errPos: integer;
|
---|
919 | begin
|
---|
920 | if AExtenstion = '' then
|
---|
921 | begin
|
---|
922 | result := -1;
|
---|
923 | exit;
|
---|
924 | end;
|
---|
925 | if ACaseSensitive then
|
---|
926 | begin
|
---|
927 | for i := 0 to Count-1 do
|
---|
928 | if (TCustomResourceEntry(Entry[i]).FEntryNameOrId.Id < 0) and
|
---|
929 | (TCustomResourceEntry(Entry[i]).FEntryNameOrId.Name = AName) and
|
---|
930 | (UTF8CompareText(Entry[i].Extension,AExtenstion) = 0) and
|
---|
931 | (TCustomResourceEntry(Entry[i]).LanguageId = ALanguageId) then
|
---|
932 | begin
|
---|
933 | result := i;
|
---|
934 | exit;
|
---|
935 | end;
|
---|
936 | end else
|
---|
937 | for i := 0 to Count-1 do
|
---|
938 | if (TCustomResourceEntry(Entry[i]).FEntryNameOrId.Id < 0) and
|
---|
939 | (UTF8CompareText(TCustomResourceEntry(Entry[i]).FEntryNameOrId.Name,AName) = 0) and
|
---|
940 | (UTF8CompareText(Entry[i].Extension,AExtenstion) = 0) and
|
---|
941 | (TCustomResourceEntry(Entry[i]).LanguageId = ALanguageId) then
|
---|
942 | begin
|
---|
943 | result := i;
|
---|
944 | exit;
|
---|
945 | end;
|
---|
946 | val(AName, entryId, errPos);
|
---|
947 | if (errPos = 0) and (entryId >= 0) then
|
---|
948 | begin
|
---|
949 | for i := 0 to Count-1 do
|
---|
950 | if (TCustomResourceEntry(Entry[i]).FEntryNameOrId.Id = entryId) and
|
---|
951 | (UTF8CompareText(Entry[i].Extension,AExtenstion) = 0) and
|
---|
952 | (TCustomResourceEntry(Entry[i]).LanguageId = ALanguageId) then
|
---|
953 | begin
|
---|
954 | result := i;
|
---|
955 | exit;
|
---|
956 | end;
|
---|
957 | end;
|
---|
958 | result := -1;
|
---|
959 | end;
|
---|
960 |
|
---|
961 | procedure TWinResourceContainer.Init;
|
---|
962 | begin
|
---|
963 | inherited Init;
|
---|
964 | FHiddenEntries := TMultiFileEntryList.Create;
|
---|
965 | end;
|
---|
966 |
|
---|
967 | procedure TWinResourceContainer.ClearHiddenEntries;
|
---|
968 | var i: integer;
|
---|
969 | begin
|
---|
970 | if Assigned(FHiddenEntries) then
|
---|
971 | begin
|
---|
972 | for i := 0 to FHiddenEntries.Count-1 do
|
---|
973 | FHiddenEntries[i].Free;
|
---|
974 | FHiddenEntries.Clear;
|
---|
975 | end;
|
---|
976 | end;
|
---|
977 |
|
---|
978 | procedure TWinResourceContainer.RemoveHidden(AEntry: TCustomResourceEntry);
|
---|
979 | var
|
---|
980 | index: LongInt;
|
---|
981 | begin
|
---|
982 | if Assigned(FHiddenEntries) then
|
---|
983 | begin
|
---|
984 | index := FHiddenEntries.IndexOf(AEntry);
|
---|
985 | if index <> -1 then
|
---|
986 | begin
|
---|
987 | AEntry.Free;
|
---|
988 | FHiddenEntries.Delete(index);
|
---|
989 | end;
|
---|
990 | end;
|
---|
991 | end;
|
---|
992 |
|
---|
993 | function TWinResourceContainer.CreateEntry(AName: utf8string; AExtension: utf8string;
|
---|
994 | AContent: TStream; ALanguageId: integer): TMultiFileEntry;
|
---|
995 | var
|
---|
996 | resourceInfo: TResourceInfo;
|
---|
997 | entryName: TNameOrId;
|
---|
998 | errPos: integer;
|
---|
999 | begin
|
---|
1000 | FillChar({%H-}resourceInfo, sizeof(resourceInfo), 0);
|
---|
1001 | resourceInfo.LanguageId := ALanguageId;
|
---|
1002 | val(AName, entryName.Id, errPos);
|
---|
1003 | if (errPos = 0) and (entryName.Id >= 0) then
|
---|
1004 | entryName.Name := IntToStr(entryName.Id)
|
---|
1005 | else
|
---|
1006 | begin
|
---|
1007 | entryName.Id := -1;
|
---|
1008 | entryName.Name := AName;
|
---|
1009 | end;
|
---|
1010 |
|
---|
1011 | case UTF8LowerCase(AExtension) of
|
---|
1012 | 'ico': begin
|
---|
1013 | result := TGroupIconEntry.Create(self, entryName, resourceInfo);
|
---|
1014 | AContent.Position:= 0;
|
---|
1015 | TGroupIconEntry(result).CopyFrom(AContent);
|
---|
1016 | AContent.Free;
|
---|
1017 | end;
|
---|
1018 | 'cur': begin
|
---|
1019 | result := TGroupCursorEntry.Create(self, entryName, resourceInfo);
|
---|
1020 | AContent.Position:= 0;
|
---|
1021 | TGroupCursorEntry(result).CopyFrom(AContent);
|
---|
1022 | AContent.Free;
|
---|
1023 | end;
|
---|
1024 | 'bmp': begin
|
---|
1025 | result := TBitmapResourceEntry.Create(self, entryName, resourceInfo, AContent);
|
---|
1026 | AContent.Position:= 0;
|
---|
1027 | TBitmapResourceEntry(result).CopyFrom(AContent);
|
---|
1028 | AContent.Free;
|
---|
1029 | end;
|
---|
1030 | 'dat': result := TUnformattedResourceEntry.Create(self, NameOrId(RT_RCDATA), entryName, resourceInfo, AContent);
|
---|
1031 | 'html','htm': result := TUnformattedResourceEntry.Create(self, NameOrId(RT_HTML), entryName, resourceInfo, AContent);
|
---|
1032 | 'manifest': result := TUnformattedResourceEntry.Create(self, NameOrId(RT_MANIFEST), entryName, resourceInfo, AContent);
|
---|
1033 | 'ani': result := TUnformattedResourceEntry.Create(self, NameOrId(RT_ANICURSOR), entryName, resourceInfo, AContent);
|
---|
1034 | else
|
---|
1035 | case SuggestImageFormat('.'+AExtension) of
|
---|
1036 | ifUnknown: raise exception.Create('Unhandled file extension');
|
---|
1037 | else
|
---|
1038 | result := TUnformattedResourceEntry.Create(self, NameOrId(RT_RCDATA), entryName, resourceInfo, AContent);
|
---|
1039 | end;
|
---|
1040 | end;
|
---|
1041 | end;
|
---|
1042 |
|
---|
1043 | function TWinResourceContainer.CreateEntry(AName: utf8string; AExtension: utf8string;
|
---|
1044 | AContent: TStream): TMultiFileEntry;
|
---|
1045 | begin
|
---|
1046 | result := CreateEntry(AName, AExtension, AContent, 0);
|
---|
1047 | end;
|
---|
1048 |
|
---|
1049 | procedure TWinResourceContainer.Clear;
|
---|
1050 | begin
|
---|
1051 | ClearHiddenEntries;
|
---|
1052 | inherited Clear;
|
---|
1053 | end;
|
---|
1054 |
|
---|
1055 | destructor TWinResourceContainer.Destroy;
|
---|
1056 | begin
|
---|
1057 | ClearHiddenEntries;
|
---|
1058 | FreeAndNil(FHiddenEntries);
|
---|
1059 | inherited Destroy;
|
---|
1060 | end;
|
---|
1061 |
|
---|
1062 | procedure TWinResourceContainer.Delete(AIndex: integer);
|
---|
1063 | begin
|
---|
1064 | if (AIndex >= 0) and (AIndex < Count) then
|
---|
1065 | TCustomResourceEntry(Entry[AIndex]).DecrementReferences;
|
---|
1066 | inherited Delete(AIndex);
|
---|
1067 | end;
|
---|
1068 |
|
---|
1069 | procedure TWinResourceContainer.SaveToStream(ADestination: TStream);
|
---|
1070 | var
|
---|
1071 | i: Integer;
|
---|
1072 | begin
|
---|
1073 | for i := 0 to Count-1 do
|
---|
1074 | TCustomResourceEntry(Entry[i]).Serialize(ADestination);
|
---|
1075 | for i := 0 to FHiddenEntries.Count-1 do
|
---|
1076 | TCustomResourceEntry(FHiddenEntries.Items[i]).Serialize(ADestination);
|
---|
1077 | end;
|
---|
1078 |
|
---|
1079 | function TWinResourceContainer.InternalFind(const AEntry: TNameOrId;
|
---|
1080 | const AType: TNameOrId; ALanguageId: integer): TCustomResourceEntry;
|
---|
1081 | var i: integer;
|
---|
1082 | begin
|
---|
1083 | if Assigned(FHiddenEntries) and (ALanguageId = 0) and (AType.Id >= 0) then
|
---|
1084 | begin
|
---|
1085 | for i := 0 to FHiddenEntries.Count-1 do
|
---|
1086 | if (TCustomResourceEntry(FHiddenEntries.Items[i]).FEntryNameOrId = AEntry) and
|
---|
1087 | (TCustomResourceEntry(FHiddenEntries.Items[i]).FTypeNameOrId = AType) then
|
---|
1088 | begin
|
---|
1089 | result := TCustomResourceEntry(FHiddenEntries.Items[i]);
|
---|
1090 | exit;
|
---|
1091 | end;
|
---|
1092 | end;
|
---|
1093 | for i := 0 to Count-1 do
|
---|
1094 | if (TCustomResourceEntry(Entry[i]).FEntryNameOrId = AEntry) and
|
---|
1095 | (TCustomResourceEntry(Entry[i]).FTypeNameOrId = AType) and
|
---|
1096 | (TCustomResourceEntry(Entry[i]).LanguageId = ALanguageId) then
|
---|
1097 | begin
|
---|
1098 | result := TCustomResourceEntry(Entry[i]);
|
---|
1099 | exit;
|
---|
1100 | end;
|
---|
1101 | result := nil;
|
---|
1102 | end;
|
---|
1103 |
|
---|
1104 | procedure TWinResourceContainer.AddHidden(AEntry: TCustomResourceEntry);
|
---|
1105 | begin
|
---|
1106 | FHiddenEntries.Add(AEntry);
|
---|
1107 | end;
|
---|
1108 |
|
---|
1109 | function TWinResourceContainer.GetMaxId(AType: TNameOrId): integer;
|
---|
1110 | var i: integer;
|
---|
1111 | begin
|
---|
1112 | result := 0;
|
---|
1113 | if Assigned(FHiddenEntries) and (AType.Id >= 0) then
|
---|
1114 | begin
|
---|
1115 | for i := 0 to FHiddenEntries.Count-1 do
|
---|
1116 | if (TCustomResourceEntry(FHiddenEntries.Items[i]).FTypeNameOrId = AType) then
|
---|
1117 | begin
|
---|
1118 | if TCustomResourceEntry(FHiddenEntries.Items[i]).Id > result then result := TCustomResourceEntry(FHiddenEntries.Items[i]).Id;
|
---|
1119 | end;
|
---|
1120 | end;
|
---|
1121 | for i := 0 to Count-1 do
|
---|
1122 | if (TCustomResourceEntry(Entry[i]).FTypeNameOrId = AType) then
|
---|
1123 | begin
|
---|
1124 | if TCustomResourceEntry(Entry[i]).Id > result then result := TCustomResourceEntry(Entry[i]).Id;
|
---|
1125 | end;
|
---|
1126 | end;
|
---|
1127 |
|
---|
1128 | procedure TWinResourceContainer.IncrementReferenceOf(ANameId, ATypeId: integer);
|
---|
1129 | var
|
---|
1130 | item: TCustomResourceEntry;
|
---|
1131 | begin
|
---|
1132 | item := InternalFind(NameOrId(ANameId), NameOrId(ATypeId));
|
---|
1133 | if Assigned(item) then inc(item.FReferenceCount);
|
---|
1134 | end;
|
---|
1135 |
|
---|
1136 | procedure TWinResourceContainer.DecrementReferenceOf(ANameId, ATypeId: integer);
|
---|
1137 | var
|
---|
1138 | item: TCustomResourceEntry;
|
---|
1139 | begin
|
---|
1140 | item := InternalFind(NameOrId(ANameId), NameOrId(ATypeId));
|
---|
1141 | if Assigned(item) then
|
---|
1142 | begin
|
---|
1143 | if item.FReferenceCount > 1 then
|
---|
1144 | dec(item.FReferenceCount)
|
---|
1145 | else
|
---|
1146 | RemoveHidden(item);
|
---|
1147 | end;
|
---|
1148 | end;
|
---|
1149 |
|
---|
1150 | end.
|
---|
1151 |
|
---|