/usr/src/castle-game-engine-5.2.0/base/android/castleandroidassetstream.pas is in castle-game-engine-src 5.2.0-2.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 | {
Copyright 2013-2014 Michalis Kamburelis.
This file is part of "Castle Game Engine".
"Castle Game Engine" is free software; see the file COPYING.txt,
included in this distribution, for details about the copyright.
"Castle Game Engine" is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
----------------------------------------------------------------------------
}
{ Reading Android asset files as streams. }
unit CastleAndroidAssetStream;
interface
uses SysUtils, Classes, CastleAndroidAssetManager;
type
EAssetReadError = class(EReadError);
EAssetNotFound = class(EAssetReadError);
TReadAssetStream = class(TStream)
private
Asset: PAAsset;
FPosition: Int64;
protected
function GetSize: Int64; override;
function GetPosition: Int64; override;
{ This stream doesn't support setting size.
(All other versions of SetSize also call this.)
@raises(EStreamNotImplementedSetSize Always.) }
procedure SetSize(NewSize: Longint); override;
public
{ Open a stream for an asset on given path.
The path should be a valid Android asset path,
like @code(images/my_texture.png). }
constructor Create(Path: string);
destructor Destroy; override;
{ This stream doesn't support seeking.
(SetPosition and all other versions of Seek also call this.)
@raises(EStreamNotImplementedSeek Always.) }
function Seek(const Offset: Int64; Origin: TSeekOrigin): Int64; override;
{ This stream doesn't support writing.
(WriteBuffer also calls this.)
@raises(EStreamNotImplementedWrite Always.) }
function Write(const Buffer; Count: Longint): Longint; override;
function Read(var Buffer; Count: Longint): Longint; override;
end;
var
{ Asset manager reference, automatically set by the Android initialization
code (usually CastleWindow), and used for reading assets. }
AssetManager: PAAssetManager;
{ Assuming that this is @code(assets:/xxx/yyy) URL, convert it to an asset path
@code(xxx/yyy). Does percent-decoding along the way. }
function URIToAssetPath(const URI: string): string;
function AssetPathToURI(const AssetPath: string): string;
implementation
uses CastleClassUtils, CastleLog, CastleStringUtils, URIParser;
constructor TReadAssetStream.Create(Path: string);
begin
inherited Create;
if ExtractFileExt(Path) = '.gz' then
begin
WritelnLog('Assets', 'Trying to access asset with .gz extension, stripping the .gz (because Android tools strip them too when packing the .apk file): %s',
[Path]);
Path := ChangeFileExt(Path, '');
end;
Asset := AAssetManager_open(AssetManager, PChar(Path), AASSET_MODE_STREAMING);
if Asset = nil then
raise EAssetNotFound.CreateFmt('Asset "%s" not found', [Path]);
end;
destructor TReadAssetStream.Destroy;
begin
if Asset <> nil then
AAsset_close(Asset);
inherited;
end;
function TReadAssetStream.Read(var Buffer; Count: Longint): Longint;
begin
Result := AAsset_read(Asset, @Buffer, Count);
if Result < 0 then
raise EAssetReadError.Create('Error when reading asset data stream');
FPosition += Result;
end;
function TReadAssetStream.GetSize: Int64;
begin
Result := AAsset_getLength(Asset);
{ Take only the least-significant 32 bits of result, because
on some Androids the higher 32-bits are nonsense (Sony Ericsson,
Android 2.3.4, WT191l). }
Result := Result and Int64(High(LongWord));
end;
function TReadAssetStream.GetPosition: Int64;
begin
Result := FPosition;
end;
procedure TReadAssetStream.SetSize(NewSize: Longint);
begin
raise EStreamNotImplementedSetSize.Create(
'TReadAssetStream.SetSize not supported');
end;
function TReadAssetStream.Seek(const Offset: Int64; Origin: TSeekOrigin): Int64;
begin
if ( (Origin = soBeginning) and (Offset = FPosition) ) or
( (Origin = soCurrent ) and (Offset = 0) ) then
{ nothing needs to be done, ok }
Exit;
raise EStreamNotImplementedSeek.Create('TReadAssetStream.Seek not supported');
Result := 0; // just to get rid of warning
end;
function TReadAssetStream.Write(const Buffer; Count: Longint): Longint;
begin
raise EStreamNotImplementedWrite.Create('TReadAssetStream.Write not supported');
Result := 0; // just to get rid of warning
end;
{ global routines ------------------------------------------------------------ }
function URIToAssetPath(const URI: string): string;
var
U: TURI;
begin
U := ParseURI(URI);
if SameText(U.Protocol, 'assets') then
Result := PrefixRemove('/', U.Path + U.Document, false) else
raise Exception.CreateFmt('URI does not have protocol "assets:", cannot convert to asset path: %s, protocol %s',
[URI, U.Protocol]);
end;
function AssetPathToURI(const AssetPath: string): string;
var
U: TURI;
begin
FillByte(U, SizeOf(U), 0);
U.Protocol := 'assets';
U.Path := '/' + AssetPath; // AssetPath does not start with slash
Result := EncodeURI(U);
end;
end.
|