int DEFAULT_CC lib_userChannel_server_send_to_channel(struct xrdp_mod* mod, int channel_id, char* data, int data_len, int total_data_len, int flags) { if (u) { update* up = g_malloc(sizeof(update), 1); up->order_type = send_to_channel; up->channel_id = channel_id; up->data = g_malloc(data_len, 0); g_memcpy(up->data, data, data_len); up->data_len = data_len; up->total_data_len = total_data_len; up->flags = flags; update_add(up); } return 0; }
/* added the pointer to the cache and send it to client, it also sets the client if it finds it returns the index in the cache does not take ownership of pointer_item */ int APP_CC xrdp_cache_add_pointer(struct xrdp_cache *self, struct xrdp_pointer_item *pointer_item) { int i; int oldest; int index; if (self == 0) { return 0; } self->pointer_stamp++; /* look for match */ for (i = 2; i < self->pointer_cache_entries; i++) { if (self->pointer_items[i].x == pointer_item->x && self->pointer_items[i].y == pointer_item->y && g_memcmp(self->pointer_items[i].data, pointer_item->data, 32 * 32 * 4) == 0 && g_memcmp(self->pointer_items[i].mask, pointer_item->mask, 32 * 32 / 8) == 0 && self->pointer_items[i].bpp == pointer_item->bpp) { self->pointer_items[i].stamp = self->pointer_stamp; xrdp_wm_set_pointer(self->wm, i); self->wm->current_pointer = i; DEBUG(("found pointer at %d", i)); return i; } } /* look for oldest */ index = 2; oldest = 0x7fffffff; for (i = 2; i < self->pointer_cache_entries; i++) { if (self->pointer_items[i].stamp < oldest) { oldest = self->pointer_items[i].stamp; index = i; } } self->pointer_items[index].x = pointer_item->x; self->pointer_items[index].y = pointer_item->y; g_memcpy(self->pointer_items[index].data, pointer_item->data, 32 * 32 * 4); g_memcpy(self->pointer_items[index].mask, pointer_item->mask, 32 * 32 / 8); self->pointer_items[index].stamp = self->pointer_stamp; self->pointer_items[index].bpp = pointer_item->bpp; xrdp_wm_send_pointer(self->wm, index, self->pointer_items[index].data, self->pointer_items[index].mask, self->pointer_items[index].x, self->pointer_items[index].y, self->pointer_items[index].bpp); self->wm->current_pointer = index; DEBUG(("adding pointer at %d", index)); return index; }
int APP_CC xrdp_cache_add_char(struct xrdp_cache *self, struct xrdp_font_char *font_item) { int i; int j; int oldest; int f; int c; int datasize; struct xrdp_font_char *fi; self->char_stamp++; /* look for match */ for (i = 7; i < 12; i++) { for (j = 0; j < 250; j++) { if (xrdp_font_item_compare(&self->char_items[i][j].font_item, font_item)) { self->char_items[i][j].stamp = self->char_stamp; DEBUG(("found font at %d %d", i, j)); return MAKELONG(j, i); } } } /* look for oldest */ f = 0; c = 0; oldest = 0x7fffffff; for (i = 7; i < 12; i++) { for (j = 0; j < 250; j++) { if (self->char_items[i][j].stamp < oldest) { oldest = self->char_items[i][j].stamp; f = i; c = j; } } } DEBUG(("adding char at %d %d", f, c)); /* set, send char and return */ fi = &self->char_items[f][c].font_item; g_free(fi->data); datasize = FONT_DATASIZE(font_item); fi->data = (char *)g_malloc(datasize, 1); g_memcpy(fi->data, font_item->data, datasize); fi->offset = font_item->offset; fi->baseline = font_item->baseline; fi->width = font_item->width; fi->height = font_item->height; self->char_items[f][c].stamp = self->char_stamp; libxrdp_orders_send_font(self->session, fi, f, c); return MAKELONG(c, f); }
static int APP_CC xrdp_caps_process_order(struct xrdp_rdp *self, struct stream *s, int len) { int i; char order_caps[32]; int ex_flags; int cap_flags; DEBUG(("order capabilities")); if (len < 20 + 2 + 2 + 2 + 2 + 2 + 2 + 32 + 2 + 2 + 4 + 4 + 4 + 4) { g_writeln("xrdp_caps_process_order: error"); return 1; } in_uint8s(s, 20); /* Terminal desc, pad */ in_uint8s(s, 2); /* Cache X granularity */ in_uint8s(s, 2); /* Cache Y granularity */ in_uint8s(s, 2); /* Pad */ in_uint8s(s, 2); /* Max order level */ in_uint8s(s, 2); /* Number of fonts */ in_uint16_le(s, cap_flags); /* Capability flags */ in_uint8a(s, order_caps, 32); /* Orders supported */ g_memcpy(self->client_info.orders, order_caps, 32); DEBUG(("dest blt-0 %d", order_caps[0])); DEBUG(("pat blt-1 %d", order_caps[1])); DEBUG(("screen blt-2 %d", order_caps[2])); DEBUG(("memblt-3-13 %d %d", order_caps[3], order_caps[13])); DEBUG(("triblt-4-14 %d %d", order_caps[4], order_caps[14])); DEBUG(("line-8 %d", order_caps[8])); DEBUG(("line-9 %d", order_caps[9])); DEBUG(("rect-10 %d", order_caps[10])); DEBUG(("desksave-11 %d", order_caps[11])); DEBUG(("polygon-20 %d", order_caps[20])); DEBUG(("polygon2-21 %d", order_caps[21])); DEBUG(("polyline-22 %d", order_caps[22])); DEBUG(("ellipse-25 %d", order_caps[25])); DEBUG(("ellipse2-26 %d", order_caps[26])); DEBUG(("text2-27 %d", order_caps[27])); DEBUG(("order_caps dump")); #if defined(XRDP_DEBUG) g_hexdump(order_caps, 32); #endif in_uint8s(s, 2); /* Text capability flags */ /* read extended order support flags */ in_uint16_le(s, ex_flags); /* Ex flags */ if (cap_flags & 0x80) /* ORDER_FLAGS_EXTRA_SUPPORT */ { self->client_info.order_flags_ex = ex_flags; if (ex_flags & XR_ORDERFLAGS_EX_CACHE_BITMAP_REV3_SUPPORT) { g_writeln("xrdp_caps_process_order: bitmap cache v3 supported"); self->client_info.bitmap_cache_version |= 4; } } in_uint8s(s, 4); /* Pad */ in_uint32_le(s, i); /* desktop cache size, usually 0x38400 */ self->client_info.desktop_cache = i; DEBUG(("desktop cache size %d", i)); in_uint8s(s, 4); /* Unknown */ in_uint8s(s, 4); /* Unknown */ /* check if libpainter should be used for drawing, instead of orders */ if (!(order_caps[TS_NEG_DSTBLT_INDEX] && order_caps[TS_NEG_PATBLT_INDEX] && order_caps[TS_NEG_SCRBLT_INDEX] && order_caps[TS_NEG_MEMBLT_INDEX])) { g_writeln("xrdp_caps_process_order: not enough orders supported by client, using painter."); self->client_info.no_orders_supported = 1; } return 0; }
static int APP_CC xrdp_caps_process_codecs(struct xrdp_rdp *self, struct stream *s, int len) { int codec_id; int codec_count; int index; int codec_properties_length; int i1; char *codec_guid; char *next_guid; if (len < 1) { g_writeln("xrdp_caps_process_codecs: error"); return 1; } in_uint8(s, codec_count); len--; for (index = 0; index < codec_count; index++) { codec_guid = s->p; if (len < 16 + 1 + 2) { g_writeln("xrdp_caps_process_codecs: error"); return 1; } in_uint8s(s, 16); in_uint8(s, codec_id); in_uint16_le(s, codec_properties_length); len -= 16 + 1 + 2; if (len < codec_properties_length) { g_writeln("xrdp_caps_process_codecs: error"); return 1; } len -= codec_properties_length; next_guid = s->p + codec_properties_length; if (g_memcmp(codec_guid, XR_CODEC_GUID_NSCODEC, 16) == 0) { g_writeln("xrdp_caps_process_codecs: nscodec, codec id %d, properties len %d", codec_id, codec_properties_length); self->client_info.ns_codec_id = codec_id; i1 = MIN(64, codec_properties_length); g_memcpy(self->client_info.ns_prop, s->p, i1); self->client_info.ns_prop_len = i1; } else if (g_memcmp(codec_guid, XR_CODEC_GUID_REMOTEFX, 16) == 0) { g_writeln("xrdp_caps_process_codecs: RemoteFX, codec id %d, properties len %d", codec_id, codec_properties_length); self->client_info.rfx_codec_id = codec_id; i1 = MIN(64, codec_properties_length); g_memcpy(self->client_info.rfx_prop, s->p, i1); self->client_info.rfx_prop_len = i1; } else if (g_memcmp(codec_guid, XR_CODEC_GUID_JPEG, 16) == 0) { g_writeln("xrdp_caps_process_codecs: jpeg, codec id %d, properties len %d", codec_id, codec_properties_length); self->client_info.jpeg_codec_id = codec_id; i1 = MIN(64, codec_properties_length); g_memcpy(self->client_info.jpeg_prop, s->p, i1); self->client_info.jpeg_prop_len = i1; /* make sure that requested quality is between 0 to 100 */ if (self->client_info.jpeg_prop[0] < 0 || self->client_info.jpeg_prop[0] > 100) { g_writeln(" Warning: the requested jpeg quality (%d) is invalid," " falling back to default", self->client_info.jpeg_prop[0]); self->client_info.jpeg_prop[0] = 75; /* use default */ } g_writeln(" jpeg quality set to %d", self->client_info.jpeg_prop[0]); } else if (g_memcmp(codec_guid, XR_CODEC_GUID_H264, 16) == 0) { g_writeln("xrdp_caps_process_codecs: h264, codec id %d, properties len %d", codec_id, codec_properties_length); self->client_info.h264_codec_id = codec_id; i1 = MIN(64, codec_properties_length); g_memcpy(self->client_info.h264_prop, s->p, i1); self->client_info.h264_prop_len = i1; } else { g_writeln("xrdp_caps_process_codecs: unknown codec id %d", codec_id); } s->p = next_guid; } return 0; }
static void cliprdr_get_clipboard(XEvent* e) { Atom type; unsigned long len, bytes_left, dummy; int format, result; unsigned char *data; log_message(l_config, LOG_LEVEL_DEBUG, "vchannel_cliprdr[cliprdr_get_clipboard]: " "New owner %i", e->xselection.requestor); XGetWindowProperty (e->xselection.display, e->xselection.requestor, e->xselection.property, 0, 0, False, AnyPropertyType, &type, &format, &len, &bytes_left, &data); // Check Format list if (type == XA_ATOM || format == 32) { result = XGetWindowProperty (e->xselection.display, e->xselection.requestor, e->xselection.property, 0, bytes_left, 0, XA_ATOM, &type, &format, &len, &dummy, &data); if (result == Success) { int i = 0; Atom atom; for (i = 0; i < len ; i++) { atom = ((Atom*)data)[i]; log_message(l_config, LOG_LEVEL_DEBUG, "vchannel_cliprdr[cliprdr_get_clipboard]: " "format : %s", XGetAtomName(display, atom)); if (clipboard_format_supported(&clipboard, atom)) { clipboard_add_current_clipboard_format(&clipboard, atom); } } if (clipboard_current_clipboard_size(&clipboard) > 0) { atom = clipboard_get_current_clipboard_format(&clipboard, 0); log_message(l_config, LOG_LEVEL_DEBUG, "vchannel_cliprdr[cliprdr_get_clipboard]: " "Request for format %s", XGetAtomName(display, atom)); XConvertSelection(display, clipboard_atom, atom, xrdp_clipboard, wclip, CurrentTime); XSync (e->xselectionclear.display, False); } return; } log_message(l_config, LOG_LEVEL_DEBUG, "vchannel_cliprdr[cliprdr_get_clipboard]: " "Failed to parse atom list"); return; } // DATA is There log_message(l_config, LOG_LEVEL_DEBUG, "vchannel_cliprdr[cliprdr_get_clipboard]: " "Data type : %s\n", XGetAtomName(e->xselection.display, e->xselection.property)); if (bytes_left > 0 && clipboard_format_supported(&clipboard, e->xselection.target)) { unsigned char* clipboard_data = NULL; int clipboard_size = 0; result = XGetWindowProperty(e->xselection.display, e->xselection.requestor, e->xselection.property, 0, bytes_left, 0, e->xselection.target, &type, &format, &len, &dummy, &data); if (result == Success) { log_message(l_config, LOG_LEVEL_DEBUG_PLUS, "vchannel_cliprdr[cliprdr_get_clipboard]: " "New data in clipboard: %s", data); int index = -1; index = clipboard_get_current_clipboard_format_index(&clipboard, e->xselection.target); // Don't forget the null terminated character clipboard_data = g_malloc(bytes_left + 1, 1); clipboard_size = bytes_left; g_memcpy(clipboard_data, data, bytes_left); log_message(l_config, LOG_LEVEL_DEBUG, "vchannel_cliprdr[cliprdr_get_clipboard]: " "clipboard %s[%i] updated with '%s'", XGetAtomName(display, e->xselection.target), index, data); clipboard_add_current_clipboard_data(&clipboard, clipboard_data, clipboard_size, e->xselection.target); if (index < (clipboard_current_clipboard_size(&clipboard) - 1)) { Atom format = clipboard_get_current_clipboard_format(&clipboard, index + 1); log_message(l_config, LOG_LEVEL_DEBUG, "vchannel_cliprdr[cliprdr_get_clipboard]: " "Request for format %s", XGetAtomName(display, format)); XConvertSelection(display, clipboard_atom, format, xrdp_clipboard, wclip, CurrentTime); XSync (e->xselectionclear.display, False); } else { XSetSelectionOwner(display, clipboard_atom, wclip, CurrentTime); XSync(display, False); // File content is not supported for now if ((! clipboard_current_clipboard_format_exist(&clipboard, format_file_gnome_atom)) && (! clipboard_current_clipboard_format_exist(&clipboard, format_file_text_uri_list_atom))) cliprdr_send_format_list(); } } else { log_message(l_config, LOG_LEVEL_DEBUG, "vchannel_cliprdr[cliprdr_get_clipboard]: " "Failed to get clipboard content"); } XFree (data); } }
void cliprdr_process_message(struct stream* packet, int length, int total_length) { log_message(l_config, LOG_LEVEL_DEBUG, "vchannel_cliprdr[process_message]: " "New message for clipchannel"); int msg_type; int msg_flags; int msg_size; struct stream* s; if(length != total_length) { log_message(l_config, LOG_LEVEL_DEBUG_PLUS, "vchannel_cliprdr[cliprdr_process_message]: " "Packet is fragmented"); if(is_fragmented_packet == 0) { log_message(l_config, LOG_LEVEL_DEBUG_PLUS, "vchannel_cliprdr[cliprdr_process_message]: " "Packet is fragmented : first part"); is_fragmented_packet = 1; fragment_size = length; make_stream(splitted_packet); init_stream(splitted_packet, total_length); g_memcpy(splitted_packet->p, packet->p, length); return; } else { g_memcpy(splitted_packet->p+fragment_size, packet->p, length); fragment_size += length; if (fragment_size == total_length) { log_message(l_config, LOG_LEVEL_DEBUG, "vchannel_cliprdr[cliprdr_process_message]: " "Packet is fragmented : last part"); s = splitted_packet; } else { log_message(l_config, LOG_LEVEL_DEBUG, "vchannel_cliprdr[cliprdr_process_message]: " "Packet is fragmented : next part"); return; } } } else { s = packet; } in_uint16_le(s, msg_type); log_message(l_config, LOG_LEVEL_DEBUG, "vchannel_cliprdr[process_message]: " "Message type : %04x", msg_type); in_uint16_le(s, msg_flags); log_message(l_config, LOG_LEVEL_DEBUG, "vchannel_cliprdr[process_message]: " "Message flags : %04x", msg_flags); in_uint32_le(s, msg_size); log_message(l_config, LOG_LEVEL_DEBUG, "vchannel_cliprdr[process_message]: " "Message size : %i", msg_size); switch (msg_type) { case CB_FORMAT_LIST : log_message(l_config, LOG_LEVEL_DEBUG, "vchannel_cliprdr[process_message]: " "Client format list announce"); cliprdr_process_format_list(s, msg_flags, msg_size); //cliprdr_send_format_list(); break; case CB_FORMAT_DATA_RESPONSE : log_message(l_config, LOG_LEVEL_DEBUG, "vchannel_cliprdr[process_message]: " "Client data request response"); cliprdr_process_data_request_response(s, msg_flags, msg_size); pthread_cond_signal(&reply_cond); break; case CB_FORMAT_LIST_RESPONSE : log_message(l_config, LOG_LEVEL_DEBUG, "vchannel_cliprdr[process_message]: " "Client format list response"); break; case CB_FORMAT_DATA_REQUEST : log_message(l_config, LOG_LEVEL_DEBUG, "vchannel_cliprdr[process_message]: " "Client data request"); cliprdr_process_data_request(s, msg_flags, msg_size); break; default: log_message(l_config, LOG_LEVEL_DEBUG, "vchannel_cliprdr[process_message]: " "Unknow message type : %i", msg_type); } if(is_fragmented_packet == 1) { is_fragmented_packet = 0; fragment_size = 0; free_stream(s); } }
static int clipboard_get_file(const char *file, int bytes) { int sindex; int pindex; int flags; char full_fn[256]; /* /etc/xrdp/xrdp.ini */ char filename[256]; /* xrdp.ini */ char pathname[256]; /* /etc/xrdp */ struct cb_file_info *cfi; /* x-special/gnome-copied-files */ if ((g_strncmp(file, "copy", 4) == 0) && (bytes == 4)) { return 0; } if ((g_strncmp(file, "cut", 3) == 0) && (bytes == 3)) { return 0; } sindex = 0; flags = CB_FILE_ATTRIBUTE_ARCHIVE; /* text/uri-list */ /* x-special/gnome-copied-files */ if (g_strncmp(file, "file://", 7) == 0) { sindex = 7; } pindex = bytes; while (pindex > sindex) { if (file[pindex] == '/') { break; } pindex--; } g_memset(pathname, 0, 256); g_memset(filename, 0, 256); g_memcpy(pathname, file + sindex, pindex - sindex); if (pathname[0] == 0) { pathname[0] = '/'; } g_memcpy(filename, file + pindex + 1, (bytes - 1) - pindex); /* this should replace %20 with space */ clipboard_check_file(pathname); clipboard_check_file(filename); g_snprintf(full_fn, 255, "%s/%s", pathname, filename); if (g_directory_exist(full_fn)) { log_error("clipboard_get_file: file [%s] is a directory, " "not supported", full_fn); flags |= CB_FILE_ATTRIBUTE_DIRECTORY; return 1; } if (!g_file_exist(full_fn)) { log_error("clipboard_get_file: file [%s] does not exist", full_fn); return 1; } else { cfi = (struct cb_file_info*)g_malloc(sizeof(struct cb_file_info), 1); list_add_item(g_files_list, (tintptr)cfi); g_strcpy(cfi->filename, filename); g_strcpy(cfi->pathname, pathname); cfi->size = g_file_get_size(full_fn); cfi->flags = flags; cfi->time = (g_time1() + CB_EPOCH_DIFF) * 10000000LL; log_debug("ok filename [%s] pathname [%s] size [%d]", cfi->filename, cfi->pathname, cfi->size); } return 0; }
int APP_CC dev_redir_data_in(struct stream* s, int chan_id, int chan_flags, int length, int total_length) { int component; int packetId; int result; struct stream* packet; if(length != total_length) { log_message(&log_conf, LOG_LEVEL_DEBUG, "rdpdr channel[dev_redir_data_in]: " "packet is fragmented"); if(is_fragmented_packet == 0) { log_message(&log_conf, LOG_LEVEL_DEBUG, "rdpdr channel[dev_redir_data_in]: " "packet is fragmented : first part"); is_fragmented_packet = 1; fragment_size = length; make_stream(splitted_packet); init_stream(splitted_packet, total_length); g_memcpy(splitted_packet->p,s->p, length ); log_hexdump(&log_conf, LOG_LEVEL_DEBUG, (unsigned char*)s->p, length); return 0; } else { g_memcpy(splitted_packet->p+fragment_size, s->p, length ); fragment_size += length; if (fragment_size == total_length ) { log_message(&log_conf, LOG_LEVEL_DEBUG, "rdpdr channel[dev_redir_data_in]: " "packet is fragmented : last part"); packet = splitted_packet; } else { log_message(&log_conf, LOG_LEVEL_DEBUG, "rdpdr channel[dev_redir_data_in]: " "packet is fragmented : next part"); return 0; } } } else { packet = s; } log_message(&log_conf, LOG_LEVEL_DEBUG, "rdpdr channel[dev_redir_data_in]: data received:"); log_hexdump(&log_conf, LOG_LEVEL_DEBUG, (unsigned char*)packet->p, total_length); in_uint16_le(packet, component); in_uint16_le(packet, packetId); log_message(&log_conf, LOG_LEVEL_DEBUG, "rdpdr channel[dev_redir_data_in]: component=0x%04x packetId=0x%04x", component, packetId); if ( component == RDPDR_CTYP_CORE ) { switch (packetId) { case PAKID_CORE_CLIENTID_CONFIRM : result = dev_redir_clientID_confirm(packet); break; case PAKID_CORE_CLIENT_NAME : result = dev_redir_client_name(packet); break; case PAKID_CORE_CLIENT_CAPABILITY: result = dev_redir_client_capability(packet); break; case PAKID_CORE_DEVICELIST_ANNOUNCE: result = dev_redir_devicelist_announce(packet); break; case PAKID_CORE_DEVICE_IOCOMPLETION: result = dev_redir_iocompletion(packet); break; default: log_message(&log_conf, LOG_LEVEL_WARNING, "rdpdr channel[dev_redir_data_in]: " "unknown message %02x",packetId); result = 1; } if(is_fragmented_packet == 1) { is_fragmented_packet = 0; fragment_size = 0; free_stream(packet); } } return result; }
/* * called when WTSVirtualChannelOpenEx is invoked in xrdpapi.c * ******************************************************************************/ int DEFAULT_CC my_api_trans_conn_in(struct trans *trans, struct trans *new_trans) { struct xrdp_api_data *ad; struct stream *s; int error; int index; char chan_pri; if ((trans == 0) || (trans != g_api_lis_trans) || (new_trans == 0)) { return 1; } LOGM((LOG_LEVEL_DEBUG, "my_api_trans_conn_in:")); LOG(10, ("my_api_trans_conn_in: got incoming")); s = trans_get_in_s(new_trans); s->end = s->data; error = trans_force_read(new_trans, 64); if (error != 0) { LOG(0, ("my_api_trans_conn_in: trans_force_read failed")); trans_delete(new_trans); } s->end = s->data; ad = (struct xrdp_api_data *) g_malloc(sizeof(struct xrdp_api_data), 1); g_memcpy(ad->header, s->data, 64); ad->flags = GGET_UINT32(ad->header, 16); ad->chan_id = -1; ad->dvc_chan_id = -1; if (ad->flags > 0) { /* opening a dynamic virtual channel */ if ((index = find_empty_slot_in_dvc_channels()) < 0) { /* exceeded MAX_DVC_CHANNELS */ LOG(0, ("my_api_trans_conn_in: MAX_DVC_CHANNELS reached; giving up!")) g_free(ad); trans_delete(new_trans); return 1; } g_dvc_channels[index] = ad; chan_pri = 4 - ad->flags; ad->dvc_chan_id = g_dvc_chan_id++; ad->is_connected = 0; ad->transp = new_trans; drdynvc_send_open_channel_request(chan_pri, ad->dvc_chan_id, ad->header); } else { /* opening a static virtual channel */ for (index = 0; index < g_num_chan_items; index++) { LOG(10, ("my_api_trans_conn_in: %s %s", ad->header, g_chan_items[index].name)); if (g_strcasecmp(ad->header, g_chan_items[index].name) == 0) { LOG(10, ("my_api_trans_conn_in: found it at %d", index)); ad->chan_id = g_chan_items[index].id; break; } } if (index == g_num_chan_items) { g_writeln("did not find SVC named %s", ad->header); } } new_trans->callback_data = ad; trans_delete(g_api_con_trans); g_api_con_trans = new_trans; g_api_con_trans->trans_data_in = my_api_trans_data_in; g_api_con_trans->header_size = 0; return 0; }
static int APP_CC compress_rdp_5(struct xrdp_mppc_enc *enc, tui8 *srcData, int len) { char *outputBuffer; /* points to enc->outputBuffer */ char *hptr_end; /* points to end of history data */ char *historyPointer; /* points to first byte of srcData in * historyBuffer */ char *hbuf_start; /* points to start of history buffer */ char *cptr1; char *cptr2; int opb_index; /* index into outputBuffer */ int bits_left; /* unused bits in current byte in outputBuffer */ tui32 copy_offset; /* pattern match starts here... */ tui32 lom; /* ...and matches this many bytes */ int last_crc_index; /* don't compute CRC beyond this index */ tui16 *hash_table; /* hash table for pattern matching */ tui32 i; tui32 j; tui32 k; tui32 x; tui8 data; tui16 data16; tui32 historyOffset; tui16 crc; tui32 ctr; tui32 saved_ctr; tui32 data_end; tui8 byte_val; crc = 0; opb_index = 0; bits_left = 8; copy_offset = 0; hash_table = enc->hash_table; hbuf_start = enc->historyBuffer; outputBuffer = enc->outputBuffer; g_memset(outputBuffer, 0, len); enc->flags = PACKET_COMPR_TYPE_64K; if (enc->first_pkt) { enc->first_pkt = 0; enc->flagsHold |= PACKET_AT_FRONT; } if ((enc->historyOffset + len) > enc->buf_len) { /* historyBuffer cannot hold srcData - rewind it */ enc->historyOffset = 0; enc->flagsHold |= PACKET_AT_FRONT; g_memset(hash_table, 0, enc->buf_len * 2); } /* point to next free byte in historyBuffer */ historyOffset = enc->historyOffset; /* add / append new data to historyBuffer */ g_memcpy(&(enc->historyBuffer[historyOffset]), srcData, len); /* point to start of data to be compressed */ historyPointer = &(enc->historyBuffer[historyOffset]); ctr = copy_offset = lom = 0; /* if we are at start of history buffer, do not attempt to compress */ /* first 2 bytes,because minimum LoM is 3 */ if (historyOffset == 0) { /* encode first two bytes are literals */ for (x = 0; x < 2; x++) { data = *(historyPointer + x); DLOG(("%.2x ", (tui8) data)); if (data & 0x80) { /* insert encoded literal */ insert_2_bits(0x02); data &= 0x7f; insert_7_bits(data); } else { /* insert literal */ insert_8_bits(data); } } /* store hash for first two entries in historyBuffer */ crc = CRC_INIT; byte_val = enc->historyBuffer[0]; CRC(crc, byte_val); byte_val = enc->historyBuffer[1]; CRC(crc, byte_val); byte_val = enc->historyBuffer[2]; CRC(crc, byte_val); hash_table[crc] = 0; crc = CRC_INIT; byte_val = enc->historyBuffer[1]; CRC(crc, byte_val); byte_val = enc->historyBuffer[2]; CRC(crc, byte_val); byte_val = enc->historyBuffer[3]; CRC(crc, byte_val); hash_table[crc] = 1; /* first two bytes have already been processed */ ctr = 2; } enc->historyOffset += len; /* point to last byte in new data */ hptr_end = &(enc->historyBuffer[enc->historyOffset - 1]); /* do not compute CRC beyond this */ last_crc_index = enc->historyOffset - 3; /* do not search for pattern match beyond this */ data_end = len - 2; /* start compressing data */ while (ctr < data_end) { cptr1 = historyPointer + ctr; crc = CRC_INIT; byte_val = *cptr1; CRC(crc, byte_val); byte_val = *(cptr1 + 1); CRC(crc, byte_val); byte_val = *(cptr1 + 2); CRC(crc, byte_val); /* cptr2 points to start of pattern match */ cptr2 = hbuf_start + hash_table[crc]; copy_offset = cptr1 - cptr2; /* save current entry */ hash_table[crc] = cptr1 - hbuf_start; /* double check that we have a pattern match */ if ((*cptr1 != *cptr2) || (*(cptr1 + 1) != *(cptr2 + 1)) || (*(cptr1 + 2) != *(cptr2 + 2))) { /* no match found; encode literal byte */ data = *cptr1; DLOG(("%.2x ", data)); if (data < 0x80) { /* literal byte < 0x80 */ insert_8_bits(data); } else { /* literal byte >= 0x80 */ insert_2_bits(0x02); data &= 0x7f; insert_7_bits(data); } ctr++; continue; } /* we have a match - compute Length of Match */ cptr1 += 3; cptr2 += 3; lom = 3; while ((cptr1 <= hptr_end) && (*(cptr1++) == *(cptr2++))) { lom++; } saved_ctr = ctr + lom; DLOG(("<%d: %ld,%d> ", (historyPointer + ctr) - hbuf_start, copy_offset, lom)); /* compute CRC for matching segment and store in hash table */ cptr1 = historyPointer + ctr; if (cptr1 + lom > hbuf_start + last_crc_index) { /* we have gone beyond last_crc_index - go back */ j = last_crc_index - (cptr1 - hbuf_start); } else { j = lom - 1; } ctr++; for (i = 0; i < j; i++) { cptr1 = historyPointer + ctr; /* compute CRC on triplet */ crc = CRC_INIT; byte_val = *(cptr1++); CRC(crc, byte_val); byte_val = *(cptr1++); CRC(crc, byte_val); byte_val = *(cptr1++); CRC(crc, byte_val); /* save current entry */ hash_table[crc] = (cptr1 - 3) - hbuf_start; /* point to next triplet */ ctr++; } ctr = saved_ctr; /* encode copy_offset and insert into output buffer */ if (copy_offset <= 63) /* (copy_offset >= 0) is always true */ { /* insert binary header */ data = 0x1f; insert_5_bits(data); /* insert 6 bits of copy_offset */ data = (char) (copy_offset & 0x3f); insert_6_bits(data); } else if ((copy_offset >= 64) && (copy_offset <= 319)) { /* insert binary header */ data = 0x1e; insert_5_bits(data); /* insert 8 bits of copy offset */ data = (char) (copy_offset - 64); insert_8_bits(data); } else if ((copy_offset >= 320) && (copy_offset <= 2367)) { /* insert binary header */ data = 0x0e; insert_4_bits(data); /* insert 11 bits of copy offset */ data16 = copy_offset - 320;; insert_11_bits(data16); } else { /* copy_offset is 2368+ */ /* insert binary header */ data = 0x06; insert_3_bits(data); /* insert 16 bits of copy offset */ data16 = copy_offset - 2368;; insert_16_bits(data16); } /* encode length of match and insert into output buffer */ if (lom == 3) { /* binary header is 'zero'; since outputBuffer is zero */ /* filled, all we have to do is update bits_left */ bits_left--; if (bits_left == 0) { opb_index++; bits_left = 8; } } else if ((lom >= 4) && (lom <= 7)) { /* insert binary header */ data = 0x02; insert_2_bits(data); /* insert lower 2 bits of LoM */ data = (char) (lom - 4); insert_2_bits(data); } else if ((lom >= 8) && (lom <= 15)) { /* insert binary header */ data = 0x06; insert_3_bits(data); /* insert lower 3 bits of LoM */ data = (char) (lom - 8); insert_3_bits(data); } else if ((lom >= 16) && (lom <= 31)) { /* insert binary header */ data = 0x0e; insert_4_bits(data); /* insert lower 4 bits of LoM */ data = (char) (lom - 16); insert_4_bits(data); } else if ((lom >= 32) && (lom <= 63)) { /* insert binary header */ data = 0x1e; insert_5_bits(data); /* insert lower 5 bits of LoM */ data = (char) (lom - 32); insert_5_bits(data); } else if ((lom >= 64) && (lom <= 127)) { /* insert binary header */ data = 0x3e; insert_6_bits(data); /* insert lower 6 bits of LoM */ data = (char) (lom - 64); insert_6_bits(data); } else if ((lom >= 128) && (lom <= 255)) { /* insert binary header */ data = 0x7e; insert_7_bits(data); /* insert lower 7 bits of LoM */ data = (char) (lom - 128); insert_7_bits(data); } else if ((lom >= 256) && (lom <= 511)) { /* insert binary header */ data = 0xfe; insert_8_bits(data); /* insert lower 8 bits of LoM */ data = (char) (lom - 256); insert_8_bits(data); } else if ((lom >= 512) && (lom <= 1023)) { /* insert binary header */ data16 = 0x1fe; insert_9_bits(data16); /* insert lower 9 bits of LoM */ data16 = lom - 512; insert_9_bits(data16); } else if ((lom >= 1024) && (lom <= 2047)) { /* insert binary header */ data16 = 0x3fe; insert_10_bits(data16); /* insert 10 lower bits of LoM */ data16 = lom - 1024; insert_10_bits(data16); } else if ((lom >= 2048) && (lom <= 4095)) { /* insert binary header */ data16 = 0x7fe; insert_11_bits(data16); /* insert 11 lower bits of LoM */ data16 = lom - 2048; insert_11_bits(data16); } else if ((lom >= 4096) && (lom <= 8191)) { /* insert binary header */ data16 = 0xffe; insert_12_bits(data16); /* insert 12 lower bits of LoM */ data16 = lom - 4096; insert_12_bits(data16); } else if ((lom >= 8192) && (lom <= 16383)) { /* insert binary header */ data16 = 0x1ffe; insert_13_bits(data16); /* insert 13 lower bits of LoM */ data16 = lom - 8192; insert_13_bits(data16); } else if ((lom >= 16384) && (lom <= 32767)) { /* insert binary header */ data16 = 0x3ffe; insert_14_bits(data16); /* insert 14 lower bits of LoM */ data16 = lom - 16384; insert_14_bits(data16); } else if ((lom >= 32768) && (lom <= 65535)) { /* insert binary header */ data16 = 0x7ffe; insert_15_bits(data16); /* insert 15 lower bits of LoM */ data16 = lom - 32768; insert_15_bits(data16); } } /* end while (ctr < data_end) */ /* add remaining data to the output */ while (len - ctr > 0) { data = srcData[ctr]; DLOG(("%.2x ", data)); if (data < 0x80) { /* literal byte < 0x80 */ insert_8_bits(data); } else { /* literal byte >= 0x80 */ insert_2_bits(0x02); data &= 0x7f; insert_7_bits(data); } ctr++; } /* if bits_left == 8, opb_index has already been incremented */ if ((bits_left == 8) && (opb_index > len)) { /* compressed data longer than uncompressed data */ /* give up */ enc->historyOffset = 0; g_memset(hash_table, 0, enc->buf_len * 2); enc->flagsHold |= PACKET_FLUSHED; enc->first_pkt = 1; return 1; } else if (opb_index + 1 > len) { /* compressed data longer than uncompressed data */ /* give up */ enc->historyOffset = 0; g_memset(hash_table, 0, enc->buf_len * 2); enc->flagsHold |= PACKET_FLUSHED; enc->first_pkt = 1; return 1; } /* if bits_left != 8, increment opb_index, which is zero indexed */ if (bits_left != 8) { opb_index++; } if (opb_index > len) { /* give up */ enc->historyOffset = 0; g_memset(hash_table, 0, enc->buf_len * 2); enc->flagsHold |= PACKET_FLUSHED; enc->first_pkt = 1; return 1; } enc->flags |= PACKET_COMPRESSED; enc->bytes_in_opb = opb_index; enc->flags |= enc->flagsHold; enc->flagsHold = 0; DLOG(("\n")); return 1; }