2
0

GLS.PersistentClasses.pas 45 KB

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