acFileStorage equivalent
2016-04-12 19:53
519 查看
searching for a vcl that can enable embed any files within dfm similar to acfilestorage
When there are bugs with the file naming, then the porting wasn't completely done. The problem with "malformed" strings is still always the same. A string is treated as ANSI, but since Delphi 2009 the strings in Delphi has the Unicode format. What means, a string of Length 5 needs 10 bytes to store. Another typical fault is to treat a Unicode Buffer as ANSI. Such things leads always into "malformed" strings.
Now, you need to change the way the file name is stored. The function "WriteStream(…)" should be something like this…
Code:
Here is the function "ReadStream(…)"…
Code:
The filename is stored in the format UTF8 byte, which allows in the best case one Byte for one Character. Please remember Unicode needs two Bytes per Character.
Useless to say, that this is a breaking change. The chance is high, that existing streams couldn't be read sucessfulyy. In this case the DFM should be clear manually. I should be enough to remove the content of the property "StoredData = { ... }", which is easy to find. The component could then be loaded again.
Note: Now, it's not recommended to use the component TacFileStorage, because in the worst case a file with 1 MiB became 2 MiB, because of it is stored as Hex string. It would be much better to use a resource file that is unpacked on run-time.
https://www.board4allcz.eu/showthread.php?t=626035
When there are bugs with the file naming, then the porting wasn't completely done. The problem with "malformed" strings is still always the same. A string is treated as ANSI, but since Delphi 2009 the strings in Delphi has the Unicode format. What means, a string of Length 5 needs 10 bytes to store. Another typical fault is to treat a Unicode Buffer as ANSI. Such things leads always into "malformed" strings.
Now, you need to change the way the file name is stored. The function "WriteStream(…)" should be something like this…
Code:
procedure TStoredFile.WriteData(Stream: TStream); var Buffer: TArray<Byte>; TheSize: Cardinal; Target: Pointer; begin // storing the file name Buffer := TEncoding.UTF8.GetBytes(FFileName); <- The filename is converted to UTF8… TheSize := Length(Buffer); Stream.Write(TheSize, 4); Stream.Write(Buffer, 0, TheSize); <- …and the bytes will be written // pack and write data TheSize := SFCalcTargetSz(FSize); // calculate required size for taget buffer GetMem(Target, TheSize); try TheSize := SFPack(FData.Memory, Target, FSize); Stream.Write(TheSize, 4); // compressed size Stream.Write(Target^, TheSize); // original size and compressed data finally FreeMem(Target); end; end;
Here is the function "ReadStream(…)"…
Code:
procedure TStoredFile.ReadData(Stream: TStream); var Buffer: TArray<Byte>; TheSize: Cardinal; Source: Pointer; begin // reading the file name Stream.Read(TheSize, SizeOf(TheSize)); SetLength(Buffer, TheSize); Stream.Read(Buffer, 0, TheSize); <- Read the UTF8 Bytes… FFileName := TEncoding.UTF8.GetString(Buffer, 0, TheSize); <- …and convert them back to Unicode // reading the file size Stream.Read(TheSize, 4); // compressed size if (Owner = nil) or TacFileStorage(Owner).Compressed then begin dec(TheSize, 4); GetMem(Source, TheSize); // allocating memory for compressed buffer Stream.Read(FSize, 4); // original size FData.SetSize(FSize); // allocating memory for decompressed buffer try Stream.Read(Source^, TheSize); // reading compressed data SFUnpack(Source, FData.Memory, TheSize); finally FreeMem(Source); end end else // this is for compatibility with older versions begin FSize := TheSize; FData.SetSize(FSize); // reading the stream Stream.ReadBuffer(FData.Memory^, FSize); end; end;
The filename is stored in the format UTF8 byte, which allows in the best case one Byte for one Character. Please remember Unicode needs two Bytes per Character.
Useless to say, that this is a breaking change. The chance is high, that existing streams couldn't be read sucessfulyy. In this case the DFM should be clear manually. I should be enough to remove the content of the property "StoredData = { ... }", which is easy to find. The component could then be loaded again.
Note: Now, it's not recommended to use the component TacFileStorage, because in the worst case a file with 1 MiB became 2 MiB, because of it is stored as Hex string. It would be much better to use a resource file that is unpacked on run-time.
https://www.board4allcz.eu/showthread.php?t=626035
相关文章推荐
- Codeforces Round #303 (Div.2)-B. Equidistant String(模拟)
- clone
- POJ2524:Ubiquitous Religions (并查集模板)
- [置顶] JavaSE学习笔记_19:Java-GUI
- UIButton相关设置
- Xcode中添加UITableView后设置cell高度无法达到期望值的解决办法
- LeetCode *** 62. Unique Paths
- 62. Unique Paths
- easyUI框架下实现日期按年,年月,年月日方式显示
- 文章标题WERTYUIOP[ 每日一到算法题]
- D. Longest Subsequence
- D. Longest Subsequence
- Java之——生成短8位UUID
- 利用localStorage实现对ueditor编辑内容定时保存为草稿
- Cannot assign requested address解决办法
- uva 1152 4 values whose sum is zero ——yhx
- Light OJ 1061 N Queen Again
- 对于初学iOS开发者有用之在UITableView的导航栏中加入Item的方法
- HUE配置zookeeper,HDFS报错Failed to access filesystem root解决
- runOnUiThread-----startAnimation