GLS.PersistentClasses.pas 45 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813
  1. //
  2. // The graphics engine GLScene https://github.com/glscene
  3. //
  4. unit GLS.PersistentClasses;
  5. (*
  6. Base persistence classes.
  7. The registered class is:
  8. [TGLPersistentObjectList]
  9. These classes are used in GLScene but are designed for generic purpose.
  10. They implement a slightly different persistence mechanism then that of the VCL,
  11. allowing for object-level versioning (100% backward compatibility) and full
  12. polymorphic persistence.
  13. Internal Note: stripped down versions of XClasses & XLists.
  14. *)
  15. interface
  16. uses
  17. System.Classes,
  18. System.SysUtils,
  19. GLScene.Strings;
  20. type
  21. PObject = ^TObject;
  22. //Virtual layer similar to VCL's TReader (but reusable)
  23. TGLVirtualReader = class
  24. private
  25. FStream: TStream;
  26. public
  27. constructor Create(Stream: TStream); virtual;
  28. property Stream: TStream read FStream;
  29. procedure ReadTypeError;
  30. procedure Read(var Buf; Count: Longint); virtual; abstract;
  31. function NextValue: TValueType; virtual; abstract;
  32. function ReadInteger: Integer; virtual; abstract;
  33. function ReadBoolean: Boolean; virtual; abstract;
  34. function ReadString: String; virtual; abstract;
  35. function ReadFloat: Extended; virtual; abstract;
  36. procedure ReadListBegin; virtual; abstract;
  37. procedure ReadListEnd; virtual; abstract;
  38. function EndOfList: Boolean; virtual; abstract;
  39. procedure ReadTStrings(aStrings: TStrings);
  40. end;
  41. //Virtual layer similar to VCL's TWriter (but reusable)
  42. TGLVirtualWriter = class
  43. private
  44. FStream: TStream;
  45. public
  46. constructor Create(Stream: TStream); virtual;
  47. property Stream: TStream read FStream;
  48. procedure Write(const Buf; Count: Longint); virtual; abstract;
  49. procedure WriteInteger(anInteger: Integer); virtual; abstract;
  50. procedure WriteBoolean(aBoolean: Boolean); virtual; abstract;
  51. procedure WriteString(const aString: string); virtual; abstract;
  52. procedure WriteFloat(const aFloat: Extended); virtual; abstract;
  53. procedure WriteListBegin; virtual; abstract;
  54. procedure WriteListEnd; virtual; abstract;
  55. procedure WriteTStrings(const aStrings: TStrings; storeObjects: Boolean = True);
  56. end;
  57. TGLVirtualReaderClass = class of TGLVirtualReader;
  58. TGLVirtualWriterClass = class of TGLVirtualWriter;
  59. (*Interface for persistent objects.
  60. This interface does not really allow polymorphic persistence,
  61. but is rather intended as a way to unify persistence calls for iterators *)
  62. IGLPersistentObject = interface(IInterface)
  63. ['{A9A0198A-F11B-4325-A92C-2F24DB41652B}']
  64. procedure WriteToFiler(writer: TGLVirtualWriter);
  65. procedure ReadFromFiler(reader: TGLVirtualReader);
  66. end;
  67. (* Base class for persistent objects.
  68. The base requirement is implementation of ReadFromFiler & WriteToFiler
  69. in sub-classes, the immediate benefits are support of streaming (to stream,
  70. file or string), assignment and cloning.
  71. The other requirement being the use of a virtual constructor, which allows
  72. polymorphic construction (don't forget to register your subclasses).
  73. Note that TGLPersistentObject implements IUnknown, but does *not* implement
  74. reference counting *)
  75. TGLPersistentObject = class(TPersistent, IGLPersistentObject)
  76. protected
  77. procedure RaiseFilerException(const archiveVersion: Integer);
  78. function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
  79. function _AddRef: Integer; stdcall;
  80. function _Release: Integer; stdcall;
  81. public
  82. constructor Create; virtual;
  83. constructor CreateFromFiler(reader: TGLVirtualReader);
  84. destructor Destroy; override;
  85. procedure Assign(source: TPersistent); override;
  86. function CreateClone: TGLPersistentObject; dynamic;
  87. class function FileSignature: string; virtual;
  88. class function FileVirtualWriter: TGLVirtualWriterClass; virtual;
  89. class function FileVirtualReader: TGLVirtualReaderClass; virtual;
  90. procedure WriteToFiler(writer: TGLVirtualWriter); dynamic;
  91. procedure ReadFromFiler(reader: TGLVirtualReader); dynamic;
  92. procedure SaveToStream(stream: TStream; writerClass: TGLVirtualWriterClass = nil); dynamic;
  93. procedure LoadFromStream(stream: TStream; readerClass: TGLVirtualReaderClass = nil); dynamic;
  94. procedure SaveToFile(const fileName: string; writerClass: TGLVirtualWriterClass = nil); dynamic;
  95. procedure LoadFromFile(const fileName: string; readerClass: TGLVirtualReaderClass = nil); dynamic;
  96. function SaveToString(writerClass: TGLVirtualWriterClass = nil): string; dynamic;
  97. procedure LoadFromString(const data: string; readerClass: TGLVirtualReaderClass = nil); dynamic;
  98. end;
  99. TGLPersistentObjectClass = class of TGLPersistentObject;
  100. PPointerObjectList = ^TPointerObjectList;
  101. TPointerObjectList = array[0..MaxInt div (2*SizeOf(Pointer))] of TObject;
  102. TObjectListSortCompare = function(item1, item2: TObject): Integer;
  103. (*A persistent Object list.
  104. Similar to TList but works on TObject items and has facilities for
  105. persistence of contained data. Unlike the VCL's TObjectList, this one
  106. does NOT free its objects upon destruction or Clear, use Clean and CleanFree
  107. for that, and as such can be used for object referral lists too.
  108. But only TGLPersistentObject items will be streamed appropriately.
  109. The list can be used in a stack-like fashion with Push & Pop, and can
  110. perform basic boolean set operations.
  111. Note: the IndexOf implementation is up to 3 times faster than that of TList *)
  112. TGLPersistentObjectList = class(TGLPersistentObject)
  113. private
  114. FList: PPointerObjectList;
  115. FCount: Integer;
  116. FCapacity: Integer;
  117. FGrowthDelta: Integer;
  118. protected
  119. procedure Error; virtual;
  120. function Get(Index: Integer): TObject; inline;
  121. procedure Put(Index: Integer; Item: TObject);
  122. procedure SetCapacity(newCapacity: Integer); inline;
  123. procedure SetCount(NewCount: Integer); inline;
  124. function GetFirst: TObject; inline;
  125. procedure SetFirst(item: TObject);
  126. function GetLast: TObject;
  127. procedure SetLast(item: TObject);
  128. // Default event for ReadFromFiler
  129. procedure AfterObjectCreatedByReader(Sender: TObject); virtual;
  130. procedure DoClean;
  131. public
  132. constructor Create; override;
  133. destructor Destroy; override;
  134. procedure WriteToFiler(writer: TGLVirtualWriter); override;
  135. procedure ReadFromFiler(reader: TGLVirtualReader); override;
  136. procedure ReadFromFilerWithEvent(reader: TGLVirtualReader;
  137. afterSenderObjectCreated: TNotifyEvent);
  138. function Add(const item: TObject): Integer; inline;
  139. procedure AddNils(nbVals: Cardinal);
  140. procedure Delete(index: Integer);
  141. procedure DeleteItems(index: Integer; nbVals: Cardinal);
  142. procedure Exchange(Index1, Index2: Integer);
  143. procedure Insert(Index: Integer; Item: TObject);
  144. procedure InsertNils(index: Integer; nbVals: Cardinal);
  145. procedure Move(CurIndex, NewIndex: Integer);
  146. function Remove(Item: TObject): Integer;
  147. procedure DeleteAndFree(index: Integer);
  148. procedure DeleteAndFreeItems(index: Integer; nbVals: Cardinal);
  149. function RemoveAndFree(item: TObject): Integer;
  150. property GrowthDelta: integer read FGrowthDelta write FGrowthDelta;
  151. function Expand: TGLPersistentObjectList;
  152. property Items[Index: Integer]: TObject read Get write Put; default;
  153. property Count: Integer read FCount write SetCount;
  154. property List: PPointerObjectList read FList;
  155. property Capacity: Integer read FCapacity write SetCapacity;
  156. //Makes sure capacity is at least aCapacity.
  157. procedure RequiredCapacity(aCapacity: Integer);
  158. (*Removes all "nil" from the list.
  159. Note: Capacity is unchanged, no memory us freed, the list is just
  160. made shorter. This functions is orders of magnitude faster than
  161. its TList eponymous. *)
  162. procedure Pack;
  163. //Empty the list without freeing the objects.
  164. procedure Clear; virtual;
  165. //Empty the list and free the objects.
  166. procedure Clean; virtual;
  167. //Empty the list, free the objects and Free self.
  168. procedure CleanFree;
  169. function IndexOf(Item: TObject): Integer;
  170. property First: TObject read GetFirst write SetFirst;
  171. property Last: TObject read GetLast write SetLast;
  172. procedure Push(item: TObject);
  173. function Pop: TObject;
  174. procedure PopAndFree;
  175. function AddObjects(const objectList: TGLPersistentObjectList): Integer;
  176. procedure RemoveObjects(const objectList: TGLPersistentObjectList);
  177. procedure Sort(compareFunc: TObjectListSortCompare);
  178. end;
  179. //Wraps a TReader-compatible reader.
  180. TGLBinaryReader = class(TGLVirtualReader)
  181. protected
  182. function ReadValue: TValueType;
  183. function ReadWideString(vType: TValueType): WideString;
  184. public
  185. procedure Read(var Buf; Count: Longint); override;
  186. function NextValue: TValueType; override;
  187. function ReadInteger: Integer; override;
  188. function ReadBoolean: Boolean; override;
  189. function ReadString: string; override;
  190. function ReadFloat: Extended; override;
  191. procedure ReadListBegin; override;
  192. procedure ReadListEnd; override;
  193. function EndOfList: Boolean; override;
  194. end;
  195. //Wraps a TWriter-compatible writer.
  196. TGLBinaryWriter = class(TGLVirtualWriter)
  197. protected
  198. procedure WriteAnsiString(const aString: AnsiString); virtual;
  199. procedure WriteWideString(const aString: WideString); virtual;
  200. public
  201. procedure Write(const Buf; Count: Longint); override;
  202. procedure WriteInteger(anInteger: Integer); override;
  203. procedure WriteBoolean(aBoolean: Boolean); override;
  204. procedure WriteString(const aString: string); override;
  205. procedure WriteFloat(const aFloat: Extended); override;
  206. procedure WriteListBegin; override;
  207. procedure WriteListEnd; override;
  208. end;
  209. //Reads object persistence in Text format.
  210. TGLTextReader = class(TGLVirtualReader)
  211. private
  212. FValueType: string;
  213. FData: string;
  214. protected
  215. procedure ReadLine(const requestedType: string = '');
  216. public
  217. procedure Read(var Buf; Count: Longint); override;
  218. function NextValue: TValueType; override;
  219. function ReadInteger: Integer; override;
  220. function ReadBoolean: Boolean; override;
  221. function ReadString: string; override;
  222. function ReadFloat: Extended; override;
  223. procedure ReadListBegin; override;
  224. procedure ReadListEnd; override;
  225. function EndOfList: Boolean; override;
  226. end;
  227. //Writes object persistence in Text format.
  228. TGLTextWriter = class(TGLVirtualWriter)
  229. private
  230. FIndentLevel: Integer;
  231. protected
  232. procedure WriteLine(const valueType, data: string);
  233. public
  234. constructor Create(aStream: TStream); override;
  235. destructor Destroy; override;
  236. procedure Write(const Buf; Count: Longint); override;
  237. procedure WriteInteger(anInteger: Integer); override;
  238. procedure WriteBoolean(aBoolean: Boolean); override;
  239. procedure WriteString(const aString: string); override;
  240. procedure WriteFloat(const aFloat: Extended); override;
  241. procedure WriteListBegin; override;
  242. procedure WriteListEnd; override;
  243. end;
  244. //TPersistent which has knowledge of its owner.
  245. TGLOwnedPersistent = class(TPersistent)
  246. private
  247. FOwner: TPersistent;
  248. protected
  249. function GetOwner: TPersistent; override;
  250. public
  251. constructor Create(AOwner: TPersistent); virtual;
  252. end;
  253. //TPersistent that inplements IInterface.
  254. TGLInterfacedPersistent = class(TPersistent, IInterface)
  255. protected
  256. // Implementing IInterface.
  257. function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
  258. function _AddRef: Integer; stdcall;
  259. function _Release: Integer; stdcall;
  260. end;
  261. //TCollectionItem thet inplements IInterface.
  262. TGLInterfacedCollectionItem = class(TCollectionItem, IInterface)
  263. protected
  264. // Implementing IInterface.
  265. function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
  266. function _AddRef: Integer; stdcall;
  267. function _Release: Integer; stdcall;
  268. end;
  269. //Triggered when file signature does not match.
  270. EInvalidFileSignature = class(Exception)
  271. end;
  272. //Usually triggered when a filing error is detected.
  273. EFilerException = class(Exception)
  274. end;
  275. procedure RaiseFilerException(aClass: TClass; archiveVersion: Integer);
  276. function UTF8ToWideString(const s: AnsiString): WideString;
  277. // ------------------------------------------------------------------
  278. implementation
  279. // ------------------------------------------------------------------
  280. const
  281. cDefaultListGrowthDelta = 64;
  282. cVTInteger = 'Int';
  283. cVTFloat = 'Float';
  284. cVTString = 'Str';
  285. cVTBoolean = 'Bool';
  286. cVTRaw = 'Raw';
  287. cVTListBegin = '{';
  288. cVTListEnd = '}';
  289. cTrue = 'True';
  290. cFalse = 'False';
  291. procedure RaiseFilerException(aClass: TClass; archiveVersion: Integer);
  292. begin
  293. raise EFilerException.Create(aClass.ClassName +
  294. strUnknownArchiveVersion + IntToStr(archiveVersion));
  295. end;
  296. function UTF8ToWideString(const s: AnsiString): WideString;
  297. const
  298. bytesFromUTF8: packed array[0..255] of Byte = (
  299. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  300. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  301. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  302. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  303. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  304. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  305. 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
  306. 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5);
  307. offsetsFromUTF8: array[0..5] of Cardinal = (
  308. $00000000, $00003080, $000E2080, $03C82080, $FA082080, $82082080);
  309. MaximumUCS2: Cardinal = $0000FFFF;
  310. MaximumUCS4: Cardinal = $7FFFFFFF;
  311. ReplacementCharacter: Cardinal = $0000FFFD;
  312. halfShift: Integer = 10;
  313. halfBase: Cardinal = $0010000;
  314. halfMask: Cardinal = $3FF;
  315. SurrogateHighStart: Cardinal = $D800;
  316. SurrogateLowStart: Cardinal = $DC00;
  317. var
  318. sLength, L, J, T: Cardinal;
  319. ch: Cardinal;
  320. extraBytesToWrite: Word;
  321. begin
  322. sLength := Length(s);
  323. if sLength = 0 then
  324. begin
  325. Result := '';
  326. Exit;
  327. end;
  328. SetLength(Result, sLength); // creates enough room
  329. L := 1;
  330. T := 1;
  331. while L <= Cardinal(sLength) do
  332. begin
  333. ch := 0;
  334. extraBytesToWrite := bytesFromUTF8[Ord(S[L])];
  335. for J := extraBytesToWrite downto 1 do
  336. begin
  337. ch := ch + Ord(S[L]);
  338. Inc(L);
  339. ch := ch shl 6;
  340. end;
  341. ch := ch + Ord(S[L]);
  342. Inc(L);
  343. ch := ch - offsetsFromUTF8[extraBytesToWrite];
  344. if ch <= MaximumUCS2 then
  345. begin
  346. Result[T] := WideChar(ch);
  347. Inc(T);
  348. end
  349. else if ch > MaximumUCS4 then
  350. begin
  351. Result[T] := WideChar(ReplacementCharacter);
  352. Inc(T);
  353. end
  354. else
  355. begin
  356. ch := ch - halfBase;
  357. Result[T] := WideChar((ch shr halfShift) + SurrogateHighStart);
  358. Inc(T);
  359. Result[T] := WideChar((ch and halfMask) + SurrogateLowStart);
  360. Inc(T);
  361. end;
  362. end;
  363. SetLength(Result, T - 1); // now fix up length
  364. end;
  365. // ------------------
  366. // ------------------ TGLVirtualReader ------------------
  367. // ------------------
  368. constructor TGLVirtualReader.Create(Stream: TStream);
  369. begin
  370. FStream := Stream;
  371. end;
  372. procedure TGLVirtualReader.ReadTypeError;
  373. begin
  374. raise EReadError.CreateFmt('%s, read type error', [ClassName]);
  375. end;
  376. procedure TGLVirtualReader.ReadTStrings(aStrings: TStrings);
  377. var
  378. i: Integer;
  379. objectsStored: Boolean;
  380. begin
  381. aStrings.BeginUpdate;
  382. aStrings.Clear;
  383. objectsStored := ReadBoolean;
  384. i := ReadInteger;
  385. if objectsStored then
  386. while i > 0 do
  387. begin
  388. aStrings.AddObject(ReadString, TObject(ReadInteger));
  389. Dec(i);
  390. end
  391. else
  392. while i > 0 do
  393. begin
  394. aStrings.Add(ReadString);
  395. Dec(i);
  396. end;
  397. aStrings.EndUpdate;
  398. end;
  399. // ------------------
  400. // ------------------ TGLVirtualWriter ------------------
  401. // ------------------
  402. constructor TGLVirtualWriter.Create(Stream: TStream);
  403. begin
  404. FStream := Stream;
  405. end;
  406. procedure TGLVirtualWriter.WriteTStrings(const aStrings: TStrings;
  407. storeObjects: Boolean = True);
  408. var
  409. i: Integer;
  410. begin
  411. writeBoolean(storeObjects);
  412. if Assigned(aStrings) then
  413. begin
  414. WriteInteger(aStrings.Count);
  415. if storeObjects then
  416. for i := 0 to aStrings.Count - 1 do
  417. begin
  418. WriteString(aStrings[i]);
  419. WriteInteger(Integer(aStrings.Objects[i]));
  420. end
  421. else
  422. for i := 0 to aStrings.Count - 1 do
  423. WriteString(aStrings[i]);
  424. end
  425. else
  426. WriteInteger(0);
  427. end;
  428. // ------------------
  429. // ------------------ TGLPersistentObject ------------------
  430. // ------------------
  431. constructor TGLPersistentObject.Create;
  432. begin
  433. inherited Create;
  434. end;
  435. constructor TGLPersistentObject.CreateFromFiler(reader: TGLVirtualReader);
  436. begin
  437. Create;
  438. ReadFromFiler(reader);
  439. end;
  440. destructor TGLPersistentObject.Destroy;
  441. begin
  442. inherited Destroy;
  443. end;
  444. procedure TGLPersistentObject.Assign(source: TPersistent);
  445. var
  446. ms: TStringStream; // faster than a TMemoryStream...
  447. begin
  448. if source.ClassType = Self.ClassType then
  449. begin
  450. ms := TStringStream.Create('');
  451. try
  452. TGLPersistentObject(source).SaveToStream(ms);
  453. ms.Position := 0;
  454. LoadFromStream(ms);
  455. finally
  456. ms.Free;
  457. end;
  458. end
  459. else
  460. inherited;
  461. end;
  462. function TGLPersistentObject.CreateClone: TGLPersistentObject;
  463. begin
  464. Result := TGLPersistentObjectClass(Self.ClassType).Create;
  465. Result.Assign(Self);
  466. end;
  467. class function TGLPersistentObject.FileSignature: string;
  468. begin
  469. Result := '';
  470. end;
  471. class function TGLPersistentObject.FileVirtualWriter: TGLVirtualWriterClass;
  472. begin
  473. Result := TGLBinaryWriter;
  474. end;
  475. class function TGLPersistentObject.FileVirtualReader: TGLVirtualReaderClass;
  476. begin
  477. Result := TGLBinaryReader;
  478. end;
  479. procedure TGLPersistentObject.WriteToFiler(writer: TGLVirtualWriter);
  480. begin
  481. // nothing
  482. Assert(Assigned(writer));
  483. end;
  484. procedure TGLPersistentObject.ReadFromFiler(reader: TGLVirtualReader);
  485. begin
  486. // nothing
  487. Assert(Assigned(reader));
  488. end;
  489. procedure TGLPersistentObject.RaiseFilerException(const archiveVersion: Integer);
  490. begin
  491. raise EFilerException.Create(ClassName + strUnknownArchiveVersion + IntToStr(archiveVersion)); //IGNORE
  492. end;
  493. function TGLPersistentObject.QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
  494. begin
  495. if GetInterface(IID, Obj) then
  496. Result := S_OK
  497. else
  498. Result := E_NOINTERFACE;
  499. end;
  500. function TGLPersistentObject._AddRef: Integer; stdcall;
  501. begin
  502. // ignore
  503. Result := 1;
  504. end;
  505. function TGLPersistentObject._Release: Integer; stdcall;
  506. begin
  507. // ignore
  508. Result := 0;
  509. end;
  510. procedure TGLPersistentObject.SaveToStream(stream: TStream; writerClass: TGLVirtualWriterClass = nil);
  511. var
  512. wr: TGLVirtualWriter;
  513. fileSig: AnsiString;
  514. begin
  515. if writerClass = nil then
  516. writerClass := TGLBinaryWriter;
  517. wr := writerClass.Create(stream);
  518. try
  519. if FileSignature <> '' then
  520. begin
  521. fileSig := AnsiString(FileSignature);
  522. wr.Write(fileSig[1], Length(fileSig));
  523. end;
  524. WriteToFiler(wr);
  525. finally
  526. wr.Free;
  527. end;
  528. end;
  529. procedure TGLPersistentObject.LoadFromStream(stream: TStream; readerClass: TGLVirtualReaderClass = nil);
  530. var
  531. rd: TGLVirtualReader;
  532. sig: AnsiString;
  533. begin
  534. if readerClass = nil then
  535. readerClass := TGLBinaryReader;
  536. rd := readerClass.Create(stream);
  537. try
  538. if FileSignature <> '' then
  539. begin
  540. SetLength(sig, Length(FileSignature));
  541. rd.Read(sig[1], Length(FileSignature));
  542. if sig <> AnsiString(FileSignature) then
  543. raise EInvalidFileSignature.Create(strInvalidFileSignature);
  544. end;
  545. ReadFromFiler(rd);
  546. finally
  547. rd.Free;
  548. end;
  549. end;
  550. procedure TGLPersistentObject.SaveToFile(const fileName: string; writerClass: TGLVirtualWriterClass = nil);
  551. var
  552. fs: TStream;
  553. begin
  554. if writerClass = nil then
  555. writerClass := FileVirtualWriter;
  556. fs := TFileStream.Create(fileName, fmCreate);
  557. try
  558. SaveToStream(fs, writerClass);
  559. finally
  560. fs.Free;
  561. end;
  562. end;
  563. procedure TGLPersistentObject.LoadFromFile(const fileName: string; readerClass: TGLVirtualReaderClass = nil);
  564. var
  565. fs: TStream;
  566. begin
  567. if readerClass = nil then
  568. readerClass := FileVirtualReader;
  569. fs := TFileStream.Create(fileName, fmOpenRead + fmShareDenyWrite);
  570. try
  571. LoadFromStream(fs, readerClass);
  572. finally
  573. fs.Free;
  574. end;
  575. end;
  576. function TGLPersistentObject.SaveToString(writerClass: TGLVirtualWriterClass = nil): string;
  577. var
  578. ss: TStringStream;
  579. begin
  580. ss := TStringStream.Create('');
  581. try
  582. SaveToStream(ss, writerClass);
  583. Result := ss.DataString;
  584. finally
  585. ss.Free;
  586. end;
  587. end;
  588. procedure TGLPersistentObject.LoadFromString(const data: string; readerClass: TGLVirtualReaderClass = nil);
  589. var
  590. ss: TStringStream;
  591. begin
  592. ss := TStringStream.Create(data);
  593. try
  594. LoadFromStream(ss, readerClass);
  595. finally
  596. ss.Free;
  597. end;
  598. end;
  599. // ------------------
  600. // ------------------ TGLPersistentObjectList ------------------
  601. // ------------------
  602. constructor TGLPersistentObjectList.Create;
  603. begin
  604. inherited Create;
  605. FGrowthDelta := cDefaultListGrowthDelta;
  606. end;
  607. destructor TGLPersistentObjectList.Destroy;
  608. begin
  609. Clear;
  610. inherited Destroy;
  611. end;
  612. function TGLPersistentObjectList.Add(const item: TObject): Integer;
  613. begin
  614. Result := FCount;
  615. if Result = FCapacity then
  616. SetCapacity(FCapacity + FGrowthDelta);
  617. FList^[Result] := Item;
  618. Inc(FCount);
  619. end;
  620. procedure TGLPersistentObjectList.AddNils(nbVals: Cardinal);
  621. begin
  622. if Integer(nbVals) + Count > Capacity then
  623. SetCapacity(Integer(nbVals) + Count);
  624. FillChar(FList[FCount], Integer(nbVals) * SizeOf(TObject), 0);
  625. FCount := FCount + Integer(nbVals);
  626. end;
  627. function TGLPersistentObjectList.AddObjects(const objectList: TGLPersistentObjectList): Integer;
  628. begin
  629. if Assigned(objectList) then
  630. begin
  631. Result := FCount;
  632. SetCount(Result + objectList.Count);
  633. System.Move(objectList.FList^[0], FList^[Result],
  634. objectList.FCount * SizeOf(TObject));
  635. end
  636. else
  637. Result := 0;
  638. end;
  639. procedure TGLPersistentObjectList.RemoveObjects(const objectList: TGLPersistentObjectList);
  640. var
  641. i: Integer;
  642. begin
  643. for i := 0 to objectList.Count - 1 do
  644. Remove(objectList[i]);
  645. end;
  646. procedure TGLPersistentObjectList.Clear;
  647. begin
  648. if Assigned(Self) and Assigned(FList) then
  649. begin
  650. SetCount(0);
  651. SetCapacity(0);
  652. end;
  653. end;
  654. procedure TGLPersistentObjectList.Delete(index: Integer);
  655. begin
  656. {$IFOPT R+}
  657. if Cardinal(Index) >= Cardinal(FCount) then
  658. Error;
  659. {$ENDIF}
  660. Dec(FCount);
  661. if index < FCount then
  662. System.Move(FList[index + 1], FList[index], (FCount - index) * SizeOf(TObject));
  663. end;
  664. procedure TGLPersistentObjectList.DeleteItems(index: Integer; nbVals: Cardinal);
  665. begin
  666. {$IFOPT R+}
  667. Assert(Cardinal(index) < Cardinal(FCount));
  668. {$ENDIF}
  669. if nbVals > 0 then
  670. begin
  671. if index + Integer(nbVals) < FCount then
  672. begin
  673. System.Move(FList[index + Integer(nbVals)],
  674. FList[index],
  675. (FCount - index - Integer(nbVals)) * SizeOf(TObject));
  676. end;
  677. Dec(FCount, nbVals);
  678. end;
  679. end;
  680. procedure TGLPersistentObjectList.Exchange(index1, index2: Integer);
  681. var
  682. item: TObject;
  683. locList: PPointerObjectList;
  684. begin
  685. {$IFOPT R+}
  686. if (Cardinal(Index1) >= Cardinal(FCount)) or
  687. (Cardinal(Index2) >= Cardinal(FCount)) then
  688. Error;
  689. {$ENDIF}
  690. locList := FList;
  691. item := locList^[index1];
  692. locList^[index1] := locList^[index2];
  693. locList^[index2] := item;
  694. end;
  695. function TGLPersistentObjectList.Expand: TGLPersistentObjectList;
  696. begin
  697. if FCount = FCapacity then
  698. SetCapacity(FCapacity + FGrowthDelta);
  699. Result := Self;
  700. end;
  701. function TGLPersistentObjectList.GetFirst: TObject;
  702. begin
  703. {$IFOPT R+}
  704. if Cardinal(FCount) = 0 then
  705. Error;
  706. {$ENDIF}
  707. Result := FList^[0];
  708. end;
  709. procedure TGLPersistentObjectList.SetFirst(item: TObject);
  710. begin
  711. {$IFOPT R+}
  712. if Cardinal(FCount) = 0 then
  713. Error;
  714. {$ENDIF}
  715. FList^[0] := item;
  716. end;
  717. procedure TGLPersistentObjectList.Error;
  718. begin
  719. raise EListError.Create(strListIndexError);
  720. end;
  721. function TGLPersistentObjectList.Get(Index: Integer): TObject;
  722. begin
  723. {$IFOPT R+}
  724. if Cardinal(Index) >= Cardinal(FCount) then
  725. Error;
  726. {$ENDIF}
  727. Result := FList^[Index];
  728. end;
  729. // IndexOf
  730. //
  731. function TGLPersistentObjectList.IndexOf(Item: TObject): Integer;
  732. var
  733. I: Integer;
  734. begin
  735. if FCount <= 0 then
  736. Result := -1
  737. else
  738. begin
  739. Result := -1;
  740. for I := 0 to FCount - 1 do
  741. if FList^[I] = Item then
  742. begin
  743. Result := I;
  744. Exit;
  745. end;
  746. end;
  747. end;
  748. procedure TGLPersistentObjectList.Insert(index: Integer; item: TObject);
  749. begin
  750. {$IFOPT R+}
  751. if Cardinal(index) > Cardinal(FCount) then
  752. Error;
  753. {$ENDIF}
  754. if FCount = FCapacity then
  755. SetCapacity(FCapacity + FGrowthDelta);
  756. if Index < FCount then
  757. System.Move(FList[index], FList[index + 1],
  758. (FCount - index) * SizeOf(TObject));
  759. FList^[index] := item;
  760. Inc(FCount);
  761. end;
  762. procedure TGLPersistentObjectList.InsertNils(index: Integer; nbVals: Cardinal);
  763. var
  764. nc: Integer;
  765. begin
  766. {$IFOPT R+}
  767. Assert(Cardinal(Index) <= Cardinal(FCount));
  768. {$ENDIF}
  769. if nbVals > 0 then
  770. begin
  771. nc := FCount + Integer(nbVals);
  772. if nc > FCapacity then
  773. SetCapacity(nc);
  774. if Index < FCount then
  775. System.Move(FList[Index], FList[Index + Integer(nbVals)],
  776. (FCount - Index) * SizeOf(TObject));
  777. FillChar(FList[Index], Integer(nbVals) * SizeOf(TObject), 0);
  778. FCount := nc;
  779. end;
  780. end;
  781. function TGLPersistentObjectList.GetLast: TObject;
  782. begin
  783. {$IFOPT R+}
  784. if Cardinal(FCount) = 0 then
  785. Error;
  786. {$ENDIF}
  787. Result := FList^[FCount - 1];
  788. end;
  789. procedure TGLPersistentObjectList.SetLast(item: TObject);
  790. begin
  791. {$IFOPT R+}
  792. if Cardinal(FCount) = 0 then
  793. Error;
  794. {$ENDIF}
  795. FList^[FCount - 1] := item;
  796. end;
  797. procedure TGLPersistentObjectList.Move(CurIndex, NewIndex: Integer);
  798. var
  799. item: Pointer;
  800. begin
  801. if curIndex <> newIndex then
  802. begin
  803. {$IFOPT R+}
  804. if Cardinal(newIndex) >= Cardinal(Count) then
  805. Error;
  806. if Cardinal(curIndex) >= Cardinal(Count) then
  807. Error;
  808. {$ENDIF}
  809. item := FList^[curIndex];
  810. if curIndex < newIndex then
  811. begin
  812. // curIndex+1 necessarily exists since curIndex<newIndex and newIndex<Count
  813. System.Move(List[curIndex + 1], List[curIndex], (NewIndex - CurIndex) * SizeOf(TObject));
  814. end
  815. else
  816. begin
  817. // newIndex+1 necessarily exists since newIndex<curIndex and curIndex<Count
  818. System.Move(List[newIndex], List[newIndex + 1], (CurIndex - NewIndex) * SizeOf(TObject));
  819. end;
  820. FList^[newIndex] := TObject(item);
  821. end;
  822. end;
  823. procedure TGLPersistentObjectList.Put(Index: Integer; Item: TObject);
  824. begin
  825. {$IFOPT R+}
  826. if Cardinal(Index) >= Cardinal(FCount) then
  827. Error;
  828. {$ENDIF}
  829. FList^[Index] := Item;
  830. end;
  831. function TGLPersistentObjectList.Remove(item: TObject): Integer;
  832. begin
  833. Result := IndexOf(item);
  834. if Result >= 0 then
  835. Delete(Result);
  836. end;
  837. procedure TGLPersistentObjectList.Pack;
  838. var
  839. i, j, n: Integer;
  840. p: PPointerObjectList;
  841. pk: PObject;
  842. begin
  843. p := List;
  844. n := Count - 1;
  845. while (n >= 0) and (p^[n] = nil) do
  846. Dec(n);
  847. for i := 0 to n do
  848. begin
  849. if p^[i] = nil then
  850. begin
  851. pk := @(p^[i]);
  852. for j := i + 1 to n do
  853. begin
  854. if p^[j] <> nil then
  855. begin
  856. pk^ := p^[j];
  857. Inc(pk);
  858. end;
  859. end;
  860. SetCount((Cardinal(pk) - Cardinal(p)) div SizeOf(TObject));
  861. Exit;
  862. end;
  863. end;
  864. SetCount(n + 1);
  865. end;
  866. procedure TGLPersistentObjectList.SetCapacity(newCapacity: Integer);
  867. begin
  868. if newCapacity <> FCapacity then
  869. begin
  870. if newCapacity < FCount then
  871. FCount := newCapacity;
  872. ReallocMem(FList, newCapacity * SizeOf(TObject));
  873. FCapacity := newCapacity;
  874. end;
  875. end;
  876. procedure TGLPersistentObjectList.RequiredCapacity(aCapacity: Integer);
  877. begin
  878. if FCapacity < aCapacity then
  879. SetCapacity(aCapacity);
  880. end;
  881. procedure TGLPersistentObjectList.SetCount(newCount: Integer);
  882. begin
  883. if newCount > FCapacity then
  884. SetCapacity(newCount);
  885. if newCount > FCount then
  886. FillChar(FList[FCount], (newCount - FCount) * SizeOf(TObject), 0);
  887. FCount := NewCount;
  888. end;
  889. procedure TGLPersistentObjectList.DeleteAndFree(index: Integer);
  890. var
  891. obj: TObject;
  892. begin
  893. obj := Get(index);
  894. Delete(index);
  895. obj.Free;
  896. end;
  897. procedure TGLPersistentObjectList.DeleteAndFreeItems(index: Integer; nbVals: Cardinal);
  898. var
  899. i, n: Integer;
  900. begin
  901. {$IFOPT R+}
  902. Assert(Cardinal(index) < Cardinal(FCount));
  903. {$ENDIF}
  904. n := index + Integer(nbVals);
  905. if n >= FCount then
  906. n := FCount - 1;
  907. for i := index to n do
  908. FList^[i].Free;
  909. DeleteItems(index, nbVals);
  910. end;
  911. function TGLPersistentObjectList.RemoveAndFree(item: TObject): Integer;
  912. begin
  913. Result := IndexOf(item);
  914. if Result >= 0 then
  915. begin
  916. Delete(Result);
  917. item.Free;
  918. end;
  919. end;
  920. procedure TGLPersistentObjectList.DoClean;
  921. var
  922. i: Integer;
  923. begin
  924. // a 'for' loop could crash if freeing an item removes other items form the list
  925. i := FCount - 1;
  926. while i >= 0 do
  927. begin
  928. if i < FCount then
  929. FList^[i].Free;
  930. Dec(i);
  931. end;
  932. end;
  933. procedure TGLPersistentObjectList.Clean;
  934. begin
  935. DoClean;
  936. Clear;
  937. end;
  938. procedure TGLPersistentObjectList.CleanFree;
  939. begin
  940. if Self <> nil then
  941. begin
  942. Clean;
  943. Destroy;
  944. end;
  945. end;
  946. procedure TGLPersistentObjectList.WriteToFiler(writer: TGLVirtualWriter);
  947. (*
  948. Object List Filer Format :
  949. Integer (Version)
  950. ListBegin
  951. ...[Object]...[Object]...
  952. ListEnd
  953. with [Object] being either (read vertically)
  954. Boolean (unused) String (ClassName) Integer (reference)
  955. Integer Object Data Object Data
  956. *)
  957. var
  958. i, objId: integer;
  959. objTypes: TList;
  960. aType: TClass;
  961. begin
  962. objTypes := TList.Create;
  963. try
  964. with writer do
  965. begin
  966. WriteInteger(0); // Archive Version 0 (uh... not exactly... but...)
  967. WriteListBegin;
  968. for i := 0 to FCount - 1 do
  969. begin
  970. if FList^[i] = nil then
  971. begin
  972. // store nil as... nil
  973. WriteBoolean(False);
  974. WriteInteger(0);
  975. end
  976. else if (FList^[i] is TGLPersistentObject) then
  977. begin
  978. // yeah, a TGLPersistentObject
  979. aType := FList^[i].ClassType;
  980. objId := objTypes.IndexOf(aType);
  981. if objId < 0 then
  982. begin
  983. // class is unknown
  984. objTypes.Add(aType);
  985. WriteString(aType.ClassName);
  986. end
  987. else
  988. begin
  989. // class already registered
  990. WriteInteger(objId);
  991. end;
  992. TGLPersistentObject(FList^[i]).WriteToFiler(writer);
  993. end
  994. else
  995. begin
  996. // Dunno that stuff here, store as is
  997. WriteBoolean(False);
  998. WriteInteger(Integer(FList^[i]));
  999. end;
  1000. end;
  1001. WriteListEnd;
  1002. end;
  1003. finally
  1004. objTypes.Free;
  1005. end;
  1006. end;
  1007. procedure TGLPersistentObjectList.ReadFromFilerWithEvent(reader: TGLVirtualReader; afterSenderObjectCreated: TNotifyEvent);
  1008. var
  1009. obj: TGLPersistentObject;
  1010. m: TGLPersistentObjectClass;
  1011. version: integer;
  1012. objTypes: TList;
  1013. begin
  1014. objTypes := TList.Create;
  1015. try
  1016. Clean;
  1017. with reader do
  1018. begin
  1019. version := ReadInteger;
  1020. if version = 0 then
  1021. begin
  1022. ReadListBegin;
  1023. while not EndOfList do
  1024. case Cardinal(NextValue) of
  1025. Cardinal(vaFalse), Cardinal(vaTrue):
  1026. begin
  1027. // stored 'as was' value
  1028. ReadBoolean; // ignored
  1029. Add(TObject(Cardinal(ReadInteger)));
  1030. end;
  1031. Cardinal(vaString), Cardinal(vaLString), Cardinal(vaWString),
  1032. Cardinal(vaInt64) + 1 { vaUTF8String }:
  1033. begin
  1034. // Unknown class, to be registered
  1035. m := TGLPersistentObjectClass(FindClass(ReadString));
  1036. objTypes.Add(m);
  1037. obj := m.Create;
  1038. if Assigned(afterSenderObjectCreated) then
  1039. afterSenderObjectCreated(obj);
  1040. obj.ReadFromFiler(reader);
  1041. Add(obj);
  1042. end;
  1043. Cardinal(vaInt8), Cardinal(vaInt16), Cardinal(vaInt32):
  1044. begin
  1045. // known class, direct retrieve
  1046. m := TGLPersistentObjectClass(objTypes[ReadInteger]);
  1047. obj := m.Create;
  1048. if Assigned(afterSenderObjectCreated) then
  1049. afterSenderObjectCreated(obj);
  1050. obj.ReadFromFiler(reader);
  1051. Add(obj);
  1052. end;
  1053. else
  1054. raise Exception.Create(strBrokenObjectListArchive);
  1055. end;
  1056. ReadListEnd;
  1057. end
  1058. else
  1059. RaiseFilerException(version);
  1060. end;
  1061. finally
  1062. objTypes.Free;
  1063. end;
  1064. end;
  1065. procedure TGLPersistentObjectList.ReadFromFiler(reader: TGLVirtualReader);
  1066. begin
  1067. ReadFromFilerWithEvent(reader, AfterObjectCreatedByReader);
  1068. end;
  1069. procedure TGLPersistentObjectList.AfterObjectCreatedByReader(Sender: TObject);
  1070. begin
  1071. // nothing
  1072. end;
  1073. procedure TGLPersistentObjectList.Push(item: TObject);
  1074. begin
  1075. Add(item);
  1076. end;
  1077. function TGLPersistentObjectList.Pop: TObject;
  1078. begin
  1079. if FCount > 0 then
  1080. begin
  1081. Result := FList^[FCount - 1];
  1082. Dec(FCount);
  1083. end
  1084. else
  1085. Result := nil;
  1086. end;
  1087. procedure TGLPersistentObjectList.PopAndFree;
  1088. begin
  1089. Pop.Free;
  1090. end;
  1091. procedure POListQuickSort(SortList: PPointerObjectList; L, R: Integer;
  1092. compareFunc: TObjectListSortCompare);
  1093. var
  1094. I, J: Integer;
  1095. P, T: TObject;
  1096. begin
  1097. repeat
  1098. I := L;
  1099. J := R;
  1100. P := SortList^[(L + R) shr 1];
  1101. repeat
  1102. while compareFunc(SortList^[I], P) < 0 do
  1103. Inc(I);
  1104. while compareFunc(SortList^[J], P) > 0 do
  1105. Dec(J);
  1106. if I <= J then
  1107. begin
  1108. T := SortList^[I];
  1109. SortList^[I] := SortList^[J];
  1110. SortList^[J] := T;
  1111. Inc(I);
  1112. Dec(J);
  1113. end;
  1114. until I > J;
  1115. if L < J then
  1116. POListQuickSort(SortList, L, J, compareFunc);
  1117. L := I;
  1118. until I >= R;
  1119. end;
  1120. procedure TGLPersistentObjectList.Sort(compareFunc: TObjectListSortCompare);
  1121. begin
  1122. if Count > 1 then
  1123. POListQuickSort(FList, 0, Count - 1, compareFunc);
  1124. end;
  1125. // ------------------
  1126. // ------------------ TGLBinaryReader ------------------
  1127. // ------------------
  1128. procedure TGLBinaryReader.Read(var Buf; Count: Longint);
  1129. begin
  1130. FStream.Read(Buf, Count);
  1131. end;
  1132. function TGLBinaryReader.ReadValue: TValueType;
  1133. var
  1134. b: byte;
  1135. begin
  1136. Read(b, 1);
  1137. Result := TValueType(b);
  1138. end;
  1139. function TGLBinaryReader.NextValue: TValueType;
  1140. var
  1141. pos: Int64;
  1142. begin
  1143. pos := FStream.Position;
  1144. Result := ReadValue;
  1145. FStream.Position := pos;
  1146. end;
  1147. function TGLBinaryReader.ReadInteger: Integer;
  1148. var
  1149. tempShort: ShortInt;
  1150. tempSmallInt: SmallInt;
  1151. begin
  1152. case ReadValue of
  1153. vaInt8:
  1154. begin
  1155. Read(tempShort, 1);
  1156. Result := tempShort;
  1157. end;
  1158. vaInt16:
  1159. begin
  1160. Read(tempSmallInt, 2);
  1161. Result := tempSmallInt;
  1162. end;
  1163. vaInt32: Read(Result, 4);
  1164. else
  1165. Result := 0;
  1166. ReadTypeError;
  1167. end;
  1168. end;
  1169. function TGLBinaryReader.ReadBoolean: Boolean;
  1170. begin
  1171. case ReadValue of
  1172. vaTrue: Result := True;
  1173. vaFalse: Result := False;
  1174. else
  1175. ReadTypeError;
  1176. Result := False;
  1177. end;
  1178. end;
  1179. function TGLBinaryReader.ReadString: string;
  1180. var
  1181. n: Cardinal;
  1182. vType: TValueType;
  1183. tempString: AnsiString;
  1184. begin
  1185. n := 0;
  1186. vType := ReadValue;
  1187. case Cardinal(vType) of
  1188. Cardinal(vaWString),
  1189. Cardinal(vaInt64) + 1:
  1190. begin // vaUTF8String
  1191. Result := ReadWideString(vType);
  1192. Exit;
  1193. end;
  1194. Cardinal(vaString): Read(n, 1);
  1195. Cardinal(vaLString): Read(n, 4);
  1196. else
  1197. ReadTypeError;
  1198. end;
  1199. SetLength(tempString, n);
  1200. if n > 0 then
  1201. Read(tempString[1], n);
  1202. Result := string(tempString);
  1203. end;
  1204. function TGLBinaryReader.ReadWideString(vType: TValueType): WideString;
  1205. var
  1206. n: Cardinal;
  1207. utf8buf: AnsiString;
  1208. begin
  1209. Read(n, 4);
  1210. case Cardinal(vType) of
  1211. Cardinal(vaWString):
  1212. begin
  1213. SetLength(Result, n);
  1214. if n > 0 then
  1215. Read(Result[1], n * 2);
  1216. end;
  1217. Cardinal(vaInt64) + 1:
  1218. begin // vaUTF8String
  1219. SetLength(utf8buf, n);
  1220. if n > 0 then
  1221. begin
  1222. Read(utf8buf[1], n);
  1223. Result := UTF8ToWideString(utf8buf);
  1224. end;
  1225. end;
  1226. else
  1227. ReadTypeError;
  1228. end;
  1229. end;
  1230. function TGLBinaryReader.ReadFloat: Extended;
  1231. {$IFDEF WIN64}
  1232. var
  1233. C: TExtended80Rec; // Temporary variable to store 10 bytes floating point number in a Win64 application
  1234. {$ENDIF}
  1235. begin
  1236. Result := 0.0;
  1237. {$IFDEF WIN64}
  1238. if ReadValue = vaExtended then
  1239. begin
  1240. Read(C, SizeOf(C)); // Load value into the temp variable
  1241. Result := Extended(C); // Typecast into an Extended: in a win64 application is a Double
  1242. end
  1243. else
  1244. ReadTypeError;
  1245. {$ELSE}
  1246. if ReadValue = vaExtended then
  1247. Read(Result, SizeOf(Result))
  1248. else
  1249. ReadTypeError;
  1250. {$ENDIF}
  1251. end;
  1252. procedure TGLBinaryReader.ReadListBegin;
  1253. begin
  1254. if ReadValue <> vaList then
  1255. ReadTypeError;
  1256. end;
  1257. procedure TGLBinaryReader.ReadListEnd;
  1258. begin
  1259. if ReadValue <> vaNull then
  1260. ReadTypeError;
  1261. end;
  1262. function TGLBinaryReader.EndOfList: Boolean;
  1263. begin
  1264. Result := (NextValue = vaNull);
  1265. end;
  1266. // ------------------
  1267. // ------------------ TGLBinaryWriter ------------------
  1268. // ------------------
  1269. procedure TGLBinaryWriter.Write(const Buf; Count: Longint);
  1270. begin
  1271. FStream.Write(Buf, Count);
  1272. end;
  1273. procedure TGLBinaryWriter.WriteInteger(anInteger: Integer);
  1274. type
  1275. TIntStruct = packed record
  1276. typ: byte;
  1277. val: Integer;
  1278. end;
  1279. var
  1280. ins: TIntStruct;
  1281. begin
  1282. ins.val := anInteger;
  1283. if (anInteger >= Low(ShortInt)) and (anInteger <= High(ShortInt)) then
  1284. begin
  1285. ins.typ := byte(vaInt8);
  1286. Write(ins, 2);
  1287. end
  1288. else if (anInteger >= Low(SmallInt)) and (anInteger <= High(SmallInt)) then
  1289. begin
  1290. ins.typ := byte(vaInt16);
  1291. Write(ins, 3);
  1292. end
  1293. else
  1294. begin
  1295. ins.typ := byte(vaInt32);
  1296. Write(ins, 5);
  1297. end;
  1298. end;
  1299. procedure TGLBinaryWriter.WriteBoolean(aBoolean: Boolean);
  1300. const
  1301. cBoolToType: array[False..True] of byte = (byte(vaFalse), byte(vaTrue));
  1302. begin
  1303. Write(cBoolToType[aBoolean], 1);
  1304. end;
  1305. procedure TGLBinaryWriter.WriteAnsiString(const aString: AnsiString);
  1306. type
  1307. TStringHeader = packed record
  1308. typ: Byte;
  1309. length: Integer;
  1310. end;
  1311. var
  1312. sh: TStringHeader;
  1313. begin
  1314. sh.Length := Length(aString);
  1315. if sh.Length <= 255 then
  1316. begin
  1317. sh.typ := byte(vaString);
  1318. Write(sh, 2);
  1319. if sh.Length > 0 then
  1320. Write(aString[1], sh.Length);
  1321. end
  1322. else
  1323. begin
  1324. sh.typ := byte(vaLString);
  1325. Write(sh, 5);
  1326. Write(aString[1], sh.Length);
  1327. end;
  1328. end;
  1329. procedure TGLBinaryWriter.WriteWideString(const aString: WideString);
  1330. type
  1331. TStringHeader = packed record
  1332. typ: Byte;
  1333. length: Integer;
  1334. end;
  1335. var
  1336. sh: TStringHeader;
  1337. begin
  1338. sh.Length := Length(aString);
  1339. sh.typ := byte(vaWString);
  1340. Write(sh, 5);
  1341. if sh.Length > 0 then
  1342. Write(aString[1], sh.length * SizeOf(WideChar));
  1343. end;
  1344. procedure TGLBinaryWriter.WriteString(const aString: string);
  1345. begin
  1346. {$IFDEF UNICODE}
  1347. // TODO: should really check if the string can be simplified to: vaString / vaLString / vaUTF8String
  1348. WriteWideString(aString);
  1349. {$ELSE}
  1350. WriteAnsiString(aString);
  1351. {$ENDIF}
  1352. end;
  1353. procedure TGLBinaryWriter.WriteFloat(const aFloat: Extended);
  1354. type
  1355. TExtendedStruct = packed record
  1356. typ: Byte;
  1357. {$IFDEF WIN64}
  1358. val :TExtended80Rec; // Structure to handle a 10 bytes floating point value
  1359. {$ELSE}
  1360. val :Extended;
  1361. {$ENDIF}
  1362. end;
  1363. var
  1364. str: TExtendedStruct;
  1365. begin
  1366. {$IFDEF WIN64}
  1367. str.typ := byte(vaExtended);
  1368. str.val := TExtended80Rec(aFloat); // Typecast the float value (in a Win64 app the type is a Double) into the 10 bytes struct
  1369. Write(str, SizeOf(str));
  1370. {$ELSE}
  1371. str.typ := byte(vaExtended);
  1372. str.val := aFloat;
  1373. Write(str, SizeOf(str));
  1374. {$ENDIF}
  1375. end;
  1376. procedure TGLBinaryWriter.WriteListBegin;
  1377. const
  1378. buf: byte = byte(vaList);
  1379. begin
  1380. Write(buf, 1);
  1381. end;
  1382. procedure TGLBinaryWriter.WriteListEnd;
  1383. const
  1384. buf: byte = byte(vaNull);
  1385. begin
  1386. Write(buf, 1);
  1387. end;
  1388. // ------------------
  1389. // ------------------ TGLTextReader ------------------
  1390. // ------------------
  1391. procedure TGLTextReader.ReadLine(const requestedType: string = '');
  1392. var
  1393. line: string;
  1394. c: Byte;
  1395. p: Integer;
  1396. begin
  1397. // will need speed upgrade, someday...
  1398. line := '';
  1399. repeat
  1400. Stream.Read(c, 1);
  1401. if c >= 32 then
  1402. line := line + chr(c);
  1403. until c = 10;
  1404. line := Trim(line);
  1405. p := Pos(' ', line);
  1406. if p > 0 then
  1407. begin
  1408. FValueType := Copy(line, 1, p - 1);
  1409. FData := Trim(Copy(line, p + 1, MaxInt));
  1410. end
  1411. else
  1412. begin
  1413. FValueType := line;
  1414. FData := '';
  1415. end;
  1416. if requestedType <> '' then
  1417. if requestedType <> FValueType then
  1418. raise EFilerException.Create('Invalid type, expected "'
  1419. + requestedType + '", found "FValueType".');
  1420. end;
  1421. procedure TGLTextReader.Read(var Buf; Count: Longint);
  1422. function HexCharToInt(const c: Char): Integer;
  1423. begin
  1424. if c <= '9' then
  1425. Result := Integer(c) - Integer('0')
  1426. else if c < 'a' then
  1427. Result := Integer(c) - Integer('A') + 10
  1428. else
  1429. Result := Integer(c) - Integer('a') + 10;
  1430. end;
  1431. var
  1432. i, j: Integer;
  1433. begin
  1434. ReadLine(cVTRaw);
  1435. j := 1;
  1436. for i := 0 to Count - 1 do
  1437. begin
  1438. PAnsiChar(@Buf)[i] := AnsiChar((HexCharToInt(FData[j]) shl 4)
  1439. + HexCharToInt(FData[j + 1]));
  1440. Inc(j, 2);
  1441. end;
  1442. end;
  1443. function TGLTextReader.NextValue: TValueType;
  1444. var
  1445. p: Int64;
  1446. begin
  1447. p := Stream.Position;
  1448. ReadLine;
  1449. if FValueType = cVTInteger then
  1450. Result := vaInt32
  1451. else if FValueType = cVTFloat then
  1452. Result := vaExtended
  1453. else if FValueType = cVTString then
  1454. Result := vaString
  1455. else if FValueType = cVTBoolean then
  1456. if FData = cTrue then
  1457. Result := vaTrue
  1458. else
  1459. Result := vaFalse
  1460. else if FValueType = cVTRaw then
  1461. Result := vaBinary
  1462. else if FValueType = cVTListBegin then
  1463. Result := vaList
  1464. else
  1465. Result := vaNULL;
  1466. Stream.Position := p;
  1467. end;
  1468. function TGLTextReader.ReadInteger: Integer;
  1469. begin
  1470. ReadLine(cVTInteger);
  1471. Result := StrToInt(FData);
  1472. end;
  1473. function TGLTextReader.ReadBoolean: Boolean;
  1474. begin
  1475. ReadLine(cVTBoolean);
  1476. Result := (FData = cTrue);
  1477. end;
  1478. function TGLTextReader.ReadString: string;
  1479. var
  1480. i: Integer;
  1481. begin
  1482. ReadLine(cVTString);
  1483. Result := '';
  1484. i := 1;
  1485. while i < Length(FData) do
  1486. begin
  1487. if FData[i] = '#' then
  1488. begin
  1489. Result := Result + Char(StrToInt(Copy(FData, i + 1, 3)));
  1490. Inc(i, 3);
  1491. end
  1492. else
  1493. Result := Result + FData[i];
  1494. Inc(i);
  1495. end;
  1496. Assert(FData[i] = '.', 'Invalid stored string.');
  1497. end;
  1498. function TGLTextReader.ReadFloat: Extended;
  1499. var
  1500. oldDc: Char;
  1501. begin
  1502. ReadLine(cVTInteger);
  1503. oldDc := FormatSettings.DecimalSeparator;
  1504. FormatSettings.DecimalSeparator := '.';
  1505. Result := StrToFloat(FData);
  1506. FormatSettings.DecimalSeparator := oldDc;
  1507. end;
  1508. procedure TGLTextReader.ReadListBegin;
  1509. begin
  1510. ReadLine(cVTListBegin);
  1511. end;
  1512. procedure TGLTextReader.ReadListEnd;
  1513. begin
  1514. ReadLine(cVTListEnd);
  1515. end;
  1516. function TGLTextReader.EndOfList: Boolean;
  1517. var
  1518. p: Int64;
  1519. begin
  1520. p := Stream.Position;
  1521. ReadLine;
  1522. Result := (FValueType = cVTListEnd);
  1523. Stream.Position := p;
  1524. end;
  1525. // ------------------
  1526. // ------------------ TGLTextWriter ------------------
  1527. // ------------------
  1528. constructor TGLTextWriter.Create(aStream: TStream);
  1529. begin
  1530. inherited;
  1531. end;
  1532. destructor TGLTextWriter.Destroy;
  1533. begin
  1534. inherited;
  1535. end;
  1536. procedure TGLTextWriter.WriteLine(const valueType, data: string);
  1537. var
  1538. buf: AnsiString;
  1539. begin
  1540. buf := StringOfChar(AnsiChar(#32), FIndentLevel);
  1541. buf := buf + AnsiString(valueType + ' ' + data) + #13#10;
  1542. Stream.Write(buf[1], Length(buf));
  1543. end;
  1544. procedure TGLTextWriter.Write(const Buf; Count: Longint);
  1545. const
  1546. cNibbleToHex: PChar = '0123456789ABCDEF';
  1547. var
  1548. i, j, b: Integer;
  1549. data: string;
  1550. begin
  1551. SetLength(data, Count * 2);
  1552. j := 1;
  1553. for i := 0 to Count - 1 do
  1554. begin
  1555. b := Integer(PAnsiChar(@buf)[i]);
  1556. data[j] := cNibbleToHex[b shr 4];
  1557. data[j + 1] := cNibbleToHex[b and 15];
  1558. Inc(j, 2);
  1559. end;
  1560. WriteLine(cVTRaw, data);
  1561. end;
  1562. procedure TGLTextWriter.WriteInteger(anInteger: Integer);
  1563. begin
  1564. WriteLine(cVTInteger, IntToStr(anInteger));
  1565. end;
  1566. procedure TGLTextWriter.WriteBoolean(aBoolean: Boolean);
  1567. begin
  1568. if aBoolean then
  1569. WriteLine(cVTBoolean, cTrue)
  1570. else
  1571. WriteLine(cVTBoolean, cFalse);
  1572. end;
  1573. procedure TGLTextWriter.WriteString(const aString: string);
  1574. var
  1575. i: Integer;
  1576. s: string;
  1577. begin
  1578. s := '';
  1579. for i := 1 to Length(aString) do
  1580. if aString[i] >= #32 then
  1581. s := s + aString[i]
  1582. else
  1583. s := s + Format('#%.3d', [Integer(aString[i])]);
  1584. WriteLine(cVTString, s + '.');
  1585. end;
  1586. procedure TGLTextWriter.WriteFloat(const aFloat: Extended);
  1587. begin
  1588. WriteLine(cVTInteger, FloatToStr(aFloat));
  1589. end;
  1590. procedure TGLTextWriter.WriteListBegin;
  1591. begin
  1592. WriteLine(cVTListBegin, '');
  1593. Inc(FIndentLevel, 3);
  1594. end;
  1595. procedure TGLTextWriter.WriteListEnd;
  1596. begin
  1597. Dec(FIndentLevel, 3);
  1598. WriteLine(cVTListEnd, '');
  1599. end;
  1600. // ------------------
  1601. // ------------------ TGLOwnedPersistent ------------------
  1602. // ------------------
  1603. constructor TGLOwnedPersistent.Create(AOwner: TPersistent);
  1604. begin
  1605. FOwner := AOwner;
  1606. end;
  1607. function TGLOwnedPersistent.GetOwner: TPersistent;
  1608. begin
  1609. Result := FOwner;
  1610. end;
  1611. // ------------------
  1612. // ------------------ TGLInterfacedPersistent ------------------
  1613. // ------------------
  1614. function TGLInterfacedPersistent._AddRef: Integer; stdcall;
  1615. begin
  1616. Result := -1; //ignore
  1617. end;
  1618. function TGLInterfacedPersistent._Release: Integer; stdcall;
  1619. begin
  1620. Result := -1; //ignore
  1621. end;
  1622. function TGLInterfacedPersistent.QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
  1623. begin
  1624. if GetInterface(IID, Obj) then
  1625. Result := S_OK
  1626. else
  1627. Result := E_NOINTERFACE;
  1628. end;
  1629. // ------------------
  1630. // ------------------ TGLInterfacedCollectionItem ------------------
  1631. // ------------------
  1632. function TGLInterfacedCollectionItem._AddRef: Integer; stdcall;
  1633. begin
  1634. Result := -1; //ignore
  1635. end;
  1636. function TGLInterfacedCollectionItem._Release: Integer; stdcall;
  1637. begin
  1638. Result := -1; //ignore
  1639. end;
  1640. function TGLInterfacedCollectionItem.QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
  1641. begin
  1642. if GetInterface(IID, Obj) then
  1643. Result := S_OK
  1644. else
  1645. Result := E_NOINTERFACE;
  1646. end;
  1647. // ------------------------------------------------------------------
  1648. initialization
  1649. // ------------------------------------------------------------------
  1650. RegisterClass(TGLPersistentObjectList);
  1651. end.