stringtableresource.pp 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 2008 by Giulio Bernardi
  4. String table resource type
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. **********************************************************************}
  11. unit stringtableresource;
  12. {$MODE OBJFPC}
  13. interface
  14. uses
  15. Classes, SysUtils, resource;
  16. type
  17. EStringTableResourceException = class(EResourceException);
  18. EStringTableNameNotAllowedException = class(EStringTableResourceException);
  19. EStringTableIndexOutOfBoundsException = class(EStringTableResourceException);
  20. resourcestring
  21. SNameNotAllowed = 'Resource ID must be an ordinal in the range 1-4096';
  22. SIndexOutOfBounds = 'String ID out of bounds: %d';
  23. type
  24. { TStringTableResource }
  25. TStringTableResource = class(TAbstractResource)
  26. private
  27. fType : TResourceDesc;
  28. fName : TResourceDesc;
  29. fFirstID : word;
  30. fCount : integer;
  31. fList : TStringList;
  32. fCanChangeDesc : boolean;
  33. function IDtoIndex(const aId : word) : integer;
  34. procedure CheckListLoaded;
  35. function ReadWideString : string;
  36. procedure WriteWideString(const aString : string);
  37. function GetLastID : word;
  38. procedure SetFirstID(aId : word);
  39. function GetString(id : word) : string;
  40. procedure SetString(id : word; aString : string);
  41. procedure CheckIndex(const aIndex : word);
  42. protected
  43. function GetType : TResourceDesc; override;
  44. function GetName : TResourceDesc; override;
  45. function ChangeDescTypeAllowed(aDesc : TResourceDesc) : boolean; override;
  46. function ChangeDescValueAllowed(aDesc : TResourceDesc) : boolean; override;
  47. procedure NotifyResourcesLoaded; override;
  48. public
  49. constructor Create; override;
  50. constructor Create(aType,aName : TResourceDesc); override;
  51. destructor Destroy; override;
  52. procedure UpdateRawData; override;
  53. property FirstID : word read fFirstID write SetFirstID;
  54. property LastID : word read GetLastID;
  55. property Count : integer read fCount;
  56. property Strings[id : word] : string read GetString write SetString; default;
  57. end;
  58. implementation
  59. uses
  60. resfactory;
  61. { TStringTableResource }
  62. function TStringTableResource.IDtoIndex(const aId: word): integer;
  63. begin
  64. Result:=aID-fFirstID;
  65. end;
  66. procedure TStringTableResource.CheckListLoaded;
  67. var i : integer;
  68. begin
  69. if fList<>nil then exit;
  70. fList:=TStringList.Create;
  71. fList.Capacity:=16;
  72. if RawData.Size=0 then exit;
  73. RawData.Position:=0;
  74. for i:=0 to 15 do
  75. fList.Add(ReadWideString);
  76. end;
  77. function TStringTableResource.ReadWideString: string;
  78. var ws : widestring;
  79. w : word;
  80. i : integer;
  81. begin
  82. RawData.ReadBuffer(w,2);
  83. {$IFDEF ENDIAN_BIG}
  84. w:=SwapEndian(w);
  85. {$ENDIF}
  86. setlength(ws,w);
  87. for i:=1 to length(ws) do
  88. begin
  89. RawData.ReadBuffer(w,2);
  90. {$IFDEF ENDIAN_BIG}
  91. w:=SwapEndian(w);
  92. {$ENDIF}
  93. ws[i]:=widechar(w);
  94. end;
  95. Result:=ws;
  96. end;
  97. procedure TStringTableResource.WriteWideString(const aString: string);
  98. var ws : widestring;
  99. w : word;
  100. i : integer;
  101. begin
  102. w:=length(aString);
  103. {$IFDEF ENDIAN_BIG}
  104. w:=SwapEndian(w);
  105. {$ENDIF}
  106. RawData.WriteBuffer(w,2);
  107. ws:=aString;
  108. for i:=1 to length(ws) do
  109. begin
  110. w:=word(ws[i]);
  111. {$IFDEF ENDIAN_BIG}
  112. w:=SwapEndian(w);
  113. {$ENDIF}
  114. RawData.WriteBuffer(w,2);
  115. end;
  116. end;
  117. function TStringTableResource.GetLastID: word;
  118. begin
  119. Result:=fFirstID+15;
  120. end;
  121. procedure TStringTableResource.SetFirstID(aId: word);
  122. begin
  123. aId:=aID and $FFF0;
  124. fFirstID:=aID;
  125. fCanChangeDesc:=true;
  126. fName.ID:=(aID div 16)+1;
  127. fCanChangeDesc:=false;
  128. end;
  129. function TStringTableResource.GetString(id: word): string;
  130. var idx : integer;
  131. begin
  132. CheckIndex(id);
  133. CheckListLoaded;
  134. idx:=IDtoIndex(id);
  135. if idx>=fList.Count then Result:=''
  136. else Result:=fList[idx];
  137. end;
  138. procedure TStringTableResource.SetString(id: word; aString: string);
  139. var idx,i : integer;
  140. begin
  141. CheckIndex(id);
  142. CheckListLoaded;
  143. idx:=IDtoIndex(id);
  144. if idx<fList.Count then fList[idx]:=aString
  145. else if idx>=fList.Count then
  146. begin
  147. for i:=fList.Count to idx-1 do
  148. fList.Add('');
  149. fList.Add(aString);
  150. end;
  151. end;
  152. procedure TStringTableResource.UpdateRawData;
  153. var i : integer;
  154. begin
  155. if fList=nil then exit;
  156. RawData.Size:=0;
  157. RawData.Position:=0;
  158. for i:=FirstID to LastID do
  159. WriteWideString(Strings[i]);
  160. FreeAndNil(fList);
  161. end;
  162. function TStringTableResource.GetType: TResourceDesc;
  163. begin
  164. Result:=fType;
  165. end;
  166. function TStringTableResource.GetName: TResourceDesc;
  167. begin
  168. Result:=fName;
  169. end;
  170. function TStringTableResource.ChangeDescTypeAllowed(aDesc: TResourceDesc
  171. ): boolean;
  172. begin
  173. Result:=fCanChangeDesc;
  174. end;
  175. function TStringTableResource.ChangeDescValueAllowed(aDesc: TResourceDesc
  176. ): boolean;
  177. begin
  178. Result:=fCanChangeDesc;
  179. end;
  180. procedure TStringTableResource.NotifyResourcesLoaded;
  181. begin
  182. end;
  183. procedure TStringTableResource.CheckIndex(const aIndex: word);
  184. begin
  185. if (aIndex<FirstID) or (aIndex>LastID) then
  186. raise EStringTableIndexOutOfBoundsException.CreateFmt(SIndexOutOfBounds,[aIndex])
  187. end;
  188. constructor TStringTableResource.Create;
  189. begin
  190. inherited Create;
  191. fCanChangeDesc:=false;
  192. fList:=nil;
  193. fType:=TResourceDesc.Create(RT_STRING);
  194. fName:=TResourceDesc.Create(1);
  195. fCount:=16;
  196. fFirstID:=0;
  197. SetDescOwner(fType);
  198. SetDescOwner(fName);
  199. end;
  200. constructor TStringTableResource.Create(aType, aName: TResourceDesc);
  201. begin
  202. Create;
  203. if (aName.DescType<>dtId) or ((aName.ID <1) or (aName.ID >4096)) then
  204. raise EStringTableNameNotAllowedException.Create(SNameNotAllowed);
  205. fCanChangeDesc:=true;
  206. fName.Assign(aName);
  207. fCanChangeDesc:=false;
  208. fCount:=16;
  209. fFirstID:=(fName.ID-1) * 16;
  210. end;
  211. destructor TStringTableResource.Destroy;
  212. begin
  213. fType.Free;
  214. fName.Free;
  215. if fList<>nil then
  216. fList.Free;
  217. inherited Destroy;
  218. end;
  219. initialization
  220. TResourceFactory.RegisterResourceClass(RT_STRING,TStringTableResource);
  221. end.