OpenCores
URL https://opencores.org/ocsvn/forwardcom/forwardcom/trunk

Subversion Repositories forwardcom

[/] [forwardcom/] [bintools/] [containers.cpp] - Blame information for rev 79

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 48 Agner
/****************************  containers.cpp  **********************************
2
* Author:        Agner Fog
3
* Date created:  2006-07-15
4
* Last modified: 2018-03-30
5
* Version:       1.10
6
* Project:       Binary tools for ForwardCom instruction set
7
*
8
* This module contains container classes CMemoryBuffer and CFileBuffer for
9
* dynamic memory allocation and file read/write. See containers.h for
10
* further description.
11
*
12
* Copyright 2006-2020 GNU General Public License http://www.gnu.org/licenses
13
*****************************************************************************/
14
 
15
#include "stdafx.h"
16
 
17
// Names of file formats
18
SIntTxt FileFormatNames[] = {
19
    {FILETYPE_ELF,          "x86 ELF"},
20
    {FILETYPE_FWC,          "ForwardCom ELF"},
21
    {FILETYPE_ASM,          "assembly"},
22
    {FILETYPE_FWC_EXE,      "forwardCom executable"},
23
    {FILETYPE_FWC_LIB,      "forwardCom library"},
24
    {FILETYPE_LIBRARY,      "library"}
25
};
26
 
27
 
28
// Members of class CMemoryBuffer
29
 
30
// Constructor
31
CMemoryBuffer::CMemoryBuffer() {
32
    buffer = 0;
33
    num_entries = data_size = buffer_size = 0;
34
}
35
 
36
// Destructor
37
CMemoryBuffer::~CMemoryBuffer() {
38
    clear();                                  // De-allocate buffer
39
}
40
 
41
// De-allocate buffer
42
void CMemoryBuffer::clear() {
43
    if (buffer) delete[] buffer;
44
    buffer = 0;
45
    num_entries = data_size = buffer_size = 0;
46
}
47
 
48
// Set all contents to zero without changing data size
49
void CMemoryBuffer::zero() {
50
    if (buffer) memset(buffer, 0, buffer_size);
51
}
52
 
53
void CMemoryBuffer::setSize(uint32_t size) {
54
    // Allocate, reallocate or deallocate buffer of specified size.
55
    // DataSize is initially zero. It is increased by push or pushString.
56
    // Setting size > dataSize will allocate more buffer and fill it with zeroes but not increase dataSize.
57
    // Setting size < dataSize will decrease dataSize so that some of the data are discarded.
58
    if (size < data_size) {
59
        // Request to delete some data
60
        data_size = size;
61
        if (size == 0) num_entries = 0;
62
        return;
63
    }
64
    if (size <= buffer_size) {
65
        // Request to reduce size but not delete it
66
        return;                                  // Ignore
67
    }
68
    size = (size + buffer_size + 15) & uint32_t(-16);   // Double size and round up to value divisible by 16
69
    int8_t * buffer2 = 0;                        // New buffer
70
    buffer2 = new int8_t[size];                  // Allocate new buffer
71
    if (buffer2 == 0) {err.submit(ERR_MEMORY_ALLOCATION); return;} // Error can't allocate
72
    memset (buffer2, 0, size);                   // Initialize to all zeroes
73
    if (buffer) {
74
        // A smaller buffer is previously allocated
75
        memcpy (buffer2, buffer, buffer_size);   // Copy contents of old buffer into new
76
        delete[] buffer;                         // De-allocate old buffer
77
    }
78
    buffer = buffer2;                            // Save pointer to buffer
79
    buffer_size = size;                          // Save size
80
}
81
 
82
void CMemoryBuffer::setDataSize(uint32_t size) {
83
    // Set data size and fill any new data with zeroes
84
    if (size > buffer_size) {
85
        setSize(size);
86
    }
87
    else if (size > data_size) {
88
        memset(buffer + data_size, 0, size - data_size);
89
    }
90
    data_size = size;
91
}
92
 
