synabyte.pas 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375
  1. {==============================================================================|
  2. | Project : Ararat Synapse | 003.012.008 |
  3. |==============================================================================|
  4. | Content: buffer wrapper layer
  5. |==============================================================================|
  6. | Copyright (c)1999-2014, Lukas Gebauer |
  7. | All rights reserved. |
  8. | |
  9. | Redistribution and use in source and binary forms, with or without |
  10. | modification, are permitted provided that the following conditions are met: |
  11. | |
  12. | Redistributions of source code must retain the above copyright notice, this |
  13. | list of conditions and the following disclaimer. |
  14. | |
  15. | Redistributions in binary form must reproduce the above copyright notice, |
  16. | this list of conditions and the following disclaimer in the documentation |
  17. | and/or other materials provided with the distribution. |
  18. | |
  19. | Neither the name of Lukas Gebauer nor the names of its contributors may |
  20. | be used to endorse or promote products derived from this software without |
  21. | specific prior written permission. |
  22. | |
  23. | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
  24. | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
  25. | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
  26. | ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR |
  27. | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
  28. | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
  29. | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
  30. | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
  31. | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
  32. | OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH |
  33. | DAMAGE. |
  34. |==============================================================================|
  35. | The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).|
  36. | Portions created by Lukas Gebauer are Copyright (c) 1999-2012. |
  37. | All Rights Reserved. |
  38. |==============================================================================|
  39. | Contributor(s): Radek Cervinka, delphi.cz |
  40. | Ondrej Pokorny, kluug.net
  41. |==============================================================================|
  42. | History: see HISTORY.HTM from distribution package |
  43. | (Found at URL: http://www.ararat.cz/synapse/) |
  44. |==============================================================================}
  45. {:@abstract(NextGen and Unicode buffer layer)}
  46. unit synabyte;
  47. {$i jedi.inc}
  48. interface
  49. uses
  50. sysutils;
  51. {$IFDEF NEXTGEN}
  52. {$ZEROBASEDSTRINGS OFF}
  53. {$ENDIF}
  54. type
  55. {$IFDEF UNICODE}
  56. TSynaByte = byte;
  57. TSynaBytes = record
  58. private
  59. FBytes: TBytes;
  60. FRefCheck: string;
  61. function GetChars(const Index: NativeInt): Char;
  62. procedure SetChars(const Index: NativeInt; const Value: Char);
  63. function AGetLength: NativeInt;
  64. procedure ASetLength(const Value: NativeInt);
  65. procedure UpdateTerminator;
  66. procedure CheckCow;
  67. procedure Unique;
  68. public
  69. class operator Implicit(const V1: String): TSynaBytes;
  70. class operator Implicit(const V1: RawByteString): TSynaBytes;
  71. class operator Implicit(const V1: TSynaBytes): String;
  72. class operator Implicit(const V1: Char): TSynaBytes;
  73. class operator Explicit(const V1: TBytes): TSynaBytes;
  74. class operator Add(const V1, V2: TSynaBytes): TSynaBytes;
  75. class operator Equal(const V1, V2: TSynaBytes): Boolean;
  76. class operator NotEqual(const V1, V2: TSynaBytes): Boolean;
  77. function Clone: TSynaBytes;
  78. procedure Delete(Start, Count: Integer);
  79. function Data: Pointer;
  80. property Chars[const Index: NativeInt]: Char read GetChars write SetChars; default;
  81. property Length: NativeInt read AGetLength write ASetLength;
  82. property Bytes:TBytes read FBytes;
  83. end;
  84. // procedure SetLength(var s: TSynaBytes; Count:Integer); overload;
  85. {$ELSE}
  86. TSynaBytes = AnsiString;
  87. TSynaByte = AnsiChar;
  88. {$ENDIF}
  89. {$IFNDEF DELPHI12_UP}
  90. TBytes = Array of Byte;
  91. function CharInSet(C: Char; const CharSet: TSysCharSet): Boolean;
  92. {$ENDIF}
  93. function StringOf(const bytes: TSynaBytes):string; overload;
  94. function StringOf(const bytes: TBytes):string; overload;
  95. function StringOf(const bytes: PByte): String; overload;
  96. procedure DeleteInternal (var s: TSynaBytes; Start, Count: Integer);
  97. implementation
  98. {$IFDEF UNICODE}
  99. function IsBytesEquals(const Bytes1, Bytes2: TBytes; const Len1, Len2: NativeInt): Boolean;
  100. var
  101. i: NativeInt;
  102. begin
  103. if Len1 <> Len2 then
  104. Exit(False);
  105. for i := 0 to Len1 - 1 do
  106. if Bytes1[i] <> Bytes2[i] then
  107. Exit(False);
  108. Result := True;
  109. end;
  110. class operator TSynaBytes.Implicit(const V1: String): TSynaBytes;
  111. begin
  112. Result.FBytes := TEncoding.Default.GetBytes(V1);
  113. Result.Length := System.Length(Result.FBytes);
  114. end;
  115. class operator TSynaBytes.Add(const V1, V2: TSynaBytes): TSynaBytes;
  116. begin
  117. Result.Length := V1.Length + V2.Length;
  118. if V1.Length > 0 then
  119. Move(V1.FBytes[0], Result.FBytes[0], V1.Length);
  120. if V2.Length > 0 then
  121. Move(V2.FBytes[0], Result.FBytes[V1.Length], V2.Length);
  122. end;
  123. procedure TSynaBytes.CheckCow;
  124. function RefCount: Integer;
  125. var
  126. xStrPtr: ^Integer;
  127. begin
  128. //get reference count of FStrBuffer, correct results on 32bit, 64bit and also mobile
  129. xStrPtr := Pointer(PChar(FRefCheck));
  130. Dec(xStrPtr, 2);
  131. Result := xStrPtr^;
  132. end;
  133. begin
  134. if RefCount <> 1 then
  135. begin
  136. Unique;
  137. end;
  138. FRefCheck := '!';
  139. end;
  140. function TSynaBytes.Clone: TSynaBytes;
  141. begin
  142. Result.Length := Self.Length;
  143. Move(FBytes[0], Result.FBytes[0], Self.Length);
  144. end;
  145. function TSynaBytes.Data: Pointer;
  146. begin
  147. Result := @FBytes[0];
  148. end;
  149. // zero based
  150. procedure TSynaBytes.Delete(Start, Count: Integer);
  151. begin
  152. if Count <= 0 then
  153. Exit;
  154. CheckCow;
  155. if Length - Count <= 0 then
  156. begin
  157. Length := 0;
  158. Exit;
  159. end;
  160. if (Start >= 0) then
  161. begin
  162. Move(FBytes[Start + Count], FBytes[Start], Length - Count);
  163. Length := Length - Count;
  164. end;
  165. end;
  166. class operator TSynaBytes.Equal(const V1, V2: TSynaBytes): Boolean;
  167. begin
  168. Result := IsBytesEquals(V1.FBytes, V2.FBytes, V1.Length, V2.Length);
  169. end;
  170. class operator TSynaBytes.Explicit(const V1: TBytes): TSynaBytes;
  171. begin
  172. Result.FBytes := Copy(V1);
  173. Result.Length := System.Length(V1);
  174. end;
  175. function TSynaBytes.GetChars(const Index: NativeInt): Char;
  176. begin
  177. Result := Char(FBytes[Index]);
  178. end;
  179. function TSynaBytes.AGetLength: NativeInt;
  180. begin
  181. Result := System.Length(FBytes);
  182. if Result > 0 then
  183. Result := Result - 1; // Null Terminator
  184. end;
  185. class operator TSynaBytes.Implicit(const V1: Char): TSynaBytes;
  186. begin
  187. Result.FBytes := TEncoding.Default.GetBytes(V1);
  188. Result.Length := System.Length(Result.FBytes);
  189. end;
  190. class operator TSynaBytes.Implicit(const V1: RawByteString): TSynaBytes;
  191. var
  192. I: Integer;
  193. begin
  194. Result.Length := System.Length(V1);
  195. for I := 1 to System.Length(V1) do
  196. Result.FBytes[I-1] := Byte(V1[I]);//warning: null-terminated strings!
  197. end;
  198. class operator TSynaBytes.Implicit(const V1: TSynaBytes): String;
  199. var
  200. {$IFDEF MSWINDOWS}
  201. S: RawByteString;
  202. {$ELSE}
  203. I: Integer;
  204. C: PWord;
  205. {$ENDIF}
  206. begin
  207. SetLength(Result, V1.Length);
  208. if V1.Length > 0 then
  209. begin
  210. //ïåðåïèñàë, 4873
  211. {$IFDEF MSWINDOWS}
  212. SetLength(s, V1.Length);
  213. Move(V1.FBytes[0], s[1], V1.Length);
  214. Result := string(s);
  215. //åùå ïåðåïèñàë, 7592
  216. {$ELSE}
  217. C := PWord(PWideChar(Result));
  218. for I := 0 to V1.Length-1 do
  219. begin
  220. C^ := V1.FBytes[I];
  221. Inc(C);
  222. end;
  223. {$ENDIF}
  224. end;
  225. end;
  226. class operator TSynaBytes.NotEqual(const V1, V2: TSynaBytes): Boolean;
  227. begin
  228. Result := not IsBytesEquals(V1.FBytes, V2.FBytes, V1.Length, V2.Length);
  229. end;
  230. procedure TSynaBytes.SetChars(const Index: NativeInt; const Value: Char);
  231. begin
  232. CheckCow;
  233. FBytes[Index] := Byte(Value);
  234. end;
  235. procedure TSynaBytes.Unique;
  236. var
  237. b:TBytes;
  238. begin
  239. SetLength(b, Self.Length + 1);
  240. Move(FBytes[0], b[0], Self.Length);
  241. FBytes := b;
  242. end;
  243. procedure TSynaBytes.UpdateTerminator;
  244. begin
  245. if System.Length(FBytes) > 0 then
  246. FBytes[System.Length(FBytes) - 1] := 0;
  247. end;
  248. procedure TSynaBytes.ASetLength(const Value: NativeInt);
  249. begin
  250. System.SetLength(FBytes, Value + 1); // +1, null terminator
  251. Self.UpdateTerminator();
  252. end;
  253. {$ENDIF}
  254. function StringOf(const bytes: TSynaBytes):string;
  255. begin
  256. Result := bytes;
  257. end;
  258. function StringOf(const bytes: TBytes):string;
  259. {$IFDEF UNICODE}
  260. var
  261. I: Integer;
  262. C: PWord;
  263. begin
  264. SetLength(Result, Length(bytes));
  265. if Length(bytes) > 0 then
  266. begin
  267. C := PWord(PWideChar(Result));
  268. for I := 0 to Length(bytes)-1 do
  269. begin
  270. C^ := bytes[I];
  271. Inc(C);
  272. end;
  273. end;
  274. {$ELSE}
  275. begin
  276. SetLength(Result, Length(bytes));
  277. if Length(bytes) > 0 then
  278. Move(bytes[0], result[1], Length(bytes));
  279. {$ENDIF}
  280. end;
  281. function StringOf(const bytes: PByte):string;
  282. var
  283. count: Integer;
  284. buf: PByte;
  285. {$IFDEF UNICODE}
  286. I: Integer;
  287. C: PWord;
  288. {$ENDIF}
  289. begin
  290. Count := 0;
  291. buf := bytes;
  292. while buf^<>0 do
  293. begin
  294. inc(count);
  295. inc(buf);
  296. end;
  297. {$IFDEF UNICODE}
  298. SetLength(Result, count);
  299. if count > 0 then
  300. begin
  301. C := PWord(PWideChar(Result));
  302. for I := 0 to count-1 do
  303. begin
  304. C^ := bytes[I];
  305. Inc(C);
  306. end;
  307. end;
  308. {$ELSE}
  309. SetLength(Result, count);
  310. Move(bytes^, result[1], count);
  311. {$ENDIF}
  312. end;
  313. procedure DeleteInternal (var s: TSynaBytes; Start, Count: Integer);
  314. begin
  315. {$IFDEF UNICODE}
  316. s.Delete(Start - 1, Count);
  317. {$ELSE}
  318. Delete(s, Start , Count);
  319. {$ENDIF}
  320. end;
  321. {$IFNDEF DELPHI12_UP}
  322. function CharInSet(C: Char; const CharSet: TSysCharSet): Boolean;
  323. begin
  324. Result := C in CharSet;
  325. end;
  326. {$ENDIF}
  327. end.