GLS.PersistentClasses.pas 45 KB

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