93
uint32_t CMemoryBuffer::push(void const * obj, uint32_t size) {
94
    // Add object to buffer, return offset
95
    // Parameters: 
96
    // obj = pointer to object, 0 if fill with zeroes
97
    // size = size of object to push
98
 
99
    // Old offset will be offset to new object
100
    uint32_t OldOffset = data_size;
101
 
102
    // New data size will be old data size plus size of new object
103
    uint32_t NewOffset = data_size + size;
104
 
105
    if (NewOffset > buffer_size) {
106
        // Buffer too small, allocate more space.
107
        // We can use SetSize for this only if it is certain that obj is not 
108
        // pointing to an object previously allocated in the old buffer
109
        // because it would be deallocated before copied into the new buffer:
110
        // SetSize (NewOffset + NewOffset / 2 + 1024);
111
 
112
        // Allocate more space without using SetSize:
113
        // Double the size + 1 kB, and round up size to value divisible by 16
114
        uint32_t NewSize = (NewOffset * 2 + 1024 + 15) & uint32_t(-16);
115
        int8_t * buffer2 = 0;                    // New buffer
116
        // Allocate new buffer
117
        buffer2 = new int8_t[NewSize];
118
        if (buffer2 == 0) {
119
            // Error can't allocate
120
            err.submit(ERR_MEMORY_ALLOCATION);  return 0;
121
        }
122
        // Initialize to all zeroes
123
        memset (buffer2, 0, NewSize);
124
        if (buffer) {
125
            // A smaller buffer is previously allocated
126
            // Copy contents of old buffer into new
127
            memcpy (buffer2, buffer, buffer_size);
128
        }
129
        buffer_size = NewSize;                   // Save size
130
        if (obj && size) {
131
            // Copy object to new buffer
132
            memcpy (buffer2 + OldOffset, obj, size);
133
            obj = 0;                             // Prevent copying once more
134
        }
135
        // Delete old buffer after copying object
136
        if (buffer) delete[] buffer;
137
 
138
        // Save pointer to new buffer
139
        buffer = buffer2;
140
    }
141
    // Copy object to buffer if nonzero
142
    if (obj && size) {
143
        memcpy (buffer + OldOffset, obj, size);
144
    }
145
    if (size) {
146
        // Adjust new offset
147
        data_size = NewOffset;
148
    }
149
    num_entries++;
150
 
151
    // Return offset to allocated object
152
    return OldOffset;
153
}
154
 
155
uint32_t CMemoryBuffer::pushString(char const * s) {
156
    // Add ASCIIZ string to buffer, return offset
157
    return push (s, uint32_t(strlen(s))+1);
158
}
159
 
160
uint32_t CMemoryBuffer::getLastIndex() const {
161
    // Index of last object pushed (zero-based)
162
    return num_entries - 1;
163
}
164
 
165
void CMemoryBuffer::align(uint32_t a) {
166
    // Align next entry to address divisible by a. must be a power of 2
167
    // uint32_t NewOffset = (data_size + a - 1) / a * a;   // use this if a is not a power of 2
168
    uint32_t NewOffset = (data_size + a - 1) & (-(int32_t)a);
169
    if (NewOffset > buffer_size) {
170
        // Allocate more space
171
        setSize (NewOffset + 2048);
172
    }
173
    // Set DataSize to after alignment space
174
    data_size = NewOffset;
175
}
176
 
177
// Make a copy of whole buffer
178
void CMemoryBuffer::copy(CMemoryBuffer const & b) {
179
    setSize(0);                                  // clear own buffer
180
    setSize(b.dataSize());                       // set new size
181
    memcpy(buffer, b.buf(), b.dataSize());       // copy data
182
    num_entries = b.numEntries();                // copy num_entries
183
    data_size = b.dataSize();                    // size used
184
}
185
 
186
// Members of class CFileBuffer
187
CFileBuffer::CFileBuffer() : CMemoryBuffer() {
188
    // Default constructor
189
    fileType = wordSize = executable = 0;
190
}
191
 
