diff --git a/README.md b/README.md index b474f94..4f5446a 100644 --- a/README.md +++ b/README.md @@ -37,8 +37,16 @@ Any and all contributions are welcome. Included is also a `cadius.pro` file you ## Changelog +#### 1.4.0 +- Adds AppleSingle file format support, with initial support for data and ProDOS file info IDs 1 & 11 ([#7](https://github.com/mach-kernel/cadius/issues/7)). +- Fix path bugs on Windows ([#9](https://github.com/mach-kernel/cadius/issues/9)). +- Fix buffer overflow from [#12](https://github.com/mach-kernel/cadius/issues/12). +- Fix segfault when using `EXTRACTVOLUME`. + +A big thank you to [@oliverschmidt](https://github.com/oliverschmidt) for helping test this release! + #### 1.3.2 -- Maintenance release / macro cleanup +- Maintenance release / macro cleanup. #### 1.3.1 - Resolves timestamp bugs in [#10](https://github.com/mach-kernel/cadius/issues/10). Thanks, @a2-4am! @@ -48,17 +56,17 @@ Any and all contributions are welcome. Included is also a `cadius.pro` file you - `REPLACEFILE` command, `DELETEFILE` support for type/auxtype suffix. #### 1.2-b3 -- Fix Windows build issues, make some shared OS methods static / remove from `os.c` ([@mach-kernel](https://github.com/mach-kernel)) +- Fix Windows build issues, make some shared OS methods static / remove from `os.c` ([@mach-kernel](https://github.com/mach-kernel)). #### 1.2-b2 -- Clean up OS macros, explicit `win32` and `posix` modules ([@mach-kernel](https://github.com/mach-kernel)) +- Clean up OS macros, explicit `win32` and `posix` modules ([@mach-kernel](https://github.com/mach-kernel)). #### 1.2-b1 -- UTF-8 encode all source files -- Initial POSIX support ([@mach-kernel](https://github.com/mach-kernel)) +- UTF-8 encode all source files. +- Initial POSIX support ([@mach-kernel](https://github.com/mach-kernel)). #### 1.1 -- Initial fork from BrutalDeluxe +- Initial fork from BrutalDeluxe. ## License diff --git a/Src/Dc_Prodos.h b/Src/Dc_Prodos.h index afe0517..292a2d2 100644 --- a/Src/Dc_Prodos.h +++ b/Src/Dc_Prodos.h @@ -249,7 +249,6 @@ struct file_descriptive_entry struct file_descriptive_entry *next; }; - struct prodos_file { int entry_type; /* Seedling, Sapling, Tree, Extended */ diff --git a/Src/Dc_Shared.c b/Src/Dc_Shared.c index 6cad307..5de8e9c 100644 --- a/Src/Dc_Shared.c +++ b/Src/Dc_Shared.c @@ -12,8 +12,9 @@ #include #include "Dc_Shared.h" -#include "os/os.h" #include "Dc_Memory.h" +#include "File_AppleSingle.h" +#include "os/os.h" #ifdef IS_WINDOWS #include @@ -64,6 +65,7 @@ unsigned char *LoadBinaryFile(char *file_path, int *data_length_rtn) /* Renvoi les données et la taille */ *data_length_rtn = nb_read; + return(data); } diff --git a/Src/Dc_Shared.h b/Src/Dc_Shared.h index 85ccb83..4d1fef3 100644 --- a/Src/Dc_Shared.h +++ b/Src/Dc_Shared.h @@ -8,9 +8,11 @@ #pragma once -typedef unsigned char BYTE; -typedef unsigned short WORD; -typedef unsigned long DWORD; +#include + +typedef unsigned char BYTE; +typedef uint16_t WORD; +typedef uint32_t DWORD; #define BUFFER_SIZE 2048 diff --git a/Src/File_AppleSingle.c b/Src/File_AppleSingle.c new file mode 100644 index 0000000..f815ed7 --- /dev/null +++ b/Src/File_AppleSingle.c @@ -0,0 +1,218 @@ +#include "File_AppleSingle.h" + +const unsigned int AS_MAGIC = (uint32_t) 0x00051600; + +static uint32_t as_field32(uint32_t num) +{ + return IS_LITTLE_ENDIAN ? swap32(num) : num; +} + +static uint16_t as_field16(uint16_t num) +{ + return IS_LITTLE_ENDIAN ? swap16(num) : num; +} + +/** + * Is this an AppleSingle file? + * @brief ASIsAppleSingle + * @param buf + * @return + */ +bool ASIsAppleSingle(unsigned char *buf) +{ + int buf_magic; + memcpy(&buf_magic, buf, sizeof(AS_MAGIC)); + buf_magic = as_field32(buf_magic); + + return buf_magic == AS_MAGIC; +} + +/** + * Parse header out of raw data buffer. + * @brief ASParseHeader + * @param buf The buffer + * @return + */ +struct as_file_header *ASParseHeader(unsigned char *buf) +{ + struct as_file_header *header = malloc(sizeof(as_file_header)); + struct as_file_header *buf_header = (as_file_header *) buf; + + header->magic = as_field32(buf_header->magic); + header->version = as_field32(buf_header->version); + header->num_entries = as_field16(buf_header->num_entries); + + return header; +} + +/** + * @brief ASParseProdosEntry + * @param entry_buf The entry buffer + * @return + */ +struct as_prodos_info *ASParseProdosEntry(unsigned char *entry_buf, DWORD length) +{ + struct as_prodos_info *prodos_entry = malloc(sizeof(as_prodos_info)); + struct as_prodos_info *buf_prodos_entry = (as_prodos_info *) entry_buf; + + prodos_entry->access = as_field16(buf_prodos_entry->access); + prodos_entry->filetype = as_field16(buf_prodos_entry->filetype); + prodos_entry->auxtype = as_field32(buf_prodos_entry->auxtype); + + return prodos_entry; +} + +/** + * Read headers and return a list of as_file_entry pointers. + * @brief ASGetEntries + * @param buf + * @return + */ +struct as_file_entry *ASGetEntries(struct as_file_header *header, unsigned char *buf) +{ + if (!header) + { + printf(" Invalid AppleSingle file!\n"); + return NULL; + } + + struct as_file_entry *entries = malloc( + header->num_entries * sizeof(as_file_entry) + ); + + struct as_file_entry *buf_entries = buf + sizeof(as_file_header); + memcpy(entries, buf_entries, header->num_entries * sizeof(as_file_entry)); + + if (IS_LITTLE_ENDIAN) + for (int i = 0; i < header->num_entries; ++i) + { + entries[i].entry_id = swap32(entries[i].entry_id); + entries[i].offset = swap32(entries[i].offset); + entries[i].length = swap32(entries[i].length); + } + + return entries; +} + +/** + * Grab data from data entry and place in prodos_file. + * @brief ASDecorateDataFork + * @param current_file The current file + * @param data The data + * @param data_fork_entry The data fork entry + */ +void ASDecorateDataFork(struct prodos_file *current_file, unsigned char *data, as_file_entry *data_fork_entry) +{ + if (data_fork_entry->entry_id != data_fork) return; + + unsigned char *data_entry = malloc(data_fork_entry->length); + memcpy(data_entry, data + data_fork_entry->offset, data_fork_entry->length); + current_file->data = data_entry; + current_file->data_length = data_fork_entry->length; + + return; +} + +/** + * Read ProDOS metadata struct and place in prodos_file. + * + * @brief ASDecorateProdosFileInfo + * @param current_file The current file + * @param data The data + * @param prodos_entry The prodos entry + */ +void ASDecorateProdosFileInfo(struct prodos_file *current_file, unsigned char *data, as_file_entry *prodos_entry) +{ + if (prodos_entry->entry_id != prodos_file_info) return; + + struct as_prodos_info *info_meta = ASParseProdosEntry( + data + prodos_entry->offset, prodos_entry->length + ); + + if (!info_meta) return; + + current_file->access = info_meta->access; + current_file->type = info_meta->filetype; + current_file->aux_type = info_meta->auxtype; + + return; +} + +/** + * Parse AppleSingle header and write attributes into prodos_file + * struct + * @brief ASDecorateProdosFile + * @param current_file + * @param data + */ +void ASDecorateProdosFile(struct prodos_file *current_file, unsigned char *data) +{ + struct as_file_header *header = ASParseHeader(data); + struct as_file_entry *entries = ASGetEntries(header, data); + + for (int i = 0; i < header->num_entries; ++i) + switch(entries[i].entry_id) + { + case data_fork: + ASDecorateDataFork(current_file, data, &entries[i]); + break; + case prodos_file_info: + ASDecorateProdosFileInfo(current_file, data, &entries[i]); + break; + default: + printf(" Entry ID %d unsupported, ignoring!\n", entries[i].entry_id); + printf(" (See https://tools.ietf.org/html/rfc1740 for ID lookup)\n"); + break; + } + return; +} + +struct as_from_prodos ASFromProdosFile(struct prodos_file *file) +{ + struct as_file_header *as_header = malloc(sizeof(as_file_header)); + as_header->magic = as_field32(AS_MAGIC); + for (int i = 0; i < 4; ++i) as_header->filler[i] = 0; + as_header->version = as_field32(0x00020000); + as_header->num_entries = as_field16(2); + + uint32_t header_offset = sizeof(as_file_header) + (2 * sizeof(as_file_entry)); + struct as_file_entry *data_entry = malloc(sizeof(as_file_entry)); + data_entry->entry_id = as_field32(data_fork); + data_entry->length = as_field32(file->data_length); + data_entry->offset = as_field32(header_offset); + + uint32_t prodos_entry_offset = header_offset + file->data_length; + struct as_file_entry *prodos_entry = malloc(sizeof(as_file_entry)); + prodos_entry->entry_id = as_field32(prodos_file_info); + prodos_entry->length = as_field32(sizeof(as_prodos_info)); + prodos_entry->offset = as_field32(prodos_entry_offset); + + struct as_prodos_info *prodos_info = malloc(sizeof(as_prodos_info)); + prodos_info->access = as_field16(file->entry->access); + prodos_info->filetype = as_field16(file->entry->file_type); + prodos_info->auxtype = as_field32(file->entry->file_aux_type); + + uint32_t payload_size = prodos_entry_offset + sizeof(as_prodos_info); + char *payload = malloc(payload_size); + char *seek = payload; + + memcpy(seek, as_header, sizeof(as_file_header)); + seek += sizeof(as_file_header); + + memcpy(seek, data_entry, sizeof(as_file_entry)); + seek += sizeof(as_file_entry); + + memcpy(seek, prodos_entry, sizeof(as_file_entry)); + seek += sizeof(as_file_entry); + + memcpy(seek, file->data, file->data_length); + seek += file->data_length; + + memcpy(seek, prodos_info, sizeof(as_prodos_info)); + + struct as_from_prodos as_file; + as_file.length = payload_size; + as_file.data = payload; + + return as_file; +} \ No newline at end of file diff --git a/Src/File_AppleSingle.h b/Src/File_AppleSingle.h new file mode 100644 index 0000000..41e796d --- /dev/null +++ b/Src/File_AppleSingle.h @@ -0,0 +1,83 @@ +/** + * AppleSingle file format support + * RFC 1740: https://tools.ietf.org/html/rfc1740 + * + * Author: David Stancu, @mach-kernel, Mar. 2018 + * + */ + +#pragma once + +#include +#include +#include +#include +#include + +#include "Dc_Shared.h" +#include "Dc_Prodos.h" + +const unsigned int AS_MAGIC; +#define IS_LITTLE_ENDIAN 'APPL' == (uint32_t) 0x4150504C + +#pragma pack(push, 1) + +typedef struct as_file_header +{ + DWORD magic; + DWORD version; + DWORD filler[4]; + WORD num_entries; +} as_file_header; + +typedef struct as_file_entry +{ + DWORD entry_id; + DWORD offset; + DWORD length; +} as_file_entry; + +typedef enum as_entry_types +{ + data_fork = 1, + resource_fork = 2, + real_name = 3, + comment = 4, + icon_bw = 5, + icon_color = 6, + file_dates_info = 8, + finder_info = 9, + mac_file_info = 10, + prodos_file_info = 11, + msdos_file_info = 12, + short_name = 13, + afp_file_info = 14, + directory_id = 15 +} as_entry_types; + +typedef struct as_prodos_info +{ + WORD access; + WORD filetype; + DWORD auxtype; +} as_prodos_info; + +typedef struct as_from_prodos +{ + uint16_t length; + char *data; +} as_from_prodos; + +#pragma pack(pop) + +bool ASIsAppleSingle(unsigned char *buf); + +struct as_file_header *ASParseHeader(unsigned char *buf); +struct as_prodos_info *ASParseProdosEntry(unsigned char *entry_buf, DWORD length); +struct as_file_entry *ASGetEntries(struct as_file_header *header, unsigned char *buf); + +void ASDecorateDataFork(struct prodos_file *current_file, unsigned char *data, as_file_entry *data_fork_entry); +void ASDeocrateProdosFileInfo(struct prodos_file *current_file, unsigned char *data, as_file_entry *prodos_entry); +void ASDecorateProdosFile(struct prodos_file *current_file, unsigned char *data); + +struct as_from_prodos ASFromProdosFile(struct prodos_file *file); \ No newline at end of file diff --git a/Src/Main.c b/Src/Main.c index c242360..4c8e07c 100644 --- a/Src/Main.c +++ b/Src/Main.c @@ -9,6 +9,7 @@ #include #include #include +#include #if IS_WINDOWS #include @@ -78,7 +79,7 @@ int main(int argc, char *argv[]) verbose = 0; /* Message Information */ - printf("%s v 1.3.1, (c) Brutal Deluxe 2011-2013.\n",argv[0]); + printf("%s v 1.4.0 (c) Brutal Deluxe 2011-2013.\n",argv[0]); /* Vérification des paramètres */ if(argc < 3) @@ -94,6 +95,9 @@ int main(int argc, char *argv[]) if(!my_stricmp(argv[argc-1],"-V")) verbose = 1; + /* AppleSingle */ + bool output_apple_single = !my_stricmp(argv[argc - 1], "-A"); + /** Décode les paramètres **/ param = GetParamLine(argc-verbose,argv); if(param == NULL) @@ -137,6 +141,7 @@ int main(int argc, char *argv[]) { /* Information */ printf(" - Extract file '%s'\n",param->prodos_file_path); + if (output_apple_single) printf(" - Creating AppleSingle file!\n"); /** Charge l'image 2mg **/ current_image = LoadProdosImage(param->image_file_path); @@ -144,7 +149,12 @@ int main(int argc, char *argv[]) return(3); /** Extrait le fichier sur disque **/ - ExtractOneFile(current_image,param->prodos_file_path,param->output_directory_path); + ExtractOneFile( + current_image, + param->prodos_file_path, + param->output_directory_path, + output_apple_single + ); /* Libération mémoire */ mem_free_image(current_image); @@ -153,6 +163,7 @@ int main(int argc, char *argv[]) { /* Information */ printf(" - Extract folder '%s' :\n",param->prodos_folder_path); + if (output_apple_single) printf(" - Creating AppleSingle files!\n"); /** Charge l'image 2mg **/ current_image = LoadProdosImage(param->image_file_path); @@ -165,7 +176,12 @@ int main(int argc, char *argv[]) return(4); /** Extrait les fichiers du répertoire **/ - ExtractFolderFiles(current_image,folder_entry,param->output_directory_path); + ExtractFolderFiles( + current_image, + folder_entry, + param->output_directory_path, + output_apple_single + ); /* Stat */ printf(" => File(s) : %d, Folder(s) : %d, Error(s) : %d\n",current_image->nb_extract_file,current_image->nb_extract_folder,current_image->nb_extract_error); @@ -182,9 +198,14 @@ int main(int argc, char *argv[]) /* Information */ printf(" - Extract volume '%s' :\n",current_image->volume_header->volume_name_case); + if (output_apple_single) printf(" - Creating AppleSingle files!\n"); /** Extrait les fichiers du volume **/ - ExtractVolumeFiles(current_image,param->output_directory_path); + ExtractVolumeFiles( + current_image, + param->output_directory_path, + output_apple_single + ); /* Stat */ printf(" => File(s) : %d, Folder(s) : %d, Error(s) : %d\n",current_image->nb_extract_file,current_image->nb_extract_folder,current_image->nb_extract_error); @@ -393,9 +414,9 @@ int main(int argc, char *argv[]) int fcharloc = 0; for (int i=strlen(param->file_path); i >= 0; --i) { - if (!strncmp(¶m->file_path[i], FOLDER_CHARACTER, sizeof(FOLDER_CHARACTER))) + if (!strncmp(¶m->file_path[i], &FOLDER_CHARACTER, 1)) { - fcharloc = i; + fcharloc = i + 1; break; } } @@ -403,10 +424,15 @@ int main(int argc, char *argv[]) // Prepare parameters for delete char *file_name = param->file_path + fcharloc; char *prodos_file_name = strdup(param->prodos_folder_path); - strcat(prodos_file_name, &FOLDER_CHARACTER); + + // The tool does not use Windows path conventions + if (strncmp(&prodos_file_name[strlen(prodos_file_name) - 1], \ + &FOLDER_CHARACTER, strlen(FOLDER_CHARACTER))) + strcat(prodos_file_name, "/"); + strcat(prodos_file_name, file_name); - printf(" - Replacing file '%s' :\n",param->file_path); + printf(" - Replacing file '%s' :\n",prodos_file_name); DeleteProdosFile(current_image, prodos_file_name); AddFile(current_image, param->file_path, param->prodos_folder_path,1); @@ -495,7 +521,8 @@ void usage(char *program_path) printf(" ----\n"); printf(" %s EXTRACTFILE <[2mg|hdv|po]_image_path> \n",program_path); printf(" %s EXTRACTFOLDER <[2mg|hdv|po]_image_path> \n",program_path); - printf(" %s EXTRACTVOLUME <[2mg|hdv|po]_image_path> \n",program_path); + printf(" %s EXTRACTVOLUME <[2mg|hdv|po]_image_path> \n\n",program_path); + printf(" [-A] Extract as AppleSingle\n"); printf(" ----\n"); printf(" %s RENAMEFILE <[2mg|hdv|po]_image_path> \n",program_path); printf(" %s RENAMEFOLDER <[2mg|hdv|po]_image_path> \n",program_path); @@ -537,6 +564,13 @@ struct parameter *GetParamLine(int argc, char *argv[]) struct parameter *param; char local_buffer[256]; + for (int i = 0; i < argc; ++i) + if (strlen(argv[i]) > 256) + { + printf(" Error: Argument too long!\n"); + return(NULL); + } + /* Vérifications */ if(argc < 3) { @@ -589,7 +623,7 @@ struct parameter *GetParamLine(int argc, char *argv[]) } /** EXTRACTFILE **/ - if(!my_stricmp(argv[1],"EXTRACTFILE") && argc == 5) + if(!my_stricmp(argv[1],"EXTRACTFILE") && argc >= 5) { param->action = ACTION_EXTRACT_FILE; @@ -615,7 +649,7 @@ struct parameter *GetParamLine(int argc, char *argv[]) } /** EXTRACTFOLDER **/ - if(!my_stricmp(argv[1],"EXTRACTFOLDER") && argc == 5) + if(!my_stricmp(argv[1],"EXTRACTFOLDER") && argc >= 5) { param->action = ACTION_EXTRACT_FOLDER; @@ -641,7 +675,7 @@ struct parameter *GetParamLine(int argc, char *argv[]) } /** EXTRACTVOLUME **/ - if(!my_stricmp(argv[1],"EXTRACTVOLUME") && argc == 4) + if(!my_stricmp(argv[1],"EXTRACTVOLUME") && argc >= 4) { param->action = ACTION_EXTRACT_VOLUME; diff --git a/Src/Prodos_Add.c b/Src/Prodos_Add.c index 5f6e370..e60b290 100644 --- a/Src/Prodos_Add.c +++ b/Src/Prodos_Add.c @@ -18,12 +18,13 @@ #include #include +#include "os/os.h" #include "Dc_Shared.h" #include "Dc_Memory.h" #include "Dc_Prodos.h" -#include "os/os.h" #include "Prodos_Create.h" #include "Prodos_Add.h" +#include "File_AppleSingle.h" static struct prodos_file *LoadFile(char *); static int GetFileInformation(char *,char *,struct prodos_file *); @@ -309,7 +310,7 @@ static struct prodos_file *LoadFile(char *file_path_data) // Start from end of string until we arrive to path delimiter strcpy(folder_path,file_path_data); for(i=strlen(folder_path); i>=0; i--) - if(!strncmp(&folder_path[i], FOLDER_CHARACTER, sizeof(FOLDER_CHARACTER))) + if(!strncmp(&folder_path[i], &FOLDER_CHARACTER, strlen(FOLDER_CHARACTER))) { folder_path[i+1] = '\0'; break; @@ -318,7 +319,7 @@ static struct prodos_file *LoadFile(char *file_path_data) // Similarly, also extract the filename strcpy(file_name,file_path_data); for(i=strlen(file_path_data); i>=0; i--) - if(!strncmp(&folder_path[i], FOLDER_CHARACTER, sizeof(FOLDER_CHARACTER))) + if(!strncmp(&folder_path[i], &FOLDER_CHARACTER, strlen(FOLDER_CHARACTER))) { strcpy(file_name,&file_path_data[i+1]); break; @@ -347,9 +348,28 @@ static struct prodos_file *LoadFile(char *file_path_data) current_file->file_name[i] = toupper(current_file->file_name[i]); /* Proper Case */ current_file->name_case = BuildProdosCase(current_file->file_name_case); - - /*** Chargement des Data ***/ - current_file->data = LoadBinaryFile(file_path_data,¤t_file->data_length); + + // Load data. If an AppleSingle file, parse it. + unsigned char *data = LoadBinaryFile(file_path_data, ¤t_file->data_length); + + if (data == NULL) + { + printf(" Error : Cannot load file %s\n", file_path_data); + return NULL; + } + + bool is_apple_single = ASIsAppleSingle(data); + + if (is_apple_single) + { + printf(" AppleSingle format detected!\n"); + ASDecorateProdosFile(current_file, data); + } + else + { + current_file->data = data; + } + if(current_file->data != NULL && current_file->data_length == 0) { free(current_file->data); @@ -369,7 +389,7 @@ static struct prodos_file *LoadFile(char *file_path_data) /** Chargement des Informations du fichier contenue dans _FileInformation.txt **/ sprintf(file_path,"%s_FileInformation.txt",folder_path); found = GetFileInformation(file_path,file_name,current_file); - if(!found) + if(!found && !is_apple_single) { /* Valeurs par défaut */ current_file->type = 0x00; diff --git a/Src/Prodos_Extract.c b/Src/Prodos_Extract.c index 74632c4..cec6efa 100644 --- a/Src/Prodos_Extract.c +++ b/Src/Prodos_Extract.c @@ -18,14 +18,22 @@ #include "Dc_Prodos.h" #include "os/os.h" #include "Prodos_Extract.h" +#include "File_AppleSingle.h" -static int CreateOutputFile(struct prodos_file *,char *); +static int CreateOutputFile(struct prodos_file *,char *, bool); static void SetFileInformation(char *,struct prodos_file *); -/**************************************************************/ -/* ExtractOneFile() : Extrait un fichier Prodos sur disque. */ -/**************************************************************/ -void ExtractOneFile(struct prodos_image *current_image, char *prodos_file_path, char *output_directory_path) +/** + * Extracts one file + * + * @brief ExtractOneFile + * + * @param current_image + * @param prodos_file_path + * @param output_directory_path + * @param output_apple_single + */ +void ExtractOneFile(struct prodos_image *current_image, char *prodos_file_path, char *output_directory_path, bool output_apple_single) { int error; struct file_descriptive_entry *current_entry; @@ -55,7 +63,7 @@ void ExtractOneFile(struct prodos_image *current_image, char *prodos_file_path, } /** Création du fichier sur disque **/ - error = CreateOutputFile(current_file,output_directory_path); + error = CreateOutputFile(current_file,output_directory_path,output_apple_single); /* Libération mémoire */ mem_free_file(current_file); @@ -65,7 +73,7 @@ void ExtractOneFile(struct prodos_image *current_image, char *prodos_file_path, /************************************************************************/ /* ExtractFolderFiles() : Fonction récursive d'extraction de fichier. */ /************************************************************************/ -void ExtractFolderFiles(struct prodos_image *current_image, struct file_descriptive_entry *folder_entry, char *output_directory_path) +void ExtractFolderFiles(struct prodos_image *current_image, struct file_descriptive_entry *folder_entry, char *output_directory_path, bool output_apple_single) { int i, error; char *windows_folder_path; @@ -130,7 +138,7 @@ void ExtractFolderFiles(struct prodos_image *current_image, struct file_descript } /** Création du fichier sur disque **/ - error = CreateOutputFile(current_file,windows_folder_path); + error = CreateOutputFile(current_file,windows_folder_path,output_apple_single); /* Libération mémoire */ mem_free_file(current_file); @@ -153,7 +161,7 @@ void ExtractFolderFiles(struct prodos_image *current_image, struct file_descript printf(" + Extract Folder : %s\n",current_entry->file_path); /** Récursivité **/ - ExtractFolderFiles(current_image,current_entry,windows_folder_path); + ExtractFolderFiles(current_image,current_entry,windows_folder_path,output_apple_single); } /** Libération mémoire **/ @@ -164,7 +172,7 @@ void ExtractFolderFiles(struct prodos_image *current_image, struct file_descript /****************************************************************************/ /* ExtractVolumeFiles() : Fonction d'extraction des fichiers d'un volume. */ /****************************************************************************/ -void ExtractVolumeFiles(struct prodos_image *current_image, char *output_directory_path) +void ExtractVolumeFiles(struct prodos_image *current_image, char *output_directory_path, bool output_apple_single) { int i, error; char *windows_folder_path; @@ -228,7 +236,7 @@ void ExtractVolumeFiles(struct prodos_image *current_image, char *output_directo } /** Création du fichier sur disque **/ - error = CreateOutputFile(current_file,windows_folder_path); + error = CreateOutputFile(current_file,windows_folder_path, output_apple_single); /* Libération mémoire */ mem_free_file(current_file); @@ -251,7 +259,7 @@ void ExtractVolumeFiles(struct prodos_image *current_image, char *output_directo printf(" + Extract Folder : %s\n",current_entry->file_path); /** Récursivité **/ - ExtractFolderFiles(current_image,current_entry,windows_folder_path); + ExtractFolderFiles(current_image,current_entry,windows_folder_path,output_apple_single); } /** Libération mémoire **/ @@ -266,7 +274,7 @@ void ExtractVolumeFiles(struct prodos_image *current_image, char *output_directo * @param output_directory_path * @return */ -static int CreateOutputFile(struct prodos_file *current_file, char *output_directory_path) +static int CreateOutputFile(struct prodos_file *current_file, char *output_directory_path, bool output_apple_single) { int error; char directory_path[1024]; @@ -291,10 +299,13 @@ static int CreateOutputFile(struct prodos_file *current_file, char *output_direc strcat(file_data_path,current_file->entry->file_name_case); // Append the file type and auxtype extension - char extension[7]; - strcat(file_data_path, "#"); - sprintf(extension, "%02hhX%04hX", current_file->entry->file_type, current_file->entry->file_aux_type); - strcat(file_data_path, extension); + if (!output_apple_single) + { + char extension[7]; + strcat(file_data_path, "#"); + sprintf(extension, "%02hhX%04hX", current_file->entry->file_type, current_file->entry->file_aux_type); + strcat(file_data_path, extension); + } // ResourceFork path strcpy(file_resource_path,file_data_path); @@ -303,7 +314,15 @@ static int CreateOutputFile(struct prodos_file *current_file, char *output_direc /**********************************/ /** Création du Fichier : Data **/ /**********************************/ - error = CreateBinaryFile(file_data_path,current_file->data,current_file->data_length); + + if (output_apple_single) + { + struct as_from_prodos as_file = ASFromProdosFile(current_file); + error = CreateBinaryFile(file_data_path, as_file.data, as_file.length); + } + else + error = CreateBinaryFile(file_data_path,current_file->data,current_file->data_length); + if(error) { printf(" Error : Can't create file '%s' on disk at location '%s'.\n",current_file->entry->file_name_case,file_data_path); @@ -321,9 +340,13 @@ static int CreateOutputFile(struct prodos_file *current_file, char *output_direc #endif /** Ajoute des informations du fichier dans le fichier FileInformation.txt **/ - strcpy(file_information_path,directory_path); - strcat(file_information_path,"_FileInformation.txt"); - SetFileInformation(file_information_path,current_file); + + if (!output_apple_single) + { + strcpy(file_information_path,directory_path); + strcat(file_information_path,"_FileInformation.txt"); + SetFileInformation(file_information_path,current_file); + } /**************************************/ /** Création du Fichier : Resource **/ @@ -410,6 +433,8 @@ static void SetFileInformation(char *file_information_path, struct prodos_file * /** Ajouts des lignes existantes **/ for(i=0; i + +void ExtractOneFile(struct prodos_image *, char *, char *, bool); +void ExtractFolderFiles(struct prodos_image *, struct file_descriptive_entry *, char *, bool); +void ExtractVolumeFiles(struct prodos_image *, char *, bool); /***********************************************************************/ diff --git a/Src/os/os.h b/Src/os/os.h index 89a93bb..c151339 100644 --- a/Src/os/os.h +++ b/Src/os/os.h @@ -73,4 +73,7 @@ int my_mkdir(char *path); char *my_strcpy(char *s1, char *s2); char *my_strdup(const char *s); +uint32_t swap32(uint32_t num); +uint16_t swap16(uint16_t num); + /***********************************************************************/ diff --git a/Src/os/posix.c b/Src/os/posix.c index 7b0f33f..b2c43c2 100644 --- a/Src/os/posix.c +++ b/Src/os/posix.c @@ -172,11 +172,21 @@ void os_GetFileCreationModificationDate(char *path, struct prodos_file *file) { char *my_strcpy(char *s1, char *s2) { - return strcpy(s1, s2); + return strcpy(s1, s2); } char *my_strdup(const char *s) { - return strdup(s); + return strdup(s); +} + +uint32_t swap32(uint32_t num) +{ + return __builtin_bswap32(num); +} + +uint16_t swap16(uint16_t num) +{ + return __builtin_bswap16(num); } #endif diff --git a/Src/os/win32.c b/Src/os/win32.c index a96be49..7b3abdb 100644 --- a/Src/os/win32.c +++ b/Src/os/win32.c @@ -264,4 +264,14 @@ int my_mkdir(char *path) return mkdir(path); } +uint32_t swap32(uint32_t num) +{ + return _byteswap_ulong(num); +} + +uint16_t swap16(uint16_t num) +{ + return _byteswap_ushort(num); +} + #endif