// Initialize the library - locates the first FAT16 partition, // loads the relevant part of its boot sector to calculate // values needed for operation, and finally positions the // file reading routines to the start of root directory entries char fat16_init() { char i; unsigned long root_start; fat16_seek(0x1BE); for(i=0; i<4; i++) { fat16_read(sizeof(PartitionTable)); if(FAT16_part->partition_type == 4 || FAT16_part->partition_type == 6 || FAT16_part->partition_type == 14) break; } if(i == 4) // none of the partitions were FAT16 return FAT16_ERR_NO_PARTITION_FOUND; fat16_state.fat_start = 512 * FAT16_part->start_sector; // temporary fat16_seek(fat16_state.fat_start + FAT16_BOOT_OFFSET); fat16_read(sizeof(Fat16BootSectorFragment)); if(FAT16_boot->sector_size != 512) return FAT16_ERR_INVALID_SECTOR_SIZE; fat16_state.fat_start += FAT16_boot->reserved_sectors * 512; root_start = fat16_state.fat_start + FAT16_boot->fat_size_sectors * FAT16_boot->number_of_fats * 512; fat16_state.data_start = root_start + FAT16_boot->root_dir_entries * sizeof(Fat16Entry); fat16_state.sectors_per_cluster = FAT16_boot->sectors_per_cluster; // Prepare for fat16_open_file(), cluster is not needed fat16_state.file_left = FAT16_boot->root_dir_entries * sizeof(Fat16Entry); fat16_state.cluster_left = 0xFFFFFFFF; // avoid FAT lookup with root dir #ifdef DEBUG printf("FAT start at %08X, root dir at %08X, data at %08X\n", fat16_state.fat_start, root_start, fat16_state.data_start); #endif fat16_seek(root_start); return 0; }
char fat16_read_file(char bytes) { // returns the bytes read #ifdef DEBUG //printf("fat16_read_file: Cluster %d, bytes left %d/%d\n", fat16_state.cluster, fat16_state.file_left, fat16_state.cluster_left); #endif if(fat16_state.file_left == 0) return 0; if(fat16_state.cluster_left == 0) { fat16_seek(fat16_state.fat_start + fat16_state.cluster*2); fat16_read(2); fat16_state.cluster = FAT16_ushort[0]; fat16_state.cluster_left = fat16_state.sectors_per_cluster * 512; if(fat16_state.cluster == 0xFFFF) { // end of cluster chain fat16_state.file_left = 0; return 0; } // Go to first cluster fat16_seek(fat16_state.data_start + (fat16_state.cluster-2) * fat16_state.sectors_per_cluster * 512); #ifdef DEBUG printf("Next cluster %d\n", fat16_state.cluster); #endif } if(bytes > fat16_state.file_left) bytes = fat16_state.file_left; if(bytes > fat16_state.cluster_left) bytes = fat16_state.cluster_left; bytes = fat16_read(bytes); fat16_state.file_left -= bytes; fat16_state.cluster_left -= bytes; #ifdef DEBUG //printf("%d bytes read: Cluster %d, bytes left %d/%d\n", bytes, fat16_state.cluster, fat16_state.file_left, fat16_state.cluster_left); #endif return bytes; }
struct img_resource *img_load(struct fat16_handle *h, char *name) { int rv; struct fat16_file fd; struct img_resource *r; printf("Loading image resource %s... ", name); if (fat16_open_by_name(h, &fd, name) == -1) { printf("not found?\r\n"); return NULL; } r = malloc(sizeof(*r)); if (!r) { printf("out of memory?\r\n"); return NULL; } r->pixels_orig = malloc(fd.len + 64); if (!r->pixels_orig) { printf("out of memory?\r\n"); return NULL; } r->pixels = (unsigned int *)(((unsigned int)r->pixels_orig + 63) & ~63); rv = fat16_read(&fd, (void *)r, 8); rv = fat16_read(&fd, (void *)r->pixels, fd.len - 8); if (rv != fd.len - 8) { printf("short read (%d)\r\n", rv); free(r); return NULL; } printf("%dx%d image (pixels at %08x)\r\n", r->w, r->h, r->pixels); return r; }
uint32_t fat16_open_file(struct fat16_buffer* buffer, const char* filename, const char* extension) { for (uint16_t file_index = 0; file_index < 512; ++file_index) { uint8_t pos; fat16_seek(buffer, buffer->directory_start + (file_index * 32)); fat16_read(buffer, 32); // attributes is non-zero on files. if (buffer->data[11] > 0) { for (pos = 0; pos < 8; ++pos) { if (buffer->data[pos] != filename[pos]) { break; } } if (pos == 8) { // found the entry! for (pos = 0; pos < 3; ++pos) { if (buffer->data[8 + pos] != extension[pos]) { break; } } if (pos == 3) { // 2 bytes for cluster at buffer.data[26] // 4 bytes for file size at buffer.data[28] buffer->cluster_offset = 0; buffer->current_cluster = (buffer->data[26] | ((uint16_t)buffer->data[27]) << 8); buffer->file_left = (buffer->data[28] | ((uint32_t)buffer->data[29]) << 8 | ((uint32_t)buffer->data[30]) << 16 | ((uint32_t)buffer->data[31]) << 24); return buffer->file_left; } } } } return 0; } // fat16_open_file
uint8_t fat16_read_file(struct fat16_buffer* buffer, uint8_t* data) { if (buffer->file_left == 0) { return 0; } if (buffer->cluster_offset == FAT16_CLUSTER_SIZE) { // look up the next cluster (current cluster * 2 bytes) fat16_seek(buffer, buffer->fat_start + buffer->current_cluster * 2); fat16_read16(buffer, &buffer->current_cluster); buffer->cluster_offset = 0; if (buffer->current_cluster == 0xffff) { // done reading! return 0; } } uint32_t data_start = buffer->directory_start + 16384; data_start += ((buffer->current_cluster - 2) * FAT16_CLUSTER_SIZE) + buffer->cluster_offset; fat16_seek(buffer, data_start); uint8_t bytes_to_read; if (buffer->file_left > FAT16_BUFFER_SIZE) { bytes_to_read = FAT16_BUFFER_SIZE; } else { bytes_to_read = buffer->file_left; } fat16_read(buffer, bytes_to_read); for (uint8_t index = 0; index < bytes_to_read; ++index) { data[index] = buffer->data[index]; } buffer->cluster_offset += bytes_to_read; buffer->file_left -= bytes_to_read; return bytes_to_read; } // fat16_read_file