9 unsigned char info_signature[3] = {3, 21, 63 | 0x80};
15 unsigned name_length :4;
16 unsigned storage_type :4;
19 unsigned char file_type;
22 unsigned char size[3];
23 unsigned long creation;
24 unsigned char version;
25 unsigned char min_version;
28 unsigned long last_mod;
29 unsigned header_pointer;
33 unsigned char bytes[512];
37 unsigned char entries[1];
42 unsigned char bytes[512];
44 unsigned char addr_lo[254];
45 unsigned char size_lo[2];
46 unsigned char addr_hi[254];
47 unsigned char size_hi[2];
49 } index_block, master_block, vlir_block;
52 unsigned char bytes[512];
55 unsigned char info_block[254];
56 unsigned char vlir_records[128];
57 struct dir_entry_t dir_entry;
62 static void err_exit(char *operation, unsigned char oserr)
65 fprintf(stderr, "%s - err:%02x - %s",
66 operation, (int)_oserror, _stroserror(_oserror));
76 static unsigned get_dir_entry(char* p_name)
82 struct dirent* dirent;
84 unsigned char entry_length;
85 unsigned char entries_per_block;
86 unsigned char cur_entry;
88 /* Split path name into directory name and file name */
89 f_name = strrchr(p_name, '/');
97 f_namelen = strlen(f_name);
99 /* Start with high level functions to get handling
100 of relative path and current drive for free */
101 dir = opendir(d_name);
103 err_exit("opendir", 1);
105 dirent = readdir(dir);
107 err_exit("readdir", 1);
110 /* Field header_pointer directly follows field last_mod */
111 cur_addr = *(unsigned*)(&dirent->d_mtime.hour + 1);
113 dhandle = dio_open(getcurrentdevice());
115 err_exit("dio_open", 1);
118 if (dio_read(dhandle, cur_addr, &dir_block)) {
119 err_exit("dio_read.1", 1);
122 /* Get directory entry infos from directory header */
123 entry_length = dir_block.bytes[0x23];
124 entries_per_block = dir_block.bytes[0x24];
126 /* Skip directory header entry */
131 /* Search for next active directory entry */
134 /* Check if next directory block is necessary */
135 if (cur_entry == entries_per_block) {
137 /* Check if another directory block is present */
138 cur_addr = dir_block.content.next_block;
141 err_exit("dio_read.2", 1);
144 /* Read next directory block */
145 if (dio_read(dhandle, cur_addr, &dir_block)) {
146 err_exit("dio_read.3", 1);
149 /* Start with first entry in next block */
153 /* Compute pointer to current entry */
154 dir_entry = (struct dir_entry_t*)(dir_block.content.entries +
155 cur_entry * entry_length);
157 /* Switch to next entry */
159 } while (!dir_entry->storage_length.storage_type);
161 } while (dir_entry->storage_length.name_length != f_namelen ||
162 strncasecmp(dir_entry->file_name, f_name, f_namelen));
168 int main(int argc, char* argv[])
173 unsigned header_addr;
181 "Apple GEOS Convert 1.0\n"
182 "----------------------\n"
185 p_name = gets(input);
188 dir_addr = get_dir_entry(p_name);
190 /* Read index block */
191 if (dio_read(dhandle, dir_entry->key_pointer, &index_block)) {
192 err_exit("dio_read.4", 1);
195 /* First pointer is header block */
196 header_addr = index_block.content.addr_lo[0] |
197 index_block.content.addr_hi[0] << 8;
199 /* Read header block */
200 if (dio_read(dhandle, header_addr, &header_block)) {
201 err_exit("dio_read.5", 1);
204 /* Do some sanity check */
205 for (index = 0; index < sizeof(info_signature); ++index) {
206 if (header_block.content.info_block[index] != info_signature[index]) {
207 err_exit("file signature mismatch", 0);
211 /* Check ProDOS storage type in directory entry template */
212 if (header_block.content.dir_entry.storage_length.storage_type == 2)
215 /* ProDOS sapling file means GEOS Sequential file*/
216 printf("\nSequential file\n");
218 /* Remove header block pointer from pointer list */
219 memmove(&index_block.content.addr_lo[0],
220 &index_block.content.addr_lo[1], sizeof(index_block.content.addr_lo) - 1);
221 memmove(&index_block.content.addr_hi[0],
222 &index_block.content.addr_hi[1], sizeof(index_block.content.addr_hi) - 1);
224 /* Get file size from ProDOS directory entry template */
225 size = (unsigned long)(header_block.content.dir_entry.size[0]) |
226 (unsigned long)(header_block.content.dir_entry.size[1]) << 8 |
227 (unsigned long)(header_block.content.dir_entry.size[2]) << 16;
231 /* ProDOS tree file means GEOS VLIR file */
233 unsigned long vlir_size;
234 unsigned char vlir_blocks;
235 unsigned char record = 0;
237 printf("\nVLIR file\n");
239 /* Skip header block pointer */
245 /* Get next VLIR index pointer from index block */
246 vlir_addr = index_block.content.addr_lo[index] |
247 index_block.content.addr_hi[index] << 8;
250 /* Check for end of pointer list */
251 if (vlir_addr == 0) {
255 /* Check for empty VLIRs */
256 while (header_block.content.vlir_records[record] == 0xFF) {
258 /* Add empty VLIR index pointer to to master index block */
259 master_block.content.addr_lo[record] = 0xFF;
260 master_block.content.addr_hi[record] = 0xFF;
264 /* Add VLIR index pointer to master index block */
265 master_block.content.addr_lo[record] = (unsigned char)(vlir_addr );
266 master_block.content.addr_hi[record] = (unsigned char)(vlir_addr >> 8);
269 /* Read VLIR index block */
270 if (dio_read(dhandle, vlir_addr, &vlir_block)) {
271 err_exit("dio_read.6", 1);
274 /* Get VLIR size from VLIR index block */
275 vlir_size = (unsigned long)(vlir_block.content.size_lo[1]) |
276 (unsigned long)(vlir_block.content.size_hi[1]) << 8 |
277 (unsigned long)(vlir_block.content.size_lo[0]) << 16 |
278 (unsigned long)(vlir_block.content.size_hi[0]) << 24;
280 printf("VLIR %u size %lu bytes\n", record - 1, vlir_size);
282 /* Compute VLIR block size */
283 vlir_blocks = (unsigned char)((vlir_size + 511) / 512);
285 /* Copy VLIR block pointers from index block to VLIR index block */
286 memcpy(&vlir_block.content.addr_lo[0],
287 &index_block.content.addr_lo[index], vlir_blocks);
288 memcpy(&vlir_block.content.addr_hi[0],
289 &index_block.content.addr_hi[index], vlir_blocks);
290 index += vlir_blocks;
292 /* Write back VLIR index block */
293 if (dio_write(dhandle, vlir_addr, &vlir_block)) {
294 err_exit("dio_write.1", 1);
297 /* Add VLIR size to file size */
301 /* Replace (by now completely read) index block with
302 (by now completely created) master index block */
303 index_block = master_block;
306 printf("File size %lu bytes\n\n", size);
308 /* Set file size in index block */
309 index_block.content.size_lo[1] = (unsigned char)(size );
310 index_block.content.size_hi[1] = (unsigned char)(size >> 8);
311 index_block.content.size_lo[0] = (unsigned char)(size >> 16);
312 index_block.content.size_hi[0] = (unsigned char)(size >> 24);
314 /* Write index block */
315 if (dio_write(dhandle, dir_entry->key_pointer, &index_block)) {
316 err_exit("dio_write.2", 1);
319 /* Copy selected fields from directory entry template to directory block */
320 dir_entry->storage_length = header_block.content.dir_entry.storage_length;
321 memcpy(dir_entry->file_name, header_block.content.dir_entry.file_name, 15);
322 dir_entry->file_type = header_block.content.dir_entry.file_type;
323 dir_entry->size[0] = (unsigned char)(size );
324 dir_entry->size[1] = (unsigned char)(size >> 8);
325 dir_entry->size[2] = (unsigned char)(size >> 16);
326 dir_entry->creation = header_block.content.dir_entry.creation;
327 dir_entry->version = header_block.content.dir_entry.version;
328 dir_entry->min_version = header_block.content.dir_entry.min_version;
329 dir_entry->aux_type = header_addr;
330 dir_entry->last_mod = header_block.content.dir_entry.last_mod;
332 /* Write directory block */
333 if (dio_write(dhandle, dir_addr, &dir_block)) {
334 err_exit("dio_write.3", 1);
338 if (dio_close(dhandle)) {
339 err_exit("dio_close", 1);
342 printf("Convert to '%.*s' successful", dir_entry->storage_length.name_length,
343 dir_entry->file_name);