1 /* Distributed under the 4-part Berkeley License */
2
3 /*
4 * afflib_db.cpp:
5 *
6 * Functions for the manipulation of the AFF database.
7 */
8
9
10 #include "affconfig.h"
11 #include "afflib.h"
12 #include "afflib_i.h"
13 #include "aff_db.h"
14
15
16 /****************************************************************
17 *** Low-level functions
18 ****************************************************************/
19
20 /****************************************************************
21 *** Probe Functions
22 ****************************************************************/
23
af_probe_next_seg(AFFILE * af,char * segname,size_t segname_len,uint32_t * arg_,size_t * datasize_,size_t * segsize_,int do_rewind)24 int af_probe_next_seg(AFFILE *af,
25 char *segname,
26 size_t segname_len,
27 uint32_t *arg_, // optional arg
28 size_t *datasize_, // optional get datasize
29 size_t *segsize_, // optional get size of entire segment
30 int do_rewind) // optional rewind af->aseg, otherwise leave at start of segment data
31 {
32 if(!af->aseg)(*af->error_reporter)("af_probe_next_segment only works with aff files");
33
34 struct af_segment_head segh;
35 memset(&segh,0,sizeof(segh));
36
37 uint64_t start = ftello(af->aseg);
38 #ifdef __BORLANDC__
39 fseeko(af->aseg, start, SEEK_SET) ; // Windows is dumb :-(
40 #endif
41
42 if(fread(&segh,sizeof(segh),1,af->aseg)!=1){
43 return AF_ERROR_EOF;
44 }
45 if(strcmp(segh.magic,AF_SEGHEAD)!=0){
46 snprintf(af->error_str,sizeof(af->error_str),"afflib: segh is corrupt at %" PRIu64,start);
47 return AF_ERROR_SEGH;
48 }
49
50 uint32_t name_len = ntohl(segh.name_len);
51 uint32_t datasize = ntohl(segh.data_len);
52 if(name_len>AF_MAX_NAME_LEN){
53 snprintf(af->error_str,sizeof(af->error_str),"afflib: name_len=%" PRIu32 " (an outrageous value)",name_len);
54 return AF_ERROR_NAME;
55 }
56
57 if(name_len+1 > segname_len){
58 fseeko(af->aseg,start,SEEK_SET); // rewind to start
59 return -2;
60 }
61
62 if(fread(segname,1,name_len,af->aseg)!=name_len){
63 fseeko(af->aseg,start,SEEK_SET); // rewind
64 return -1;
65 }
66 segname[name_len] = 0;
67
68 if(do_rewind) fseeko(af->aseg,start,SEEK_SET); // rewind
69
70 uint32_t segsize = sizeof(struct af_segment_head)
71 + sizeof(struct af_segment_tail)
72 + name_len + datasize;
73
74 if(arg_) *arg_ = ntohl(segh.flag);
75 if(datasize_) *datasize_ = datasize;
76 if(segsize_) *segsize_ = segsize;
77
78 #ifdef DEBUG
79 fprintf(stderr,"af_probe_next_seg(segname=%s datasize=%d segsize=%d) do_rewind=%d\n",
80 segname,datasize,segsize,do_rewind);
81 #endif
82 return 0;
83 }
84
85 /* af_backspace:
86 * moves back one segment in the aff file.
87 * Returns 0 if success, -1 if we can't back up further.
88 */
af_backspace(AFFILE * af)89 int af_backspace(AFFILE *af)
90 {
91 struct af_segment_tail segt;
92
93 uint64_t start = ftello(af->aseg);
94
95 if(start==sizeof(AF_HEADER) || start<sizeof(segt)) return -1; // can't backspace further
96
97 uint64_t pos_tail = start - sizeof(segt); // backspace to read the tail
98 fseeko(af->aseg,pos_tail,SEEK_SET);
99 if(fread(&segt,sizeof(segt),1,af->aseg)!=1){
100 fseeko(af->aseg,start,SEEK_SET); // put it back
101 return -1; // can't read segt?
102 }
103 /* Verify that this is a segment tail. if it isn't, put the file pointer back and return */
104 if(memcmp(segt.magic,AF_SEGTAIL,sizeof(AF_SEGTAIL))!=0){
105 fseeko(af->aseg,start,SEEK_SET);
106 return -1;
107 }
108
109 /* Now I know how long the segment was. Compute where it started */
110 uint64_t seg_start = start - ntohl(segt.segment_len);
111 fseeko(af->aseg,seg_start,SEEK_SET);
112 return 0;
113 }
114
115
116
117 /* find the given segment and return 0 if found.
118 * Leave the file pointer positioned at the start of the segment.
119 * Return -1 if segment is not found, and leave pointer at the end
120 */
aff_find_seg(AFFILE * af,const char * segname,uint32_t * arg,size_t * datasize,size_t * segsize)121 int aff_find_seg(AFFILE *af,const char *segname,
122 uint32_t *arg,
123 size_t *datasize,
124 size_t *segsize)
125 {
126 char next_segment_name[AF_MAX_NAME_LEN];
127 size_t next_segsize = 0;
128 size_t next_datasize = 0;
129 uint32_t next_arg;
130
131 /* Try to use the TOC to find the segment in question */
132 struct aff_toc_mem *adm = aff_toc(af,segname);
133 if(adm){
134 if(datasize==0 && segsize==0 && arg==0){
135 /* User was just probing to see if it was present. And it is! */
136 return 0;
137 }
138 fseeko(af->aseg,adm->offset,SEEK_SET);
139 }
140 else {
141 af_rewind_seg(af);
142 }
143 while(af_probe_next_seg(af,next_segment_name,sizeof(next_segment_name),
144 &next_arg,&next_datasize,&next_segsize,1)==0){
145 if(strcmp(next_segment_name,segname)==0){ // found the segment!
146 if(datasize) *datasize = next_datasize;
147 if(segsize) *segsize = next_segsize;
148 if(arg) *arg = next_arg;
149 return 0; // return the info
150 }
151 fseeko(af->aseg,next_segsize,SEEK_CUR); // skip the segment
152 }
153 return -1; // couldn't find segment
154 }
155
af_get_segq(AFFILE * af,const char * name,int64_t * aff_quad)156 int af_get_segq(AFFILE *af,const char *name,int64_t *aff_quad)
157 {
158 unsigned char buf[8];
159 size_t bufsize = sizeof(buf);
160
161 if(af_get_seg(af,name,0,(unsigned char *)&buf,&bufsize)){
162 return -1; // couldn't get it...
163 }
164 if(bufsize!=sizeof(struct aff_quad)){ // make sure size is good.
165 return -1;
166 }
167
168 *aff_quad = af_decode_q(buf);
169 return 0;
170 }
171
172
173 /* af_update_segq:
174 * Update the named aff_quad-byte value.
175 */
176
177
af_update_segq(AFFILE * af,const char * name,int64_t value)178 int af_update_segq(AFFILE *af, const char *name, int64_t value)
179 {
180 struct aff_quad q;
181 q.low = htonl((uint32_t)(value & 0xffffffff));
182 q.high = htonl((uint32_t)(value >> 32));
183 return af_update_seg(af,name,AF_SEG_QUADWORD,(const u_char *)&q,8);
184 }
185
186
187