Skip to content

Commit 5108b52

Browse files
committed
Add stat v2 and list v2 #133
Use unsafe to read bytes
1 parent 6ee88f5 commit 5108b52

30 files changed

Lines changed: 1045 additions & 217 deletions

AdvancedSharpAdbClient.Tests/Dummys/DummySyncService.cs

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,17 +25,17 @@ public async Task OpenAsync(CancellationToken cancellationToken = default)
2525
IsOpen = true;
2626
}
2727

28-
public void Pull(string remotePath, Stream stream, Action<SyncProgressChangedEventArgs> callback = null, in bool isCancelled = false)
28+
public void Pull(string remotePath, Stream stream, Action<SyncProgressChangedEventArgs> callback = null, bool useV2 = false, in bool isCancelled = false)
2929
{
30-
for (int i = 0; i <= 100; i++)
30+
for (uint i = 0; i <= 100; i++)
3131
{
3232
callback?.Invoke(new SyncProgressChangedEventArgs(i, 100));
3333
}
3434
}
3535

36-
public async Task PullAsync(string remotePath, Stream stream, Action<SyncProgressChangedEventArgs> callback = null, CancellationToken cancellationToken = default)
36+
public async Task PullAsync(string remotePath, Stream stream, Action<SyncProgressChangedEventArgs> callback = null, bool useV2 = false, CancellationToken cancellationToken = default)
3737
{
38-
for (int i = 0; i <= 100; i++)
38+
for (uint i = 0; i <= 100; i++)
3939
{
4040
await Task.Yield();
4141
callback?.Invoke(new SyncProgressChangedEventArgs(i, 100));
@@ -44,7 +44,7 @@ public async Task PullAsync(string remotePath, Stream stream, Action<SyncProgres
4444

4545
public void Push(Stream stream, string remotePath, UnixFileStatus permission, DateTimeOffset timestamp, Action<SyncProgressChangedEventArgs> callback = null, in bool isCancelled = false)
4646
{
47-
for (int i = 0; i <= 100; i++)
47+
for (uint i = 0; i <= 100; i++)
4848
{
4949
if (i == 100)
5050
{
@@ -56,7 +56,7 @@ public void Push(Stream stream, string remotePath, UnixFileStatus permission, Da
5656

5757
public async Task PushAsync(Stream stream, string remotePath, UnixFileStatus permission, DateTimeOffset timestamp, Action<SyncProgressChangedEventArgs> callback = null, CancellationToken cancellationToken = default)
5858
{
59-
for (int i = 0; i <= 100; i++)
59+
for (uint i = 0; i <= 100; i++)
6060
{
6161
await Task.Yield();
6262
if (i == 100)
@@ -79,14 +79,24 @@ public async Task ReopenAsync(CancellationToken cancellationToken = default)
7979

8080
IAsyncEnumerable<FileStatistics> ISyncService.GetDirectoryAsyncListing(string remotePath, CancellationToken cancellationToken) => throw new NotImplementedException();
8181

82+
IAsyncEnumerable<FileStatisticsV2> ISyncService.GetDirectoryAsyncListingV2(string remotePath, CancellationToken cancellationToken) => throw new NotImplementedException();
83+
8284
IEnumerable<FileStatistics> ISyncService.GetDirectoryListing(string remotePath) => throw new NotImplementedException();
8385

8486
Task<List<FileStatistics>> ISyncService.GetDirectoryListingAsync(string remotePath, CancellationToken cancellationToken) => throw new NotImplementedException();
8587

88+
IEnumerable<FileStatisticsV2> ISyncService.GetDirectoryListingV2(string remotePath) => throw new NotImplementedException();
89+
90+
Task<List<FileStatisticsV2>> ISyncService.GetDirectoryListingV2Async(string remotePath, CancellationToken cancellationToken) => throw new NotImplementedException();
91+
8692
FileStatistics ISyncService.Stat(string remotePath) => throw new NotImplementedException();
8793

8894
Task<FileStatistics> ISyncService.StatAsync(string remotePath, CancellationToken cancellationToken) => throw new NotImplementedException();
8995

96+
FileStatisticsV2 ISyncService.StatV2(string remotePath) => throw new NotImplementedException();
97+
98+
Task<FileStatisticsV2> ISyncService.StatV2Async(string remotePath, CancellationToken cancellationToken) => throw new NotImplementedException();
99+
90100
#endregion
91101
}
92102
}

AdvancedSharpAdbClient.Tests/SyncServiceTests.Async.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ public async Task GetAsyncListingTest()
164164
}
165165

166166
/// <summary>
167-
/// Tests the <see cref="SyncService.PullAsync(string, Stream, Action{SyncProgressChangedEventArgs}?, CancellationToken)"/> method.
167+
/// Tests the <see cref="SyncService.PullAsync(string, Stream, Action{SyncProgressChangedEventArgs}?, bool, CancellationToken)"/> method.
168168
/// </summary>
169169
[Fact]
170170
public async Task PullAsyncTest()

AdvancedSharpAdbClient.Tests/SyncServiceTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ public void GetListingTest()
111111
}
112112

113113
/// <summary>
114-
/// Tests the <see cref="SyncService.Pull(string, Stream, Action{SyncProgressChangedEventArgs}?, in bool)"/> method.
114+
/// Tests the <see cref="SyncService.Pull(string, Stream, Action{SyncProgressChangedEventArgs}?, bool, in bool)"/> method.
115115
/// </summary>
116116
[Fact]
117117
public void PullTest()

AdvancedSharpAdbClient/AdbSocket.Async.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@ public virtual async Task<string> ReadSyncStringAsync(CancellationToken cancella
221221
}
222222

223223
// Get the length of the string
224-
int len = reply[0] | (reply[1] << 8) | (reply[2] << 16) | (reply[3] << 24);
224+
int len = BitConverter.ToInt32(reply);
225225

226226
// And get the string
227227
reply = new byte[len];

AdvancedSharpAdbClient/AdbSocket.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -305,7 +305,7 @@ public virtual string ReadSyncString()
305305
}
306306

307307
// Get the length of the string
308-
int len = reply[0] | (reply[1] << 8) | (reply[2] << 16) | (reply[3] << 24);
308+
int len = BitConverter.ToInt32(reply);
309309

310310
// And get the string
311311
reply = new byte[len];

AdvancedSharpAdbClient/AdvancedSharpAdbClient.csproj

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
</PropertyGroup>
1111

1212
<PropertyGroup>
13+
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
1314
<CheckNotRecommendedTargetFramework>False</CheckNotRecommendedTargetFramework>
1415
<NoWarn>$(NoWarn);NU1902;NU1903</NoWarn>
1516
<TargetFrameworks>net8.0;net10.0;netstandard1.3;netstandard2.0;netstandard2.1</TargetFrameworks>
@@ -38,7 +39,8 @@
3839
System.Range;
3940
System.Runtime.CompilerServices.CallerArgumentExpressionAttribute;
4041
System.Runtime.CompilerServices.IsExternalInit;
41-
System.Runtime.CompilerServices.InterpolatedStringHandlerAttribute
42+
System.Runtime.CompilerServices.InterpolatedStringHandlerAttribute;
43+
System.Runtime.CompilerServices.OverloadResolutionPriorityAttribute
4244
</PolySharpIncludeGeneratedTypes>
4345
</PropertyGroup>
4446

@@ -51,7 +53,6 @@
5153
</PropertyGroup>
5254

5355
<PropertyGroup Condition="$([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'net6.0-windows10.0.17763.0'))">
54-
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
5556
<TargetPlatformMinVersion>10.0.10240.0</TargetPlatformMinVersion>
5657
</PropertyGroup>
5758

AdvancedSharpAdbClient/DeviceCommands/DeviceExtensions.Async.cs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -220,15 +220,18 @@ public static Task StopAppAsync(this IAdbClient client, DeviceData device, strin
220220
/// <param name="remotePath">The path, on the device, of the file to pull.</param>
221221
/// <param name="stream">A <see cref="Stream"/> that will receive the contents of the file.</param>
222222
/// <param name="callback">An optional parameter which, when specified, returns progress notifications. The progress is reported as a value between 0 and 100, representing the percentage of the file which has been transferred.</param>
223+
/// <param name="useV2"><see langword="true"/> if use <see cref="ISyncService.Stat"/>; <see langword="true"/> use <see cref="ISyncService.StatV2"/>.</param>
223224
/// <param name="cancellationToken">A <see cref="CancellationToken"/> that can be used to cancel the task.</param>
224225
/// <returns>A <see cref="Task"/> which represents the asynchronous operation.</returns>
226+
/// <remarks>V2 need Android 8 or above.</remarks>
225227
public static async Task PullAsync(this IAdbClient client, DeviceData device,
226228
string remotePath, Stream stream,
227229
Action<SyncProgressChangedEventArgs>? callback = null,
230+
bool useV2 = false,
228231
CancellationToken cancellationToken = default)
229232
{
230233
using ISyncService service = Factories.SyncServiceFactory(client, device);
231-
await service.PullAsync(remotePath, stream, callback, cancellationToken).ConfigureAwait(false);
234+
await service.PullAsync(remotePath, stream, callback, useV2, cancellationToken).ConfigureAwait(false);
232235
}
233236

234237
/// <summary>
@@ -404,15 +407,18 @@ public static Task InstallMultiplePackageAsync(this IAdbClient client, DeviceDat
404407
/// <param name="remotePath">The path, on the device, of the file to pull.</param>
405408
/// <param name="stream">A <see cref="Stream"/> that will receive the contents of the file.</param>
406409
/// <param name="progress">An optional parameter which, when specified, returns progress notifications. The progress is reported as a value between 0 and 100, representing the percentage of the file which has been transferred.</param>
410+
/// <param name="useV2"><see langword="true"/> if use <see cref="ISyncService.Stat"/>; <see langword="true"/> use <see cref="ISyncService.StatV2"/>.</param>
407411
/// <param name="cancellationToken">A <see cref="CancellationToken"/> that can be used to cancel the task.</param>
408412
/// <returns>A <see cref="Task"/> which represents the asynchronous operation.</returns>
413+
/// <remarks>V2 need Android 8 or above.</remarks>
409414
public static async Task PullAsync(this IAdbClient client, DeviceData device,
410415
string remotePath, Stream stream,
411416
IProgress<SyncProgressChangedEventArgs>? progress,
417+
bool useV2 = false,
412418
CancellationToken cancellationToken = default)
413419
{
414420
using ISyncService service = Factories.SyncServiceFactory(client, device);
415-
await service.PullAsync(remotePath, stream, progress.AsAction(), cancellationToken).ConfigureAwait(false);
421+
await service.PullAsync(remotePath, stream, progress.AsAction(), useV2, cancellationToken).ConfigureAwait(false);
416422
}
417423

418424
/// <summary>

AdvancedSharpAdbClient/DeviceCommands/DeviceExtensions.cs

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -181,14 +181,17 @@ public static void StopApp(this IAdbClient client, DeviceData device, string pac
181181
/// <param name="remotePath">The path, on the device, of the file to pull.</param>
182182
/// <param name="stream">A <see cref="Stream"/> that will receive the contents of the file.</param>
183183
/// <param name="callback">An optional parameter which, when specified, returns progress notifications. The progress is reported as a value between 0 and 100, representing the percentage of the file which has been transferred.</param>
184+
/// <param name="useV2"><see langword="true"/> if use <see cref="ISyncService.Stat"/>; <see langword="true"/> use <see cref="ISyncService.StatV2"/>.</param>
184185
/// <param name="isCancelled">A <see cref="bool"/> that can be used to cancel the task.</param>
186+
/// <remarks>V2 need Android 8 or above.</remarks>
185187
public static void Pull(this IAdbClient client, DeviceData device,
186188
string remotePath, Stream stream,
187189
Action<SyncProgressChangedEventArgs>? callback = null,
190+
bool useV2 = false,
188191
in bool isCancelled = false)
189192
{
190193
using ISyncService service = Factories.SyncServiceFactory(client, device);
191-
service.Pull(remotePath, stream, callback, in isCancelled);
194+
service.Pull(remotePath, stream, callback, useV2, in isCancelled);
192195
}
193196

194197
/// <summary>
@@ -225,6 +228,20 @@ public static FileStatistics Stat(this IAdbClient client, DeviceData device, str
225228
return service.Stat(path);
226229
}
227230

231+
/// <summary>
232+
/// Gets the file statistics of a given file (v2).
233+
/// </summary>
234+
/// <param name="client">The <see cref="IAdbClient"/> to use when executing the command.</param>
235+
/// <param name="device">The device on which to look for the file.</param>
236+
/// <param name="path">The path to the file.</param>
237+
/// <returns>A <see cref="FileStatisticsV2"/> object that represents the file.</returns>
238+
/// <remarks>Need Android 8 or above.</remarks>
239+
public static FileStatisticsV2 StatV2(this IAdbClient client, DeviceData device, string path)
240+
{
241+
using ISyncService service = Factories.SyncServiceFactory(client, device);
242+
return service.StatV2(path);
243+
}
244+
228245
/// <summary>
229246
/// Lists the contents of a directory on the device.
230247
/// </summary>
@@ -241,6 +258,23 @@ public static IEnumerable<FileStatistics> GetDirectoryListing(this IAdbClient cl
241258
}
242259
}
243260

261+
/// <summary>
262+
/// Lists the contents of a directory on the device.
263+
/// </summary>
264+
/// <param name="client">The <see cref="IAdbClient"/> to use when executing the command.</param>
265+
/// <param name="device">The device on which to list the directory.</param>
266+
/// <param name="remotePath">The path to the directory on the device.</param>
267+
/// <returns>For each child item of the directory, a <see cref="FileStatisticsV2"/> object with information of the item.</returns>
268+
/// <remarks>Need Android 11 or above.</remarks>
269+
public static IEnumerable<FileStatisticsV2> GetDirectoryListingV2(this IAdbClient client, DeviceData device, string remotePath)
270+
{
271+
using ISyncService service = Factories.SyncServiceFactory(client, device);
272+
foreach (FileStatisticsV2 fileStatistics in service.GetDirectoryListingV2(remotePath))
273+
{
274+
yield return fileStatistics;
275+
}
276+
}
277+
244278
/// <summary>
245279
/// Gets the property of a device.
246280
/// </summary>
@@ -337,14 +371,17 @@ public static void InstallMultiplePackage(this IAdbClient client, DeviceData dev
337371
/// <param name="remotePath">The path, on the device, of the file to pull.</param>
338372
/// <param name="stream">A <see cref="Stream"/> that will receive the contents of the file.</param>
339373
/// <param name="progress">An optional parameter which, when specified, returns progress notifications. The progress is reported as a value between 0 and 100, representing the percentage of the file which has been transferred.</param>
374+
/// <param name="useV2"><see langword="true"/> if use <see cref="Stat"/>; <see langword="true"/> use <see cref="ISyncService.StatV2"/>.</param>
340375
/// <param name="isCancelled">A <see cref="bool"/> that can be used to cancel the task.</param>
376+
/// <remarks>V2 need Android 8 or above.</remarks>
341377
public static void Pull(this IAdbClient client, DeviceData device,
342378
string remotePath, Stream stream,
343379
IProgress<SyncProgressChangedEventArgs>? progress = null,
380+
bool useV2 = false,
344381
in bool isCancelled = false)
345382
{
346383
using ISyncService service = Factories.SyncServiceFactory(client, device);
347-
service.Pull(remotePath, stream, progress.AsAction(), in isCancelled);
384+
service.Pull(remotePath, stream, progress.AsAction(), useV2, in isCancelled);
348385
}
349386

350387
/// <summary>

AdvancedSharpAdbClient/Extensions/EnumerableBuilder.cs

Lines changed: 45 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,14 @@ public static AdbCommandLineStatus AdbCommandLineStatusCreator(params ReadOnlySp
2929
/// </summary>
3030
/// <param name="values">The data that feeds the <see cref="ColorData"/> struct.</param>
3131
/// <returns>A new instance of <see cref="ColorData"/> struct.</returns>
32-
public static ColorData ColorDataCreator(ReadOnlySpan<byte> values) =>
33-
new((uint)(values[0] | (values[1] << 8) | (values[2] << 16) | (values[3] << 24)),
34-
(uint)(values[4] | (values[5] << 8) | (values[6] << 16) | (values[7] << 24)));
32+
public static unsafe ColorData ColorDataCreator(ReadOnlySpan<byte> values)
33+
{
34+
fixed (byte* p = values)
35+
{
36+
ColorData* data = (ColorData*)p;
37+
return *data;
38+
}
39+
}
3540

3641
/// <summary>
3742
/// Build a <see cref="FramebufferHeader"/> struct.
@@ -45,25 +50,49 @@ public static ColorData ColorDataCreator(ReadOnlySpan<byte> values) =>
4550
/// </summary>
4651
/// <param name="values">The data that feeds the <see cref="FileStatistics"/> struct.</param>
4752
/// <returns>A new instance of <see cref="FileStatistics"/> struct.</returns>
48-
public static FileStatistics FileStatisticsCreator(ReadOnlySpan<byte> values)
53+
public static FileStatistics FileStatisticsCreator(ReadOnlySpan<byte> values) => new(FileStatisticsDataCreator(values));
54+
55+
/// <summary>
56+
/// Build a <see cref="FileStatisticsData"/> struct.
57+
/// </summary>
58+
/// <param name="values">The data that feeds the <see cref="FileStatisticsData"/> struct.</param>
59+
/// <returns>A new instance of <see cref="FileStatisticsData"/> struct.</returns>
60+
public static unsafe FileStatisticsData FileStatisticsDataCreator(ReadOnlySpan<byte> values)
4961
{
50-
int index = 0;
51-
return new FileStatistics
62+
fixed (byte* p = values)
5263
{
53-
FileMode = (UnixFileStatus)ReadUInt32(values),
54-
Size = ReadUInt32(values),
55-
Time = DateTimeOffset.FromUnixTimeSeconds(ReadUInt32(values))
56-
};
57-
uint ReadUInt32(in ReadOnlySpan<byte> data) => unchecked((uint)(data[index++] | (data[index++] << 8) | (data[index++] << 16) | (data[index++] << 24)));
64+
FileStatisticsData* data = (FileStatisticsData*)p;
65+
return *data;
66+
}
67+
}
68+
69+
/// <summary>
70+
/// Build a <see cref="FileStatisticsV2"/> struct.
71+
/// </summary>
72+
/// <param name="values">The data that feeds the <see cref="FileStatisticsV2"/> struct.</param>
73+
/// <returns>A new instance of <see cref="FileStatisticsV2"/> struct.</returns>
74+
public static FileStatisticsV2 FileStatisticsV2Creator(ReadOnlySpan<byte> values) => new(FileStatisticsDataV2Creator(values));
75+
76+
/// <summary>
77+
/// Build a <see cref="FileStatisticsDataV2"/> struct.
78+
/// </summary>
79+
/// <param name="values">The data that feeds the <see cref="FileStatisticsDataV2"/> struct.</param>
80+
/// <returns>A new instance of <see cref="FileStatisticsDataV2"/> struct.</returns>
81+
public static unsafe FileStatisticsDataV2 FileStatisticsDataV2Creator(ReadOnlySpan<byte> values)
82+
{
83+
fixed (byte* p = values)
84+
{
85+
FileStatisticsDataV2* data = (FileStatisticsDataV2*)p;
86+
return *data;
87+
}
5888
}
5989

6090
/// <summary>
6191
/// Build a <see cref="UnixFileStatus"/> enum.
6292
/// </summary>
6393
/// <param name="values">The data that feeds the <see cref="UnixFileStatus"/> struct.</param>
6494
/// <returns>A new instance of <see cref="UnixFileStatus"/> struct.</returns>
65-
public static UnixFileStatus UnixFileStatusCreator(ReadOnlySpan<byte> values) =>
66-
(UnixFileStatus)(values[0] | (values[1] << 8) | (values[2] << 16) | (values[3] << 24));
95+
public static unsafe UnixFileStatus UnixFileStatusCreator(ReadOnlySpan<byte> values) => (UnixFileStatus)BitConverter.ToUInt32(values);
6796

6897
/// <summary>
6998
/// Build a <see cref="LogEntry"/> class.
@@ -276,19 +305,19 @@ static void ReadLogEntry(BinaryReader reader, params ICollection<object> parent)
276305
ushort? ReadUInt16(in ReadOnlySpan<byte> bytes)
277306
{
278307
ReadOnlySpan<byte> data = ReadBytesSafe(bytes, 2);
279-
return data.IsEmpty ? null : (ushort)(data[0] | (data[1] << 8));
308+
return data.IsEmpty ? null : BitConverter.ToUInt16(data);
280309
}
281310

282311
uint? ReadUInt32(in ReadOnlySpan<byte> bytes)
283312
{
284313
ReadOnlySpan<byte> data = ReadBytesSafe(bytes, 4);
285-
return data.IsEmpty ? null : (uint)(data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24));
314+
return data.IsEmpty ? null : BitConverter.ToUInt32(data);
286315
}
287316

288317
int? ReadInt32(in ReadOnlySpan<byte> bytes)
289318
{
290319
ReadOnlySpan<byte> data = ReadBytesSafe(bytes, 4);
291-
return data.Length != 4 ? null : data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24);
320+
return data.Length != 4 ? null : BitConverter.ToInt32(data);
292321
}
293322

294323
ReadOnlySpan<byte> ReadBytesSafe(in ReadOnlySpan<byte> bytes, int count)

0 commit comments

Comments
 (0)