📄 tclbinary.c
字号:
} if (count == BINARY_ALL) { count = length - offset; } else { if (count == BINARY_NOCOUNT) { count = 1; } if (count > (length - offset)) { goto done; } } str = buffer + offset; size = count; /* * Trim trailing nulls and spaces, if necessary. */ if (cmd == 'A') { while (size > 0) { if (str[size-1] != '\0' && str[size-1] != ' ') { break; } size--; } } valuePtr = Tcl_NewStringObj(str, size); resultPtr = Tcl_ObjSetVar2(interp, objv[arg++], NULL, valuePtr, TCL_LEAVE_ERR_MSG | TCL_PARSE_PART1); if (resultPtr == NULL) { Tcl_DecrRefCount(valuePtr); /* unneeded */ return TCL_ERROR; } offset += count; break; case 'b': case 'B': { char *dest; if (arg >= objc) { goto badIndex; } if (count == BINARY_ALL) { count = (length - offset)*8; } else { if (count == BINARY_NOCOUNT) { count = 1; } if (count > (length - offset)*8) { goto done; } } str = buffer + offset; valuePtr = Tcl_NewObj(); Tcl_SetObjLength(valuePtr, count); dest = Tcl_GetStringFromObj(valuePtr, NULL); if (cmd == 'b') { for (i = 0; i < count; i++) { if (i % 8) { value >>= 1; } else { value = *str++; } *dest++ = (char) ((value & 1) ? '1' : '0'); } } else { for (i = 0; i < count; i++) { if (i % 8) { value <<= 1; } else { value = *str++; } *dest++ = (char) ((value & 0x80) ? '1' : '0'); } } resultPtr = Tcl_ObjSetVar2(interp, objv[arg++], NULL, valuePtr, TCL_LEAVE_ERR_MSG | TCL_PARSE_PART1); if (resultPtr == NULL) { Tcl_DecrRefCount(valuePtr); /* unneeded */ return TCL_ERROR; } offset += (count + 7 ) / 8; break; } case 'h': case 'H': { char *dest; int i; static char hexdigit[] = "0123456789abcdef"; if (arg >= objc) { goto badIndex; } if (count == BINARY_ALL) { count = (length - offset)*2; } else { if (count == BINARY_NOCOUNT) { count = 1; } if (count > (length - offset)*2) { goto done; } } str = buffer + offset; valuePtr = Tcl_NewObj(); Tcl_SetObjLength(valuePtr, count); dest = Tcl_GetStringFromObj(valuePtr, NULL); if (cmd == 'h') { for (i = 0; i < count; i++) { if (i % 2) { value >>= 4; } else { value = *str++; } *dest++ = hexdigit[value & 0xf]; } } else { for (i = 0; i < count; i++) { if (i % 2) { value <<= 4; } else { value = *str++; } *dest++ = hexdigit[(value >> 4) & 0xf]; } } resultPtr = Tcl_ObjSetVar2(interp, objv[arg++], NULL, valuePtr, TCL_LEAVE_ERR_MSG | TCL_PARSE_PART1); if (resultPtr == NULL) { Tcl_DecrRefCount(valuePtr); /* unneeded */ return TCL_ERROR; } offset += (count + 1) / 2; break; } case 'c': size = 1; goto scanNumber; case 's': case 'S': size = 2; goto scanNumber; case 'i': case 'I': size = 4; goto scanNumber; case 'f': size = sizeof(float); goto scanNumber; case 'd': size = sizeof(double); /* fall through */ scanNumber: if (arg >= objc) { goto badIndex; } if (count == BINARY_NOCOUNT) { if ((length - offset) < size) { goto done; } valuePtr = ScanNumber(buffer+offset, cmd); offset += size; } else { if (count == BINARY_ALL) { count = (length - offset) / size; } if ((length - offset) < (count * size)) { goto done; } valuePtr = Tcl_NewObj(); str = buffer+offset; for (i = 0; i < count; i++) { elementPtr = ScanNumber(str, cmd); str += size; Tcl_ListObjAppendElement(NULL, valuePtr, elementPtr); } offset += count*size; } resultPtr = Tcl_ObjSetVar2(interp, objv[arg++], NULL, valuePtr, TCL_LEAVE_ERR_MSG | TCL_PARSE_PART1); if (resultPtr == NULL) { Tcl_DecrRefCount(valuePtr); /* unneeded */ return TCL_ERROR; } break; case 'x': if (count == BINARY_NOCOUNT) { count = 1; } if ((count == BINARY_ALL) || (count > (length - offset))) { offset = length; } else { offset += count; } break; case 'X': if (count == BINARY_NOCOUNT) { count = 1; } if ((count == BINARY_ALL) || (count > offset)) { offset = 0; } else { offset -= count; } break; case '@': if (count == BINARY_NOCOUNT) { goto badCount; } if ((count == BINARY_ALL) || (count > length)) { offset = length; } else { offset = count; } break; default: { char buf[2]; Tcl_ResetResult(interp); buf[0] = cmd; buf[1] = '\0'; Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "bad field specifier \"", buf, "\"", NULL); return TCL_ERROR; } } } /* * Set the result to the last position of the cursor. */ done: Tcl_ResetResult(interp); Tcl_SetLongObj(Tcl_GetObjResult(interp), arg - 4); break; } } return TCL_OK; badValue: Tcl_ResetResult(interp); Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "expected ", errorString, " string but got \"", errorValue, "\" instead", NULL); return TCL_ERROR; badCount: errorString = "missing count for \"@\" field specifier"; goto error; badIndex: errorString = "not enough arguments for all format specifiers"; goto error; error: Tcl_ResetResult(interp); Tcl_AppendToObj(Tcl_GetObjResult(interp), errorString, -1); return TCL_ERROR;}/* *---------------------------------------------------------------------- * * GetFormatSpec -- * * This function parses the format strings used in the binary * format and scan commands. * * Results: * Moves the formatPtr to the start of the next command. Returns * the current command character and count in cmdPtr and countPtr. * The count is set to BINARY_ALL if the count character was '*' * or BINARY_NOCOUNT if no count was specified. Returns 1 on * success, or 0 if the string did not have a format specifier. * * Side effects: * None. * *---------------------------------------------------------------------- */static intGetFormatSpec(formatPtr, cmdPtr, countPtr) char **formatPtr; /* Pointer to format string. */ char *cmdPtr; /* Pointer to location of command char. */ int *countPtr; /* Pointer to repeat count value. */{ /* * Skip any leading blanks. */ while (**formatPtr == ' ') { (*formatPtr)++; } /* * The string was empty, except for whitespace, so fail. */ if (!(**formatPtr)) { return 0; } /* * Extract the command character and any trailing digits or '*'. */ *cmdPtr = **formatPtr; (*formatPtr)++; if (**formatPtr == '*') { (*formatPtr)++; (*countPtr) = BINARY_ALL; } else if (isdigit(UCHAR(**formatPtr))) { (*countPtr) = strtoul(*formatPtr, formatPtr, 10); } else { (*countPtr) = BINARY_NOCOUNT; } return 1;}/* *---------------------------------------------------------------------- * * FormatNumber -- * * This routine is called by Tcl_BinaryObjCmd to format a number * into a location pointed at by cursor. * * Results: * A standard Tcl result. * * Side effects: * Moves the cursor to the next location to be written into. * *---------------------------------------------------------------------- */static intFormatNumber(interp, type, src, cursorPtr) Tcl_Interp *interp; /* Current interpreter, used to report * errors. */ int type; /* Type of number to format. */ Tcl_Obj *src; /* Number to format. */ char **cursorPtr; /* Pointer to index into destination buffer. */{ int value; double dvalue; char cmd = (char)type; if (cmd == 'd' || cmd == 'f') { /* * For floating point types, we need to copy the data using * memcpy to avoid alignment issues. */ if (Tcl_GetDoubleFromObj(interp, src, &dvalue) != TCL_OK) { return TCL_ERROR; } if (cmd == 'd') { memcpy((*cursorPtr), &dvalue, sizeof(double)); (*cursorPtr) += sizeof(double); } else { float fvalue; /* * Because some compilers will generate floating point exceptions * on an overflow cast (e.g. Borland), we restrict the values * to the valid range for float. */ if (fabs(dvalue) > (double)FLT_MAX) { fvalue = (dvalue >= 0.0) ? FLT_MAX : -FLT_MAX; } else { fvalue = (float) dvalue; } memcpy((*cursorPtr), &fvalue, sizeof(float)); (*cursorPtr) += sizeof(float); } } else { if (Tcl_GetIntFromObj(interp, src, &value) != TCL_OK) { return TCL_ERROR; } if (cmd == 'c') { *(*cursorPtr)++ = (char)(value & 0xff); } else if (cmd == 's') { *(*cursorPtr)++ = (char)(value & 0xff); *(*cursorPtr)++ = (char)((value >> 8) & 0xff); } else if (cmd == 'S') { *(*cursorPtr)++ = (char)((value >> 8) & 0xff); *(*cursorPtr)++ = (char)(value & 0xff); } else if (cmd == 'i') { *(*cursorPtr)++ = (char)(value & 0xff); *(*cursorPtr)++ = (char)((value >> 8) & 0xff); *(*cursorPtr)++ = (char)((value >> 16) & 0xff); *(*cursorPtr)++ = (char)((value >> 24) & 0xff); } else if (cmd == 'I') { *(*cursorPtr)++ = (char)((value >> 24) & 0xff); *(*cursorPtr)++ = (char)((value >> 16) & 0xff); *(*cursorPtr)++ = (char)((value >> 8) & 0xff); *(*cursorPtr)++ = (char)(value & 0xff); } } return TCL_OK;}/* *---------------------------------------------------------------------- * * ScanNumber -- * * This routine is called by Tcl_BinaryObjCmd to scan a number * out of a buffer. * * Results: * Returns a newly created object containing the scanned number. * This object has a ref count of zero. * * Side effects: * None. * *---------------------------------------------------------------------- */static Tcl_Obj *ScanNumber(buffer, type) char *buffer; /* Buffer to scan number from. */ int type; /* Format character from "binary scan" */{ int value; /* * We cannot rely on the compiler to properly sign extend integer values * when we cast from smaller values to larger values because we don't know * the exact size of the integer types. So, we have to handle sign * extension explicitly by checking the high bit and padding with 1's as * needed. */ switch ((char) type) { case 'c': value = buffer[0]; if (value & 0x80) { value |= -0x100; } return Tcl_NewLongObj((long)value); case 's': value = (((unsigned char)buffer[0]) + ((unsigned char)buffer[1] << 8)); goto shortValue; case 'S': value = (((unsigned char)buffer[1]) + ((unsigned char)buffer[0] << 8)); shortValue: if (value & 0x8000) { value |= -0x10000; } return Tcl_NewLongObj((long)value); case 'i': value = (((unsigned char)buffer[0]) + ((unsigned char)buffer[1] << 8) + ((unsigned char)buffer[2] << 16) + ((unsigned char)buffer[3] << 24)); goto intValue; case 'I': value = (((unsigned char)buffer[3]) + ((unsigned char)buffer[2] << 8) + ((unsigned char)buffer[1] << 16) + ((unsigned char)buffer[0] << 24)); intValue: /* * Check to see if the value was sign extended properly on * systems where an int is more than 32-bits. */ if ((value & (((unsigned int)1)<<31)) && (value > 0)) { value -= (((unsigned int)1)<<31); value -= (((unsigned int)1)<<31); } return Tcl_NewLongObj((long)value); case 'f': { float fvalue; memcpy(&fvalue, buffer, sizeof(float)); return Tcl_NewDoubleObj(fvalue); } case 'd': { double dvalue; memcpy(&dvalue, buffer, sizeof(double)); return Tcl_NewDoubleObj(dvalue); } } return NULL;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -