├── .gitignore ├── misc └── node_structure.png ├── vsproj ├── RunTest.vcxproj.user ├── ObjcEncodingParser.vcxproj.user ├── RunTest.vcxproj.filters ├── ObjcEncodingParser.vcxproj.filters ├── ObjcEncodingParser.sln ├── RunTest.vcxproj └── ObjcEncodingParser.vcxproj ├── ObjcEncodingParser.xcodeproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist └── project.pbxproj ├── LICENSE ├── common.h ├── modifiers.def ├── README.md ├── run-test.c ├── Makefile ├── cursor.h ├── types.def ├── strings.h ├── parser.h └── parser.c /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | xcuserdata 3 | 4 | /obj 5 | *.a 6 | *.o -------------------------------------------------------------------------------- /misc/node_structure.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixzii/objc-encodingparser/HEAD/misc/node_structure.png -------------------------------------------------------------------------------- /vsproj/RunTest.vcxproj.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /vsproj/ObjcEncodingParser.vcxproj.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /ObjcEncodingParser.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ObjcEncodingParser.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /vsproj/RunTest.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 6 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd 7 | 8 | 9 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 10 | cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx 11 | 12 | 13 | 14 | 15 | Headers 16 | 17 | 18 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Cyandev. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /vsproj/ObjcEncodingParser.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd 11 | 12 | 13 | 14 | 15 | Sources 16 | 17 | 18 | 19 | 20 | Headers 21 | 22 | 23 | Headers 24 | 25 | 26 | Headers 27 | 28 | 29 | Headers 30 | 31 | 32 | -------------------------------------------------------------------------------- /common.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Objective-C encoding parser library 3 | * 4 | * Copyright (c) 2022 Cyandev. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | #ifndef COMMON_H 26 | #define COMMON_H 27 | 28 | #if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__) 29 | #define CONFIG_WIN32 1 30 | #endif 31 | 32 | #if defined(CONFIG_WIN32) 33 | #define ALWAYS_INLINE __inline 34 | #define NO_INLINE __declspec(noinline) 35 | #define UNUSED 36 | #else 37 | #define ALWAYS_INLINE inline __attribute__((always_inline)) 38 | #define NO_INLINE __attribute__((noinline)) 39 | #define UNUSED __attribute__((unused)) 40 | #endif 41 | 42 | #ifndef MAX 43 | #define MAX(x, y) ((x) > (y) ? (x) : (y)) 44 | #endif 45 | 46 | #ifndef ROUNDUP 47 | #define ROUNDUP(x, y) (((x) + (y) - 1) & -(y)) 48 | #endif 49 | 50 | #endif /* COMMON_H */ 51 | -------------------------------------------------------------------------------- /modifiers.def: -------------------------------------------------------------------------------- 1 | /* 2 | * Objective-C encoding parser library 3 | * 4 | * Copyright (c) 2024 Cyandev. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | #ifndef __OBJC_MODIFIER 26 | #define __OBJC_MODIFIER(name, value, rep) 27 | #endif 28 | 29 | // name val rep 30 | __OBJC_MODIFIER(OBJC_MODIFIER_COMPLEX, (1 << 0), 'j') 31 | __OBJC_MODIFIER(OBJC_MODIFIER_ATOMIC, (1 << 2), 'A') 32 | __OBJC_MODIFIER(OBJC_MODIFIER_CONST, (1 << 3), 'r') 33 | __OBJC_MODIFIER(OBJC_MODIFIER_IN, (1 << 4), 'n') 34 | __OBJC_MODIFIER(OBJC_MODIFIER_INOUT, (1 << 5), 'N') 35 | __OBJC_MODIFIER(OBJC_MODIFIER_OUT, (1 << 6), 'o') 36 | __OBJC_MODIFIER(OBJC_MODIFIER_BYCOPY, (1 << 7), 'O') 37 | __OBJC_MODIFIER(OBJC_MODIFIER_BYREF, (1 << 8), 'R') 38 | __OBJC_MODIFIER(OBJC_MODIFIER_ONEWAY, (1 << 9), 'V') 39 | __OBJC_MODIFIER(OBJC_MODIFIER_GNUREGISTER, (1 << 10), '+') 40 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Objective-C Encoding Parser 2 | 3 | This library is a simple parser for Objective-C [type encoding](https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtTypeEncodings.html) with a focus on cross-platform. 4 | 5 | See [parser.h](./parser.h) for the provided APIs and [run-test.c](./run-test.c) to learn how this library works in action. 6 | 7 | ## Features 8 | 9 | * Simple and intuitive APIs, ready for use without reading any documents. 10 | * Zero-dependency and platform-agnostic, tested in macOS, Linux and Windows, easy to integrate with your various analysis facilities. 11 | * Full support of the type encoding syntax (including struct, union), and able to get the related information of the type (like name, size and alignment). 12 | * Error tolerance for ill-formed encoding strings, the library parses inputs in its best effort. 13 | * Built-in dump function to print the human-readable string describing the type. 14 | 15 | ## Building 16 | 17 | ### Make 18 | 19 | ``` 20 | git clone https://github.com/unixzii/objc-encodingparser.git 21 | cd objc-encodingparser 22 | make 23 | ``` 24 | 25 | This will generate both the static library `libocep.a` and a `run-test` program. 26 | 27 | ### Xcode / Visual Studio 28 | 29 | The project (solution) both contains two targets: `libocep` and `RunTest`. Once build is succeeded, you can retrieve the products from your IDE's build directory. 30 | 31 | ## Type Node Explained 32 | 33 | `ocep_type_node_t` is the core structure of this library, you parse an encoding string and get the result with that type. It's like an n-ary tree and each node has a parent pointer, a child pointer and a sibling pointer. An example is shown as the below figure: 34 | 35 | ![Example Node](./misc/node_structure.png) 36 | 37 | You can use `ocep_type_node_traverse` function to visit all the children (include itself) of a given node in a DFS-fashion traverse. 38 | 39 | ## Limitations 40 | 41 | * Bit fields are currently not supported (since it's rare in Objective-C code), submit an issue if you see this important. 42 | * Type size is now calculated in the compact layout (eg. `"{?=c^vc}"` will get a size of 16 while actually it's 24). 43 | 44 | ## License 45 | 46 | This project is licensed under MIT license. -------------------------------------------------------------------------------- /run-test.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Test runner for Objective-C encoding parser library 3 | * 4 | * Copyright (c) 2022 Cyandev. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | #include 26 | #include 27 | 28 | #include "parser.h" 29 | 30 | static void run_test(const char *test) { 31 | ocep_type_node_t root = ocep_parse_encoding(test); 32 | char *dump_str = ocep_type_node_dump(root); 33 | printf("--- %s ---\n%s\n\n", test, dump_str); 34 | free(dump_str); 35 | ocep_type_node_free(root); 36 | } 37 | 38 | int main(int argc, char **argv) { 39 | if (argc > 1) { 40 | // Run with the given input. 41 | run_test(argv[1]); 42 | return 0; 43 | } 44 | 45 | // Run with a suite of tests. 46 | run_test("@@:"); 47 | run_test("v@:"); 48 | run_test("v@:{CGRect={CGPoint=dd}{CGSize=dd}}"); 49 | run_test("{B={A=[5c]}i^v}"); 50 | run_test("{?=c^vc"); // invalid encoding string on purpose 51 | run_test("{basic_string, std::allocator>={__compressed_pair::__rep, std::allocator>={__rep=(?={__long=*QQ}{__short=[23c]{?=C}}{__raw=[3Q]})}}}"); 52 | run_test("v32@0:8Ar^^{CGRect}16^q24"); 53 | return 0; 54 | } 55 | -------------------------------------------------------------------------------- /vsproj/ObjcEncodingParser.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.0.32014.148 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ObjcEncodingParser", "ObjcEncodingParser.vcxproj", "{6500AAA2-E125-419D-ACF7-698EB4B6AD44}" 7 | EndProject 8 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RunTest", "RunTest.vcxproj", "{4613528E-93FA-41B1-AEBF-CB4E567914BA}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|x64 = Debug|x64 13 | Debug|x86 = Debug|x86 14 | Release|x64 = Release|x64 15 | Release|x86 = Release|x86 16 | EndGlobalSection 17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 18 | {6500AAA2-E125-419D-ACF7-698EB4B6AD44}.Debug|x64.ActiveCfg = Debug|x64 19 | {6500AAA2-E125-419D-ACF7-698EB4B6AD44}.Debug|x64.Build.0 = Debug|x64 20 | {6500AAA2-E125-419D-ACF7-698EB4B6AD44}.Debug|x86.ActiveCfg = Debug|Win32 21 | {6500AAA2-E125-419D-ACF7-698EB4B6AD44}.Debug|x86.Build.0 = Debug|Win32 22 | {6500AAA2-E125-419D-ACF7-698EB4B6AD44}.Release|x64.ActiveCfg = Release|x64 23 | {6500AAA2-E125-419D-ACF7-698EB4B6AD44}.Release|x64.Build.0 = Release|x64 24 | {6500AAA2-E125-419D-ACF7-698EB4B6AD44}.Release|x86.ActiveCfg = Release|Win32 25 | {6500AAA2-E125-419D-ACF7-698EB4B6AD44}.Release|x86.Build.0 = Release|Win32 26 | {4613528E-93FA-41B1-AEBF-CB4E567914BA}.Debug|x64.ActiveCfg = Debug|x64 27 | {4613528E-93FA-41B1-AEBF-CB4E567914BA}.Debug|x64.Build.0 = Debug|x64 28 | {4613528E-93FA-41B1-AEBF-CB4E567914BA}.Debug|x86.ActiveCfg = Debug|Win32 29 | {4613528E-93FA-41B1-AEBF-CB4E567914BA}.Debug|x86.Build.0 = Debug|Win32 30 | {4613528E-93FA-41B1-AEBF-CB4E567914BA}.Release|x64.ActiveCfg = Release|x64 31 | {4613528E-93FA-41B1-AEBF-CB4E567914BA}.Release|x64.Build.0 = Release|x64 32 | {4613528E-93FA-41B1-AEBF-CB4E567914BA}.Release|x86.ActiveCfg = Release|Win32 33 | {4613528E-93FA-41B1-AEBF-CB4E567914BA}.Release|x86.Build.0 = Release|Win32 34 | EndGlobalSection 35 | GlobalSection(SolutionProperties) = preSolution 36 | HideSolutionNode = FALSE 37 | EndGlobalSection 38 | GlobalSection(ExtensibilityGlobals) = postSolution 39 | SolutionGuid = {F9F3E6F7-8263-4068-A459-2A4A18DA7AC1} 40 | EndGlobalSection 41 | EndGlobal 42 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Objective-C encoding parser library 3 | # 4 | # Copyright (c) 2022 Cyandev. 5 | # 6 | # Permission is hereby granted, free of charge, to any person obtaining a copy 7 | # of this software and associated documentation files (the "Software"), to deal 8 | # in the Software without restriction, including without limitation the rights 9 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | # copies of the Software, and to permit persons to whom the Software is 11 | # furnished to do so, subject to the following conditions: 12 | # 13 | # The above copyright notice and this permission notice shall be included in all 14 | # copies or substantial portions of the Software. 15 | # 16 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | # SOFTWARE. 23 | 24 | ifeq ($(OS),Windows_NT) 25 | CONFIG_WIN32=y 26 | else 27 | ifeq ($(shell uname -s),Darwin) 28 | CONFIG_DARWIN=y 29 | else 30 | CONFIG_POSIX=y 31 | endif 32 | endif 33 | 34 | OBJDIR=obj 35 | 36 | ifdef CONFIG_DARWIN 37 | CC=clang 38 | CFLAGS=-g -Wall -MMD -MF $(OBJDIR)/$(@F).d 39 | CFLAGS += -Wextra 40 | CFLAGS += -Wno-sign-compare 41 | CFLAGS += -Wno-missing-field-initializers 42 | CFLAGS += -Wundef -Wuninitialized 43 | CFLAGS += -Wunused -Wno-unused-parameter 44 | CFLAGS += -Wwrite-strings 45 | CFLAGS += -Wchar-subscripts -funsigned-char 46 | 47 | AR=ar 48 | else ifdef CONFIG_POSIX 49 | CC=gcc 50 | CFLAGS=-g -Wall 51 | 52 | AR=ar 53 | endif 54 | 55 | PROGS=run-test 56 | LIBS=libocep.a 57 | 58 | LIB_OBJS=$(OBJDIR)/parser.o 59 | 60 | all: $(LIBS) $(PROGS) 61 | 62 | run-test: $(OBJDIR)/run-test.o libocep.a 63 | $(CC) $(CFLAGS) -o $@ $(filter-out libocep.a,$^) -L. -locep 64 | 65 | libocep.a: $(LIB_OBJS) 66 | $(AR) -rcs $@ $^ 67 | 68 | $(OBJDIR)/%.o: %.c | $(OBJDIR) 69 | $(CC) $(CFLAGS) -c $< -o $@ 70 | 71 | $(OBJDIR): 72 | mkdir -p $@ 73 | 74 | clean: 75 | rm -rf $(OBJDIR) 76 | rm -rf $(PROGS) 77 | 78 | -include $(wildcard $(OBJDIR)/*.d) 79 | -------------------------------------------------------------------------------- /cursor.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Objective-C encoding parser library 3 | * 4 | * Copyright (c) 2022 Cyandev. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | #ifndef CURSOR_H 26 | #define CURSOR_H 27 | 28 | #include 29 | #include 30 | #include 31 | 32 | #include "common.h" 33 | 34 | struct ocep_cursor { 35 | size_t len; 36 | size_t idx; 37 | char str[1]; 38 | }; 39 | 40 | typedef struct ocep_cursor *ocep_cursor_t; 41 | 42 | static ocep_cursor_t ocep_cursor_new(const char *str) { 43 | size_t len = strlen(str); 44 | size_t size = sizeof(struct ocep_cursor) + len; 45 | 46 | ocep_cursor_t cursor = (ocep_cursor_t) malloc(size); 47 | if (!cursor) { 48 | return NULL; 49 | } 50 | 51 | cursor->len = len; 52 | cursor->idx = 0; 53 | memcpy(cursor->str, str, len); 54 | 55 | return cursor; 56 | } 57 | 58 | static ALWAYS_INLINE void ocep_cursor_free(ocep_cursor_t cursor) { 59 | free(cursor); 60 | } 61 | 62 | 63 | static ALWAYS_INLINE int ocep_cursor_is_eof(ocep_cursor_t cursor) { 64 | return cursor->idx >= cursor->len; 65 | } 66 | 67 | static char ocep_cursor_peek(ocep_cursor_t cursor) { 68 | if (ocep_cursor_is_eof(cursor)) { 69 | return '\0'; 70 | } 71 | return cursor->str[cursor->idx]; 72 | } 73 | 74 | static char ocep_cursor_step(ocep_cursor_t cursor) { 75 | if (ocep_cursor_is_eof(cursor)) { 76 | return '\0'; 77 | } 78 | char tok = ocep_cursor_peek(cursor); 79 | ++cursor->idx; 80 | return tok; 81 | } 82 | 83 | #endif /* CURSOR_H */ 84 | -------------------------------------------------------------------------------- /types.def: -------------------------------------------------------------------------------- 1 | /* 2 | * Objective-C encoding parser library 3 | * 4 | * Copyright (c) 2022 Cyandev. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | #ifndef __OBJC_TYPE 26 | #define __OBJC_TYPE(name, value, rep, size, simple) 27 | #endif 28 | 29 | // name val rep size simple 30 | __OBJC_TYPE(OBJC_TYPE_CHAR, 1, 'c', 1, 1) 31 | __OBJC_TYPE(OBJC_TYPE_INT, 2, 'i', 4, 1) 32 | __OBJC_TYPE(OBJC_TYPE_SHORT, 3, 's', 2, 1) 33 | __OBJC_TYPE(OBJC_TYPE_LONG, 4, 'l', 8, 1) 34 | __OBJC_TYPE(OBJC_TYPE_LONG_LONG, 5, 'q', 8, 1) 35 | __OBJC_TYPE(OBJC_TYPE_UNSIGNED_CHAR, 6, 'C', 1, 1) 36 | __OBJC_TYPE(OBJC_TYPE_UNSIGNED_INT, 7, 'I', 4, 1) 37 | __OBJC_TYPE(OBJC_TYPE_UNSIGNED_SHORT, 8, 'S', 2, 1) 38 | __OBJC_TYPE(OBJC_TYPE_UNSIGNED_LONG, 9, 'L', 8, 1) 39 | __OBJC_TYPE(OBJC_TYPE_UNSIGNED_LONG_LONG, 10, 'Q', 8, 1) 40 | __OBJC_TYPE(OBJC_TYPE_FLOAT, 11, 'f', 4, 1) 41 | __OBJC_TYPE(OBJC_TYPE_DOUBLE, 12, 'd', 8, 1) 42 | __OBJC_TYPE(OBJC_TYPE_BOOL, 13, 'B', 1, 1) 43 | __OBJC_TYPE(OBJC_TYPE_VOID, 14, 'v', 0, 1) 44 | __OBJC_TYPE(OBJC_TYPE_STRING, 15, '*', 8, 1) 45 | __OBJC_TYPE(OBJC_TYPE_OBJECT, 16, '@', 8, 1) 46 | __OBJC_TYPE(OBJC_TYPE_CLASS, 17, '#', 8, 1) 47 | __OBJC_TYPE(OBJC_TYPE_SEL, 18, ':', 8, 1) 48 | #ifndef __NO_COMPLEX_OBJC_TYPES 49 | __OBJC_TYPE(OBJC_TYPE_ARRAY, 19, '[', 8, 0) 50 | __OBJC_TYPE(OBJC_TYPE_STRUCT, 20, '{', 0, 0) 51 | __OBJC_TYPE(OBJC_TYPE_UNION, 21, '(', 0, 0) 52 | __OBJC_TYPE(OBJC_TYPE_BIT_FIELD, 22, 'b', 0, 0) 53 | __OBJC_TYPE(OBJC_TYPE_POINTER, 23, '^', 8, 0) 54 | #endif 55 | __OBJC_TYPE(OBJC_TYPE_UNKNOWN, 64, '?', 8, 1) 56 | -------------------------------------------------------------------------------- /strings.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Objective-C encoding parser library 3 | * 4 | * Copyright (c) 2022 Cyandev. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | #ifndef STRINGS_H 26 | #define STRINGS_H 27 | 28 | #include 29 | #include 30 | 31 | #include "common.h" 32 | 33 | typedef struct _strbuf { 34 | char *str; 35 | size_t len; 36 | size_t cap; 37 | } strbuf; 38 | 39 | static strbuf strbuf_alloc(const char *str, size_t extra_bytes) { 40 | size_t len = 0; 41 | if (str) { 42 | len = strlen(str); 43 | } 44 | size_t cap = len + extra_bytes + 1; 45 | 46 | strbuf buf; 47 | buf.str = (char *) calloc(cap, 1); 48 | buf.len = len; 49 | buf.cap = cap; 50 | 51 | if (str) { 52 | #if defined(CONFIG_WIN32) 53 | strcpy_s(buf.str, buf.cap, str); 54 | #else 55 | strcpy(buf.str, str); 56 | #endif 57 | } 58 | 59 | return buf; 60 | } 61 | 62 | static char *strbuf_take(strbuf *buf) { 63 | char *str = buf->str; 64 | buf->str = NULL; 65 | buf->len = 0; 66 | buf->cap = 0; 67 | return str; 68 | } 69 | 70 | static UNUSED void strbuf_free(strbuf *buf) { 71 | char *str = strbuf_take(buf); 72 | if (str) { 73 | free(str); 74 | } 75 | } 76 | 77 | static void strbuf_append(strbuf *buf, const char *str) { 78 | size_t str_len = strlen(str); 79 | 80 | if (buf->len + str_len <= buf->cap - 1) { 81 | #if defined(CONFIG_WIN32) 82 | strcat_s(buf->str, buf->cap, str); 83 | #else 84 | strcat(buf->str, str); 85 | #endif 86 | buf->len += str_len; 87 | return; 88 | } 89 | 90 | char *old_str = buf->str; 91 | size_t new_cap = buf->cap + str_len + 1; 92 | char *new_str = (char *) calloc(new_cap, 1); 93 | if (old_str) { 94 | #if defined(CONFIG_WIN32) 95 | strcpy_s(new_str, new_cap, old_str); 96 | #else 97 | strcpy(new_str, old_str); 98 | #endif 99 | free(old_str); 100 | } 101 | #if defined(CONFIG_WIN32) 102 | strcat_s(new_str, new_cap, str); 103 | #else 104 | strcat(new_str, str); 105 | #endif 106 | 107 | buf->str = new_str; 108 | buf->len += str_len; 109 | buf->cap = new_cap; 110 | } 111 | 112 | static void strbuf_append_repeat(strbuf *buf, char ch, int count) { 113 | char str[2] = { ch, 0 }; 114 | while (count--) { 115 | strbuf_append(buf, str); 116 | } 117 | } 118 | 119 | #endif /* STRINGS_H */ 120 | -------------------------------------------------------------------------------- /parser.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Objective-C encoding parser library 3 | * 4 | * Copyright (c) 2022 Cyandev. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | #ifndef PARSER_H 26 | #define PARSER_H 27 | 28 | #include 29 | 30 | #ifdef __cplusplus 31 | extern "C" { 32 | #endif 33 | 34 | enum { 35 | #define __OBJC_TYPE(name, value, _0, _1, _2) name = value, 36 | #include "types.def" 37 | #undef __OBJC_TYPE 38 | }; 39 | 40 | enum { 41 | #define __OBJC_MODIFIER(name, value, _0) name = value, 42 | #include "modifiers.def" 43 | #undef __OBJC_MODIFIER 44 | }; 45 | 46 | typedef struct ocep_type_node *ocep_type_node_t; 47 | 48 | struct ocep_type_node { 49 | /* Objective-C Type, see `types.def` for enum values. 50 | Return 0 for root nodes. */ 51 | int type; 52 | 53 | /* Objective-C type modifiers, see `modifiers.def` for 54 | enum values. */ 55 | int modifiers; 56 | 57 | /* Number of child types (for array, struct and union types). 58 | Note that there will only be one node in the child list 59 | for array type. */ 60 | int child_num; 61 | /* Size of the value of this type. */ 62 | int size; 63 | /* Alignment of this type. */ 64 | int alignment; 65 | 66 | /* Struct name. Only exists for struct types. */ 67 | const char *name; 68 | 69 | /* Parent node that holds this node. */ 70 | ocep_type_node_t parent; 71 | /* First child node, NULL if the type contains no children. */ 72 | ocep_type_node_t first_child; 73 | /* Next sibling node, NULL if this is the last node of the 74 | child list. */ 75 | ocep_type_node_t next_sibling; 76 | }; 77 | 78 | /* Parses the given encoding string and returns the type node. 79 | The caller must call `ocep_type_node_free` to free the memory 80 | when it has done with it. */ 81 | ocep_type_node_t ocep_parse_encoding(const char *encoding); 82 | 83 | /* Deallocates the node object. */ 84 | void ocep_type_node_free(ocep_type_node_t node); 85 | 86 | /* Recursively visits the given node, and invokes the given 87 | callback with each child node visited. */ 88 | void ocep_type_node_traverse(ocep_type_node_t node, void *userdata, 89 | void (*cb)(ocep_type_node_t cur, int num, int depth, void *userdata)); 90 | 91 | /* Dumps the given node to human-readable string. The caller 92 | must free the result string when it has done with it. */ 93 | char *ocep_type_node_dump(ocep_type_node_t node); 94 | 95 | #ifdef __cplusplus 96 | } /* extern "C" { */ 97 | #endif 98 | 99 | #endif /* PARSER_H */ 100 | -------------------------------------------------------------------------------- /vsproj/RunTest.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 16.0 23 | Win32Proj 24 | {4613528e-93fa-41b1-aebf-cb4e567914ba} 25 | RunTest 26 | 10.0 27 | 28 | 29 | 30 | Application 31 | true 32 | v143 33 | Unicode 34 | 35 | 36 | Application 37 | false 38 | v143 39 | true 40 | Unicode 41 | 42 | 43 | Application 44 | true 45 | v143 46 | Unicode 47 | 48 | 49 | Application 50 | false 51 | v143 52 | true 53 | Unicode 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | true 75 | 76 | 77 | false 78 | 79 | 80 | true 81 | 82 | 83 | false 84 | 85 | 86 | 87 | Level3 88 | true 89 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 90 | true 91 | 92 | 93 | Console 94 | true 95 | 96 | 97 | 98 | 99 | Level3 100 | true 101 | true 102 | true 103 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 104 | true 105 | 106 | 107 | Console 108 | true 109 | true 110 | true 111 | 112 | 113 | 114 | 115 | Level3 116 | true 117 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 118 | true 119 | 120 | 121 | Console 122 | true 123 | 124 | 125 | 126 | 127 | Level3 128 | true 129 | true 130 | true 131 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 132 | true 133 | 134 | 135 | Console 136 | true 137 | true 138 | true 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | {6500aaa2-e125-419d-acf7-698eb4b6ad44} 147 | 148 | 149 | 150 | 151 | 152 | -------------------------------------------------------------------------------- /vsproj/ObjcEncodingParser.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 16.0 23 | Win32Proj 24 | {6500aaa2-e125-419d-acf7-698eb4b6ad44} 25 | ObjcEncodingParser 26 | 10.0 27 | 28 | 29 | 30 | Application 31 | true 32 | v143 33 | Unicode 34 | 35 | 36 | Application 37 | false 38 | v143 39 | true 40 | Unicode 41 | 42 | 43 | StaticLibrary 44 | true 45 | v143 46 | Unicode 47 | 48 | 49 | Application 50 | false 51 | v143 52 | true 53 | Unicode 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | true 75 | 76 | 77 | false 78 | 79 | 80 | true 81 | 82 | 83 | false 84 | 85 | 86 | 87 | Level3 88 | true 89 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 90 | true 91 | 92 | 93 | Console 94 | true 95 | 96 | 97 | 98 | 99 | Level3 100 | true 101 | true 102 | true 103 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 104 | true 105 | 106 | 107 | Console 108 | true 109 | true 110 | true 111 | 112 | 113 | 114 | 115 | Level3 116 | true 117 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 118 | true 119 | 120 | 121 | Console 122 | true 123 | 124 | 125 | 126 | 127 | Level3 128 | true 129 | true 130 | true 131 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 132 | true 133 | 134 | 135 | Console 136 | true 137 | true 138 | true 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | -------------------------------------------------------------------------------- /parser.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Objective-C encoding parser library 3 | * 4 | * Copyright (c) 2022 Cyandev. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | #include 26 | #include 27 | 28 | #include "parser.h" 29 | #include "cursor.h" 30 | #include "strings.h" 31 | #include "common.h" 32 | 33 | static ocep_type_node_t ocep_type_node_new(void) { 34 | ocep_type_node_t node = (ocep_type_node_t) malloc(sizeof(struct ocep_type_node)); 35 | node->type = OBJC_TYPE_UNKNOWN; 36 | node->modifiers = 0; 37 | node->child_num = 0; 38 | node->size = 0; 39 | node->alignment = 0; 40 | node->name = NULL; 41 | node->parent = NULL; 42 | node->first_child = NULL; 43 | node->next_sibling = NULL; 44 | return node; 45 | } 46 | 47 | static void ocep_type_node_free_internal(ocep_type_node_t node) { 48 | if (node->name) { 49 | free((void *) node->name); 50 | } 51 | free(node); 52 | } 53 | 54 | static NO_INLINE int _parse_number(ocep_cursor_t cursor) { 55 | int num = 0; 56 | char tok; 57 | while (!ocep_cursor_is_eof(cursor)) { 58 | tok = ocep_cursor_peek(cursor); 59 | if (tok < '0' || tok > '9') { 60 | return num; 61 | } 62 | num = num * 10 + (tok - '0'); 63 | ocep_cursor_step(cursor); 64 | } 65 | return num; 66 | } 67 | 68 | static ALWAYS_INLINE void _skip_digits(ocep_cursor_t cursor) { 69 | (void) _parse_number(cursor); 70 | } 71 | 72 | static ocep_type_node_t _parse_one_element(ocep_cursor_t cursor, ocep_type_node_t parent); 73 | 74 | static void _parse_struct_or_union(int type, ocep_cursor_t cursor, ocep_type_node_t node) { 75 | // Structs are represented as "{name=??}", the cursor has moved pass '{' 76 | // when this function is called. 77 | 78 | char close_tok; 79 | if (type == OBJC_TYPE_STRUCT) { 80 | close_tok = '}'; 81 | } else { 82 | close_tok = ')'; 83 | } 84 | 85 | // Collect struct name. 86 | strbuf name_buf = strbuf_alloc("", 8); 87 | while (!ocep_cursor_is_eof(cursor)) { 88 | char tok_str[2] = { 0, 0 }; 89 | tok_str[0] = ocep_cursor_peek(cursor); 90 | if (tok_str[0] == close_tok) { 91 | break; 92 | } 93 | ocep_cursor_step(cursor); 94 | if (tok_str[0] == '=') { 95 | break; 96 | } 97 | strbuf_append(&name_buf, tok_str); 98 | } 99 | 100 | // Parse child nodes. 101 | ocep_type_node_t last_child = NULL; 102 | while (!ocep_cursor_is_eof(cursor)) { 103 | char tok = ocep_cursor_peek(cursor); 104 | if (tok == close_tok) { 105 | ocep_cursor_step(cursor); 106 | break; 107 | } 108 | 109 | ocep_type_node_t child = _parse_one_element(cursor, node); 110 | if (last_child) { 111 | last_child->next_sibling = child; 112 | } else { 113 | node->first_child = child; 114 | } 115 | last_child = child; 116 | 117 | node->alignment = MAX(node->alignment, child->alignment); 118 | if (type == OBJC_TYPE_STRUCT) { 119 | // FIXME: current naive algorithm assumes the compact layout. 120 | node->size += child->size; 121 | } else { 122 | node->size = MAX(node->size, child->size); 123 | } 124 | ++node->child_num; 125 | } 126 | 127 | if (type == OBJC_TYPE_STRUCT) { 128 | node->size = ROUNDUP(node->size, node->alignment); 129 | } 130 | 131 | node->type = type; 132 | node->name = strbuf_take(&name_buf); 133 | } 134 | 135 | static void _parse_array(ocep_cursor_t cursor, ocep_type_node_t node) { 136 | int count = _parse_number(cursor); 137 | 138 | ocep_type_node_t child = _parse_one_element(cursor, node); 139 | node->first_child = child; 140 | node->type = OBJC_TYPE_ARRAY; 141 | node->child_num = count; 142 | node->size = child->size * count; 143 | node->alignment = child->alignment; 144 | 145 | char tok = ocep_cursor_peek(cursor); 146 | if (tok == ']') { 147 | ocep_cursor_step(cursor); 148 | } 149 | } 150 | 151 | static void _parse_pointer(ocep_cursor_t cursor, ocep_type_node_t node) { 152 | ocep_type_node_t child = _parse_one_element(cursor, node); 153 | node->first_child = child; 154 | node->type = OBJC_TYPE_POINTER; 155 | node->child_num = 1; 156 | node->size = 8; 157 | node->alignment = 8; 158 | } 159 | 160 | static ocep_type_node_t _parse_one_element(ocep_cursor_t cursor, ocep_type_node_t parent) { 161 | ocep_type_node_t node = ocep_type_node_new(); 162 | node->parent = parent; 163 | 164 | while (1) { 165 | int not_modifier = 0; 166 | char tok = ocep_cursor_peek(cursor); 167 | switch (tok) { 168 | #define __OBJC_MODIFIER(_0, val, rep) \ 169 | case rep: \ 170 | node->modifiers |= val; \ 171 | break; 172 | #include "modifiers.def" 173 | #undef __OBJC_MODIFIER 174 | default: 175 | not_modifier = 1; 176 | break; 177 | } 178 | if (not_modifier) { 179 | break; 180 | } else { 181 | ocep_cursor_step(cursor); 182 | } 183 | } 184 | 185 | char tok = ocep_cursor_step(cursor); 186 | switch (tok) { 187 | #define __NO_COMPLEX_OBJC_TYPES 188 | #define __OBJC_TYPE(_0, val, rep, siz, _1) \ 189 | case rep: \ 190 | node->type = val; \ 191 | node->size = siz; \ 192 | node->alignment = siz; \ 193 | break; 194 | #include "types.def" 195 | #undef __OBJC_TYPE 196 | #undef __NO_COMPLEX_OBJC_TYPES 197 | case '{': 198 | _parse_struct_or_union(OBJC_TYPE_STRUCT, cursor, node); 199 | break; 200 | case '(': 201 | _parse_struct_or_union(OBJC_TYPE_UNION, cursor, node); 202 | break; 203 | case '[': 204 | _parse_array(cursor, node); 205 | break; 206 | case '^': 207 | _parse_pointer(cursor, node); 208 | break; 209 | } 210 | 211 | // Skip the frame sizes and offsets, if any. 212 | _skip_digits(cursor); 213 | 214 | return node; 215 | } 216 | 217 | ocep_type_node_t ocep_parse_encoding(const char *encoding) { 218 | ocep_cursor_t cursor = ocep_cursor_new(encoding); 219 | 220 | // Allocate the root node. 221 | ocep_type_node_t root = ocep_type_node_new(); 222 | root->type = 0; 223 | 224 | // Consume all tokens and generate subnodes. 225 | ocep_type_node_t last_elem = NULL; 226 | while (!ocep_cursor_is_eof(cursor)) { 227 | ocep_type_node_t elem = _parse_one_element(cursor, root); 228 | if (last_elem) { 229 | last_elem->next_sibling = elem; 230 | } else { 231 | root->first_child = elem; 232 | } 233 | last_elem = elem; 234 | ++root->child_num; 235 | } 236 | 237 | ocep_cursor_free(cursor); 238 | return root; 239 | } 240 | 241 | void ocep_type_node_free(ocep_type_node_t node) { 242 | if (node->parent) { 243 | abort(); // Child nodes must not be freed via `ocep_type_node_free`. 244 | return; 245 | } 246 | 247 | // Non-recursive free with node links. 248 | ocep_type_node_t cur = node; 249 | while (cur) { 250 | ocep_type_node_t to_free = NULL; 251 | if (cur->first_child) { 252 | ocep_type_node_t next = cur->first_child; 253 | cur->first_child = NULL; 254 | cur = next; 255 | } else if (cur->next_sibling) { 256 | to_free = cur; 257 | cur = cur->next_sibling; 258 | } else { 259 | to_free = cur; 260 | cur = cur->parent; 261 | } 262 | 263 | if (to_free) 264 | ocep_type_node_free_internal(to_free); 265 | } 266 | } 267 | 268 | static void ocep_type_node_traverse_internal(ocep_type_node_t node, void *userdata, 269 | int *num, int depth, 270 | void (*cb)(ocep_type_node_t cur, int num, int depth, void *userdata)) { 271 | normal: 272 | cb(node, *num, depth, userdata); 273 | ++*num; 274 | 275 | // Visit children. 276 | ocep_type_node_t first_child = node->first_child; 277 | if (first_child) { 278 | ocep_type_node_traverse_internal(first_child, userdata, num, depth + 1, cb); 279 | } 280 | 281 | // Then visit rest siblings. 282 | ocep_type_node_t next_sibling = node->next_sibling; 283 | if (next_sibling) { 284 | node = next_sibling; 285 | goto normal; // Force tail-recursion. 286 | } 287 | } 288 | 289 | void ocep_type_node_traverse(ocep_type_node_t node, void *userdata, 290 | void (*cb)(ocep_type_node_t cur, int num, int depth, void *userdata)) { 291 | int num = 0; 292 | ocep_type_node_traverse_internal(node, userdata, &num, 0, cb); 293 | } 294 | 295 | struct __ocep_type_node_dump_state { 296 | strbuf str; 297 | }; 298 | 299 | // Outlined common routine for switch cases in `ocep_type_node_dump_visitor`. 300 | static NO_INLINE void ocep_type_node_dump_outlined_1(strbuf *str_buf, 301 | int depth, const char *type, char encoding) { 302 | strbuf_append_repeat(str_buf, ' ', depth * 4); 303 | strbuf_append(str_buf, "type: "); 304 | strbuf_append(str_buf, type); 305 | strbuf_append(str_buf, "\n"); 306 | 307 | strbuf_append_repeat(str_buf, ' ', depth * 4); 308 | strbuf_append(str_buf, "encoding: "); 309 | char encoding_str[2] = { encoding, 0 }; 310 | strbuf_append(str_buf, encoding_str); 311 | strbuf_append(str_buf, "\n"); 312 | } 313 | 314 | static NO_INLINE void ocep_type_node_dump_outlined_2(strbuf *str_buf, 315 | int depth, const char *label, int value) { 316 | strbuf_append_repeat(str_buf, ' ', depth * 4); 317 | strbuf_append(str_buf, label); 318 | char value_str[32]; 319 | #if defined(CONFIG_WIN32) 320 | sprintf_s(value_str, sizeof(value_str), "%d", value); 321 | #else 322 | sprintf(value_str, "%d", value); 323 | #endif 324 | strbuf_append(str_buf, value_str); 325 | strbuf_append(str_buf, "\n"); 326 | } 327 | 328 | static NO_INLINE void ocep_type_node_dump_outlined_3(strbuf *str_buf, const char *modifier) { 329 | if (str_buf->str[str_buf->len - 1] != ' ') { 330 | strbuf_append(str_buf, ", "); 331 | } 332 | strbuf_append(str_buf, modifier); 333 | } 334 | 335 | static void ocep_type_node_dump_visitor(ocep_type_node_t node, int num, int depth, void *userdata) { 336 | if (node->type == 0) { 337 | return; 338 | } 339 | 340 | --depth; // Root node is skipped. 341 | 342 | struct __ocep_type_node_dump_state* state; 343 | state = (struct __ocep_type_node_dump_state*) userdata; 344 | 345 | strbuf *str_buf = &state->str; 346 | 347 | // Draw a separator line. 348 | if (num > 1) { 349 | strbuf_append_repeat(str_buf, ' ', depth * 4); 350 | strbuf_append_repeat(str_buf, '-', 30); 351 | strbuf_append(str_buf, "\n"); 352 | } 353 | 354 | switch (node->type) { 355 | #define __OBJC_TYPE(name, val, rep, _0, _1) \ 356 | case val: \ 357 | ocep_type_node_dump_outlined_1(str_buf, depth, #name, rep); \ 358 | break; 359 | #include "types.def" 360 | #undef __OBJC_TYPE 361 | } 362 | 363 | if (node->modifiers) { 364 | strbuf_append_repeat(str_buf, ' ', depth * 4); 365 | strbuf_append(str_buf, "modifiers: "); 366 | #define __OBJC_MODIFIER(name, val, _0) \ 367 | if (node->modifiers & val) { \ 368 | ocep_type_node_dump_outlined_3(str_buf, #name); \ 369 | } 370 | #include "modifiers.def" 371 | #undef __OBJC_MODIFIER 372 | strbuf_append(str_buf, "\n"); 373 | } 374 | 375 | ocep_type_node_dump_outlined_2(str_buf, depth, "size: ", node->size); 376 | ocep_type_node_dump_outlined_2(str_buf, depth, "alignment: ", node->alignment); 377 | if (node->child_num > 1) { 378 | ocep_type_node_dump_outlined_2(str_buf, depth, "child num: ", node->child_num); 379 | } 380 | 381 | const char *name = node->name; 382 | if (name) { 383 | strbuf_append_repeat(str_buf, ' ', depth * 4); 384 | strbuf_append(str_buf, "name: "); 385 | strbuf_append(str_buf, name); 386 | strbuf_append(str_buf, "\n"); 387 | } 388 | } 389 | 390 | char *ocep_type_node_dump(ocep_type_node_t node) { 391 | struct __ocep_type_node_dump_state state; 392 | state.str = strbuf_alloc("", 128); 393 | ocep_type_node_traverse(node, &state, &ocep_type_node_dump_visitor); 394 | return strbuf_take(&state.str); 395 | } 396 | -------------------------------------------------------------------------------- /ObjcEncodingParser.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 55; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | FA8450CE2811C642007162A3 /* parser.c in Sources */ = {isa = PBXBuildFile; fileRef = FA5D07F52810636F00ED9CA4 /* parser.c */; }; 11 | FA8450D02811C647007162A3 /* liblibocep.a in Frameworks */ = {isa = PBXBuildFile; fileRef = FA8450CA2811C639007162A3 /* liblibocep.a */; }; 12 | FA8450D32811C64E007162A3 /* run-test.c in Sources */ = {isa = PBXBuildFile; fileRef = FA5D07F02810636F00ED9CA4 /* run-test.c */; }; 13 | /* End PBXBuildFile section */ 14 | 15 | /* Begin PBXContainerItemProxy section */ 16 | FA8450D12811C64B007162A3 /* PBXContainerItemProxy */ = { 17 | isa = PBXContainerItemProxy; 18 | containerPortal = FAF1B151280F2A8500ABBA15 /* Project object */; 19 | proxyType = 1; 20 | remoteGlobalIDString = FA8450C92811C639007162A3; 21 | remoteInfo = libocep; 22 | }; 23 | /* End PBXContainerItemProxy section */ 24 | 25 | /* Begin PBXCopyFilesBuildPhase section */ 26 | FA8450BD2811C615007162A3 /* CopyFiles */ = { 27 | isa = PBXCopyFilesBuildPhase; 28 | buildActionMask = 2147483647; 29 | dstPath = /usr/share/man/man1/; 30 | dstSubfolderSpec = 0; 31 | files = ( 32 | ); 33 | runOnlyForDeploymentPostprocessing = 1; 34 | }; 35 | /* End PBXCopyFilesBuildPhase section */ 36 | 37 | /* Begin PBXFileReference section */ 38 | ED7091602C84405B0056D465 /* modifiers.def */ = {isa = PBXFileReference; lastKnownFileType = text; path = modifiers.def; sourceTree = ""; }; 39 | FA5D07EF2810636F00ED9CA4 /* strings.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = strings.h; sourceTree = ""; }; 40 | FA5D07F02810636F00ED9CA4 /* run-test.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "run-test.c"; sourceTree = ""; }; 41 | FA5D07F12810636F00ED9CA4 /* types.def */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = types.def; sourceTree = ""; }; 42 | FA5D07F22810636F00ED9CA4 /* cursor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cursor.h; sourceTree = ""; }; 43 | FA5D07F32810636F00ED9CA4 /* parser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = parser.h; sourceTree = ""; }; 44 | FA5D07F42810636F00ED9CA4 /* common.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = common.h; sourceTree = ""; }; 45 | FA5D07F52810636F00ED9CA4 /* parser.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = parser.c; sourceTree = ""; }; 46 | FA8450BF2811C615007162A3 /* RunTest */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = RunTest; sourceTree = BUILT_PRODUCTS_DIR; }; 47 | FA8450CA2811C639007162A3 /* liblibocep.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = liblibocep.a; sourceTree = BUILT_PRODUCTS_DIR; }; 48 | /* End PBXFileReference section */ 49 | 50 | /* Begin PBXFrameworksBuildPhase section */ 51 | FA8450BC2811C615007162A3 /* Frameworks */ = { 52 | isa = PBXFrameworksBuildPhase; 53 | buildActionMask = 2147483647; 54 | files = ( 55 | FA8450D02811C647007162A3 /* liblibocep.a in Frameworks */, 56 | ); 57 | runOnlyForDeploymentPostprocessing = 0; 58 | }; 59 | FA8450C82811C639007162A3 /* Frameworks */ = { 60 | isa = PBXFrameworksBuildPhase; 61 | buildActionMask = 2147483647; 62 | files = ( 63 | ); 64 | runOnlyForDeploymentPostprocessing = 0; 65 | }; 66 | /* End PBXFrameworksBuildPhase section */ 67 | 68 | /* Begin PBXGroup section */ 69 | FA8450CF2811C647007162A3 /* Frameworks */ = { 70 | isa = PBXGroup; 71 | children = ( 72 | ); 73 | name = Frameworks; 74 | sourceTree = ""; 75 | }; 76 | FAF1B150280F2A8500ABBA15 = { 77 | isa = PBXGroup; 78 | children = ( 79 | FA5D07F42810636F00ED9CA4 /* common.h */, 80 | FA5D07F22810636F00ED9CA4 /* cursor.h */, 81 | FA5D07F52810636F00ED9CA4 /* parser.c */, 82 | FA5D07F32810636F00ED9CA4 /* parser.h */, 83 | FA5D07F02810636F00ED9CA4 /* run-test.c */, 84 | FA5D07EF2810636F00ED9CA4 /* strings.h */, 85 | FA5D07F12810636F00ED9CA4 /* types.def */, 86 | ED7091602C84405B0056D465 /* modifiers.def */, 87 | FAF1B15A280F2A8500ABBA15 /* Products */, 88 | FA8450CF2811C647007162A3 /* Frameworks */, 89 | ); 90 | sourceTree = ""; 91 | }; 92 | FAF1B15A280F2A8500ABBA15 /* Products */ = { 93 | isa = PBXGroup; 94 | children = ( 95 | FA8450BF2811C615007162A3 /* RunTest */, 96 | FA8450CA2811C639007162A3 /* liblibocep.a */, 97 | ); 98 | name = Products; 99 | sourceTree = ""; 100 | }; 101 | /* End PBXGroup section */ 102 | 103 | /* Begin PBXHeadersBuildPhase section */ 104 | FA8450C62811C639007162A3 /* Headers */ = { 105 | isa = PBXHeadersBuildPhase; 106 | buildActionMask = 2147483647; 107 | files = ( 108 | ); 109 | runOnlyForDeploymentPostprocessing = 0; 110 | }; 111 | /* End PBXHeadersBuildPhase section */ 112 | 113 | /* Begin PBXNativeTarget section */ 114 | FA8450BE2811C615007162A3 /* RunTest */ = { 115 | isa = PBXNativeTarget; 116 | buildConfigurationList = FA8450C52811C615007162A3 /* Build configuration list for PBXNativeTarget "RunTest" */; 117 | buildPhases = ( 118 | FA8450BB2811C615007162A3 /* Sources */, 119 | FA8450BC2811C615007162A3 /* Frameworks */, 120 | FA8450BD2811C615007162A3 /* CopyFiles */, 121 | ); 122 | buildRules = ( 123 | ); 124 | dependencies = ( 125 | FA8450D22811C64B007162A3 /* PBXTargetDependency */, 126 | ); 127 | name = RunTest; 128 | productName = RunTest; 129 | productReference = FA8450BF2811C615007162A3 /* RunTest */; 130 | productType = "com.apple.product-type.tool"; 131 | }; 132 | FA8450C92811C639007162A3 /* libocep */ = { 133 | isa = PBXNativeTarget; 134 | buildConfigurationList = FA8450CB2811C639007162A3 /* Build configuration list for PBXNativeTarget "libocep" */; 135 | buildPhases = ( 136 | FA8450C62811C639007162A3 /* Headers */, 137 | FA8450C72811C639007162A3 /* Sources */, 138 | FA8450C82811C639007162A3 /* Frameworks */, 139 | ); 140 | buildRules = ( 141 | ); 142 | dependencies = ( 143 | ); 144 | name = libocep; 145 | productName = libocep; 146 | productReference = FA8450CA2811C639007162A3 /* liblibocep.a */; 147 | productType = "com.apple.product-type.library.static"; 148 | }; 149 | /* End PBXNativeTarget section */ 150 | 151 | /* Begin PBXProject section */ 152 | FAF1B151280F2A8500ABBA15 /* Project object */ = { 153 | isa = PBXProject; 154 | attributes = { 155 | BuildIndependentTargetsInParallel = 1; 156 | LastUpgradeCheck = 1330; 157 | TargetAttributes = { 158 | FA8450BE2811C615007162A3 = { 159 | CreatedOnToolsVersion = 13.3; 160 | }; 161 | FA8450C92811C639007162A3 = { 162 | CreatedOnToolsVersion = 13.3; 163 | }; 164 | }; 165 | }; 166 | buildConfigurationList = FAF1B154280F2A8500ABBA15 /* Build configuration list for PBXProject "ObjcEncodingParser" */; 167 | compatibilityVersion = "Xcode 13.0"; 168 | developmentRegion = en; 169 | hasScannedForEncodings = 0; 170 | knownRegions = ( 171 | en, 172 | Base, 173 | ); 174 | mainGroup = FAF1B150280F2A8500ABBA15; 175 | productRefGroup = FAF1B15A280F2A8500ABBA15 /* Products */; 176 | projectDirPath = ""; 177 | projectRoot = ""; 178 | targets = ( 179 | FA8450BE2811C615007162A3 /* RunTest */, 180 | FA8450C92811C639007162A3 /* libocep */, 181 | ); 182 | }; 183 | /* End PBXProject section */ 184 | 185 | /* Begin PBXSourcesBuildPhase section */ 186 | FA8450BB2811C615007162A3 /* Sources */ = { 187 | isa = PBXSourcesBuildPhase; 188 | buildActionMask = 2147483647; 189 | files = ( 190 | FA8450D32811C64E007162A3 /* run-test.c in Sources */, 191 | ); 192 | runOnlyForDeploymentPostprocessing = 0; 193 | }; 194 | FA8450C72811C639007162A3 /* Sources */ = { 195 | isa = PBXSourcesBuildPhase; 196 | buildActionMask = 2147483647; 197 | files = ( 198 | FA8450CE2811C642007162A3 /* parser.c in Sources */, 199 | ); 200 | runOnlyForDeploymentPostprocessing = 0; 201 | }; 202 | /* End PBXSourcesBuildPhase section */ 203 | 204 | /* Begin PBXTargetDependency section */ 205 | FA8450D22811C64B007162A3 /* PBXTargetDependency */ = { 206 | isa = PBXTargetDependency; 207 | target = FA8450C92811C639007162A3 /* libocep */; 208 | targetProxy = FA8450D12811C64B007162A3 /* PBXContainerItemProxy */; 209 | }; 210 | /* End PBXTargetDependency section */ 211 | 212 | /* Begin XCBuildConfiguration section */ 213 | FA8450C32811C615007162A3 /* Debug */ = { 214 | isa = XCBuildConfiguration; 215 | buildSettings = { 216 | CODE_SIGN_STYLE = Automatic; 217 | PRODUCT_NAME = "$(TARGET_NAME)"; 218 | }; 219 | name = Debug; 220 | }; 221 | FA8450C42811C615007162A3 /* Release */ = { 222 | isa = XCBuildConfiguration; 223 | buildSettings = { 224 | CODE_SIGN_STYLE = Automatic; 225 | PRODUCT_NAME = "$(TARGET_NAME)"; 226 | }; 227 | name = Release; 228 | }; 229 | FA8450CC2811C639007162A3 /* Debug */ = { 230 | isa = XCBuildConfiguration; 231 | buildSettings = { 232 | ALLOW_TARGET_PLATFORM_SPECIALIZATION = YES; 233 | CODE_SIGN_STYLE = Automatic; 234 | EXECUTABLE_PREFIX = lib; 235 | IPHONEOS_DEPLOYMENT_TARGET = 11.0; 236 | PRODUCT_NAME = "$(TARGET_NAME)"; 237 | SDKROOT = macosx; 238 | SKIP_INSTALL = YES; 239 | SUPPORTED_PLATFORMS = "watchsimulator watchos macosx iphonesimulator iphoneos driverkit appletvsimulator appletvos"; 240 | SUPPORTS_MACCATALYST = YES; 241 | TVOS_DEPLOYMENT_TARGET = 11.0; 242 | WATCHOS_DEPLOYMENT_TARGET = 4.0; 243 | }; 244 | name = Debug; 245 | }; 246 | FA8450CD2811C639007162A3 /* Release */ = { 247 | isa = XCBuildConfiguration; 248 | buildSettings = { 249 | ALLOW_TARGET_PLATFORM_SPECIALIZATION = YES; 250 | CODE_SIGN_STYLE = Automatic; 251 | EXECUTABLE_PREFIX = lib; 252 | IPHONEOS_DEPLOYMENT_TARGET = 11.0; 253 | PRODUCT_NAME = "$(TARGET_NAME)"; 254 | SDKROOT = macosx; 255 | SKIP_INSTALL = YES; 256 | SUPPORTED_PLATFORMS = "watchsimulator watchos macosx iphonesimulator iphoneos driverkit appletvsimulator appletvos"; 257 | SUPPORTS_MACCATALYST = YES; 258 | TVOS_DEPLOYMENT_TARGET = 11.0; 259 | WATCHOS_DEPLOYMENT_TARGET = 4.0; 260 | }; 261 | name = Release; 262 | }; 263 | FAF1B15E280F2A8500ABBA15 /* Debug */ = { 264 | isa = XCBuildConfiguration; 265 | buildSettings = { 266 | ALLOW_TARGET_PLATFORM_SPECIALIZATION = YES; 267 | ALWAYS_SEARCH_USER_PATHS = NO; 268 | CLANG_ANALYZER_NONNULL = YES; 269 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 270 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; 271 | CLANG_ENABLE_MODULES = YES; 272 | CLANG_ENABLE_OBJC_ARC = YES; 273 | CLANG_ENABLE_OBJC_WEAK = YES; 274 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 275 | CLANG_WARN_BOOL_CONVERSION = YES; 276 | CLANG_WARN_COMMA = YES; 277 | CLANG_WARN_CONSTANT_CONVERSION = YES; 278 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 279 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 280 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 281 | CLANG_WARN_EMPTY_BODY = YES; 282 | CLANG_WARN_ENUM_CONVERSION = YES; 283 | CLANG_WARN_INFINITE_RECURSION = YES; 284 | CLANG_WARN_INT_CONVERSION = YES; 285 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 286 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 287 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 288 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 289 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 290 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 291 | CLANG_WARN_STRICT_PROTOTYPES = YES; 292 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 293 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 294 | CLANG_WARN_UNREACHABLE_CODE = YES; 295 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 296 | COPY_PHASE_STRIP = NO; 297 | DEBUG_INFORMATION_FORMAT = dwarf; 298 | ENABLE_STRICT_OBJC_MSGSEND = YES; 299 | ENABLE_TESTABILITY = YES; 300 | GCC_C_LANGUAGE_STANDARD = gnu11; 301 | GCC_DYNAMIC_NO_PIC = NO; 302 | GCC_NO_COMMON_BLOCKS = YES; 303 | GCC_OPTIMIZATION_LEVEL = 0; 304 | GCC_PREPROCESSOR_DEFINITIONS = ( 305 | "DEBUG=1", 306 | "$(inherited)", 307 | ); 308 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 309 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 310 | GCC_WARN_UNDECLARED_SELECTOR = YES; 311 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 312 | GCC_WARN_UNUSED_FUNCTION = YES; 313 | GCC_WARN_UNUSED_VARIABLE = YES; 314 | MACOSX_DEPLOYMENT_TARGET = 10.13; 315 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 316 | MTL_FAST_MATH = YES; 317 | ONLY_ACTIVE_ARCH = YES; 318 | SDKROOT = macosx; 319 | SUPPORTED_PLATFORMS = "watchsimulator watchos macosx iphonesimulator iphoneos driverkit appletvsimulator appletvos"; 320 | SUPPORTS_MACCATALYST = YES; 321 | }; 322 | name = Debug; 323 | }; 324 | FAF1B15F280F2A8500ABBA15 /* Release */ = { 325 | isa = XCBuildConfiguration; 326 | buildSettings = { 327 | ALLOW_TARGET_PLATFORM_SPECIALIZATION = YES; 328 | ALWAYS_SEARCH_USER_PATHS = NO; 329 | CLANG_ANALYZER_NONNULL = YES; 330 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 331 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; 332 | CLANG_ENABLE_MODULES = YES; 333 | CLANG_ENABLE_OBJC_ARC = YES; 334 | CLANG_ENABLE_OBJC_WEAK = YES; 335 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 336 | CLANG_WARN_BOOL_CONVERSION = YES; 337 | CLANG_WARN_COMMA = YES; 338 | CLANG_WARN_CONSTANT_CONVERSION = YES; 339 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 340 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 341 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 342 | CLANG_WARN_EMPTY_BODY = YES; 343 | CLANG_WARN_ENUM_CONVERSION = YES; 344 | CLANG_WARN_INFINITE_RECURSION = YES; 345 | CLANG_WARN_INT_CONVERSION = YES; 346 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 347 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 348 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 349 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 350 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 351 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 352 | CLANG_WARN_STRICT_PROTOTYPES = YES; 353 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 354 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 355 | CLANG_WARN_UNREACHABLE_CODE = YES; 356 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 357 | COPY_PHASE_STRIP = NO; 358 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 359 | ENABLE_NS_ASSERTIONS = NO; 360 | ENABLE_STRICT_OBJC_MSGSEND = YES; 361 | GCC_C_LANGUAGE_STANDARD = gnu11; 362 | GCC_NO_COMMON_BLOCKS = YES; 363 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 364 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 365 | GCC_WARN_UNDECLARED_SELECTOR = YES; 366 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 367 | GCC_WARN_UNUSED_FUNCTION = YES; 368 | GCC_WARN_UNUSED_VARIABLE = YES; 369 | MACOSX_DEPLOYMENT_TARGET = 10.13; 370 | MTL_ENABLE_DEBUG_INFO = NO; 371 | MTL_FAST_MATH = YES; 372 | SDKROOT = macosx; 373 | SUPPORTED_PLATFORMS = "watchsimulator watchos macosx iphonesimulator iphoneos driverkit appletvsimulator appletvos"; 374 | SUPPORTS_MACCATALYST = YES; 375 | }; 376 | name = Release; 377 | }; 378 | /* End XCBuildConfiguration section */ 379 | 380 | /* Begin XCConfigurationList section */ 381 | FA8450C52811C615007162A3 /* Build configuration list for PBXNativeTarget "RunTest" */ = { 382 | isa = XCConfigurationList; 383 | buildConfigurations = ( 384 | FA8450C32811C615007162A3 /* Debug */, 385 | FA8450C42811C615007162A3 /* Release */, 386 | ); 387 | defaultConfigurationIsVisible = 0; 388 | defaultConfigurationName = Release; 389 | }; 390 | FA8450CB2811C639007162A3 /* Build configuration list for PBXNativeTarget "libocep" */ = { 391 | isa = XCConfigurationList; 392 | buildConfigurations = ( 393 | FA8450CC2811C639007162A3 /* Debug */, 394 | FA8450CD2811C639007162A3 /* Release */, 395 | ); 396 | defaultConfigurationIsVisible = 0; 397 | defaultConfigurationName = Release; 398 | }; 399 | FAF1B154280F2A8500ABBA15 /* Build configuration list for PBXProject "ObjcEncodingParser" */ = { 400 | isa = XCConfigurationList; 401 | buildConfigurations = ( 402 | FAF1B15E280F2A8500ABBA15 /* Debug */, 403 | FAF1B15F280F2A8500ABBA15 /* Release */, 404 | ); 405 | defaultConfigurationIsVisible = 0; 406 | defaultConfigurationName = Release; 407 | }; 408 | /* End XCConfigurationList section */ 409 | }; 410 | rootObject = FAF1B151280F2A8500ABBA15 /* Project object */; 411 | } 412 | --------------------------------------------------------------------------------