// // file name: client.C // // written by Ee-Chien Chang. // In USER::USER_DECISION(), modified by Ting-jen Yen // #define COMPRESS_METHOD 2 #include #include #include #include #include "sparse_mask.h" // for class item #include "sparse_2.h" #include "tcpstream.h" #include "block_item.h" #include "queue.h" #include "GLOBAL_VARIABLE.h" block_item::~block_item() { if (next!=0) { delete next; } } class user_request { public: user_request () { blocklist=0; } ~user_request () { if (!blocklist) {delete blocklist;}} int request_type; int compress_type; int id; block_item * blocklist; }; class image_descriptor { public: int width, height; char *description; }; //------------- routine in subloop.c ---------------------// int read_ihaar_fillin_data ( tcp_Stream *, block_item * ); void read_header_info ( tcp_Stream * netstream ) { // received headser information. netstream->read_int ( &HEADER.IMAGE_WIDTH ); netstream->read_int ( &HEADER.IMAGE_HEIGHT ); netstream->read_int ( &HEADER.BYTE_PER_PIXEL ); netstream->read_int ( &HEADER.NOS_LEVEL ); int w = HEADER.IMAGE_WIDTH ; int h = HEADER.IMAGE_HEIGHT; for (int i=0; i< HEADER.NOS_LEVEL; i++) { if (w%2) w++; w = w/2; if (h%2) h++; h = h/2; } HEADER.LOWEST_RESOLUTION_WIDTH = w; HEADER.LOWEST_RESOLUTION_HEIGHT= h; } void initialise_shared_data () { // mask_tree T.reInit ( HEADER.NOS_LEVEL, HEADER.IMAGE_WIDTH, HEADER.IMAGE_HEIGHT ); // coeff_hier C.reInit ( HEADER.NOS_LEVEL, HEADER.IMAGE_WIDTH, HEADER.IMAGE_HEIGHT, UNIT_SIZE, HEADER.BYTE_PER_PIXEL ); } void send_request_new ( tcp_Stream * netstream, int type_of_compression, int id ) { netstream -> COMPRESSION_TYPE = type_of_compression; netstream -> write_int ( VIEW_NEW_IMAGE ); netstream -> write_int ( 1 ); // version number netstream -> write_int ( id ); netstream -> write_int ( netstream->COMPRESSION_TYPE ); } void read_highest_level ( tcp_Stream * netstream ) { int smallest_image = C[ C.nos_level() ] . get_non_padding_width() * C[ C.nos_level() ] . get_non_padding_height()* HEADER.BYTE_PER_PIXEL; unsigned char *ttmp = new unsigned char [ smallest_image ]; netstream->read_byte ( ttmp, (unsigned long)smallest_image ); C.fillin_average ( ttmp ); delete [] ttmp; } // The class "USER" is the method that the network thread // is using to determine user request. In this program, // I just have it get a request from the queue the display // thread keeps putting it. class USER { public: USER () { l = 4; sr = 0; er = 0; sc = 0; ec = 0; } user_request * USER_DECISION (); int first_time; int l; int sr; int er; int sc; int ec; //------- //------- the following value is indentical to the value defined in //------- the class tcpstream. //------- If the value is to be changed, the value in class tcpstream //------- M U S T be modified accordingly //------- const static int COMPRESS_NON = 0; const static int COMPRESS_LZW = 1; const static int COMPRESS_GZ = 2; }; user_request * USER::USER_DECISION () { user_request * tmp = new user_request(); Queue_item *Q_item; Q_item = Q.dequeue(); if (Q_item == NULL) { tmp -> request_type = NO_REQUEST; } else if (Q_item->request_type == VIEW_NEW_IMAGE ) { tmp -> request_type = VIEW_NEW_IMAGE; tmp -> compress_type= COMPRESS_METHOD; tmp -> id = Q_item -> level; tmp -> blocklist = new block_item ( 1,40,80,40,80,0); } else if ( Q_item->request_type == GET_MORE_DATA ) { int t_r; int t_c; tmp -> request_type = GET_MORE_DATA; l = Q_item->level; sr = Q_item-> st_row; t_r = Q_item -> en_row; sc = Q_item-> st_col; t_c = Q_item -> en_col; tmp -> blocklist = new block_item ( l,sr,t_r,sc,t_c,0); } else if ( Q_item->request_type == GET_LIST ) { tmp->request_type = GET_LIST; } else { // cout << "QUIT NOW " << endl; tmp -> request_type = 3; } return tmp; } int send_request_list ( tcp_Stream *netstream) { netstream->write_int (GET_LIST); } int send_request ( tcp_Stream *netstream, block_item *req) { for ( block_item * curr_req = req; curr_req != 0; curr_req = curr_req -> next ) { netstream -> write_int ( GET_MORE_DATA ); netstream -> write_int ( curr_req->level ); netstream -> write_int ( curr_req->st_row); netstream -> write_int ( curr_req->en_row); netstream -> write_int ( curr_req->st_col); netstream -> write_int ( curr_req->en_col); } } int read_image_db(tcp_Stream *netstream, image_descriptor *&db) { char buffer[1024]; int count; netstream -> read_int(& count); db = new image_descriptor[count]; int back_compress = netstream->COMPRESSION_TYPE; netstream->COMPRESSION_TYPE = netstream->COMPRESS_NON; for (int i = 0 ; i < count ; i ++) { int len; netstream -> read_int(&len); netstream -> read_byte((unsigned char *)buffer, (long unsigned) len); db[i].description = new char[strlen(buffer) + 1]; strcpy(db[i].description, buffer); netstream -> read_int(&db[i].width); netstream -> read_int(&db[i].height); } netstream->COMPRESSION_TYPE = back_compress; return count; } int make_selection(image_descriptor *db, int size) { int result; do { cout << "The server serves the following images right now: "<< endl; for (int i = 0; i < size; i ++) cout << " [" << i + 1 << "] " << db[i].description << " (" << db[i].width << "x" << db[i].height << ")" << endl; cout << endl << "Please select from (1-" << size << "):" << endl; cin >> result; result --; if (result < 0 || result >= size) cout << "Invalid input. Please try again." << endl; } while (result < 0 || result >= size); return result; } //------------------------------------------------------- // all usage of semaphore only appears in // 1) the following main program // 2) read_ihaar_fillin_data // 3) netc.c //------------------------------------------------------- void client_network ( tcp_Stream * netstream ) { //------------------ n e t w o r k i n i t i a l i z a t i o n int quit_now = 0; int first_time =1; int in_network = 0; int read_ahead = 0; user_request *choice[5]; USER * user = new USER (); while ( ! quit_now ) { //------------ c h e c k w h a t t h e u s e r w a n t // user_request * choice = user -> USER_DECISION (); while (Q.length() <= 0 && in_network > 0) { int t=read_ihaar_fillin_data ( netstream, choice[0] -> blocklist ); // in file subloop.c delete choice[0]; in_network --; for (int i = 0; i < in_network + read_ahead; i ++) { choice[i] = choice[i+1]; } } if (!read_ahead) choice[in_network] = user -> USER_DECISION (); read_ahead = 0; if (choice[in_network] -> request_type == VIEW_NEW_IMAGE) { send_request_new ( netstream, choice[in_network] -> compress_type, choice[in_network] -> id); if (!first_time) { sem_wait ( &DATA_READY ); } read_header_info ( netstream ); initialise_shared_data (); read_highest_level ( netstream ); //------------- tell the display module i'm already done. sem_post ( &DATA_READY ); first_time =0; delete choice[in_network]; //----------------------------------------- } else if (choice[in_network] -> request_type == GET_LIST ) { image_descriptor *db; send_request_list ( netstream); int size = read_image_db(netstream, db); int selected_id = make_selection(db, size); Q.enqueue(selected_id); } else if (choice[in_network] -> request_type == GET_MORE_DATA ) { while (in_network < 2 && Q.length() > 0) { send_request ( netstream, choice[in_network] -> blocklist ); in_network ++; choice[in_network] = user -> USER_DECISION (); if (choice[in_network]-> request_type != GET_MORE_DATA) { read_ahead = 1; break; } } if (!read_ahead) { send_request( netstream, choice[in_network] -> blocklist ); in_network ++; } int t=read_ihaar_fillin_data ( netstream, choice[0] -> blocklist ); // in file subloop.c delete choice[0]; in_network --; for (int i = 0; i < in_network+read_ahead; i ++) { choice[i] = choice[i+1]; } } else if (choice[in_network] -> request_type == CLOSE_CONNECTION) { cout << "Quit ...." << endl; quit_now = 1; netstream -> write_int ( CLOSE_CONNECTION); delete choice[in_network]; } sched_yield(); } }