summaryrefslogtreecommitdiffstats
path: root/patterns/xcur.hexpat
diff options
context:
space:
mode:
Diffstat (limited to 'patterns/xcur.hexpat')
-rw-r--r--patterns/xcur.hexpat107
1 files changed, 107 insertions, 0 deletions
diff --git a/patterns/xcur.hexpat b/patterns/xcur.hexpat
new file mode 100644
index 0000000..c14a2ee
--- /dev/null
+++ b/patterns/xcur.hexpat
@@ -0,0 +1,107 @@
+#pragma author memdmp
+#pragma description XCursor (.xcur) file format
+
+#pragma MIME image/x-xcursor
+
+#pragma endian little
+#pragma magic [ 58 63 75 72 ] @ 0x00
+#pragma pattern_limit 4294967295
+
+import std.sys;
+import type.magic;
+
+struct ARGBPixel {
+ u8 alpha [[color("ffffff")]];
+ u8 red [[color("ff0000")]];
+ u8 green [[color("00ff00")]];
+ u8 blue [[color("0000ff")]];
+} [[static, color(std::format("{:02X}{:02X}{:02X}", red, green, blue))]];
+
+struct ARGBPixelRow<auto rowSize> {
+ ARGBPixel columns[rowSize] [[name("Columns"), inline]];
+};
+struct ARGBImageData<auto rowSize, auto colSize> {
+ ARGBPixelRow<rowSize> rows[colSize] [[name("Rows"), inline]];
+};
+
+enum ChunkHeaderSize : u32 {
+ Comment = 20,
+ Image = 36,
+};
+enum ChunkType : u32 {
+ Comment = 0xfffe0001,
+ Image = 0xfffd0002
+};
+enum CommentSubtype : u32 {
+ Copyright = 1,
+ License = 2,
+ Other = 3,
+};
+
+struct Chunk<auto tocSubtype> {
+ /** Must match chunkType */
+ ChunkHeaderSize chunkHeaderSize [[name("Chunk Header Size"), single_color]];
+ /** Must match chunkHeaderSize */
+ ChunkType chunkType [[name("Chunk Type"), single_color]];
+ if (chunkType == ChunkType::Image) {
+ std::assert_warn(chunkHeaderSize == ChunkHeaderSize::Image, "ChunkType::Image requires ChunkHeaderSize::Image. Behaviour is undefined.");
+ /** The subtype - should(/must) match the one in the table of contents */
+ u32 subtype [[name("Subtype"), single_color]];
+ std::assert_warn(tocSubtype == subtype, "TOC subtype should match Chunk subtype for images.");
+ /** Must be 1 */
+ u32 version [[name("Image Spec Version"), single_color]];
+ std::assert_warn(version == 1, "version != 1 is not supported for ChunkType::Image");
+ /** Width of the cursor */
+ u32 width [[name("Width"), single_color]];
+ std::assert_warn(width <= 0x7fff, "0x7fff is the maximum allowed width!");
+ /** Height of the cursor */
+ u32 height [[name("Height"), single_color]];
+ std::assert_warn(height <= 0x7fff, "0x7fff is the maximum allowed height!");
+ /** Real cursor X position within the bitmap */
+ u32 xhot [[name("X Position (xhot)"), single_color]];
+ std::assert_warn(xhot <= width, "xhot must be less than or equal to width");
+ /** Real cursor Y position within the bitmap */
+ u32 yhot [[name("Y Position (yhot)"), single_color]];
+ std::assert_warn(yhot <= height, "yhot must be less than or equal to height");
+ /** Delay between frames with the same subtype */
+ u32 delay_ms [[name("Delay (ms)"), single_color]];
+ ARGBImageData<width, height> pixels;
+ } else if (chunkType == ChunkType::Comment) {
+ std::assert_warn(chunkHeaderSize == ChunkHeaderSize::Comment, "ChunkType::Comment requires ChunkHeaderSize::Comment. Behaviour is undefined.");
+ /** What kinda comment it is */
+ CommentSubtype subtype [[name("Comment Type"), single_color]];
+ /** Must be 1 */
+ u32 version [[name("Comment Version"), single_color]];
+ std::assert_warn(version == 1, "version != 1 is not supported for ChunkType::Comment");
+ /** The length of the contents */
+ u32 length [[name("Comment Length"), single_color]];
+ /** The contents */
+ char contents[length] [[name("Comment Contents"), single_color]];
+ }
+};
+
+struct Toc {
+ /** Entry Type */
+ char type[4] [[name("Entry Type"), single_color]];
+ /** The subtype - used to distinguish between different sizes */
+ u32 subtype [[name("Entry Subtype"), single_color]];
+ /** Pointer to the chunk */
+ Chunk<subtype> *position : u32 [[name("Chunk Pointer"), single_color]];
+};
+
+struct XCursor {
+ /** Magic string, must be "Xcur" (0x58 0x63 0x75 0x72) */
+ type::Magic<"Xcur"> magic [[name("Magic"), comment("The XCursor Magic string"), color("000000")]];
+ /** bytes in this header */
+ u32 header_size [[name("Header Size"), comment("Indicates the size of the current file header, in bytes"), color("99aaff")]];
+ std::assert_warn(header_size == 12, "Cursor is required to have a 12 byte header size");
+ /** File version number */
+ u32 version [[name("File Version"), color("7744ff")]];
+ std::assert_warn(version == 1, "Only Xcur v1 is supported");
+ /** Number of table of contents entries */
+ u32 ntoc [[name("TOC Length"), comment("Indicates the amount of entries in the table of contents"), color("cc99bb")]];
+ /** Table of contents entries */
+ Toc toc[ntoc] [[name("Table of Contents")]];
+};
+
+XCursor xcursor @ 0x00 [[name("XCursor")]];