diff --git a/.gitmodules b/.gitmodules index 6947977ff2..affe64d3a9 100644 --- a/.gitmodules +++ b/.gitmodules @@ -112,6 +112,9 @@ [submodule "vendor/grammars/PHP-Twig.tmbundle"] path = vendor/grammars/PHP-Twig.tmbundle url = https://github.com/Anomareh/PHP-Twig.tmbundle +[submodule "vendor/grammars/PatternLanguage-Grammar"] + path = vendor/grammars/PatternLanguage-Grammar + url = https://github.com/WerWolv/PatternLanguage-Grammar.git [submodule "vendor/grammars/PogoScript.tmbundle"] path = vendor/grammars/PogoScript.tmbundle url = https://github.com/featurist/PogoScript.tmbundle diff --git a/grammars.yml b/grammars.yml index dba0be30d3..1084b65931 100644 --- a/grammars.yml +++ b/grammars.yml @@ -100,6 +100,8 @@ vendor/grammars/ObjectScript.tmBundle: - source.objectscript_macros vendor/grammars/PHP-Twig.tmbundle: - text.html.twig +vendor/grammars/PatternLanguage-Grammar: +- source.pl vendor/grammars/PogoScript.tmbundle: - source.pogoscript vendor/grammars/PowerBuilder.tmbundle: diff --git a/lib/linguist/languages.yml b/lib/linguist/languages.yml index 108105d56e..3634b14984 100644 --- a/lib/linguist/languages.yml +++ b/lib/linguist/languages.yml @@ -3275,6 +3275,20 @@ INI: codemirror_mode: properties codemirror_mime_type: text/x-properties language_id: 163 +ImHex Pattern Language: + type: programming + color: "#3a6be0" + extensions: + - ".hexpat" + aliases: + - ImHex + - ImHexPatternLanguage + - imhexpl + tm_scope: source.pl + ace_mode: c_cpp + codemirror_mode: clike + codemirror_mime_type: text/x-csrc + language_id: 805861688 IRC log: type: data aliases: diff --git a/samples/ImHex Pattern Language/jpeg.hexpat b/samples/ImHex Pattern Language/jpeg.hexpat new file mode 100644 index 0000000000..8f74ef9810 --- /dev/null +++ b/samples/ImHex Pattern Language/jpeg.hexpat @@ -0,0 +1,167 @@ +#pragma author WerWolv +#pragma description JPEG Image + +import std.io; +import std.mem; +import type.magic; +#pragma endian big + +#pragma MIME image/jpeg + +enum Marker : u8 { + TEM = 0x01, + SOF0 = 0xC0, + SOF1 = 0xC1, + SOF2 = 0xC2, + SOF3 = 0xC3, + DHT = 0xC4, + SOF5 = 0xC5, + SOF6 = 0xC6, + SOF7 = 0xC7, + SOI = 0xD8, + EOI = 0xD9, + SOS = 0xDA, + DQT = 0xDB, + DNL = 0xDC, + DRI = 0xDD, + DHP = 0xDE, + APP0 = 0xE0, + APP1 = 0xE1, + APP2 = 0xE2, + APP3 = 0xE3, + APP4 = 0xE4, + APP5 = 0xE5, + APP6 = 0xE6, + APP7 = 0xE7, + APP8 = 0xE8, + APP9 = 0xE9, + APP10 = 0xEA, + APP11 = 0xEB, + APP12 = 0xEC, + APP13 = 0xED, + APP14 = 0xEE, + APP15 = 0xEF, + COM = 0xFE, + UNKNOWN = 0x00 +}; + +enum DensityUnit : u8 { + NoUnit = 0x00, + PixelsPerInch = 0x01, + PixelsPerCm = 0x02 +}; + +enum ColorTransform : u8 { + Unknown = 0x00, + YCbCr = 0x01, + YCCK = 0x02 +}; + +struct Pixel { + u8 r, g, b; +} [[sealed, transform("transform_pixel")]]; + +fn transform_pixel(Pixel pixel) { + return (0xFF << 24) | (pixel.b << 16) | (pixel.g << 8) | (pixel.r << 0); +}; + + +struct APP0 { + type::Magic<"JFIF\x00"> magic; + u8 versionMajor, versionMinor; + DensityUnit densityUnit; + u16 densityX, densityY; + u8 thumbnailX, thumbnailY; + Pixel thumbnail[thumbnailX * thumbnailY] [[sealed]]; +}; + +struct APP14 { + type::Magic<"Adobe"> magic; + u16 version; + u16 flags0; + u16 flags1; + ColorTransform transform; +}; + +enum ComponentId : u8 { + Y = 1, + CB = 2, + CR = 3, + I = 4, + Q = 5, + B = 66, + G = 71, + R = 82 +}; + +struct SOF0Component { + ComponentId componentId; + u8 samplingFactors; + u8 quantizationTableId; +} [[format_read("sof0_component_read")]]; + +fn sof0_component_read(SOF0Component c) { + return std::format("({}, {}, {})", c.componentId, c.samplingFactors, c.quantizationTableId); +}; + +fn get_eoi_marker_position() { + u32 pos = std::mem::find_sequence_in_range(0, $, std::mem::size(), 0xFF, 0xD9); + return pos; + +}; + +struct SOF0 { + u8 bitsPerSample; + u16 imageHeight, imageWidth; + u8 numComponents; + SOF0Component components[numComponents]; +}; + +struct SOSComponent { + ComponentId componentId; + u8 huffmanTable; +}; + +struct SOS { + u8 numComponents; + SOSComponent components[numComponents]; + u8 startSpectralSelection; + u8 endSpectral; + u8 apprBitPos; + u8 image_data[get_eoi_marker_position() - $] [[sealed]]; +}; + +struct Segment { + if (std::mem::read_unsigned($, 1) != 0xFF) { + Marker marker = Marker::UNKNOWN; + u8 data[get_eoi_marker_position() - $]; + } else { + type::Magic<"\xff"> magic; + Marker marker; + + if (marker == Marker::SOI || marker == Marker::EOI) { + + } else { + u16 length; + if (marker == Marker::APP0) { + APP0 data; + } else if (marker == Marker::APP14) { + APP14 data; + } else if (marker == Marker::COM) { + char data[length - sizeof(length)]; + } else if (marker == Marker::SOF0) { + SOF0 data; + } else if (marker == Marker::SOS) { + SOS data; + } else { + u8 data[length - sizeof(length)] [[sealed]]; + } + } + } +} [[format_read("segment_read")]]; + +fn segment_read(Segment s) { + return std::format("{}", s.marker); +}; + +Segment segments[while(!std::mem::eof())] @ 0x00 [[hex::visualize("image", this)]]; diff --git a/samples/ImHex Pattern Language/sqlite.hexpat b/samples/ImHex Pattern Language/sqlite.hexpat new file mode 100644 index 0000000000..70f5e73eb6 --- /dev/null +++ b/samples/ImHex Pattern Language/sqlite.hexpat @@ -0,0 +1,95 @@ +#pragma description SQLite 3 database +#pragma author WerWolv +#pragma MIME application/vnd.sqlite3 + +import type.magic; + +enum FileFormatVersion : u8 { + Legacy = 1, + WAL = 2 +}; + +enum TextEncoding : u32 { + UTF8 = 1, + UTF16LE = 2, + UTF16BE = 3 +}; + +struct SQLiteVersion { + u32 rawValue; + + u8 major = (rawValue / 1000000) % 1000 [[export]]; + u8 minor = (rawValue / 1000) % 1000 [[export]]; + u8 patch = (rawValue / 1) % 1000 [[export]]; +} [[sealed, format("format_sqlite_version")]]; + +fn format_sqlite_version(ref auto version) { + return std::format("v{}.{}.{} [{}]", version.major, version.minor, version.patch, version.rawValue); +}; + +u16 globalPageSize = 0; + +enum PageType : u8 { + InteriorIndexBTreePage = 0x02, + InteriorTableBTreePage = 0x05, + LeafIndexBTreePage = 0x0A, + LeafTableBTreePage = 0x0D +}; + +struct Page { + PageType pageType; + u16 freeBlockStart; + u16 numCells; + u16 cellContentAreaStart; + u8 fragmentedFreeBytesCount; + + if (pageType == PageType::InteriorIndexBTreePage || pageType == PageType::InteriorTableBTreePage) + u32 rightMostPointer; +} [[fixed_size(le u16(globalPageSize))]]; + +struct DatabaseHeader { + type::Magic<"SQLite format 3\x00"> magic; + u16 pageSizeValue; + u16 pageSize = pageSizeValue == 1 ? 65536 : le u16(pageSizeValue) [[export]]; + globalPageSize = pageSize; + + FileFormatVersion readVersion, writeVersion; + padding[1]; + u8 maxEmbeddedPayloadFraction; + if (maxEmbeddedPayloadFraction != 64) + std::warning("Unexpected Max Embedded Payload Fraction"); + + u8 minEmbeddedPayloadFraction; + if (minEmbeddedPayloadFraction != 32) + std::warning("Unexpected Min Embedded Payload Fraction"); + + u8 leafPayloadFraction; + if (leafPayloadFraction != 32) + std::warning("Unexpected Leaf Payload Fraction"); + + u32 fileChangeCounter; + u32 totalPageCount; + + u32 freelistTrunkPageNumber; + u32 totalFreeListPageCount; + + u32 schemaCookie; + u32 schemaFormatNumber; + u32 defaultPageCacheSize; + u32 largestRootBTreePage; + TextEncoding textEncoding; + u32 userVersion; + u32 incrementalVacuumMode; + u32 applicationId; + padding[20]; + u32 versionValidForNumber; + SQLiteVersion sqliteVersionNumber; +}; + +struct SQLite3 { + be DatabaseHeader header; + + be Page pages[le u16(header.totalPageCount) - 1] @ le u16(header.pageSize); +}; + +SQLite3 sqlite3 @ 0x00; \ No newline at end of file diff --git a/vendor/README.md b/vendor/README.md index 7747c21845..87694f7c76 100644 --- a/vendor/README.md +++ b/vendor/README.md @@ -280,6 +280,7 @@ This is a list of grammars that Linguist selects to provide syntax highlighting - **ISPC:** [ispc/ispc.syntax](https://github.com/ispc/ispc.syntax) - **Idris:** [idris-hackers/idris-sublime](https://github.com/idris-hackers/idris-sublime) - **Ignore List:** [Alhadis/language-etc](https://github.com/Alhadis/language-etc) +- **ImHex Pattern Language:** [WerWolv/PatternLanguage-Grammar](https://github.com/WerWolv/PatternLanguage-Grammar) - **Imba:** [imba/imba-linguist-grammar](https://github.com/imba/imba-linguist-grammar) - **Inform 7:** [iftechfoundation/language-inform7](https://github.com/iftechfoundation/language-inform7) - **Ink:** [inkle/ink-tmlanguage](https://github.com/inkle/ink-tmlanguage) diff --git a/vendor/grammars/PatternLanguage-Grammar b/vendor/grammars/PatternLanguage-Grammar new file mode 160000 index 0000000000..1b478509e1 --- /dev/null +++ b/vendor/grammars/PatternLanguage-Grammar @@ -0,0 +1 @@ +Subproject commit 1b478509e1d9fb4dca0ad9eb3220c1a0cce2b492 diff --git a/vendor/licenses/git_submodule/PatternLanguage-Grammar.dep.yml b/vendor/licenses/git_submodule/PatternLanguage-Grammar.dep.yml new file mode 100644 index 0000000000..c14a129746 --- /dev/null +++ b/vendor/licenses/git_submodule/PatternLanguage-Grammar.dep.yml @@ -0,0 +1,31 @@ +--- +name: PatternLanguage-Grammar +version: 1b478509e1d9fb4dca0ad9eb3220c1a0cce2b492 +type: git_submodule +homepage: https://github.com/WerWolv/PatternLanguage-Grammar.git +license: mit +licenses: +- sources: LICENSE + text: | + MIT License + + Copyright (c) 2025 WerWolv + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +notices: []