-
Notifications
You must be signed in to change notification settings - Fork 1
Add parsing support for Install files. #29
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3,6 +3,8 @@ | |
| #include <ctype.h> | ||
| #include <curl/curl.h> | ||
| #include <openssl/md5.h> | ||
| #include <stdint.h> | ||
| #include <stdio.h> | ||
| #include <stdlib.h> | ||
| #include <string.h> | ||
| #include <sys/stat.h> | ||
|
|
@@ -518,6 +520,227 @@ static int download_build_config(CURL *curl, const struct cdns *cdns, | |
| return ret; | ||
| } | ||
|
|
||
| #define MAX_TAGS 128 | ||
| #define MAX_FILES 1024 | ||
| #define MAX_FILE_NAME_LENGTH 255 | ||
|
|
||
| // Structure to hold an install tag entry | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this comment doesn't add value; just remove |
||
| typedef struct { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. remove the typedef, and use snake case: |
||
| char name[64]; | ||
| uint16_t type; | ||
| uint8_t *files; | ||
| } InstallTagEntry; | ||
|
|
||
| // Structure to hold an install file entry | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. same deal here: remove comment, remove typedef, snake case |
||
| typedef struct { | ||
| char name[MAX_FILE_NAME_LENGTH]; | ||
| uint8_t content_hash[16]; | ||
| uint32_t size; | ||
| uint8_t *tags; | ||
| } InstallFileEntry; | ||
|
|
||
| // Structure to hold the parsed install file information | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. same here re comment, typedef, name |
||
| typedef struct { | ||
| int hash_size; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. everything else in tactless assumes a 16-byte hash; more consistent to just do the same. this field doesn't need to exist |
||
| int version; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this should just be asserted to some value; doesn't need to be here |
||
| int num_tags; | ||
| InstallTagEntry tags[MAX_TAGS]; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this should be dynamically allocated, and just declared |
||
| int num_entries; | ||
| InstallFileEntry files[MAX_FILES]; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. same here |
||
| } InstallFile; | ||
|
|
||
| void print_install_file(const InstallFile *install) { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. see how the various _dump functions are set up, exposed in tactless.h, and invoked from main.c |
||
| printf("Install File Info:\n"); | ||
| printf("Hash Size: %d\nTags: %d\nFiles: %d\n", install->hash_size, | ||
| install->num_tags, install->num_entries); | ||
| printf("Version: %d\n", install->version); | ||
|
|
||
| // Print tag entries | ||
| printf("\nParsed Tag Entries:\n"); | ||
| for (int i = 0; i < install->num_tags; i++) { | ||
| printf("Tag %d: Name='%s', Type=%d\n", i, install->tags[i].name, | ||
| install->tags[i].type); | ||
| } | ||
|
|
||
| // Print file entries | ||
| printf("\nParsed File Entries:\n"); | ||
| for (int i = 0; i < install->num_entries; i++) { | ||
| char hex[33]; | ||
| hash2hex(install->files[i].content_hash, hex); | ||
| printf("\n%s (size: %u, md5: %s, tags: ", install->files[i].name, | ||
| install->files[i].size, hex); | ||
|
|
||
| int tag_count = 0; // Counter for associated tags | ||
| for (int j = 0; j < install->num_tags; j++) { | ||
| if (install->files[i].tags[j] == | ||
| 1) { // If the file is associated with this tag | ||
| if (tag_count > 0) { | ||
| printf(","); // Separate tags with a comma | ||
| } | ||
| printf("%d=%s", install->tags[j].type, install->tags[j].name); | ||
| tag_count++; | ||
| } | ||
| } | ||
|
|
||
| if (tag_count == 0) { | ||
| printf("None"); | ||
| } | ||
| printf(")"); // End of tag list | ||
| } | ||
| printf("\n"); | ||
| } | ||
|
|
||
| int parse_install_file(const uint8_t *data, size_t data_size, | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. rename it |
||
| InstallFile *install) { | ||
| size_t offset = 0; | ||
| // Validate the "IN" header | ||
| if (offset + 2 > data_size || | ||
| strncmp((char *)(data + offset), "IN", 2) != 0) { | ||
| fprintf(stderr, "Invalid install file format.\n"); | ||
| return -1; | ||
| } | ||
| // Skip "IN" header | ||
| offset += 2; | ||
|
|
||
| // header version byte | ||
| install->version = data[offset]; | ||
| offset += 1; | ||
|
|
||
| // Read hash size and validate | ||
| install->hash_size = data[offset++]; | ||
|
|
||
| if (install->hash_size != 16) { | ||
| fprintf(stderr, "Error: Unsupported install hash size! Got: %d\n", | ||
| install->hash_size); | ||
| return -1; | ||
| } | ||
|
|
||
| install->num_tags = uint16be(data + offset); | ||
| offset += 2; | ||
|
|
||
| install->num_entries = uint32be(data + offset); | ||
| offset += 4; | ||
|
|
||
| if (install->num_tags > MAX_TAGS || install->num_entries > MAX_FILES) { | ||
| fprintf(stderr, | ||
| "Error: Too many tags or files! Increase MAX_TAGS or MAX_FILES.\n"); | ||
| return -1; | ||
| } | ||
|
|
||
| int bytes_per_tag = (install->num_entries + 7) / 8; | ||
|
|
||
| // Read Tags | ||
| for (int i = 0; i < install->num_tags; i++) { | ||
| InstallTagEntry *tag = &install->tags[i]; | ||
|
|
||
| // **Read Tag Name (Null-Terminated String)** | ||
| size_t max_length = 64; | ||
| size_t name_len = strnlen((char *)(data + offset), max_length); | ||
|
|
||
| // Copy safely with explicit null termination | ||
| strncpy(tag->name, (char *)(data + offset), name_len); | ||
| tag->name[name_len] = '\0'; | ||
| offset += name_len + 1; // Move past string (including null terminator) | ||
|
|
||
| // **Read Type (UInt16, Handle Endianness)** | ||
| tag->type = uint16be(data + offset); | ||
| offset += 2; // Move past the type | ||
|
|
||
| // **Allocate Memory for Bitmask** | ||
| tag->files = malloc(bytes_per_tag); | ||
| if (!tag->files) { | ||
| fprintf(stderr, "Memory allocation failed for tag files.\n"); | ||
| return -1; | ||
| } | ||
| byte filebits[bytes_per_tag]; | ||
| // **Read the File Bitmask** | ||
| memcpy(filebits, data + offset, bytes_per_tag); | ||
| offset += bytes_per_tag; | ||
|
|
||
| // **Apply Bitmask Transformation** | ||
| for (int j = 0; j < bytes_per_tag; j++) { | ||
| tag->files[j] = | ||
| ((filebits[j] * 0x0202020202ULL & 0x010884422010ULL) % 1023); | ||
| } | ||
| // Dump tag->files | ||
| /* printf("\nTag %s %u %d: ", tag->name, tag->type, i); | ||
| for (int j = 0; j < bytes_per_tag; j++) { | ||
| printf("%02x", tag->files[j]); | ||
| } */ | ||
| } | ||
| // printf("\n"); | ||
|
|
||
| // Read file entries | ||
| for (int i = 0; i < install->num_entries; i++) { | ||
| InstallFileEntry *file_entry = &install->files[i]; | ||
|
|
||
| // Ensure the offset doesn't exceed the buffer | ||
| if (offset >= data_size) { | ||
| fprintf(stderr, "[ERROR] File %d offset exceeds data size!\n", i); | ||
| break; | ||
| } | ||
|
|
||
| // Find the null-terminated file name | ||
| size_t max_name_length = data_size - offset; | ||
| size_t name_len = strnlen((char *)(data + offset), max_name_length); | ||
|
|
||
| if (name_len == 0 || name_len >= max_name_length) { | ||
| fprintf(stderr, "[WARNING] File %d has an invalid name at offset %zu!\n", | ||
| i, offset); | ||
| file_entry->name[0] = '\0'; // Handle invalid name | ||
| } else { | ||
| // Copy the file name safely | ||
| memcpy(file_entry->name, data + offset, name_len); | ||
| file_entry->name[name_len] = '\0'; // Null-terminate properly | ||
| } | ||
|
|
||
| // Move past the filename including the null terminator | ||
| offset += name_len + 1; | ||
|
|
||
| // Ensure we have enough space to move forward | ||
| if (offset + 20 > data_size) { | ||
| fprintf(stderr, | ||
| "[ERROR] Not enough space to read metadata for File %d!\n", i); | ||
| break; | ||
| } | ||
|
|
||
| // Read content hash | ||
| memcpy(file_entry->content_hash, data + offset, install->hash_size); | ||
| offset += install->hash_size; | ||
|
|
||
| // Read file size | ||
| file_entry->size = uint32be(data + offset); | ||
| offset += 4; | ||
|
|
||
| // Allocate memory for storing tags per file | ||
| file_entry->tags = calloc(install->num_tags, sizeof(uint8_t)); | ||
| if (!file_entry->tags) { | ||
| fprintf(stderr, "Memory allocation failed for file tags.\n"); | ||
| return -1; | ||
| } | ||
|
|
||
| // Check tag bitmask and associate tags with the file | ||
| for (int t = 0; t < install->num_tags; t++) { | ||
| InstallTagEntry tagEntry = install->tags[t]; | ||
| // Safety check: Ensure `files` exists | ||
| if (!tagEntry.files) { | ||
| fprintf(stderr, "[ERROR] install->tags[%d].files is NULL!\n", t); | ||
| return -1; | ||
| } | ||
|
|
||
| // Avoid out-of-bounds access | ||
|
|
||
| if ((i / 8) < bytes_per_tag && | ||
| (install->tags[t].files[i / 8] & (1 << (i % 8)))) { | ||
| file_entry->tags[t] = 1; | ||
| } else { | ||
| file_entry->tags[t] = 0; | ||
| } | ||
| } | ||
| } | ||
| return 1; | ||
| } | ||
|
|
||
| struct cdn_config { | ||
| byte (*archives)[16]; | ||
| int narchives; | ||
|
|
@@ -833,8 +1056,15 @@ static int download_install(CURL *curl, const struct cdns *cdns, | |
| const byte *ckey, const byte *ekey) { | ||
| size_t size; | ||
| byte *text = download_from_cdn(curl, cdns, "data", ckey, ekey, &size); | ||
| int ret = text != NULL; | ||
| InstallFile *install = malloc(sizeof(InstallFile)); | ||
| if (!install) { | ||
| free(text); | ||
| return 0; | ||
| } | ||
| int ret = parse_install_file(text, size, install); | ||
| print_install_file(install); | ||
| free(text); | ||
| free(install); | ||
| return ret; | ||
| } | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
remove all three of these and use dynamic allocation instead