diff --git a/Makefile b/Makefile index 416d028..6822b06 100755 --- a/Makefile +++ b/Makefile @@ -83,7 +83,7 @@ all-lib: $(CHECKCFG) lib$(NAME).so.$(MAJOR) # Make a module object out of a module source file. define make-moduleobj-rule - $(OBJDIR)/$1/%.o: $(SRCDIR)/$1/%.c | $(OBJDIR)/$1 + $(OBJDIR)/$1/%.o: $(SRCDIR)/$1/%.c $(INC:%=$(INCDIR)/%.h) | $(OBJDIR)/$1 $(call bcmd,cc,$$@,$(CC) -c -o $$@ $$< $(CFLAGS)) endef $(foreach mod,$(MODULES), \ diff --git a/Makefile.vars b/Makefile.vars index ba52815..342f4c6 100755 --- a/Makefile.vars +++ b/Makefile.vars @@ -95,10 +95,17 @@ $(foreach mod,$(MODULES), \ $(eval $(call get-module-source,$(mod)))) #******************************************************************************# -# Look for public headers (not internals.h or internals/**/*.h # +# Look for headers # #******************************************************************************# - INCPUB := $(basename $(shell find $(INCDIR) \ - -name "*.h" -and -not -path "*internals*" -printf "%P\n" | sort)) +# All headers + INC := \ + $(basename $(shell find $(INCDIR) -name "*.h" -printf "%P\n")) + +# Public headers only (not internals.h or internals/**/*.h) + INCPUB := \ + $(basename $(shell find $(INCDIR) \ + \( -name "*.h" -and -not -path "*internals*" \) \ + -printf "%P\n" | sort)) #******************************************************************************# # Look for manpages # diff --git a/include/libg1m/format/lang.h b/include/libg1m/format/lang.h index b8d949e..4f6f65c 100644 --- a/include/libg1m/format/lang.h +++ b/include/libg1m/format/lang.h @@ -12,8 +12,91 @@ # include # pragma pack(1) -/* The format of this file is yet to discover. (may be discovered by someone - * out there, I don't know yet) */ +/* Thanks to amazonka for his (minimalist) description of the G3L format + * at Cemetech. So the G3L format starts off with a header: */ + +struct g3l_subheader { + /* a checksum */ + uint32_t checksum; + + /* magic: always "0401" */ + uint8_t magic[4]; + + /* lol */ + uint8_t undocumented[14]; + + /* size of the message zone size */ + uint32_t message_zone_size; + + /* undocumented, again */ + uint8_t undocumented5[6]; + + /* name of the language */ + uint8_t language_name2[28]; + + /* size of the entire file */ + uint32_t filesize; + + /* size of the entire file - starts with an '@' */ + uint8_t internal_name[8]; + + /* undocumented */ + uint8_t undocumented2[200]; + + /* version number string: "XX.XX.XXXX" */ + uint8_t version[10]; + + /* unused */ + uint8_t unused2[2]; + + /* creation time: "YYYY.MMDD.HHMM" */ + uint8_t datetime[14]; + + /* big undocumented thing */ + uint8_t undocumented3[3410]; + + /* language name (zero terminated) */ + uint8_t language_name[16]; + + /* language salutation (zero terminated) */ + uint8_t language_salutation[16]; + + /* filename (extension included) */ + uint8_t g3l_filename[16]; + + /* undocumented */ + uint8_t undocumented4[308]; +}; + +/* Then there is something amazonka names the "executable code section". + * This is in fact the message zone. + */ + +struct g3l_lang_header { + /* sequence: '4C 59 37 35 35 00 00 00 02' (LY755 ) */ + uint8_t sequence[9]; + + /* unused byte. */ + uint8_t unused; + + /* number of messages ("possibly 0 base indexed") */ + uint32_t num; + + /* unused bytes */ + uint8_t unused2[2]; +}; + +/* Then we have offsets of all messages (4 bytes each), + * then messages themselves, zero-terminated. + * + * The four last bytes of the files are a little footer, which is: */ + +struct g3l_footer { + /* copy of the first checksum in the subheader */ + uint32_t checksum; +}; + +/* This footer is not counted as part of the file. */ # pragma pack() #endif /* LIBG1M_FORMAT_LANG_H */ diff --git a/src/parse/lang.c b/src/parse/lang.c index 21d7778..f317abe 100644 --- a/src/parse/lang.c +++ b/src/parse/lang.c @@ -38,7 +38,60 @@ int g1m_parse_lang(g1m_t *handle, FILE *stream) int g1m_parse_lang_cg(g1m_t *handle, FILE *stream) { (void)handle; - (void)stream; - log_info("Language type isn't managed yet."); + /* read the subheader */ + DREAD(hd, g3l_subheader) + + /* correct the endianness */ + hd.message_zone_size = be32toh(hd.message_zone_size); + + /* log */ + log_info("internal name is '%.8s'", hd.internal_name); + log_info("language name is '%.16s'", hd.language_name); + log_info("language salutation is '%.16s'", hd.language_salutation); + log_info("version is '%.10s'", hd.version); + log_info("datetime is '%.14s'", hd.datetime); + log_info("g3l filename is '%.16s'", hd.g3l_filename); + + /* read the languages header */ + DREAD(lhd, g3l_lang_header) + logm_info(&lhd, sizeof(struct g3l_lang_header)); + + /* correct endianness */ + lhd.num = be32toh(lhd.num); + + /* log */ + log_info("there are %d messages", lhd.num); + + /* read the entire message zone */ + size_t message_zone_size = hd.message_zone_size + - sizeof(struct g3l_lang_header); + uint8_t message_zone[message_zone_size]; + READ(message_zone, message_zone_size) + + /* get parts */ + const uint_fast32_t num = lhd.num + 1; + uint32_t *offsets = (uint32_t*)message_zone; + uint8_t *messages = (uint8_t*)message_zone + num * sizeof(uint32_t); + + /* read messages */ + for (uint_fast32_t i = 0; i < num; i++) { + /* check if offset is valid */ + if (offsets[i] == (uint32_t)-1) { + log_info("[#%ld] -", i); + continue ; + } + + /* correct offset */ + offsets[i] = be32toh(offsets[i]); + + /* log */ + log_info("[#%ld] message: '%s'", i, &messages[offsets[i]]); + } + + /* parse footer */ + DREAD(footer, g3l_footer) + /* TODO: check the checksum */ + + /* no error */ return (0); } diff --git a/src/parse/picture.c b/src/parse/picture.c index a8b3199..44da5fd 100644 --- a/src/parse/picture.c +++ b/src/parse/picture.c @@ -60,7 +60,7 @@ int g1m_parse_g3p(g1m_t *handle, FILE *stream, /* check some little things */ int is_obfuscated = - (std->obfuscated + 8) & 0xff != ((std->filesize & 0xff00) >> 8); + ((std->obfuscated + 8) & 0xff) != ((std->filesize & 0xff00) >> 8); int has_footer = 1; /* might change? */ size_t deflated_image_size = ihd.data_size - has_footer * 0x4;