wow_dbc 1.0.3 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +10 -1
- data/ext/wow_dbc/wow_dbc.c +238 -92
- data/lib/wow_dbc/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: daa39b72eec7d417d3777f459f768921622f1a0977eb4a2482c5115088b1bff7
|
4
|
+
data.tar.gz: e7ed2d3250a931ba99285ef60b7b793ef1ca322f5002b677f7a2de80ae8d4eab
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 94eeb6ab0fcde158aada012a60fc0450cae3bd52763a964d044d3b2218fb59cbc23f6923be89e9d5252f1d33ec90459d72bae7960def2dff01ebb3842c2571ef
|
7
|
+
data.tar.gz: 83178273b7310b5f1fc0abbb435f07402ecbdfff288676b61f31a1c307d9b975e829a0060f8ff6daadecddf60767bc9cfd430168ae319bfbb6a6b25d38826b92
|
data/README.md
CHANGED
@@ -37,7 +37,16 @@ Here's a quick example of how to use WowDBC:
|
|
37
37
|
require 'wow_dbc'
|
38
38
|
|
39
39
|
# Correct field names for the Item.dbc file
|
40
|
-
field_names =
|
40
|
+
field_names = {
|
41
|
+
id: :uint32,
|
42
|
+
class: :uint32,
|
43
|
+
subclass: :uint32,
|
44
|
+
sound_override_subclass: :int32,
|
45
|
+
material: :uint32,
|
46
|
+
displayid: :uint32,
|
47
|
+
inventory_type: :uint32,
|
48
|
+
sheath_type: :uint32
|
49
|
+
}
|
41
50
|
|
42
51
|
# Open the Item.dbc file
|
43
52
|
dbc = WowDBC::DBCFile.new('path/to/your/Item.dbc', field_names)
|
data/ext/wow_dbc/wow_dbc.c
CHANGED
@@ -3,6 +3,23 @@
|
|
3
3
|
#include <stdint.h>
|
4
4
|
#include <string.h>
|
5
5
|
|
6
|
+
typedef enum {
|
7
|
+
TYPE_UINT32,
|
8
|
+
TYPE_INT32,
|
9
|
+
TYPE_FLOAT,
|
10
|
+
TYPE_STRING
|
11
|
+
} FieldType;
|
12
|
+
|
13
|
+
typedef struct {
|
14
|
+
FieldType type;
|
15
|
+
union {
|
16
|
+
uint32_t uint32_value;
|
17
|
+
int32_t int32_value;
|
18
|
+
float float_value;
|
19
|
+
uint32_t string_offset;
|
20
|
+
} value;
|
21
|
+
} FieldValue;
|
22
|
+
|
6
23
|
typedef struct {
|
7
24
|
char magic[4];
|
8
25
|
uint32_t record_count;
|
@@ -13,9 +30,9 @@ typedef struct {
|
|
13
30
|
|
14
31
|
typedef struct {
|
15
32
|
DBCHeader header;
|
16
|
-
|
33
|
+
FieldValue **records;
|
17
34
|
char *string_block;
|
18
|
-
VALUE
|
35
|
+
VALUE field_definitions; // Ruby hash of field names and types
|
19
36
|
} DBCFile;
|
20
37
|
|
21
38
|
static VALUE rb_mWowDBC;
|
@@ -38,8 +55,8 @@ static void dbc_free(void *ptr) {
|
|
38
55
|
static size_t dbc_memsize(const void *ptr) {
|
39
56
|
const DBCFile *dbc = (const DBCFile *)ptr;
|
40
57
|
return sizeof(DBCFile) +
|
41
|
-
(dbc->header.record_count * sizeof(
|
42
|
-
(dbc->header.record_count * dbc->header.field_count * sizeof(
|
58
|
+
(dbc->header.record_count * sizeof(FieldValue *)) +
|
59
|
+
(dbc->header.record_count * dbc->header.field_count * sizeof(FieldValue)) +
|
43
60
|
dbc->header.string_block_size;
|
44
61
|
}
|
45
62
|
|
@@ -56,13 +73,32 @@ static VALUE dbc_alloc(VALUE klass) {
|
|
56
73
|
return TypedData_Wrap_Struct(klass, &dbc_data_type, dbc);
|
57
74
|
}
|
58
75
|
|
59
|
-
static
|
76
|
+
static FieldType ruby_to_field_type(VALUE type_value) {
|
77
|
+
ID type_id;
|
78
|
+
|
79
|
+
if (RB_TYPE_P(type_value, T_SYMBOL)) {
|
80
|
+
type_id = SYM2ID(type_value);
|
81
|
+
} else if (RB_TYPE_P(type_value, T_STRING)) {
|
82
|
+
type_id = rb_intern(StringValueCStr(type_value));
|
83
|
+
} else {
|
84
|
+
rb_raise(rb_eTypeError, "Field type must be a symbol or string, got %s", rb_obj_classname(type_value));
|
85
|
+
}
|
86
|
+
|
87
|
+
if (type_id == rb_intern("uint32")) return TYPE_UINT32;
|
88
|
+
if (type_id == rb_intern("int32")) return TYPE_INT32;
|
89
|
+
if (type_id == rb_intern("float")) return TYPE_FLOAT;
|
90
|
+
if (type_id == rb_intern("string")) return TYPE_STRING;
|
91
|
+
|
92
|
+
rb_raise(rb_eArgError, "Invalid field type: %s", rb_id2name(type_id));
|
93
|
+
}
|
94
|
+
|
95
|
+
static VALUE dbc_initialize(VALUE self, VALUE filepath, VALUE field_definitions) {
|
60
96
|
DBCFile *dbc;
|
61
97
|
TypedData_Get_Struct(self, DBCFile, &dbc_data_type, dbc);
|
62
98
|
|
63
99
|
rb_iv_set(self, "@filepath", filepath);
|
64
|
-
dbc->
|
65
|
-
rb_iv_set(self, "@
|
100
|
+
dbc->field_definitions = rb_hash_dup(field_definitions);
|
101
|
+
rb_iv_set(self, "@field_definitions", dbc->field_definitions);
|
66
102
|
|
67
103
|
return self;
|
68
104
|
}
|
@@ -82,7 +118,6 @@ static VALUE dbc_read(VALUE self) {
|
|
82
118
|
rb_raise(rb_eIOError, "Failed to read DBC header");
|
83
119
|
}
|
84
120
|
|
85
|
-
// Free existing records if any
|
86
121
|
if (dbc->records) {
|
87
122
|
for (uint32_t i = 0; i < dbc->header.record_count; i++) {
|
88
123
|
free(dbc->records[i]);
|
@@ -90,16 +125,42 @@ static VALUE dbc_read(VALUE self) {
|
|
90
125
|
free(dbc->records);
|
91
126
|
}
|
92
127
|
|
93
|
-
dbc->records = ALLOC_N(
|
128
|
+
dbc->records = ALLOC_N(FieldValue *, dbc->header.record_count);
|
129
|
+
VALUE field_definitions = rb_iv_get(self, "@field_definitions");
|
130
|
+
VALUE field_names = rb_funcall(field_definitions, rb_intern("keys"), 0);
|
131
|
+
|
94
132
|
for (uint32_t i = 0; i < dbc->header.record_count; i++) {
|
95
|
-
dbc->records[i] = ALLOC_N(
|
96
|
-
|
97
|
-
|
98
|
-
|
133
|
+
dbc->records[i] = ALLOC_N(FieldValue, dbc->header.field_count);
|
134
|
+
for (uint32_t j = 0; j < dbc->header.field_count; j++) {
|
135
|
+
VALUE field_name = rb_ary_entry(field_names, j);
|
136
|
+
VALUE field_type = rb_hash_aref(field_definitions, field_name);
|
137
|
+
|
138
|
+
FieldType type;
|
139
|
+
if (NIL_P(field_type)) {
|
140
|
+
type = TYPE_UINT32; // Default to UINT32 if type is nil
|
141
|
+
} else {
|
142
|
+
type = ruby_to_field_type(field_type);
|
143
|
+
}
|
144
|
+
dbc->records[i][j].type = type;
|
145
|
+
|
146
|
+
if (fread(&dbc->records[i][j].value, sizeof(uint32_t), 1, file) != 1) {
|
147
|
+
fclose(file);
|
148
|
+
rb_raise(rb_eIOError, "Failed to read DBC record field");
|
149
|
+
}
|
150
|
+
|
151
|
+
switch (type) {
|
152
|
+
case TYPE_UINT32:
|
153
|
+
break;
|
154
|
+
case TYPE_INT32:
|
155
|
+
break;
|
156
|
+
case TYPE_FLOAT:
|
157
|
+
break;
|
158
|
+
case TYPE_STRING:
|
159
|
+
break;
|
160
|
+
}
|
99
161
|
}
|
100
162
|
}
|
101
163
|
|
102
|
-
// Free existing string block if any
|
103
164
|
if (dbc->string_block) {
|
104
165
|
free(dbc->string_block);
|
105
166
|
}
|
@@ -111,6 +172,7 @@ static VALUE dbc_read(VALUE self) {
|
|
111
172
|
}
|
112
173
|
|
113
174
|
fclose(file);
|
175
|
+
|
114
176
|
return self;
|
115
177
|
}
|
116
178
|
|
@@ -130,9 +192,11 @@ static VALUE dbc_write(VALUE self) {
|
|
130
192
|
}
|
131
193
|
|
132
194
|
for (uint32_t i = 0; i < dbc->header.record_count; i++) {
|
133
|
-
|
134
|
-
|
135
|
-
|
195
|
+
for (uint32_t j = 0; j < dbc->header.field_count; j++) {
|
196
|
+
if (fwrite(&dbc->records[i][j].value, sizeof(uint32_t), 1, file) != 1) {
|
197
|
+
fclose(file);
|
198
|
+
rb_raise(rb_eIOError, "Failed to write DBC record field");
|
199
|
+
}
|
136
200
|
}
|
137
201
|
}
|
138
202
|
|
@@ -145,30 +209,62 @@ static VALUE dbc_write(VALUE self) {
|
|
145
209
|
return self;
|
146
210
|
}
|
147
211
|
|
212
|
+
static VALUE field_value_to_ruby(FieldValue *value, char *string_block) {
|
213
|
+
switch (value->type) {
|
214
|
+
case TYPE_UINT32:
|
215
|
+
return UINT2NUM(value->value.uint32_value);
|
216
|
+
case TYPE_INT32:
|
217
|
+
return INT2NUM(value->value.int32_value);
|
218
|
+
case TYPE_FLOAT:
|
219
|
+
return DBL2NUM(value->value.float_value);
|
220
|
+
case TYPE_STRING:
|
221
|
+
return rb_str_new2(&string_block[value->value.string_offset]);
|
222
|
+
}
|
223
|
+
return Qnil;
|
224
|
+
}
|
225
|
+
|
226
|
+
static void ruby_to_field_value(VALUE ruby_value, FieldType type, FieldValue *field_value) {
|
227
|
+
field_value->type = type;
|
228
|
+
switch (type) {
|
229
|
+
case TYPE_UINT32:
|
230
|
+
field_value->value.uint32_value = NUM2UINT(ruby_value);
|
231
|
+
break;
|
232
|
+
case TYPE_INT32:
|
233
|
+
field_value->value.int32_value = NUM2INT(ruby_value);
|
234
|
+
break;
|
235
|
+
case TYPE_FLOAT:
|
236
|
+
field_value->value.float_value = (float)NUM2DBL(ruby_value);
|
237
|
+
break;
|
238
|
+
case TYPE_STRING:
|
239
|
+
field_value->value.string_offset = NUM2UINT(ruby_value);
|
240
|
+
break;
|
241
|
+
}
|
242
|
+
}
|
243
|
+
|
148
244
|
static VALUE dbc_create_record(VALUE self) {
|
149
245
|
DBCFile *dbc;
|
150
246
|
TypedData_Get_Struct(self, DBCFile, &dbc_data_type, dbc);
|
151
247
|
|
152
248
|
uint32_t new_count = dbc->header.record_count + 1;
|
153
|
-
REALLOC_N(dbc->records,
|
154
|
-
dbc->records[new_count - 1] = ALLOC_N(
|
155
|
-
memset(dbc->records[new_count - 1], 0, dbc->header.field_count * sizeof(
|
249
|
+
REALLOC_N(dbc->records, FieldValue *, new_count);
|
250
|
+
dbc->records[new_count - 1] = ALLOC_N(FieldValue, dbc->header.field_count);
|
251
|
+
memset(dbc->records[new_count - 1], 0, dbc->header.field_count * sizeof(FieldValue));
|
156
252
|
|
157
253
|
dbc->header.record_count = new_count;
|
158
254
|
|
159
255
|
return INT2FIX(new_count - 1);
|
160
256
|
}
|
161
257
|
|
162
|
-
static VALUE dbc_update_record(VALUE self, VALUE index, VALUE
|
258
|
+
static VALUE dbc_update_record(VALUE self, VALUE index, VALUE field, VALUE value) {
|
163
259
|
DBCFile *dbc;
|
164
260
|
TypedData_Get_Struct(self, DBCFile, &dbc_data_type, dbc);
|
165
261
|
|
166
262
|
long idx = FIX2LONG(index);
|
167
263
|
long field_idx = -1;
|
168
264
|
|
169
|
-
|
170
|
-
for (long i = 0; i < RARRAY_LEN(
|
171
|
-
if (rb_eql(rb_ary_entry(
|
265
|
+
VALUE field_names = rb_funcall(dbc->field_definitions, rb_intern("keys"), 0);
|
266
|
+
for (long i = 0; i < RARRAY_LEN(field_names); i++) {
|
267
|
+
if (rb_eql(rb_ary_entry(field_names, i), field)) {
|
172
268
|
field_idx = i;
|
173
269
|
break;
|
174
270
|
}
|
@@ -178,25 +274,25 @@ static VALUE dbc_update_record(VALUE self, VALUE index, VALUE field_name, VALUE
|
|
178
274
|
rb_raise(rb_eArgError, "Invalid record or field index");
|
179
275
|
}
|
180
276
|
|
181
|
-
|
182
|
-
|
183
|
-
return Qnil;
|
184
|
-
}
|
277
|
+
VALUE field_type = rb_hash_aref(dbc->field_definitions, field);
|
278
|
+
FieldType type = ruby_to_field_type(field_type);
|
185
279
|
|
186
|
-
|
187
|
-
|
188
|
-
|
280
|
+
if (type == TYPE_STRING) {
|
281
|
+
// For string fields, we need to update the string block
|
282
|
+
char *str = StringValueCStr(value);
|
283
|
+
uint32_t offset = dbc->header.string_block_size;
|
284
|
+
uint32_t str_len = strlen(str) + 1;
|
189
285
|
|
190
|
-
|
286
|
+
dbc->string_block = realloc(dbc->string_block, dbc->header.string_block_size + str_len);
|
287
|
+
memcpy(dbc->string_block + offset, str, str_len);
|
288
|
+
dbc->header.string_block_size += str_len;
|
191
289
|
|
192
|
-
|
193
|
-
|
290
|
+
dbc->records[idx][field_idx].type = TYPE_STRING;
|
291
|
+
dbc->records[idx][field_idx].value.string_offset = offset;
|
292
|
+
} else {
|
293
|
+
ruby_to_field_value(value, type, &dbc->records[idx][field_idx]);
|
194
294
|
}
|
195
295
|
|
196
|
-
free(dbc->records[idx]);
|
197
|
-
memmove(&dbc->records[idx], &dbc->records[idx + 1], (dbc->header.record_count - idx - 1) * sizeof(uint32_t *));
|
198
|
-
dbc->header.record_count--;
|
199
|
-
|
200
296
|
return Qnil;
|
201
297
|
}
|
202
298
|
|
@@ -211,9 +307,10 @@ static VALUE dbc_get_record(VALUE self, VALUE index) {
|
|
211
307
|
}
|
212
308
|
|
213
309
|
VALUE record = rb_hash_new();
|
310
|
+
VALUE field_names = rb_funcall(dbc->field_definitions, rb_intern("keys"), 0);
|
214
311
|
for (uint32_t i = 0; i < dbc->header.field_count; i++) {
|
215
|
-
VALUE field_name = rb_ary_entry(
|
216
|
-
rb_hash_aset(record, field_name,
|
312
|
+
VALUE field_name = rb_ary_entry(field_names, i);
|
313
|
+
rb_hash_aset(record, field_name, field_value_to_ruby(&dbc->records[idx][i], dbc->string_block));
|
217
314
|
}
|
218
315
|
|
219
316
|
return record;
|
@@ -233,47 +330,47 @@ static VALUE dbc_get_header(VALUE self) {
|
|
233
330
|
return header;
|
234
331
|
}
|
235
332
|
|
236
|
-
static VALUE
|
333
|
+
static VALUE dbc_update_record_multi(VALUE self, VALUE index, VALUE updates) {
|
237
334
|
DBCFile *dbc;
|
238
335
|
TypedData_Get_Struct(self, DBCFile, &dbc_data_type, dbc);
|
239
336
|
|
240
|
-
|
241
|
-
REALLOC_N(dbc->records, uint32_t *, new_count);
|
242
|
-
dbc->records[new_count - 1] = ALLOC_N(uint32_t, dbc->header.field_count);
|
243
|
-
memset(dbc->records[new_count - 1], 0, dbc->header.field_count * sizeof(uint32_t));
|
337
|
+
long idx = FIX2LONG(index);
|
244
338
|
|
245
|
-
|
246
|
-
|
247
|
-
|
339
|
+
if (idx < 0 || (uint32_t)idx >= dbc->header.record_count) {
|
340
|
+
rb_raise(rb_eArgError, "Invalid record index");
|
341
|
+
}
|
342
|
+
|
343
|
+
if (RB_TYPE_P(updates, T_HASH)) {
|
344
|
+
VALUE keys = rb_funcall(updates, rb_intern("keys"), 0);
|
248
345
|
for (long i = 0; i < RARRAY_LEN(keys); i++) {
|
249
346
|
VALUE key = rb_ary_entry(keys, i);
|
250
|
-
VALUE value = rb_hash_aref(
|
347
|
+
VALUE value = rb_hash_aref(updates, key);
|
251
348
|
long field_idx = -1;
|
252
349
|
|
253
|
-
|
254
|
-
|
350
|
+
VALUE field_names = rb_funcall(dbc->field_definitions, rb_intern("keys"), 0);
|
351
|
+
for (long j = 0; j < RARRAY_LEN(field_names); j++) {
|
352
|
+
if (rb_eql(rb_ary_entry(field_names, j), key)) {
|
255
353
|
field_idx = j;
|
256
354
|
break;
|
257
355
|
}
|
258
356
|
}
|
259
357
|
|
260
358
|
if (field_idx >= 0 && (uint32_t)field_idx < dbc->header.field_count) {
|
261
|
-
|
359
|
+
VALUE field_type = rb_hash_aref(dbc->field_definitions, key);
|
360
|
+
FieldType type = ruby_to_field_type(field_type);
|
361
|
+
ruby_to_field_value(value, type, &dbc->records[idx][field_idx]);
|
262
362
|
} else {
|
263
|
-
|
264
|
-
free(dbc->records[new_count - 1]);
|
265
|
-
REALLOC_N(dbc->records, uint32_t *, dbc->header.record_count);
|
266
|
-
rb_raise(rb_eArgError, "Invalid field name: %s", rb_id2name(SYM2ID(key)));
|
363
|
+
rb_raise(rb_eArgError, "Invalid field name: %"PRIsVALUE, key);
|
267
364
|
}
|
268
365
|
}
|
366
|
+
} else {
|
367
|
+
rb_raise(rb_eArgError, "Updates must be a hash");
|
269
368
|
}
|
270
369
|
|
271
|
-
|
272
|
-
|
273
|
-
return INT2FIX(new_count - 1);
|
370
|
+
return Qnil;
|
274
371
|
}
|
275
372
|
|
276
|
-
static VALUE
|
373
|
+
static VALUE dbc_delete_record(VALUE self, VALUE index) {
|
277
374
|
DBCFile *dbc;
|
278
375
|
TypedData_Get_Struct(self, DBCFile, &dbc_data_type, dbc);
|
279
376
|
|
@@ -283,29 +380,9 @@ static VALUE dbc_update_record_multi(VALUE self, VALUE index, VALUE updates) {
|
|
283
380
|
rb_raise(rb_eArgError, "Invalid record index");
|
284
381
|
}
|
285
382
|
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
VALUE key = rb_ary_entry(keys, i);
|
290
|
-
VALUE value = rb_hash_aref(updates, key);
|
291
|
-
long field_idx = -1;
|
292
|
-
|
293
|
-
for (long j = 0; j < RARRAY_LEN(dbc->field_names); j++) {
|
294
|
-
if (rb_eql(rb_ary_entry(dbc->field_names, j), key)) {
|
295
|
-
field_idx = j;
|
296
|
-
break;
|
297
|
-
}
|
298
|
-
}
|
299
|
-
|
300
|
-
if (field_idx >= 0 && (uint32_t)field_idx < dbc->header.field_count) {
|
301
|
-
dbc->records[idx][field_idx] = NUM2UINT(value);
|
302
|
-
} else {
|
303
|
-
rb_raise(rb_eArgError, "Invalid field name: %s", rb_id2name(SYM2ID(key)));
|
304
|
-
}
|
305
|
-
}
|
306
|
-
} else {
|
307
|
-
rb_raise(rb_eArgError, "Updates must be a hash");
|
308
|
-
}
|
383
|
+
free(dbc->records[idx]);
|
384
|
+
memmove(&dbc->records[idx], &dbc->records[idx + 1], (dbc->header.record_count - idx - 1) * sizeof(FieldValue *));
|
385
|
+
dbc->header.record_count--;
|
309
386
|
|
310
387
|
return Qnil;
|
311
388
|
}
|
@@ -315,10 +392,10 @@ static VALUE dbc_find_by(VALUE self, VALUE field, VALUE value) {
|
|
315
392
|
TypedData_Get_Struct(self, DBCFile, &dbc_data_type, dbc);
|
316
393
|
|
317
394
|
long field_idx = -1;
|
395
|
+
VALUE field_names = rb_funcall(dbc->field_definitions, rb_intern("keys"), 0);
|
318
396
|
|
319
|
-
|
320
|
-
|
321
|
-
if (rb_eql(rb_ary_entry(dbc->field_names, i), field)) {
|
397
|
+
for (long i = 0; i < RARRAY_LEN(field_names); i++) {
|
398
|
+
if (rb_eql(rb_ary_entry(field_names, i), field)) {
|
322
399
|
field_idx = i;
|
323
400
|
break;
|
324
401
|
}
|
@@ -331,11 +408,12 @@ static VALUE dbc_find_by(VALUE self, VALUE field, VALUE value) {
|
|
331
408
|
VALUE result = rb_ary_new();
|
332
409
|
|
333
410
|
for (uint32_t i = 0; i < dbc->header.record_count; i++) {
|
334
|
-
|
411
|
+
VALUE field_value = field_value_to_ruby(&dbc->records[i][field_idx], dbc->string_block);
|
412
|
+
if (rb_eql(field_value, value)) {
|
335
413
|
VALUE record = rb_hash_new();
|
336
414
|
for (uint32_t j = 0; j < dbc->header.field_count; j++) {
|
337
|
-
VALUE field_name = rb_ary_entry(
|
338
|
-
rb_hash_aset(record, field_name,
|
415
|
+
VALUE field_name = rb_ary_entry(field_names, j);
|
416
|
+
rb_hash_aset(record, field_name, field_value_to_ruby(&dbc->records[i][j], dbc->string_block));
|
339
417
|
}
|
340
418
|
rb_ary_push(result, record);
|
341
419
|
}
|
@@ -362,9 +440,11 @@ static VALUE dbc_write_to(VALUE self, VALUE new_filepath) {
|
|
362
440
|
}
|
363
441
|
|
364
442
|
for (uint32_t i = 0; i < dbc->header.record_count; i++) {
|
365
|
-
|
366
|
-
|
367
|
-
|
443
|
+
for (uint32_t j = 0; j < dbc->header.field_count; j++) {
|
444
|
+
if (fwrite(&dbc->records[i][j].value, sizeof(uint32_t), 1, file) != 1) {
|
445
|
+
fclose(file);
|
446
|
+
rb_raise(rb_eIOError, "Failed to write DBC record");
|
447
|
+
}
|
368
448
|
}
|
369
449
|
}
|
370
450
|
|
@@ -377,6 +457,72 @@ static VALUE dbc_write_to(VALUE self, VALUE new_filepath) {
|
|
377
457
|
return self;
|
378
458
|
}
|
379
459
|
|
460
|
+
static VALUE dbc_create_record_with_values(VALUE self, VALUE values) {
|
461
|
+
DBCFile *dbc;
|
462
|
+
TypedData_Get_Struct(self, DBCFile, &dbc_data_type, dbc);
|
463
|
+
|
464
|
+
if (!RB_TYPE_P(values, T_HASH)) {
|
465
|
+
rb_raise(rb_eArgError, "Values must be a hash");
|
466
|
+
}
|
467
|
+
|
468
|
+
// Check for invalid field names
|
469
|
+
VALUE keys = rb_funcall(values, rb_intern("keys"), 0);
|
470
|
+
for (long i = 0; i < RARRAY_LEN(keys); i++) {
|
471
|
+
VALUE key = rb_ary_entry(keys, i);
|
472
|
+
if (NIL_P(rb_hash_aref(dbc->field_definitions, key))) {
|
473
|
+
rb_raise(rb_eArgError, "Invalid field name: %"PRIsVALUE, key);
|
474
|
+
}
|
475
|
+
}
|
476
|
+
|
477
|
+
uint32_t new_count = dbc->header.record_count + 1;
|
478
|
+
REALLOC_N(dbc->records, FieldValue *, new_count);
|
479
|
+
dbc->records[new_count - 1] = ALLOC_N(FieldValue, dbc->header.field_count);
|
480
|
+
|
481
|
+
VALUE field_names = rb_funcall(dbc->field_definitions, rb_intern("keys"), 0);
|
482
|
+
for (uint32_t i = 0; i < dbc->header.field_count; i++) {
|
483
|
+
VALUE field_name = rb_ary_entry(field_names, i);
|
484
|
+
VALUE value = rb_hash_aref(values, field_name);
|
485
|
+
VALUE field_type = rb_hash_aref(dbc->field_definitions, field_name);
|
486
|
+
FieldType type = ruby_to_field_type(field_type);
|
487
|
+
|
488
|
+
if (NIL_P(value)) {
|
489
|
+
// Set default values for missing fields
|
490
|
+
switch (type) {
|
491
|
+
case TYPE_UINT32:
|
492
|
+
case TYPE_INT32:
|
493
|
+
dbc->records[new_count - 1][i].value.uint32_value = 0;
|
494
|
+
break;
|
495
|
+
case TYPE_FLOAT:
|
496
|
+
dbc->records[new_count - 1][i].value.float_value = 0.0f;
|
497
|
+
break;
|
498
|
+
case TYPE_STRING:
|
499
|
+
dbc->records[new_count - 1][i].value.string_offset = 0; // Empty string
|
500
|
+
break;
|
501
|
+
}
|
502
|
+
} else {
|
503
|
+
if (type == TYPE_STRING) {
|
504
|
+
char *str = StringValueCStr(value);
|
505
|
+
uint32_t offset = dbc->header.string_block_size;
|
506
|
+
uint32_t str_len = strlen(str) + 1;
|
507
|
+
|
508
|
+
dbc->string_block = realloc(dbc->string_block, dbc->header.string_block_size + str_len);
|
509
|
+
memcpy(dbc->string_block + offset, str, str_len);
|
510
|
+
dbc->header.string_block_size += str_len;
|
511
|
+
|
512
|
+
dbc->records[new_count - 1][i].type = TYPE_STRING;
|
513
|
+
dbc->records[new_count - 1][i].value.string_offset = offset;
|
514
|
+
} else {
|
515
|
+
ruby_to_field_value(value, type, &dbc->records[new_count - 1][i]);
|
516
|
+
}
|
517
|
+
}
|
518
|
+
dbc->records[new_count - 1][i].type = type;
|
519
|
+
}
|
520
|
+
|
521
|
+
dbc->header.record_count = new_count;
|
522
|
+
|
523
|
+
return INT2FIX(new_count - 1);
|
524
|
+
}
|
525
|
+
|
380
526
|
void Init_wow_dbc(void) {
|
381
527
|
rb_mWowDBC = rb_define_module("WowDBC");
|
382
528
|
rb_cDBCFile = rb_define_class_under(rb_mWowDBC, "DBCFile", rb_cObject);
|
data/lib/wow_dbc/version.rb
CHANGED