192
void CFileBuffer::read(const char * filename, int ignoreError) {
193
    // Read file into buffer
194
    // InoreError: 0: abort on error, CMDL_FILE_IN_IF_EXISTS: ignore error, CMDL_FILE_SEARCH_PATH: search for file also in exe directory
195
    uint32_t status;                             // Error status
196
 
197
    const int MAXPATHL = 1024;  //!                 // Buffer for constructing file path
198
    char name[MAXPATHL];
199
#if defined (_WIN32) || defined (__WINDOWS__)
200
    const char slash[2] = "\\";  // path separator depends on operating system
201
#else
202
    const char slash[2] = "/";
203
#endif
204
 
205
#ifdef _MSC_VER  // Microsoft compiler prefers this:
206
 
207
    int fh;                                      // File handle
208
    fh = _open(filename, O_RDONLY | O_BINARY);   // Open file in binary mode
209
    if (fh == -1) {
210
        if (ignoreError == CMDL_FILE_SEARCH_PATH && strlen(cmd.programName) + strlen(filename) < MAXPATHL) {
211
            // Search for file in directory of executable file
212
            strcpy(name, cmd.programName);
213
            char *s1 = name, * s2;               // find last slash
214
            do {
215
                s2 = strchr(s1+1, slash[0]);
216
                if (s2) s1 = s2;  else *s1 = 0;
217
            } while(s2);
218
            strcat(name, slash);
219
            strcat(name, filename);
220
            fh = _open(name, O_RDONLY | O_BINARY); // Open file in binary mode
221
        }
222
        if (fh == -1) {
223
            // Cannot read file
224
            if (ignoreError != CMDL_FILE_IN_IF_EXISTS) err.submit(ERR_INPUT_FILE, filename); // Error. Input file must be read
225
            setSize(0); return;                  // Make empty file buffer
226
        }
227
    }
228
    data_size = _filelength(fh);                 // Get file size
229
    if (data_size <= 0) {
230
        if (ignoreError == 0) err.submit(ERR_FILE_SIZE, filename); // Wrong size
231
        return;}
232
    setSize(data_size + 2048);                   // Allocate buffer, 2k extra
233
    status = _read(fh, buf(), data_size);        // Read from file
234
    if (status != data_size) err.submit(ERR_INPUT_FILE, filename);
235
    status = _close(fh);                         // Close file
236
    if (status != 0) err.submit(ERR_INPUT_FILE, filename);
237
 
238
#else              // Works with most compilers:
239
 
240
    FILE * fh = fopen(filename, "rb");
241
    if (!fh) {
242
        // Cannot read file
243
        if (ignoreError == CMDL_FILE_SEARCH_PATH && strlen(cmd.programName) + strlen(filename) < MAXPATHL) {
244
            // Search for file in directory of executable file
245
            strcpy(name, cmd.programName);
246
            char *s1 = name, * s2;               // find last slash
247
            do {
248
                s2 = strchr(s1+1, slash[0]);
249
                if (s2) s1 = s2;  else *s1 = 0;
250
            } while(s2);
251
            strcat(name, slash);
252
            strcat(name, filename);
253
            fh = fopen(name, "rb");
254
        }
255
        if (!fh) {
256
            // Cannot read file
257
            if (ignoreError != CMDL_FILE_IN_IF_EXISTS) err.submit(ERR_INPUT_FILE, filename); // Error. Input file must be read
258
            setSize(0); return;                  // Make empty file buffer
259
        }
260
    }
261
    // Find file size
262
    fseek(fh, 0, SEEK_END);
263
    long int fsize = ftell(fh);
264
    if (fsize <= 0 && ignoreError == 0) {
265
        // File zero size
266
        err.submit(ERR_FILE_SIZE, filename); fclose(fh); return;
267
    }
268
    if ((unsigned long)fsize >= 0xFFFFFFFF) {
269
        // File too big 
270
        err.submit(ERR_FILE_SIZE, filename); fclose(fh); return;
271
    }
272
    data_size = (uint32_t)fsize;
273
    rewind(fh);
274
    // Allocate buffer
275
    setSize(data_size + 2048);                    // Allocate buffer, 2k extra
276
    // Read entire file
277
    status = (uint32_t)fread(buf(), 1, data_size, fh);
278
    if (status != data_size) err.submit(ERR_INPUT_FILE, filename);
279
    status = fclose(fh);
280
    if (status != 0) err.submit(ERR_INPUT_FILE, filename);
281
 
282
#endif
283
}
284
 
285
void CFileBuffer::write(const char * filename) {
286
    // Write buffer to file:
287
 
288
    // Two alternative ways to write a file:
289
 
290
#ifdef _MSC_VER    // Microsoft compiler prefers this:
291
 
292
    int fh;                                      // File handle
293
    uint32_t status;                             // Error status
294
    // Open file in binary mode
295
    fh = _open(filename, O_RDWR | O_BINARY | O_CREAT | O_TRUNC, _S_IREAD | _S_IWRITE);
296
    // Check if error
297
    if (fh == -1) {err.submit(ERR_OUTPUT_FILE, filename);  return;}
298
    // Write file
299
    status = _write(fh, buf(), data_size);
300
    // Check if error
301
    if (status != data_size) err.submit(ERR_OUTPUT_FILE, filename);
302
    // Close file
303
    status = _close(fh);
304
    // Check if error
305
    if (status != 0) err.submit(ERR_OUTPUT_FILE, filename);
306
 
307
#else              // Works with most compilers:
308
 
309
    // Open file in binary mode
310
    FILE * ff = fopen(filename, "wb");
311
    // Check if error
312
    if (!ff) {err.submit(ERR_OUTPUT_FILE, filename);  return;}
313
    // Write file
314
    uint32_t n = (uint32_t)fwrite(buf(), 1, data_size, ff);
315
    // Check if error
316
    if (n != data_size) err.submit(ERR_OUTPUT_FILE, filename);
317
    // Close file
318
    n = fclose(ff);
319
    // Check if error
320
    if (n) {err.submit(ERR_OUTPUT_FILE, filename);  return;}
321
 
322
#endif
323
}
324
 
