Annotation of parser3/src/types/pa_vfile.C, revision 1.79

1.34      paf         1: 
1.5       paf         2: /** @file
1.14      paf         3:        Parser: @b file parser type.
1.3       paf         4: 
1.77      moko        5:        Copyright (c) 2001-2017 Art. Lebedev Studio (http://www.artlebedev.com)
1.26      paf         6:        Author: Alexandr Petrosian <paf@design.ru> (http://paf.design.ru)
1.30      paf         7: */
1.3       paf         8: 
1.37      paf         9: #include "classes.h"
1.78      moko       10: #include "pa_base64.h"
1.1       paf        11: #include "pa_vfile.h"
                     12: #include "pa_vstring.h"
1.3       paf        13: #include "pa_vint.h"
1.70      moko       14: #include "pa_charsets.h"
1.50      misha      15: #include "pa_request.h"
1.1       paf        16: 
1.79    ! moko       17: volatile const char * IDENT_PA_VFILE_C="$Id: pa_vfile.C,v 1.78 2019/11/13 22:05:48 moko Exp $" IDENT_PA_VFILE_H;
1.51      moko       18: 
1.37      paf        19: // externs
                     20: 
                     21: extern Methoded* file_class;
                     22: 
                     23: // defines for statics
                     24: 
                     25: #define SIZE_NAME "size"
                     26: #define TEXT_NAME "text"
                     27: 
1.50      misha      28: #define MODE_VALUE_TEXT "text"
                     29: #define MODE_VALUE_BINARY "binary"
                     30: 
1.58      moko       31: #define CONTENT_TYPE_TEXT "text/plain"
                     32: #define CONTENT_TYPE_BINARY "application/octet-stream"
                     33: 
1.37      paf        34: // statics
                     35: 
                     36: static const String size_name(SIZE_NAME);
                     37: static const String text_name(TEXT_NAME);
1.50      misha      38: 
                     39: static const String mode_value_text(MODE_VALUE_TEXT);
                     40: static const String mode_value_binary(MODE_VALUE_BINARY);
1.37      paf        41: 
1.58      moko       42: static const String content_type_text(CONTENT_TYPE_TEXT);
                     43: static const String content_type_binary(CONTENT_TYPE_BINARY);
                     44: 
1.59      moko       45: inline bool content_type_is_default(Value *content_type){
                     46:        if(content_type){
                     47:                const String *ct=content_type->get_string();
                     48:                return ct == &content_type_text || ct == &content_type_binary;
                     49:        }
                     50:        return true;
                     51: }
                     52: 
1.37      paf        53: // methods
                     54: 
                     55: VStateless_class *VFile::get_class() { return file_class; }
                     56: 
1.76      moko       57: HashStringValue *VFile::get_hash() { Value *prefetch PA_ATTR_UNUSED =get_element(text_name); return &ffields; }
1.74      moko       58: 
                     59: 
1.61      moko       60: void VFile::set_all(bool atainted, bool ais_text_mode, const char* avalue_ptr, size_t avalue_size, const String* afile_name) {
1.8       paf        61:        fvalue_ptr=avalue_ptr;
                     62:        fvalue_size=avalue_size;
1.53      misha      63: 
1.43      misha      64:        ftext_tainted=atainted;
1.60      moko       65:        fis_text_content=ais_text_mode;
1.8       paf        66: 
1.10      paf        67:        ffields.clear();
1.43      misha      68: 
1.60      moko       69:        set_name(afile_name);
1.73      moko       70:        ffields.put(size_name, new VDouble(fvalue_size));
1.58      moko       71:        set_mode(ais_text_mode);
1.54      moko       72: }
1.53      misha      73: 
1.54      moko       74: void VFile::set(bool atainted, bool ais_text_mode, char* avalue_ptr, size_t avalue_size, const String* afile_name, Value* acontent_type, Request* r) {
                     75:        if(ais_text_mode && avalue_ptr && avalue_size) {
                     76:                fix_line_breaks(avalue_ptr, avalue_size);
                     77:        }
1.61      moko       78:        set_all(atainted, ais_text_mode, avalue_ptr, avalue_size, afile_name);
1.60      moko       79:        set_content_type(acontent_type, afile_name, r);
1.50      misha      80: }
                     81: 
