/* Process an update PDU */ static void process_update_pdu(STREAM s) { uint16 update_type, count; in_uint16_le(s, update_type); // TODO ui_begin_update(); __android_log_print(ANDROID_LOG_INFO, "JNIMsg", "process_update_pdu STREAM:%p", s); switch (update_type) { case RDP_UPDATE_ORDERS: in_uint8s(s, 2); /* pad */ in_uint16_le(s, count); in_uint8s(s, 2); /* pad */ process_orders(s, count); break; case RDP_UPDATE_BITMAP: process_bitmap_updates(s); break; case RDP_UPDATE_PALETTE: process_palette(s); break; case RDP_UPDATE_SYNCHRONIZE: break; default: unimpl("update %d\n", update_type); } // TODO ui_end_update(); }
/* Process a licence packet */ void licence_process(RDPCLIENT * This, STREAM s) { uint8 tag; in_uint8(s, tag); in_uint8s(s, 3); /* version, length */ switch (tag) { case LICENCE_TAG_DEMAND: licence_process_demand(This, s); break; case LICENCE_TAG_AUTHREQ: licence_process_authreq(This, s); break; case LICENCE_TAG_ISSUE: licence_process_issue(This, s); break; case LICENCE_TAG_REISSUE: case LICENCE_TAG_RESULT: break; default: unimpl("licence tag 0x%x\n", tag); } }
/* Process a licence packet */ void licence_process(RDConnectionRef conn, RDStreamRef s) { uint8 tag; in_uint8(s, tag); in_uint8s(s, 3); /* version, length */ switch (tag) { case LICENCE_TAG_DEMAND: licence_process_demand(conn, s); break; case LICENCE_TAG_AUTHREQ: licence_process_authreq(conn, s); break; case LICENCE_TAG_ISSUE: licence_process_issue(conn, s); break; case LICENCE_TAG_REISSUE: case LICENCE_TAG_RESULT: break; default: unimpl("licence tag 0x%x\n", tag); } }
/* Process a licence packet */ void licence_process(STREAM s) { uint16 tag; in_uint16_le(s, tag); in_uint8s(s, 2); /* length */ switch (tag) { case LICENCE_TAG_DEMAND: licence_process_demand(s); break; case LICENCE_TAG_AUTHREQ: licence_process_authreq(s); break; case LICENCE_TAG_ISSUE: licence_process_issue(s); break; case LICENCE_TAG_REISSUE: break; case LICENCE_TAG_RESULT: break; default: unimpl("licence tag 0x%x\n", tag); } }
/* Process a pointer PDU */ static void process_pointer_pdu(STREAM s) { uint16 message_type; uint16 x, y; in_uint16_le(s, message_type); in_uint8s(s, 2); /* pad */ switch (message_type) { case RDP_POINTER_MOVE: in_uint16_le(s, x); in_uint16_le(s, y); if (s_check(s)) ui_move_pointer(x, y); break; case RDP_POINTER_COLOR: process_colour_pointer_pdu(s); break; case RDP_POINTER_CACHED: process_cached_pointer_pdu(s); break; case RDP_POINTER_SYSTEM: process_system_pointer_pdu(s); break; default: unimpl("Pointer message 0x%x\n", message_type); } }
/* Process an update PDU */ static void process_update_pdu(STREAM s) { uint16 update_type, count; in_uint16_le(s, update_type); ui_begin_update(); switch (update_type) { case RDP_UPDATE_ORDERS: in_uint8s(s, 2); /* pad */ in_uint16_le(s, count); in_uint8s(s, 2); /* pad */ process_orders(s, count); break; case RDP_UPDATE_BITMAP: process_bitmap_updates(s); break; case RDP_UPDATE_PALETTE: process_palette(s); break; case RDP_UPDATE_SYNCHRONIZE: break; default: unimpl("update %d\n", update_type); } ui_end_update(); }
static void cliprdr_process(STREAM s) { uint16 type, status; uint32 length, format; uint8 *data; in_uint16_le(s, type); in_uint16_le(s, status); in_uint32_le(s, length); data = s->p; DEBUG_CLIPBOARD(("CLIPRDR recv: type=%d, status=%d, length=%d\n", type, status, length)); if (status == CLIPRDR_ERROR) { switch (type) { case CLIPRDR_FORMAT_ACK: /* FIXME: We seem to get this when we send an announce while the server is still processing a paste. Try sending another announce. */ cliprdr_send_native_format_announce(last_formats, last_formats_length); break; case CLIPRDR_DATA_RESPONSE: ui_clip_request_failed(); break; default: DEBUG_CLIPBOARD(("CLIPRDR error (type=%d)\n", type)); } return; } switch (type) { case CLIPRDR_CONNECT: ui_clip_sync(); break; case CLIPRDR_FORMAT_ANNOUNCE: ui_clip_format_announce(data, length); cliprdr_send_packet(CLIPRDR_FORMAT_ACK, CLIPRDR_RESPONSE, NULL, 0); return; case CLIPRDR_FORMAT_ACK: break; case CLIPRDR_DATA_REQUEST: in_uint32_le(s, format); ui_clip_request_data(format); break; case CLIPRDR_DATA_RESPONSE: ui_clip_handle_data(data, length); break; case 7: /* TODO: W2K3 SP1 sends this on connect with a value of 1 */ break; default: unimpl("CLIPRDR packet type %d\n", type); } }
static void rdpdr_process(RDPCLIENT * This, STREAM s) { uint32 handle; uint8 *magic; #if WITH_DEBUG_RDP5 printf("--- rdpdr_process ---\n"); hexdump(s->p, s->end - s->p); #endif in_uint8p(s, magic, 4); if ((magic[0] == 'r') && (magic[1] == 'D')) { if ((magic[2] == 'R') && (magic[3] == 'I')) { rdpdr_process_irp(This, s); return; } if ((magic[2] == 'n') && (magic[3] == 'I')) { rdpdr_send_connect(This); rdpdr_send_name(This); return; } if ((magic[2] == 'C') && (magic[3] == 'C')) { /* connect from server */ rdpdr_send_clientcapabilty(This); rdpdr_send_available(This); return; } if ((magic[2] == 'r') && (magic[3] == 'd')) { /* connect to a specific resource */ in_uint32(s, handle); #if WITH_DEBUG_RDP5 DEBUG(("RDPDR: Server connected to resource %d\n", handle)); #endif return; } if ((magic[2] == 'P') && (magic[3] == 'S')) { /* server capability */ return; } } if ((magic[0] == 'R') && (magic[1] == 'P')) { if ((magic[2] == 'C') && (magic[3] == 'P')) { printercache_process(This, s); return; } } unimpl("RDPDR packet type %c%c%c%c\n", magic[0], magic[1], magic[2], magic[3]); }
/* Process a system pointer PDU */ void process_system_pointer_pdu(STREAM s) { uint16 system_pointer_type; in_uint16_le(s, system_pointer_type); switch (system_pointer_type) { case RDP_NULL_POINTER: ui_set_null_cursor(); break; default: unimpl("System pointer message 0x%x\n", system_pointer_type); } }
/* used in uiports and rdp_main_loop, processes the rdp packets waiting */ RD_BOOL rdp_loop(RD_BOOL * deactivated, uint32 * ext_disc_reason) { uint8 type; RD_BOOL cont = True; STREAM s; while (cont) { s = rdp_recv(&type); if (s == NULL) return False; switch (type) { case RDP_PDU_DEMAND_ACTIVE: process_demand_active(s); *deactivated = False; break; case RDP_PDU_DEACTIVATE: DEBUG(("RDP_PDU_DEACTIVATE\n")); *deactivated = True; break; case RDP_PDU_REDIRECT: return process_redirect_pdu(s, False); break; case RDP_PDU_ENHANCED_REDIRECT: return process_redirect_pdu(s, True); break; case RDP_PDU_DATA: /* If we got a data PDU, we don't need to keep the password in memory anymore and therefor we should clear it for security reasons. */ if (g_password[0] != '\0') memset(g_password, 0, sizeof(g_password)); process_data_pdu(s, ext_disc_reason); break; case 0: break; default: unimpl("PDU %d\n", type); } cont = g_next_packet < s->end; } return True; }
/* used in uiports and rdp_main_loop, processes the rdp packets waiting */ RD_BOOL rdp_loop(RD_BOOL * deactivated, uint32 * ext_disc_reason) { __android_log_print(ANDROID_LOG_INFO, "JNIMsg", "rdp_loop"); uint8 type; RD_BOOL cont = True; STREAM s; while (cont) { s = rdp_recv(&type); if (s == NULL) return False; switch (type) { case RDP_PDU_DEMAND_ACTIVE: __android_log_print(ANDROID_LOG_INFO, "JNIMsg", "rdp_loop RDP_PDU_DEMAND_ACTIVE"); process_demand_active(s); *deactivated = False; break; case RDP_PDU_DEACTIVATE: __android_log_print(ANDROID_LOG_INFO, "JNIMsg", "rdp_loop RDP_PDU_DEACTIVATE"); DEBUG(("RDP_PDU_DEACTIVATE\n")); *deactivated = True; break; case RDP_PDU_REDIRECT: __android_log_print(ANDROID_LOG_INFO, "JNIMsg", "rdp_loop RDP_PDU_REDIRECT"); return process_redirect_pdu(s); break; case RDP_PDU_DATA: __android_log_print(ANDROID_LOG_INFO, "JNIMsg", "rdp_loop RDP_PDU_DATA"); process_data_pdu(s, ext_disc_reason); break; case 0: break; default: unimpl("PDU %d\n", type); } cont = g_next_packet < s->end; } return True; }
/* used in uiports and rdp_main_loop, processes the rdp packets waiting */ BOOL rdp_loop(RDPCLIENT * This, BOOL * deactivated, uint32 * ext_disc_reason) { uint8 type; BOOL disc = False; /* True when a disconnect PDU was received */ BOOL cont = True; STREAM s; while (cont) { s = rdp_recv(This, &type); if (s == NULL) return False; switch (type) { case RDP_PDU_DEMAND_ACTIVE: if(!process_demand_active(This, s)) return False; *deactivated = False; break; case RDP_PDU_DEACTIVATE: DEBUG(("RDP_PDU_DEACTIVATE\n")); *deactivated = True; break; case RDP_PDU_REDIRECT: return process_redirect_pdu(This, s); break; case RDP_PDU_DATA: disc = process_data_pdu(This, s, ext_disc_reason); break; case 0: break; default: unimpl("PDU %d\n", type); } if (disc) return False; cont = This->next_packet < s->end; } return True; }
/* Process incoming packets */ BOOL rdp_main_loop(void) { uint8 type; STREAM s; while ((s = rdp_recv(&type)) != NULL) { switch (type) { case RDP_PDU_DEMAND_ACTIVE: process_demand_active(s); break; case RDP_PDU_DEACTIVATE: DEBUG(("RDP_PDU_DEACTIVATE\n")); /* We thought we could detect a clean shutdown of the session by this packet, but it seems Windows 2003 is sending us one of these when we reconnect to a disconnected session return True; */ break; case RDP_PDU_DATA: process_data_pdu(s); break; case 0: break; default: unimpl("PDU %d\n", type); } } return True; /* We want to detect if we got a clean shutdown, but we can't. Se above. return False; */ }
/* Process data PDU */ static void process_data_pdu(STREAM s) { uint8 data_pdu_type; in_uint8s(s, 8); /* shareid, pad, streamid, length */ in_uint8(s, data_pdu_type); in_uint8s(s, 3); /* compress_type, compress_len */ switch (data_pdu_type) { case RDP_DATA_PDU_UPDATE: process_update_pdu(s); break; case RDP_DATA_PDU_POINTER: process_pointer_pdu(s); break; case RDP_DATA_PDU_BELL: ui_bell(); break; case RDP_DATA_PDU_LOGON: DEBUG(("Received Logon PDU\n")); /* User logged on */ break; case RDP_DATA_PDU_DISCONNECT: /* Normally received when user logs out or disconnects from a console session on Windows XP and 2003 Server */ DEBUG(("Received disconnect PDU\n")); break; default: unimpl("data PDU %d\n", data_pdu_type); } }
/* Process a secondary order */ static void process_secondary_order(STREAM s) { uint16 length; uint8 type; uint8 *next_order; in_uint16_le(s, length); in_uint8s(s, 2); /* flags */ in_uint8(s, type); next_order = s->p + length + 7; switch (type) { case RDP_ORDER_RAW_BMPCACHE: process_raw_bmpcache(s); break; case RDP_ORDER_COLCACHE: process_colcache(s); break; case RDP_ORDER_BMPCACHE: process_bmpcache(s); break; case RDP_ORDER_FONTCACHE: process_fontcache(s); break; default: unimpl("secondary order %d\n", type); } s->p = next_order; }
/* used in uiports and rdp_main_loop, processes the rdp packets waiting */ RD_BOOL rdp_loop(RD_BOOL * deactivated, uint32 * ext_disc_reason) { uint8 type; RD_BOOL cont = True; STREAM s; while (cont) { s = rdp_recv(&type); if (s == NULL) return False; switch (type) { case RDP_PDU_DEMAND_ACTIVE: process_demand_active(s); *deactivated = False; break; case RDP_PDU_DEACTIVATE: DEBUG(("RDP_PDU_DEACTIVATE\n")); *deactivated = True; break; case RDP_PDU_REDIRECT: return process_redirect_pdu(s); break; case RDP_PDU_DATA: process_data_pdu(s, ext_disc_reason); break; case 0: break; default: unimpl("PDU %d\n", type); } cont = g_next_packet < s->end; } return True; }
void rdpsnd_process(STREAM s) { uint8 type; uint16 datalen; uint32 volume; static uint16 tick, format; static uint8 packet_index; static BOOL awaiting_data_packet; #ifdef RDPSND_DEBUG printf("RDPSND recv:\n"); hexdump(s->p, s->end - s->p); #endif if (awaiting_data_packet) { if (format >= MAX_FORMATS) { error("RDPSND: Invalid format index\n"); return; } if (!device_open || (format != current_format)) { if (!device_open && !wave_out_open()) { rdpsnd_send_completion(tick, packet_index); return; } if (!wave_out_set_format(&formats[format])) { rdpsnd_send_completion(tick, packet_index); wave_out_close(); device_open = False; return; } device_open = True; current_format = format; } wave_out_write(s, tick, packet_index); awaiting_data_packet = False; return; } in_uint8(s, type); in_uint8s(s, 1); /* unknown? */ in_uint16_le(s, datalen); switch (type) { case RDPSND_WRITE: in_uint16_le(s, tick); in_uint16_le(s, format); in_uint8(s, packet_index); awaiting_data_packet = True; break; case RDPSND_CLOSE: wave_out_close(); device_open = False; break; case RDPSND_NEGOTIATE: rdpsnd_process_negotiate(s); break; case RDPSND_UNKNOWN6: rdpsnd_process_unknown6(s); break; case RDPSND_SET_VOLUME: in_uint32(s, volume); if (device_open) { wave_out_volume((volume & 0xffff), (volume & 0xffff0000) >> 16); } break; default: unimpl("RDPSND packet type %d\n", type); break; } }
/* Process data PDU */ static RD_BOOL process_data_pdu(STREAM s, uint32 * ext_disc_reason) { uint8 data_pdu_type; uint8 ctype; uint16 clen; uint32 len; uint32 roff, rlen; struct stream *ns = &(g_mppc_dict.ns); in_uint8s(s, 6); /* shareid, pad, streamid */ in_uint16_le(s, len); in_uint8(s, data_pdu_type); in_uint8(s, ctype); in_uint16_le(s, clen); clen -= 18; if (ctype & RDP_MPPC_COMPRESSED) { if (len > RDP_MPPC_DICT_SIZE) error("error decompressed packet size exceeds max\n"); if (mppc_expand(s->p, clen, ctype, &roff, &rlen) == -1) error("error while decompressing packet\n"); /* len -= 18; */ /* allocate memory and copy the uncompressed data into the temporary stream */ ns->data = (uint8 *) xrealloc(ns->data, rlen); memcpy((ns->data), (unsigned char *) (g_mppc_dict.hist + roff), rlen); ns->size = rlen; ns->end = (ns->data + ns->size); ns->p = ns->data; ns->rdp_hdr = ns->p; s = ns; } switch (data_pdu_type) { case RDP_DATA_PDU_UPDATE: process_update_pdu(s); break; case RDP_DATA_PDU_CONTROL: DEBUG(("Received Control PDU\n")); break; case RDP_DATA_PDU_SYNCHRONISE: DEBUG(("Received Sync PDU\n")); break; case RDP_DATA_PDU_POINTER: process_pointer_pdu(s); break; case RDP_DATA_PDU_BELL: ui_bell(); break; case RDP_DATA_PDU_LOGON: DEBUG(("Received Logon PDU\n")); /* User logged on */ process_pdu_logon(s); break; case RDP_DATA_PDU_DISCONNECT: process_disconnect_pdu(s, ext_disc_reason); /* We used to return true and disconnect immediately here, but * Windows Vista sends a disconnect PDU with reason 0 when * reconnecting to a disconnected session, and MSTSC doesn't * drop the connection. I think we should just save the status. */ break; case RDP_DATA_PDU_AUTORECONNECT_STATUS: warning("Automatic reconnect using cookie, failed.\n"); break; default: unimpl("data PDU %d\n", data_pdu_type); } return False; }
/* Process an order PDU */ void process_orders(STREAM s) { RDP_ORDER_STATE *os = &order_state; uint32 present; uint16 num_orders; uint8 order_flags; int size, processed = 0; BOOL delta; in_uint8s(s, 2); /* pad */ in_uint16_le(s, num_orders); in_uint8s(s, 2); /* pad */ while (processed < num_orders) { in_uint8(s, order_flags); if (!(order_flags & RDP_ORDER_STANDARD)) { error("order parsing failed\n"); break; } if (order_flags & RDP_ORDER_SECONDARY) { process_secondary_order(s); } else { if (order_flags & RDP_ORDER_CHANGE) { in_uint8(s, os->order_type); } switch (os->order_type) { case RDP_ORDER_TRIBLT: case RDP_ORDER_TEXT2: size = 3; break; case RDP_ORDER_PATBLT: case RDP_ORDER_MEMBLT: case RDP_ORDER_LINE: size = 2; break; default: size = 1; } rdp_in_present(s, &present, order_flags, size); if (order_flags & RDP_ORDER_BOUNDS) { if (!(order_flags & RDP_ORDER_LASTBOUNDS)) rdp_parse_bounds(s, &os->bounds); ui_set_clip(os->bounds.left, os->bounds.top, os->bounds.right - os->bounds.left + 1, os->bounds.bottom - os->bounds.top + 1); } delta = order_flags & RDP_ORDER_DELTA; switch (os->order_type) { case RDP_ORDER_DESTBLT: process_destblt(s, &os->destblt, present, delta); break; case RDP_ORDER_PATBLT: process_patblt(s, &os->patblt, present, delta); break; case RDP_ORDER_SCREENBLT: process_screenblt(s, &os->screenblt, present, delta); break; case RDP_ORDER_LINE: process_line(s, &os->line, present, delta); break; case RDP_ORDER_RECT: process_rect(s, &os->rect, present, delta); break; case RDP_ORDER_DESKSAVE: process_desksave(s, &os->desksave, present, delta); break; case RDP_ORDER_MEMBLT: process_memblt(s, &os->memblt, present, delta); break; case RDP_ORDER_TRIBLT: process_triblt(s, &os->triblt, present, delta); break; case RDP_ORDER_POLYLINE: process_polyline(s, &os->polyline, present, delta); break; case RDP_ORDER_TEXT2: process_text2(s, &os->text2, present, delta); break; default: unimpl("order %d\n", os->order_type); return; } if (order_flags & RDP_ORDER_BOUNDS) ui_reset_clip(); } processed++; } if (s->p != next_packet) error("%d bytes remaining\n", (int) (next_packet - s->p)); }
/* 1 byte bitmap decompress */ static RD_BOOL bitmap_decompress1(uint8 * output, int width, int height, uint8 * input, int size) { uint8 *end = input + size; uint8 *prevline = NULL, *line = NULL; int opcode, count, offset, isfillormix, x = width; int lastopcode = -1, insertmix = False, bicolour = False; uint8 code; uint8 colour1 = 0, colour2 = 0; uint8 mixmask, mask = 0; uint8 mix = 0xff; int fom_mask = 0; while (input < end) { fom_mask = 0; code = CVAL(input); opcode = code >> 4; /* Handle different opcode forms */ switch (opcode) { case 0xc: case 0xd: case 0xe: opcode -= 6; count = code & 0xf; offset = 16; break; case 0xf: opcode = code & 0xf; if (opcode < 9) { count = CVAL(input); count |= CVAL(input) << 8; } else { count = (opcode < 0xb) ? 8 : 1; } offset = 0; break; default: opcode >>= 1; count = code & 0x1f; offset = 32; break; } /* Handle strange cases for counts */ if (offset != 0) { isfillormix = ((opcode == 2) || (opcode == 7)); if (count == 0) { if (isfillormix) count = CVAL(input) + 1; else count = CVAL(input) + offset; } else if (isfillormix) { count <<= 3; } } /* Read preliminary data */ switch (opcode) { case 0: /* Fill */ if ((lastopcode == opcode) && !((x == width) && (prevline == NULL))) insertmix = True; break; case 8: /* Bicolour */ colour1 = CVAL(input); case 3: /* Colour */ colour2 = CVAL(input); break; case 6: /* SetMix/Mix */ case 7: /* SetMix/FillOrMix */ mix = CVAL(input); opcode -= 5; break; case 9: /* FillOrMix_1 */ mask = 0x03; opcode = 0x02; fom_mask = 3; break; case 0x0a: /* FillOrMix_2 */ mask = 0x05; opcode = 0x02; fom_mask = 5; break; } lastopcode = opcode; mixmask = 0; /* Output body */ while (count > 0) { if (x >= width) { if (height <= 0) return False; x = 0; height--; prevline = line; line = output + height * width; } switch (opcode) { case 0: /* Fill */ if (insertmix) { if (prevline == NULL) line[x] = mix; else line[x] = prevline[x] ^ mix; insertmix = False; count--; x++; } if (prevline == NULL) { REPEAT(line[x] = 0) } else { REPEAT(line[x] = prevline[x]) } break; case 1: /* Mix */ if (prevline == NULL) { REPEAT(line[x] = mix) } else { REPEAT(line[x] = prevline[x] ^ mix) } break; case 2: /* Fill or Mix */ if (prevline == NULL) { REPEAT ( MASK_UPDATE(); if (mask & mixmask) line[x] = mix; else line[x] = 0; ) } else { REPEAT ( MASK_UPDATE(); if (mask & mixmask) line[x] = prevline[x] ^ mix; else line[x] = prevline[x]; ) } break; case 3: /* Colour */ REPEAT(line[x] = colour2) break; case 4: /* Copy */ REPEAT(line[x] = CVAL(input)) break; case 8: /* Bicolour */ REPEAT ( if (bicolour) { line[x] = colour2; bicolour = False; } else { line[x] = colour1; bicolour = True; count++; } ) break; case 0xd: /* White */ REPEAT(line[x] = 0xff) break; case 0xe: /* Black */ REPEAT(line[x] = 0) break; default: unimpl("bitmap opcode 0x%x\n", opcode); return False; }
/* Process data PDU */ static BOOL process_data_pdu(STREAM s, uint32 * ext_disc_reason) { uint8 data_pdu_type; uint8 ctype; uint16 clen; uint32 len; uint32 roff, rlen; struct stream *ns = &(g_mppc_dict.ns); in_uint8s(s, 6); /* shareid, pad, streamid */ in_uint16(s, len); in_uint8(s, data_pdu_type); in_uint8(s, ctype); in_uint16(s, clen); clen -= 18; if (ctype & RDP_MPPC_COMPRESSED) { if (len > RDP_MPPC_DICT_SIZE) error("error decompressed packet size exceeds max\n"); if (mppc_expand(s->p, clen, ctype, &roff, &rlen) == -1) error("error while decompressing packet\n"); /* len -= 18; */ /* allocate memory and copy the uncompressed data into the temporary stream */ ns->data = (uint8 *) xrealloc(ns->data, rlen); memcpy((ns->data), (unsigned char *) (g_mppc_dict.hist + roff), rlen); ns->size = rlen; ns->end = (ns->data + ns->size); ns->p = ns->data; ns->rdp_hdr = ns->p; s = ns; } switch (data_pdu_type) { case RDP_DATA_PDU_UPDATE: process_update_pdu(s); break; case RDP_DATA_PDU_CONTROL: DEBUG(("Received Control PDU\n")); break; case RDP_DATA_PDU_SYNCHRONISE: DEBUG(("Received Sync PDU\n")); break; case RDP_DATA_PDU_POINTER: process_pointer_pdu(s); break; case RDP_DATA_PDU_BELL: ui_bell(); break; case RDP_DATA_PDU_LOGON: DEBUG(("Received Logon PDU\n")); /* User logged on */ break; case RDP_DATA_PDU_DISCONNECT: process_disconnect_pdu(s, ext_disc_reason); return True; default: unimpl("data PDU %d\n", data_pdu_type); } return False; }
bool GrGpuGLFixed::flushGraphicsState(GrPrimitiveType type) { bool usingTextures[kNumStages]; for (int s = 0; s < kNumStages; ++s) { usingTextures[s] = VertexUsesStage(s, fGeometrySrc.fVertexLayout); if (usingTextures[s] && fCurrDrawState.fSamplerStates[s].isGradient()) { unimpl("Fixed pipe doesn't support radial/sweep gradients"); return false; } } if (GR_GL_SUPPORT_ES1) { if (BlendCoefReferencesConstant(fCurrDrawState.fSrcBlend) || BlendCoefReferencesConstant(fCurrDrawState.fDstBlend)) { unimpl("ES1 doesn't support blend constant"); return false; } } if (!flushGLStateCommon(type)) { return false; } if (fDirtyFlags.fRenderTargetChanged) { flushProjectionMatrix(); } for (int s = 0; s < kNumStages; ++s) { bool wasUsingTexture = VertexUsesStage(s, fHWGeometryState.fVertexLayout); if (usingTextures[s] != wasUsingTexture) { setTextureUnit(s); if (usingTextures[s]) { GR_GL(Enable(GR_GL_TEXTURE_2D)); } else { GR_GL(Disable(GR_GL_TEXTURE_2D)); } } } uint32_t vertColor = (fGeometrySrc.fVertexLayout & kColor_VertexLayoutBit); uint32_t prevVertColor = (fHWGeometryState.fVertexLayout & kColor_VertexLayoutBit); if (vertColor != prevVertColor) { if (vertColor) { GR_GL(ShadeModel(GR_GL_SMOOTH)); // invalidate the immediate mode color fHWDrawState.fColor = GrColor_ILLEGAL; } else { GR_GL(ShadeModel(GR_GL_FLAT)); } } if (!vertColor && fHWDrawState.fColor != fCurrDrawState.fColor) { GR_GL(Color4ub(GrColorUnpackR(fCurrDrawState.fColor), GrColorUnpackG(fCurrDrawState.fColor), GrColorUnpackB(fCurrDrawState.fColor), GrColorUnpackA(fCurrDrawState.fColor))); fHWDrawState.fColor = fCurrDrawState.fColor; } // set texture environment, decide whether we are modulating by RGB or A. for (int s = 0; s < kNumStages; ++s) { if (usingTextures[s]) { GrGLTexture* texture = (GrGLTexture*)fCurrDrawState.fTextures[s]; if (NULL != texture) { TextureEnvRGBOperands nextRGBOperand0 = (GrPixelConfigIsAlphaOnly(texture->config())) ? kAlpha_TextureEnvRGBOperand : kColor_TextureEnvRGBOperand; if (fHWRGBOperand0[s] != nextRGBOperand0) { setTextureUnit(s); GR_GL(TexEnvi(GR_GL_TEXTURE_ENV, GR_GL_OPERAND0_RGB, (nextRGBOperand0==kAlpha_TextureEnvRGBOperand) ? GR_GL_SRC_ALPHA : GR_GL_SRC_COLOR)); fHWRGBOperand0[s] = nextRGBOperand0; } if (((1 << s) & fDirtyFlags.fTextureChangedMask) || (fHWDrawState.fSamplerStates[s].getMatrix() != getSamplerMatrix(s))) { GrMatrix texMat = getSamplerMatrix(s); AdjustTextureMatrix(texture, GrSamplerState::kNormal_SampleMode, &texMat); GrGpuMatrix glm; glm.set(texMat); setTextureUnit(s); GR_GL(MatrixMode(GR_GL_TEXTURE)); GR_GL(LoadMatrixf(glm.fMat)); recordHWSamplerMatrix(s, getSamplerMatrix(s)); } } else { GrAssert(!"Rendering with texture vert flag set but no bound texture"); return false; } } } if (fHWDrawState.fViewMatrix != fCurrDrawState.fViewMatrix) { GrGpuMatrix glm; glm.set(fCurrDrawState.fViewMatrix); GR_GL(MatrixMode(GR_GL_MODELVIEW)); GR_GL(LoadMatrixf(glm.fMat)); fHWDrawState.fViewMatrix = fCurrDrawState.fViewMatrix; } resetDirtyFlags(); return true; }
static void rdpusb_process(STREAM s) { int rc; uint32 len; uint8 code; uint32 devid; PUSBPROXYDEV proxy = NULL; #ifdef RDPUSB_DEBUG Log(("RDPUSB recv:\n")); hexdump(s->p, s->end - s->p); #endif in_uint32_le (s, len); if (len > s->end - s->p) { error("RDPUSB: not enough data len = %d, bytes left %d\n", len, s->end - s->p); return; } in_uint8(s, code); Log(("RDPUSB recv: len = %d, code = %d\n", len, code)); switch (code) { case RDPUSB_REQ_OPEN: { PUSBDEVICE pDevice; in_uint32_le(s, devid); proxy = (PUSBPROXYDEV )xmalloc (sizeof (USBPROXYDEV)); if (!proxy) { error("RDPUSB: Out of memory allocating proxy backend data\n"); return; } memset (proxy, 0, sizeof (USBPROXYDEV)); proxy->pvInstanceDataR3 = xmalloc(g_USBProxyDeviceHost.cbBackend); if (!proxy->pvInstanceDataR3) { xfree (proxy); error("RDPUSB: Out of memory allocating proxy backend data\n"); return; } proxy->Dev.pszName = "Remote device"; proxy->devid = devid; for (pDevice = g_pUsbDevices; pDevice; pDevice = pDevice->pNext) if ((pDevice->bPort << 8) + pDevice->bBus == devid) break; rc = pDevice ? op_usbproxy_back_open(proxy, pDevice->pszAddress) : VERR_NOT_FOUND; if (rc != VINF_SUCCESS) { rdpusb_send_access_denied (code, devid); xfree (proxy); proxy = NULL; } else { if (g_proxies) { g_proxies->pPrev = proxy; } proxy->pNext = g_proxies; g_proxies = proxy; } } break; case RDPUSB_REQ_CLOSE: { in_uint32_le(s, devid); proxy = devid2proxy (devid); if (proxy) { op_usbproxy_back_close(proxy); if (proxy->pPrev) { proxy->pPrev->pNext = proxy->pNext; } else { g_proxies = proxy->pNext; } if (proxy->pNext) { proxy->pNext->pPrev = proxy->pPrev; } xfree (proxy->pvInstanceDataR3); xfree (proxy); proxy = NULL; } /* No reply. */ } break; case RDPUSB_REQ_RESET: { in_uint32_le(s, devid); proxy = devid2proxy (devid); if (!proxy) { rdpusb_send_access_denied (code, devid); break; } rc = op_usbproxy_back_reset(proxy); if (rc != VINF_SUCCESS) { rdpusb_send_reply (code, vrdp_usb_status (!rc, &proxy->Dev), devid); } } break; case RDPUSB_REQ_SET_CONFIG: { uint8 cfg; in_uint32_le(s, devid); proxy = devid2proxy (devid); if (!proxy) { rdpusb_send_access_denied (code, devid); break; } in_uint8(s, cfg); rc = op_usbproxy_back_set_config(proxy, cfg); if (RT_FAILURE(rc)) { rdpusb_send_reply (code, vrdp_usb_status (rc, &proxy->Dev), devid); } } break; case RDPUSB_REQ_CLAIM_INTERFACE: { uint8 ifnum; in_uint32_le(s, devid); proxy = devid2proxy (devid); if (!proxy) { rdpusb_send_access_denied (code, devid); break; } in_uint8(s, ifnum); in_uint8(s, ifnum); rc = op_usbproxy_back_claim_interface(proxy, ifnum); if (RT_FAILURE(rc)) { rdpusb_send_reply (code, vrdp_usb_status (rc, &proxy->Dev), devid); } } break; case RDPUSB_REQ_RELEASE_INTERFACE: { uint8 ifnum; in_uint32_le(s, devid); proxy = devid2proxy (devid); if (!proxy) { rdpusb_send_access_denied (code, devid); break; } in_uint8(s, ifnum); rc = op_usbproxy_back_release_interface(proxy, ifnum); if (RT_FAILURE(rc)) { rdpusb_send_reply (code, vrdp_usb_status (rc, &proxy->Dev), devid); } } break; case RDPUSB_REQ_INTERFACE_SETTING: { uint8 ifnum; uint8 setting; in_uint32_le(s, devid); proxy = devid2proxy (devid); if (!proxy) { rdpusb_send_access_denied (code, devid); break; } in_uint8(s, ifnum); in_uint8(s, setting); rc = op_usbproxy_back_interface_setting(proxy, ifnum, setting); if (RT_FAILURE(rc)) { rdpusb_send_reply (code, vrdp_usb_status (rc, &proxy->Dev), devid); } } break; case RDPUSB_REQ_QUEUE_URB: { uint32 handle; uint8 type; uint8 ep; uint8 dir; uint32 urblen; uint32 datalen; PVUSBURB pUrb; // struct vusb_urb *urb; in_uint32_le(s, devid); proxy = devid2proxy (devid); if (!proxy) { /* No reply. */ break; } in_uint32(s, handle); in_uint8(s, type); in_uint8(s, ep); in_uint8(s, dir); in_uint32(s, urblen); in_uint32(s, datalen); /* Allocate a single block for URB description and data buffer */ pUrb = (PVUSBURB)xmalloc (sizeof (VUSBURB) + (urblen <= sizeof (pUrb->abData)? 0: urblen - sizeof (pUrb->abData)) ); memset (pUrb, 0, sizeof (VUSBURB)); pUrb->pDev = &proxy->Dev; pUrb->handle = handle; pUrb->enmType = type; pUrb->enmStatus = 0; pUrb->EndPt = ep; pUrb->enmDir = dir; pUrb->cbData = urblen; Log(("RDPUSB: queued URB handle = %d\n", handle)); if (datalen) { in_uint8a (s, pUrb->abData, datalen); } rc = op_usbproxy_back_queue_urb(proxy, pUrb); /* No reply required. */ if (RT_SUCCESS(rc)) { if (proxy->pUrbs) { proxy->pUrbs->pPrev = pUrb; } pUrb->pNext = proxy->pUrbs; proxy->pUrbs = pUrb; } else { xfree (pUrb); } } break; case RDPUSB_REQ_REAP_URB: { rdpusb_reap_urbs (); } break; case RDPUSB_REQ_CLEAR_HALTED_EP: { uint8 ep; in_uint32_le(s, devid); proxy = devid2proxy (devid); if (!proxy) { rdpusb_send_access_denied (code, devid); break; } in_uint8(s, ep); rc = op_usbproxy_back_clear_halted_ep(proxy, ep); if (RT_FAILURE(rc)) { rdpusb_send_reply (code, vrdp_usb_status (rc, &proxy->Dev), devid); } } break; case RDPUSB_REQ_CANCEL_URB: { uint32 handle; PVUSBURB pUrb = NULL; in_uint32_le(s, devid); proxy = devid2proxy (devid); if (!proxy) { rdpusb_send_access_denied (code, devid); break; } in_uint32_le(s, handle); pUrb = proxy->pUrbs; while (pUrb && pUrb->handle != handle) { pUrb = pUrb->pNext; } if (pUrb) { op_usbproxy_back_cancel_urb(proxy, pUrb); /* No reply required. */ /* Remove URB from list. */ if (pUrb->pPrev) { pUrb->pPrev->pNext = pUrb->pNext; } else { proxy->pUrbs = pUrb->pNext; } if (pUrb->pNext) { pUrb->pNext->pPrev = pUrb->pPrev; } pUrb->pNext = pUrb->pPrev = NULL; Log(("Cancelled URB %p\n", pUrb)); // xfree (pUrb); } } break; case RDPUSB_REQ_DEVICE_LIST: { void *buf = NULL; int len = 0; buf = build_device_list (&len); s = rdpusb_init_packet(len? len: 2, code); if (len) { out_uint8p (s, buf, len); } else { out_uint16_le(s, 0); } s_mark_end(s); rdpusb_send(s); if (buf) { free (buf); } } break; case RDPUSB_REQ_NEGOTIATE: { s = rdpusb_init_packet(1, code); out_uint8(s, VRDP_USB_CAPS_FLAG_ASYNC); s_mark_end(s); rdpusb_send(s); } break; default: unimpl("RDPUSB code %d\n", code); break; } }
void rdp5_process(STREAM s) { uint16 length, count, x, y; uint8 type, ctype; uint8 *next; uint32 roff, rlen; struct stream *ns = &(g_mppc_dict.ns); struct stream *ts; #if 0 printf("RDP5 data:\n"); hexdump(s->p, s->end - s->p); #endif ui_begin_update(); while (s->p < s->end) { in_uint8(s, type); if (type & RDP5_COMPRESSED) { in_uint8(s, ctype); in_uint16_le(s, length); type ^= RDP5_COMPRESSED; } else { ctype = 0; in_uint16_le(s, length); } g_next_packet = next = s->p + length; if (ctype & RDP_MPPC_COMPRESSED) { if (mppc_expand(s->p, length, ctype, &roff, &rlen) == -1) error("error while decompressing packet\n"); /* allocate memory and copy the uncompressed data into the temporary stream */ ns->data = (uint8 *) xrealloc(ns->data, rlen); memcpy((ns->data), (unsigned char *) (g_mppc_dict.hist + roff), rlen); ns->size = rlen; ns->end = (ns->data + ns->size); ns->p = ns->data; ns->rdp_hdr = ns->p; ts = ns; } else ts = s; switch (type) { case 0: /* update orders */ in_uint16_le(ts, count); process_orders(ts, count); break; case 1: /* update bitmap */ in_uint8s(ts, 2); /* part length */ process_bitmap_updates(ts); break; case 2: /* update palette */ in_uint8s(ts, 2); /* uint16 = 2 */ process_palette(ts); break; case 3: /* update synchronize */ break; case 5: /* null pointer */ ui_set_null_cursor(); break; case 6: /* default pointer */ break; case 8: /* pointer position */ in_uint16_le(ts, x); in_uint16_le(ts, y); if (s_check(ts)) ui_move_pointer(x, y); break; case 9: /* color pointer */ process_colour_pointer_pdu(ts); break; case 10: /* cached pointer */ process_cached_pointer_pdu(ts); break; case 11: process_new_pointer_pdu(ts); break; default: unimpl("RDP5 opcode %d\n", type); } s->p = next; } ui_end_update(); }
static void rdpsnd_process_packet(uint8 opcode, STREAM s) { uint16 vol_left, vol_right; static uint16 tick, format; static uint8 packet_index; switch (opcode) { case RDPSND_WRITE: in_uint16_le(s, tick); in_uint16_le(s, format); in_uint8(s, packet_index); in_uint8s(s, 3); DEBUG_SOUND(("RDPSND: RDPSND_WRITE(tick: %u, format: %u, index: %u, data: %u bytes)\n", (unsigned) tick, (unsigned) format, (unsigned) packet_index, (unsigned) s->size - 8)); if (format >= MAX_FORMATS) { error("RDPSND: Invalid format index\n"); break; } if (!device_open || (format != current_format)) { /* * If we haven't selected a device by now, then either * we've failed to find a working device, or the server * is sending bogus RDPSND_WRITE. */ if (!current_driver) { rdpsnd_send_completion(tick, packet_index); break; } if (!device_open && !current_driver->wave_out_open()) { rdpsnd_send_completion(tick, packet_index); break; } if (!current_driver->wave_out_set_format(&formats[format])) { rdpsnd_send_completion(tick, packet_index); current_driver->wave_out_close(); device_open = False; break; } device_open = True; current_format = format; } rdpsnd_queue_write(rdpsnd_dsp_process (s->p, s->end - s->p, current_driver, &formats[current_format]), tick, packet_index); return; break; case RDPSND_CLOSE: DEBUG_SOUND(("RDPSND: RDPSND_CLOSE()\n")); if (device_open) current_driver->wave_out_close(); device_open = False; break; case RDPSND_NEGOTIATE: rdpsnd_process_negotiate(s); break; case RDPSND_PING: rdpsnd_process_ping(s); break; case RDPSND_SET_VOLUME: in_uint16_le(s, vol_left); in_uint16_le(s, vol_right); DEBUG_SOUND(("RDPSND: RDPSND_VOLUME(left: 0x%04x (%u %%), right: 0x%04x (%u %%))\n", (unsigned) vol_left, (unsigned) vol_left / 655, (unsigned) vol_right, (unsigned) vol_right / 655)); if (device_open) current_driver->wave_out_volume(vol_left, vol_right); break; default: unimpl("RDPSND packet type %x\n", opcode); break; } }
static void rdpdr_process_irp(RDPCLIENT * This, STREAM s) { uint32 result = 0, length = 0, desired_access = 0, request, file, info_level, buffer_len, id, major, minor, device, offset, bytes_in, bytes_out, error_mode, share_mode, disposition, total_timeout, interval_timeout, flags_and_attributes = 0; char filename[PATH_MAX]; uint8 *buffer, *pst_buf; struct stream out; DEVICE_FNS *fns; BOOL rw_blocking = True; NTSTATUS status = STATUS_INVALID_DEVICE_REQUEST; in_uint32_le(s, device); in_uint32_le(s, file); in_uint32_le(s, id); in_uint32_le(s, major); in_uint32_le(s, minor); buffer_len = 0; buffer = (uint8 *) xmalloc(1024); buffer[0] = 0; switch (This->rdpdr_device[device].device_type) { case DEVICE_TYPE_SERIAL: fns = &serial_fns; rw_blocking = False; break; case DEVICE_TYPE_PARALLEL: fns = ¶llel_fns; rw_blocking = False; break; case DEVICE_TYPE_PRINTER: fns = &printer_fns; break; case DEVICE_TYPE_DISK: fns = &disk_fns; rw_blocking = False; break; case DEVICE_TYPE_SCARD: default: error("IRP for bad device %ld\n", device); return; } switch (major) { case IRP_MJ_CREATE: in_uint32_be(s, desired_access); in_uint8s(s, 0x08); /* unknown */ in_uint32_le(s, error_mode); in_uint32_le(s, share_mode); in_uint32_le(s, disposition); in_uint32_le(s, flags_and_attributes); in_uint32_le(s, length); if (length && (length / 2) < 256) { rdp_in_unistr(This, s, filename, length); convert_to_unix_filename(filename); } else { filename[0] = 0; } if (!fns->create) { status = STATUS_NOT_SUPPORTED; break; } status = fns->create(This, device, desired_access, share_mode, disposition, flags_and_attributes, filename, &result); buffer_len = 1; break; case IRP_MJ_CLOSE: if (!fns->close) { status = STATUS_NOT_SUPPORTED; break; } status = fns->close(This, file); break; case IRP_MJ_READ: if (!fns->read) { status = STATUS_NOT_SUPPORTED; break; } in_uint32_le(s, length); in_uint32_le(s, offset); #if WITH_DEBUG_RDP5 DEBUG(("RDPDR IRP Read (length: %d, offset: %d)\n", length, offset)); #endif if (!rdpdr_handle_ok(This, device, file)) { status = STATUS_INVALID_HANDLE; break; } if (rw_blocking) /* Complete read immediately */ { buffer = (uint8 *) xrealloc((void *) buffer, length); if (!buffer) { status = STATUS_CANCELLED; break; } status = fns->read(This, file, buffer, length, offset, &result); buffer_len = result; break; } /* Add request to table */ pst_buf = (uint8 *) xmalloc(length); if (!pst_buf) { status = STATUS_CANCELLED; break; } serial_get_timeout(This, file, length, &total_timeout, &interval_timeout); if (add_async_iorequest (This, device, file, id, major, length, fns, total_timeout, interval_timeout, pst_buf, offset)) { status = STATUS_PENDING; break; } status = STATUS_CANCELLED; break; case IRP_MJ_WRITE: buffer_len = 1; if (!fns->write) { status = STATUS_NOT_SUPPORTED; break; } in_uint32_le(s, length); in_uint32_le(s, offset); in_uint8s(s, 0x18); #if WITH_DEBUG_RDP5 DEBUG(("RDPDR IRP Write (length: %d)\n", result)); #endif if (!rdpdr_handle_ok(This, device, file)) { status = STATUS_INVALID_HANDLE; break; } if (rw_blocking) /* Complete immediately */ { status = fns->write(This, file, s->p, length, offset, &result); break; } /* Add to table */ pst_buf = (uint8 *) xmalloc(length); if (!pst_buf) { status = STATUS_CANCELLED; break; } in_uint8a(s, pst_buf, length); if (add_async_iorequest (This, device, file, id, major, length, fns, 0, 0, pst_buf, offset)) { status = STATUS_PENDING; break; } status = STATUS_CANCELLED; break; case IRP_MJ_QUERY_INFORMATION: if (This->rdpdr_device[device].device_type != DEVICE_TYPE_DISK) { status = STATUS_INVALID_HANDLE; break; } in_uint32_le(s, info_level); out.data = out.p = buffer; out.size = sizeof(buffer); status = disk_query_information(This, file, info_level, &out); result = buffer_len = out.p - out.data; break; case IRP_MJ_SET_INFORMATION: if (This->rdpdr_device[device].device_type != DEVICE_TYPE_DISK) { status = STATUS_INVALID_HANDLE; break; } in_uint32_le(s, info_level); out.data = out.p = buffer; out.size = sizeof(buffer); status = disk_set_information(This, file, info_level, s, &out); result = buffer_len = out.p - out.data; break; case IRP_MJ_QUERY_VOLUME_INFORMATION: if (This->rdpdr_device[device].device_type != DEVICE_TYPE_DISK) { status = STATUS_INVALID_HANDLE; break; } in_uint32_le(s, info_level); out.data = out.p = buffer; out.size = sizeof(buffer); status = disk_query_volume_information(This, file, info_level, &out); result = buffer_len = out.p - out.data; break; case IRP_MJ_DIRECTORY_CONTROL: if (This->rdpdr_device[device].device_type != DEVICE_TYPE_DISK) { status = STATUS_INVALID_HANDLE; break; } switch (minor) { case IRP_MN_QUERY_DIRECTORY: in_uint32_le(s, info_level); in_uint8s(s, 1); in_uint32_le(s, length); in_uint8s(s, 0x17); if (length && length < 2 * 255) { rdp_in_unistr(This, s, filename, length); convert_to_unix_filename(filename); } else { filename[0] = 0; } out.data = out.p = buffer; out.size = sizeof(buffer); status = disk_query_directory(This, file, info_level, filename, &out); result = buffer_len = out.p - out.data; if (!buffer_len) buffer_len++; break; case IRP_MN_NOTIFY_CHANGE_DIRECTORY: /* JIF unimpl("IRP major=0x%x minor=0x%x: IRP_MN_NOTIFY_CHANGE_DIRECTORY\n", major, minor); */ in_uint32_le(s, info_level); /* notify mask */ This->notify_stamp = True; status = disk_create_notify(This, file, info_level); result = 0; if (status == STATUS_PENDING) add_async_iorequest(This, device, file, id, major, length, fns, 0, 0, NULL, 0); break; default: status = STATUS_INVALID_PARAMETER; /* JIF */ unimpl("IRP major=0x%x minor=0x%x\n", major, minor); } break; case IRP_MJ_DEVICE_CONTROL: if (!fns->device_control) { status = STATUS_NOT_SUPPORTED; break; } in_uint32_le(s, bytes_out); in_uint32_le(s, bytes_in); in_uint32_le(s, request); in_uint8s(s, 0x14); buffer = (uint8 *) xrealloc((void *) buffer, bytes_out + 0x14); if (!buffer) { status = STATUS_CANCELLED; break; } out.data = out.p = buffer; out.size = sizeof(buffer); status = fns->device_control(This, file, request, s, &out); result = buffer_len = out.p - out.data; /* Serial SERIAL_WAIT_ON_MASK */ if (status == STATUS_PENDING) { if (add_async_iorequest (This, device, file, id, major, length, fns, 0, 0, NULL, 0)) { status = STATUS_PENDING; break; } } break; case IRP_MJ_LOCK_CONTROL: if (This->rdpdr_device[device].device_type != DEVICE_TYPE_DISK) { status = STATUS_INVALID_HANDLE; break; } in_uint32_le(s, info_level); out.data = out.p = buffer; out.size = sizeof(buffer); /* FIXME: Perhaps consider actually *do* something here :-) */ status = STATUS_SUCCESS; result = buffer_len = out.p - out.data; break; default: unimpl("IRP major=0x%x minor=0x%x\n", major, minor); break; } if (status != STATUS_PENDING) { rdpdr_send_completion(This, device, id, status, result, buffer, buffer_len); } if (buffer) xfree(buffer); buffer = NULL; }
/* * XXX warn about ``unsigned char *'' vs ``char *'', * unlike gcc */ static int compare_tlist(struct type_node *dest, struct type_node *src, int flag) { struct type_node *dest_start = dest; for (; dest != NULL && src != NULL; dest = dest->next, src = src->next) { if (src->type == TN_FUNCTION || dest->type == TN_FUNCTION) { if (dest->type != src->type) { /* XXX fix this later */ if (dest == dest_start) { /* * Ordinary function symbols are * compatible with pointers to * functions */ if (dest->type == TN_FUNCTION) { if (src->type == TN_POINTER_TO) { src = src->next; } else { return -1; } } else { if (dest->type == TN_POINTER_TO) { dest = dest->next; } else { return -1; } } } } } if (dest->type != src->type) { /* Pointer vs array vs function */ if (flag & CMPTY_ARRAYPTR) { if ((dest->type == TN_ARRAY_OF || src->type == TN_ARRAY_OF || dest->type == TN_VARARRAY_OF || src->type == TN_VARARRAY_OF) && (dest->type == TN_POINTER_TO || src->type == TN_POINTER_TO)) { continue; } } return -1; } switch (dest->type) { case TN_ARRAY_OF: case TN_VARARRAY_OF: if (flag & CMPTY_TENTDEC) { #if REMOVE_ARRARG if (!dest->have_array_size || !src->have_array_size) { #else if (dest->arrarg->const_value == NULL || src->arrarg->const_value == NULL) { #endif /* * probably * extern int foo[]; * int foo[123]; * -> OK! */ break; } } if (dest->arrarg_const != src->arrarg_const && ((flag & CMPTY_ARRAYPTR) == 0 || dest_start != dest)) { #if REMOVE_ARRARG if (!src->have_array_size || !dest->have_array_size) { #else if (src->arrarg->const_value == NULL || dest->arrarg->const_value == NULL) { #endif /* * One side has unspecified size, this * is OK! * extern char foo[]; * char (*p)[5] = &foo; * char bar[5]; * char (*p2)[] = &bar; */ break; } else { /* Array sizes differ */ return -1; } } break; case TN_POINTER_TO: break; case TN_FUNCTION: if (compare_tfunc(dest->tfunc, src->tfunc) == -1) { return -1; } break; } } if (dest != NULL || src != NULL) { /* One list is longer, so it differs by definition */ return -1; } return 0; } #endif /* #ifndef PREPROCESSOR */ int compare_types(struct type *dest, struct type *src, int flag) { int is_void_ptr = 0; /* 04/08/08: Changed this (for the better, hopefully!) */ if (dest->tlist != NULL && dest->tlist->type == TN_POINTER_TO && dest->tlist->next == NULL && dest->code == TY_VOID) { is_void_ptr = 1; } else if (src->tlist != NULL && src->tlist->type == TN_POINTER_TO && src->tlist->next == NULL && src->code == TY_VOID) { is_void_ptr = 1; } if (dest->code != src->code) { /* * Differing base type - This is ok if we have a void * pointer vs a non-void pointer, otherwise return error */ if (!is_void_ptr || src->tlist == NULL || dest->tlist == NULL) { return -1; } } if (flag & CMPTY_SIGN) { if (dest->sign != dest->sign) { /* Differing sign */ return -1; } } if (flag & CMPTY_CONST) { if (IS_CONST(dest->flags) != IS_CONST(src->flags)) { /* One is const-qualified */ /*return -1;*/ } } /* * 04/08/08: Skip the tlist comparison if this is void pointer * vs non-void pointer; Otherwise tlists of different length * will compare uneven, as in void * vs int **, which is wrong */ if (is_void_ptr) { return 0; } #ifndef PREPROCESSOR return compare_tlist(dest->tlist, src->tlist, flag); #else return -1; #endif } int check_init_type(struct type *ofwhat, struct expr *init) { if (ofwhat->tlist == NULL) { if (init->next != NULL) { } } else if (ofwhat->tlist->type == TN_ARRAY_OF) { if (init->type->code == TOK_STRING_LITERAL) { return 0; } else { struct expr *ex; for (ex = init; ex != NULL; ex = ex->next) { } } } return 0; } void copy_type(struct type *dest, const struct type *src, int fullcopy) { if (fullcopy) { memcpy(dest, src, sizeof *dest); } else { memcpy(dest, src, sizeof *dest); } } struct type_node * copy_tlist(struct type_node **dest, const struct type_node *src) { struct type_node *head; struct type_node *tail; struct type_node *tn; if (src == NULL) { *dest = NULL; return NULL; } head = tail = NULL; do { tn = n_xmalloc(sizeof *tn); memcpy(tn, src, sizeof *tn); if (head == NULL) { head = tail = tn; } else { tail->next = tn; tail = tail->next; } } while ((src = src->next) != NULL); *dest = head; return tail; } void set_type_sign(struct type *ty) { if (ty->code == TY_UCHAR || ty->code == TY_USHORT || ty->code == TY_UINT || ty->code == TY_ULONG || ty->code == TY_ULLONG) { ty->sign = TOK_KEY_UNSIGNED; } else if (!IS_FLOATING(ty->code) && ty->code != TY_STRUCT && ty->code != TY_UNION) { ty->sign = TOK_KEY_SIGNED; } } struct type * make_basic_type(int code) { #define N_TYPES (TY_MAX - TY_MIN) #if 0 static struct type basic_types[N_TYPES]; #endif static int inited; static struct type *basic_types; if (!inited) { int i; int nbytes = N_TYPES * sizeof(struct type); int need_mprotect = 1; basic_types = debug_malloc_pages(nbytes); if (basic_types == NULL) { /* * Probably debug_malloc_pages() doesn't work * on this system */ basic_types = n_xmalloc(nbytes); need_mprotect = 0; } memset(basic_types, 0, nbytes); for (i = 0; i < N_TYPES; ++i) { basic_types[i].code = i + TY_MIN; set_type_sign(&basic_types[i]); } inited = 1; if (need_mprotect) { /* * We make the array unwritable because it really * should not be written to; Modifying it is a bug * that has happend more than once. * * The void cast is necessary because of a broken * Solaris prototype that takes caddr_t :-/ */ mprotect((void *)basic_types, nbytes, PROT_READ); } } if (code < 0 || (code - TY_MIN) >= N_TYPES) { printf("BUG: bad code for make_basic_type: %d\n", code); abort(); } #if 0 if (code == TY_PSEUDEO_SIZE_T) { static struct type ty; static struct type *p; if (p == NULL) { ty = basic_types[TY_UINT]; } } #endif #if 0 /* As of Jan 6 2007, the basic types may not be modified anymore */ basic_types[code - TY_MIN].tlist = NULL; #endif return &basic_types[code - TY_MIN]; } struct type * make_void_ptr_type(void) { static struct type *ty; if (ty == NULL) { ty = make_basic_type(TY_VOID); ty = n_xmemdup(ty, sizeof *ty); append_typelist(ty, TN_POINTER_TO, NULL, NULL, NULL); } return ty; } struct type * make_array_type(int size, int is_wide_char) { struct type *ret = alloc_type(); if (is_wide_char) { ret->code = backend->get_wchar_t()->code; ret->sign = backend->get_wchar_t()->sign; } else { ret->code = TY_CHAR; if (CHAR_MAX == UCHAR_MAX) { /* XXX */ ret->sign = TOK_KEY_UNSIGNED; } else { ret->sign = TOK_KEY_SIGNED; } } ret->storage = TOK_KEY_STATIC; ret->tlist = alloc_type_node(); ret->tlist->type = TN_ARRAY_OF; ret->tlist->arrarg_const = size; #if REMOVE_ARRARG ret->tlist->have_array_size = 1; #endif return ret; } /* * Helper function for parse_declarator()- stores pointer/array-of/function * property (specified by ``type'' argument) with optional arguments type_arg * (for pointer/array-of) and tf (for function) in type specified by t * * 01/26/08: Extended to do some sanity checking (functions may not return * functions or arrays). This means some type constructions are now REQUIRED * to go through append_typelist()! May not be the best approach, needs * testing?! */ void append_typelist(struct type *t, int type, void *type_arg, struct ty_func *tf, struct token *tok) { struct type_node *te; struct expr *ex; (void) tok; /* XXX unneeded?!?! */ /* Allocate and insert new type node */ if (t->tlist == NULL) { te = t->tlist = t->tlist_tail = alloc_type_node(); te->prev = NULL; if (type == TN_FUNCTION) { /* * If the first node in the type list is a function * designator, this means we are dealing with a genuine * function declaration/definition (as opposed to a * pointer) */ t->is_func = 1; } } else { /* * 01/26/08: Some sanity checking! */ int tailtype = t->tlist_tail->type; if (tailtype == TN_ARRAY_OF || tailtype == TN_VARARRAY_OF) { if (type == TN_FUNCTION) { errorfl(tok, "Invalid declaration of `array of " "functions' - Maybe you meant `array " "of pointer to function'; `void (*ar[N])();'?"); return /* -1 XXX */ ; } } else if (tailtype == TN_FUNCTION) { if (type == TN_ARRAY_OF || type == TN_VARARRAY_OF) { errorfl(tok, "Invalid declaration of `function " "returning array' - If you really want " "to return an array by value, put it " "into a structure!"); return /* -1 XXX */ ; } else if (type == TN_FUNCTION) { errorfl(tok, "Invalid declaration of `function " "returning function' - You can at most " "return a pointer to a function; " "`void (*foo())();'"); return /* -1 XXX */ ; } } te = alloc_type_node(); te->prev = t->tlist_tail; t->tlist_tail->next = te; t->tlist_tail = t->tlist_tail->next; } te->next = NULL; te->type = type; switch (type) { case TN_VARARRAY_OF: case TN_ARRAY_OF: #if REMOVE_ARRARG ex = type_arg; if (ex->const_value == NULL) { /* Size not specified - extern char buf[]; */ te->have_array_size = 0; } else { te->have_array_size = 1; ex->const_value->type = n_xmemdup(ex->const_value->type, sizeof(struct type)); cross_convert_tyval(ex->const_value, NULL, NULL); te->arrarg_const = cross_to_host_size_t( ex->const_value); if (te->arrarg_const == 0) { /* * In GNU C, * int foo[0]; * may be a flexible array member */ te->have_array_size = 0; #if 0 errorfl(tok, "Cannot create zero-sized arrays"); #endif } } if (type == TN_VARARRAY_OF) { te->variable_arrarg = ex; } #else /* Using arrarg */ te->arrarg = type_arg; if (te->arrarg->const_value) { te->arrarg->const_value->type = n_xmemdup(te->arrarg->const_value->type, sizeof(struct type)); cross_convert_tyval(te->arrarg->const_value, NULL, NULL); te->arrarg_const = /* *(size_t *) */ cross_to_host_size_t( te->arrarg->const_value); /*->value; */ if (te->arrarg_const == 0) { /* * In GNU C, * int foo[0]; * may be a flexible array member */ te->arrarg->const_value = NULL; #if 0 errorfl(tok, "Cannot create zero-sized arrays"); #endif } } #endif /* REMOVE_ARRARG is disabled */ break; case TN_POINTER_TO: te->ptrarg = type_arg? *(int *)type_arg: 0; break; case TN_FUNCTION: te->tfunc = tf; break; } } static struct { char *name; int code; } basic_type_names[] = { { "char", TY_CHAR }, { "unsigned char", TY_UCHAR }, { "signed char", TY_SCHAR }, { "short", TY_SHORT }, { "unsigned short", TY_USHORT }, { "int", TY_INT }, { "unsigned int", TY_UINT }, { "long", TY_LONG }, { "unsigned long", TY_ULONG }, { "float", TY_FLOAT }, { "double", TY_DOUBLE }, { "long double", TY_LDOUBLE }, { "struct", TY_STRUCT }, { "union", TY_UNION }, { "enum", TY_ENUM }, { "void", TY_VOID }, { "long long", TY_LLONG }, { "unsigned long long", TY_ULLONG }, { "_Bool", TY_BOOL }, { NULL, 0 } }; char * ret_type_to_text(struct type *ty) { struct type_node *orig_tlist = NULL; char *ret; if (ty->tlist != NULL) { orig_tlist = ty->tlist; if (ty->tlist->type == TN_FUNCTION) { ty->tlist = ty->tlist->next; } else if (ty->tlist->type == TN_POINTER_TO && ty->tlist->next != NULL && ty->tlist->next->type == TN_FUNCTION) { ty->tlist = ty->tlist->next->next; } ret = type_to_text(ty); ty->tlist = orig_tlist; } else { ret = type_to_text(ty); } return ret; } char * type_to_text(struct type *dt) { struct type_node *t; char *buf = NULL; char *p = NULL; size_t size = 0; size_t used = 0; int i; for (t = dt->tlist; t != NULL; t = t->next) { switch (t->type) { case TN_ARRAY_OF: case TN_VARARRAY_OF: make_room(&buf, &size, used + 64); used += sprintf(buf+used, "an array of %d ", (int)t->arrarg_const); break; case TN_POINTER_TO: { char *quali = ""; if (t->ptrarg != 0) { switch (t->ptrarg) { case TOK_KEY_VOLATILE: quali = "volatile"; break; case TOK_KEY_CONST: quali = "constant"; break; case TOK_KEY_RESTRICT: quali = "restricted"; break; } } make_room(&buf, &size, used + 32); used += sprintf(buf+used, "a %s pointer to ", quali); break; } case TN_FUNCTION: make_room(&buf, &size, used + 32); used += sprintf(buf+used, "a function (with %d args) returning ", t->tfunc->nargs); break; } } #if 0 p = basic_type_names[dt->code - TY_MIN]; #endif for (i = 0; basic_type_names[i].name != NULL; ++i) { if (dt->code == basic_type_names[i].code) { p = basic_type_names[i].name; break; } } make_room(&buf, &size, strlen(p) + 5); used += sprintf(buf+used, "%s", p); if (dt->code == TY_STRUCT) { if (dt->tstruc && dt->tstruc->tag) { make_room(&buf, &size, used + strlen(dt->tstruc->tag) + 2); sprintf(buf+used, " %s", dt->tstruc->tag); } } return buf; } #ifndef PREPROCESSOR extern void put_ppc_llong(struct num *); /* * XXX same stupid size_t cross-compilaion bug as const_from_value().. * this stuff SUCKS!!! */ struct token * const_from_type(struct type *ty, int from_alignment, int extype, struct token *t) { struct token *ret = alloc_token(); size_t size; int size_t_size; #if 0 ret->type = TY_ULONG; /* XXX size_t */ #endif ret->type = backend->get_size_t()->code; if (from_alignment) { size = backend->get_align_type(ty); } else { size = backend->get_sizeof_type(ty, t); } /*ret->data = n_xmemdup(&size, sizeof size);*/ ret->data = n_xmalloc(16); /* XXX */ size_t_size = backend->get_sizeof_type(backend->get_size_t(), NULL); if (sizeof size == size_t_size) { memcpy(ret->data, &size, sizeof size); } else if (sizeof(int) == size_t_size) { unsigned int i = (unsigned int)size; memcpy(ret->data, &i, sizeof i); } else if (sizeof(long) == size_t_size) { unsigned long l = (unsigned long)size; memcpy(ret->data, &l, sizeof l); } else if (sizeof(long long) == size_t_size) { unsigned long long ll = (unsigned long long)size; memcpy(ret->data, &ll, sizeof ll); } else { unimpl(); } if (backend->abi == ABI_POWER64 && extype != EXPR_CONST && extype != EXPR_CONSTINIT /* What about EXPR_OPTCONSTINIT?! */ ) { struct num *n = n_xmalloc(sizeof *n); /* * XXX see definition of put_ppc_llong() for an * explanation of this mess */ n->type = ret->type; n->value = ret->data; put_ppc_llong(n); /*ret->data = llong_const;*/ ret->data2 = llong_const; } return ret; } /* * XXX this interface is ROTTEN!! * too easy to pass a ``size_t'' for value with ty=NULL by accident!! * * XXXX WOAH this was totally broken WRT cross-compilation! ``type'' * is interpreted as host type when dealing with ``value'', and as * target type too by making it the type of the token! Current ad-hoc * kludge sucks! */ struct token * const_from_value(void *value, struct type *ty) { struct token *ret = alloc_token(); size_t size; if (ty == NULL) { ret->type = TY_INT; size = backend->get_sizeof_type(make_basic_type( TY_INT), NULL);; } else { ret->type = ty->code; size = backend->get_sizeof_type(ty, NULL); } if (ty && (IS_LONG(ty->code) || IS_LLONG(ty->code))) { if (sizeof(long) == size) { /* Size matches - nothing to do */ ; } else { static long long llv; llv = *(int *)value; value = &llv; } } ret->data = n_xmemdup(value, size); if (backend->abi == ABI_POWER64 && ty != NULL && is_integral_type(ty) && size == 8) { struct num *n = n_xmalloc(sizeof *n); static struct num nullnum; *n = nullnum; n->type = ret->type; n->value = ret->data; put_ppc_llong(n); ret->data2 = llong_const; } return ret; } /* * Construct a floating point constant token of type ``type'' * containing ``value'' (which must be a string parsable by sscanf().) */ struct token * fp_const_from_ascii(const char *value, int type) { struct num *n; struct token *ret = n_xmalloc(sizeof *ret); n = cross_scan_value(value, type, 0, 0, 1); if (n == NULL) { return NULL; } /* * XXX token.data is ``struct ty_float'', not * ``struct num''. Because the interfaces are * still messed up, we have to get the current * ty_float corresponding to ``n'' from the * float list. This SUCKS! */ ret->data = float_const/*n->value*/; ret->type = type; ret->ascii = n_xstrdup(value); return ret; } struct token * const_from_string(const char *value) { struct token *ret = alloc_token(); struct type *ty; struct ty_string *tmpstr; tmpstr = alloc_ty_string(); tmpstr->size = strlen(value) + 1; tmpstr->str = n_xmemdup(value, tmpstr->size); tmpstr->is_wide_char = 0; ret->type = TOK_STRING_LITERAL; ty = make_array_type(tmpstr->size, tmpstr->is_wide_char); tmpstr->ty = ty; ret->data = tmpstr; return ret; } int is_integral_type(struct type *t) { if (t->tlist != NULL) { return 0; } if (IS_CHAR(t->code) || IS_SHORT(t->code) || IS_INT(t->code) || IS_LONG(t->code) || IS_LLONG(t->code) || t->code == TY_ENUM) { return 1; } return 0; } int is_floating_type(struct type *t) { if (t->tlist != NULL) { return 0; } if (t->code == TY_FLOAT || t->code == TY_DOUBLE || t->code == TY_LDOUBLE) { return 1; } return 0; } int is_arithmetic_type(struct type *t) { if (t->tlist != NULL) { return 0; } if (IS_FLOATING(t->code) || is_integral_type(t)) { return 1; } return 0; } int is_array_type(struct type *t) { struct type_node *tn; if (t->tlist == NULL) { return 0; } for (tn = t->tlist; tn != NULL; tn = tn->next) { if (tn->type != TN_ARRAY_OF) { return 0; } else { break; } } return 1; } int is_basic_agg_type(struct type *t) { if (t->tlist == NULL) { if (t->code == TY_STRUCT || t->code == TY_UNION) { return 1; } } else if (is_array_type(t)) { return 1; } return 0; } int is_scalar_type(struct type *t) { if (t->tlist == NULL && (t->code == TY_STRUCT || t->code == TY_UNION || t->code == TY_VOID)) { return 0; } return 1; } int is_arr_of_ptr(struct type *t) { struct type_node *tn; for (tn = t->tlist; tn != NULL; tn = tn->next) { if (tn->type == TN_POINTER_TO) { return 1; } else if (tn->type == TN_FUNCTION) { return 0; } } return 0; } int is_nullptr_const(struct token *constant, struct type *ty) { if (IS_INT(ty->code) && *(unsigned *)constant->data == 0) { return 1; } else if (IS_LONG(ty->code) && *(unsigned long *)constant->data == 0) { return 1; } return 0; } /* * The source type must be passed with a vreg because we need the null * pointer constant and object backing information it gives us */ int check_types_assign( struct token *t, struct type *left, struct vreg *right, int to_const_ok, int silent) { struct type *ltype = left; struct type *rtype = right->type; if (ltype == NULL || rtype == NULL) { printf("attempt to assign to/from value without type :(\n"); abort(); } /* * 01/26/08: Changed this to call is_modifyable(), which also * rules out assignment to const-qualified pointers */ /*if (ltype->tlist == NULL && ltype->is_const && !to_const_ok) { */ if (!is_modifyable(ltype) && !to_const_ok) { if (!silent) { errorfl(t, "Assignment to const-qualified object"); } return -1; } if (is_arithmetic_type(ltype)) { if (!is_arithmetic_type(rtype)) { if (ltype->code == TY_BOOL && rtype->tlist != NULL) { /* ok - pointer to bool */ return 0; } else { int allow = 0; if (rtype->tlist != NULL && is_integral_type(ltype)) { /* * 03/09/09: Give in and allow pointer * to integer assignment with a warning */ allow = 1; } if (!silent) { if (allow) { warningfl(t, "Assignment from non-arithmetic to " "arithmetic type"); } else { errorfl(t, "Assignment from non-arithmetic to " "arithmetic type"); } } if (allow) { return 0; } else { return -1; } } } else if (ltype->sign != rtype->sign && !right->from_const) { /* * Do not warn about signedness differences if the * right side is a constant! */ #if 0 /* XXX Too verbose */ warningfl(t, "Assignment from type of differing signedness"); #endif return 0; } return 0; } else if (ltype->tlist == NULL) { /* Must be struct/union */ if (rtype->tlist != NULL) { if (ltype->code == TY_BOOL) { return 0; } else { if (!silent) { /* 06/01/08: Warn, not error */ warningfl(t, "Assignment from pointer to non-pointer type"); } /* * 07/20/08: The return below was commented out! * That's wrong because pointer to struct will * compare assignable to struct * Why was this removed? */ return -1; } } else if (ltype->code == TY_BOOL) { return 0; /* _Bool b = ptr; is OK */ } else if (rtype->code != ltype->code || rtype->tstruc != ltype->tstruc) { if (!silent) { errorfl(t, "Assignment from incompatible type"); } return -1; } else { return 0; } } else { /* Left is pointer of some sort */ if (right->is_nullptr_const) { ; /* ok */ } else if (rtype->tlist == NULL) { if (!silent) { warningfl(t, "Assignment from non-pointer " "to pointer type"); } /* return -1;*/ } else if (rtype->code == TY_VOID && rtype->tlist->type == TN_POINTER_TO && rtype->tlist->next == NULL) { ; /* void pointer - compatible */ } else if (ltype->code == TY_VOID && ltype->tlist->type == TN_POINTER_TO && ltype->tlist->next == NULL) { ; /* void pointer - compatible */ } else if (compare_tlist(ltype->tlist, rtype->tlist, CMPTY_ARRAYPTR)) { if (!silent) { warningfl(t, "Assignment from incompatible pointer type" " (illegal in ISO C, and very " "probably not what you want)"); } else { /* * This is only used for transparent_union * right now... in that case we do not want * to allow this assignment because type- * checking is the whole point of that * language extension */ return -1; } return 0; } else if (!IS_CONST(ltype->flags) && IS_CONST(rtype->flags)) { if (!silent) { warningfl(t, "Assignment from const-qualified type " "to unqualified one"); } return 0; } else if (rtype->code != ltype->code && rtype->code != TY_VOID && ltype->code != TY_VOID /* XXX */ && (!IS_CHAR(ltype->code) || !IS_CHAR(rtype->code))) { if (type_without_sign(ltype->code) == type_without_sign(rtype->code)) { if (!silent) { warningfl(t, "Assignment from pointer of " "differing signedness"); } else { return -1; } return 0; } else { if (!silent) { warningfl(t, "Assignment from incompatible " "pointer type (illegal in ISO C, and " "very probably not what you want)"); } else { return -1; } #if 0 return -1; #endif return 0; } } else if (IS_CONST(ltype->flags) && !IS_CONST(rtype->flags) && ltype->tlist != NULL && ltype->tlist->next != NULL) { if (!silent) { warningfl(t, "ISO C does not allow assignment " "from `T **' to `const T **' without a " "cast (otherwise invalid code like " "`const char dont_modify; char *p; const " "char **cp = &p; *cp = &dont_modify; *p = 0;' " "would pass without warning)"); } return 0; } } return 0; } struct type * addrofify_type(struct type *ty) { struct type *ret = n_xmemdup(ty, sizeof *ty); struct type_node *tn; copy_tlist(&ret->tlist, ret->tlist); tn = alloc_type_node(); tn->type = TN_POINTER_TO; tn->next = ret->tlist; ret->tlist = tn; return ret; } int type_without_sign(int code) { int rc = code; if (code == TY_UCHAR) rc = TY_CHAR; else if (code == TY_USHORT) rc = TY_SHORT; else if (code == TY_UINT) rc = TY_INT; else if (code == TY_ULONG) rc = TY_LONG; else if (code == TY_ULLONG) rc = TY_LLONG; return rc; }
void printercache_process(STREAM s) { uint32 type, printer_length, driver_length, printer_unicode_length, blob_length; char device_name[9], printer[256], driver[256]; in_uint32_le(s, type); switch (type) { case 4: /* rename item */ in_uint8(s, printer_length); in_uint8s(s, 0x3); /* padding */ in_uint8(s, driver_length); in_uint8s(s, 0x3); /* padding */ /* NOTE - 'driver' doesn't contain driver, it contains the new printer name */ rdp_in_unistr(s, printer, sizeof(printer), printer_length); rdp_in_unistr(s, driver, sizeof(driver), driver_length); printercache_rename_blob(printer, driver); break; case 3: /* delete item */ in_uint8(s, printer_unicode_length); in_uint8s(s, 0x3); /* padding */ rdp_in_unistr(s, printer, sizeof(printer), printer_unicode_length); printercache_unlink_blob(printer); break; case 2: /* save printer data */ in_uint32_le(s, printer_unicode_length); in_uint32_le(s, blob_length); if (printer_unicode_length < 2 * 255) { rdp_in_unistr(s, printer, sizeof(printer), printer_unicode_length); printercache_save_blob(printer, s->p, blob_length); } break; case 1: /* save device data */ in_uint8a(s, device_name, 5); /* get LPTx/COMx name */ /* need to fetch this data so that we can get the length of the packet to store. */ in_uint8s(s, 0x2); /* ??? */ in_uint8s(s, 0x2) /* pad?? */ in_uint32_be(s, driver_length); in_uint32_be(s, printer_length); in_uint8s(s, 0x7) /* pad?? */ /* next is driver in unicode */ /* next is printer in unicode */ /* TODO: figure out how to use this information when reconnecting */ /* actually - all we need to store is the driver and printer */ /* and figure out what the first word is. */ /* rewind stream so that we can save this blob */ /* length is driver_length + printer_length + 19 */ /* rewind stream */ s->p = s->p - 19; printercache_save_blob(device_name, s->p, driver_length + printer_length + 19); break; default: unimpl("RDPDR Printer Cache Packet Type: %d\n", type); break; } }