325
int CFileBuffer::getFileType() {
326
    // Detect file type
327
    //if (fileType) return fileType;             // Must re-evaluate fileType in case buffer is reused
328
    if (!data_size) return 0;                    // No file
329
    if (!buf()) return 0;                        // No contents
330
 
331
    //uint32_t namelen = fileName ? (uint32_t)strlen(fileName) : 0;
332
 
333
    //if (strncmp((char*)Buf(),ELFMAG,4) == 0) {
334
    if (get<uint32_t>(0) == ELFMAG) {
335
        // ELF file
336
        fileType = FILETYPE_ELF;
337
        executable = get<ElfFwcEhdr>(0).e_type != ET_REL;
338
        switch (buf()[EI_CLASS]) {
339
        case ELFCLASS32:
340
            wordSize = 32; break;
341
        case ELFCLASS64:
342
            wordSize = 64; break;
343
        }
344
        machineType = get<ElfFwcEhdr>(0).e_machine;   // Copy file header.e_machine;
345
        if (machineType == EM_FORWARDCOM) fileType = FILETYPE_FWC;
346
    }
347
    else if (memcmp(buf(), archiveSignature, 8) == 0) {
348
        fileType = FILETYPE_LIBRARY;
349
    }
350
    else {
351
        // Unknown file type
352
        int utype = get<uint32_t>(0);
353
       // err.submit(ERR_UNKNOWN_FILE_TYPE, utype, fileName); 
354
        err.submit(ERR_UNKNOWN_FILE_TYPE, utype, "!");
355
        fileType = 0;
356
    }
357
    return fileType;
358
}
359
 
360
 
361
char const * CFileBuffer::getFileFormatName(int FileType) {
362
    // Get name of file format type
363
    return Lookup (FileFormatNames, FileType);
364
}
365
 
366
 
367
void CFileBuffer::setFileType(int type) {
368
    // Set file format type
369
    fileType = type;
370
}
371
 
372
void CFileBuffer::reset() {
373
    // Set all members to zero
374
    clear();                                  // Deallocate memory buffer
375
    zeroAllMembers(*this);
376
}
377
 
378
void operator >> (CMemoryBuffer & a, CMemoryBuffer & b) {
379
    // Transfer ownership of buffer and other properties from a to b
380
    b.clear();                                   // De-allocate old buffer from target if it has one
381
    b.buffer = a.buffer;                         // Transfer buffer
382
    a.buffer = 0;                                // Remove buffer from source, so that buffer has only one owner
383
 
384
    // Copy properties
385
    b.data_size   = a.dataSize();                // Size of data, offset to vacant space
386
    b.buffer_size = a.bufferSize();              // Size of allocated buffer
387
    b.num_entries = a.numEntries();              // Number of objects pushed
388
    a.clear();                                   // Reset a's properties
389
}
390
 
391
void operator >> (CFileBuffer & a, CFileBuffer & b) {
392
    // Transfer ownership of buffer and other properties from a to b
393
    b.clear();                                   // De-allocate old buffer from target if it has one
394
    b.buffer = a.buffer;                         // Transfer buffer
395
    a.buffer = 0;                                // Remove buffer from source, so that buffer has only one owner
396
 
397
    // Copy properties
398
    b.data_size   = a.dataSize();                // Size of data, offset to vacant space
399
    b.buffer_size = a.bufferSize();              // Size of allocated buffer
400
    b.num_entries = a.numEntries();              // Number of objects pushed
401
    b.executable = a.executable;                 // File is executable
402
    b.machineType = a.machineType;               // Machine type
403
    if (a.wordSize) b.wordSize = a.wordSize;     // Segment word size (16, 32, 64)
404
    if (a.getFileType()) {
405
        b.fileType = a.getFileType();            // Object file type
406
    }
407
    a.clear();                                   // Reset a's properties
408
}
409
 
410
 
411
// Class CTextFileBuffer is used for building text files
412
// Constructor
413
CTextFileBuffer::CTextFileBuffer() {
414
    column = 0;
415
#ifdef _WIN32
416
    lineType = 0;                                // DOS/Windows type linefeed
417
#else
418
    lineType = 1;                                // Unix type linefeed
419
#endif
420
}
421
 
