fastapi.c

Go to the documentation of this file.
00001 // $Id: fastapi_8c-source.html,v 1.2 2006/02/09 19:12:40 Daniel.May Exp $
00002 //
00003 // FIX Adapted for STreaming (sm) (FAST Protocol (sm)) 
00004 //
00005 // Copyright (c) 2005-2006, Pantor Engineering AB (http://www.pantor.com)
00006 // Copyright (c) 2005-2006, SpryWare LLC (http://www.spryware.com)
00007 // Copyright (c) 2005-2006, FIX Protocol Ltd (http://www.fixprotocol.org)
00008 // All Rights Reserved.
00009 //
00010 // This work is distributed under the W3C® Software License [1] in the
00011 // hope that it will be useful, but WITHOUT ANY WARRANTY; without even the
00012 // implied warranty of MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS 
00013 // FOR A PARTICULAR PURPOSE.
00014 //
00015 // [1] http://www.w3.org/Consortium/Legal/2002/copyright-software-20021231
00016 // [FPL's Intellectual Property details] http://www.fixprotocol.org/ip
00017 // [FAST Protocol details] http://www.fixprotocol.org/fast
00018 // [FAST Protocol credits] http://fixprotocol.org/fastcredits
00019 
00020 #include "common.h"
00021 #include "fastapi.h"
00022 
00024 
00025 static void reset_buffer (fast_buffer_t* buffer)
00026 {
00027    buffer->head = buffer->data;
00028    buffer->tail = buffer->data;
00029    buffer->end  = buffer->data + sizeof (buffer->data);
00030 }
00031 
00032 static void init_buffer (fast_buffer_t* buffer, int fd)
00033 {
00034    reset_buffer (buffer);
00035 
00036    buffer->fd = fd;
00037 }
00038 
00039 static inline int buffer_empty_p (fast_buffer_t* buffer)
00040 {
00041    return buffer->head >= buffer->tail;
00042 }
00043 
00044 static inline int get_buffer_left (fast_buffer_t* buffer)
00045 {
00046    return buffer->end - buffer->tail;
00047 }
00048 
00049 static inline int get_buffer_size (fast_buffer_t* buffer)
00050 {
00051    return buffer->end - buffer->data;
00052 }
00053 
00054 static inline int get_buffer_used (fast_buffer_t* buffer)
00055 {
00056    return buffer->tail - buffer->head;
00057 }
00058 
00060 
00061 static inline u32 get_tag_op (u32 tag)
00062 {
00063    return (tag >> TAG_SHIFT_OP) & TAG_MAX_OP;
00064 }
00065 
00066 static inline u32 get_tag_slot (u32 tag)
00067 {
00068    return (tag >> TAG_SHIFT_SLOT) & TAG_MAX_SLOT;
00069 }
00070 
00071 static inline u32 get_tag_tid (u32 tag)
00072 {
00073    return (tag >> TAG_SHIFT_TID) & TAG_MAX_TID;
00074 }
00075 
00076 static inline u32 get_tag_type (u32 tag)
00077 {
00078    return (tag >> TAG_SHIFT_TYPE) & TAG_MAX_TYPE;
00079 }
00080 
00081 static inline fast_cv_t* cv_get_tag_state (fast_codec_t* codec, u32 tag)
00082 {
00083    u32 slot = get_tag_tid (tag);
00084 
00085    return & codec->cv [slot];
00086 }
00087 
00088 static inline i32* cv_get_i32_values (fast_codec_t* codec, u32 tag)
00089 {
00090    return cv_get_tag_state (codec, tag)->i32_values;
00091 }
00092 
00093 static inline u32* cv_get_u32_values (fast_codec_t* codec, u32 tag)
00094 {
00095    return cv_get_tag_state (codec, tag)->u32_values;
00096 }
00097 
00098 static inline u8** cv_get_str_values (fast_codec_t* codec, u32 tag)
00099 {
00100    return cv_get_tag_state (codec, tag)->str_values;
00101 }
00102 
00103 static inline u32* cv_get_valid_values (fast_codec_t* codec, u32 tag)
00104 {
00105    return cv_get_tag_state (codec, tag)->valid;
00106 }
00107 
00109 
00110 static inline i32 cv_get_i32 (fast_codec_t* codec, u32 tag)
00111 {
00112    return cv_get_i32_values (codec, tag) [get_tag_slot (tag)];
00113 }
00114 
00115 static inline u32 cv_get_u32 (fast_codec_t* codec, u32 tag)
00116 {
00117    return cv_get_u32_values (codec, tag) [get_tag_slot (tag)];
00118 }
00119 
00120 static inline u8* cv_get_str (fast_codec_t* codec, u32 tag)
00121 {
00122    u8** str_values = cv_get_str_values (codec, tag);
00123    u32 slot = get_tag_slot (tag);
00124 
00125    if (str_values [slot] == NULL)
00126    {
00127       str_values [slot] = malloc (1024);
00128       assert (str_values [slot] != NULL);
00129       strcpy ((char*) str_values [slot], "");
00130    }
00131 
00132    return str_values [slot];
00133 }
00134 
00136 
00137 static inline void cv_set_valid (fast_codec_t* codec, u32 tag)
00138 {
00139    cv_get_valid_values (codec, tag) [get_tag_slot (tag)] = 1;
00140 }
00141 
00142 static inline int cv_is_valid (fast_codec_t* codec, u32 tag)
00143 {
00144    return cv_get_valid_values (codec, tag) [get_tag_slot (tag)] != 0;
00145 }
00146 
00148 
00149 static inline int cv_eq_i32 (fast_codec_t* codec, u32 tag, i32 data)
00150 {
00151    return cv_is_valid (codec, tag) && cv_get_i32 (codec, tag) == data;
00152 }
00153 
00154 static inline int cv_eq_u32 (fast_codec_t* codec, u32 tag, u32 data)
00155 {
00156    return cv_is_valid (codec, tag) && cv_get_u32 (codec, tag) == data;
00157 }
00158 
00159 static inline int cv_eq_str (fast_codec_t* codec, u32 tag, u8* data, int size)
00160 {
00161    u8* cp = cv_get_str (codec, tag);
00162 
00163    // Invalid or not the same length
00164    // Fixme: cp [size] != '\0' not a valid test?
00165    if (cv_is_valid (codec, tag) == 0 || cp [size] != '\0')
00166       return 0;
00167 
00168    return memcmp (cp, data, size) == 0;
00169 }
00170 
00172 
00174 
00175 static inline void cv_set_i32 (fast_codec_t* codec, u32 tag, i32 data)
00176 {
00177    cv_get_i32_values (codec, tag) [get_tag_slot (tag)] = data;
00178    cv_set_valid (codec, tag);
00179 }
00180 
00182 
00183 static inline void cv_set_u32 (fast_codec_t* codec, u32 tag, u32 data)
00184 {
00185    cv_get_u32_values (codec, tag) [get_tag_slot (tag)] = data;
00186    cv_set_valid (codec, tag);
00187 }
00188 
00190 
00191 static inline void cv_set_str (fast_codec_t* codec, u32 tag,
00192                                u8* data, int size)
00193 {
00194    u8* cp = cv_get_str (codec, tag);
00195 
00196    memcpy (cp, data, size);
00197    cp [size] = '\0';
00198 
00199    cv_set_valid (codec, tag);
00200 }
00202 
00203 static int u32_to_size (u32 data)
00204 {
00205    if (data < 0x00000080) return 1; // 128
00206    if (data < 0x00004000) return 2; // 16384
00207    if (data < 0x00200000) return 3; // 2097152
00208    if (data < 0x10000000) return 4; // 268435456
00209 
00210    return 5;
00211 }
00212 
00213 static int i32_to_size (i32 data)
00214 {
00215    if (data < 0)
00216    {
00217       if (data >= 0xffffffc0) return 1; // -64
00218       if (data >= 0xffffe000) return 2; // -8192
00219       if (data >= 0xfff00000) return 3; // -1048576
00220       if (data >= 0xf8000000) return 4; // -124317728
00221    }
00222    else
00223    {
00224       if (data <  0x00000040) return 1; // 64
00225       if (data <  0x00002000) return 2; // 8192
00226       if (data <  0x00100000) return 3; // 1048576
00227       if (data <  0x08000000) return 4; // 134217728
00228    }
00229    return 5;
00230 }
00231 
00233 
00234 static const char* format_error_code (fast_error_t code)
00235 {
00236    switch (code)
00237    {
00238     case FAST_ERR_NONE:     return "none";
00239     case FAST_ERR_CODEC:    return "bad codec";
00240     case FAST_ERR_SIZE:     return "size error";
00241     case FAST_ERR_VALUE:    return "missing value";
00242     case FAST_ERR_TAG_OP:   return "tag op unsupported";
00243     case FAST_ERR_TAG_TYPE: return "bad tag type";
00244     case FAST_ERR_CALL_SEQ: return "bad call sequence";
00245     case FAST_ERR_IO:       return "I/O library error";
00246     default:                return "??";
00247    }
00248 }
00249 
00250 static const char* format_tag_op (fast_op_t op)
00251 {
00252    static char buffer [32];
00253 
00254    switch (op)
00255    {
00256     case FAST_OP_NONE:  return "NONE";
00257     case FAST_OP_COPY:  return "COPY";
00258     case FAST_OP_INCR:  return "INCR";
00259     case FAST_OP_DELTA: return "DELTA";
00260 
00261     default:
00262       snprintf (buffer, sizeof (buffer), "%u", op);
00263       return buffer;
00264    }
00265 }
00266 
00267 static const char* format_tag_type (fast_type_t type)
00268 {
00269    static char buffer [32];
00270 
00271    switch (type)
00272    {
00273     case FAST_TYPE_NULL: return "NULL";
00274     case FAST_TYPE_U32:  return "U32";
00275     case FAST_TYPE_I32:  return "I32";
00276     case FAST_TYPE_STR:  return "STR";
00277 
00278     default:
00279       snprintf (buffer, sizeof (buffer), "%u", type);
00280       return buffer;
00281    }
00282 }
00283 
00285 
00286 static int set_err (const char* fn, fast_codec_t* codec,
00287                      fast_tag_t tag, fast_error_t code,
00288                      const char* format, ...)
00289 {
00290    char buffer [1024];
00291    va_list ap;
00292 
00293    codec->error->fn   = fn;
00294    codec->error->tag  = tag;
00295    codec->error->code = code;
00296 
00297    va_start (ap, format);
00298    vsnprintf (buffer, sizeof (buffer), format, ap);
00299    va_end   (ap);
00300 
00301    if (codec->error->text != NULL)
00302       free (codec->error->text);
00303 
00304    codec->error->text = malloc (strlen (buffer) + 1);
00305    strcpy (codec->error->text, buffer);
00306 
00307    if (codec->verbose >= 1)
00308       fprintf (stderr, "error: %s\n", fast_error_string (codec));
00309 
00310    return -1;
00311 }
00312 
00313 static int check_codec (const char* fn, fast_codec_t* codec)
00314 {
00315    if (codec == NULL)
00316    {
00317       fprintf (stderr, "error: [%s] NULL codec\n", fn);
00318       return -1;
00319    }
00320    if (codec->magic != FAST_CODEC_MAGIC)
00321       return set_err (fn, codec, -1, FAST_ERR_CODEC,
00322                       "bad codec magic number");
00323 
00324    return 0;
00325 }
00326 
00327 static int check_type (const char* fn, fast_codec_t* codec,
00328                        fast_tag_t tag, u32 type)
00329 {
00330    if (get_tag_type (tag) != type)
00331       return set_err (fn, codec, tag, FAST_ERR_TAG_TYPE,
00332                       "type=%s (%s expected)",
00333                       format_tag_type (get_tag_type (tag)),
00334                       format_tag_type (type));
00335 
00336    return 0;
00337 }
00338 
00339 static int bad_op_error (const char* fn, fast_codec_t* codec, fast_tag_t tag)
00340 {
00341    return set_err (fn, codec, tag, FAST_ERR_TAG_OP, "");
00342 }
00343                                 
00344 static int value_error (const char* fn, fast_codec_t* codec, fast_tag_t tag)
00345 {
00346    return set_err (fn, codec, tag, FAST_ERR_VALUE, "");
00347 }
00348 
00350 
00351 const char* fast_error_string (fast_codec_t* codec)
00352 {
00353    fast_tag_t tag = codec->error->tag;
00354 
00355    static char buffer [1024];
00356 
00357    snprintf (buffer, sizeof (buffer), "[%s] %s|%s|%u|%u %s: %s",
00358              codec->error->fn,
00359              format_tag_type (get_tag_type (tag)),
00360              format_tag_op (get_tag_op (tag)),
00361              get_tag_tid (tag),
00362              get_tag_slot (tag),
00363              format_error_code (codec->error->code),
00364              codec->error->text ? codec->error->text : "");
00365 
00366    return buffer;
00367 }
00368 
00369 int fast_print_error (fast_codec_t* codec, FILE* fp)
00370 {
00371    const char* msg = fast_error_string (codec);
00372 
00373    fprintf (fp, "%s\n", msg);
00374    return 0;
00375 }
00376 
00378 
00380 
00381 static int get_pmap (fast_codec_t* codec, fast_tag_t tag)
00382 {
00383    u32 pos = get_tag_slot (tag);
00384 
00385    // Optimization: Don't range check pos separately
00386    // We only need to check for the current size.
00387    if (pos >= codec->pmap->size)
00388       return 0;
00389 
00390    return codec->pmap->bits [pos];
00391 }
00392 
00394 
00395 static void reset_pmap (fast_codec_t* codec)
00396 {
00397    // Fixme: Consider memset'ing to max_pos.
00398    memset (codec->pmap->bits, 0, MAX_PMAP_BITS);
00399    codec->pmap->max_pos = 0;
00400 }
00401 
00403 
00404 static int set_pmap (fast_codec_t* codec, fast_tag_t tag)
00405 {
00406    u32 pos = get_tag_slot (tag);
00407 
00408    if (pos > codec->pmap->max_pos)
00409    {
00410       // Optimization: Only range check pos if pos
00411       // is larger than the current max_pos
00412       if (pos >= MAX_PMAP_BITS)
00413          return set_err (FUNCTION, codec, tag, FAST_ERR_SIZE,
00414                          "pmap slot=%d (< %d expected)",
00415                          pos, MAX_PMAP_BITS);
00416 
00417       codec->pmap->max_pos = pos;
00418    }
00419    codec->pmap->bits [pos] = 1;
00420    return 0;
00421 }
00422 
00423 static u32 bit_mask [8] = { 64, 32, 16, 8, 4, 2, 1, 0 };
00424 
00425 // emit_pmap copies the pmap into the data buffer
00426 // and returns the size of the pmap
00427 
00429 
00430 static int emit_pmap (fast_codec_t* codec, u8* data)
00431 {
00432    int bytes = align7 (codec->pmap->max_pos + 1); // get map size in bytes
00433    int offset;
00434    int p1;
00435 
00436    // pack slots from map->bits (seven at a time) into
00437    // data to form a STOP bit coded field.
00438 
00439    for (p1 = 0, offset = 0 ; p1 < bytes ; p1 ++, offset += 7)
00440    {
00441       u8* bits = & codec->pmap->bits [offset];
00442       u32 temp = 0;
00443       int p2;
00444 
00445       for (p2 = 0 ; p2 < 7 ; p2 ++) // pack 7 slot into temp
00446       {
00447          if (bits [p2] > 0)
00448             temp |= bit_mask [p2];
00449       }
00450 
00451       data [p1] = temp;
00452    }
00453 
00454    data [bytes - 1] |= 0x80; // Set the STOP bit
00455    return bytes;
00456 }
00457 
00459 
00461 
00462 static inline void emit_byte (fast_codec_t* codec, u8 data)
00463 {
00464    *codec->msg->tail ++ = data;
00465 }
00466 
00468 
00471 
00472 static inline  int check_msg_avail (const char* fn, fast_codec_t* codec,
00473                                     fast_tag_t tag, int size)
00474 {
00475    if (get_buffer_left (codec->msg) < size)
00476       return set_err (fn, codec, tag, FAST_ERR_SIZE,
00477                       "message buffer overflow avail=%d needed=%d",
00478                       get_buffer_left (codec->msg), size);
00479    return 0;
00480 }
00481 
00483 
00485 
00486 static int emit_i32 (fast_codec_t* codec, fast_tag_t tag, i32 data)
00487 {
00488    int size = i32_to_size (data);
00489 
00490    // Check buffer space once, not for every byte
00491    if (check_msg_avail (FUNCTION, codec, tag, size) < 0)
00492       return -1;
00493 
00494    switch (size)
00495    {
00496       // Shifts are arithmetic (signed)
00497       // The sign bit of data will be copied on right shifts
00498     case 5: emit_byte (codec, (data >> 28) & 0x7f);
00499     case 4: emit_byte (codec, (data >> 21) & 0x7f);
00500     case 3: emit_byte (codec, (data >> 14) & 0x7f);
00501     case 2: emit_byte (codec, (data >>  7) & 0x7f);
00502     case 1: emit_byte (codec, (data & 0x7f) | 0x80);
00503       {
00504          int code = set_pmap (codec, tag);
00505 
00506          if (code < 0)
00507             return code;
00508       }
00509       return size;
00510 
00511     default:
00512       return set_err (FUNCTION, codec, tag, FAST_ERR_SIZE,
00513                       "size=%d data=%d (%08x)", size, data, data);
00514    }
00515 }
00516 
00518 
00519 static int emit_u32 (fast_codec_t* codec, fast_tag_t tag, u32 data)
00520 {
00521    int size = u32_to_size (data);
00522 
00523    // Check buffer space once, not for every byte
00524    if (check_msg_avail (FUNCTION, codec, tag, size) < 0)
00525       return -1;
00526 
00527    switch (size)
00528    {
00529       // Shifts are logical (unsigned)
00530     case 5: emit_byte (codec,  data >> 28);
00531     case 4: emit_byte (codec, (data >> 21) & 0x7f);
00532     case 3: emit_byte (codec, (data >> 14) & 0x7f);
00533     case 2: emit_byte (codec, (data >>  7) & 0x7f);
00534     case 1: emit_byte (codec, (data & 0x7f) | 0x80);
00535       {
00536          int code = set_pmap (codec, tag);
00537 
00538          if (code < 0)
00539             return code;
00540       }
00541       return size;
00542 
00543     default:
00544       return set_err (FUNCTION, codec, tag, FAST_ERR_SIZE,
00545                       "size=%d data=%d (%08x)", size, data, data);
00546    }
00547 }
00548 
00550 
00551 static int emit_str (fast_codec_t* codec, fast_tag_t tag, u8* data, int size)
00552 {
00553    // Zero length strings cannot be encoded
00554    if (size <= 0)
00555       return set_err (FUNCTION, codec, tag, FAST_ERR_SIZE,
00556                       "size=%d (>0 expected)", size);
00557 
00558    // Check buffer space once, not for every byte
00559    if (check_msg_avail (FUNCTION, codec, tag, size) < 0)
00560       return -1;
00561 
00562    {
00563       int p1;
00564 
00565       for (p1 = 0 ; p1 < size - 1 ; p1 ++)
00566          emit_byte (codec, data [p1]);
00567 
00568       emit_byte (codec, data [p1] | 0x80); // Last byte
00569    }
00570 
00571    {
00572       int code = set_pmap (codec, tag);
00573 
00574       if (code < 0)
00575          return code;
00576    }
00577    return size;
00578 }
00579 
00581 
00583 
00584 static int parse_bytes (fast_codec_t* codec, u8* data, int size)
00585 {
00586    int p1;
00587 
00588    // Fixme: Filler may be other than space?
00589    memset (data, 0, size);
00590 
00591    for (p1 = 0 ; p1 < size ; p1 ++)
00592    {
00593       u8 temp;
00594 
00595       fast_buffer_t* input = codec->input;
00596 
00597       if (buffer_empty_p (input))
00598       {
00599          int bytes;
00600 
00601          if (codec->skip_io == 1)
00602             return -1;
00603 
00604          bytes = read (input->fd, input->data, get_buffer_size (input));
00605 
00606          if (bytes <= 0)
00607          {
00608             if (bytes < 0)
00609                fprintf (stderr, "read failed: %s\n", strerror (errno));
00610 
00611             return -1;
00612          }
00613 
00614          input->head = input->data;
00615          input->tail = input->head + bytes;
00616 
00617       }
00618       temp = *input->head ++;
00619 
00620       data [p1] = temp;
00621 
00622       if (temp >= 0x80)
00623       {
00624          data [p1] &= 0x7f;
00625          return p1 + 1;
00626       }
00627    }
00628 
00629    // Fixme: calculate the real number of bytes in the field.
00630 
00631    return set_err (FUNCTION, codec, -1, FAST_ERR_SIZE,
00632                    "parse buffer overflow size=%d", size);
00633 }
00634 
00635 static int parse_pmap (fast_codec_t* codec)
00636 {
00637    fast_pmap_t* pmap = codec->pmap;
00638 
00639    u8  data [MAX_PMAP_BYTES];
00640 
00641    int bytes = parse_bytes (codec, data, MAX_PMAP_BYTES);
00642    int offset;
00643    int p1;
00644 
00645    if (bytes < 0)
00646       return bytes;
00647 
00648    for (p1 = 0, offset = 0 ; p1 < bytes ; p1 ++, offset += 7)
00649    {
00650       u32 temp = data [p1];
00651       int p2;
00652 
00653       for (p2 = 0 ; p2 < 7 ; p2 ++)
00654       {
00655          pmap->bits [offset + p2] = (temp & bit_mask [p2]) != 0;
00656       }
00657    }
00658 
00659    codec->pmap->size = 7 * bytes;
00660    return bytes;
00661 }
00662 
00663 #define SIGN_MASK_I32 0x40
00664 #define SIGN_MASK_U32 0x00
00665 
00666 static int parse_32 (fast_codec_t* codec, fast_tag_t tag,
00667                      u32* data, int sign_mask)
00668 {
00669    u8  buffer [5];
00670    int bytes;
00671    int p1;
00672    i32 temp;
00673 
00674    if (get_pmap (codec, tag) == 0)
00675       return 0;
00676 
00677    bytes = parse_bytes (codec, buffer, sizeof (buffer));
00678 
00679    if (bytes < 0)
00680       return bytes;
00681 
00682    temp = 0 - ((buffer [0] & sign_mask) != 0);
00683 
00684    for (p1 = 0 ; p1 < bytes ; p1 ++)
00685       temp = (temp << 7) | buffer [p1];
00686 
00687    *data = temp;
00688    return bytes;
00689 }
00690 
00692 
00694 
00695 static int parse_u32 (fast_codec_t* codec, fast_tag_t tag, u32* data)
00696 {
00697    return parse_32 (codec, tag, data, SIGN_MASK_U32);
00698 }
00699 
00701 
00702 static int parse_i32 (fast_codec_t* codec, fast_tag_t tag, i32* data)
00703 {
00704    return parse_32 (codec, tag, (u32*) data, SIGN_MASK_I32);
00705 }
00706 
00708 
00709 static int parse_str (fast_codec_t* codec, fast_tag_t tag, u8* data, int size)
00710 {
00711    return get_pmap (codec, tag) == 0 ? 0 : parse_bytes (codec, data, size);
00712 }
00713 
00715 // Decoder functions
00716 
00719 
00720 int fast_decode_new_msg (fast_codec_t* codec, fast_tag_t tag)
00721 {
00722    if (check_codec (FUNCTION, codec) < 0)
00723       return -1;
00724 
00725    return parse_pmap (codec);
00726 }
00727 
00729 
00730 int fast_decode_end_msg (fast_codec_t* codec, fast_tag_t tag)
00731 {
00732    if (check_codec (FUNCTION, codec) < 0)
00733       return -1;
00734 
00735    return 0;
00736 }
00737 
00739 
00741 
00742 int fast_decode_str (fast_codec_t* codec, fast_tag_t tag,
00743                      u8* data, int size)
00744 {
00745    fast_op_t op = get_tag_op (tag);
00746 
00747    int bytes;
00748 
00749    if (check_codec (FUNCTION, codec) < 0)
00750       return -1;
00751 
00752    if (check_type  (FUNCTION, codec, tag, FAST_TYPE_STR) < 0)
00753       return -1;
00754 
00755 #if 0
00756    // Fixme: Remove arbitrary limit
00757    if (size <= 0 || size >= 1024)
00758       return set_err (FUNCTION, codec, tag, FAST_ERR_SIZE,
00759                       "size=%d (1-1023 expected)", size);
00760 #endif
00761 
00762    switch (op)
00763    {
00764     case FAST_OP_NONE:
00765       bytes = parse_str (codec, tag, data, size);
00766 
00767       if (bytes < 0) // End of input
00768          return -1;
00769 
00770       if (bytes == 0)
00771          return value_error (FUNCTION, codec, tag);
00772 
00773       break;
00774 
00775     case FAST_OP_COPY:
00776       bytes = parse_str (codec, tag, data, size);
00777 
00778       if (bytes < 0)
00779          return -1;
00780 
00781       if (bytes > 0)
00782       {
00783          // Set current value
00784          cv_set_str (codec, tag, data, size);
00785       }
00786       else
00787       {
00788          // Copy current value
00789          memcpy (data, cv_get_str (codec, tag), size);
00790       }
00791       return size;
00792 
00793     case FAST_OP_INCR:
00794       return bad_op_error (FUNCTION, codec, tag);
00795 
00796     case FAST_OP_DELTA:
00797       {
00798          u8  buffer [1024];
00799          u8* curr = cv_get_str (codec, tag);
00800 
00801          u32 bytes = parse_str (codec, tag, buffer, size);
00802 
00803          if (cv_is_valid (codec, tag))
00804          {
00805             int temp;
00806 
00807             if (bytes > (u32)size)
00808                return set_err (FUNCTION, codec, tag, FAST_ERR_SIZE,
00809                                "oversized value %d > size=%d", bytes, size);
00810 
00811             // This implementation requires delta string field values
00812             // to be exactly the size of the field.
00813 
00814             temp = strlen ((char*) curr);
00815 
00816             if (temp != size)
00817                return set_err (FUNCTION, codec, tag, FAST_ERR_SIZE,
00818                                "size mismatch %d != %d", temp, size);
00819 
00820             // Replace (tail of) current value
00821             memcpy (curr + size - bytes, buffer, bytes);
00822          }
00823          else
00824          {
00825             // Set current value
00826             cv_set_str (codec, tag, buffer, bytes);
00827          }
00828 
00829          memcpy (data, cv_get_str (codec, tag), size);
00830       }
00831       break;
00832 
00833     default:
00834       bad_op_error (FUNCTION, codec, tag);
00835    }
00836    return 0;
00837 }
00838 
00840 
00842 
00843 int fast_decode_i32 (fast_codec_t* codec, fast_tag_t tag, i32* value)
00844 {
00845    fast_op_t op = get_tag_op (tag);
00846 
00847    i32 temp = 0;
00848    int bytes;
00849 
00850    if (check_codec (FUNCTION, codec) < 0)
00851       return -1;
00852 
00853    if (check_type  (FUNCTION, codec, tag, FAST_TYPE_I32) < 0)
00854       return -1;
00855 
00856    switch (op)
00857    {
00858     case FAST_OP_NONE: // Value must be present
00859       bytes = parse_i32 (codec, tag, & temp);
00860 
00861       if (bytes > 0)
00862       {
00863          cv_set_i32 (codec, tag, temp);
00864          break;
00865       }
00866 
00867       if (bytes < 0) // End of input
00868          return -1;
00869 
00870       return value_error (FUNCTION, codec, tag);
00871 
00872     case FAST_OP_COPY: // Use previous value if not present
00873       bytes = parse_i32 (codec, tag, & temp);
00874 
00875       if (bytes == 0) // No value - use previous [common case]
00876          break;
00877 
00878       if (bytes < 0) // End of input
00879          return -1;
00880 
00881       cv_set_i32 (codec, tag, temp);
00882       break;
00883 
00884     case FAST_OP_INCR: // Use previous value plus one if not present
00885       bytes = parse_i32 (codec, tag, & temp);
00886 
00887       if (bytes < 0) // End of input
00888          return -1;
00889 
00890       if (bytes == 0) // No value - use previous plus one
00891       {
00892          // Rule: The previous value must be valid
00893          if (cv_is_valid (codec, tag) == 0)
00894             return value_error (FUNCTION, codec, tag);
00895 
00896          temp = cv_get_i32 (codec, tag) + 1;
00897       }
00898 
00899       cv_set_i32 (codec, tag, (u32) temp);
00900       break;
00901 
00902     case FAST_OP_DELTA:
00903       if (cv_is_valid (codec, tag))
00904       {
00905          // Rule: delta defaults to ZERO if there is
00906          // no value present
00907 
00908          i32 delta;
00909 
00910          bytes = parse_i32 (codec, tag, & delta);
00911 
00912          if (bytes < 0) // error state already set
00913             return -1;
00914 
00915          if (bytes > 0)
00916          {
00917             temp = cv_get_i32 (codec, tag) + delta;
00918             cv_set_i32 (codec, tag, temp);
00919          }
00920       }
00921       else
00922       {
00923          // Rule: A field must be present it the
00924          // current value isn't valid
00925 
00926          bytes = parse_i32 (codec, tag, & temp);
00927 
00928          if (bytes < 0) // error state already set
00929             return -1;
00930 
00931          if (bytes == 0)
00932             return value_error (FUNCTION, codec, tag);
00933 
00934          cv_set_i32 (codec, tag, temp);
00935       }
00936       break;
00937 
00938     default:
00939       return bad_op_error (FUNCTION, codec, tag);
00940    }
00941 
00942    *value = cv_get_i32 (codec, tag);
00943    return 0;
00944 }
00945 
00947 
00949 
00950 int fast_decode_u32 (fast_codec_t* codec, fast_tag_t tag, u32* value)
00951 {
00952    fast_op_t op = get_tag_op (tag);
00953 
00954    u32 next = 0;
00955    int bytes;
00956 
00957    if (check_codec (FUNCTION, codec) < 0)
00958       return -1;
00959 
00960    if (check_type  (FUNCTION, codec, tag, FAST_TYPE_U32) < 0)
00961       return -1;
00962 
00963    switch (op)
00964    {
00965     case FAST_OP_NONE: // Value must be present
00966       bytes = parse_u32 (codec, tag, & next);
00967 
00968       if (bytes < 0) // End of input
00969          return -1;
00970 
00971       if (bytes == 0) // No data
00972          return value_error (FUNCTION, codec, tag);
00973 
00974       break;
00975 
00976     case FAST_OP_COPY: // Use previous value if not present
00977       bytes = parse_u32 (codec, tag, & next);
00978 
00979       if (bytes < 0) // End of input
00980          return -1;
00981 
00982       if (bytes == 0) // No value - use previous [common case]
00983       {
00984          if (cv_is_valid (codec, tag) == 0) // must be valid
00985             return value_error (FUNCTION, codec, tag);
00986          
00987          next = cv_get_u32 (codec, tag);
00988          break;
00989       }
00990       break;
00991 
00992     case FAST_OP_INCR: // use previous value plus one if not present
00993       bytes = parse_u32 (codec, tag, & next);
00994 
00995       if (bytes < 0) // End of input
00996          return -1;
00997 
00998       if (bytes == 0) // No value - use previous plus one
00999       {
01000          if (cv_is_valid (codec, tag) == 0) // must be valid
01001             return value_error (FUNCTION, codec, tag);
01002 
01003          next = cv_get_u32 (codec, tag) + 1;
01004       }
01005       break;
01006 
01007     case FAST_OP_DELTA:
01008       if (cv_is_valid (codec, tag))
01009       {
01010          // Rule: delta defaults to ZERO if there is
01011          // no value present
01012 
01013          i32 delta;
01014 
01015          bytes = parse_i32 (codec, tag, & delta);
01016          
01017          if (bytes < 0)
01018             return -1;
01019 
01020          next = cv_get_u32 (codec, tag);
01021 
01022          if (bytes > 0)
01023             next += delta;
01024       }
01025       else
01026       {
01027          // Rule: A field must be present if the
01028          // current value isn't valid
01029 
01030          bytes = parse_u32 (codec, tag, & next);
01031 
01032          if (bytes < 0)
01033             return -1;
01034 
01035          if (bytes == 0)
01036             return value_error (FUNCTION, codec, tag);
01037       }
01038       break;
01039 
01040     default:
01041       return bad_op_error (FUNCTION, codec, tag);
01042    }
01043 
01044    cv_set_u32 (codec, tag, next);
01045 
01046    *value = cv_get_u32 (codec, tag);
01047    return 0;
01048 }
01049 
01051 
01052 // flush_group moves the current pmap and body data to the output
01053 // buffer.
01054 // Currently, flush_group is only called from flush_msg, but will
01055 // also be called from other sites when repeating groups become
01056 // supported in this implementation. 
01057 
01058 
01061 //
01063 
01064 static int flush_group (fast_codec_t* codec)
01065 {
01066    fast_buffer_t* output = codec->output;
01067    fast_buffer_t* msg = codec->msg;
01068 
01069    int map_size;
01070 
01072 
01073    int size = get_buffer_used (msg);
01074    int need = MAX_PMAP_BYTES + size;
01075       
01076    if (get_buffer_left (output) <= need)
01077       return set_err (FUNCTION, codec, -1, FAST_ERR_SIZE,
01078                       "output buffer overflow left=%d need=%d",
01079                       get_buffer_left (output), need);
01080 
01082    map_size = emit_pmap (codec, output->tail);
01083 
01084    output->tail += map_size;
01085 
01087    memcpy (output->tail, msg->head, size);
01088 
01089    output->tail += size;
01090 
01092    reset_pmap (codec);
01093 
01094    reset_buffer (codec->msg);
01095    return 0;
01096 }
01097 
01100 
01101 static int flush_msg (fast_codec_t* codec)
01102 {
01103    fast_buffer_t* output = codec->output;
01104 
01105    flush_group (codec);
01106 
01107    if (codec->skip_io == 0)
01108    {
01109       if (write_n (output->fd, output->head, get_buffer_used (output)) < 0)
01110          return set_err (FUNCTION, codec, -1, FAST_ERR_IO,
01111                          "write_n failed: %s", strerror (errno));
01112 
01113       reset_buffer (output);
01114    }
01115 
01116    return 0;
01117 }
01118 
01120 
01121 // fast_encode_new_msg is called to setup encoding for a message.
01122 // It must not be called again without calling fast_encode_end_msg
01123 // in between.
01124 
01126 
01127 int fast_encode_new_msg (fast_codec_t* codec, fast_tag_t tag)
01128 {
01129    check_codec (FUNCTION, codec);
01130 
01131    if (codec->in_message != 0)
01132       return set_err (FUNCTION, codec, tag, FAST_ERR_CALL_SEQ,
01133                       "already in a message");
01134 
01135    codec->in_message = 1;
01136    codec->curr_tag = tag;
01137    return 0;
01138 }
01139 
01141 
01142 int fast_encode_end_msg (fast_codec_t* codec, fast_tag_t tag)
01143 {
01144    check_codec (FUNCTION, codec);
01145 
01146    if (codec->in_message == 0)
01147       return set_err (FUNCTION, codec, tag, FAST_ERR_CALL_SEQ,
01148                       "not in a message");
01149 
01150    codec->in_message = 0;
01151    return flush_msg (codec);
01152 }
01153 
01155 
01157 
01158 int fast_encode_i32 (fast_codec_t* codec, fast_tag_t tag, i32 value)
01159 {
01160    fast_op_t op = get_tag_op (tag);
01161 
01162    if (check_codec (FUNCTION, codec) < 0)
01163       return -1;
01164 
01165    if (check_type  (FUNCTION, codec, tag, FAST_TYPE_I32) < 0)
01166       return -1;
01167 
01168    switch (op)
01169    {
01170     case FAST_OP_NONE: // Always emit value
01171       break;
01172 
01173     case FAST_OP_COPY: // Emit value if not equal to previous value
01174       if (cv_eq_i32 (codec, tag, value))
01175          return 0;
01176       break;
01177 
01178     case FAST_OP_INCR: // Fixme: Implement
01179       return bad_op_error (FUNCTION, codec, tag);
01180 
01181     case FAST_OP_DELTA: // Fixme: Implement
01182       return bad_op_error (FUNCTION, codec, tag);
01183 
01184     default:
01185       return bad_op_error (FUNCTION, codec, tag);
01186    }
01187 
01188    cv_set_i32 (codec, tag, value);
01189    return emit_i32 (codec, tag, value);
01190 }
01191 
01192 static int find_char_delta_offset (u8* a, u8* b, int size)
01193 {
01194    int p1;
01195 
01196    for (p1 = 0 ; p1 < size ; p1 ++)
01197       if (a [p1] != b [p1])
01198          break;
01199 
01200    return p1;
01201 }
01202 
01204 
01205 int fast_encode_str (fast_codec_t* codec, fast_tag_t tag,
01206                      u8* data, int size)
01207 {
01208    fast_op_t op = get_tag_op (tag);
01209 
01210    if (check_codec (FUNCTION, codec) < 0)
01211       return -1;
01212 
01213    if (check_type  (FUNCTION, codec, tag, FAST_TYPE_STR) < 0)
01214       return -1;
01215 
01216    // Note: We don't prune the string in the codec layer
01217    // Pruning should be done by the app codec
01218 
01219    switch (op)
01220    {
01221     case FAST_OP_NONE:
01222       break; // Always emit value
01223 
01224     case FAST_OP_COPY: // Emit value if not equal to previous value
01225       if (cv_eq_str (codec, tag, data, size))
01226          return 0;
01227 
01228       break;
01229 
01230     case FAST_OP_INCR: // Not defined in the spec
01231       return bad_op_error (FUNCTION, codec, tag);
01232 
01233     case FAST_OP_DELTA:
01234       {
01235          u8* curr = cv_get_str (codec, tag);
01236          u32 offset = find_char_delta_offset (curr, data, size);
01237 
01238          if (offset == size)
01239             return 0;
01240 
01241          memcpy (curr + offset, data + offset, size - offset);
01242 
01243          data += offset;
01244          size -= offset;
01245 
01246          return emit_str (codec, tag, data, size);
01247       }
01248 
01249     default:
01250       return bad_op_error (FUNCTION, codec, tag);
01251    }
01252 
01253    cv_set_str (codec, tag, data, size);
01254    return emit_str (codec, tag, data, size);
01255 }
01256 
01258 
01259 int fast_encode_u32 (fast_codec_t* codec, fast_tag_t tag, u32 value)
01260 {
01261    fast_op_t op = get_tag_op (tag);
01262    u32 next = value;
01263 
01264    if (check_codec (FUNCTION, codec) < 0)
01265       return -1;
01266 
01267    if (check_type  (FUNCTION, codec, tag, FAST_TYPE_U32) < 0)
01268       return -1;
01269 
01270    switch (op)
01271    {
01272     case FAST_OP_NONE: // Always emit value
01273       break;
01274 
01275     case FAST_OP_COPY: // Emit value if not equal to previous value
01276       if (cv_eq_u32 (codec, tag, value))
01277          return 0;
01278 
01279       break;
01280 
01281     case FAST_OP_INCR: // Emit value if not previous value plus one
01282       next = value + 1;
01283 
01284       if (cv_eq_u32 (codec, tag, value))
01285       {
01286          cv_set_u32 (codec, tag, next);
01287          return 0;
01288       }
01289       break;
01290 
01291     case FAST_OP_DELTA:
01292       if (cv_is_valid (codec, tag)) // Emit value if not equal to previous
01293       {
01294          i32 delta = (i32) value - cv_get_u32 (codec, tag);
01295 
01296          // Fixme: use parameter to control zero deltas
01297          if (delta == 0)
01298             return 0;
01299 
01300          cv_set_u32 (codec, tag, value);
01301          return emit_i32 (codec, tag, delta);
01302       }
01303       break;
01304 
01305     default:
01306       return bad_op_error (FUNCTION, codec, tag);
01307    }
01308 
01309    cv_set_u32 (codec, tag, next); // update previous value state
01310    return emit_u32 (codec, tag, value); // emit the value
01311 }
01312 
01314 
01316 
01317 fast_codec_t* fast_create_codec (void)
01318 {
01319    fast_codec_t* codec = malloc (sizeof (*codec));
01320 
01321    if (codec == NULL)
01322    {
01323       fprintf (stderr, "error: [%s] malloc failed\n", FUNCTION);
01324       return NULL;
01325    }
01326 
01327    memset (codec, 0, sizeof (*codec));
01328 
01329    codec->magic  = FAST_CODEC_MAGIC;
01330 
01331    init_buffer (codec->msg,   -1);
01332    init_buffer (codec->input,  0);
01333    init_buffer (codec->output, 1);
01334 
01335    return codec;
01336 }
01337 
01338 int fast_destroy_codec (fast_codec_t* codec)
01339 {
01340    if (codec == NULL)
01341    {
01342       fprintf (stderr, "error: [%s] null codec\n", FUNCTION);
01343       return -1;
01344    }
01345 
01346    if (codec->magic != FAST_CODEC_MAGIC)
01347    {
01348       fprintf (stderr, "error: [%s] bad codec magic number\n", FUNCTION);
01349       return -1;
01350    }
01351 
01352    codec->magic = 0; // To prevent dangling references
01353    free (codec);
01354    return 0;
01355 }
01356 
01357 u32 fast_ascii_to_u32 (u8* data, int size)
01358 {
01359    u32 temp = 0;
01360    int p1;
01361 
01362    for (p1 = 0 ; p1 < size ; p1 ++)
01363    {
01364       int chr = data [p1];
01365       temp = temp * 10 + chr - '0';
01366    }
01367    return temp;
01368 }

Generated on Thu Feb 9 13:11:33 2006 for fastapi by doxygen 1.4.6-NO    FAST ProtocolSM