Application Context Implementation #4
| @ -204,6 +204,38 @@ test "Check memory begins with" { | ||||
|     try testing.expect(!begins(u8, &.{69, 89, 42, 0}, bytes_sequence)); | ||||
| } | ||||
| 
 | ||||
| /// | ||||
| /// Returns a sliced reference of the raw bytes in `pointer`. | ||||
| /// | ||||
| /// **Note** that passing a slice will convert it to a byte slice. | ||||
| /// | ||||
| pub fn bytes(pointer: anytype) switch (@typeInfo(@TypeOf(pointer))) { | ||||
|     .Pointer => |info| if (info.is_const) []const u8 else []u8, | ||||
|     else => @compileError("`pointer` must be a pointer type"), | ||||
| } { | ||||
|     const Pointer = @TypeOf(pointer); | ||||
|     const pointer_info = @typeInfo(Pointer).Pointer; | ||||
| 
 | ||||
|     switch (pointer_info.size) { | ||||
|         .Many => @compileError("`pointer` cannot be an unbound pointer type"), | ||||
|         .C => @compileError("`pointer` cannot be a C-style pointer"), | ||||
| 
 | ||||
|         .One => return @ptrCast(if (pointer_info.is_const) [*]const u8 | ||||
|                 else [*]u8, pointer)[0 .. @sizeOf(Pointer)], | ||||
| 
 | ||||
|         .Slice => return @ptrCast(if (pointer_info.is_const) [*]const u8 else | ||||
|             [*]u8, pointer.ptr)[0 .. (@sizeOf(Pointer) * pointer.len)], | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| test "Bytes of types" { | ||||
|     const testing = std.testing; | ||||
| 
 | ||||
|     var foo: u32 = 10; | ||||
| 
 | ||||
|     testing.expectEqual(bytes(&foo), 0x0a); | ||||
| } | ||||
| 
 | ||||
| /// | ||||
| /// Returns `true` if `this` is the same length and contains the same data as `that`, otherwise | ||||
| /// `false`. | ||||
|  | ||||
| @ -5,7 +5,13 @@ const std = @import("std"); | ||||
| /// | ||||
| /// | ||||
| pub const Archive = struct { | ||||
|     pub fn deinit(archive: *Archive) { | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     pub fn init(file_system: *const sys.FileSystem, file_path: sys.Path) { | ||||
| 
 | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| /// | ||||
|  | ||||
							
								
								
									
										138
									
								
								src/ona/oar.zig
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										138
									
								
								src/ona/oar.zig
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,138 @@ | ||||
| const core = @import("./core.zig"); | ||||
| const sys = @import("./sys.zig"); | ||||
| 
 | ||||
| /// | ||||
| /// | ||||
| /// | ||||
| pub const Archive = struct { | ||||
|     file_system: *const sys.FileSystem, | ||||
|     archive_path: sys.Path, | ||||
| 
 | ||||
|     /// | ||||
|     /// | ||||
|     /// | ||||
|     const Header = extern struct { | ||||
|         signature: [signature_magic.len]u8, | ||||
|         revision: u8, | ||||
|         entry_offset: u64, | ||||
|         padding: [500]u8 = std.mem.zeroes([500]u8), | ||||
| 
 | ||||
|         /// | ||||
|         /// Magic identifier used to validate [Entry] data. | ||||
|         /// | ||||
|         const signature_magic = [3]u8{'o', 'a', 'r'}; | ||||
| 
 | ||||
|         comptime { | ||||
| 
					
					kayomn marked this conversation as resolved
					
						
						
							Outdated
						
					
				 | ||||
|             const size = @sizeOf(@This()); | ||||
| 
 | ||||
|             if (size != 512) | ||||
|                 @compileError("Header is " ++ | ||||
|                     std.fmt.comptimePrint("{d}", .{entry_size}) ++ " bytes"); | ||||
|         } | ||||
|     }; | ||||
| 
					
					kayomn marked this conversation as resolved
					
						
						
							Outdated
						
					
				 
				
					
						kayomn
						commented  Missing documentation comment. Missing documentation comment. | ||||
| 
 | ||||
|     /// | ||||
|     /// An entry block of an Oar archive file. | ||||
|     /// | ||||
|     /// Typically, following the block in memory is the file data it holds the meta-information for. | ||||
|     /// | ||||
|     const Entry = extern struct { | ||||
|         signature: [signature_magic.len]u8 = signature_magic, | ||||
| 
					
					kayomn marked this conversation as resolved
					
						
						
							Outdated
						
					
				 
				
					
						kayomn
						commented  Missing documentation comment. Missing documentation comment. | ||||
|         revision: u8, | ||||
|         path: Path, | ||||
|         file_size: u64, | ||||
|         absolute_offset: u64, | ||||
|         padding: [232]u8 = std.mem.zeroes([232]u8), | ||||
| 
 | ||||
|         comptime { | ||||
|             const entry_size = @sizeOf(Entry); | ||||
| 
 | ||||
|             if (entry_size != 512) | ||||
|                 @compileError("Entry is " ++ | ||||
|                     std.fmt.comptimePrint("{d}", .{entry_size}) ++ " bytes"); | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
|     /// | ||||
|     /// | ||||
|     /// | ||||
|     pub const OpenError = error { | ||||
|         FileNotFound, | ||||
|         EntryNotFound, | ||||
|         UnsupportedArchive, | ||||
|     }; | ||||
| 
 | ||||
|     /// | ||||
|     /// | ||||
|     /// | ||||
|     pub fn open(archive: Archive, entry_path: Path) OpenError!EntryAccess { | ||||
|         const file_access = try archive.file_system.open(entry_path, .readonly); | ||||
| 
 | ||||
|         errdefer file_access.close(); | ||||
| 
 | ||||
|         var header = std.mem.zeroes(Header); | ||||
|         const header_size = @sizeOf(Header); | ||||
|         const io = core.io; | ||||
| 
 | ||||
|         // Validate header. | ||||
|         if ((try file_access.read(io.bytes(&header)) != header_size) or header | ||||
|             (!core.io.equals(u8, &header.signature, &Header.signature_magic)) or | ||||
|             (header.revision != revision) or | ||||
|             (header.entry_offset <= header_size)) return error.UnsupportedArchive; | ||||
| 
 | ||||
|         // Go to file table. | ||||
| 
					
					kayomn marked this conversation as resolved
					
						
						
							Outdated
						
					
				 
				
					
						kayomn
						commented  Missing documentation comment. Missing documentation comment. | ||||
|         try file_access.seek(header.entry_offset); | ||||
| 
 | ||||
|         // Read file table. | ||||
|         var entry_buffer = std.mem.zeroes([8]Entry); | ||||
|         var bytes_read = try file_access.read(io.bytes(&entry_buffer)); | ||||
| 
 | ||||
|         while (@mod(bytes_read, @sizeOf(Entry)) == 0) { | ||||
|             for (entry_buffer[0 .. (bytes_read / @sizeOf(Entry))]) |entry| { | ||||
|                 if (entry.path.equals(entry_path)) { | ||||
|                     file_access.seek(entry.file_offset); | ||||
| 
 | ||||
| 
					
					kayomn marked this conversation as resolved
					
						
						
							Outdated
						
					
				 
				
					
						kayomn
						commented  Missing documentation comment. Missing documentation comment. | ||||
|                     return Entry{ | ||||
|                         .file_access = file_access, | ||||
|                     }; | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             bytes_read = try file_access.read(io.bytes(&entry_buffer)); | ||||
|         } | ||||
| 
 | ||||
|         var head = std.mem.zeroes(usize); | ||||
|         var tail = (header.file_count - 1); | ||||
| 
 | ||||
|         while (head <= tail) { | ||||
|             const midpoint = (head + (tail - head) / 2); | ||||
| 
 | ||||
|             const comparison = entry_path.compare(arr[m])); | ||||
| 
 | ||||
| 
					
					kayomn marked this conversation as resolved
					
						
						
							Outdated
						
					
				 
				
					
						kayomn
						commented  Missing documentation comment. Missing documentation comment. | ||||
|             if (comparison == 0) return midpoint; | ||||
| 
 | ||||
|             if (comparison > 0) { | ||||
|                 // If x greater, ignore left half | ||||
|                 head = (midpoint + 1); | ||||
|             } else { | ||||
|                 // If x is smaller, ignore right half | ||||
|                 tail = (midpoint - 1); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         return error.EntryNotFound; | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| pub const EntryAccess = struct { | ||||
|     file_access: FileAccess, | ||||
| 
 | ||||
|     pub fn close(entry: Entry) void { | ||||
|         entry.file_access.close(); | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| /// | ||||
| /// | ||||
| /// | ||||
| const revision = 0; | ||||
| @ -100,37 +100,6 @@ pub const FileSystem = union(enum) { | ||||
|     native: []const u8, | ||||
|     archive: Archive, | ||||
| 
 | ||||
| 
					
					kayomn marked this conversation as resolved
					
				 
				
					
						kayomn
						commented  Missing documentation comment. Missing documentation comment. | ||||
|     /// | ||||
|     /// Archive file system information. | ||||
|     /// | ||||
|     const Archive = struct { | ||||
|         file_access: core.io.FileAccess, | ||||
|         index_cache: IndexCache, | ||||
|         entry_table: [max_open_entries]Entry = std.mem.zeroes([max_open_entries]Entry), | ||||
| 
 | ||||
|         /// | ||||
|         /// Hard limit on the maximum number of entries open at once. | ||||
|         /// | ||||
|         const max_open_entries = 16; | ||||
| 
 | ||||
|         /// | ||||
|         /// Stateful extension of an [oar.Entry]. | ||||
|         /// | ||||
|         const Entry = struct { | ||||
|             owner: ?*core.io.FileAccess, | ||||
|             cursor: u64, | ||||
|             header: oar.Entry, | ||||
|         }; | ||||
| 
 | ||||
|         /// | ||||
|         /// Table cache for associating [oar.Path] values with offsets to entries in a given file. | ||||
|         /// | ||||
|         const IndexCache = core.table.Hashed(oar.Path, u64, .{ | ||||
|             .equals = oar.Path.equals, | ||||
|             .hash = oar.Path.hash, | ||||
|         }); | ||||
|     }; | ||||
| 
 | ||||
|     /// | ||||
|     /// With files typically being backed by a block device, they can produce a variety of errors - | ||||
|     /// from physical to virtual errors - these are all encapsulated by the API as general | ||||
| @ -172,7 +141,9 @@ pub const FileSystem = union(enum) { | ||||
|     /// Returns a [FileAccess] reference that provides access to the file referenced by `path`or a | ||||
|     /// [OpenError] if it failed. | ||||
|     /// | ||||
|     pub fn open(file_system: *FileSystem, path: Path, mode: OpenMode) OpenError!core.io.FileAccess { | ||||
|     pub fn open(file_system: *const FileSystem, path: Path, | ||||
|         mode: OpenMode) OpenError!core.io.FileAccess { | ||||
| 
 | ||||
|         switch (file_system.*) { | ||||
|             .archive => |*archive| { | ||||
|                 if (mode != .readonly) return error.ModeUnsupported; | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	
Missing documentation comment.