422
uint32_t CTextFileBuffer::put(const char * text) {
423
    // Write text string to buffer
424
    uint32_t len = (uint32_t)strlen(text);       // Length of text
425
    uint32_t ret = push(text, len);              // Add to buffer without terminating zero
426
    column += len;                               // Update column
427
    return ret;                                  // Return index
428
}
429
 
430
void CTextFileBuffer::put(const char character) {
431
    // Write single character to buffer
432
    push(&character, 1);                         // Add to buffer
433
    column ++;                                   // Update column
434
}
435
 
436
uint32_t CTextFileBuffer::putStringN(const char * s, uint32_t len) {
437
    // Write string to buffer, add terminating zero
438
    static const int8_t nul = 0;
439
    uint32_t retval = push(s, len);
440
    push(&nul, 1);
441
    num_entries--;                               // compensate for pushing twice
442
    column += len + 1;
443
    return retval;
444
}
445
 
446
void CTextFileBuffer::newLine() {
447
    // Add linefeed
448
    if (lineType == 0) {
449
        push("\r\n", 2);                         // DOS/Windows style linefeed
450
    }
451
    else {
452
        push("\n", 1);                           // UNIX style linefeed
453
    }
454
    column = 0;                                  // Reset column
455
}
456
 
457
void CTextFileBuffer::tabulate(uint32_t i) {
458
    // Insert spaces until column i
459
    uint32_t j;
460
    if (i > column) {                            // Only insert spaces if we are not already past i
461
        for (j = column; j < i; j++) push(" ", 1); // Insert i - column spaces
462
        column = i;                              // Update column
463
    }
464
}
465
 
466
void CTextFileBuffer::putDecimal(int32_t x, int IsSigned) {
467
    // Write decimal number to buffer, unsigned or signed
468
    char text[16];
469
    sprintf(text, IsSigned ? "%i" : "%u", x);
470
    put(text);
471
}
472
 
473
void CTextFileBuffer::putHex(uint8_t x, int ox) {
474
    // Write hexadecimal 8 bit number to buffer
475
    // ox meaning: 1 = put 0x prefix, 2 = prefix zeroes to fixed length
476
    char text[16];
477
    sprintf(text, ox & 2 ? "%s%02X" : "%s%X", ox & 1 ? "0x" : "", x);
478
    put(text);
479
}
480
 
481
void CTextFileBuffer::putHex(uint16_t x, int ox) {
482
    // Write hexadecimal 16 bit number to buffer
483
    // ox meaning: 1 = put 0x prefix, 2 = prefix zeroes to fixed length
484
    char text[16];
485
    sprintf(text, ox & 2 ? "%s%04X" : "%s%X", ox & 1 ? "0x" : "", x);
486
    put(text);
487
}
488
 
489
void CTextFileBuffer::putHex(uint32_t x, int ox) {
490
    // Write hexadecimal 32 bit number to buffer
491
    // ox meaning: 1 = put 0x prefix, 2 = prefix zeroes to fixed length
492
    char text[16];
493
    sprintf(text, ox & 2 ? "%s%08X" : "%s%X", ox & 1 ? "0x" : "", x);
494
    put(text);
495
}
496
 
497
void CTextFileBuffer::putHex(uint64_t x, int ox) {
498
    // Write unsigned hexadecimal 64 bit number to buffer
499
    // ox meaning: 1 = put 0x prefix, 2 = prefix zeroes to fixed length
500
    char text[32];
501
    if (ox & 2) {  // Print all digits
502
        sprintf(text, "%s%08X%08X", ox & 1 ? "0x" : "", highDWord(x), uint32_t(x));
503
    }
504
    else { // Skip leading zeroes
505
        if (highDWord(x)) {
506
            sprintf(text, "%s%X%08X", ox & 1 ? "0x" : "", highDWord(x), uint32_t(x));
507
        }
508
        else {
509
            sprintf(text, "%s%X", ox & 1 ? "0x" : "", uint32_t(x));
510
        }
511
    }
512
    put(text);
513
}
514
 
515
void CTextFileBuffer::putFloat16(uint16_t x) {
516
    // Write half precision floating point number to buffer
517
    char text[32];
518
    sprintf(text, "%.3G", half2float(x));
519
    put(text);
520
}
521
 
522
 
523
void CTextFileBuffer::putFloat(float x) {
524
    // Write floating point number to buffer
525
    char text[64];
526
    sprintf(text, "%.7G", x);
527
    put(text);
528
}
529
 
530
void CTextFileBuffer::putFloat(double x) {
531
    // Write floating point number to buffer
532
    char text[64];
533
    sprintf(text, "%.12G", x);
534
    put(text);
535
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.