1.54      moko       82: void VFile::set_binary(bool atainted, const char* avalue_ptr, size_t avalue_size, const String* afile_name, Value* acontent_type, Request* r) {
1.61      moko       83:        set_all(atainted, false, avalue_ptr, avalue_size, afile_name);
1.60      moko       84:        set_content_type(acontent_type, afile_name, r);
                     85: }
                     86: 
                     87: void VFile::set_binary_string(bool atainted, const char* avalue_ptr, size_t avalue_size) {
1.61      moko       88:        set_all(atainted, false, avalue_ptr, avalue_size, 0);
1.54      moko       89: }
1.53      misha      90: 
1.71      moko       91: void VFile::set(VFile& avfile, bool *ais_text_mode, const String* afile_name, Value* acontent_type, Request* r) {
1.58      moko       92:        fvalue_ptr=avfile.fvalue_ptr;
                     93:        fvalue_size=avfile.fvalue_size;
                     94:        ftext_tainted=avfile.ftext_tainted;
1.69      moko       95:        fis_text_mode=avfile.fis_text_mode;
1.58      moko       96:        fis_text_content=avfile.fis_text_content;
1.53      misha      97: 
                     98:        ffields.clear();
1.50      misha      99:        for(HashStringValue::Iterator i(avfile.ffields); i; i.next())
1.53      misha     100:                if(i.key() != text_name) // do not copy cached .text value
1.58      moko      101:                        ffields.put(*new String(i.key(), String::L_TAINTED), i.value());
1.54      moko      102: 
1.71      moko      103:        if(ais_text_mode)
                    104:                set_mode(*ais_text_mode);
1.58      moko      105: 
                    106:        if(afile_name)
                    107:                set_name(afile_name);
                    108: 
1.71      moko      109:        if(acontent_type || afile_name || ( ais_text_mode && content_type_is_default(ffields.get(content_type_name)) ))
1.58      moko      110:                set_content_type(acontent_type, afile_name, r);
1.53      misha     111: }
                    112: 
                    113: const char* VFile::text_cstr() {
                    114:        const char* p=value_ptr();
1.54      moko      115:        if(fis_text_content)
1.53      misha     116:                return p;
                    117: 
                    118:        size_t size=fvalue_size;
                    119: 
                    120:        if(const char *premature_zero_pos=(const char *)memchr(p, 0, size))
                    121:                size=premature_zero_pos-p;
                    122: 
1.63      moko      123:        char *copy_ptr=size?pa_strdup(p, size):0;
1.54      moko      124:        // text mode but binary content
1.53      misha     125:        if(fis_text_mode && size)
                    126:                fix_line_breaks(copy_ptr, size);
                    127:        return copy_ptr;
1.50      misha     128: }
                    129: 
1.53      misha     130: void VFile::set_mode(bool ais_text_mode){
                    131:        fis_text_mode=ais_text_mode;
1.56      moko      132:        if(fvalue_ptr)
                    133:                ffields.put(mode_name, new VString(ais_text_mode? mode_value_text : mode_value_binary ));
1.50      misha     134: }
                    135: 
                    136: void VFile::set_name(const String* afile_name){
1.79    ! moko      137:        const char *lfile_name;
1.57      misha     138:        if(afile_name && !afile_name->is_empty()) {
1.67      moko      139:                if(afile_name->starts_with("http://") || afile_name->starts_with("https://")){
                    140:                        size_t query=afile_name->pos('?');
                    141:                        if(query!=STRING_NOT_FOUND)
                    142:                                afile_name=&afile_name->mid(0,query);
                    143:                }
1.79    ! moko      144:                lfile_name=pa_filename(afile_name->taint_cstr(String::L_FILE_SPEC));
1.66      moko      145:                if(!lfile_name[0])
1.79    ! moko      146:                        lfile_name=NONAME_DAT;
1.14      paf       147:        } else
1.79    ! moko      148:                lfile_name=NONAME_DAT;
1.50      misha     149: 
1.53      misha     150:        ffields.put(name_name, new VString(*new String(lfile_name, String::L_FILE_SPEC)));
1.50      misha     151: }
1.43      misha     152: 
1.50      misha     153: void VFile::set_content_type(Value* acontent_type, const String* afile_name, Request* r){
                    154:        if(!acontent_type && afile_name && r)
                    155:                acontent_type=new VString(r->mime_type_of(afile_name));
1.43      misha     156: 
1.58      moko      157:        if(!acontent_type)
                    158:                acontent_type=new VString(fis_text_mode ? content_type_text : content_type_binary);
                    159: 
                    160:        ffields.put(content_type_name, acontent_type);
1.43      misha     161: }
                    162: 
1.70      moko      163: Charset* VFile::detect_binary_charset(Charset *charset){
                    164:        if(!charset)
1.68      moko      165:                if(Value* content_type=ffields.get(content_type_name))
                    166:                        if(const String *ct=content_type->get_string())
1.70      moko      167:                                charset=detect_charset(ct->cstr());
1.72      moko      168:        return pa_charsets.checkBOM((char*&)fvalue_ptr, fvalue_size, charset); // checkBOM can alter ptr, but not the content
1.68      moko      169: }
                    170: 
                    171: void VFile::transcode(Charset& from_charset, Charset& to_charset){
                    172:        String::C result=Charset::transcode(String::C(fvalue_ptr, fvalue_size), from_charset, to_charset);
                    173:        fvalue_ptr=result.str;
                    174:        fvalue_size=result.length;
                    175:        ffields.put(size_name, new VInt(fvalue_size));
                    176: }
                    177: 
