Compare commits

...
4 Commits
26 changed files with 1589 additions and 382 deletions

No files matched your search

+9
View File
@@ -217,6 +217,7 @@ Flag exe_params[] =
{ "-dis_weapons", "Disable weapon rendering", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-dis_weapons", },
{ "-output_sexps", "Output SEXPs to sexps.html", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-output_sexps", },
{ "-output_scripting", "Output scripting to scripting.html", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-output_scripting", },
{ "-output_json_data", "Output table objects to [table].json", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-output_json_data", },
{ "-save_render_target", "Save render targets to file", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-save_render_target", },
{ "-debug_window", "Display debug window", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-debug_window", },
{ "-verify_vps", "Spew VP CRCs to vp_crcs.txt", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-verify_vps", },
@@ -494,6 +495,9 @@ bool Cmdline_no_unfocus_pause = false;
cmdline_parm get_flags_arg("-get_flags", "Output the launcher flags file", AT_NONE);
cmdline_parm output_sexp_arg("-output_sexps", NULL, AT_NONE); //WMC - outputs all SEXPs to sexps.html
cmdline_parm output_scripting_arg("-output_scripting", NULL, AT_NONE); //WMC
cmdline_parm output_json_data_arg("-output_json_data", "Output table objects to [table].json", AT_NONE); //chief1983, Cmdline_output_json_data
bool Cmdline_output_json_data = false;
// Deprecated flags - CommanderDJ
cmdline_parm deprecated_spec_arg("-spec", "Deprecated", AT_NONE);
@@ -1509,6 +1513,11 @@ bool SetCmdlineParams()
output_sexps("sexps.html");
}
if ( output_json_data_arg.found() )
{
Cmdline_output_json_data = true;
}
if ( no_vbo_arg.found() )
{
Cmdline_novbo = 1;
+1
View File
@@ -155,5 +155,6 @@ extern int Cmdline_reparse_mainhall;
extern bool Cmdline_frame_profile;
extern bool Cmdline_profile_write_file;
extern bool Cmdline_no_unfocus_pause;
extern bool Cmdline_output_json_data;
#endif
+7
View File
@@ -7127,6 +7127,13 @@ int game_main(char *cmdline)
return 0;
}
// maybe output parsed table objects, and exit
if (Cmdline_output_json_data) {
ship_output_json("ships.json");
weapons_output_json("weapons.json");
game_shutdown();
return 0;
}
// maybe spew VP CRCs, and exit
if (Cmdline_verify_vps) {
+488 -158
View File
@@ -83,7 +83,17 @@
#include "debugconsole/console.h"
#include "debugconsole/console.h"
#include "math/vecmat.h"
#include "cfile/cfilesystem.h"
#include "jansson.h"
#ifndef JSON_REAL_PRECISION
#define JSON_REAL_PRECISION(n) 0
#endif
#ifndef JSON_ESCAPE_SLASH
#define JSON_ESCAPE_SLASH 0
#endif
#define NUM_SHIP_SUBSYSTEM_SETS 20 // number of subobject sets to use (because of the fact that it's a linked list,
// we can't easily go fully dynamic)
@@ -1256,6 +1266,60 @@ void parse_ship_particle_effect(ship_info* sip, particle_effect* pe, char *id_st
}
}
void parse_allowed_weapons(ship_info *sip, bool is_primary, bool is_dogfight)
{
int i, num_allowed;
int allowed_weapons[MAX_WEAPON_TYPES];
const int max_banks = (is_primary ? MAX_SHIP_PRIMARY_BANKS : MAX_SHIP_SECONDARY_BANKS);
const int weapon_type = (is_dogfight ? DOGFIGHT_WEAPON : REGULAR_WEAPON);
const int offset = (is_primary ? 0 : MAX_SHIP_PRIMARY_BANKS);
const char *allowed_banks_str = is_primary ? (is_dogfight ? "$Allowed Dogfight PBanks:" : "$Allowed PBanks:")
: (is_dogfight ? "$Allowed Dogfight SBanks:" : "$Allowed SBanks:");
const char *bank_type_str = is_primary ? "primary" : "secondary";
// Goober5000 - fixed Bobboau's implementation of restricted banks
int bank;
// Set the weapons filter used in weapons loadout (for primary weapons)
if (optional_string(allowed_banks_str))
{
bank = -1;
while (check_for_string("("))
{
bank++;
// make sure we don't specify more than we have banks for
if (bank >= max_banks)
{
Warning(LOCATION, "%s bank-specific loadout for %s exceeds permissible number of %s banks. Ignoring the rest...", allowed_banks_str, sip->name, bank_type_str);
bank--;
break;
}
num_allowed = stuff_int_list(allowed_weapons, MAX_WEAPON_TYPES, WEAPON_LIST_TYPE);
// actually say which weapons are allowed
for ( i = 0; i < num_allowed; i++ )
{
if ( allowed_weapons[i] >= 0 ) // MK, Bug fix, 9/6/99. Used to be "allowed_weapons" not "allowed_weapons[i]".
{
sip->allowed_bank_restricted_weapons[offset+bank][allowed_weapons[i]] |= weapon_type;
}
}
}
// set flags if need be
if (bank > 0) // meaning there was a restricted bank table entry
{
for (i=0; i<=bank; i++)
{
sip->restricted_loadout_flag[offset+i] |= weapon_type;
}
}
}
}
/**
* Common method for parsing ship/subsystem primary/secondary weapons so that the parser doesn't flip out in the event of a problem.
*
@@ -1355,8 +1419,7 @@ int parse_and_add_briefing_icon_info()
int parse_ship_values(ship_info* sip, bool first_time, bool replace)
{
char buf[SHIP_MULTITEXT_LENGTH];
int i, j, num_allowed;
int allowed_weapons[MAX_WEAPON_TYPES];
int i, j;
int rtn = 0;
char name_tmp[NAME_LENGTH];
@@ -1628,7 +1691,7 @@ int parse_ship_values(ship_info* sip, bool first_time, bool replace)
if (optional_string("$Enable Team Colors:")) {
stuff_boolean(&sip->uses_team_colors);
sip->default_team_name = "None";
}
}
if (optional_string("$Default Team:")) {
char temp[NAME_LENGTH];
@@ -2221,86 +2284,9 @@ int parse_ship_values(ship_info* sip, bool first_time, bool replace)
stuff_float( &sip->weapon_model_draw_distance );
}
// Goober5000 - fixed Bobboau's implementation of restricted banks
int bank;
// Set the weapons filter used in weapons loadout (for primary weapons)
if (optional_string("$Allowed PBanks:"))
{
bank = -1;
while (check_for_string("("))
{
bank++;
// make sure we don't specify more than we have banks for
if (bank >= MAX_SHIP_PRIMARY_BANKS)
{
Warning(LOCATION, "$Allowed PBanks bank-specific loadout for %s exceeds permissible number of primary banks. Ignoring the rest...", sip->name);
bank--;
break;
}
num_allowed = stuff_int_list(allowed_weapons, MAX_WEAPON_TYPES, WEAPON_LIST_TYPE);
// actually say which weapons are allowed
for ( i = 0; i < num_allowed; i++ )
{
if ( allowed_weapons[i] >= 0 ) // MK, Bug fix, 9/6/99. Used to be "allowed_weapons" not "allowed_weapons[i]".
{
sip->allowed_bank_restricted_weapons[bank][allowed_weapons[i]] |= REGULAR_WEAPON;
}
}
}
// set flags if need be
if (bank > 0) // meaning there was a restricted bank table entry
{
for (i=0; i<=bank; i++)
{
sip->restricted_loadout_flag[i] |= REGULAR_WEAPON;
}
}
}
// Set the weapons filter used in weapons loadout (for primary weapons)
if (optional_string("$Allowed Dogfight PBanks:"))
{
bank = -1;
while (check_for_string("("))
{
bank++;
// make sure we don't specify more than we have banks for
if (bank >= MAX_SHIP_PRIMARY_BANKS)
{
Warning(LOCATION, "$Allowed Dogfight PBanks bank-specific loadout for %s exceeds permissible number of primary banks. Ignoring the rest...", sip->name);
bank--;
break;
}
num_allowed = stuff_int_list(allowed_weapons, MAX_WEAPON_TYPES, WEAPON_LIST_TYPE);
// actually say which weapons are allowed
for ( i = 0; i < num_allowed; i++ )
{
if ( allowed_weapons[i] >= 0 ) // MK, Bug fix, 9/6/99. Used to be "allowed_weapons" not "allowed_weapons[i]".
{
sip->allowed_bank_restricted_weapons[bank][allowed_weapons[i]] |= DOGFIGHT_WEAPON;
}
}
}
// set flags if need be
if (bank > 0) // meaning there was a restricted bank table entry
{
for (i=0; i<=bank; i++)
{
sip->restricted_loadout_flag[i] |= DOGFIGHT_WEAPON;
}
}
}
parse_allowed_weapons(sip, true, false);
parse_allowed_weapons(sip, true, true);
// Get primary bank weapons
parse_weapon_bank(sip, true, &sip->num_primary_banks, sip->primary_bank_weapons, sip->primary_bank_ammo_capacity);
@@ -2312,82 +2298,8 @@ int parse_ship_values(ship_info* sip, bool first_time, bool replace)
}
// Set the weapons filter used in weapons loadout (for secondary weapons)
if (optional_string("$Allowed SBanks:"))
{
bank = -1;
while (check_for_string("("))
{
bank++;
// make sure we don't specify more than we have banks for
if (bank >= MAX_SHIP_SECONDARY_BANKS)
{
Warning(LOCATION, "$Allowed SBanks bank-specific loadout for %s exceeds permissible number of secondary banks. Ignoring the rest...", sip->name);
bank--;
break;
}
num_allowed = stuff_int_list(allowed_weapons, MAX_WEAPON_TYPES, WEAPON_LIST_TYPE);
// actually say which weapons are allowed
for ( i = 0; i < num_allowed; i++ )
{
if ( allowed_weapons[i] >= 0 ) // MK, Bug fix, 9/6/99. Used to be "allowed_weapons" not "allowed_weapons[i]".
{
sip->allowed_bank_restricted_weapons[MAX_SHIP_PRIMARY_BANKS+bank][allowed_weapons[i]] |= REGULAR_WEAPON;
}
}
}
// set flags if need be
if (bank > 0) // meaning there was a restricted bank table entry
{
for (i=0; i<=bank; i++)
{
sip->restricted_loadout_flag[MAX_SHIP_PRIMARY_BANKS+i] |= REGULAR_WEAPON;
}
}
}
// Set the weapons filter used in weapons loadout (for secondary weapons)
if (optional_string("$Allowed Dogfight SBanks:"))
{
bank = -1;
while (check_for_string("("))
{
bank++;
// make sure we don't specify more than we have banks for
if (bank >= MAX_SHIP_SECONDARY_BANKS)
{
Warning(LOCATION, "$Allowed Dogfight SBanks bank-specific loadout for %s exceeds permissible number of secondary banks. Ignoring the rest...", sip->name);
bank--;
break;
}
num_allowed = stuff_int_list(allowed_weapons, MAX_WEAPON_TYPES, WEAPON_LIST_TYPE);
// actually say which weapons are allowed
for ( i = 0; i < num_allowed; i++ )
{
if ( allowed_weapons[i] >= 0 ) // MK, Bug fix, 9/6/99. Used to be "allowed_weapons" not "allowed_weapons[i]".
{
sip->allowed_bank_restricted_weapons[MAX_SHIP_PRIMARY_BANKS+bank][allowed_weapons[i]] |= DOGFIGHT_WEAPON;
}
}
}
// set flags if need be
if (bank > 0) // meaning there was a restricted bank table entry
{
for (i=0; i<=bank; i++)
{
sip->restricted_loadout_flag[MAX_SHIP_PRIMARY_BANKS+i] |= DOGFIGHT_WEAPON;
}
}
}
parse_allowed_weapons(sip, false, false);
parse_allowed_weapons(sip, false, true);
// Get secondary bank weapons
parse_weapon_bank(sip, false, &sip->num_secondary_banks, sip->secondary_bank_weapons, sip->secondary_bank_ammo_capacity);
@@ -17888,3 +17800,421 @@ int get_nearest_bbox_point(object *ship_obj, vec3d *start, vec3d *box_pt)
return inside;
}
bool check_restricted(const ship_info* sip, json_t* bank_json, bool restricted, int bank, int weapon_idx, int weapon_type)
{
// bank is a bank index, weapon_idx is a weapon type. sip->allowed_bank_restricted_weapons[bank][weapon_idx] is a 2-bit bitfield.
if(sip->allowed_bank_restricted_weapons[bank][weapon_idx] & weapon_type)
{
json_array_append(bank_json, json_string(Weapon_info[weapon_idx].name));
if(!restricted && bank > 0)
{
restricted = true;
}
}
return restricted;
}
void append_weapons(const ship_info* sip, json_t* ship_data, bool is_primary, int bank_offset)
{
int bank, weapon_idx, num_banks;
bool restricted = false, dogfight_restricted = false;
json_t *Allowed_banks = json_array();
json_t *Allowed_dogfight_banks = json_array();
json_t *Default_banks = json_array();
json_t *Bank_capacity = json_array();
json_t *Show_models = json_array();
char Allowed_Banks_name[16], Allowed_Dogfight_Banks_name[25], Default_Banks_name[16], Bank_Capacity_name[16], Show_Models_name[23], type_name[10];
if(is_primary)
{
num_banks = sip->num_primary_banks;
strcpy_s(type_name, "Primary");
}
else
{
num_banks = sip->num_secondary_banks;
strcpy_s(type_name, "Secondary");
}
sprintf(Allowed_Banks_name, "$Allowed %cBanks", type_name[0]);
sprintf(Allowed_Dogfight_Banks_name, "$Allowed Dogfight %cBanks", type_name[0]);
sprintf(Default_Banks_name, "$Default %cBanks", type_name[0]);
sprintf(Bank_Capacity_name, "$%cBank Capacity", type_name[0]);
sprintf(Show_Models_name, "$Show %s Models", type_name);
for(bank = bank_offset; bank < bank_offset + num_banks; bank++)
{
json_t *regular_bank = json_array();
json_t *dogfight_bank = json_array();
for(weapon_idx = 0; weapon_idx < Num_weapon_types; weapon_idx++)
{
restricted = check_restricted(sip, regular_bank, restricted, bank, weapon_idx, REGULAR_WEAPON);
dogfight_restricted = check_restricted(sip, dogfight_bank, dogfight_restricted, bank, weapon_idx, DOGFIGHT_WEAPON);
}
json_array_append(Allowed_banks, regular_bank);
json_array_append(Allowed_dogfight_banks, dogfight_bank);
if(is_primary)
{
json_array_append(Default_banks, json_string(Weapon_info[sip->primary_bank_weapons[bank - bank_offset]].name));
json_array_append(Bank_capacity, json_integer(sip->primary_bank_ammo_capacity[bank - bank_offset]));
json_array_append(Show_models, json_boolean(sip->draw_primary_models[bank - bank_offset]));
}
else
{
json_array_append(Default_banks, json_string(Weapon_info[sip->secondary_bank_weapons[bank - bank_offset]].name));
json_array_append(Bank_capacity, json_integer(sip->secondary_bank_ammo_capacity[bank - bank_offset]));
json_array_append(Show_models, json_boolean(sip->draw_secondary_models[bank - bank_offset]));
}
}
json_object_set_new(ship_data, Allowed_Banks_name, (restricted ? Allowed_banks : json_array_get(Allowed_banks, 0)));
json_object_set_new(ship_data, Allowed_Dogfight_Banks_name, (dogfight_restricted ? Allowed_dogfight_banks : json_array_get(Allowed_dogfight_banks, 0)));
json_object_set_new(ship_data, Default_Banks_name, Default_banks);
json_object_set_new(ship_data, Bank_Capacity_name, Bank_capacity);
json_object_set_new(ship_data, Show_Models_name, Show_models);
}
void ship_output_json(const char *outfile)
{
mprintf(("Exporting ship data to json.\n"));
int i;
json_t *ships_obj = json_object();
json_t *Ships = json_array();
ship_info *sip;
species_info *species;
char full_name[MAX_PATH_LEN];
json_object_set_new(ships_obj, "default_player_ship", json_string(default_player_ship));
// Loop over the Ship_info array and add a new entry to ship_info_arr each time
for (i = 0; i < Num_ship_classes; i++)
{
int j;
sip = &Ship_info[i];
species = &Species_info[sip->species];
json_t *ship_data = json_object();
json_t *Displays = json_array();
json_t *Replacements = json_array();
json_t *Cockpit_offset = json_object();
json_t *Detail_distance = json_array();
json_t *ND = json_array();
json_t *Impact = json_object();
json_t *Collision_Physics = json_object();
json_t *Debris = json_object();
json_t *Max_Velocity = json_object();
json_t *Rotation_Time = json_object();
json_t *Anims = json_array();
json_t *Model_point_shield_controls = json_array();
size_t insert_index, shield_point;
json_t *quadrant;
json_t *Shield_color = json_object();
json_object_set_new(ship_data, "$Name", json_string(sip->name));
json_object_set_new(ship_data, "$Alt Name", json_string(sip->alt_name));
json_object_set_new(ship_data, "$Short Name", json_string(sip->short_name));
json_object_set_new(ship_data, "$Species", json_string(species->species_name));
json_object_set_new(ship_data, "+Type", json_string(sip->type_str));
json_object_set_new(ship_data, "+Maneuverability", json_string(sip->maneuverability_str));
json_object_set_new(ship_data, "+Armor", json_string(sip->armor_str));
json_object_set_new(ship_data, "+Manufacturer", json_string(sip->manufacturer_str));
json_object_set_new(ship_data, "+Description", json_string(sip->desc));
json_object_set_new(ship_data, "+Tech Title", json_string(sip->tech_title));
json_object_set_new(ship_data, "+Tech Description", json_string(sip->tech_desc));
json_object_set_new(ship_data, "+Length", json_string(sip->ship_length));
json_object_set_new(ship_data, "+Gun Mounts", json_string(sip->gun_mounts));
json_object_set_new(ship_data, "+Missile Banks", json_string(sip->missile_banks));
switch(sip->selection_effect)
{
case 0:
json_object_set_new(ship_data, "$Selection Effect", json_string("off"));
break;
case 1:
json_object_set_new(ship_data, "$Selection Effect", json_string("FS1"));
break;
case 2:
default:
json_object_set_new(ship_data, "$Selection Effect", json_string("FS2"));
}
json_object_set_new(ship_data, "$Cockpit POF file", json_string(sip->cockpit_pof_file));
json_object_set_new(Cockpit_offset, "x", json_real(sip->cockpit_offset.xyz.x));
json_object_set_new(Cockpit_offset, "y", json_real(sip->cockpit_offset.xyz.y));
json_object_set_new(Cockpit_offset, "z", json_real(sip->cockpit_offset.xyz.z));
json_object_set_new(ship_data, "+Cockpit offset", Cockpit_offset);
for(SCP_vector<cockpit_display_info>::iterator display = sip->displays.begin(); display != sip->displays.end(); ++display)
{
json_t *display_data = json_object();
json_t *offsets = json_array();
json_t *size = json_array();
json_object_set_new(display_data, "+Texture", json_string(display->filename));
json_array_append_new(offsets, json_integer(display->offset[0]));
json_array_append_new(offsets, json_integer(display->offset[1]));
json_object_set_new(display_data, "+Offsets", offsets);
json_array_append_new(size, json_integer(display->size[0]));
json_array_append_new(size, json_integer(display->size[1]));
json_object_set_new(display_data, "+Size", size);
json_object_set_new(display_data, "+Background", json_string(display->bg_filename));
json_object_set_new(display_data, "+Foreground", json_string(display->fg_filename));
json_object_set_new(display_data, "+Display Name", json_string(display->name));
json_array_append_new(Displays, display_data);
}
json_object_set_new(ship_data, "$Cockpit Display", Displays);
json_object_set_new(ship_data, "$POF file", json_string(sip->pof_file));
for(SCP_vector<texture_replace>::iterator replace = sip->replacement_textures.begin(); replace != sip->replacement_textures.end(); ++replace)
{
json_t *replace_data = json_object();
json_object_set_new(replace_data, "+old", json_string(replace->old_texture));
json_object_set_new(replace_data, "+new", json_string(replace->new_texture));
json_array_append_new(Replacements, replace_data);
}
json_object_set_new(ship_data, "$Texture Replace", Replacements);
json_object_set_new(ship_data, "$POF target file", json_string(sip->pof_file_hud));
json_object_set_new(ship_data, "$POF target LOD", json_integer(sip->hud_target_lod));
for (j = 0; j < sip->num_detail_levels; j++)
{
json_array_append_new(Detail_distance, json_integer(sip->detail_distance[j]));
}
json_object_set_new(ship_data, "$Detail distance", Detail_distance);
for (j = 0; j < sip->num_nondark_colors; j++)
{
json_t *nd_values = json_object();
json_object_set_new(nd_values, "red", json_integer(sip->nondark_colors[j][0]));
json_object_set_new(nd_values, "green", json_integer(sip->nondark_colors[j][1]));
json_object_set_new(nd_values, "blue", json_integer(sip->nondark_colors[j][2]));
json_array_append_new(ND, nd_values);
}
json_object_set_new(ship_data, "$ND", ND);
json_object_set_new(ship_data, "$Enable Team Colors", json_boolean(sip->uses_team_colors));
json_object_set_new(ship_data, "$Default Team", json_string(sip->default_team_name.c_str()));
json_object_set_new(ship_data, "$Damage Lightning Type", json_string(Lightning_types[sip->damage_lightning_type]));
if(sip->collision_damage_type_idx > -1 && sip->collision_damage_type_idx < Damage_types.size())
{
json_object_set_new(Impact, "+Damage Type", json_string(Damage_types.at(sip->collision_damage_type_idx).name));
}
else
{
json_object_set_new(Impact, "+Damage Type", json_null());
}
json_object_set_new(ship_data, "$Impact", Impact);
// Skipping spews
json_object_set_new(Collision_Physics, "+Bounce", json_real(sip->collision_physics.bounce));
json_object_set_new(Collision_Physics, "+Both Small Bounce", json_real(sip->collision_physics.both_small_bounce));
json_object_set_new(Collision_Physics, "+Friction", json_real(sip->collision_physics.friction));
json_object_set_new(Collision_Physics, "+Rotation Factor", json_real(sip->collision_physics.rotation_factor));
json_object_set_new(Collision_Physics, "+Landing Max Forward Vel", json_real(sip->collision_physics.landing_max_z));
json_object_set_new(Collision_Physics, "+Landing Min Forward Vel", json_real(sip->collision_physics.landing_min_z));
json_object_set_new(Collision_Physics, "+Landing Max Descent Vel", json_real(sip->collision_physics.landing_min_y));
json_object_set_new(Collision_Physics, "+Landing Max Horizontal Vel", json_real(sip->collision_physics.landing_max_x));
json_object_set_new(Collision_Physics, "+Landing Max Angle", json_real(sip->collision_physics.landing_max_angle));
json_object_set_new(Collision_Physics, "+Landing Min Angle", json_real(sip->collision_physics.landing_min_angle));
json_object_set_new(Collision_Physics, "+Landing Max Rotate Angle", json_real(sip->collision_physics.landing_max_rot_angle));
json_object_set_new(Collision_Physics, "+Reorient Max Forward Vel", json_real(sip->collision_physics.reorient_max_z));
json_object_set_new(Collision_Physics, "+Reorient Min Forward Vel", json_real(sip->collision_physics.reorient_min_z));
json_object_set_new(Collision_Physics, "+Reorient Max Descent Vel", json_real(sip->collision_physics.reorient_min_y));
json_object_set_new(Collision_Physics, "+Reorient Max Horizontal Vel", json_real(sip->collision_physics.reorient_max_x));
json_object_set_new(Collision_Physics, "+Reorient Max Angle", json_real(sip->collision_physics.reorient_max_angle));
json_object_set_new(Collision_Physics, "+Reorient Min Angle", json_real(sip->collision_physics.reorient_min_angle));
json_object_set_new(Collision_Physics, "+Reorient Max Rotate Angle", json_real(sip->collision_physics.reorient_max_rot_angle));
json_object_set_new(Collision_Physics, "+Reorient Speed Mult", json_real(sip->collision_physics.reorient_mult));
json_object_set_new(Collision_Physics, "+Landing Rest Angle", json_real(sip->collision_physics.landing_rest_angle));
if(sip->collision_damage_type_idx > -1 && sip->collision_damage_type_idx < Snds.size())
{
json_object_set_new(Collision_Physics, "+Landing Sound", json_string(Snds.at(sip->collision_physics.landing_sound_idx).name.c_str()));
}
else
{
json_object_set_new(Collision_Physics, "+Landing Sound", json_null());
}
json_object_set_new(ship_data, "$Collision Physics", Collision_Physics);
json_object_set_new(Debris, "+Min Lifetime", json_real(sip->debris_min_lifetime));
json_object_set_new(Debris, "+Max Lifetime", json_real(sip->debris_max_lifetime));
json_object_set_new(Debris, "+Min Speed", json_real(sip->debris_min_speed));
json_object_set_new(Debris, "+Max Speed", json_real(sip->debris_max_speed));
json_object_set_new(Debris, "+Min Rotation speed", json_real(sip->debris_min_rotspeed));
json_object_set_new(Debris, "+Max Rotation speed", json_real(sip->debris_max_rotspeed));
if(sip->collision_damage_type_idx > -1 && sip->collision_damage_type_idx < Damage_types.size())
{
json_object_set_new(Debris, "+Damage Type", json_string(Damage_types.at(sip->debris_damage_type_idx).name));
}
else
{
json_object_set_new(Debris, "+Damage Type", json_null());
}
json_object_set_new(Debris, "+Min Hitpoints", json_real(sip->debris_min_hitpoints));
json_object_set_new(Debris, "+Max Hitpoints", json_real(sip->debris_max_hitpoints));
json_object_set_new(Debris, "+Damage Multiplier", json_real(sip->debris_damage_mult));
json_object_set_new(Debris, "+Lightning Arc Percent", json_real(sip->debris_arc_percent * 100.0f));
json_object_set_new(ship_data, "$Debris", Debris);
json_object_set_new(ship_data, "$Density", json_real(sip->density));
json_object_set_new(ship_data, "$Damp", json_real(sip->damp));
json_object_set_new(ship_data, "$Rotdamp", json_real(sip->rotdamp));
json_object_set_new(ship_data, "$Banking Constant", json_real(sip->delta_bank_const));
json_object_set_new(Max_Velocity, "x", json_real(sip->max_vel.xyz.x));
json_object_set_new(Max_Velocity, "y", json_real(sip->max_vel.xyz.y));
json_object_set_new(Max_Velocity, "z", json_real(sip->max_vel.xyz.z));
json_object_set_new(ship_data, "$Max Velocity", Max_Velocity);
json_object_set_new(Rotation_Time, "x", json_real(sip->rotation_time.xyz.x));
json_object_set_new(Rotation_Time, "y", json_real(sip->rotation_time.xyz.y));
json_object_set_new(Rotation_Time, "z", json_real(sip->rotation_time.xyz.z));
json_object_set_new(ship_data, "$Rotation Time", Rotation_Time);
json_object_set_new(ship_data, "$Rear Velocity", json_real(sip->max_rear_vel));
json_object_set_new(ship_data, "$Forward accel", json_real(sip->forward_accel));
json_object_set_new(ship_data, "$Forward decel", json_real(sip->forward_decel));
json_object_set_new(ship_data, "$Slide accel", json_real(sip->slide_accel));
json_object_set_new(ship_data, "$Slide decel", json_real(sip->slide_decel));
json_object_set_new(ship_data, "$Glide", json_boolean(sip->can_glide));
json_object_set_new(ship_data, "+Dynamic Glide Cap", json_boolean(sip->glide_dynamic_cap));
json_object_set_new(ship_data, "+Max Glide Speed", json_real(sip->glide_cap));
json_object_set_new(ship_data, "+Glide Accel Mult", json_real(sip->glide_accel_mult));
json_object_set_new(ship_data, "$Use Newtonian Dampening", json_boolean(sip->use_newtonian_damp));
json_object_set_new(ship_data, "$Autoaim FOV", json_integer(sip->autoaim_fov));
// Skipping convergence, ugh...
json_object_set_new(ship_data, "$Warpin type", json_string(Warp_types[sip->warpin_type]));
if(sip->warpin_snd_start > -1 && sip->warpin_snd_start < Snds.size())
{
json_object_set_new(ship_data, "$Warpin Start Sound", json_string(Snds.at(sip->warpin_snd_start).name.c_str()));
}
else
{
json_object_set_new(ship_data, "$Warpin Start Sound", json_null());
}
if(sip->warpin_snd_end > -1 && sip->warpin_snd_end < Snds.size())
{
json_object_set_new(ship_data, "$Warpin End Sound", json_string(Snds.at(sip->warpin_snd_end).name.c_str()));
}
else
{
json_object_set_new(ship_data, "$Warpin End Sound", json_null());
}
json_object_set_new(ship_data, "$Warpin speed", json_real(sip->warpin_speed));
json_object_set_new(ship_data, "$Warpin time", json_real(sip->warpin_time));
json_object_set_new(ship_data, "$Warpin decel exp", json_real(sip->warpin_decel_exp));
json_object_set_new(ship_data, "$Warpin radius", json_real(sip->warpin_radius));
json_object_set_new(ship_data, "$Warpin animation", json_string(sip->warpin_anim));
json_object_set_new(ship_data, "$Warpout type", json_string(Warp_types[sip->warpout_type]));
if(sip->warpout_snd_start > -1 && sip->warpout_snd_start < Snds.size())
{
json_object_set_new(ship_data, "$Warpout Start Sound", json_string(Snds.at(sip->warpout_snd_start).name.c_str()));
}
else
{
json_object_set_new(ship_data, "$Warpout Start Sound", json_null());
}
if(sip->warpout_snd_end > -1 && sip->warpout_snd_end < Snds.size())
{
json_object_set_new(ship_data, "$Warpout End Sound", json_string(Snds.at(sip->warpout_snd_end).name.c_str()));
}
else
{
json_object_set_new(ship_data, "$Warpout End Sound", json_null());
}
json_object_set_new(ship_data, "$Warpout engage time", json_real(sip->warpout_engage_time));
json_object_set_new(ship_data, "$Warpout speed", json_real(sip->warpout_speed));
json_object_set_new(ship_data, "$Warpout time", json_real(sip->warpout_time));
json_object_set_new(ship_data, "$Warpout accel exp", json_real(sip->warpout_accel_exp));
json_object_set_new(ship_data, "$Warpout radius", json_real(sip->warpout_radius));
json_object_set_new(ship_data, "$Warpout animation", json_string(sip->warpout_anim));
json_object_set_new(ship_data, "$Player warpout speed", json_real(sip->warpout_player_speed));
json_object_set_new(ship_data, "$Expl inner rad", json_real(sip->shockwave.inner_rad));
json_object_set_new(ship_data, "$Expl outer rad", json_real(sip->shockwave.outer_rad));
json_object_set_new(ship_data, "$Expl damage", json_real(sip->shockwave.damage));
json_object_set_new(ship_data, "$Expl blast", json_real(sip->shockwave.blast));
json_object_set_new(ship_data, "$Expl Propogates", json_boolean(sip->explosion_propagates));
json_object_set_new(ship_data, "$Propagating Expl Radius Multiplier", json_real(sip->prop_exp_rad_mult));
json_object_set_new(ship_data, "$Expl Visual Rad", json_real(sip->big_exp_visual_rad));
json_object_set_new(ship_data, "$Base Death-Roll Time", json_integer(sip->death_roll_base_time));
json_object_set_new(ship_data, "$Death-Roll Explosion Radius Mult", json_real(sip->death_roll_r_mult));
json_object_set_new(ship_data, "$Death-Roll Explosion Intensity Mult", json_real(sip->death_roll_time_mult));
json_object_set_new(ship_data, "$Death FX Explosion Radius Mult", json_real(sip->death_fx_r_mult));
json_object_set_new(ship_data, "$Death FX Explosion Count", json_integer(sip->death_fx_count));
// Skipping more particle stuff for now
json_object_set_new(ship_data, "$Vaporize Percent Chance", json_real(sip->vaporize_chance));
if(sip->shockwave.damage_type_idx > -1 && sip->shockwave.damage_type_idx < Damage_types.size())
{
json_object_set_new(ship_data, "$Shockwave Damage Type", json_string(Damage_types.at(sip->shockwave.damage_type_idx).name));
}
else
{
json_object_set_new(ship_data, "$Shockwave Damage Type", json_null());
}
json_object_set_new(ship_data, "$Shockwave Speed", json_real(sip->shockwave.speed));
json_object_set_new(ship_data, "$Shockwave Count", json_real(sip->shockwave_count));
json_object_set_new(ship_data, "$Shockwave model", json_string(sip->shockwave.pof_name));
json_object_set_new(ship_data, "$Shockwave name", json_string(sip->shockwave.name));
for(SCP_vector<int>::iterator anim = sip->explosion_bitmap_anims.begin(); anim != sip->explosion_bitmap_anims.end(); ++anim)
{
json_array_append_new(Anims, json_integer(*anim));
}
json_object_set_new(ship_data, "$Explosion Animations", Anims);
json_object_set_new(ship_data, "$Weapon Model Draw Distance", json_real(sip->weapon_model_draw_distance));
append_weapons(sip, ship_data, true, 0);
append_weapons(sip, ship_data, false, MAX_SHIP_PRIMARY_BANKS);
json_object_set_new(ship_data, "$Shields", json_real(sip->max_shield_strength));
json_object_set_new(ship_data, "+Auto Spread", json_real(sip->auto_shield_spread));
json_object_set_new(ship_data, "+Allow Bypass", json_boolean(sip->auto_shield_spread_bypass));
json_object_set_new(ship_data, "+Spread From LOD", json_integer(sip->auto_shield_spread_from_lod));
for(j = 0; j < sizeof(sip->shield_point_augment_ctrls) / sizeof(int); j++)
{
if(sip->shield_point_augment_ctrls[j] != -1)
{
insert_index = 0;
json_array_foreach(Model_point_shield_controls, shield_point, quadrant)
{
insert_index = shield_point;
if(sip->shield_point_augment_ctrls[j] < shield_point)
{
break;
}
}
switch(j)
{
case 0:
json_array_insert_new(Model_point_shield_controls, insert_index, json_string("right"));
break;
case 1:
json_array_insert_new(Model_point_shield_controls, insert_index, json_string("front"));
break;
case 2:
json_array_insert_new(Model_point_shield_controls, insert_index, json_string("rear"));
break;
case 3:
json_array_insert_new(Model_point_shield_controls, insert_index, json_string("left"));
break;
}
}
}
json_object_set_new(ship_data, "$Model Point Shield Controls", Model_point_shield_controls);
json_object_set_new(Shield_color, "red", json_integer(sip->shield_color[0]));
json_object_set_new(Shield_color, "green", json_integer(sip->shield_color[1]));
json_object_set_new(Shield_color, "blue", json_integer(sip->shield_color[2]));
json_object_set_new(ship_data, "$Shield Color", Shield_color);
json_object_set_new(ship_data, "$Power Output", json_real(sip->power_output));
json_object_set_new(ship_data, "$Shield Regeneration Rate", json_real(sip->max_shield_regen_per_second));
json_object_set_new(ship_data, "$Support Shield Repair Rate", json_real(sip->sup_shield_repair_rate * 100));
json_object_set_new(ship_data, "$Weapon Regeneration Rate", json_real(sip->max_weapon_regen_per_second));
json_object_set_new(ship_data, "$Max Oclk Speed", json_real(sip->max_overclocked_speed));
json_object_set_new(ship_data, "$Max Weapon Eng", json_real(sip->max_weapon_reserve));
json_object_set_new(ship_data, "$Hitpoints", json_real(sip->max_hull_strength));
json_object_set_new(ship_data, "$Hull Repair Rate", json_real(sip->hull_repair_rate * 100));
json_object_set_new(ship_data, "$Support Hull Repair Rate", json_real(sip->sup_hull_repair_rate * 100));
json_object_set_new(ship_data, "$Subsystem Repair Rate", json_real(sip->subsys_repair_rate * 100));
json_object_set_new(ship_data, "$Support Subsystem Repair Rate", json_real(sip->sup_subsys_repair_rate * 100));
json_object_set_new(ship_data, "$Armor Type", ( (sip->armor_type_idx > -1) ? json_string(Armor_types[sip->armor_type_idx].GetNamePtr()) : json_null() ));
json_object_set_new(ship_data, "$Shield Armor Type", ( (sip->shield_armor_type_idx > -1) ? json_string(Armor_types[sip->shield_armor_type_idx].GetNamePtr()) : json_null() ));
// Skipping flags
json_array_append_new(Ships, ship_data);
}
json_object_set_new(ships_obj, "Ships", Ships);
cf_create_default_path_string(full_name, sizeof(full_name) - 1, CF_TYPE_ROOT, outfile);
json_dump_file(ships_obj, full_name, JSON_ESCAPE_SLASH | JSON_INDENT(4) | JSON_PRESERVE_ORDER | JSON_REAL_PRECISION(4));
}
+2
View File
@@ -2006,4 +2006,6 @@ int get_default_player_ship_index();
*/
int get_nearest_bbox_point(object *ship_obj, vec3d *start, vec3d *box_pt);
extern void ship_output_json(const char *outfile);
#endif
+3
View File
@@ -670,4 +670,7 @@ void weapon_pause_sounds();
// Unpauses all running weapon sounds
void weapon_unpause_sounds();
// Dumps parsed weapon data to a json file
extern void weapons_output_json(const char *outfile);
#endif
+5
View File
@@ -7022,3 +7022,8 @@ void weapon_unpause_sounds()
// Pause all beam sounds
beam_unpause_sounds();
}
void weapons_output_json(const char *outfile)
{
mprintf(("Exporting weapon data to json.\n"));
}
+1 -1
View File
@@ -1,4 +1,4 @@
Copyright (c) 2009-2013 Petri Lehtinen <[email protected]>
Copyright (c) 2009-2014 Petri Lehtinen <[email protected]>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
+19 -13
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2013 Petri Lehtinen <[email protected]>
* Copyright (c) 2009-2014 Petri Lehtinen <[email protected]>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
@@ -22,6 +22,9 @@
#define MAX_INTEGER_STR_LENGTH 100
#define MAX_REAL_STR_LENGTH 100
#define FLAGS_TO_INDENT(f) ((f) & 0x1F)
#define FLAGS_TO_PRECISION(f) (((f) >> 11) & 0x1F)
struct object_key {
size_t serial;
const char *key;
@@ -45,9 +48,9 @@ static const char whitespace[] = " ";
static int dump_indent(size_t flags, int depth, int space, json_dump_callback_t dump, void *data)
{
if(JSON_INDENT(flags) > 0)
if(FLAGS_TO_INDENT(flags) > 0)
{
int i, ws_count = JSON_INDENT(flags);
int i, ws_count = FLAGS_TO_INDENT(flags);
if(dump("\n", 1, data))
return -1;
@@ -65,24 +68,25 @@ static int dump_indent(size_t flags, int depth, int space, json_dump_callback_t
return 0;
}
static int dump_string(const char *str, json_dump_callback_t dump, void *data, size_t flags)
static int dump_string(const char *str, size_t len, json_dump_callback_t dump, void *data, size_t flags)
{
const char *pos, *end;
const char *pos, *end, *lim;
int32_t codepoint;
if(dump("\"", 1, data))
return -1;
end = pos = str;
lim = str + len;
while(1)
{
const char *text;
char seq[13];
int length;
while(*end)
while(end < lim)
{
end = utf8_iterate(pos, &codepoint);
end = utf8_iterate(pos, lim - pos, &codepoint);
if(!end)
return -1;
@@ -126,7 +130,7 @@ static int dump_string(const char *str, json_dump_callback_t dump, void *data, s
/* codepoint is in BMP */
if(codepoint < 0x10000)
{
sprintf(seq, "\\u%04x", codepoint);
sprintf(seq, "\\u%04X", codepoint);
length = 6;
}
@@ -139,7 +143,7 @@ static int dump_string(const char *str, json_dump_callback_t dump, void *data, s
first = 0xD800 | ((codepoint & 0xffc00) >> 10);
last = 0xDC00 | (codepoint & 0x003ff);
sprintf(seq, "\\u%04x\\u%04x", first, last);
sprintf(seq, "\\u%04X\\u%04X", first, last);
length = 12;
}
@@ -207,7 +211,8 @@ static int do_dump(const json_t *json, size_t flags, int depth,
int size;
double value = json_real_value(json);
size = jsonp_dtostr(buffer, MAX_REAL_STR_LENGTH, value);
size = jsonp_dtostr(buffer, MAX_REAL_STR_LENGTH, value,
FLAGS_TO_PRECISION(flags));
if(size < 0)
return -1;
@@ -215,7 +220,7 @@ static int do_dump(const json_t *json, size_t flags, int depth,
}
case JSON_STRING:
return dump_string(json_string_value(json), dump, data, flags);
return dump_string(json_string_value(json), json_string_length(json), dump, data, flags);
case JSON_ARRAY:
{
@@ -336,7 +341,7 @@ static int do_dump(const json_t *json, size_t flags, int depth,
value = json_object_get(json, key);
assert(value);
dump_string(key, dump, data, flags);
dump_string(key, strlen(key), dump, data, flags);
if(dump(separator, separator_length, data) ||
do_dump(value, flags, depth + 1, dump, data))
{
@@ -372,8 +377,9 @@ static int do_dump(const json_t *json, size_t flags, int depth,
while(iter)
{
void *next = json_object_iter_next((json_t *)json, iter);
const char *key = json_object_iter_key(iter);
dump_string(json_object_iter_key(iter), dump, data, flags);
dump_string(key, strlen(key), dump, data, flags);
if(dump(separator, separator_length, data) ||
do_dump(json_object_iter_value(iter), flags, depth + 1,
dump, data))
+36 -44
View File
@@ -1,12 +1,21 @@
/*
* Copyright (c) 2009-2013 Petri Lehtinen <[email protected]>
* Copyright (c) 2009-2014 Petri Lehtinen <[email protected]>
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#if HAVE_CONFIG_H
#include <jansson_private_config.h>
#endif
#include <stdlib.h>
#include <string.h>
#if HAVE_STDINT_H
#include <stdint.h>
#endif
#include <jansson_config.h> /* for JSON_INLINE */
#include "jansson_private.h" /* for container_of() */
#include "hashtable.h"
@@ -15,24 +24,13 @@ typedef struct hashtable_list list_t;
typedef struct hashtable_pair pair_t;
typedef struct hashtable_bucket bucket_t;
extern volatile uint32_t hashtable_seed;
/* Implementation of the hash function */
#include "lookup3.h"
#define list_to_pair(list_) container_of(list_, pair_t, list)
/* From http://www.cse.yorku.ca/~oz/hash.html */
static size_t hash_str(const void *ptr)
{
const char *str = (const char *)ptr;
size_t hash = 5381;
size_t c;
while((c = (size_t)*str))
{
hash = ((hash << 5) + hash) + c;
str++;
}
return hash;
}
#define hash_str(key) ((size_t)hashlittle((key), strlen(key), hashtable_seed))
static JSON_INLINE void list_init(list_t *list)
{
@@ -74,19 +72,6 @@ static void insert_to_bucket(hashtable_t *hashtable, bucket_t *bucket,
}
}
static const size_t primes[] = {
5, 13, 23, 53, 97, 193, 389, 769, 1543, 3079, 6151, 12289, 24593,
49157, 98317, 196613, 393241, 786433, 1572869, 3145739, 6291469,
12582917, 25165843, 50331653, 100663319, 201326611, 402653189,
805306457, 1610612741
};
static JSON_INLINE size_t num_buckets(hashtable_t *hashtable)
{
return primes[hashtable->num_buckets];
}
static pair_t *hashtable_find_pair(hashtable_t *hashtable, bucket_t *bucket,
const char *key, size_t hash)
{
@@ -120,7 +105,7 @@ static int hashtable_do_del(hashtable_t *hashtable,
bucket_t *bucket;
size_t index;
index = hash % num_buckets(hashtable);
index = hash & hashmask(hashtable->order);
bucket = &hashtable->buckets[index];
pair = hashtable_find_pair(hashtable, bucket, key, hash);
@@ -167,14 +152,14 @@ static int hashtable_do_rehash(hashtable_t *hashtable)
jsonp_free(hashtable->buckets);
hashtable->num_buckets++;
new_size = num_buckets(hashtable);
hashtable->order++;
new_size = hashsize(hashtable->order);
hashtable->buckets = jsonp_malloc(new_size * sizeof(bucket_t));
if(!hashtable->buckets)
return -1;
for(i = 0; i < num_buckets(hashtable); i++)
for(i = 0; i < hashsize(hashtable->order); i++)
{
hashtable->buckets[i].first = hashtable->buckets[i].last =
&hashtable->list;
@@ -199,14 +184,14 @@ int hashtable_init(hashtable_t *hashtable)
size_t i;
hashtable->size = 0;
hashtable->num_buckets = 0; /* index to primes[] */
hashtable->buckets = jsonp_malloc(num_buckets(hashtable) * sizeof(bucket_t));
hashtable->order = 3;
hashtable->buckets = jsonp_malloc(hashsize(hashtable->order) * sizeof(bucket_t));
if(!hashtable->buckets)
return -1;
list_init(&hashtable->list);
for(i = 0; i < num_buckets(hashtable); i++)
for(i = 0; i < hashsize(hashtable->order); i++)
{
hashtable->buckets[i].first = hashtable->buckets[i].last =
&hashtable->list;
@@ -230,12 +215,12 @@ int hashtable_set(hashtable_t *hashtable,
size_t hash, index;
/* rehash if the load ratio exceeds 1 */
if(hashtable->size >= num_buckets(hashtable))
if(hashtable->size >= hashsize(hashtable->order))
if(hashtable_do_rehash(hashtable))
return -1;
hash = hash_str(key);
index = hash % num_buckets(hashtable);
index = hash & hashmask(hashtable->order);
bucket = &hashtable->buckets[index];
pair = hashtable_find_pair(hashtable, bucket, key, hash);
@@ -249,7 +234,14 @@ int hashtable_set(hashtable_t *hashtable,
/* offsetof(...) returns the size of pair_t without the last,
flexible member. This way, the correct amount is
allocated. */
pair = jsonp_malloc(offsetof(pair_t, key) + strlen(key) + 1);
size_t len = strlen(key);
if(len >= (size_t)-1 - offsetof(pair_t, key)) {
/* Avoid an overflow if the key is very long */
return -1;
}
pair = jsonp_malloc(offsetof(pair_t, key) + len + 1);
if(!pair)
return -1;
@@ -273,7 +265,7 @@ void *hashtable_get(hashtable_t *hashtable, const char *key)
bucket_t *bucket;
hash = hash_str(key);
bucket = &hashtable->buckets[hash % num_buckets(hashtable)];
bucket = &hashtable->buckets[hash & hashmask(hashtable->order)];
pair = hashtable_find_pair(hashtable, bucket, key, hash);
if(!pair)
@@ -294,7 +286,7 @@ void hashtable_clear(hashtable_t *hashtable)
hashtable_do_clear(hashtable);
for(i = 0; i < num_buckets(hashtable); i++)
for(i = 0; i < hashsize(hashtable->order); i++)
{
hashtable->buckets[i].first = hashtable->buckets[i].last =
&hashtable->list;
@@ -316,7 +308,7 @@ void *hashtable_iter_at(hashtable_t *hashtable, const char *key)
bucket_t *bucket;
hash = hash_str(key);
bucket = &hashtable->buckets[hash % num_buckets(hashtable)];
bucket = &hashtable->buckets[hash & hashmask(hashtable->order)];
pair = hashtable_find_pair(hashtable, bucket, key, hash);
if(!pair)
+3 -2
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2013 Petri Lehtinen <[email protected]>
* Copyright (c) 2009-2014 Petri Lehtinen <[email protected]>
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
@@ -32,7 +32,7 @@ struct hashtable_bucket {
typedef struct hashtable {
size_t size;
struct hashtable_bucket *buckets;
size_t num_buckets; /* index to primes[] */
size_t order; /* hashtable has pow(2, order) buckets */
struct hashtable_list list;
} hashtable_t;
@@ -40,6 +40,7 @@ typedef struct hashtable {
#define hashtable_key_to_iter(key_) \
(&(container_of(key_, struct hashtable_pair, key)->list))
/**
* hashtable_init - Initialize a hashtable object
*
+277
View File
@@ -0,0 +1,277 @@
/* Generate sizeof(uint32_t) bytes of as random data as possible to seed
the hash function.
*/
#ifdef HAVE_CONFIG_H
#include <jansson_private_config.h>
#endif
#include <stdio.h>
#include <time.h>
#ifdef HAVE_STDINT_H
#include <stdint.h>
#endif
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif
#ifdef HAVE_SCHED_H
#include <sched.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#if defined(_WIN32)
/* For GetModuleHandle(), GetProcAddress() and GetCurrentProcessId() */
#include <windows.h>
#endif
#include "jansson.h"
static uint32_t buf_to_uint32(char *data) {
size_t i;
uint32_t result = 0;
for (i = 0; i < sizeof(uint32_t); i++)
result = (result << 8) | (unsigned char)data[i];
return result;
}
/* /dev/urandom */
#if !defined(_WIN32) && defined(USE_URANDOM)
static int seed_from_urandom(uint32_t *seed) {
/* Use unbuffered I/O if we have open(), close() and read(). Otherwise
fall back to fopen() */
char data[sizeof(uint32_t)];
int ok;
#if defined(HAVE_OPEN) && defined(HAVE_CLOSE) && defined(HAVE_READ)
int urandom;
urandom = open("/dev/urandom", O_RDONLY);
if (urandom == -1)
return 1;
ok = read(urandom, data, sizeof(uint32_t)) == sizeof(uint32_t);
close(urandom);
#else
FILE *urandom;
urandom = fopen("/dev/urandom", "rb");
if (!urandom)
return 1;
ok = fread(data, 1, sizeof(uint32_t), urandom) == sizeof(uint32_t);
fclose(urandom);
#endif
if (!ok)
return 1;
*seed = buf_to_uint32(data);
return 0;
}
#endif
/* Windows Crypto API */
#if defined(_WIN32) && defined(USE_WINDOWS_CRYPTOAPI)
#include <wincrypt.h>
typedef BOOL (WINAPI *CRYPTACQUIRECONTEXTA)(HCRYPTPROV *phProv, LPCSTR pszContainer, LPCSTR pszProvider, DWORD dwProvType, DWORD dwFlags);
typedef BOOL (WINAPI *CRYPTGENRANDOM)(HCRYPTPROV hProv, DWORD dwLen, BYTE *pbBuffer);
typedef BOOL (WINAPI *CRYPTRELEASECONTEXT)(HCRYPTPROV hProv, DWORD dwFlags);
static int seed_from_windows_cryptoapi(uint32_t *seed)
{
HINSTANCE hAdvAPI32 = NULL;
CRYPTACQUIRECONTEXTA pCryptAcquireContext = NULL;
CRYPTGENRANDOM pCryptGenRandom = NULL;
CRYPTRELEASECONTEXT pCryptReleaseContext = NULL;
HCRYPTPROV hCryptProv = 0;
BYTE data[sizeof(uint32_t)];
int ok;
hAdvAPI32 = GetModuleHandle(TEXT("advapi32.dll"));
if(hAdvAPI32 == NULL)
return 1;
pCryptAcquireContext = (CRYPTACQUIRECONTEXTA)GetProcAddress(hAdvAPI32, "CryptAcquireContextA");
if (!pCryptAcquireContext)
return 1;
pCryptGenRandom = (CRYPTGENRANDOM)GetProcAddress(hAdvAPI32, "CryptGenRandom");
if (!pCryptGenRandom)
return 1;
pCryptReleaseContext = (CRYPTRELEASECONTEXT)GetProcAddress(hAdvAPI32, "CryptReleaseContext");
if (!pCryptReleaseContext)
return 1;
if (!pCryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
return 1;
ok = pCryptGenRandom(hCryptProv, sizeof(uint32_t), data);
pCryptReleaseContext(hCryptProv, 0);
if (!ok)
return 1;
*seed = buf_to_uint32((char *)data);
return 0;
}
#endif
/* gettimeofday() and getpid() */
static int seed_from_timestamp_and_pid(uint32_t *seed) {
#ifdef HAVE_GETTIMEOFDAY
/* XOR of seconds and microseconds */
struct timeval tv;
gettimeofday(&tv, NULL);
*seed = (uint32_t)tv.tv_sec ^ (uint32_t)tv.tv_usec;
#else
/* Seconds only */
*seed = (uint32_t)time(NULL);
#endif
/* XOR with PID for more randomness */
#if defined(_WIN32)
*seed ^= (uint32_t)GetCurrentProcessId();
#elif defined(HAVE_GETPID)
*seed ^= (uint32_t)getpid();
#endif
return 0;
}
static uint32_t generate_seed() {
uint32_t seed;
int done = 0;
#if !defined(_WIN32) && defined(USE_URANDOM)
if (!done && seed_from_urandom(&seed) == 0)
done = 1;
#endif
#if defined(_WIN32) && defined(USE_WINDOWS_CRYPTOAPI)
if (!done && seed_from_windows_cryptoapi(&seed) == 0)
done = 1;
#endif
if (!done) {
/* Fall back to timestamp and PID if no better randomness is
available */
seed_from_timestamp_and_pid(&seed);
}
/* Make sure the seed is never zero */
if (seed == 0)
seed = 1;
return seed;
}
volatile uint32_t hashtable_seed = 0;
#if defined(HAVE_ATOMIC_BUILTINS) && (defined(HAVE_SCHED_YIELD) || !defined(_WIN32))
static volatile char seed_initialized = 0;
void json_object_seed(size_t seed) {
uint32_t new_seed = (uint32_t)seed;
if (hashtable_seed == 0) {
if (__atomic_test_and_set(&seed_initialized, __ATOMIC_RELAXED) == 0) {
/* Do the seeding ourselves */
if (new_seed == 0)
new_seed = generate_seed();
__atomic_store_n(&hashtable_seed, new_seed, __ATOMIC_RELEASE);
} else {
/* Wait for another thread to do the seeding */
do {
#ifdef HAVE_SCHED_YIELD
sched_yield();
#endif
} while(__atomic_load_n(&hashtable_seed, __ATOMIC_ACQUIRE) == 0);
}
}
}
#elif defined(HAVE_SYNC_BUILTINS) && (defined(HAVE_SCHED_YIELD) || !defined(_WIN32))
void json_object_seed(size_t seed) {
uint32_t new_seed = (uint32_t)seed;
if (hashtable_seed == 0) {
if (new_seed == 0) {
/* Explicit synchronization fences are not supported by the
__sync builtins, so every thread getting here has to
generate the seed value.
*/
new_seed = generate_seed();
}
do {
if (__sync_bool_compare_and_swap(&hashtable_seed, 0, new_seed)) {
/* We were the first to seed */
break;
} else {
/* Wait for another thread to do the seeding */
#ifdef HAVE_SCHED_YIELD
sched_yield();
#endif
}
} while(hashtable_seed == 0);
}
}
#elif defined(_WIN32)
static long seed_initialized = 0;
void json_object_seed(size_t seed) {
uint32_t new_seed = (uint32_t)seed;
if (hashtable_seed == 0) {
if (InterlockedIncrement(&seed_initialized) == 1) {
/* Do the seeding ourselves */
if (new_seed == 0)
new_seed = generate_seed();
hashtable_seed = new_seed;
} else {
/* Wait for another thread to do the seeding */
do {
SwitchToThread();
} while (hashtable_seed == 0);
}
}
}
#else
/* Fall back to a thread-unsafe version */
void json_object_seed(size_t seed) {
uint32_t new_seed = (uint32_t)seed;
if (hashtable_seed == 0) {
if (new_seed == 0)
new_seed = generate_seed();
hashtable_seed = new_seed;
}
}
#endif
+28 -19
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2013 Petri Lehtinen <[email protected]>
* Copyright (c) 2009-2014 Petri Lehtinen <[email protected]>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
@@ -21,11 +21,11 @@ extern "C" {
/* version */
#define JANSSON_MAJOR_VERSION 2
#define JANSSON_MINOR_VERSION 5
#define JANSSON_MINOR_VERSION 7
#define JANSSON_MICRO_VERSION 0
/* Micro version is omitted if it's 0 */
#define JANSSON_VERSION "2.5"
#define JANSSON_VERSION "2.7"
/* Version as a 3-byte hex number, e.g. 0x010201 == 1.2.1. Use this
for numeric comparisons, e.g. #if JANSSON_VERSION_HEX >= ... */
@@ -67,23 +67,26 @@ typedef long json_int_t;
#endif
#define json_typeof(json) ((json)->type)
#define json_is_object(json) (json && json_typeof(json) == JSON_OBJECT)
#define json_is_array(json) (json && json_typeof(json) == JSON_ARRAY)
#define json_is_string(json) (json && json_typeof(json) == JSON_STRING)
#define json_is_integer(json) (json && json_typeof(json) == JSON_INTEGER)
#define json_is_real(json) (json && json_typeof(json) == JSON_REAL)
#define json_is_object(json) ((json) && json_typeof(json) == JSON_OBJECT)
#define json_is_array(json) ((json) && json_typeof(json) == JSON_ARRAY)
#define json_is_string(json) ((json) && json_typeof(json) == JSON_STRING)
#define json_is_integer(json) ((json) && json_typeof(json) == JSON_INTEGER)
#define json_is_real(json) ((json) && json_typeof(json) == JSON_REAL)
#define json_is_number(json) (json_is_integer(json) || json_is_real(json))
#define json_is_true(json) (json && json_typeof(json) == JSON_TRUE)
#define json_is_false(json) (json && json_typeof(json) == JSON_FALSE)
#define json_is_true(json) ((json) && json_typeof(json) == JSON_TRUE)
#define json_is_false(json) ((json) && json_typeof(json) == JSON_FALSE)
#define json_boolean_value json_is_true
#define json_is_boolean(json) (json_is_true(json) || json_is_false(json))
#define json_is_null(json) (json && json_typeof(json) == JSON_NULL)
#define json_is_null(json) ((json) && json_typeof(json) == JSON_NULL)
/* construction, destruction, reference counting */
json_t *json_object(void);
json_t *json_array(void);
json_t *json_string(const char *value);
json_t *json_stringn(const char *value, size_t len);
json_t *json_string_nocheck(const char *value);
json_t *json_stringn_nocheck(const char *value, size_t len);
json_t *json_integer(json_int_t value);
json_t *json_real(double value);
json_t *json_true(void);
@@ -126,6 +129,7 @@ typedef struct {
/* getters, setters, manipulation */
void json_object_seed(size_t seed);
size_t json_object_size(const json_t *object);
json_t *json_object_get(const json_t *object, const char *key);
int json_object_set_new(json_t *object, const char *key, json_t *value);
@@ -199,16 +203,18 @@ int json_array_insert(json_t *array, size_t ind, json_t *value)
}
const char *json_string_value(const json_t *string);
size_t json_string_length(const json_t *string);
json_int_t json_integer_value(const json_t *integer);
double json_real_value(const json_t *real);
double json_number_value(const json_t *json);
int json_string_set(json_t *string, const char *value);
int json_string_setn(json_t *string, const char *value, size_t len);
int json_string_set_nocheck(json_t *string, const char *value);
int json_string_setn_nocheck(json_t *string, const char *value, size_t len);
int json_integer_set(json_t *integer, json_int_t value);
int json_real_set(json_t *real, double value);
/* pack, unpack */
json_t *json_pack(const char *fmt, ...);
@@ -240,6 +246,7 @@ json_t *json_deep_copy(const json_t *value);
#define JSON_DISABLE_EOF_CHECK 0x2
#define JSON_DECODE_ANY 0x4
#define JSON_DECODE_INT_AS_REAL 0x8
#define JSON_ALLOW_NUL 0x10
typedef size_t (*json_load_callback_t)(void *buffer, size_t buflen, void *data);
@@ -252,13 +259,15 @@ json_t *json_load_callback(json_load_callback_t callback, void *data, size_t fla
/* encoding */
#define JSON_INDENT(n) (n & 0x1F)
#define JSON_COMPACT 0x20
#define JSON_ENSURE_ASCII 0x40
#define JSON_SORT_KEYS 0x80
#define JSON_PRESERVE_ORDER 0x100
#define JSON_ENCODE_ANY 0x200
#define JSON_ESCAPE_SLASH 0x400
#define JSON_MAX_INDENT 0x1F
#define JSON_INDENT(n) ((n) & JSON_MAX_INDENT)
#define JSON_COMPACT 0x20
#define JSON_ENSURE_ASCII 0x40
#define JSON_SORT_KEYS 0x80
#define JSON_PRESERVE_ORDER 0x100
#define JSON_ENCODE_ANY 0x200
#define JSON_ESCAPE_SLASH 0x400
#define JSON_REAL_PRECISION(n) (((n) & 0x1F) << 11)
typedef int (*json_dump_callback_t)(const char *buffer, size_t size, void *data);
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2010-2013 Petri Lehtinen <[email protected]>
* Copyright (c) 2010-2014 Petri Lehtinen <[email protected]>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
+9 -3
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2013 Petri Lehtinen <[email protected]>
* Copyright (c) 2009-2014 Petri Lehtinen <[email protected]>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
@@ -49,6 +49,7 @@ typedef struct {
typedef struct {
json_t json;
char *value;
size_t length;
} json_string_t;
typedef struct {
@@ -64,9 +65,13 @@ typedef struct {
#define json_to_object(json_) container_of(json_, json_object_t, json)
#define json_to_array(json_) container_of(json_, json_array_t, json)
#define json_to_string(json_) container_of(json_, json_string_t, json)
#define json_to_real(json_) container_of(json_, json_real_t, json)
#define json_to_real(json_) container_of(json_, json_real_t, json)
#define json_to_integer(json_) container_of(json_, json_integer_t, json)
/* Create a string by taking ownership of an existing buffer */
json_t *jsonp_stringn_nocheck_own(const char *value, size_t len);
/* Error message formatting */
void jsonp_error_init(json_error_t *error, const char *source);
void jsonp_error_set_source(json_error_t *error, const char *source);
void jsonp_error_set(json_error_t *error, int line, int column,
@@ -76,13 +81,14 @@ void jsonp_error_vset(json_error_t *error, int line, int column,
/* Locale independent string<->double conversions */
int jsonp_strtod(strbuffer_t *strbuffer, double *out);
int jsonp_dtostr(char *buffer, size_t size, double value);
int jsonp_dtostr(char *buffer, size_t size, double value, int prec);
/* Wrappers for custom memory functions */
void* jsonp_malloc(size_t size);
void jsonp_free(void *ptr);
char *jsonp_strndup(const char *str, size_t length);
char *jsonp_strdup(const char *str);
char *jsonp_strndup(const char *str, size_t len);
/* Windows compatibility */
#ifdef _WIN32
+67 -39
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2013 Petri Lehtinen <[email protected]>
* Copyright (c) 2009-2014 Petri Lehtinen <[email protected]>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
@@ -63,7 +63,10 @@ typedef struct {
strbuffer_t saved_text;
int token;
union {
char *string;
struct {
char *val;
size_t len;
} string;
json_int_t integer;
double real;
} value;
@@ -279,6 +282,13 @@ static void lex_save_cached(lex_t *lex)
}
}
static void lex_free_string(lex_t *lex)
{
jsonp_free(lex->value.string.val);
lex->value.string.val = NULL;
lex->value.string.len = 0;
}
/* assumes that str points to 'u' plus at least 4 valid hex digits */
static int32_t decode_unicode_escape(const char *str)
{
@@ -297,7 +307,7 @@ static int32_t decode_unicode_escape(const char *str)
else if(l_isupper(c))
value += c - 'A' + 10;
else
assert(0);
return -1;
}
return value;
@@ -310,7 +320,7 @@ static void lex_scan_string(lex_t *lex, json_error_t *error)
char *t;
int i;
lex->value.string = NULL;
lex->value.string.val = NULL;
lex->token = TOKEN_INVALID;
c = lex_get_save(lex, error);
@@ -365,14 +375,12 @@ static void lex_scan_string(lex_t *lex, json_error_t *error)
- two \uXXXX escapes (length 12) forming an UTF-16 surrogate pair
are converted to 4 bytes
*/
lex->value.string = jsonp_malloc(lex->saved_text.length + 1);
if(!lex->value.string) {
t = jsonp_malloc(lex->saved_text.length + 1);
if(!t) {
/* this is not very nice, since TOKEN_INVALID is returned */
goto out;
}
/* the target */
t = lex->value.string;
lex->value.string.val = t;
/* + 1 to skip the " */
p = strbuffer_value(&lex->saved_text) + 1;
@@ -381,17 +389,24 @@ static void lex_scan_string(lex_t *lex, json_error_t *error)
if(*p == '\\') {
p++;
if(*p == 'u') {
char buffer[4];
int length;
size_t length;
int32_t value;
value = decode_unicode_escape(p);
if(value < 0) {
error_set(error, lex, "invalid Unicode escape '%.6s'", p - 1);
goto out;
}
p += 5;
if(0xD800 <= value && value <= 0xDBFF) {
/* surrogate pair */
if(*p == '\\' && *(p + 1) == 'u') {
int32_t value2 = decode_unicode_escape(++p);
if(value2 < 0) {
error_set(error, lex, "invalid Unicode escape '%.6s'", p - 1);
goto out;
}
p += 5;
if(0xDC00 <= value2 && value2 <= 0xDFFF) {
@@ -420,16 +435,9 @@ static void lex_scan_string(lex_t *lex, json_error_t *error)
error_set(error, lex, "invalid Unicode '\\u%04X'", value);
goto out;
}
else if(value == 0)
{
error_set(error, lex, "\\u0000 is not allowed");
goto out;
}
if(utf8_encode(value, buffer, &length))
if(utf8_encode(value, t, &length))
assert(0);
memcpy(t, buffer, length);
t += length;
}
else {
@@ -451,11 +459,12 @@ static void lex_scan_string(lex_t *lex, json_error_t *error)
*(t++) = *(p++);
}
*t = '\0';
lex->value.string.len = t - lex->value.string.val;
lex->token = TOKEN_STRING;
return;
out:
jsonp_free(lex->value.string);
lex_free_string(lex);
}
#ifndef JANSSON_USING_CMAKE /* disabled if using cmake */
@@ -474,7 +483,7 @@ static int lex_scan_number(lex_t *lex, int c, json_error_t *error)
{
const char *saved_text;
char *end;
double value;
double doubleval;
lex->token = TOKEN_INVALID;
@@ -499,16 +508,16 @@ static int lex_scan_number(lex_t *lex, int c, json_error_t *error)
}
if(c != '.' && c != 'E' && c != 'e') {
json_int_t value;
json_int_t intval;
lex_unget_unsave(lex, c);
saved_text = strbuffer_value(&lex->saved_text);
errno = 0;
value = json_strtoint(saved_text, &end, 10);
intval = json_strtoint(saved_text, &end, 10);
if(errno == ERANGE) {
if(value < 0)
if(intval < 0)
error_set(error, lex, "too big negative integer");
else
error_set(error, lex, "too big integer");
@@ -518,7 +527,7 @@ static int lex_scan_number(lex_t *lex, int c, json_error_t *error)
assert(end == saved_text + lex->saved_text.length);
lex->token = TOKEN_INTEGER;
lex->value.integer = value;
lex->value.integer = intval;
return 0;
}
@@ -552,13 +561,13 @@ static int lex_scan_number(lex_t *lex, int c, json_error_t *error)
lex_unget_unsave(lex, c);
if(jsonp_strtod(&lex->saved_text, &value)) {
if(jsonp_strtod(&lex->saved_text, &doubleval)) {
error_set(error, lex, "real number overflow");
goto out;
}
lex->token = TOKEN_REAL;
lex->value.real = value;
lex->value.real = doubleval;
return 0;
out:
@@ -571,10 +580,8 @@ static int lex_scan(lex_t *lex, json_error_t *error)
strbuffer_clear(&lex->saved_text);
if(lex->token == TOKEN_STRING) {
jsonp_free(lex->value.string);
lex->value.string = NULL;
}
if(lex->token == TOKEN_STRING)
lex_free_string(lex);
c = lex_get(lex, error);
while(c == ' ' || c == '\t' || c == '\n' || c == '\r')
@@ -635,13 +642,14 @@ out:
return lex->token;
}
static char *lex_steal_string(lex_t *lex)
static char *lex_steal_string(lex_t *lex, size_t *out_len)
{
char *result = NULL;
if(lex->token == TOKEN_STRING)
{
result = lex->value.string;
lex->value.string = NULL;
if(lex->token == TOKEN_STRING) {
result = lex->value.string.val;
*out_len = lex->value.string.len;
lex->value.string.val = NULL;
lex->value.string.len = 0;
}
return result;
}
@@ -659,7 +667,7 @@ static int lex_init(lex_t *lex, get_func get, void *data)
static void lex_close(lex_t *lex)
{
if(lex->token == TOKEN_STRING)
jsonp_free(lex->value.string);
lex_free_string(lex);
strbuffer_close(&lex->saved_text);
}
@@ -680,6 +688,7 @@ static json_t *parse_object(lex_t *lex, size_t flags, json_error_t *error)
while(1) {
char *key;
size_t len;
json_t *value;
if(lex->token != TOKEN_STRING) {
@@ -687,9 +696,14 @@ static json_t *parse_object(lex_t *lex, size_t flags, json_error_t *error)
goto error;
}
key = lex_steal_string(lex);
key = lex_steal_string(lex, &len);
if(!key)
return NULL;
if (memchr(key, '\0', len)) {
jsonp_free(key);
error_set(error, lex, "NUL byte in object key not supported");
goto error;
}
if(flags & JSON_REJECT_DUPLICATES) {
if(json_object_get(object, key)) {
@@ -788,7 +802,21 @@ static json_t *parse_value(lex_t *lex, size_t flags, json_error_t *error)
switch(lex->token) {
case TOKEN_STRING: {
json = json_string_nocheck(lex->value.string);
const char *value = lex->value.string.val;
size_t len = lex->value.string.len;
if(!(flags & JSON_ALLOW_NUL)) {
if(memchr(value, '\0', len)) {
error_set(error, lex, "\\u0000 is not allowed without JSON_ALLOW_NUL");
return NULL;
}
}
json = jsonp_stringn_nocheck_own(value, len);
if(json) {
lex->value.string.val = NULL;
lex->value.string.len = 0;
}
break;
}
+381
View File
@@ -0,0 +1,381 @@
/*
-------------------------------------------------------------------------------
lookup3.c, by Bob Jenkins, May 2006, Public Domain.
These are functions for producing 32-bit hashes for hash table lookup.
hashword(), hashlittle(), hashlittle2(), hashbig(), mix(), and final()
are externally useful functions. Routines to test the hash are included
if SELF_TEST is defined. You can use this free for any purpose. It's in
the public domain. It has no warranty.
You probably want to use hashlittle(). hashlittle() and hashbig()
hash byte arrays. hashlittle() is is faster than hashbig() on
little-endian machines. Intel and AMD are little-endian machines.
On second thought, you probably want hashlittle2(), which is identical to
hashlittle() except it returns two 32-bit hashes for the price of one.
You could implement hashbig2() if you wanted but I haven't bothered here.
If you want to find a hash of, say, exactly 7 integers, do
a = i1; b = i2; c = i3;
mix(a,b,c);
a += i4; b += i5; c += i6;
mix(a,b,c);
a += i7;
final(a,b,c);
then use c as the hash value. If you have a variable length array of
4-byte integers to hash, use hashword(). If you have a byte array (like
a character string), use hashlittle(). If you have several byte arrays, or
a mix of things, see the comments above hashlittle().
Why is this so big? I read 12 bytes at a time into 3 4-byte integers,
then mix those integers. This is fast (you can do a lot more thorough
mixing with 12*3 instructions on 3 integers than you can with 3 instructions
on 1 byte), but shoehorning those bytes into integers efficiently is messy.
-------------------------------------------------------------------------------
*/
#include <stdlib.h>
#ifdef HAVE_CONFIG_H
#include <jansson_private_config.h>
#endif
#ifdef HAVE_STDINT_H
#include <stdint.h> /* defines uint32_t etc */
#endif
#ifdef HAVE_SYS_PARAM_H
#include <sys/param.h> /* attempt to define endianness */
#endif
#ifdef HAVE_ENDIAN_H
# include <endian.h> /* attempt to define endianness */
#endif
/*
* My best guess at if you are big-endian or little-endian. This may
* need adjustment.
*/
#if (defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && \
__BYTE_ORDER == __LITTLE_ENDIAN) || \
(defined(i386) || defined(__i386__) || defined(__i486__) || \
defined(__i586__) || defined(__i686__) || defined(vax) || defined(MIPSEL))
# define HASH_LITTLE_ENDIAN 1
# define HASH_BIG_ENDIAN 0
#elif (defined(__BYTE_ORDER) && defined(__BIG_ENDIAN) && \
__BYTE_ORDER == __BIG_ENDIAN) || \
(defined(sparc) || defined(POWERPC) || defined(mc68000) || defined(sel))
# define HASH_LITTLE_ENDIAN 0
# define HASH_BIG_ENDIAN 1
#else
# define HASH_LITTLE_ENDIAN 0
# define HASH_BIG_ENDIAN 0
#endif
#define hashsize(n) ((uint32_t)1<<(n))
#define hashmask(n) (hashsize(n)-1)
#define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
/*
-------------------------------------------------------------------------------
mix -- mix 3 32-bit values reversibly.
This is reversible, so any information in (a,b,c) before mix() is
still in (a,b,c) after mix().
If four pairs of (a,b,c) inputs are run through mix(), or through
mix() in reverse, there are at least 32 bits of the output that
are sometimes the same for one pair and different for another pair.
This was tested for:
* pairs that differed by one bit, by two bits, in any combination
of top bits of (a,b,c), or in any combination of bottom bits of
(a,b,c).
* "differ" is defined as +, -, ^, or ~^. For + and -, I transformed
the output delta to a Gray code (a^(a>>1)) so a string of 1's (as
is commonly produced by subtraction) look like a single 1-bit
difference.
* the base values were pseudorandom, all zero but one bit set, or
all zero plus a counter that starts at zero.
Some k values for my "a-=c; a^=rot(c,k); c+=b;" arrangement that
satisfy this are
4 6 8 16 19 4
9 15 3 18 27 15
14 9 3 7 17 3
Well, "9 15 3 18 27 15" didn't quite get 32 bits diffing
for "differ" defined as + with a one-bit base and a two-bit delta. I
used http://burtleburtle.net/bob/hash/avalanche.html to choose
the operations, constants, and arrangements of the variables.
This does not achieve avalanche. There are input bits of (a,b,c)
that fail to affect some output bits of (a,b,c), especially of a. The
most thoroughly mixed value is c, but it doesn't really even achieve
avalanche in c.
This allows some parallelism. Read-after-writes are good at doubling
the number of bits affected, so the goal of mixing pulls in the opposite
direction as the goal of parallelism. I did what I could. Rotates
seem to cost as much as shifts on every machine I could lay my hands
on, and rotates are much kinder to the top and bottom bits, so I used
rotates.
-------------------------------------------------------------------------------
*/
#define mix(a,b,c) \
{ \
a -= c; a ^= rot(c, 4); c += b; \
b -= a; b ^= rot(a, 6); a += c; \
c -= b; c ^= rot(b, 8); b += a; \
a -= c; a ^= rot(c,16); c += b; \
b -= a; b ^= rot(a,19); a += c; \
c -= b; c ^= rot(b, 4); b += a; \
}
/*
-------------------------------------------------------------------------------
final -- final mixing of 3 32-bit values (a,b,c) into c
Pairs of (a,b,c) values differing in only a few bits will usually
produce values of c that look totally different. This was tested for
* pairs that differed by one bit, by two bits, in any combination
of top bits of (a,b,c), or in any combination of bottom bits of
(a,b,c).
* "differ" is defined as +, -, ^, or ~^. For + and -, I transformed
the output delta to a Gray code (a^(a>>1)) so a string of 1's (as
is commonly produced by subtraction) look like a single 1-bit
difference.
* the base values were pseudorandom, all zero but one bit set, or
all zero plus a counter that starts at zero.
These constants passed:
14 11 25 16 4 14 24
12 14 25 16 4 14 24
and these came close:
4 8 15 26 3 22 24
10 8 15 26 3 22 24
11 8 15 26 3 22 24
-------------------------------------------------------------------------------
*/
#define final(a,b,c) \
{ \
c ^= b; c -= rot(b,14); \
a ^= c; a -= rot(c,11); \
b ^= a; b -= rot(a,25); \
c ^= b; c -= rot(b,16); \
a ^= c; a -= rot(c,4); \
b ^= a; b -= rot(a,14); \
c ^= b; c -= rot(b,24); \
}
/*
-------------------------------------------------------------------------------
hashlittle() -- hash a variable-length key into a 32-bit value
k : the key (the unaligned variable-length array of bytes)
length : the length of the key, counting by bytes
initval : can be any 4-byte value
Returns a 32-bit value. Every bit of the key affects every bit of
the return value. Two keys differing by one or two bits will have
totally different hash values.
The best hash table sizes are powers of 2. There is no need to do
mod a prime (mod is sooo slow!). If you need less than 32 bits,
use a bitmask. For example, if you need only 10 bits, do
h = (h & hashmask(10));
In which case, the hash table should have hashsize(10) elements.
If you are hashing n strings (uint8_t **)k, do it like this:
for (i=0, h=0; i<n; ++i) h = hashlittle( k[i], len[i], h);
By Bob Jenkins, 2006. [email protected]. You may use this
code any way you wish, private, educational, or commercial. It's free.
Use for hash table lookup, or anything where one collision in 2^^32 is
acceptable. Do NOT use for cryptographic purposes.
-------------------------------------------------------------------------------
*/
static uint32_t hashlittle(const void *key, size_t length, uint32_t initval)
{
uint32_t a,b,c; /* internal state */
union { const void *ptr; size_t i; } u; /* needed for Mac Powerbook G4 */
/* Set up the internal state */
a = b = c = 0xdeadbeef + ((uint32_t)length) + initval;
u.ptr = key;
if (HASH_LITTLE_ENDIAN && ((u.i & 0x3) == 0)) {
const uint32_t *k = (const uint32_t *)key; /* read 32-bit chunks */
/* Detect Valgrind or AddressSanitizer */
#ifdef VALGRIND
# define NO_MASKING_TRICK 1
#else
# if defined(__has_feature) /* Clang */
# if __has_feature(address_sanitizer) /* is ASAN enabled? */
# define NO_MASKING_TRICK 1
# endif
# else
# if defined(__SANITIZE_ADDRESS__) /* GCC 4.8.x, is ASAN enabled? */
# define NO_MASKING_TRICK 1
# endif
# endif
#endif
#ifdef NO_MASKING_TRICK
const uint8_t *k8;
#endif
/*------ all but last block: aligned reads and affect 32 bits of (a,b,c) */
while (length > 12)
{
a += k[0];
b += k[1];
c += k[2];
mix(a,b,c);
length -= 12;
k += 3;
}
/*----------------------------- handle the last (probably partial) block */
/*
* "k[2]&0xffffff" actually reads beyond the end of the string, but
* then masks off the part it's not allowed to read. Because the
* string is aligned, the masked-off tail is in the same word as the
* rest of the string. Every machine with memory protection I've seen
* does it on word boundaries, so is OK with this. But VALGRIND will
* still catch it and complain. The masking trick does make the hash
* noticably faster for short strings (like English words).
*/
#ifndef NO_MASKING_TRICK
switch(length)
{
case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;
case 11: c+=k[2]&0xffffff; b+=k[1]; a+=k[0]; break;
case 10: c+=k[2]&0xffff; b+=k[1]; a+=k[0]; break;
case 9 : c+=k[2]&0xff; b+=k[1]; a+=k[0]; break;
case 8 : b+=k[1]; a+=k[0]; break;
case 7 : b+=k[1]&0xffffff; a+=k[0]; break;
case 6 : b+=k[1]&0xffff; a+=k[0]; break;
case 5 : b+=k[1]&0xff; a+=k[0]; break;
case 4 : a+=k[0]; break;
case 3 : a+=k[0]&0xffffff; break;
case 2 : a+=k[0]&0xffff; break;
case 1 : a+=k[0]&0xff; break;
case 0 : return c; /* zero length strings require no mixing */
}
#else /* make valgrind happy */
k8 = (const uint8_t *)k;
switch(length)
{
case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;
case 11: c+=((uint32_t)k8[10])<<16; /* fall through */
case 10: c+=((uint32_t)k8[9])<<8; /* fall through */
case 9 : c+=k8[8]; /* fall through */
case 8 : b+=k[1]; a+=k[0]; break;
case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */
case 6 : b+=((uint32_t)k8[5])<<8; /* fall through */
case 5 : b+=k8[4]; /* fall through */
case 4 : a+=k[0]; break;
case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */
case 2 : a+=((uint32_t)k8[1])<<8; /* fall through */
case 1 : a+=k8[0]; break;
case 0 : return c;
}
#endif /* !valgrind */
} else if (HASH_LITTLE_ENDIAN && ((u.i & 0x1) == 0)) {
const uint16_t *k = (const uint16_t *)key; /* read 16-bit chunks */
const uint8_t *k8;
/*--------------- all but last block: aligned reads and different mixing */
while (length > 12)
{
a += k[0] + (((uint32_t)k[1])<<16);
b += k[2] + (((uint32_t)k[3])<<16);
c += k[4] + (((uint32_t)k[5])<<16);
mix(a,b,c);
length -= 12;
k += 6;
}
/*----------------------------- handle the last (probably partial) block */
k8 = (const uint8_t *)k;
switch(length)
{
case 12: c+=k[4]+(((uint32_t)k[5])<<16);
b+=k[2]+(((uint32_t)k[3])<<16);
a+=k[0]+(((uint32_t)k[1])<<16);
break;
case 11: c+=((uint32_t)k8[10])<<16; /* fall through */
case 10: c+=k[4];
b+=k[2]+(((uint32_t)k[3])<<16);
a+=k[0]+(((uint32_t)k[1])<<16);
break;
case 9 : c+=k8[8]; /* fall through */
case 8 : b+=k[2]+(((uint32_t)k[3])<<16);
a+=k[0]+(((uint32_t)k[1])<<16);
break;
case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */
case 6 : b+=k[2];
a+=k[0]+(((uint32_t)k[1])<<16);
break;
case 5 : b+=k8[4]; /* fall through */
case 4 : a+=k[0]+(((uint32_t)k[1])<<16);
break;
case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */
case 2 : a+=k[0];
break;
case 1 : a+=k8[0];
break;
case 0 : return c; /* zero length requires no mixing */
}
} else { /* need to read the key one byte at a time */
const uint8_t *k = (const uint8_t *)key;
/*--------------- all but the last block: affect some 32 bits of (a,b,c) */
while (length > 12)
{
a += k[0];
a += ((uint32_t)k[1])<<8;
a += ((uint32_t)k[2])<<16;
a += ((uint32_t)k[3])<<24;
b += k[4];
b += ((uint32_t)k[5])<<8;
b += ((uint32_t)k[6])<<16;
b += ((uint32_t)k[7])<<24;
c += k[8];
c += ((uint32_t)k[9])<<8;
c += ((uint32_t)k[10])<<16;
c += ((uint32_t)k[11])<<24;
mix(a,b,c);
length -= 12;
k += 12;
}
/*-------------------------------- last block: affect all 32 bits of (c) */
switch(length) /* all the case statements fall through */
{
case 12: c+=((uint32_t)k[11])<<24;
case 11: c+=((uint32_t)k[10])<<16;
case 10: c+=((uint32_t)k[9])<<8;
case 9 : c+=k[8];
case 8 : b+=((uint32_t)k[7])<<24;
case 7 : b+=((uint32_t)k[6])<<16;
case 6 : b+=((uint32_t)k[5])<<8;
case 5 : b+=k[4];
case 4 : a+=((uint32_t)k[3])<<24;
case 3 : a+=((uint32_t)k[2])<<16;
case 2 : a+=((uint32_t)k[1])<<8;
case 1 : a+=k[0];
break;
case 0 : return c;
}
}
final(a,b,c);
return c;
}
+12 -7
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2013 Petri Lehtinen <[email protected]>
* Copyright (c) 2009-2014 Petri Lehtinen <[email protected]>
* Copyright (c) 2011-2012 Basile Starynkevitch <[email protected]>
*
* Jansson is free software; you can redistribute it and/or modify it
@@ -12,6 +12,10 @@
#include "jansson.h"
#include "jansson_private.h"
/* C89 allows these to be macros */
#undef malloc
#undef free
/* memory function pointers */
static json_malloc_t do_malloc = malloc;
static json_free_t do_free = free;
@@ -34,18 +38,19 @@ void jsonp_free(void *ptr)
char *jsonp_strdup(const char *str)
{
char *new_str;
size_t len;
return jsonp_strndup(str, strlen(str));
}
len = strlen(str);
if(len == (size_t)-1)
return NULL;
char *jsonp_strndup(const char *str, size_t len)
{
char *new_str;
new_str = jsonp_malloc(len + 1);
if(!new_str)
return NULL;
memcpy(new_str, str, len + 1);
memcpy(new_str, str, len);
new_str[len] = '\0';
return new_str;
}
+72 -29
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2013 Petri Lehtinen <[email protected]>
* Copyright (c) 2009-2014 Petri Lehtinen <[email protected]>
* Copyright (c) 2011-2012 Graeme Smecher <[email protected]>
*
* Jansson is free software; you can redistribute it and/or modify
@@ -125,19 +125,18 @@ static json_t *pack(scanner_t *s, va_list *ap);
/* ours will be set to 1 if jsonp_free() must be called for the result
afterwards */
static char *read_string(scanner_t *s, va_list *ap,
const char *purpose, int *ours)
const char *purpose, size_t *out_len, int *ours)
{
char t;
strbuffer_t strbuff;
const char *str;
size_t length;
char *result;
next_token(s);
t = token(s);
prev_token(s);
if(t != '#' && t != '+') {
if(t != '#' && t != '%' && t != '+') {
/* Optimize the simple case */
str = va_arg(*ap, const char *);
@@ -146,11 +145,14 @@ static char *read_string(scanner_t *s, va_list *ap,
return NULL;
}
if(!utf8_check_string(str, -1)) {
length = strlen(str);
if(!utf8_check_string(str, length)) {
set_error(s, "<args>", "Invalid UTF-8 %s", purpose);
return NULL;
}
*out_len = length;
*ours = 0;
return (char *)str;
}
@@ -170,6 +172,9 @@ static char *read_string(scanner_t *s, va_list *ap,
if(token(s) == '#') {
length = va_arg(*ap, int);
}
else if(token(s) == '%') {
length = va_arg(*ap, size_t);
}
else {
prev_token(s);
length = strlen(str);
@@ -188,15 +193,15 @@ static char *read_string(scanner_t *s, va_list *ap,
}
}
result = strbuffer_steal_value(&strbuff);
if(!utf8_check_string(result, -1)) {
if(!utf8_check_string(strbuff.value, strbuff.length)) {
set_error(s, "<args>", "Invalid UTF-8 %s", purpose);
strbuffer_close(&strbuff);
return NULL;
}
*out_len = strbuff.length;
*ours = 1;
return result;
return strbuffer_steal_value(&strbuff);
}
static json_t *pack_object(scanner_t *s, va_list *ap)
@@ -206,6 +211,7 @@ static json_t *pack_object(scanner_t *s, va_list *ap)
while(token(s) != '}') {
char *key;
size_t len;
int ours;
json_t *value;
@@ -219,15 +225,19 @@ static json_t *pack_object(scanner_t *s, va_list *ap)
goto error;
}
key = read_string(s, ap, "object key", &ours);
key = read_string(s, ap, "object key", &len, &ours);
if(!key)
goto error;
next_token(s);
value = pack(s, ap);
if(!value)
if(!value) {
if(ours)
jsonp_free(key);
goto error;
}
if(json_object_set_new_nocheck(object, key, value)) {
if(ours)
@@ -290,20 +300,20 @@ static json_t *pack(scanner_t *s, va_list *ap)
case '[':
return pack_array(s, ap);
case 's': { /* string */
case 's': /* string */
{
char *str;
size_t len;
int ours;
json_t *result;
str = read_string(s, ap, "string", &ours);
str = read_string(s, ap, "string", &len, &ours);
if(!str)
return NULL;
result = json_string_nocheck(str);
if(ours)
jsonp_free(str);
return result;
if (ours)
return jsonp_stringn_nocheck_own(str, len);
else
return json_stringn_nocheck(str, len);
}
case 'n': /* null */
@@ -340,6 +350,7 @@ static int unpack_object(scanner_t *s, json_t *root, va_list *ap)
{
int ret = -1;
int strict = 0;
int gotopt = 0;
/* Use a set (emulated by a hashtable) to check that all object
keys are accessed. Checking that the correct number of keys
@@ -396,7 +407,7 @@ static int unpack_object(scanner_t *s, json_t *root, va_list *ap)
next_token(s);
if(token(s) == '?') {
opt = 1;
opt = gotopt = 1;
next_token(s);
}
@@ -422,10 +433,26 @@ static int unpack_object(scanner_t *s, json_t *root, va_list *ap)
if(strict == 0 && (s->flags & JSON_STRICT))
strict = 1;
if(root && strict == 1 && key_set.size != json_object_size(root)) {
long diff = (long)json_object_size(root) - (long)key_set.size;
set_error(s, "<validation>", "%li object item(s) left unpacked", diff);
goto out;
if(root && strict == 1) {
/* We need to check that all non optional items have been parsed */
const char *key;
json_t *value;
long unpacked = 0;
if (gotopt) {
/* We have optional keys, we need to iter on each key */
json_object_foreach(root, key, value) {
if(!hashtable_get(&key_set, key)) {
unpacked++;
}
}
} else {
/* No optional keys, we can just compare the number of items */
unpacked = (long)json_object_size(root) - (long)key_set.size;
}
if (unpacked) {
set_error(s, "<validation>", "%li object item(s) left unpacked", unpacked);
goto out;
}
}
ret = 0;
@@ -523,16 +550,32 @@ static int unpack(scanner_t *s, json_t *root, va_list *ap)
}
if(!(s->flags & JSON_VALIDATE_ONLY)) {
const char **target;
const char **str_target;
size_t *len_target = NULL;
target = va_arg(*ap, const char **);
if(!target) {
str_target = va_arg(*ap, const char **);
if(!str_target) {
set_error(s, "<args>", "NULL string argument");
return -1;
}
if(root)
*target = json_string_value(root);
next_token(s);
if(token(s) == '%') {
len_target = va_arg(*ap, size_t *);
if(!len_target) {
set_error(s, "<args>", "NULL string length argument");
return -1;
}
}
else
prev_token(s);
if(root) {
*str_target = json_string_value(root);
if(len_target)
*len_target = json_string_length(root);
}
}
return 0;
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2013 Petri Lehtinen <[email protected]>
* Copyright (c) 2009-2014 Petri Lehtinen <[email protected]>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2013 Petri Lehtinen <[email protected]>
* Copyright (c) 2009-2014 Petri Lehtinen <[email protected]>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
+9 -5
View File
@@ -2,12 +2,13 @@
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include "jansson_private.h"
#include "strbuffer.h"
/* need config.h to get the correct snprintf */
/* need jansson_private_config.h to get the correct snprintf */
#ifdef HAVE_CONFIG_H
#include <config.h>
#include <jansson_private_config.h>
#endif
#if JSON_HAVE_LOCALECONV
@@ -69,7 +70,7 @@ int jsonp_strtod(strbuffer_t *strbuffer, double *out)
value = strtod(strbuffer->value, &end);
assert(end == strbuffer->value + strbuffer->length);
if(errno == ERANGE && value != 0) {
if((value == HUGE_VAL || value == -HUGE_VAL) && errno == ERANGE) {
/* Overflow */
return -1;
}
@@ -78,13 +79,16 @@ int jsonp_strtod(strbuffer_t *strbuffer, double *out)
return 0;
}
int jsonp_dtostr(char *buffer, size_t size, double value)
int jsonp_dtostr(char *buffer, size_t size, double value, int precision)
{
int ret;
char *start, *end;
size_t length;
ret = snprintf(buffer, size, "%.17g", value);
if (precision == 0)
precision = 17;
ret = snprintf(buffer, size, "%.*g", precision, value);
if(ret < 0)
return -1;
+13 -16
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2013 Petri Lehtinen <[email protected]>
* Copyright (c) 2009-2014 Petri Lehtinen <[email protected]>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
@@ -8,7 +8,7 @@
#include <string.h>
#include "utf.h"
int utf8_encode(int32_t codepoint, char *buffer, int *size)
int utf8_encode(int32_t codepoint, char *buffer, size_t *size)
{
if(codepoint < 0)
return -1;
@@ -44,7 +44,7 @@ int utf8_encode(int32_t codepoint, char *buffer, int *size)
return 0;
}
int utf8_check_first(char byte)
size_t utf8_check_first(char byte)
{
unsigned char u = (unsigned char)byte;
@@ -80,9 +80,9 @@ int utf8_check_first(char byte)
}
}
int utf8_check_full(const char *buffer, int size, int32_t *codepoint)
size_t utf8_check_full(const char *buffer, size_t size, int32_t *codepoint)
{
int i;
size_t i;
int32_t value = 0;
unsigned char u = (unsigned char)buffer[0];
@@ -136,12 +136,12 @@ int utf8_check_full(const char *buffer, int size, int32_t *codepoint)
return 1;
}
const char *utf8_iterate(const char *buffer, int32_t *codepoint)
const char *utf8_iterate(const char *buffer, size_t bufsize, int32_t *codepoint)
{
int count;
size_t count;
int32_t value;
if(!*buffer)
if(!bufsize)
return buffer;
count = utf8_check_first(buffer[0]);
@@ -152,7 +152,7 @@ const char *utf8_iterate(const char *buffer, int32_t *codepoint)
value = (unsigned char)buffer[0];
else
{
if(!utf8_check_full(buffer, count, &value))
if(count > bufsize || !utf8_check_full(buffer, count, &value))
return NULL;
}
@@ -162,21 +162,18 @@ const char *utf8_iterate(const char *buffer, int32_t *codepoint)
return buffer + count;
}
int utf8_check_string(const char *string, int length)
int utf8_check_string(const char *string, size_t length)
{
int i;
if(length == -1)
length = strlen(string);
size_t i;
for(i = 0; i < length; i++)
{
int count = utf8_check_first(string[i]);
size_t count = utf8_check_first(string[i]);
if(count == 0)
return 0;
else if(count > 1)
{
if(i + count > length)
if(count > length - i)
return 0;
if(!utf8_check_full(&string[i], count, NULL))
+11 -23
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2013 Petri Lehtinen <[email protected]>
* Copyright (c) 2009-2014 Petri Lehtinen <[email protected]>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
@@ -9,31 +9,19 @@
#define UTF_H
#ifdef HAVE_CONFIG_H
#include <config.h>
#include <jansson_private_config.h>
#endif
#ifdef HAVE_INTTYPES_H
/* inttypes.h includes stdint.h in a standard environment, so there's
no need to include stdint.h separately. If inttypes.h doesn't define
int32_t, it's defined in config.h. */
#include <inttypes.h>
#endif /* HAVE_INTTYPES_H */
#ifdef HAVE_STDINT_H
#include <stdint.h>
#endif
#else /* !HAVE_CONFIG_H */
#ifdef _WIN32
typedef int int32_t;
#else /* !_WIN32 */
/* Assume a standard environment */
#include <inttypes.h>
#endif /* _WIN32 */
int utf8_encode(int32_t codepoint, char *buffer, size_t *size);
#endif /* HAVE_CONFIG_H */
size_t utf8_check_first(char byte);
size_t utf8_check_full(const char *buffer, size_t size, int32_t *codepoint);
const char *utf8_iterate(const char *buffer, size_t size, int32_t *codepoint);
int utf8_encode(int codepoint, char *buffer, int *size);
int utf8_check_first(char byte);
int utf8_check_full(const char *buffer, int size, int32_t *codepoint);
const char *utf8_iterate(const char *buffer, int32_t *codepoint);
int utf8_check_string(const char *string, int length);
int utf8_check_string(const char *string, size_t length);
#endif
+111 -20
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2013 Petri Lehtinen <[email protected]>
* Copyright (c) 2009-2014 Petri Lehtinen <[email protected]>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
@@ -9,11 +9,19 @@
#define _GNU_SOURCE
#endif
#ifdef HAVE_CONFIG_H
#include <jansson_private_config.h>
#endif
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#ifdef HAVE_STDINT_H
#include <stdint.h>
#endif
#include "jansson.h"
#include "hashtable.h"
#include "jansson_private.h"
@@ -21,8 +29,10 @@
/* Work around nonstandard isnan() and isinf() implementations */
#ifndef isnan
#ifndef __sun
static JSON_INLINE int isnan(double x) { return x != x; }
#endif
#endif
#ifndef isinf
static JSON_INLINE int isinf(double x) { return !isnan(x) && isnan(x - x); }
#endif
@@ -36,11 +46,19 @@ static JSON_INLINE void json_init(json_t *json, json_type type)
/*** object ***/
extern volatile uint32_t hashtable_seed;
json_t *json_object(void)
{
json_object_t *object = jsonp_malloc(sizeof(json_object_t));
if(!object)
return NULL;
if (!hashtable_seed) {
/* Autoseed */
json_object_seed(0);
}
json_init(&object->json, JSON_OBJECT);
if(hashtable_init(&object->hashtable))
@@ -76,7 +94,7 @@ json_t *json_object_get(const json_t *json, const char *key)
{
json_object_t *object;
if(!json_is_object(json))
if(!key || !json_is_object(json))
return NULL;
object = json_to_object(json);
@@ -108,7 +126,7 @@ int json_object_set_new_nocheck(json_t *json, const char *key, json_t *value)
int json_object_set_new(json_t *json, const char *key, json_t *value)
{
if(!key || !utf8_check_string(key, -1))
if(!key || !utf8_check_string(key, strlen(key)))
{
json_decref(value);
return -1;
@@ -121,7 +139,7 @@ int json_object_del(json_t *json, const char *key)
{
json_object_t *object;
if(!json_is_object(json))
if(!key || !json_is_object(json))
return -1;
object = json_to_object(json);
@@ -620,33 +638,68 @@ static json_t *json_array_deep_copy(const json_t *array)
/*** string ***/
json_t *json_string_nocheck(const char *value)
static json_t *string_create(const char *value, size_t len, int own)
{
char *v;
json_string_t *string;
if(!value)
return NULL;
string = jsonp_malloc(sizeof(json_string_t));
if(!string)
return NULL;
json_init(&string->json, JSON_STRING);
if(own)
v = (char *)value;
else {
v = jsonp_strndup(value, len);
if(!v)
return NULL;
}
string->value = jsonp_strdup(value);
if(!string->value) {
jsonp_free(string);
string = jsonp_malloc(sizeof(json_string_t));
if(!string) {
if(!own)
jsonp_free(v);
return NULL;
}
json_init(&string->json, JSON_STRING);
string->value = v;
string->length = len;
return &string->json;
}
json_t *json_string(const char *value)
json_t *json_string_nocheck(const char *value)
{
if(!value || !utf8_check_string(value, -1))
if(!value)
return NULL;
return json_string_nocheck(value);
return string_create(value, strlen(value), 0);
}
json_t *json_stringn_nocheck(const char *value, size_t len)
{
return string_create(value, len, 0);
}
/* this is private; "steal" is not a public API concept */
json_t *jsonp_stringn_nocheck_own(const char *value, size_t len)
{
return string_create(value, len, 1);
}
json_t *json_string(const char *value)
{
if(!value)
return NULL;
return json_stringn(value, strlen(value));
}
json_t *json_stringn(const char *value, size_t len)
{
if(!value || !utf8_check_string(value, len))
return NULL;
return json_stringn_nocheck(value, len);
}
const char *json_string_value(const json_t *json)
@@ -657,7 +710,23 @@ const char *json_string_value(const json_t *json)
return json_to_string(json)->value;
}
size_t json_string_length(const json_t *json)
{
if(!json_is_string(json))
return 0;
return json_to_string(json)->length;
}
int json_string_set_nocheck(json_t *json, const char *value)
{
if(!value)
return -1;
return json_string_setn_nocheck(json, value, strlen(value));
}
int json_string_setn_nocheck(json_t *json, const char *value, size_t len)
{
char *dup;
json_string_t *string;
@@ -665,23 +734,32 @@ int json_string_set_nocheck(json_t *json, const char *value)
if(!json_is_string(json) || !value)
return -1;
dup = jsonp_strdup(value);
dup = jsonp_strndup(value, len);
if(!dup)
return -1;
string = json_to_string(json);
jsonp_free(string->value);
string->value = dup;
string->length = len;
return 0;
}
int json_string_set(json_t *json, const char *value)
{
if(!value || !utf8_check_string(value, -1))
if(!value)
return -1;
return json_string_set_nocheck(json, value);
return json_string_setn(json, value, strlen(value));
}
int json_string_setn(json_t *json, const char *value, size_t len)
{
if(!value || !utf8_check_string(value, len))
return -1;
return json_string_setn_nocheck(json, value, len);
}
static void json_delete_string(json_string_t *string)
@@ -692,12 +770,25 @@ static void json_delete_string(json_string_t *string)
static int json_string_equal(json_t *string1, json_t *string2)
{
return strcmp(json_string_value(string1), json_string_value(string2)) == 0;
json_string_t *s1, *s2;
if(!json_is_string(string1) || !json_is_string(string2))
return 0;
s1 = json_to_string(string1);
s2 = json_to_string(string2);
return s1->length == s2->length && !memcmp(s1->value, s2->value, s1->length);
}
static json_t *json_string_copy(const json_t *string)
{
return json_string_nocheck(json_string_value(string));
json_string_t *s;
if(!json_is_string(string))
return NULL;
s = json_to_string(string);
return json_stringn_nocheck(s->value, s->length);
}
@@ -614,6 +614,8 @@
918A074C1804B4A600983AE1 /* libjansson.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 918A07221804AFAA00983AE1 /* libjansson.a */; };
918A074D1804B4A600983AE1 /* libmongoose.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 918A07141804AF0F00983AE1 /* libmongoose.a */; };
9193B29817EDFEB7003CC0BA /* profiling.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9193B29717EDFEB7003CC0BA /* profiling.cpp */; };
91F4EE3A1AB32675006EF158 /* hashtable_seed.c in Sources */ = {isa = PBXBuildFile; fileRef = 91F4EE381AB32675006EF158 /* hashtable_seed.c */; };
91F4EE3B1AB32675006EF158 /* lookup3.h in Headers */ = {isa = PBXBuildFile; fileRef = 91F4EE391AB32675006EF158 /* lookup3.h */; };
F007DDF612F4F44600D2F6C1 /* jconfig.h in Headers */ = {isa = PBXBuildFile; fileRef = F007DDB512F4F44600D2F6C1 /* jconfig.h */; };
F007DDF712F4F44600D2F6C1 /* jdct.h in Headers */ = {isa = PBXBuildFile; fileRef = F007DDB612F4F44600D2F6C1 /* jdct.h */; };
F007DDF912F4F44600D2F6C1 /* jerror.h in Headers */ = {isa = PBXBuildFile; fileRef = F007DDB812F4F44600D2F6C1 /* jerror.h */; };
@@ -1556,6 +1558,8 @@
918A07361804B01800983AE1 /* utf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = utf.h; sourceTree = "<group>"; };
918A07371804B01800983AE1 /* value.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = value.c; sourceTree = "<group>"; };
9193B29717EDFEB7003CC0BA /* profiling.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = profiling.cpp; sourceTree = "<group>"; };
91F4EE381AB32675006EF158 /* hashtable_seed.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = hashtable_seed.c; sourceTree = "<group>"; };
91F4EE391AB32675006EF158 /* lookup3.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = lookup3.h; sourceTree = "<group>"; };
B2F67ED704C74A3F00A80002 /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = /System/Library/Frameworks/OpenGL.framework; sourceTree = "<absolute>"; };
B2F67F1E04C773E400A80002 /* GLUT.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = GLUT.framework; path = /System/Library/Frameworks/GLUT.framework; sourceTree = "<absolute>"; };
F007DDB512F4F44600D2F6C1 /* jconfig.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = jconfig.h; sourceTree = "<group>"; };
@@ -3116,6 +3120,8 @@
918A07261804B01800983AE1 /* jansson */ = {
isa = PBXGroup;
children = (
91F4EE381AB32675006EF158 /* hashtable_seed.c */,
91F4EE391AB32675006EF158 /* lookup3.h */,
918A07271804B01800983AE1 /* dump.c */,
918A07281804B01800983AE1 /* error.c */,
918A07291804B01800983AE1 /* hashtable.c */,
@@ -3544,6 +3550,7 @@
buildActionMask = 2147483647;
files = (
918A07461804B01800983AE1 /* utf.h in Headers */,
91F4EE3B1AB32675006EF158 /* lookup3.h in Headers */,
918A073B1804B01800983AE1 /* hashtable.h in Headers */,
918A073E1804B01800983AE1 /* jansson_private.h in Headers */,
918A07431804B01800983AE1 /* strbuffer.h in Headers */,
@@ -4219,6 +4226,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
91F4EE3A1AB32675006EF158 /* hashtable_seed.c in Sources */,
918A07451804B01800983AE1 /* utf.c in Sources */,
918A07391804B01800983AE1 /* error.c in Sources */,
918A07441804B01800983AE1 /* strconv.c in Sources */,
@@ -4587,6 +4595,13 @@
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
EXECUTABLE_PREFIX = lib;
GCC_PREPROCESSOR_DEFINITIONS = (
_DEBUG,
SCP_UNIX,
USE_OPENAL,
APPLE_APP,
HAVE_STDINT_H,
);
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
PRODUCT_NAME = "$(TARGET_NAME)";
};
@@ -4599,6 +4614,13 @@
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
EXECUTABLE_PREFIX = lib;
GCC_PREPROCESSOR_DEFINITIONS = (
NDEBUG,
SCP_UNIX,
USE_OPENAL,
APPLE_APP,
HAVE_STDINT_H,
);
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
PRODUCT_NAME = "$(TARGET_NAME)";
};