GLS.PersistentClasses.pas 45 KB

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