1.46      misha     178: void VFile::save(Request_charsets& charsets, const String& file_spec, bool is_text, Charset* asked_charset) {
                    179:        if(fvalue_ptr)
                    180:                file_write(charsets, file_spec, fvalue_ptr, fvalue_size, is_text, false/*do_append*/, asked_charset);
                    181:        else
1.58      moko      182:                throw Exception(PARSER_RUNTIME, &file_spec, "saving stat-ed file");
1.46      misha     183: }
                    184: 
1.50      misha     185: bool VFile::is_text_mode(const String& mode) {
                    186:        if(mode==mode_value_text)
                    187:                return true;
                    188:        if(mode==mode_value_binary)
                    189:                return false;
1.62      moko      190:        throw Exception(PARSER_RUNTIME, &mode, "is invalid mode, must be either '" MODE_VALUE_TEXT "' or '" MODE_VALUE_BINARY "'");
1.50      misha     191: }
1.58      moko      192: 
1.68      moko      193: bool VFile::is_valid_mode(const String& mode) {
1.50      misha     194:        return (mode==mode_value_text || mode==mode_value_binary);
                    195: }
                    196: 
1.45      misha     197: Value* VFile::get_element(const String& aname) {
1.43      misha     198:        Value* result;
                    199: 
                    200:        // $method
1.45      misha     201:        if(result=VStateless_object::get_element(aname))
1.43      misha     202:                return result;
                    203: 
                    204:        // $field
                    205:        if(result=ffields.get(aname))
                    206:                return result;
                    207: 
                    208:        // $text - if not cached
1.53      misha     209:        if(aname == text_name && fvalue_ptr && fvalue_size) {
1.43      misha     210:                // assigned file have ptr and we really have some bytes
1.42      misha     211: 
1.53      misha     212:                result=new VString(*new String(text_cstr(), ftext_tainted ? String::L_TAINTED : String::L_AS_IS));
1.42      misha     213: 
1.53      misha     214:                // cache it
1.43      misha     215:                ffields.put(text_name, result);
1.35      paf       216: 
                    217:                return result;
1.43      misha     218:        }
1.35      paf       219: 
1.43      misha     220:        return 0;
1.3       paf       221: }
1.48      misha     222: 
1.52      moko      223: const String* VFile::get_json_string(Json_options& options){
1.49      moko      224:        String& result=*new String("{\n", String::L_AS_IS);
                    225:        
                    226:        String * indent=NULL;
                    227: 
1.52      moko      228:        if (options.indent){
                    229:                indent = new String(",\n\t", String::L_AS_IS); *indent << options.indent << "\"";
                    230:                result << "\t" << options.indent;
1.49      moko      231:        }
                    232: 
                    233:        result << "\"class\":\"file\"";
1.48      misha     234: 
                    235:        for(HashStringValue::Iterator i(ffields); i; i.next() ){
                    236:                String::Body key=i.key();
                    237:                if(key != text_name){
1.49      moko      238:                        indent ? result << *indent : result << ",\n\"";
                    239:                        result << String(key, String::L_JSON) << "\":" << *i.value()->get_json_string(options);
1.48      misha     240:                }
                    241:        }
                    242: 
                    243:        if(fvalue_ptr){
1.52      moko      244:                switch(options.file){
1.48      misha     245:                        case Json_options::F_BASE64:
                    246:                                {
1.49      moko      247:                                        indent ? result << *indent : result << ",\n\"";
                    248:                                        result << "base64\":\"";
1.48      misha     249:                                        const char* encoded=pa_base64_encode(fvalue_ptr, fvalue_size);
1.55      moko      250:                                        result.append_help_length(encoded, 0, String::L_JSON);
1.49      moko      251:                                        result << "\"";
1.48      misha     252:                                        break;
                    253:                                }
                    254:                        case Json_options::F_TEXT:
                    255:                                {
1.49      moko      256:                                        indent ? result << *indent : result << ",\n\"";
                    257:                                        result << "text\":\"";
1.55      moko      258:                                        result.append_help_length(text_cstr(), 0, String::L_JSON);
1.49      moko      259:                                        result << "\"";
1.48      misha     260:                                        break;
                    261:                                }
1.64      moko      262:                        case Json_options::F_BODYLESS: break;
1.48      misha     263:                }
                    264:        }
                    265: 
1.52      moko      266:        result << "\n" << options.indent << "}";
1.49      moko      267:        return &result;
1.48      misha     268: }

E-mail: