wow_dbc 1.0.3 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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