#include #include #include #include #include #include #include <9p.h> #include #include "mapbook.h" #include "ifslib.h" #include "import_ppm.h" #include "convolute.h" #include "imgfs.h" File * create_new_file(File *dir, char* filename, int perm, int id_code, Mapbook *m) { File *file; Aux *a; if (dir == nil || filename == nil) return nil; incref(dir); /* so walk doesn't kill it immediately on failure */ file = walkfile(dir, filename); if (file) { file = nil; } else { a = new_aux(id_code, m); file = createfile(dir, filename, getuser(), perm, &a->index); incref(dir); } decref(dir); return file; } void add_channels(File* dir, Mapbook* m) { create_new_file(dir, "ctrl", 0666, id_ctrl, m); create_new_file(dir, "ppm", 0444, id_ppm, m); create_new_file(dir, "width", 0666, id_width, m); create_new_file(dir, "height", 0666, id_height, m); create_new_file(dir, "red", 0666, id_red, m); create_new_file(dir, "green", 0666, id_green, m); create_new_file(dir, "blue", 0666, id_blue, m); create_new_file(dir, "select", 0666, id_select, m); create_new_file(dir, "alpha", 0666, id_alpha, m); // as yet unused but present for when required // nothing to stop them being used /* create_new_file(dir, "cyan", 0666, id_cyan, m); create_new_file(dir, "magenta", 0666, id_magenta, m); create_new_file(dir, "yellow", 0666, id_yellow, m); create_new_file(dir, "black", 0666, id_black, m); create_new_file(dir, "hue", 0666, id_cyan, m); create_new_file(dir, "saturation", 0666, id_magenta, m); create_new_file(dir, "lightness", 0666, id_yellow, m); */ } Aux * create_new_image_folder(char *filename) { Aux *a; File *file = walkfile(images_folder, filename); if (file) return nil; a = new_aux(id_imgfolder, nil); file = createfile(images_folder, filename, getuser(), DMDIR|0555, &a->index); incref(images_folder); add_channels(file, a->mapbook); return a; } Aux * get_aux(void *indexp) { Aux *a = nil; if(indexp) { int index = *(int*)indexp; for(a = aux_list; a; a = a->next) if (a->index == index) break; } return a; } Aux * new_aux(int id, Mapbook *m) { Aux *a; if (m == nil) { m = (Mapbook*) emallocz(sizeof(Mapbook)); m->index = mapbook_count++; } if(aux_list == nil) { aux_list = (Aux*) emallocz (sizeof(Aux)); aux_list->index = aux_count++; aux_list->id = id; aux_list->mapbook = m; return aux_list; } a = aux_list; while(a->next) a = a->next; a->next = (Aux*) emallocz (sizeof(Aux)); a->next->id = id; a->next->index = aux_count++; a->next->mapbook = m; return a->next; }; void free_aux(Aux *a) { a->mapbook = free_mapbook(a->mapbook); free(a); } int channel_to_id(char *channel) { if(strcmp("red", channel) == 0) return id_red; if(strcmp("green", channel) == 0) return id_green; if(strcmp("blue", channel) == 0) return id_blue; if(strcmp("cyan", channel) == 0) return id_cyan; if(strcmp("magenta", channel) == 0) return id_magenta; if(strcmp("yellow", channel) == 0) return id_yellow; if(strcmp("black", channel) == 0) return id_black; if(strcmp("hue", channel) == 0) return id_hue; if(strcmp("saturation", channel) == 0) return id_saturation; if(strcmp("lightness", channel) == 0) return id_lightness; if(strcmp("select", channel) == 0) return id_select; if(strcmp("alpha", channel) == 0) return id_alpha; return 0; } char * process_ctl_message(Aux *aux, Req *r) { int t; char *tokens[4]; int id; t = getfields(r->ifcall.data, tokens, 4, 1, " \t"); switch(t) { case 3: if(strcmp("import", tokens[0]) == 0) { *(strchr(tokens[2], '\n')) = 0; if(strcmp("ppm", tokens[1]) == 0) return import_ppm(aux, tokens[2]); } case 4 : if (strcmp("convolute", tokens[0]) == 0) { id = channel_to_id(tokens[1]); if(id) { *(strchr(tokens[3], '\n')) = 0; return convolute(aux, id, tokens[2], tokens[3]); } else { fprint(2, "Invalid channel name\n"); } } break; } return nil; } void fswrite(Req *r) { Aux *aux ; Bitmap *target; char *errstr = nil; char *txt; vlong dataend; aux = get_aux(r->fid->file->aux); if(aux== nil) { respond(nil, "not found"); return; } if(aux->id & 0xFF00) { // it's a channel target = get_or_create_bitmap(aux->mapbook, aux->id); dataend = aux->mapbook->width * aux->mapbook->height; if ((r->ifcall.offset + r->ifcall.count) > dataend) { respond(r, "too much data"); return; } memcpy(&target->data[r->ifcall.offset], r->ifcall.data, r->ifcall.count); r->ofcall.count = r->ifcall.count; respond(r, nil); return; } switch(aux->id) { case id_new : if (r->ifcall.count > 0) { txt = (char*)emallocz(r->ifcall.count+1); memcpy(txt, r->ifcall.data, r->ifcall.count); txt[strcspn(txt, "\n/\0 ")] = 0; if(create_new_image_folder(txt)) r->ofcall.count = r->ifcall.count; else errstr = smprint("create failed - file existed"); } break; case id_width : errstr = set_mapbook_width(aux->mapbook, atoi(r->ifcall.data)); break; case id_height : errstr = set_mapbook_height(aux->mapbook, atoi(r->ifcall.data)); break; case id_ctrl : errstr = process_ctl_message(aux, r); break; } respond(r, errstr); free(errstr); } void fill_ofcall_with_data(Fcall *ifcall, Fcall *ofcall, int datasize, char *data) { if (ifcall->offset < datasize) { if((ifcall->offset + ifcall->count) < datasize) { ofcall->data = data + ifcall->offset; ofcall->count = ifcall->count; } else { ofcall->data = data + ifcall->offset; ofcall->count = datasize - ifcall->offset; } } else { ofcall->data = nil; ofcall->count = 0; } } void fill_ofcall_with_bitmap(Fcall *ifcall, Fcall *ofcall, Mapbook *m, int id) { Bitmap *b; long pixels; if(b = get_bitmap(m, id)) { pixels = m->width * m->height; fill_ofcall_with_data(ifcall, ofcall, pixels, (char*) b->data); } else { ofcall->data = nil; ofcall->count = 0; } } char * ppm_header(Mapbook *m) { return smprint("P6 %06d %06d 255\n", m->width, m->height); } long ppm_size(char *header, Mapbook *m) { return strlen(header) + 3 * m->width * m->height; } char * fill_ofcall_with_ppm(Fcall *ifcall, Fcall *ofcall, Mapbook *m) { char *header; int header_size; long ppmsize, limit, req_length, start, pixel, end_pixel; char *insert_point; Bitmap *r, *g, *b; ofcall->data = nil; ofcall->count = 0; if(!m) return ofcall->data; header = ppm_header(m); header_size = strlen(header); ppmsize = ppm_size(header, m); if(ifcall->offset < ppmsize) { r = get_bitmap(m, id_red); g = get_bitmap(m, id_green); b = get_bitmap(m, id_blue); req_length = ifcall->offset + ifcall->count; limit = (req_length < ppmsize) ? req_length : ppmsize; req_length = limit - ifcall->offset; insert_point = ofcall->data = (char*) emallocz(req_length); start = ifcall->offset; if(start < header_size) { ofcall->count = header_size - start; if (ofcall->count > ifcall->count) ofcall->count = ifcall->count; memcpy(insert_point, &header[start], ofcall->count); insert_point = &ofcall->data[ofcall->count]; } else ofcall->count = 0; if(ofcall->count == ifcall->count) return ofcall->data; req_length -= ofcall->count; start = ifcall->offset + ofcall->count - header_size; pixel = start / 3; /* reads always finish on a pixel boundary so that the next read starts at a pixel boundary though I have no proof that it *always* works this switch was supposed deal with the boundaries but it was always unused so I commented it out switch(start % 3) { case 1 : insert_point[0] = r->data[pixel-1]; insert_point = &insert_point[1]; ofcall->count++; req_length--; if (req_length == 0) return ofcall->data; case 2: insert_point[0] = b->data[pixel-1]; insert_point = &insert_point[1]; ofcall->count++; req_length--; if (req_length == 0) return ofcall->data; } */ end_pixel = pixel + req_length / 3; for(; pixel < end_pixel; pixel++) { insert_point[0] = r->data[pixel]; ofcall->count++; req_length--; if (req_length == 0) return ofcall->data; insert_point[1] = g->data[pixel]; ofcall->count++; req_length--; if (req_length == 0) return ofcall->data; insert_point[2] = b->data[pixel]; ofcall->count++; req_length--; if (req_length == 0) return ofcall->data; insert_point = &insert_point[3]; } // reads always finish on a pixel boundary so that the next read starts at a pixel boundary // similarly there was another switch here, it was wrong so I deleted it } return ofcall->data; } void fsread(Req *r) { Aux *aux; char *data=nil; aux = get_aux(r->fid->file->aux); if(!aux) { respond(r, "not found"); return; } switch(aux->id){ case id_width : data = smprint("%d", aux->mapbook->width); readstr(r, data); break; case id_height : data = smprint("%d", aux->mapbook->height); readstr(r, data); break; case id_ppm : data = fill_ofcall_with_ppm(&r->ifcall, &r->ofcall, aux->mapbook); break; default : if(aux->id & 0xFF00) // it's a channel fill_ofcall_with_bitmap(&r->ifcall, &r->ofcall, aux->mapbook, aux->id); } respond(r, nil); free(data); } void fsend (Srv *) { Aux *aux, *next; for(aux = aux_list; aux; aux = next) { next = aux->next; free_aux(aux); } aux_list = nil; } void fstati(Req *r) { Aux *a = get_aux(r->fid->file->aux); char *data; if(a) switch(a->id) { case id_width : data = smprint("%d", a->mapbook->width); r->d.length = strlen(data); free(data); break; case id_height : data = smprint("%d", a->mapbook->height); r->d.length = strlen(data); free(data); break; case id_ppm : data = ppm_header(a->mapbook); r->d.length = ppm_size(data, a->mapbook); free(data); break; default : if(a->id & 0xFF00) { // it's a channel Mapbook *m = (Mapbook*) (a->mapbook); if(m) { if(get_bitmap(m, a->id)) { r->d.length = m->width * m->height; } } } break; } respond(r, nil); } Srv fs = { .read= fsread, .write= fswrite, .end= fsend, .stat= fstati, }; static void usage(void) { fprint(2, "usage: imgfs [-n mtpt] \n"); exits("usage"); } void main(int argc, char **argv) { char *mtpt; mtpt = "/n/imgfs"; ARGBEGIN{ case 'n': mtpt = ARGF(); break; }ARGEND; if(argc != 0) usage(); tree = fs.tree = alloctree(getuser(), getuser(), DMDIR|0555, nil); create_new_file(tree->root, "new", 0666, id_new, nil); images_folder = create_new_file(tree->root, "images", DMDIR|0777, id_images_folder, nil); postmountsrv(&fs, nil, mtpt, MREPL); exits(nil); } /* Put mk install imgfs/imgfs cd /n/imgfs echo arab > new cd images/arab imgfs/import_ppm /usr/maht/imgfs/arabian.ppm ls -l * wc ppm */